diff options
Diffstat (limited to 'clang/test/CodeGenCXX')
431 files changed, 26690 insertions, 0 deletions
diff --git a/clang/test/CodeGenCXX/2003-11-02-WeakLinkage.cpp b/clang/test/CodeGenCXX/2003-11-02-WeakLinkage.cpp new file mode 100644 index 0000000..02f9fc6 --- /dev/null +++ b/clang/test/CodeGenCXX/2003-11-02-WeakLinkage.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s +// The template should compile to linkonce linkage, not weak linkage. + +// CHECK-NOT: weak +template<class T> +void thefunc(); + +template<class T> +inline void thefunc() {} + +void test() { + thefunc<int>(); +} diff --git a/clang/test/CodeGenCXX/2003-11-18-PtrMemConstantInitializer.cpp b/clang/test/CodeGenCXX/2003-11-18-PtrMemConstantInitializer.cpp new file mode 100644 index 0000000..9cecf48 --- /dev/null +++ b/clang/test/CodeGenCXX/2003-11-18-PtrMemConstantInitializer.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + +struct Gfx { + void opMoveSetShowText(); +}; + +struct Operator { + void (Gfx::*func)(); +}; + +Operator opTab[] = { + {&Gfx::opMoveSetShowText}, +}; diff --git a/clang/test/CodeGenCXX/2003-11-27-MultipleInheritanceThunk.cpp b/clang/test/CodeGenCXX/2003-11-27-MultipleInheritanceThunk.cpp new file mode 100644 index 0000000..3e53397 --- /dev/null +++ b/clang/test/CodeGenCXX/2003-11-27-MultipleInheritanceThunk.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + + +struct CallSite { + int X; + + CallSite(const CallSite &CS); +}; + +struct AliasAnalysis { + int TD; + + virtual int getModRefInfo(CallSite CS); +}; + + +struct Pass { + int X; + virtual int foo(); +}; + +struct AliasAnalysisCounter : public Pass, public AliasAnalysis { + int getModRefInfo(CallSite CS) { + return 0; + } +}; + +AliasAnalysisCounter AAC; diff --git a/clang/test/CodeGenCXX/2003-11-29-DuplicatedCleanupTest.cpp b/clang/test/CodeGenCXX/2003-11-29-DuplicatedCleanupTest.cpp new file mode 100644 index 0000000..45325bc --- /dev/null +++ b/clang/test/CodeGenCXX/2003-11-29-DuplicatedCleanupTest.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + + +void doesntThrow() throw(); +struct F { + ~F() { doesntThrow(); } +}; + +void atest() { + F A; +lab: + F B; + goto lab; +} + +void test(int val) { +label: { + F A; + F B; + if (val == 0) goto label; + if (val == 1) goto label; +} +} + +void test3(int val) { +label: { + F A; + F B; + if (val == 0) { doesntThrow(); goto label; } + if (val == 1) { doesntThrow(); goto label; } +} +} + +void test4(int val) { +label: { + F A; + F B; + if (val == 0) { F C; goto label; } + if (val == 1) { F D; goto label; } +} +} diff --git a/clang/test/CodeGenCXX/2003-12-08-ArrayOfPtrToMemberFunc.cpp b/clang/test/CodeGenCXX/2003-12-08-ArrayOfPtrToMemberFunc.cpp new file mode 100644 index 0000000..38de271 --- /dev/null +++ b/clang/test/CodeGenCXX/2003-12-08-ArrayOfPtrToMemberFunc.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + +struct Evil { + void fun (); +}; +int foo(); +typedef void (Evil::*memfunptr) (); +static memfunptr jumpTable[] = { &Evil::fun }; + +void Evil::fun() { + (this->*jumpTable[foo()]) (); +} diff --git a/clang/test/CodeGenCXX/2004-01-11-DynamicInitializedConstant.cpp b/clang/test/CodeGenCXX/2004-01-11-DynamicInitializedConstant.cpp new file mode 100644 index 0000000..0c9333f --- /dev/null +++ b/clang/test/CodeGenCXX/2004-01-11-DynamicInitializedConstant.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +// CHECK-NOT: constant +extern int X; +const int Y = X; +const int* foo() { return &Y; } diff --git a/clang/test/CodeGenCXX/2004-03-08-ReinterpretCastCopy.cpp b/clang/test/CodeGenCXX/2004-03-08-ReinterpretCastCopy.cpp new file mode 100644 index 0000000..a6e2e30 --- /dev/null +++ b/clang/test/CodeGenCXX/2004-03-08-ReinterpretCastCopy.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + +struct A { + virtual void Method() = 0; +}; + +struct B : public A { + virtual void Method() { } +}; + +typedef void (A::*fn_type_a)(void); +typedef void (B::*fn_type_b)(void); + +int main(int argc, char **argv) +{ + fn_type_a f = reinterpret_cast<fn_type_a>(&B::Method); + fn_type_b g = reinterpret_cast<fn_type_b>(f); + B b; + (b.*g)(); + return 0; +} diff --git a/clang/test/CodeGenCXX/2004-03-09-UnmangledBuiltinMethods.cpp b/clang/test/CodeGenCXX/2004-03-09-UnmangledBuiltinMethods.cpp new file mode 100644 index 0000000..5d8c8b0 --- /dev/null +++ b/clang/test/CodeGenCXX/2004-03-09-UnmangledBuiltinMethods.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +// CHECK: _ZN11AccessFlags6strlenEv +struct AccessFlags { + void strlen(); +}; + +void AccessFlags::strlen() { } diff --git a/clang/test/CodeGenCXX/2004-03-15-CleanupsAndGotos.cpp b/clang/test/CodeGenCXX/2004-03-15-CleanupsAndGotos.cpp new file mode 100644 index 0000000..01350c0 --- /dev/null +++ b/clang/test/CodeGenCXX/2004-03-15-CleanupsAndGotos.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + +// Testcase from Bug 291 + +struct X { + ~X(); +}; + +void foo() { + X v; + +TryAgain: + goto TryAgain; +} diff --git a/clang/test/CodeGenCXX/2004-06-08-LateTemplateInstantiation.cpp b/clang/test/CodeGenCXX/2004-06-08-LateTemplateInstantiation.cpp new file mode 100644 index 0000000..97254c1 --- /dev/null +++ b/clang/test/CodeGenCXX/2004-06-08-LateTemplateInstantiation.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + + +template<typename Ty> +struct normal_iterator { + int FIELD; +}; + +void foo(normal_iterator<int>); +normal_iterator<int> baz(); + +void bar() { + foo(baz()); +} + +void *bar2() { + return (void*)foo; +} diff --git a/clang/test/CodeGenCXX/2004-09-27-DidntEmitTemplate.cpp b/clang/test/CodeGenCXX/2004-09-27-DidntEmitTemplate.cpp new file mode 100644 index 0000000..618894f --- /dev/null +++ b/clang/test/CodeGenCXX/2004-09-27-DidntEmitTemplate.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +// This is a testcase for LLVM PR445, which was a problem where the +// instantiation of callDefaultCtor was not being emitted correctly. + +// CHECK-NOT: declare{{.*}}callDefaultCtor +struct Pass {}; + +template<typename PassName> +Pass *callDefaultCtor() { return new Pass(); } + +void foo(Pass *(*C)()); + +struct basic_string { + bool empty() const { return true; } +}; + + +bool foo2(basic_string &X) { + return X.empty(); +} +void baz() { foo(callDefaultCtor<Pass>); } diff --git a/clang/test/CodeGenCXX/2004-11-27-ExceptionCleanupAssertion.cpp b/clang/test/CodeGenCXX/2004-11-27-ExceptionCleanupAssertion.cpp new file mode 100644 index 0000000..ebcce77 --- /dev/null +++ b/clang/test/CodeGenCXX/2004-11-27-ExceptionCleanupAssertion.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 %s -emit-llvm -o /dev/null + +// This is PR421 + +struct Strongbad { + Strongbad(const char *str ); + ~Strongbad(); + operator const char *() const; +}; + +void TheCheat () { + Strongbad foo(0); + Strongbad dirs[] = { Strongbad(0) + 1}; +} diff --git a/clang/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp b/clang/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp new file mode 100644 index 0000000..3bfecd5 --- /dev/null +++ b/clang/test/CodeGenCXX/2004-11-27-FriendDefaultArgCrash.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-llvm %s -o /dev/null + +// PR447 + +namespace nm { + struct str { + friend int foo(int arg = 0); + }; +} diff --git a/clang/test/CodeGenCXX/2005-01-03-StaticInitializers.cpp b/clang/test/CodeGenCXX/2005-01-03-StaticInitializers.cpp new file mode 100644 index 0000000..875c412 --- /dev/null +++ b/clang/test/CodeGenCXX/2005-01-03-StaticInitializers.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +struct S { + int A[2]; +}; + +// CHECK-NOT: llvm.global_ctor +int XX = (int)(long)&(((struct S*)0)->A[1]); diff --git a/clang/test/CodeGenCXX/2005-02-11-AnonymousUnion.cpp b/clang/test/CodeGenCXX/2005-02-11-AnonymousUnion.cpp new file mode 100644 index 0000000..dee5817 --- /dev/null +++ b/clang/test/CodeGenCXX/2005-02-11-AnonymousUnion.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - + +// Test anonymous union with members of the same size. +int test1(float F) { + union { + float G; + int i; + }; + G = F; + return i; +} + +// test anonymous union with members of differing size. +int test2(short F) { + volatile union { + short G; + int i; + }; + G = F; + return i; +} + +// Make sure that normal unions work. duh :) +volatile union U_t { + short S; + int i; +} U; + +int test3(short s) { + U.S = s; + return U.i; +} diff --git a/clang/test/CodeGenCXX/2005-02-13-BadDynamicInit.cpp b/clang/test/CodeGenCXX/2005-02-13-BadDynamicInit.cpp new file mode 100644 index 0000000..b1db67a --- /dev/null +++ b/clang/test/CodeGenCXX/2005-02-13-BadDynamicInit.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// This testcase corresponds to PR509 +struct Data { + unsigned *data; + unsigned array[1]; +}; + +// CHECK-NOT: llvm.global_ctors +Data shared_null = { shared_null.array }; diff --git a/clang/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp b/clang/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp new file mode 100644 index 0000000..c37f5dc --- /dev/null +++ b/clang/test/CodeGenCXX/2005-02-14-BitFieldOffset.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +// CHECK-NOT: i32 6 +struct QVectorTypedData { + int size; + unsigned int sharable : 1; + unsigned short array[1]; +}; + +void foo(QVectorTypedData *X) { + X->array[0] = 123; +} diff --git a/clang/test/CodeGenCXX/2005-02-19-BitfieldStructCrash.cpp b/clang/test/CodeGenCXX/2005-02-19-BitfieldStructCrash.cpp new file mode 100644 index 0000000..937a300 --- /dev/null +++ b/clang/test/CodeGenCXX/2005-02-19-BitfieldStructCrash.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + +struct QChar {unsigned short X; QChar(unsigned short); } ; + +struct Command { + Command(QChar c) : c(c) {} + unsigned int type : 4; + QChar c; + }; + +Command X(QChar('c')); + +void Foo(QChar ); +void bar() { Foo(X.c); } diff --git a/clang/test/CodeGenCXX/2005-02-19-UnnamedVirtualThunkArgument.cpp b/clang/test/CodeGenCXX/2005-02-19-UnnamedVirtualThunkArgument.cpp new file mode 100644 index 0000000..986001a --- /dev/null +++ b/clang/test/CodeGenCXX/2005-02-19-UnnamedVirtualThunkArgument.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -emit-llvm %s -o /dev/null + +struct Foo { + Foo(); + virtual ~Foo(); +}; + +struct Bar { + Bar(); + virtual ~Bar(); + virtual bool test(bool) const; +}; + +struct Baz : public Foo, public Bar { + Baz(); + virtual ~Baz(); + virtual bool test(bool) const; +}; + +bool Baz::test(bool) const { + return true; +} diff --git a/clang/test/CodeGenCXX/2005-02-20-BrokenReferenceTest.cpp b/clang/test/CodeGenCXX/2005-02-20-BrokenReferenceTest.cpp new file mode 100644 index 0000000..36f911e --- /dev/null +++ b/clang/test/CodeGenCXX/2005-02-20-BrokenReferenceTest.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -emit-llvm %s -o /dev/null + +void test(unsigned char *b, int rb) { + typedef unsigned char imgfoo[10][rb]; + imgfoo &br = *(imgfoo *)b; + + br[0][0] = 1; + + rb = br[0][0]; +} diff --git a/clang/test/CodeGenCXX/2006-03-01-GimplifyCrash.cpp b/clang/test/CodeGenCXX/2006-03-01-GimplifyCrash.cpp new file mode 100644 index 0000000..b809751 --- /dev/null +++ b/clang/test/CodeGenCXX/2006-03-01-GimplifyCrash.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + +struct PrefMapElem { + virtual ~PrefMapElem(); + unsigned int fPrefId; +}; + +int foo() { + PrefMapElem* fMap; + if (fMap[0].fPrefId == 1) + return 1; + + return 0; +} diff --git a/clang/test/CodeGenCXX/2006-03-06-C++RecurseCrash.cpp b/clang/test/CodeGenCXX/2006-03-06-C++RecurseCrash.cpp new file mode 100644 index 0000000..01476b7 --- /dev/null +++ b/clang/test/CodeGenCXX/2006-03-06-C++RecurseCrash.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - +namespace std { + class exception { }; + + class type_info { + public: + virtual ~type_info(); + }; + +} + +namespace __cxxabiv1 { + class __si_class_type_info : public std::type_info { + ~__si_class_type_info(); + }; +} + +class recursive_init: public std::exception { +public: + virtual ~recursive_init() throw (); +}; + +recursive_init::~recursive_init() throw() { } diff --git a/clang/test/CodeGenCXX/2006-09-12-OpaqueStructCrash.cpp b/clang/test/CodeGenCXX/2006-09-12-OpaqueStructCrash.cpp new file mode 100644 index 0000000..bd270dd --- /dev/null +++ b/clang/test/CodeGenCXX/2006-09-12-OpaqueStructCrash.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s + +struct A { + virtual ~A(); +}; + +template <typename Ty> +struct B : public A { + ~B () { delete [] val; } +private: + Ty* val; +}; + +template <typename Ty> +struct C : public A { + C (); + ~C (); +}; + +template <typename Ty> +struct D : public A { + D () {} + private: + B<C<Ty> > blocks; +}; + +template class D<double>; diff --git a/clang/test/CodeGenCXX/2006-10-30-ClassBitfield.cpp b/clang/test/CodeGenCXX/2006-10-30-ClassBitfield.cpp new file mode 100644 index 0000000..8f61f7b --- /dev/null +++ b/clang/test/CodeGenCXX/2006-10-30-ClassBitfield.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - +// PR954 + +struct _Refcount_Base { + unsigned long _M_ref_count; + int _M_ref_count_lock; + _Refcount_Base() : _M_ref_count(0) {} +}; + +struct _Rope_RopeRep : public _Refcount_Base +{ +public: + int _M_tag:8; +}; + +int foo(_Rope_RopeRep* r) { return r->_M_tag; } diff --git a/clang/test/CodeGenCXX/2006-11-20-GlobalSymbols.cpp b/clang/test/CodeGenCXX/2006-11-20-GlobalSymbols.cpp new file mode 100644 index 0000000..34594f4 --- /dev/null +++ b/clang/test/CodeGenCXX/2006-11-20-GlobalSymbols.cpp @@ -0,0 +1,11 @@ +// PR1013 +// Check to make sure debug symbols use the correct name for globals and +// functions. Will not assemble if it fails to. +// RUN: %clang_cc1 -emit-llvm -g -o - %s | FileCheck %s + +// CHECK: f\01oo" +int foo __asm__("f\001oo"); + +int bar() { + return foo; +} diff --git a/clang/test/CodeGenCXX/2006-11-30-ConstantExprCrash.cpp b/clang/test/CodeGenCXX/2006-11-30-ConstantExprCrash.cpp new file mode 100644 index 0000000..2088e63 --- /dev/null +++ b/clang/test/CodeGenCXX/2006-11-30-ConstantExprCrash.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - +// PR1027 + +struct sys_var { + unsigned name_length; + + bool no_support_one_shot; + sys_var() {} +}; + + +struct sys_var_thd : public sys_var { +}; + +extern sys_var_thd sys_auto_is_null; + +sys_var *getsys_variables() { + return &sys_auto_is_null; +} + +sys_var *sys_variables = &sys_auto_is_null; diff --git a/clang/test/CodeGenCXX/2007-01-02-UnboundedArray.cpp b/clang/test/CodeGenCXX/2007-01-02-UnboundedArray.cpp new file mode 100644 index 0000000..0cd83fa --- /dev/null +++ b/clang/test/CodeGenCXX/2007-01-02-UnboundedArray.cpp @@ -0,0 +1,14 @@ +// Make sure unbounded arrays compile with debug information. +// +// RUN: %clang_cc1 -emit-llvm -g %s -o - + +// PR1068 + +struct Object { + char buffer[]; +}; + +int main(int argc, char** argv) { + new Object; + return 0; +} diff --git a/clang/test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp b/clang/test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp new file mode 100644 index 0000000..37005c5 --- /dev/null +++ b/clang/test/CodeGenCXX/2007-01-06-PtrMethodInit.cpp @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple i386-apple-macosx10.7.2 +// PR1084 + +extern "C" +{ + typedef unsigned char PRUint8; + typedef unsigned int PRUint32; +} +typedef PRUint32 nsresult; +struct nsID +{ +}; +typedef nsID nsIID; +class nsISupports +{ +}; +extern "C++" +{ + template < class T > struct nsCOMTypeInfo + { + static const nsIID & GetIID () + { + } + }; +} + +class nsIDOMEvent:public nsISupports +{ +}; +class nsIDOMEventListener:public nsISupports +{ +public:static const nsIID & GetIID () + { + } + virtual nsresult + __attribute__ ((regparm (0), cdecl)) HandleEvent (nsIDOMEvent * event) = + 0; +}; +class nsIDOMMouseListener:public nsIDOMEventListener +{ +public:static const nsIID & GetIID () + { + static const nsIID iid = { + }; + } + virtual nsresult + __attribute__ ((regparm (0), + cdecl)) MouseDown (nsIDOMEvent * aMouseEvent) = 0; +}; +typedef +typeof (&nsIDOMEventListener::HandleEvent) + GenericHandler; + struct EventDispatchData + { + PRUint32 message; + GenericHandler method; + PRUint8 bits; + }; + struct EventTypeData + { + const EventDispatchData *events; + int numEvents; + const nsIID *iid; + }; + static const EventDispatchData sMouseEvents[] = { + { + (300 + 2), + reinterpret_cast < GenericHandler > (&nsIDOMMouseListener::MouseDown), + 0x01} + }; +static const EventTypeData sEventTypes[] = { + { + sMouseEvents, (sizeof (sMouseEvents) / sizeof (sMouseEvents[0])), + &nsCOMTypeInfo < nsIDOMMouseListener >::GetIID ()} +}; diff --git a/clang/test/CodeGenCXX/2007-04-05-PackedBitFields-1.cpp b/clang/test/CodeGenCXX/2007-04-05-PackedBitFields-1.cpp new file mode 100644 index 0000000..6c39b55 --- /dev/null +++ b/clang/test/CodeGenCXX/2007-04-05-PackedBitFields-1.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + +#ifdef PACKED +#define P __attribute__((packed)) +#else +#define P +#endif + +struct P M_Packed { + unsigned int l_Packed; + unsigned short k_Packed : 6, + i_Packed : 15, + j_Packed : 11; + +}; + +struct M_Packed sM_Packed; + +int testM_Packed (void) { + struct M_Packed x; + return (x.i_Packed != 0); +} diff --git a/clang/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap-2.cpp b/clang/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap-2.cpp new file mode 100644 index 0000000..d7b0eae --- /dev/null +++ b/clang/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap-2.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + +#ifdef PACKED +#define P __attribute__((packed)) +#else +#define P +#endif + +struct P M_Packed { + unsigned long sorted : 1; + unsigned long from_array : 1; + unsigned long mixed_encoding : 1; + unsigned long encoding : 8; + unsigned long count : 21; + +}; + +struct M_Packed sM_Packed; + +int testM_Packed (void) { + struct M_Packed x; + return (x.count != 0); +} diff --git a/clang/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap.cpp b/clang/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap.cpp new file mode 100644 index 0000000..6911767 --- /dev/null +++ b/clang/test/CodeGenCXX/2007-04-05-PackedBitFieldsOverlap.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + + +#ifdef PACKED +#define P __attribute__((packed)) +#else +#define P +#endif + +struct P M_Packed { + unsigned int l_Packed; + unsigned short k_Packed : 6, + i_Packed : 15; + char c; + +}; + +struct M_Packed sM_Packed; + +int testM_Packed (void) { + struct M_Packed x; + return (x.i_Packed != 0); +} diff --git a/clang/test/CodeGenCXX/2007-04-05-PackedBitFieldsSmall.cpp b/clang/test/CodeGenCXX/2007-04-05-PackedBitFieldsSmall.cpp new file mode 100644 index 0000000..b31f95f --- /dev/null +++ b/clang/test/CodeGenCXX/2007-04-05-PackedBitFieldsSmall.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + + +#ifdef PACKED +// This is an example where size of Packed struct is smaller then +// the size of bit field type. +#define P __attribute__((packed)) +#else +#define P +#endif + +struct P M_Packed { + unsigned long long X:50; + unsigned Y:2; +}; + +struct M_Packed sM_Packed; + +int testM_Packed (void) { + struct M_Packed x; + return (0 != x.Y); +} + +int testM_Packed2 (void) { + struct M_Packed x; + return (0 != x.X); +} diff --git a/clang/test/CodeGenCXX/2007-04-05-StructPackedFieldUnpacked.cpp b/clang/test/CodeGenCXX/2007-04-05-StructPackedFieldUnpacked.cpp new file mode 100644 index 0000000..c848e7c --- /dev/null +++ b/clang/test/CodeGenCXX/2007-04-05-StructPackedFieldUnpacked.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - + +#ifdef PACKED +#define P __attribute__((packed)) +#else +#define P +#endif + +struct UnPacked { + int X; + int Y; +}; + +struct P M_Packed { + unsigned char A; + struct UnPacked B; +}; + +struct M_Packed sM_Packed; + +int testM_Packed (void) { + struct M_Packed x; + return (x.B.Y != 0); +} diff --git a/clang/test/CodeGenCXX/2007-04-10-PackedUnion.cpp b/clang/test/CodeGenCXX/2007-04-10-PackedUnion.cpp new file mode 100644 index 0000000..863fc82 --- /dev/null +++ b/clang/test/CodeGenCXX/2007-04-10-PackedUnion.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -emit-llvm %s -o /dev/null +extern "C" { + +#pragma pack(push, 2) + typedef struct ABC* abc; + + struct ABCS { + float red; + float green; + float blue; + float alpha; + }; + + typedef void (*XYZ)(); +#pragma pack(pop) +} + + +union ABCU { + ABCS color; + XYZ bg; +}; + +struct AData { + ABCU data; +}; + +class L { + public: + L() {} + L(const L& other); + + private: + AData fdata; +}; + + +L::L(const L& other) +{ + fdata = other.fdata; +} diff --git a/clang/test/CodeGenCXX/2007-04-14-FNoBuiltin.cpp b/clang/test/CodeGenCXX/2007-04-14-FNoBuiltin.cpp new file mode 100644 index 0000000..4475fda --- /dev/null +++ b/clang/test/CodeGenCXX/2007-04-14-FNoBuiltin.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -emit-llvm %s -fno-builtin -o - | FileCheck %s +// Check that -fno-builtin is honored. + +extern "C" int printf(const char*, ...); +void foo(const char *msg) { + // CHECK: call{{.*}}printf + printf("%s\n",msg); +} diff --git a/clang/test/CodeGenCXX/2007-05-03-VectorInit.cpp b/clang/test/CodeGenCXX/2007-05-03-VectorInit.cpp new file mode 100644 index 0000000..5bc196f --- /dev/null +++ b/clang/test/CodeGenCXX/2007-05-03-VectorInit.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -emit-llvm %s -O0 -o - +// PR1378 + +typedef float v4sf __attribute__((vector_size(16))); + +typedef v4sf float4; + +static float4 splat4(float a) +{ + float4 tmp = {a,a,a,a}; + return tmp; +} + +float4 foo(float a) +{ + return splat4(a); +} diff --git a/clang/test/CodeGenCXX/2007-07-29-RestrictPtrArg.cpp b/clang/test/CodeGenCXX/2007-07-29-RestrictPtrArg.cpp new file mode 100644 index 0000000..d7c96f5 --- /dev/null +++ b/clang/test/CodeGenCXX/2007-07-29-RestrictPtrArg.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +void foo(int * __restrict myptr1, int * myptr2) { + // CHECK: noalias + myptr1[0] = 0; + myptr2[0] = 0; +} diff --git a/clang/test/CodeGenCXX/2007-07-29-RestrictRefArg.cpp b/clang/test/CodeGenCXX/2007-07-29-RestrictRefArg.cpp new file mode 100644 index 0000000..aa9f48b --- /dev/null +++ b/clang/test/CodeGenCXX/2007-07-29-RestrictRefArg.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +void foo(int & __restrict myptr1, int & myptr2) { + // CHECK: noalias + myptr1 = 0; + myptr2 = 0; +} diff --git a/clang/test/CodeGenCXX/2007-09-10-RecursiveTypeResolution.cpp b/clang/test/CodeGenCXX/2007-09-10-RecursiveTypeResolution.cpp new file mode 100644 index 0000000..ec8a516 --- /dev/null +++ b/clang/test/CodeGenCXX/2007-09-10-RecursiveTypeResolution.cpp @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - +// PR1634 + +namespace Manta +{ + class CallbackHandle + { + protected:virtual ~ CallbackHandle (void) + { + } + }; +template < typename Data1 > class CallbackBase_1Data:public CallbackHandle + { + }; +} + +namespace __gnu_cxx +{ + template < typename _Iterator, typename _Container > + class __normal_iterator + { + _Iterator _M_current; + }; +} + +namespace std +{ + template < typename _Tp > struct allocator + { + typedef _Tp *pointer; + }; + template < typename _InputIterator, + typename _Tp > inline void find (_InputIterator __last, + const _Tp & __val) + { + }; +} + +namespace Manta +{ + template < typename _Tp, typename _Alloc> struct _Vector_base + { + struct _Vector_impl + { + _Tp *_M_start; + }; + public: + _Vector_impl _M_impl; + }; + template < typename _Tp, typename _Alloc = std::allocator < _Tp > > + class vector:protected _Vector_base < _Tp,_Alloc > + { + public: + typedef __gnu_cxx::__normal_iterator < typename _Alloc::pointer, + vector < _Tp, _Alloc > > iterator; + iterator end () + { + } + }; + class MantaInterface + { + }; + class RTRT + { + virtual CallbackHandle *registerTerminationCallback (CallbackBase_1Data < + MantaInterface * >*); + virtual void unregisterCallback (CallbackHandle *); + typedef vector < CallbackBase_1Data < int >*>PRCallbackMapType; + PRCallbackMapType parallelPreRenderCallbacks; + }; +} +using namespace Manta; +CallbackHandle * +RTRT::registerTerminationCallback (CallbackBase_1Data < MantaInterface * >*cb) +{ + return cb; +} + +void +RTRT::unregisterCallback (CallbackHandle * callback) +{ + { + typedef CallbackBase_1Data < int > callback_t; + callback_t *cb = static_cast < callback_t * >(callback); + find (parallelPreRenderCallbacks.end (), cb); + } +} diff --git a/clang/test/CodeGenCXX/2007-10-01-StructResize.cpp b/clang/test/CodeGenCXX/2007-10-01-StructResize.cpp new file mode 100644 index 0000000..8e5750d --- /dev/null +++ b/clang/test/CodeGenCXX/2007-10-01-StructResize.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -emit-llvm %s -o /dev/null + +#pragma pack(4) + +struct Bork { + unsigned int f1 : 3; + unsigned int f2 : 30; +}; + +int Foo(Bork *hdr) { + hdr->f1 = 7; + hdr->f2 = 927; +} diff --git a/clang/test/CodeGenCXX/2008-01-12-VecInit.cpp b/clang/test/CodeGenCXX/2008-01-12-VecInit.cpp new file mode 100644 index 0000000..92bfd51 --- /dev/null +++ b/clang/test/CodeGenCXX/2008-01-12-VecInit.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - +// rdar://5685492 + +typedef int __attribute__((vector_size(16))) v; +v vt = {1, 2, 3, 4}; diff --git a/clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp b/clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp new file mode 100644 index 0000000..f842f95 --- /dev/null +++ b/clang/test/CodeGenCXX/2008-05-07-CrazyOffsetOf.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - +// rdar://5914926 + +struct bork { + struct bork *next_local; + char * query; +}; +int offset = (char *) &(((struct bork *) 0x10)->query) - (char *) 0x10; diff --git a/clang/test/CodeGenCXX/2009-03-17-dbg.cpp b/clang/test/CodeGenCXX/2009-03-17-dbg.cpp new file mode 100644 index 0000000..e2e6c5a --- /dev/null +++ b/clang/test/CodeGenCXX/2009-03-17-dbg.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -emit-llvm %s -o /dev/null -g + +template <typename T1,typename T2> +inline void f(const T1&,const T2&) { } + +template <typename T1,typename T2,void F(const T1&,const T2&)> +struct A { + template <typename T> void g(T& i) { } +}; + +int main() { + int i; + A<int,int,f> a; + a.g(i); +} diff --git a/clang/test/CodeGenCXX/2009-04-23-bool2.cpp b/clang/test/CodeGenCXX/2009-04-23-bool2.cpp new file mode 100644 index 0000000..cf81cc4 --- /dev/null +++ b/clang/test/CodeGenCXX/2009-04-23-bool2.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -emit-llvm %s -o /dev/null +// g++.old-deja/g++.jason/bool2.C from gcc testsuite. +// Crashed before 67975 went in. +struct F { + bool b1 : 1; + bool b2 : 7; +}; + +int main() +{ + F f = { true, true }; + + if (int (f.b1) != 1) + return 1; +} diff --git a/clang/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp b/clang/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp new file mode 100644 index 0000000..8361680 --- /dev/null +++ b/clang/test/CodeGenCXX/2009-05-04-PureConstNounwind.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -fexceptions -emit-llvm %s -o - | FileCheck %s +int c(void) __attribute__((const)); +int p(void) __attribute__((pure)); +int t(void); + +// CHECK: define i32 @_Z1fv() { +int f(void) { + // CHECK: call i32 @_Z1cv() nounwind readnone + // CHECK: call i32 @_Z1pv() nounwind readonly + return c() + p() + t(); +} + +// CHECK: declare i32 @_Z1cv() nounwind readnone +// CHECK: declare i32 @_Z1pv() nounwind readonly +// CHECK-NOT: declare i32 @_Z1tv() nounwind diff --git a/clang/test/CodeGenCXX/2009-06-16-DebugInfoCrash.cpp b/clang/test/CodeGenCXX/2009-06-16-DebugInfoCrash.cpp new file mode 100644 index 0000000..500520b --- /dev/null +++ b/clang/test/CodeGenCXX/2009-06-16-DebugInfoCrash.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -emit-llvm %s -o /dev/null -g +// This crashes if we try to emit debug info for TEMPLATE_DECL members. +template <class T> class K2PtrVectorBase {}; +template <class T> class K2Vector {}; +template <class U > class K2Vector<U*> : public K2PtrVectorBase<U*> {}; +class ScriptInfoManager { + void PostRegister() ; + template <class SI> short ReplaceExistingElement(K2Vector<SI*>& v); +}; +void ScriptInfoManager::PostRegister() {} diff --git a/clang/test/CodeGenCXX/2009-07-16-Using.cpp b/clang/test/CodeGenCXX/2009-07-16-Using.cpp new file mode 100644 index 0000000..a692d4d --- /dev/null +++ b/clang/test/CodeGenCXX/2009-07-16-Using.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -emit-llvm %s -o /dev/null + +namespace A { + typedef int B; +} +struct B { +}; +using ::A::B; diff --git a/clang/test/CodeGenCXX/2009-08-05-ZeroInitWidth.cpp b/clang/test/CodeGenCXX/2009-08-05-ZeroInitWidth.cpp new file mode 100644 index 0000000..4404d4a --- /dev/null +++ b/clang/test/CodeGenCXX/2009-08-05-ZeroInitWidth.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - +// rdar://7114564 +struct A { + unsigned long long : (sizeof(unsigned long long) * 8) - 16; +}; +struct B { + A a; +}; +struct B b = { + {} +}; diff --git a/clang/test/CodeGenCXX/2009-08-11-VectorRetTy.cpp b/clang/test/CodeGenCXX/2009-08-11-VectorRetTy.cpp new file mode 100644 index 0000000..21b88c9 --- /dev/null +++ b/clang/test/CodeGenCXX/2009-08-11-VectorRetTy.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -emit-llvm -o /dev/null +// <rdar://problem/7096460> +typedef void (*Func) (); +typedef long long m64 __attribute__((__vector_size__(8), __may_alias__)); +static inline m64 __attribute__((__always_inline__, __nodebug__)) _mm_set1_pi16() {} +template <class MM> +static void Bork() { + const m64 mmx_0x00ff = _mm_set1_pi16(); +} +struct A {}; +Func arr[] = { + Bork<A> +}; diff --git a/clang/test/CodeGenCXX/2009-09-09-packed-layout.cpp b/clang/test/CodeGenCXX/2009-09-09-packed-layout.cpp new file mode 100644 index 0000000..9de2f61 --- /dev/null +++ b/clang/test/CodeGenCXX/2009-09-09-packed-layout.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -emit-llvm -triple i386-apple-darwin11 %s -o /dev/null +class X { + public: + virtual ~X(); + short y; +}; +#pragma pack(push, 1) +class Z : public X { + public: enum { foo = ('x') }; + virtual int y() const; +}; +#pragma pack(pop) +class Y : public X { +public: enum { foo = ('y'), bar = 0 }; +}; +X x; +Y y; +Z z; diff --git a/clang/test/CodeGenCXX/2009-10-27-crash.cpp b/clang/test/CodeGenCXX/2009-10-27-crash.cpp new file mode 100644 index 0000000..482bb75 --- /dev/null +++ b/clang/test/CodeGenCXX/2009-10-27-crash.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -emit-llvm %s -o /dev/null +// Radar 7328944 + +typedef struct +{ + unsigned short a : 1; + unsigned short b : 2; + unsigned short c : 1; + unsigned short d : 1; + unsigned short e : 1; + unsigned short f : 1; + unsigned short g : 2; + unsigned short : 7; + union + { + struct + { + unsigned char h : 1; + unsigned char i : 1; + unsigned char j : 1; + unsigned char : 5; + }; + struct + { + unsigned char k : 3; + unsigned char : 5; + }; + }; + unsigned char : 8; +} tt; + +typedef struct +{ + unsigned char s; + tt t; + unsigned int u; +} ttt; + +ttt X = { + 4, + { 0 }, + 55, +}; diff --git a/clang/test/CodeGenCXX/2009-12-23-MissingSext.cpp b/clang/test/CodeGenCXX/2009-12-23-MissingSext.cpp new file mode 100644 index 0000000..e6ff7b3 --- /dev/null +++ b/clang/test/CodeGenCXX/2009-12-23-MissingSext.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// The store of p.y into the temporary was not +// getting extended to 32 bits, so uninitialized +// bits of the temporary were used. 7366161. +struct foo { + char x:8; + signed int y:24; +}; +int bar(struct foo p, int x) { +// CHECK: bar +// CHECK: and {{.*}} 16777215 +// CHECK: and {{.*}} 16777215 + x = (p.y > x ? x : p.y); + return x; +// CHECK: ret +} diff --git a/clang/test/CodeGenCXX/2010-03-09-AnonAggregate.cpp b/clang/test/CodeGenCXX/2010-03-09-AnonAggregate.cpp new file mode 100644 index 0000000..99883d8 --- /dev/null +++ b/clang/test/CodeGenCXX/2010-03-09-AnonAggregate.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -g -S -o %t %s +// PR: 6554 +// More then one anonymous aggregates on one line creates chaos when MDNode uniquness is +// combined with RAUW operation. +// This test case causes crashes if malloc is configured to trip buffer overruns. +class MO { + + union { struct { union { int BA; } Val; int Offset; } OffsetedInfo; } Contents; + +}; + +class MO m; diff --git a/clang/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp b/clang/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp new file mode 100644 index 0000000..7c05535 --- /dev/null +++ b/clang/test/CodeGenCXX/2010-05-10-Var-DbgInfo.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -emit-llvm -O0 -g %s -o /dev/null +// PR 7104 + +struct A { + int Ai; +}; + +struct B : public A {}; +struct C : public B {}; + +const char * f(int C::*){ return ""; } +int f(int B::*) { return 1; } + +struct D : public C {}; + +const char * g(int B::*){ return ""; } +int g(int D::*) { return 1; } + +void test() +{ + int i = f(&A::Ai); + + const char * str = g(&A::Ai); +} + +// conversion of B::* to C::* is better than conversion of A::* to C::* +typedef void (A::*pmfa)(); +typedef void (B::*pmfb)(); +typedef void (C::*pmfc)(); + +struct X { + operator pmfa(); + operator pmfb(); +}; + + +void g(pmfc); + +void test2(X x) +{ + g(x); +} diff --git a/clang/test/CodeGenCXX/2010-05-11-alwaysinlineinstantiation.cpp b/clang/test/CodeGenCXX/2010-05-11-alwaysinlineinstantiation.cpp new file mode 100644 index 0000000..fe0740b --- /dev/null +++ b/clang/test/CodeGenCXX/2010-05-11-alwaysinlineinstantiation.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +// CHECK-NOT: ZN12basic_stringIcEC1Ev +// CHECK: ZN12basic_stringIcED1Ev +// CHECK: ZN12basic_stringIcED1Ev +template<class charT> +class basic_string +{ +public: + basic_string(); + ~basic_string(); +}; + +template <class charT> +__attribute__ ((__visibility__("hidden"), __always_inline__)) inline +basic_string<charT>::basic_string() +{ +} + +template <class charT> +inline +basic_string<charT>::~basic_string() +{ +} + +typedef basic_string<char> string; + +extern template class basic_string<char>; + +int main() +{ + string s; +} diff --git a/clang/test/CodeGenCXX/2010-05-12-PtrToMember-Dbg.cpp b/clang/test/CodeGenCXX/2010-05-12-PtrToMember-Dbg.cpp new file mode 100644 index 0000000..048811f --- /dev/null +++ b/clang/test/CodeGenCXX/2010-05-12-PtrToMember-Dbg.cpp @@ -0,0 +1,17 @@ +//RUN: %clang_cc1 -emit-llvm -g -o - %s | FileCheck %s +//CHECK: DW_TAG_auto_variable +class Foo +{ + public: + int x; + int y; + Foo (int i, int j) { x = i; y = j; } +}; + + +Foo foo(10, 11); + +int main() { + int Foo::* pmi = &Foo::y; + return foo.*pmi; +} diff --git a/clang/test/CodeGenCXX/2010-06-21-LocalVarDbg.cpp b/clang/test/CodeGenCXX/2010-06-21-LocalVarDbg.cpp new file mode 100644 index 0000000..2542378 --- /dev/null +++ b/clang/test/CodeGenCXX/2010-06-21-LocalVarDbg.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -g -emit-llvm %s -o - | FileCheck %s +// Do not use function name to create named metadata used to hold +// local variable info. For example. llvm.dbg.lv.~A is an invalid name. + +// CHECK-NOT: llvm.dbg.lv.~A +class A { +public: + ~A() { int i = 0; i++; } +}; + +int foo(int i) { + A a; + return 0; +} diff --git a/clang/test/CodeGenCXX/2010-06-22-BitfieldInit.cpp b/clang/test/CodeGenCXX/2010-06-22-BitfieldInit.cpp new file mode 100644 index 0000000..f82e527 --- /dev/null +++ b/clang/test/CodeGenCXX/2010-06-22-BitfieldInit.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -emit-llvm -g %s -o - +struct TEST2 +{ + int subid:32; + int :0; +}; + +typedef struct _TEST3 +{ + TEST2 foo; + TEST2 foo2; +} TEST3; + +TEST3 test = + { + {0}, + {0} + }; + +int main() { return 0; } diff --git a/clang/test/CodeGenCXX/2010-06-22-ZeroBitfield.cpp b/clang/test/CodeGenCXX/2010-06-22-ZeroBitfield.cpp new file mode 100644 index 0000000..c2f37f7 --- /dev/null +++ b/clang/test/CodeGenCXX/2010-06-22-ZeroBitfield.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -emit-llvm -g %s -o - +struct s8_0 { unsigned : 0; }; +struct s8_1 { double x; }; +struct s8 { s8_0 a; s8_1 b; }; +s8 f8() { return s8(); } diff --git a/clang/test/CodeGenCXX/2010-07-23-DeclLoc.cpp b/clang/test/CodeGenCXX/2010-07-23-DeclLoc.cpp new file mode 100644 index 0000000..7405448 --- /dev/null +++ b/clang/test/CodeGenCXX/2010-07-23-DeclLoc.cpp @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -emit-llvm -g %s -o - | FileCheck %s +// Require the template function declaration refer to the correct filename. +// First, locate the function decl in metadata, and pluck out the file handle: +// CHECK: {{extract_dwarf_data_from_header.*extract_dwarf_data_from_header.*extract_dwarf_data_from_header.*[^ ]+", metadata !}}[[filehandle:[0-9]+]], +// Second: Require that filehandle refer to the correct filename: +// CHECK: {{^!}}[[filehandle]] = metadata {{![{].*}} metadata !"decl_should_be_here.hpp", +typedef long unsigned int __darwin_size_t; +typedef __darwin_size_t size_t; +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +namespace std { + template<typename _Tp> class auto_ptr { + _Tp* _M_ptr; + public: + typedef _Tp element_type; + auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { } + element_type& operator*() const throw() { } + }; +} +class Pointer32 { +public: + typedef uint32_t ptr_t; + typedef uint32_t size_t; +}; +class Pointer64 { +public: + typedef uint64_t ptr_t; + typedef uint64_t size_t; +}; +class BigEndian {}; +class LittleEndian {}; +template <typename _SIZE, typename _ENDIANNESS> class SizeAndEndianness { +public: + typedef _SIZE SIZE; +}; +typedef SizeAndEndianness<Pointer32, LittleEndian> ISA32Little; +typedef SizeAndEndianness<Pointer32, BigEndian> ISA32Big; +typedef SizeAndEndianness<Pointer64, LittleEndian> ISA64Little; +typedef SizeAndEndianness<Pointer64, BigEndian> ISA64Big; +template <typename SIZE> class TRange { +protected: + typename SIZE::ptr_t _location; + typename SIZE::size_t _length; + TRange(typename SIZE::ptr_t location, typename SIZE::size_t length) : _location(location), _length(length) { } +}; +template <typename SIZE, typename T> class TRangeValue : public TRange<SIZE> { + T _value; +public: + TRangeValue(typename SIZE::ptr_t location, typename SIZE::size_t length, T value) : TRange<SIZE>(location, length), _value(value) {}; +}; +template <typename SIZE> class TAddressRelocator {}; +class CSCppSymbolOwner{}; +class CSCppSymbolOwnerData{}; +template <typename SIZE> class TRawSymbolOwnerData +{ + TRangeValue< SIZE, uint8_t* > _TEXT_text_section; + const char* _dsym_path; + uint32_t _dylib_current_version; + uint32_t _dylib_compatibility_version; +public: + TRawSymbolOwnerData() : + _TEXT_text_section(0, 0, __null), _dsym_path(__null), _dylib_current_version(0), _dylib_compatibility_version(0) {} +}; +template <typename SIZE_AND_ENDIANNESS> class TExtendedMachOHeader {}; +# 16 "decl_should_be_here.hpp" +template <typename SIZE_AND_ENDIANNESS> void extract_dwarf_data_from_header(TExtendedMachOHeader<SIZE_AND_ENDIANNESS>& header, + TRawSymbolOwnerData<typename SIZE_AND_ENDIANNESS::SIZE>& symbol_owner_data, + TAddressRelocator<typename SIZE_AND_ENDIANNESS::SIZE>* address_relocator) {} +struct CSCppSymbolOwnerHashFunctor { + size_t operator()(const CSCppSymbolOwner& symbol_owner) const { +# 97 "wrong_place_for_decl.cpp" + } +}; +template <typename SIZE_AND_ENDIANNESS> CSCppSymbolOwnerData* create_symbol_owner_data_arch_specific(CSCppSymbolOwner* symbol_owner, const char* dsym_path) { + typedef typename SIZE_AND_ENDIANNESS::SIZE SIZE; + std::auto_ptr< TRawSymbolOwnerData<SIZE> > data(new TRawSymbolOwnerData<SIZE>()); + std::auto_ptr< TExtendedMachOHeader<SIZE_AND_ENDIANNESS> > header; + extract_dwarf_data_from_header(*header, *data, (TAddressRelocator<typename SIZE_AND_ENDIANNESS::SIZE>*)__null); +} +CSCppSymbolOwnerData* create_symbol_owner_data2(CSCppSymbolOwner* symbol_owner, const char* dsym_path) { + create_symbol_owner_data_arch_specific< ISA32Little >(symbol_owner, dsym_path); + create_symbol_owner_data_arch_specific< ISA32Big >(symbol_owner, dsym_path); + create_symbol_owner_data_arch_specific< ISA64Little >(symbol_owner, dsym_path); + create_symbol_owner_data_arch_specific< ISA64Big >(symbol_owner, dsym_path); +} diff --git a/clang/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp b/clang/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp new file mode 100644 index 0000000..a853a57 --- /dev/null +++ b/clang/test/CodeGenCXX/2011-12-19-init-list-ctor.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s + +struct A { + A(const char *); +}; + +// CHECK: @arr = global [3 x %struct.S] zeroinitializer +// CHECK: @.str = {{.*}}constant [6 x i8] c"hello\00" +// CHECK: @.str1 = {{.*}}constant [6 x i8] c"world\00" +// CHECK: @.str2 = {{.*}}constant [8 x i8] c"goodbye\00" + +struct S { + int n; + A s; +} arr[] = { + { 0, "hello" }, + { 1, "world" }, + { 2, "goodbye" } +}; + +// CHECK: store i32 0, i32* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 0, i32 0) +// CHECK: call void @_ZN1AC1EPKc(%struct.A* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 0, i32 1), i8* getelementptr inbounds ([6 x i8]* @.str, i32 0, i32 0)) +// CHECK: store i32 1, i32* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 1, i32 0) +// CHECK: call void @_ZN1AC1EPKc(%struct.A* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 1, i32 1), i8* getelementptr inbounds ([6 x i8]* @.str1, i32 0, i32 0)) +// CHECK: store i32 2, i32* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 2, i32 0) +// CHECK: call void @_ZN1AC1EPKc(%struct.A* getelementptr inbounds ([3 x %struct.S]* @arr, i64 0, i64 2, i32 1), i8* getelementptr inbounds ([8 x i8]* @.str2, i32 0, i32 0)) diff --git a/clang/test/CodeGenCXX/2012-02-06-VecInitialization.cpp b/clang/test/CodeGenCXX/2012-02-06-VecInitialization.cpp new file mode 100644 index 0000000..720420e --- /dev/null +++ b/clang/test/CodeGenCXX/2012-02-06-VecInitialization.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -emit-llvm -o - -triple i386-apple-darwin %s | FileCheck %s +// PR11930 + +typedef char vec_t __attribute__ ((__ext_vector_type__ (8))); +void h() { +// CHECK: store <8 x i8> + vec_t v(0); +} diff --git a/clang/test/CodeGenCXX/2012-03-16-StoreAlign.cpp b/clang/test/CodeGenCXX/2012-03-16-StoreAlign.cpp new file mode 100644 index 0000000..a6375f8 --- /dev/null +++ b/clang/test/CodeGenCXX/2012-03-16-StoreAlign.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -emit-llvm -o - -triple x86_64-apple-darwin %s | FileCheck %s +// <rdar://problem/11043589> + +struct Length { + Length(double v) { + m_floatValue = static_cast<float>(v); + } + + bool operator==(const Length& o) const { + return getFloatValue() == o.getFloatValue(); + } + bool operator!=(const Length& o) const { return !(*this == o); } +private: + float getFloatValue() const { + return m_floatValue; + } + float m_floatValue; +}; + + +struct Foo { + static Length inchLength(double inch); + static bool getPageSizeFromName(const Length &A) { + static const Length legalWidth = inchLength(8.5); + if (A != legalWidth) return true; + return false; + } +}; + +// CHECK: @_ZZN3Foo19getPageSizeFromNameERK6LengthE10legalWidth = linkonce_odr global %struct.Length zeroinitializer, align 4 +// CHECK: store float %{{.*}}, float* getelementptr inbounds (%struct.Length* @_ZZN3Foo19getPageSizeFromNameERK6LengthE10legalWidth, i32 0, i32 0), align 1 + +bool bar(Length &b) { + Foo f; + return f.getPageSizeFromName(b); +} diff --git a/clang/test/CodeGenCXX/DynArrayInit.cpp b/clang/test/CodeGenCXX/DynArrayInit.cpp new file mode 100644 index 0000000..4b4c2ec --- /dev/null +++ b/clang/test/CodeGenCXX/DynArrayInit.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -O3 -emit-llvm -o - %s | FileCheck %s +// PR7490 + +// CHECK: define signext i8 @_Z2f0v +// CHECK: ret i8 0 +// CHECK: } +inline void* operator new[](unsigned long, void* __p) { return __p; } +static void f0_a(char *a) { + new (a) char[4](); +} +char f0() { + char a[4]; + f0_a(a); + return a[0] + a[1] + a[2] + a[3]; +} diff --git a/clang/test/CodeGenCXX/PR4827-cast.cpp b/clang/test/CodeGenCXX/PR4827-cast.cpp new file mode 100644 index 0000000..34a840c --- /dev/null +++ b/clang/test/CodeGenCXX/PR4827-cast.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s +struct A; +struct B; +extern A *f(); +void a() { (B *) f(); } diff --git a/clang/test/CodeGenCXX/PR4983-constructor-conversion.cpp b/clang/test/CodeGenCXX/PR4983-constructor-conversion.cpp new file mode 100644 index 0000000..797a1ba --- /dev/null +++ b/clang/test/CodeGenCXX/PR4983-constructor-conversion.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -emit-llvm-only %s + +struct A { + A(const char *s){} +}; + +struct B { + A a; + + B() : a("test") { } +}; + +void f() { + A a("test"); +} + diff --git a/clang/test/CodeGenCXX/PR5050-constructor-conversion.cpp b/clang/test/CodeGenCXX/PR5050-constructor-conversion.cpp new file mode 100644 index 0000000..c50dafb --- /dev/null +++ b/clang/test/CodeGenCXX/PR5050-constructor-conversion.cpp @@ -0,0 +1,19 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +struct A { A(const A&, int i1 = 1); }; + +struct B : A { }; + +A f(const B &b) { + return b; +} + +// CHECK-LP64: callq __ZN1AC1ERKS_i + +// CHECK-LP32: calll L__ZN1AC1ERKS_i + + diff --git a/clang/test/CodeGenCXX/PR5093-static-member-function.cpp b/clang/test/CodeGenCXX/PR5093-static-member-function.cpp new file mode 100644 index 0000000..ceab852 --- /dev/null +++ b/clang/test/CodeGenCXX/PR5093-static-member-function.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +struct a { + static void f(); +}; + +void g(a *a) { + // CHECK: call void @_ZN1a1fEv() + a->f(); +} diff --git a/clang/test/CodeGenCXX/PR5834-constructor-conversion.cpp b/clang/test/CodeGenCXX/PR5834-constructor-conversion.cpp new file mode 100644 index 0000000..044d8e5 --- /dev/null +++ b/clang/test/CodeGenCXX/PR5834-constructor-conversion.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s + +// PR5834 +struct ASTMultiMover {}; +struct ASTMultiPtr { + ASTMultiPtr(); + ASTMultiPtr(ASTMultiPtr&); + ASTMultiPtr(ASTMultiMover mover); + operator ASTMultiMover(); +}; +void f1() { + extern void f0(ASTMultiPtr); + f0(ASTMultiPtr()); +} diff --git a/clang/test/CodeGenCXX/PR5863-unreachable-block.cpp b/clang/test/CodeGenCXX/PR5863-unreachable-block.cpp new file mode 100644 index 0000000..3f32d75 --- /dev/null +++ b/clang/test/CodeGenCXX/PR5863-unreachable-block.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm-only %s + +// PR5863 +class E { }; + +void P1() { + try { + int a=0, b=0; + if (a > b) // simply filling in 0 or 1 doesn't trigger the assertion + throw E(); // commenting out 'if' or 'throw' 'fixes' the assertion failure + try { } catch (...) { } // empty try/catch block needed for failure + } catch (...) { } // this try/catch block needed for failure +} diff --git a/clang/test/CodeGenCXX/PR6474.cpp b/clang/test/CodeGenCXX/PR6474.cpp new file mode 100644 index 0000000..0b155ce --- /dev/null +++ b/clang/test/CodeGenCXX/PR6474.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 %s -emit-llvm-only + +namespace test0 { +template <typename T> struct X { + virtual void foo(); + virtual void bar(); + virtual void baz(); +}; + +template <typename T> void X<T>::foo() {} +template <typename T> void X<T>::bar() {} +template <typename T> void X<T>::baz() {} + +template <> void X<char>::foo() {} +template <> void X<char>::bar() {} +} + +namespace test1 { +template <typename T> struct X { + virtual void foo(); + virtual void bar(); + virtual void baz(); +}; + +template <typename T> void X<T>::foo() {} +template <typename T> void X<T>::bar() {} +template <typename T> void X<T>::baz() {} + +template <> void X<char>::bar() {} +template <> void X<char>::foo() {} +} diff --git a/clang/test/CodeGenCXX/__null.cpp b/clang/test/CodeGenCXX/__null.cpp new file mode 100644 index 0000000..8a17797 --- /dev/null +++ b/clang/test/CodeGenCXX/__null.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 %s -emit-llvm -o %t + +int* a = __null; +int b = __null; + +void f() { + int* c = __null; + int d = __null; +} diff --git a/clang/test/CodeGenCXX/abstract-class-ctors-dtors.cpp b/clang/test/CodeGenCXX/abstract-class-ctors-dtors.cpp new file mode 100644 index 0000000..012c223 --- /dev/null +++ b/clang/test/CodeGenCXX/abstract-class-ctors-dtors.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// Check that we dont emit the complete constructor/destructor for this class. +struct A { + virtual void f() = 0; + A(); + ~A(); +}; + +// CHECK-NOT: define void @_ZN1AC1Ev +// CHECK: define void @_ZN1AC2Ev +// CHECK: define void @_ZN1AD1Ev +// CHECK: define void @_ZN1AD2Ev +A::A() { } + +A::~A() { } diff --git a/clang/test/CodeGenCXX/address-of-fntemplate.cpp b/clang/test/CodeGenCXX/address-of-fntemplate.cpp new file mode 100644 index 0000000..162c6e5 --- /dev/null +++ b/clang/test/CodeGenCXX/address-of-fntemplate.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +template <typename T> void f(T) {} +template <typename T> void f() { } + +void test() { + // CHECK: @_Z1fIiEvT_ + void (*p)(int) = &f; + + // CHECK: @_Z1fIiEvv + void (*p2)() = f<int>; +} +// CHECK: define linkonce_odr void @_Z1fIiEvT_ +// CHECK: define linkonce_odr void @_Z1fIiEvv + +namespace PR6973 { + template<typename T> + struct X { + void f(const T&); + }; + + template<typename T> + int g(); + + void h(X<int (*)()> xf) { + xf.f(&g<int>); + } +} diff --git a/clang/test/CodeGenCXX/alloca-align.cpp b/clang/test/CodeGenCXX/alloca-align.cpp new file mode 100644 index 0000000..99d6ab5 --- /dev/null +++ b/clang/test/CodeGenCXX/alloca-align.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s + +struct s0 { + int Start, End; + unsigned Alignment; + int TheStores __attribute__((aligned(16))); +}; + +// CHECK: define void @f0 +// CHECK: alloca %struct.s0, align 16 +extern "C" void f0() { + (void) s0(); +} + +// CHECK: define void @f1 +// CHECK: alloca %struct.s0, align 16 +extern "C" void f1() { + (void) (struct s0) { 0, 0, 0, 0 }; +} + +// CHECK: define i32 @f2 +// CHECK: alloca %struct.s1, align 2 +struct s1 { short x; short y; }; +extern "C" struct s1 f2(int a, struct s1 *x, struct s1 *y) { + if (a) + return *x; + return *y; +} diff --git a/clang/test/CodeGenCXX/anonymous-namespaces.cpp b/clang/test/CodeGenCXX/anonymous-namespaces.cpp new file mode 100644 index 0000000..32e17a3 --- /dev/null +++ b/clang/test/CodeGenCXX/anonymous-namespaces.cpp @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 -emit-llvm %s -o - > %t +// RUN: FileCheck %s -check-prefix=1 < %t +// RUN: FileCheck %s -check-prefix=2 < %t + +int f(); + +namespace { + // CHECK-1: @_ZN12_GLOBAL__N_11bE = internal global i32 0 + // CHECK-1: @_ZN12_GLOBAL__N_1L1cE = internal global i32 0 + // CHECK-1: @_ZN12_GLOBAL__N_11D1dE = internal global i32 0 + // CHECK-1: @_ZN12_GLOBAL__N_11aE = internal global i32 0 + int a = 0; + + int b = f(); + + static int c = f(); + + class D { + static int d; + }; + + int D::d = f(); + + // Check for generation of a VTT with internal linkage + // CHECK-1: @_ZTSN12_GLOBAL__N_11X1EE = internal constant + struct X { + struct EBase { }; + struct E : public virtual EBase { virtual ~E() {} }; + }; + + // CHECK-1: define internal i32 @_ZN12_GLOBAL__N_13fooEv() + int foo() { + return 32; + } + + // CHECK-1: define internal i32 @_ZN12_GLOBAL__N_11A3fooEv() + namespace A { + int foo() { + return 45; + } + } +} + +int concrete() { + return a + foo() + A::foo(); +} + +void test_XE() { throw X::E(); } + +// Miscompile on llvmc plugins. +namespace test2 { + struct A { + template <class T> struct B { + static void foo() {} + }; + }; + namespace { + struct C; + } + + // CHECK-2: define void @_ZN5test24testEv() + // CHECK-2: call void @_ZN5test21A1BINS_12_GLOBAL__N_11CEE3fooEv() + void test() { + A::B<C>::foo(); + } + + // CHECK-2: define internal void @_ZN5test21A1BINS_12_GLOBAL__N_11CEE3fooEv() +} diff --git a/clang/test/CodeGenCXX/anonymous-union-member-initializer.cpp b/clang/test/CodeGenCXX/anonymous-union-member-initializer.cpp new file mode 100644 index 0000000..a12ae53 --- /dev/null +++ b/clang/test/CodeGenCXX/anonymous-union-member-initializer.cpp @@ -0,0 +1,181 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +// rdar://8818236 +namespace rdar8818236 { +struct S { + char c2; + union { + char c; + int i; + }; +}; + +// CHECK: @_ZN11rdar88182363fooE = global i64 4 +char S::*foo = &S::c; +} + +struct A { + union { + int a; + void* b; + }; + + A() : a(0) { } +}; + +A a; + +namespace PR7021 { + struct X + { + union { long l; }; + }; + + // CHECK: define void @_ZN6PR70211fENS_1XES0_ + void f(X x, X z) { + X x1; + + // CHECK: store i64 1, i64 + x1.l = 1; + + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 + X x2(x1); + + X x3; + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 + x3 = x1; + + // CHECK: ret void + } +} + +namespace test2 { + struct A { + struct { + union { + int b; + }; + }; + + A(); + }; + + A::A() : b(10) { } + // CHECK: define void @_ZN5test21AC2Ev( + // CHECK-NOT: } + // CHECK: store i32 10 + // CHECK: } +} + +namespace PR10512 { + struct A { + A(); + A(int); + A(long); + + struct { + struct {int x;}; + struct {int y;}; + }; + }; + + // CHECK: define void @_ZN7PR105121AC2Ev + // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]] + // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]] + // CHECK-NEXT: [[THIS1:%[a-zA-z0-9.]+]] = load [[A]]** [[THISADDR]] + // CHECK-NEXT: ret void + A::A() {} + + // CHECK: define void @_ZN7PR105121AC2Ei + // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]] + // CHECK-NEXT: [[XADDR:%[a-zA-z0-9.]+]] = alloca i32 + // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]] + // CHECK-NEXT: store i32 [[X:%[a-zA-z0-9.]+]], i32* [[XADDR]] + // CHECK-NEXT: [[THIS1:%[a-zA-z0-9.]+]] = load [[A]]** [[THISADDR]] + // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK-NEXT: [[TMP:%[a-zA-z0-9.]+]] = load i32* [[XADDR]] + // CHECK-NEXT: store i32 [[TMP]] + // CHECK-NEXT: ret void + A::A(int x) : x(x) { } + + // CHECK: define void @_ZN7PR105121AC2El + // CHECK: [[THISADDR:%[a-zA-z0-9.]+]] = alloca [[A:%"struct[A-Za-z0-9:.]+"]] + // CHECK-NEXT: [[XADDR:%[a-zA-z0-9.]+]] = alloca i64 + // CHECK-NEXT: store [[A]]* [[THIS:%[a-zA-z0-9.]+]], [[A]]** [[THISADDR]] + // CHECK-NEXT: store i64 [[X:%[a-zA-z0-9.]+]], i64* [[XADDR]] + // CHECK-NEXT: [[THIS1:%[a-zA-z0-9.]+]] = load [[A]]** [[THISADDR]] + // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 1}} + // CHECK-NEXT: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK-NEXT: [[TMP:%[a-zA-z0-9.]+]] = load i64* [[XADDR]] + // CHECK-NEXT: [[CONV:%[a-zA-z0-9.]+]] = trunc i64 [[TMP]] to i32 + // CHECK-NEXT: store i32 [[CONV]] + // CHECK-NEXT: ret void + A::A(long y) : y(y) { } +} + +namespace test3 { + struct A { + union { + mutable char fibers[100]; + struct { + void (*callback)(void*); + void *callback_value; + }; + }; + + A(); + }; + + A::A() : callback(0), callback_value(0) {} + // CHECK: define void @_ZN5test31AC2Ev( + // CHECK: [[THIS:%.*]] = load + // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0 + // CHECK-NEXT: [[STRUCT:%.*]] = bitcast {{.*}}* [[UNION]] to + // CHECK-NEXT: [[CALLBACK:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 0 + // CHECK: store + // CHECK-NEXT: [[UNION:%.*]] = getelementptr inbounds {{.*}} [[THIS]], i32 0, i32 0 + // CHECK-NEXT: [[STRUCT:%.*]] = bitcast {{.*}}* [[UNION]] to + // CHECK-NEXT: [[CVALUE:%.*]] = getelementptr inbounds {{.*}} [[STRUCT]], i32 0, i32 1 + // CHECK-NEXT: store i8* null, i8** [[CVALUE]] +} + +struct S { + // CHECK: store i32 42 + // CHECK: store i32 55 + S() : x(42), y(55) {} + union { + struct { + int x; + union { int y; }; + }; + }; +} s; + + +//PR8760 +template <typename T> struct Foo { + Foo() : ptr(__nullptr) {} + union { + T *ptr; + }; +}; +Foo<int> f; + +namespace PR9683 { + struct QueueEntry { + union { + struct { + void* mPtr; + union { + unsigned mSubmissionTag; + }; + }; + unsigned mValue; + }; + QueueEntry() {} + }; + QueueEntry QE; +} diff --git a/clang/test/CodeGenCXX/apple-kext-guard-variable.cpp b/clang/test/CodeGenCXX/apple-kext-guard-variable.cpp new file mode 100644 index 0000000..76875a0 --- /dev/null +++ b/clang/test/CodeGenCXX/apple-kext-guard-variable.cpp @@ -0,0 +1,9 @@ +// RUN: %clang -target x86_64-apple-darwin10 -S -o %t.s -mkernel -Xclang -verify %s + +// rdar://problem/9143356 + +int foo(); +void test() { + static int y = 0; + static int x = foo(); // expected-error {{this initialization requires a guard variable, which the kernel does not support}} +} diff --git a/clang/test/CodeGenCXX/apple-kext-indirect-call-2.C b/clang/test/CodeGenCXX/apple-kext-indirect-call-2.C new file mode 100644 index 0000000..7e25200 --- /dev/null +++ b/clang/test/CodeGenCXX/apple-kext-indirect-call-2.C @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -fno-rtti -emit-llvm -o - %s | FileCheck %s + +// CHECK: @_ZTV1A = unnamed_addr constant [4 x i8*] [i8* null, i8* null, i8* bitcast (i8* (%struct.A*)* @_ZNK1A3abcEv to i8*), i8* null] +// CHECK: @_ZTV4Base = unnamed_addr constant [4 x i8*] [i8* null, i8* null, i8* bitcast (i8* (%struct.A*)* @_ZNK4Base3abcEv to i8*), i8* null] +// CHECK: @_ZTV8Derived2 = unnamed_addr constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (i8* (%struct.A*)* @_ZNK8Derived23efgEv to i8*), i8* null] +// CHECK: @_ZTV2D2 = unnamed_addr constant [5 x i8*] [i8* null, i8* null, i8* null, i8* bitcast (i8* (%struct.A*)* @_ZNK2D23abcEv to i8*), i8* null] + +struct A { + virtual const char* abc(void) const; +}; + +const char* A::abc(void) const {return "A"; }; + +struct B : virtual A { + virtual void VF(); +}; + +void B::VF() {} + +void FUNC(B* p) { +// CHECK: [[T1:%.*]] = load i8* (%struct.A*)** getelementptr inbounds (i8* (%struct.A*)** bitcast ([4 x i8*]* @_ZTV1A to i8* (%struct.A*)**), i64 2) +// CHECK-NEXT: [[T2:%.*]] = call i8* [[T1]] + const char* c = p->A::abc(); +} + + +// Test2 +struct Base { virtual char* abc(void) const; }; + +char* Base::abc() const { return 0; } + +struct Derived : public Base { +}; + +void FUNC1(Derived* p) { +// CHECK: [[U1:%.*]] = load i8* (%struct.A*)** getelementptr inbounds (i8* (%struct.A*)** bitcast ([4 x i8*]* @_ZTV4Base to i8* (%struct.A*)**), i64 2) +// CHECK-NEXT: [[U2:%.*]] = call i8* [[U1]] + char* c = p->Base::abc(); +} + + +// Test3 +struct Base2 { }; + +struct Derived2 : virtual Base2 { + virtual char* efg(void) const; +}; + +char* Derived2::efg(void) const { return 0; } + +void FUNC2(Derived2* p) { +// CHECK: [[V1:%.*]] = load i8* (%struct.A*)** getelementptr inbounds (i8* (%struct.A*)** bitcast ([5 x i8*]* @_ZTV8Derived2 to i8* (%struct.A*)**), i64 3) +// CHECK-NEXT: [[V2:%.*]] = call i8* [[V1]] + char* c = p->Derived2::efg(); +} + +// Test4 +struct Base3 { }; + +struct D1 : virtual Base3 { +}; + +struct D2 : virtual Base3 { + virtual char *abc(void) const; +}; + +struct Sub : D1, D2 { +}; + +char* D2::abc(void) const { return 0; } + +void FUNC3(Sub* p) { +// CHECK: [[W1:%.*]] = load i8* (%struct.A*)** getelementptr inbounds (i8* (%struct.A*)** bitcast ([5 x i8*]* @_ZTV2D2 to i8* (%struct.A*)**), i64 3) +// CHECK-NEXT: [[W2:%.*]] = call i8* [[W1]] + char* c = p->D2::abc(); +} + diff --git a/clang/test/CodeGenCXX/apple-kext-indirect-call.C b/clang/test/CodeGenCXX/apple-kext-indirect-call.C new file mode 100644 index 0000000..2dbb0b8 --- /dev/null +++ b/clang/test/CodeGenCXX/apple-kext-indirect-call.C @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -emit-llvm -o - %s | FileCheck %s + +struct Base { + virtual void abc(void) const; +}; + +void Base::abc(void) const {} + +void FUNC(Base* p) { + p->Base::abc(); +} + +// CHECK: getelementptr inbounds (void (%struct.Base*)** bitcast ([3 x i8*]* @_ZTV4Base to void (%struct.Base*)**), i64 2) +// CHECK-NOT: call void @_ZNK4Base3abcEv diff --git a/clang/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp b/clang/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp new file mode 100644 index 0000000..bd275f1 --- /dev/null +++ b/clang/test/CodeGenCXX/apple-kext-indirect-virtual-dtor-call.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -fno-rtti -emit-llvm -o - %s | FileCheck %s + +// CHECK: define void @_ZN2B1D0Ev +// CHECK: [[T1:%.*]] = load void (%struct.B1*)** getelementptr inbounds (void (%struct.B1*)** bitcast ([5 x i8*]* @_ZTV2B1 to void (%struct.B1*)**), i64 2) +// CHECK-NEXT: call void [[T1]](%struct.B1* [[T2:%.*]]) +// CHECK: define void @_Z6DELETEP2B1 +// CHECK: [[T3:%.*]] = load void (%struct.B1*)** getelementptr inbounds (void (%struct.B1*)** bitcast ([5 x i8*]* @_ZTV2B1 to void (%struct.B1*)**), i64 2) +// CHECK-NEXT: call void [[T3]](%struct.B1* [[T4:%.*]]) + + +struct B1 { + virtual ~B1(); +}; + +B1::~B1() {} + +void DELETE(B1 *pb1) { + pb1->B1::~B1(); +} diff --git a/clang/test/CodeGenCXX/apple-kext-linkage.C b/clang/test/CodeGenCXX/apple-kext-linkage.C new file mode 100644 index 0000000..59d228e --- /dev/null +++ b/clang/test/CodeGenCXX/apple-kext-linkage.C @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -emit-llvm -o - %s | FileCheck %s + +struct Base { + virtual ~Base(); +} ; + +struct Derived : Base { + void operator delete(void *) { } + Derived(); +}; + +void foo() { + Derived d1; // ok +} + +// CHECK: define internal i32 @_Z1fj( +inline unsigned f(unsigned n) { return n == 0 ? 0 : n + f(n-1); } + +unsigned g(unsigned n) { return f(n); } + +// rdar://problem/10133200: give explicit instantiations external linkage in kernel mode +// CHECK: define void @_Z3barIiEvv() +template <typename T> void bar() {} +template void bar<int>(); + +// CHECK: define internal i32 @_Z5identIiET_S0_( +template <typename X> X ident(X x) { return x; } + +int foo(int n) { return ident(n); } + +// CHECK: define internal void @_ZN7DerivedD1Ev( +// CHECK: define internal void @_ZN7DerivedD0Ev( +// CHECK: define internal void @_ZN7DeriveddlEPv( diff --git a/clang/test/CodeGenCXX/apple-kext-no-staticinit-section.C b/clang/test/CodeGenCXX/apple-kext-no-staticinit-section.C new file mode 100644 index 0000000..0401d49 --- /dev/null +++ b/clang/test/CodeGenCXX/apple-kext-no-staticinit-section.C @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fapple-kext -fno-rtti -emit-llvm -o - %s | FileCheck %s +// rdar://8825235 +/** +1) Normally, global object construction code ends up in __StaticInit segment of text section + .section __TEXT,__StaticInit,regular,pure_instructions + In kext mode, they end up in the __text segment. +*/ + +class foo { +public: + foo(); + virtual ~foo(); +}; + +foo a; +foo b; +foo c; +foo::~foo() {} + +// CHECK-NOT: __TEXT,__StaticInit,regular,pure_instructions diff --git a/clang/test/CodeGenCXX/apple-kext.cpp b/clang/test/CodeGenCXX/apple-kext.cpp new file mode 100644 index 0000000..03506a8 --- /dev/null +++ b/clang/test/CodeGenCXX/apple-kext.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fno-use-cxa-atexit -fapple-kext -emit-llvm -o - %s | FileCheck %s + +// CHECK: @_ZN5test01aE = global [[A:%.*]] zeroinitializer +// CHECK: @llvm.global_ctors = appending global {{.*}} { i32 65535, void ()* [[CTOR0:@.*]] } +// CHECK: @llvm.global_dtors = appending global {{.*}} { i32 65535, void ()* [[DTOR0:@.*]] } + +// rdar://11241230 +namespace test0 { + struct A { A(); ~A(); }; + A a; +} +// CHECK: define internal void [[CTOR0_:@.*]]() +// CHECK: call void @_ZN5test01AC1Ev([[A]]* @_ZN5test01aE) +// CHECK-NEXT: ret void + +// CHECK: define internal void [[CTOR0]]() +// CHECK: call void [[CTOR0_]]() +// CHECK-NEXT: ret void + +// CHECK: define internal void [[DTOR0]]() +// CHECK: call void @_ZN5test01AD1Ev([[A]]* @_ZN5test01aE) +// CHECK-NEXT: ret void diff --git a/clang/test/CodeGenCXX/arm-cc.cpp b/clang/test/CodeGenCXX/arm-cc.cpp new file mode 100644 index 0000000..6027746 --- /dev/null +++ b/clang/test/CodeGenCXX/arm-cc.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 %s -triple=arm-unknown-linux-gnueabi -target-abi aapcs -emit-llvm -o - | FileCheck %s + +class SMLoc { + const char *Ptr; +public: + SMLoc(); + SMLoc(const SMLoc &RHS); +}; +SMLoc foo(void *p); +void bar(void *x) { + foo(x); +} +void zed(SMLoc x); +void baz() { + SMLoc a; + zed(a); +} + +// CHECK: declare void @_Z3fooPv(%class.SMLoc* sret, i8*) +// CHECK: declare void @_Z3zed5SMLoc(%class.SMLoc*) diff --git a/clang/test/CodeGenCXX/arm.cpp b/clang/test/CodeGenCXX/arm.cpp new file mode 100644 index 0000000..6c60f30 --- /dev/null +++ b/clang/test/CodeGenCXX/arm.cpp @@ -0,0 +1,369 @@ +// RUN: %clang_cc1 %s -triple=thumbv7-apple-ios3.0 -fno-use-cxa-atexit -target-abi apcs-gnu -emit-llvm -o - -fexceptions | FileCheck %s + +// CHECK: @_ZZN5test74testEvE1x = internal global i32 0, align 4 +// CHECK: @_ZGVZN5test74testEvE1x = internal global i32 0 +// CHECK: @_ZZN5test84testEvE1x = internal global [[TEST8A:.*]] zeroinitializer, align 1 +// CHECK: @_ZGVZN5test84testEvE1x = internal global i32 0 + +typedef typeof(sizeof(int)) size_t; + +class foo { +public: + foo(); + virtual ~foo(); +}; + +class bar : public foo { +public: + bar(); +}; + +// The global dtor needs the right calling conv with -fno-use-cxa-atexit +// rdar://7817590 +bar baz; + +// PR9593 +// Make sure atexit(3) is used for global dtors. + +// CHECK: call [[BAR:%.*]]* @_ZN3barC1Ev( +// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_baz) + +// CHECK: define internal void @__dtor_baz() +// CHECK: call [[BAR]]* @_ZN3barD1Ev([[BAR]]* @baz) + +// Destructors and constructors must return this. +namespace test1 { + void foo(); + + struct A { + A(int i) { foo(); } + ~A() { foo(); } + void bar() { foo(); } + }; + + // CHECK: define void @_ZN5test14testEv() + void test() { + // CHECK: [[AV:%.*]] = alloca [[A:%.*]], align 1 + // CHECK: call [[A]]* @_ZN5test11AC1Ei([[A]]* [[AV]], i32 10) + // CHECK: invoke void @_ZN5test11A3barEv([[A]]* [[AV]]) + // CHECK: call [[A]]* @_ZN5test11AD1Ev([[A]]* [[AV]]) + // CHECK: ret void + A a = 10; + a.bar(); + } + + // CHECK: define linkonce_odr [[A]]* @_ZN5test11AC1Ei([[A]]* %this, i32 %i) unnamed_addr + // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 + // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] + // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] + // CHECK: call [[A]]* @_ZN5test11AC2Ei( + // CHECK: ret [[A]]* [[THIS1]] + + // CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr + // CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4 + // CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]] + // CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]] + // CHECK: call [[A]]* @_ZN5test11AD2Ev( + // CHECK: ret [[A]]* [[THIS1]] +} + +// Awkward virtual cases. +namespace test2 { + void foo(); + + struct A { + int x; + + A(int); + virtual ~A() { foo(); } + }; + + struct B { + int y; + int z; + + B(int); + virtual ~B() { foo(); } + }; + + struct C : A, virtual B { + int q; + + C(int i) : A(i), B(i) { foo(); } + ~C() { foo(); } + }; + + void test() { + C c = 10; + } + + // Tests at eof +} + +namespace test3 { + struct A { + int x; + ~A(); + }; + + void a() { + // CHECK: define void @_ZN5test31aEv() + // CHECK: call noalias i8* @_Znam(i32 48) + // CHECK: store i32 4 + // CHECK: store i32 10 + A *x = new A[10]; + } + + void b(int n) { + // CHECK: define void @_ZN5test31bEi( + // CHECK: [[N:%.*]] = load i32* + // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 4) + // CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8) + // CHECK: [[OR:%.*]] = or i1 + // CHECK: [[SZ:%.*]] = select i1 [[OR]] + // CHECK: call noalias i8* @_Znam(i32 [[SZ]]) + // CHECK: store i32 4 + // CHECK: store i32 [[N]] + A *x = new A[n]; + } + + void c() { + // CHECK: define void @_ZN5test31cEv() + // CHECK: call noalias i8* @_Znam(i32 808) + // CHECK: store i32 4 + // CHECK: store i32 200 + A (*x)[20] = new A[10][20]; + } + + void d(int n) { + // CHECK: define void @_ZN5test31dEi( + // CHECK: [[N:%.*]] = load i32* + // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 80) + // CHECK: [[NE:%.*]] = mul i32 [[N]], 20 + // CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8) + // CHECK: [[SZ:%.*]] = select + // CHECK: call noalias i8* @_Znam(i32 [[SZ]]) + // CHECK: store i32 4 + // CHECK: store i32 [[NE]] + A (*x)[20] = new A[n][20]; + } + + void e(A *x) { + // CHECK: define void @_ZN5test31eEPNS_1AE( + // CHECK: icmp eq {{.*}}, null + // CHECK: getelementptr {{.*}}, i64 -8 + // CHECK: getelementptr {{.*}}, i64 4 + // CHECK: bitcast {{.*}} to i32* + // CHECK: load + // CHECK: invoke {{.*}} @_ZN5test31AD1Ev + // CHECK: call void @_ZdaPv + delete [] x; + } + + void f(A (*x)[20]) { + // CHECK: define void @_ZN5test31fEPA20_NS_1AE( + // CHECK: icmp eq {{.*}}, null + // CHECK: getelementptr {{.*}}, i64 -8 + // CHECK: getelementptr {{.*}}, i64 4 + // CHECK: bitcast {{.*}} to i32* + // CHECK: load + // CHECK: invoke {{.*}} @_ZN5test31AD1Ev + // CHECK: call void @_ZdaPv + delete [] x; + } +} + +namespace test4 { + struct A { + int x; + void operator delete[](void *, size_t sz); + }; + + void a() { + // CHECK: define void @_ZN5test41aEv() + // CHECK: call noalias i8* @_Znam(i32 48) + // CHECK: store i32 4 + // CHECK: store i32 10 + A *x = new A[10]; + } + + void b(int n) { + // CHECK: define void @_ZN5test41bEi( + // CHECK: [[N:%.*]] = load i32* + // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 4) + // CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8) + // CHECK: [[SZ:%.*]] = select + // CHECK: call noalias i8* @_Znam(i32 [[SZ]]) + // CHECK: store i32 4 + // CHECK: store i32 [[N]] + A *x = new A[n]; + } + + void c() { + // CHECK: define void @_ZN5test41cEv() + // CHECK: call noalias i8* @_Znam(i32 808) + // CHECK: store i32 4 + // CHECK: store i32 200 + A (*x)[20] = new A[10][20]; + } + + void d(int n) { + // CHECK: define void @_ZN5test41dEi( + // CHECK: [[N:%.*]] = load i32* + // CHECK: @llvm.umul.with.overflow.i32(i32 [[N]], i32 80) + // CHECK: [[NE:%.*]] = mul i32 [[N]], 20 + // CHECK: @llvm.uadd.with.overflow.i32(i32 {{.*}}, i32 8) + // CHECK: [[SZ:%.*]] = select + // CHECK: call noalias i8* @_Znam(i32 [[SZ]]) + // CHECK: store i32 4 + // CHECK: store i32 [[NE]] + A (*x)[20] = new A[n][20]; + } + + void e(A *x) { + // CHECK: define void @_ZN5test41eEPNS_1AE( + // CHECK: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8 + // CHECK: getelementptr inbounds {{.*}}, i64 4 + // CHECK: bitcast + // CHECK: [[T0:%.*]] = load i32* + // CHECK: [[T1:%.*]] = mul i32 4, [[T0]] + // CHECK: [[T2:%.*]] = add i32 [[T1]], 8 + // CHECK: call void @_ZN5test41AdaEPvm(i8* [[ALLOC]], i32 [[T2]]) + delete [] x; + } + + void f(A (*x)[20]) { + // CHECK: define void @_ZN5test41fEPA20_NS_1AE( + // CHECK: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8 + // CHECK: getelementptr inbounds {{.*}}, i64 4 + // CHECK: bitcast + // CHECK: [[T0:%.*]] = load i32* + // CHECK: [[T1:%.*]] = mul i32 4, [[T0]] + // CHECK: [[T2:%.*]] = add i32 [[T1]], 8 + // CHECK: call void @_ZN5test41AdaEPvm(i8* [[ALLOC]], i32 [[T2]]) + delete [] x; + } +} + +// <rdar://problem/8386802>: don't crash +namespace test5 { + struct A { + ~A(); + }; + + // CHECK: define void @_ZN5test54testEPNS_1AE + void test(A *a) { + // CHECK: [[PTR:%.*]] = alloca [[A:%.*]]*, align 4 + // CHECK-NEXT: store [[A]]* {{.*}}, [[A]]** [[PTR]], align 4 + // CHECK-NEXT: [[TMP:%.*]] = load [[A]]** [[PTR]], align 4 + // CHECK-NEXT: call [[A]]* @_ZN5test51AD1Ev([[A]]* [[TMP]]) + // CHECK-NEXT: ret void + a->~A(); + } +} + +namespace test6 { + struct A { + virtual ~A(); + }; + + // CHECK: define void @_ZN5test64testEPNS_1AE + void test(A *a) { + // CHECK: [[AVAR:%.*]] = alloca [[A:%.*]]*, align 4 + // CHECK-NEXT: store [[A]]* {{.*}}, [[A]]** [[AVAR]], align 4 + // CHECK-NEXT: [[V:%.*]] = load [[A]]** [[AVAR]], align 4 + // CHECK-NEXT: [[ISNULL:%.*]] = icmp eq [[A]]* [[V]], null + // CHECK-NEXT: br i1 [[ISNULL]] + // CHECK: [[T0:%.*]] = bitcast [[A]]* [[V]] to [[A]]* ([[A]]*)*** + // CHECK-NEXT: [[T1:%.*]] = load [[A]]* ([[A]]*)*** [[T0]] + // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* ([[A]]*)** [[T1]], i64 1 + // CHECK-NEXT: [[T3:%.*]] = load [[A]]* ([[A]]*)** [[T2]] + // CHECK-NEXT: call [[A]]* [[T3]]([[A]]* [[V]]) + // CHECK-NEXT: br label + // CHECK: ret void + delete a; + } +} + +namespace test7 { + int foo(); + + // Static and guard tested at top of file + + // CHECK: define void @_ZN5test74testEv() + void test() { + // CHECK: [[T0:%.*]] = load i32* @_ZGVZN5test74testEvE1x + // CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0 + // CHECK-NEXT: br i1 [[T2]] + // -> fallthrough, end + // CHECK: [[T3:%.*]] = call i32 @__cxa_guard_acquire(i32* @_ZGVZN5test74testEvE1x) + // CHECK-NEXT: [[T4:%.*]] = icmp ne i32 [[T3]], 0 + // CHECK-NEXT: br i1 [[T4]] + // -> fallthrough, end + // CHECK: [[INIT:%.*]] = invoke i32 @_ZN5test73fooEv() + // CHECK: store i32 [[INIT]], i32* @_ZZN5test74testEvE1x, align 4 + // CHECK-NEXT: call void @__cxa_guard_release(i32* @_ZGVZN5test74testEvE1x) + // CHECK-NEXT: br label + // -> end + // end: + // CHECK: ret void + static int x = foo(); + + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: cleanup + // CHECK: call void @__cxa_guard_abort(i32* @_ZGVZN5test74testEvE1x) + // CHECK: resume { i8*, i32 } + } +} + +namespace test8 { + struct A { + A(); + ~A(); + }; + + // Static and guard tested at top of file + + // CHECK: define void @_ZN5test84testEv() + void test() { + // CHECK: [[T0:%.*]] = load i32* @_ZGVZN5test84testEvE1x + // CHECK-NEXT: [[T1:%.*]] = and i32 [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = icmp eq i32 [[T1]], 0 + // CHECK-NEXT: br i1 [[T2]] + // -> fallthrough, end + // CHECK: [[T3:%.*]] = call i32 @__cxa_guard_acquire(i32* @_ZGVZN5test84testEvE1x) + // CHECK-NEXT: [[T4:%.*]] = icmp ne i32 [[T3]], 0 + // CHECK-NEXT: br i1 [[T4]] + // -> fallthrough, end + // CHECK: [[INIT:%.*]] = invoke [[TEST8A]]* @_ZN5test81AC1Ev([[TEST8A]]* @_ZZN5test84testEvE1x) + + // FIXME: Here we register a global destructor that + // unconditionally calls the destructor. That's what we've always + // done for -fno-use-cxa-atexit here, but that's really not + // semantically correct at all. + + // CHECK: call void @__cxa_guard_release(i32* @_ZGVZN5test84testEvE1x) + // CHECK-NEXT: br label + // -> end + // end: + // CHECK: ret void + static A x; + + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: cleanup + // CHECK: call void @__cxa_guard_abort(i32* @_ZGVZN5test84testEvE1x) + // CHECK: resume { i8*, i32 } + } +} + + // CHECK: define linkonce_odr [[C:%.*]]* @_ZTv0_n12_N5test21CD1Ev( + // CHECK: call [[C]]* @_ZN5test21CD1Ev( + // CHECK: ret [[C]]* undef + + // CHECK: define linkonce_odr void @_ZTv0_n12_N5test21CD0Ev( + // CHECK: call void @_ZN5test21CD0Ev( + // CHECK: ret void + +// CH_ECK: @_GLOBAL__D_a() +// CH_ECK: call %class.bar* @_ZN3barD1Ev(%class.bar* @baz) diff --git a/clang/test/CodeGenCXX/array-construction.cpp b/clang/test/CodeGenCXX/array-construction.cpp new file mode 100644 index 0000000..7b565a4 --- /dev/null +++ b/clang/test/CodeGenCXX/array-construction.cpp @@ -0,0 +1,37 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +extern "C" int printf(...); + +static int count; +static float fcount; + +class xpto { +public: + xpto() : i(count++), f(fcount++) { + printf("xpto::xpto()\n"); + } + int i; + float f; + + ~xpto() { + printf("xpto::~xpto()\n"); + } +}; + +int main() { + xpto array[2][3][4]; + for (int h = 0; h < 2; h++) + for (int i = 0; i < 3; i++) + for (int j = 0; j < 4; j++) + printf("array[%d][%d][%d] = {%d, %f}\n", + h, i, j, array[h][i][j].i, array[h][i][j].f); +} + +// CHECK-LP64: callq __ZN4xptoC1Ev + +// CHECK-LP32: calll L__ZN4xptoC1Ev + diff --git a/clang/test/CodeGenCXX/array-operator-delete-call.cpp b/clang/test/CodeGenCXX/array-operator-delete-call.cpp new file mode 100644 index 0000000..1b23c4d --- /dev/null +++ b/clang/test/CodeGenCXX/array-operator-delete-call.cpp @@ -0,0 +1,64 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +extern "C" int printf(...); + +int count; + +struct S { + S() : iS (++count) { printf("S::S(%d)\n", iS); } + ~S() { printf("S::~S(%d)\n", iS); } + int iS; +}; + +struct V { + V() : iV (++count) { printf("V::V(%d)\n", iV); } + virtual ~V() { printf("V::~V(%d)\n", iV); } + int iV; +}; + +struct COST +{ + S *cost; + V *vcost; + unsigned *cost_val; + + ~COST(); + COST(); +}; + + +COST::COST() +{ + cost = new S[3]; + vcost = new V[4]; + cost_val = new unsigned[10]; +} + +COST::~COST() +{ + if (cost) { + delete [] cost; + } + if (vcost) { + delete [] vcost; + } + if (cost_val) + delete [] cost_val; +} + +COST c1; + +int main() +{ + COST c3; +} +COST c2; + +// CHECK-LP64: callq __ZdaPv + +// CHECK-LP32: calll L__ZdaPv + diff --git a/clang/test/CodeGenCXX/array-pointer-decay.cpp b/clang/test/CodeGenCXX/array-pointer-decay.cpp new file mode 100644 index 0000000..3fe6b72 --- /dev/null +++ b/clang/test/CodeGenCXX/array-pointer-decay.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - + +void f(const char*); + +void g() { + f("hello"); +} diff --git a/clang/test/CodeGenCXX/array-value-initialize.cpp b/clang/test/CodeGenCXX/array-value-initialize.cpp new file mode 100644 index 0000000..27607c1 --- /dev/null +++ b/clang/test/CodeGenCXX/array-value-initialize.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s +// RUN: %clang_cc1 -triple i386-apple-darwin -emit-llvm -o - %s + +// PR5463 +extern "C" int printf(...); + +struct S { + double filler; +}; + +struct Foo { + Foo(void) : bar_(), dbar_(), sbar_() { + for (int i = 0; i < 5; i++) { + printf("bar_[%d] = %d\n", i, bar_[i]); + printf("dbar_[%d] = %f\n", i, dbar_[i]); + printf("sbar_[%d].filler = %f\n", i, sbar_[i].filler); + } + } + + int bar_[5]; + double dbar_[5]; + S sbar_[5]; +}; + +int test1(void) { + Foo a; +} + +// PR7063 + + +struct Unit +{ + Unit() {} + Unit(const Unit& v) {} +}; + + +struct Stuff +{ + Unit leafPos[1]; +}; + + +int main() +{ + + Stuff a; + Stuff b = a; + + return 0; +} diff --git a/clang/test/CodeGenCXX/asm.cpp b/clang/test/CodeGenCXX/asm.cpp new file mode 100644 index 0000000..3b745a7 --- /dev/null +++ b/clang/test/CodeGenCXX/asm.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s + +struct A +{ + ~A(); +}; +int foo(A); + +void bar(A &a) +{ + // CHECK: call void asm + asm("" : : "r"(foo(a)) ); // rdar://8540491 + // CHECK: call void @_ZN1AD1Ev +} diff --git a/clang/test/CodeGenCXX/assign-operator.cpp b/clang/test/CodeGenCXX/assign-operator.cpp new file mode 100644 index 0000000..e19df27 --- /dev/null +++ b/clang/test/CodeGenCXX/assign-operator.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -verify -o - |FileCheck %s + +class x { +public: int operator=(int); +}; +void a() { + x a; + a = 1u; +} + +void f(int i, int j) { + // CHECK: load i32 + // CHECK: load i32 + // CHECK: add nsw i32 + // CHECK: store i32 + // CHECK: store i32 17, i32 + // CHECK: ret + (i += j) = 17; +} + +// Taken from g++.old-deja/g++.jason/net.C +namespace test1 { + template <class T> void fn (T t) { } + template <class T> struct A { + void (*p)(T); + A() { p = fn; } + }; + + A<int> a; +} diff --git a/clang/test/CodeGenCXX/atomic.cpp b/clang/test/CodeGenCXX/atomic.cpp new file mode 100644 index 0000000..36bb4ef --- /dev/null +++ b/clang/test/CodeGenCXX/atomic.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i686-apple-darwin9 | FileCheck %s + +namespace PR11411 { + template<typename _Tp> struct Ptr { + void f(); + }; + + // CHECK: define linkonce_odr void @_ZN7PR114113PtrIiE1fEv + // CHECK-NOT: ret + template<typename _Tp> inline void Ptr<_Tp>::f() { + int* _refcount; + // CHECK: atomicrmw add i32* + __sync_fetch_and_add(_refcount, 1); + // CHECK-NEXT: ret void + } + void f(Ptr<int> *a) { a->f(); } +} diff --git a/clang/test/CodeGenCXX/atomicinit.cpp b/clang/test/CodeGenCXX/atomicinit.cpp new file mode 100644 index 0000000..38d012e --- /dev/null +++ b/clang/test/CodeGenCXX/atomicinit.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 %s -emit-llvm -O1 -o - -triple=i686-apple-darwin9 | FileCheck %s +struct A { + _Atomic(int) i; + A(int j); + void v(int j); +}; +// Storing to atomic values should be atomic +// CHECK: store atomic i32 +void A::v(int j) { i = j; } +// Initialising atomic values should not be atomic +// CHECK-NOT: store atomic +A::A(int j) : i(j) {} + +struct B { + int i; + B(int x) : i(x) {} +}; + +_Atomic(B) b; + +// CHECK: define void @_Z11atomic_initR1Ai +void atomic_init(A& a, int i) { + // CHECK-NOT: atomic + // CHECK: tail call void @_ZN1BC1Ei + __c11_atomic_init(&b, B(i)); + // CHECK-NEXT: ret void +} + +// CHECK: define void @_Z16atomic_init_boolPU7_Atomicbb +void atomic_init_bool(_Atomic(bool) *ab, bool b) { + // CHECK-NOT: atomic + // CHECK: {{zext i1.*to i8}} + // CHECK-NEXT: store i8 + __c11_atomic_init(ab, b); + // CHECK-NEXT: ret void +} + +struct AtomicBoolMember { + _Atomic(bool) ab; + AtomicBoolMember(bool b); +}; + +// CHECK: define void @_ZN16AtomicBoolMemberC2Eb +// CHECK: {{zext i1.*to i8}} +// CHECK-NEXT: store i8 +// CHECK-NEXT: ret void +AtomicBoolMember::AtomicBoolMember(bool b) : ab(b) { } + diff --git a/clang/test/CodeGenCXX/attr-used.cpp b/clang/test/CodeGenCXX/attr-used.cpp new file mode 100644 index 0000000..2c82184 --- /dev/null +++ b/clang/test/CodeGenCXX/attr-used.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +// <rdar://problem/8684363>: clang++ not respecting __attribute__((used)) on destructors +struct X0 { + // CHECK: define linkonce_odr {{.*}} @_ZN2X0C1Ev + __attribute__((used)) X0() {} + // CHECK: define linkonce_odr {{.*}} @_ZN2X0D1Ev + __attribute__((used)) ~X0() {} +}; diff --git a/clang/test/CodeGenCXX/attr.cpp b/clang/test/CodeGenCXX/attr.cpp new file mode 100644 index 0000000..9e8740e --- /dev/null +++ b/clang/test/CodeGenCXX/attr.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s | FileCheck %s + +// CHECK: @test2 = alias i32 ()* @_Z5test1v + +// CHECK: define i32 @_Z3foov() nounwind align 1024 +int foo() __attribute__((aligned(1024))); +int foo() { } + +class C { + virtual void bar1() __attribute__((aligned(1))); + virtual void bar2() __attribute__((aligned(2))); + virtual void bar3() __attribute__((aligned(1024))); +} c; + +// CHECK: define void @_ZN1C4bar1Ev(%class.C* %this) nounwind align 2 +void C::bar1() { } + +// CHECK: define void @_ZN1C4bar2Ev(%class.C* %this) nounwind align 2 +void C::bar2() { } + +// CHECK: define void @_ZN1C4bar3Ev(%class.C* %this) nounwind align 1024 +void C::bar3() { } + +// PR6635 +// CHECK: define i32 @_Z5test1v() +int test1() { return 10; } +// CHECK at top of file +extern "C" int test2() __attribute__((alias("_Z5test1v"))); diff --git a/clang/test/CodeGenCXX/bitfield-layout.cpp b/clang/test/CodeGenCXX/bitfield-layout.cpp new file mode 100644 index 0000000..15f33d2 --- /dev/null +++ b/clang/test/CodeGenCXX/bitfield-layout.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix LP64 %s +// RUN: %clang_cc1 %s -triple=i386-apple-darwin10 -emit-llvm -o - -O3 | FileCheck -check-prefix LP32 %s + +// CHECK-LP64: %union.Test1 = type { i32, [4 x i8] } +union Test1 { + int a; + int b: 39; +} t1; + +// CHECK-LP64: %union.Test2 = type { i8 } +union Test2 { + int : 6; +} t2; + +// CHECK-LP64: %union.Test3 = type { [2 x i8] } +union Test3 { + int : 9; +} t3; + + +#define CHECK(x) if (!(x)) return __LINE__ + +int f() { + struct { + int a; + + unsigned long long b : 65; + + int c; + } c; + + c.a = 0; + c.b = (unsigned long long)-1; + c.c = 0; + + CHECK(c.a == 0); + CHECK(c.b == (unsigned long long)-1); + CHECK(c.c == 0); + +// CHECK-LP64: ret i32 0 +// CHECK-LP32: ret i32 0 + return 0; +} diff --git a/clang/test/CodeGenCXX/block-byref-cxx-objc.cpp b/clang/test/CodeGenCXX/block-byref-cxx-objc.cpp new file mode 100644 index 0000000..30f1f07 --- /dev/null +++ b/clang/test/CodeGenCXX/block-byref-cxx-objc.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks | FileCheck %s +// rdar://8594790 + +struct A { + int x; + A(const A &); + A(); + ~A(); +}; + +int main() +{ + __block A BYREF_VAR; + ^{ BYREF_VAR.x = 1234; }; + return 0; +} + +// CHECK: define internal void @__Block_byref_object_copy_ +// CHECK: call {{.*}} @_ZN1AC1ERKS_ +// CHECK: define internal void @__Block_byref_object_dispose_ +// CHECK: call {{.*}} @_ZN1AD1Ev +// CHECK: define internal void @__copy_helper_block_ +// CHECK: call void @_Block_object_assign +// CHECK: define internal void @__destroy_helper_block_ +// CHECK: call void @_Block_object_dispose + +// rdar://problem/11135650 +namespace test1 { + struct A { int x; A(); ~A(); }; + + void test() { + return; + __block A a; + } +} diff --git a/clang/test/CodeGenCXX/block-destruct.cpp b/clang/test/CodeGenCXX/block-destruct.cpp new file mode 100644 index 0000000..f809ca2 --- /dev/null +++ b/clang/test/CodeGenCXX/block-destruct.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s + +struct A { ~A(); }; + +void f() { + __block A a; +} + +// CHECK: call void @_ZN1AD1Ev diff --git a/clang/test/CodeGenCXX/block-in-ctor-dtor.cpp b/clang/test/CodeGenCXX/block-in-ctor-dtor.cpp new file mode 100644 index 0000000..e4389a4 --- /dev/null +++ b/clang/test/CodeGenCXX/block-in-ctor-dtor.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s + +typedef void (^dispatch_block_t)(void); + +void dispatch_once(dispatch_block_t); + +class Zone { +public: + Zone(); + ~Zone(); +}; + +Zone::Zone() { + dispatch_once(^{}); + dispatch_once(^{}); +} + +Zone::~Zone() { + dispatch_once(^{}); + dispatch_once(^{}); +} + +class X : public virtual Zone { + X(); + ~X(); +}; + +X::X() { + dispatch_once(^{}); + dispatch_once(^{}); +}; + +X::~X() { + dispatch_once(^{}); + dispatch_once(^{}); +}; + + +// CHECK: define internal void @___ZN4ZoneC2Ev_block_invoke_ +// CHECK: define internal void @___ZN4ZoneC2Ev_block_invoke_ +// CHECK: define internal void @___ZN4ZoneD2Ev_block_invoke_ +// CHECK: define internal void @___ZN4ZoneD2Ev_block_invoke_ +// CHECK: define internal void @___ZN1XC1Ev_block_invoke_ +// CHECK: define internal void @___ZN1XC1Ev_block_invoke_ +// CHECK: define internal void @___ZN1XC2Ev_block_invoke_ +// CHECK: define internal void @___ZN1XC2Ev_block_invoke_ +// CHECK: define internal void @___ZN1XD2Ev_block_invoke_ +// CHECK: define internal void @___ZN1XD2Ev_block_invoke_ diff --git a/clang/test/CodeGenCXX/block.cpp b/clang/test/CodeGenCXX/block.cpp new file mode 100644 index 0000000..619d8b0 --- /dev/null +++ b/clang/test/CodeGenCXX/block.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -fblocks +// Just test that this doesn't crash the compiler... + +void func(void*); + +struct Test +{ + virtual void use() { func((void*)this); } + Test(Test&c) { func((void*)this); } + Test() { func((void*)this); } +}; + +void useBlock(void (^)(void)); + +int main (void) { + __block Test t; + useBlock(^(void) { t.use(); }); +} + diff --git a/clang/test/CodeGenCXX/blocks-cxx11.cpp b/clang/test/CodeGenCXX/blocks-cxx11.cpp new file mode 100644 index 0000000..996db1a --- /dev/null +++ b/clang/test/CodeGenCXX/blocks-cxx11.cpp @@ -0,0 +1,84 @@ +// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -std=c++11 -emit-llvm -o - | FileCheck %s + +template <class T> void takeItByValue(T); +void takeABlock(void (^)()); + +// rdar://problem/11022704 +namespace test_int { + void test() { + const int x = 100; + takeABlock(^{ takeItByValue(x); }); + // CHECK: call void @_Z13takeItByValueIiEvT_(i32 100) + } +} + +namespace test_int_ref { + void test() { + const int y = 200; + const int &x = y; + takeABlock(^{ takeItByValue(x); }); + + // TODO: there's no good reason that this isn't foldable. + // CHECK: call void @_Z13takeItByValueIiEvT_(i32 {{%.*}}) + } +} + +namespace test_float { + void test() { + const float x = 1; + takeABlock(^{ takeItByValue(x); }); + // CHECK: call void @_Z13takeItByValueIfEvT_(float 1.0 + } +} + +namespace test_float_ref { + void test() { + const float y = 100; + const float &x = y; + takeABlock(^{ takeItByValue(x); }); + + // TODO: there's no good reason that this isn't foldable. + // CHECK: call void @_Z13takeItByValueIfEvT_(float {{%.*}}) + } +} + +namespace test_complex_int { + void test() { + constexpr _Complex int x = 500; + takeABlock(^{ takeItByValue(x); }); + // CHECK: store i32 500, + + // CHECK: store i32 500, + // CHECK-NEXT: store i32 0, + // CHECK-NEXT: [[COERCE:%.*]] = bitcast + // CHECK-NEXT: [[CVAL:%.*]] = load i64* [[COERCE]] + // CHECK-NEXT: call void @_Z13takeItByValueICiEvT_(i64 [[CVAL]]) + } +} + +namespace test_complex_int_ref { + void test() { + const _Complex int y = 100; + const _Complex int &x = y; + takeABlock(^{ takeItByValue(x); }); + // CHECK: call void @_Z13takeItByValueICiEvT_(i64 + } +} + +namespace test_complex_int_ref_mutable { + _Complex int y = 100; + void test() { + const _Complex int &x = y; + takeABlock(^{ takeItByValue(x); }); + // CHECK: [[R:%.*]] = load i32* getelementptr inbounds ({ i32, i32 }* @_ZN28test_complex_int_ref_mutable1yE, i32 0, i32 0) + // CHECK-NEXT: [[I:%.*]] = load i32* getelementptr inbounds ({ i32, i32 }* @_ZN28test_complex_int_ref_mutable1yE, i32 0, i32 1) + // CHECK-NEXT: [[RSLOT:%.*]] = getelementptr inbounds { i32, i32 }* [[CSLOT:%.*]], i32 0, i32 0 + // CHECK-NEXT: [[ISLOT:%.*]] = getelementptr inbounds { i32, i32 }* [[CSLOT]], i32 0, i32 1 + // CHECK-NEXT: store i32 [[R]], i32* [[RSLOT]] + // CHECK-NEXT: store i32 [[I]], i32* [[ISLOT]] + // CHECK-NEXT: [[COERCE:%.*]] = bitcast { i32, i32 }* [[CSLOT]] to i64* + // CHECK-NEXT: [[CVAL:%.*]] = load i64* [[COERCE]], + // CHECK-NEXT: call void @_Z13takeItByValueICiEvT_(i64 [[CVAL]]) + } +} + diff --git a/clang/test/CodeGenCXX/blocks.cpp b/clang/test/CodeGenCXX/blocks.cpp new file mode 100644 index 0000000..eb54478 --- /dev/null +++ b/clang/test/CodeGenCXX/blocks.cpp @@ -0,0 +1,228 @@ +// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s + +namespace test0 { + // CHECK: define void @_ZN5test04testEi( + // CHECK: define internal void @__test_block_invoke_{{.*}}( + // CHECK: define internal void @__block_global_{{.*}}( + void test(int x) { + ^{ ^{ (void) x; }; }; + } +} + +extern void (^out)(); + +namespace test1 { + // Capturing const objects doesn't require a local block. + // CHECK: define void @_ZN5test15test1Ev() + // CHECK: store void ()* bitcast ({{.*}} @__block_literal_global{{.*}} to void ()*), void ()** @out + void test1() { + const int NumHorsemen = 4; + out = ^{ (void) NumHorsemen; }; + } + + // That applies to structs too... + // CHECK: define void @_ZN5test15test2Ev() + // CHECK: store void ()* bitcast ({{.*}} @__block_literal_global{{.*}} to void ()*), void ()** @out + struct loc { double x, y; }; + void test2() { + const loc target = { 5, 6 }; + out = ^{ (void) target; }; + } + + // ...unless they have mutable fields... + // CHECK: define void @_ZN5test15test3Ev() + // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], + // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* + // CHECK: store void ()* [[T0]], void ()** @out + struct mut { mutable int x; }; + void test3() { + const mut obj = { 5 }; + out = ^{ (void) obj; }; + } + + // ...or non-trivial destructors... + // CHECK: define void @_ZN5test15test4Ev() + // CHECK: [[OBJ:%.*]] = alloca + // CHECK: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], + // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* + // CHECK: store void ()* [[T0]], void ()** @out + struct scope { int x; ~scope(); }; + void test4() { + const scope obj = { 5 }; + out = ^{ (void) obj; }; + } + + // ...or non-trivial copy constructors, but it's not clear how to do + // that and still have a constant initializer in '03. +} + +namespace test2 { + struct A { + A(); + A(const A &); + ~A(); + }; + + struct B { + B(); + B(const B &); + ~B(); + }; + + // CHECK: define void @_ZN5test24testEv() + void test() { + __block A a; + __block B b; + } + + // CHECK: define internal void @__Block_byref_object_copy + // CHECK: call void @_ZN5test21AC1ERKS0_( + + // CHECK: define internal void @__Block_byref_object_dispose + // CHECK: call void @_ZN5test21AD1Ev( + + // CHECK: define internal void @__Block_byref_object_copy + // CHECK: call void @_ZN5test21BC1ERKS0_( + + // CHECK: define internal void @__Block_byref_object_dispose + // CHECK: call void @_ZN5test21BD1Ev( +} + +// rdar://problem/9334739 +// Make sure we mark destructors for parameters captured in blocks. +namespace test3 { + struct A { + A(const A&); + ~A(); + }; + + struct B : A { + }; + + void test(B b) { + extern void consume(void(^)()); + consume(^{ (void) b; }); + } +} + +// rdar://problem/9971485 +namespace test4 { + struct A { + A(); + ~A(); + }; + + void foo(A a); + + void test() { + extern void consume(void(^)()); + consume(^{ return foo(A()); }); + } + // CHECK: define void @_ZN5test44testEv() + // CHECK: define internal void @__test_block_invoke + // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1 + // CHECK-NEXT: bitcast i8* + // CHECK-NEXT: call void @_ZN5test41AC1Ev([[A]]* [[TMP]]) + // CHECK-NEXT: call void @_ZN5test43fooENS_1AE([[A]]* [[TMP]]) + // CHECK-NEXT: call void @_ZN5test41AD1Ev([[A]]* [[TMP]]) + // CHECK-NEXT: ret void +} + +namespace test5 { + struct A { + unsigned afield; + A(); + A(const A&); + ~A(); + void foo() const; + }; + + void doWithBlock(void(^)()); + + void test(bool cond) { + A x; + void (^b)() = (cond ? ^{ x.foo(); } : (void(^)()) 0); + doWithBlock(b); + } + + // CHECK: define void @_ZN5test54testEb( + // CHECK: [[COND:%.*]] = alloca i8 + // CHECK-NEXT: [[X:%.*]] = alloca [[A:%.*]], align 4 + // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8 + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8 + // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: [[T0:%.*]] = zext i1 + // CHECK-NEXT: store i8 [[T0]], i8* [[COND]], align 1 + // CHECK-NEXT: call void @_ZN5test51AC1Ev([[A]]* [[X]]) + // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 + // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]], align 1 + // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1 + // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: br i1 [[T1]], + + // CHECK-NOT: br + // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 + // CHECK-NEXT: call void @_ZN5test51AC1ERKS0_([[A]]* [[CAPTURE]], [[A]]* [[X]]) + // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* + // CHECK-NEXT: br label + // CHECK: br label + // CHECK: phi + // CHECK-NEXT: store + // CHECK-NEXT: load + // CHECK-NEXT: call void @_ZN5test511doWithBlockEU13block_pointerFvvE( + // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: br i1 [[T0]] + // CHECK: call void @_ZN5test51AD1Ev([[A]]* [[CLEANUP_ADDR]]) + // CHECK-NEXT: br label + // CHECK: call void @_ZN5test51AD1Ev([[A]]* [[X]]) + // CHECK-NEXT: ret void +} + +namespace test6 { + struct A { + A(); + ~A(); + }; + + void foo(const A &, void (^)()); + void bar(); + + void test() { + // Make sure that the temporary cleanup isn't somehow captured + // within the block. + foo(A(), ^{ bar(); }); + bar(); + } + + // CHECK: define void @_ZN5test64testEv() + // CHECK: [[TEMP:%.*]] = alloca [[A:%.*]], align 1 + // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[TEMP]]) + // CHECK-NEXT: call void @_ZN5test63fooERKNS_1AEU13block_pointerFvvE( + // CHECK-NEXT: call void @_ZN5test61AD1Ev([[A]]* [[TEMP]]) + // CHECK-NEXT: call void @_ZN5test63barEv() + // CHECK-NEXT: ret void +} + +namespace test7 { + int f() { + static int n; + int *const p = &n; + return ^{ return *p; }(); + } +} + +namespace test8 { + // <rdar://problem/10832617>: failure to capture this after skipping rebuild + // of the 'this' pointer. + struct X { + int x; + + template<typename T> + int foo() { + return ^ { return x; }(); + } + }; + + template int X::foo<int>(); +} diff --git a/clang/test/CodeGenCXX/builtins.cpp b/clang/test/CodeGenCXX/builtins.cpp new file mode 100644 index 0000000..4542563 --- /dev/null +++ b/clang/test/CodeGenCXX/builtins.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +// PR8839 +extern "C" char memmove(); + +int main() { + // CHECK: call signext i8 @memmove() + return memmove(); +} + +// <rdar://problem/10063539> + +template<int (*Compare)(const char *s1, const char *s2)> +int equal(const char *s1, const char *s2) { + return Compare(s1, s2) == 0; +} + +// CHECK: define weak_odr i32 @_Z5equalIXadL_Z16__builtin_strcmpPKcS1_EEEiS1_S1_ +// CHECK: call i32 @strcmp +template int equal<&__builtin_strcmp>(const char*, const char*); + diff --git a/clang/test/CodeGenCXX/c-linkage.cpp b/clang/test/CodeGenCXX/c-linkage.cpp new file mode 100644 index 0000000..b1f07b7 --- /dev/null +++ b/clang/test/CodeGenCXX/c-linkage.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s +// pr6644 + +extern "C" { + namespace N { + struct X { + virtual void f(); + }; + void X::f() { } + } +} + +// CHECK: define void @_ZN1N1X1fEv diff --git a/clang/test/CodeGenCXX/c99-variable-length-array.cpp b/clang/test/CodeGenCXX/c99-variable-length-array.cpp new file mode 100644 index 0000000..d486f9b --- /dev/null +++ b/clang/test/CodeGenCXX/c99-variable-length-array.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +struct X { + X(); + ~X(); +}; + +struct Y { + Y(); + ~Y(); +}; + +// CHECK: define void @_Z1fiPPKc( +void f(int argc, const char* argv[]) { + // CHECK: call void @_ZN1XC1Ev + X x; + // CHECK: call i8* @llvm.stacksave( + const char *argv2[argc]; + // CHECK: call void @_ZN1YC1Ev + Y y; + for (int i = 0; i != argc; ++i) + argv2[i] = argv[i]; + + // CHECK: call void @_ZN1YD1Ev + // CHECK: call void @llvm.stackrestore + // CHECK: call void @_ZN1XD1Ev + // CHECK: ret void +} + +namespace PR11744 { + // Make sure this doesn't crash; there was a use-after-free issue + // for this testcase. + template<typename T> int f(int n) { + T arr[3][n]; + return 3; + } + int test = f<int>(0); +} diff --git a/clang/test/CodeGenCXX/call-arg-zero-temp.cpp b/clang/test/CodeGenCXX/call-arg-zero-temp.cpp new file mode 100644 index 0000000..101e81f --- /dev/null +++ b/clang/test/CodeGenCXX/call-arg-zero-temp.cpp @@ -0,0 +1,23 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + + +extern "C" int printf(...); + +struct obj{ int a; float b; double d; }; + +void foo(obj o) { + printf("%d %f %f\n", o.a, o.b, o.d); +} + +int main() { + obj o = obj(); + foo(obj()); +} + +// CHECK-LP64: callq __Z3foo3obj + +// CHECK-LP32: calll __Z3foo3obj diff --git a/clang/test/CodeGenCXX/cast-conversion.cpp b/clang/test/CodeGenCXX/cast-conversion.cpp new file mode 100644 index 0000000..d023b9a --- /dev/null +++ b/clang/test/CodeGenCXX/cast-conversion.cpp @@ -0,0 +1,33 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +struct A { + A(int); +}; + +struct B { + B(A); +}; + +int main () { + (B)10; + B(10); + static_cast<B>(10); +} + +// CHECK-LP64: callq __ZN1AC1Ei +// CHECK-LP64: callq __ZN1BC1E1A +// CHECK-LP64: callq __ZN1AC1Ei +// CHECK-LP64: callq __ZN1BC1E1A +// CHECK-LP64: callq __ZN1AC1Ei +// CHECK-LP64: callq __ZN1BC1E1A + +// CHECK-LP32: calll L__ZN1AC1Ei +// CHECK-LP32: calll L__ZN1BC1E1A +// CHECK-LP32: calll L__ZN1AC1Ei +// CHECK-LP32: calll L__ZN1BC1E1A +// CHECK-LP32: calll L__ZN1AC1Ei +// CHECK-LP32: calll L__ZN1BC1E1A diff --git a/clang/test/CodeGenCXX/casts.cpp b/clang/test/CodeGenCXX/casts.cpp new file mode 100644 index 0000000..436b722 --- /dev/null +++ b/clang/test/CodeGenCXX/casts.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 %s -emit-llvm -o %t + +// PR5248 +namespace PR5248 { +struct A { + void copyFrom(const A &src); + void addRef(void); + + A& operator=(int); +}; + +void A::copyFrom(const A &src) { + ((A &)src).addRef(); +} +} + +// reinterpret_cast to self +void test(PR5248::A* a) { + reinterpret_cast<PR5248::A&>(*a) = 17; +} diff --git a/clang/test/CodeGenCXX/class-layout.cpp b/clang/test/CodeGenCXX/class-layout.cpp new file mode 100644 index 0000000..dac0a0a --- /dev/null +++ b/clang/test/CodeGenCXX/class-layout.cpp @@ -0,0 +1,79 @@ +// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// An extra byte should be allocated for an empty class. +namespace Test1 { + // CHECK: %"struct.Test1::A" = type { i8 } + struct A { } *a; +} + +namespace Test2 { + // No need to add tail padding here. + // CHECK: %"struct.Test2::A" = type { i8*, i32 } + struct A { void *a; int b; } *a; +} + +namespace Test3 { + // C should have a vtable pointer. + // CHECK: %"struct.Test3::A" = type { i32 (...)**, i32 } + struct A { virtual void f(); int a; } *a; +} + +namespace Test4 { + // Test from PR5589. + // CHECK: %"struct.Test4::B" = type { %"struct.Test4::A", i16, double } + // CHECK: %"struct.Test4::A" = type { i32, i8, float } + struct A { + int a; + char c; + float b; + }; + struct B : public A { + short d; + double e; + } *b; +} + +namespace Test5 { + struct A { + virtual void f(); + char a; + }; + + // CHECK: %"struct.Test5::B" = type { [9 x i8], i8, i8, [5 x i8] } + struct B : A { + char b : 1; + char c; + } *b; +} + +// PR10912: don't crash +namespace Test6 { + template <typename T> class A { + // If T is complete, IR-gen will want to translate it recursively + // when translating T*. + T *foo; + }; + + class B; + + // This causes IR-gen to have an incomplete translation of A<B> + // sitting around. + A<B> *a; + + class C {}; + class B : public C { + // This forces Sema to instantiate A<B>, which triggers a callback + // to IR-gen. Because of the previous, incomplete translation, + // IR-gen actually cares, and it immediately tries to complete + // A<B>'s IR type. That, in turn, causes the translation of B*. + // B isn't complete yet, but it has a definition, and if we try to + // compute a record layout for that definition then we'll really + // regret it later. + A<B> a; + }; + + // The derived class E and empty base class C are required to + // provoke the original assertion. + class E : public B {}; + E *e; +} diff --git a/clang/test/CodeGenCXX/compound-literals.cpp b/clang/test/CodeGenCXX/compound-literals.cpp new file mode 100644 index 0000000..17a3114 --- /dev/null +++ b/clang/test/CodeGenCXX/compound-literals.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +struct X { + X(); + X(const X&); + X(const char*); + ~X(); +}; + +struct Y { + int i; + X x; +}; + +// CHECK: define i32 @_Z1fv() +int f() { + // CHECK: [[LVALUE:%[a-z0-9.]+]] = alloca + // CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}}* [[LVALUE]], i32 0, i32 0 + // CHECK-NEXT: store i32 17, i32* [[I]] + // CHECK-NEXT: [[X:%[a-z0-9]+]] = getelementptr inbounds {{.*}} [[LVALUE]], i32 0, i32 1 + // CHECK-NEXT: call void @_ZN1XC1EPKc({{.*}}[[X]] + // CHECK-NEXT: [[I:%[a-z0-9]+]] = getelementptr inbounds {{.*}} [[LVALUE]], i32 0, i32 0 + // CHECK-NEXT: [[RESULT:%[a-z0-9]+]] = load i32* + // CHECK-NEXT: call void @_ZN1YD1Ev + // CHECK-NEXT: ret i32 [[RESULT]] + return ((Y){17, "seventeen"}).i; +} + +// CHECK: define i32 @_Z1gv() +int g() { + // CHECK: store [2 x i32]* %{{[a-z0-9.]+}}, [2 x i32]** [[V:%[a-z0-9.]+]] + const int (&v)[2] = (int [2]) {1,2}; + + // CHECK: [[A:%[a-z0-9.]+]] = load [2 x i32]** [[V]] + // CHECK-NEXT: [[A0ADDR:%[a-z0-9.]+]] = getelementptr inbounds [2 x i32]* [[A]], i32 0, {{.*}} 0 + // CHECK-NEXT: [[A0:%[a-z0-9.]+]] = load i32* [[A0ADDR]] + // CHECK-NEXT: ret i32 [[A0]] + return v[0]; +} + +struct Z { int i[3]; }; +int *p = (Z){ {1, 2, 3} }.i; +// CHECK: define {{.*}}__cxx_global_var_init() +// CHECK: store i32* getelementptr inbounds (%struct.Z* @.compoundliteral, i32 0, i32 0, i32 0), i32** @p diff --git a/clang/test/CodeGenCXX/condition.cpp b/clang/test/CodeGenCXX/condition.cpp new file mode 100644 index 0000000..cc2eaf5 --- /dev/null +++ b/clang/test/CodeGenCXX/condition.cpp @@ -0,0 +1,317 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +void *f(); + +template <typename T> T* g() { + if (T* t = f()) + return t; + + return 0; +} + +void h() { + void *a = g<void>(); +} + +struct X { + X(); + X(const X&); + ~X(); + operator bool(); +}; + +struct Y { + Y(); + ~Y(); +}; + +X getX(); + +// CHECK: define void @_Z11if_destructi( +void if_destruct(int z) { + // Verify that the condition variable is destroyed at the end of the + // "if" statement. + // CHECK: call void @_ZN1XC1Ev + // CHECK: call zeroext i1 @_ZN1XcvbEv + if (X x = X()) { + // CHECK: store i32 18 + z = 18; + } + // CHECK: call void @_ZN1XD1Ev + // CHECK: store i32 17 + z = 17; + + // CHECK: call void @_ZN1XC1Ev + if (X x = X()) + Y y; + // CHECK: br + // CHECK: call void @_ZN1YC1Ev + // CHECK: call void @_ZN1YD1Ev + // CHECK: br + // CHECK: call void @_ZN1XD1Ev + + // CHECK: call void @_Z4getXv + // CHECK: call zeroext i1 @_ZN1XcvbEv + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + if (getX()) { } + + // CHECK: ret +} + +struct ConvertibleToInt { + ConvertibleToInt(); + ~ConvertibleToInt(); + operator int(); +}; + +ConvertibleToInt getConvToInt(); + +void switch_destruct(int z) { + // CHECK: call void @_ZN16ConvertibleToIntC1Ev + switch (ConvertibleToInt conv = ConvertibleToInt()) { + case 0: + break; + + default: + // CHECK: store i32 19 + z = 19; + break; + } + // CHECK: call void @_ZN16ConvertibleToIntD1Ev + // CHECK: store i32 20 + z = 20; + + // CHECK: call void @_Z12getConvToIntv + // CHECK: call i32 @_ZN16ConvertibleToIntcviEv + // CHECK: call void @_ZN16ConvertibleToIntD1Ev + switch(getConvToInt()) { + case 0: + break; + } + // CHECK: store i32 27 + z = 27; + // CHECK: ret +} + +int foo(); + +// CHECK: define void @_Z14while_destructi +void while_destruct(int z) { + // CHECK: [[Z:%.*]] = alloca i32 + // CHECK: [[CLEANUPDEST:%.*]] = alloca i32 + while (X x = X()) { + // CHECK: call void @_ZN1XC1Ev + // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv + // CHECK-NEXT: br i1 [[COND]] + + // Loop-exit staging block. + // CHECK: store i32 3, i32* [[CLEANUPDEST]] + // CHECK-NEXT: br + + // While body. + // CHECK: store i32 21, i32* [[Z]] + // CHECK: store i32 0, i32* [[CLEANUPDEST]] + // CHECK-NEXT: br + z = 21; + + // Cleanup. + // CHECK: call void @_ZN1XD1Ev + // CHECK-NEXT: [[DEST:%.*]] = load i32* [[CLEANUPDEST]] + // CHECK-NEXT: switch i32 [[DEST]] + } + + // CHECK: store i32 22, i32* [[Z]] + z = 22; + + // CHECK: call void @_Z4getXv + // CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv + // CHECK-NEXT: call void @_ZN1XD1Ev + // CHECK-NEXT: br + while(getX()) { } + + // CHECK: store i32 25, i32* [[Z]] + z = 25; + + // CHECK: ret +} + +// CHECK: define void @_Z12for_destructi( +void for_destruct(int z) { + // CHECK: [[Z:%.*]] = alloca i32 + // CHECK: [[CLEANUPDEST:%.*]] = alloca i32 + // CHECK: [[I:%.*]] = alloca i32 + // CHECK: call void @_ZN1YC1Ev + // CHECK-NEXT: br + // -> %for.cond + + for(Y y = Y(); X x = X(); ++z) { + // %for.cond: The loop condition. + // CHECK: call void @_ZN1XC1Ev + // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN1XcvbEv( + // CHECK-NEXT: br i1 [[COND]] + // -> %for.body, %for.cond.cleanup + + // %for.cond.cleanup: Exit cleanup staging. + // CHECK: store i32 2, i32* [[CLEANUPDEST]] + // CHECK-NEXT: br + // -> %cleanup + + // %for.body: + // CHECK: store i32 23, i32* [[Z]] + // CHECK-NEXT: br + // -> %for.inc + z = 23; + + // %for.inc: + // CHECK: [[TMP:%.*]] = load i32* [[Z]] + // CHECK-NEXT: [[INC:%.*]] = add nsw i32 [[TMP]], 1 + // CHECK-NEXT: store i32 [[INC]], i32* [[Z]] + // CHECK-NEXT: store i32 0, i32* [[CLEANUPDEST]] + // CHECK-NEXT: br + // -> %cleanup + + // %cleanup: Destroys X. + // CHECK: call void @_ZN1XD1Ev + // CHECK-NEXT: [[YDESTTMP:%.*]] = load i32* [[CLEANUPDEST]] + // CHECK-NEXT: switch i32 [[YDESTTMP]] + // 0 -> %cleanup.cont, default -> %cleanup1 + + // %cleanup.cont: (eliminable) + // CHECK: br + // -> %for.cond + + // %cleanup1: Destroys Y. + // CHECK: call void @_ZN1YD1Ev( + // CHECK-NEXT: br + // -> %for.end + } + + // %for.end: + // CHECK: store i32 24 + z = 24; + + // CHECK-NEXT: store i32 0, i32* [[I]] + // CHECK-NEXT: br + // -> %for.cond6 + + // %for.cond6: + // CHECK: call void @_Z4getXv + // CHECK-NEXT: call zeroext i1 @_ZN1XcvbEv + // CHECK-NEXT: call void @_ZN1XD1Ev + // CHECK-NEXT: br + // -> %for.body10, %for.end16 + + // %for.body10: + // CHECK: br + // -> %for.inc11 + + // %for.inc11: + // CHECK: call void @_Z4getXv + // CHECK-NEXT: load i32* [[I]] + // CHECK-NEXT: add + // CHECK-NEXT: store + // CHECK-NEXT: call void @_ZN1XD1Ev + // CHECK-NEXT: br + // -> %for.cond6 + int i = 0; + for(; getX(); getX(), ++i) { } + + // %for.end16 + // CHECK: store i32 26 + z = 26; + + // CHECK-NEXT: ret void +} + +void do_destruct(int z) { + // CHECK: define void @_Z11do_destruct + do { + // CHECK: store i32 77 + z = 77; + // CHECK: call void @_Z4getXv + // CHECK: call zeroext i1 @_ZN1XcvbEv + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + } while (getX()); + // CHECK: store i32 99 + z = 99; + // CHECK: ret +} + +int f(X); + +template<typename T> +int instantiated(T x) { + int result; + + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + // CHECK: store i32 2 + // CHECK: br + // CHECK: store i32 3 + if (f(x)) { result = 2; } else { result = 3; } + + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + // CHECK: store i32 4 + // CHECK: br + while (f(x)) { result = 4; } + + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + // CHECK: store i32 6 + // CHECK: br + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: store i32 5 + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + for (; f(x); f(x), result = 5) { + result = 6; + } + + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: call void @_ZN1XD1Ev + // CHECK: switch i32 + // CHECK: store i32 7 + // CHECK: store i32 8 + switch (f(x)) { + case 0: + result = 7; + break; + + case 1: + result = 8; + } + + // CHECK: store i32 9 + // CHECK: br + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call i32 @_Z1f1X + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + do { + result = 9; + } while (f(x)); + + // CHECK: store i32 10 + // CHECK: call void @_ZN1XC1ERKS_ + // CHECK: call zeroext i1 @_ZN1XcvbEv + // CHECK: call void @_ZN1XD1Ev + // CHECK: br + do { + result = 10; + } while (X(x)); + + // CHECK: ret i32 + return result; +} + +template int instantiated(X); diff --git a/clang/test/CodeGenCXX/conditional-expr-lvalue.cpp b/clang/test/CodeGenCXX/conditional-expr-lvalue.cpp new file mode 100644 index 0000000..96aa8b0 --- /dev/null +++ b/clang/test/CodeGenCXX/conditional-expr-lvalue.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -emit-llvm-only %s +void f(bool flag) { + int a = 1; + int b = 2; + + (flag ? a : b) = 3; +} + +// PR10756 +namespace test0 { + struct A { + A(const A &); + A &operator=(const A &); + A sub() const; + void foo() const; + }; + void foo(bool cond, const A &a) { + (cond ? a : a.sub()).foo(); + } +} diff --git a/clang/test/CodeGenCXX/conditional-gnu-ext.cpp b/clang/test/CodeGenCXX/conditional-gnu-ext.cpp new file mode 100644 index 0000000..104a91d --- /dev/null +++ b/clang/test/CodeGenCXX/conditional-gnu-ext.cpp @@ -0,0 +1,150 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s +// rdar: // 8353567 +// pr7726 + +extern "C" int printf(...); + +void test0() { +// CHECK: call i32 (...)* @printf({{.*}}, i8* inttoptr (i64 3735928559 to i8*)) + printf("%p\n", (void *)0xdeadbeef ? : (void *)0xaaaaaa); +} + +// rdar://8446940 +namespace radar8446940 { +extern "C" void abort(); + +int main () { + char x[1]; + char *y = x ? : 0; + + if (x != y) + abort(); +} +} + +namespace radar8453812 { +extern "C" void abort(); +_Complex int getComplex(_Complex int val) { + static int count; + if (count++) + abort(); + return val; +} + +_Complex int cmplx() { + _Complex int cond; + _Complex int rhs; + + return getComplex(1+2i) ? : rhs; +} + +// lvalue test +void foo (int& lv) { + ++lv; +} + +int global = 1; + +int &cond() { + static int count; + if (count++) + abort(); + return global; +} + + +int main() { + cmplx(); + int rhs = 10; + foo (cond()? : rhs); + return global-2; +} +} + +namespace test3 { + struct A { + A(); + A(const A&); + ~A(); + }; + + struct B { + B(); + B(const B&); + ~B(); + operator bool(); + operator A(); + }; + + B test0(B &x) { + // CHECK: define void @_ZN5test35test0ERNS_1BE( + // CHECK: [[X:%.*]] = alloca [[B:%.*]]*, + // CHECK-NEXT: store [[B]]* {{%.*}}, [[B]]** [[X]] + // CHECK-NEXT: [[T0:%.*]] = load [[B]]** [[X]] + // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[T0]]) + // CHECK-NEXT: br i1 [[BOOL]] + // CHECK: call void @_ZN5test31BC1ERKS0_([[B]]* [[RESULT:%.*]], [[B]]* [[T0]]) + // CHECK-NEXT: br label + // CHECK: call void @_ZN5test31BC1Ev([[B]]* [[RESULT]]) + // CHECK-NEXT: br label + // CHECK: ret void + return x ?: B(); + } + + B test1() { + // CHECK: define void @_ZN5test35test1Ev( + // CHECK: [[TEMP:%.*]] = alloca [[B]], + // CHECK-NEXT: call void @_ZN5test312test1_helperEv([[B]]* sret [[TEMP]]) + // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[TEMP]]) + // CHECK-NEXT: br i1 [[BOOL]] + // CHECK: call void @_ZN5test31BC1ERKS0_([[B]]* [[RESULT:%.*]], [[B]]* [[TEMP]]) + // CHECK-NEXT: br label + // CHECK: call void @_ZN5test31BC1Ev([[B]]* [[RESULT]]) + // CHECK-NEXT: br label + // CHECK: call void @_ZN5test31BD1Ev([[B]]* [[TEMP]]) + // CHECK-NEXT: ret void + extern B test1_helper(); + return test1_helper() ?: B(); + } + + + A test2(B &x) { + // CHECK: define void @_ZN5test35test2ERNS_1BE( + // CHECK: [[X:%.*]] = alloca [[B]]*, + // CHECK-NEXT: store [[B]]* {{%.*}}, [[B]]** [[X]] + // CHECK-NEXT: [[T0:%.*]] = load [[B]]** [[X]] + // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[T0]]) + // CHECK-NEXT: br i1 [[BOOL]] + // CHECK: call void @_ZN5test31BcvNS_1AEEv([[A:%.*]]* sret [[RESULT:%.*]], [[B]]* [[T0]]) + // CHECK-NEXT: br label + // CHECK: call void @_ZN5test31AC1Ev([[A]]* [[RESULT]]) + // CHECK-NEXT: br label + // CHECK: ret void + return x ?: A(); + } + + A test3() { + // CHECK: define void @_ZN5test35test3Ev( + // CHECK: [[TEMP:%.*]] = alloca [[B]], + // CHECK-NEXT: call void @_ZN5test312test3_helperEv([[B]]* sret [[TEMP]]) + // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[TEMP]]) + // CHECK-NEXT: br i1 [[BOOL]] + // CHECK: call void @_ZN5test31BcvNS_1AEEv([[A]]* sret [[RESULT:%.*]], [[B]]* [[TEMP]]) + // CHECK-NEXT: br label + // CHECK: call void @_ZN5test31AC1Ev([[A]]* [[RESULT]]) + // CHECK-NEXT: br label + // CHECK: call void @_ZN5test31BD1Ev([[B]]* [[TEMP]]) + // CHECK-NEXT: ret void + extern B test3_helper(); + return test3_helper() ?: A(); + } + +} + +namespace test4 { + // Make sure this doesn't crash. + void f() { + const int a = 10, b = 20; + const int *c = &(a ?: b); + } +} diff --git a/clang/test/CodeGenCXX/conditional-temporaries.cpp b/clang/test/CodeGenCXX/conditional-temporaries.cpp new file mode 100644 index 0000000..d538287 --- /dev/null +++ b/clang/test/CodeGenCXX/conditional-temporaries.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -O3 | FileCheck %s + +namespace { + +static int ctorcalls; +static int dtorcalls; + +struct A { + A() : i(0) { ctorcalls++; } + ~A() { dtorcalls++; } + int i; + + friend const A& operator<<(const A& a, int n) { + return a; + } +}; + +void g(int) { } +void g(const A&) { } + +void f1(bool b) { + g(b ? A().i : 0); + g(b || A().i); + g(b && A().i); + g(b ? A() << 1 : A() << 2); +} + +struct Checker { + Checker() { + f1(true); + f1(false); + } +}; + +Checker c; + +} + +// CHECK: define i32 @_Z12getCtorCallsv() +int getCtorCalls() { + // CHECK: ret i32 5 + return ctorcalls; +} + +// CHECK: define i32 @_Z12getDtorCallsv() +int getDtorCalls() { + // CHECK: ret i32 5 + return dtorcalls; +} + +// CHECK: define zeroext i1 @_Z7successv() +bool success() { + // CHECK: ret i1 true + return ctorcalls == dtorcalls; +} diff --git a/clang/test/CodeGenCXX/const-base-cast.cpp b/clang/test/CodeGenCXX/const-base-cast.cpp new file mode 100644 index 0000000..320c790 --- /dev/null +++ b/clang/test/CodeGenCXX/const-base-cast.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +// Check that the following construct, which is similar to one which occurs +// in Firefox, is folded correctly. +struct A { char x; }; +struct B { char y; }; +struct C : A,B {}; +unsigned char x = ((char*)(B*)(C*)0x1000) - (char*)0x1000; + +// CHECK: @x = global i8 1 diff --git a/clang/test/CodeGenCXX/const-global-linkage.cpp b/clang/test/CodeGenCXX/const-global-linkage.cpp new file mode 100644 index 0000000..d0a055b --- /dev/null +++ b/clang/test/CodeGenCXX/const-global-linkage.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +const int x = 10; +const int y = 20; +// CHECK-NOT: @x +// CHECK: @_ZL1y = internal constant i32 20 +const int& b() { return y; } + +const char z1[] = "asdf"; +const char z2[] = "zxcv"; +// CHECK-NOT: @z1 +// CHECK: @_ZL2z2 = internal constant +const char* b2() { return z2; } diff --git a/clang/test/CodeGenCXX/const-init-cxx11.cpp b/clang/test/CodeGenCXX/const-init-cxx11.cpp new file mode 100644 index 0000000..62a345a --- /dev/null +++ b/clang/test/CodeGenCXX/const-init-cxx11.cpp @@ -0,0 +1,428 @@ +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++11 | FileCheck %s + +// FIXME: The padding in all these objects should be zero-initialized. +namespace StructUnion { + struct A { + int n; + double d; + union U { + constexpr U(int x) : x(x) {} + constexpr U(const char *y) : y(y) {} + int x; + const char *y; + } u; + + constexpr A(int n, double d, int x) : n(n), d(d), u(x) {} + constexpr A(int n, double d, const char *y) : n(n), d(d), u(y) {} + }; + + // CHECK: @_ZN11StructUnion1aE = constant {{.*}} { i32 1, double 2.000000e+00, {{.*}} { i32 3, [4 x i8] undef } } + extern constexpr A a(1, 2.0, 3); + + // CHECK: @_ZN11StructUnion1bE = constant {{.*}} { i32 4, double 5.000000e+00, {{.*}} { i8* getelementptr inbounds ([6 x i8]* @{{.*}}, i32 0, i32 0) } } + extern constexpr A b(4, 5, "hello"); + + struct B { + int n; + }; + + // CHECK: @_ZN11StructUnion1cE = global {{.*}} zeroinitializer + // CHECK: @_ZN11StructUnion2c2E = global {{.*}} zeroinitializer + B c; + B c2 = B(); + + // CHECK: @_ZN11StructUnion1dE = global {{.*}} zeroinitializer + B d[10]; + + struct C { + constexpr C() : c(0) {} + int c; + }; + + // CHECK: @_ZN11StructUnion1eE = global {{.*}} zeroinitializer + C e[10]; + + struct D { + constexpr D() : d(5) {} + int d; + }; + + // CHECK: @_ZN11StructUnion1fE = global {{.*}} { i32 5 } + D f; +} + +namespace BaseClass { + template<typename T, unsigned> struct X : T {}; + struct C { char c = 1; }; + template<unsigned... Ns> struct Cs : X<C,Ns>... {}; + struct N { int n = 3; }; + struct D { double d = 4.0; }; + + template<typename ...Ts> + struct Test : Ts... { constexpr Test() : Ts()..., n(5) {} int n; }; + + using Test1 = Test<N, C, Cs<1,2>, D, X<C,1>>; + // CHECK: @_ZN9BaseClass2t1E = constant {{.*}} { i32 3, i8 1, i8 1, i8 1, double 4.000000e+00, i8 1, i32 5 }, align 8 + extern constexpr Test1 t1 = Test1(); + + struct DN : D, N {}; + struct DND : DN, X<D,0> {}; + struct DNN : DN, X<N,0> {}; + // CHECK: @_ZN9BaseClass3dndE = constant {{.*}} { double 4.000000e+00, i32 3, double 4.000000e+00 } + extern constexpr DND dnd = DND(); + // Note, N subobject is laid out in DN subobject's tail padding. + // CHECK: @_ZN9BaseClass3dnnE = constant {{.*}} { double 4.000000e+00, i32 3, i32 3 } + extern constexpr DNN dnn = DNN(); + + struct E {}; + struct Test2 : X<E,0>, X<E,1>, X<E,2>, X<E,3> {}; + // CHECK: @_ZN9BaseClass2t2E = constant {{.*}} undef + extern constexpr Test2 t2 = Test2(); + + struct __attribute((packed)) PackedD { double y = 2; }; + struct Test3 : C, PackedD { constexpr Test3() {} }; + // CHECK: @_ZN9BaseClass2t3E = constant <{ i8, double }> <{ i8 1, double 2.000000e+00 }> + extern constexpr Test3 t3 = Test3(); +} + +namespace Array { + // CHECK: @_ZN5Array3arrE = constant [2 x i32] [i32 4, i32 0] + extern constexpr int arr[2] = { 4 }; + + // CHECK: @_ZN5Array1cE = constant [6 x [4 x i8]] [{{.*}} c"foo\00", [4 x i8] c"a\00\00\00", [4 x i8] c"bar\00", [4 x i8] c"xyz\00", [4 x i8] c"b\00\00\00", [4 x i8] c"123\00"] + extern constexpr char c[6][4] = { "foo", "a", { "bar" }, { 'x', 'y', 'z' }, { "b" }, '1', '2', '3' }; + + // CHECK: @_ZN5Array2ucE = constant [4 x i8] c"foo\00" + extern constexpr unsigned char uc[] = { "foo" }; + + struct C { constexpr C() : n(5) {} int n, m = 3 * n + 1; }; + // CHECK: @_ZN5Array5ctorsE = constant [3 x {{.*}}] [{{.*}} { i32 5, i32 16 }, {{.*}} { i32 5, i32 16 }, {{.*}} { i32 5, i32 16 }] + extern const C ctors[3]; + constexpr C ctors[3]; + + // CHECK: @_ZN5Array1dE = constant {{.*}} { [2 x i32] [i32 1, i32 2], [3 x i32] [i32 3, i32 4, i32 5] } + struct D { int n[2]; int m[3]; } extern constexpr d = { 1, 2, 3, 4, 5 }; + + struct E { + char c[4]; + char d[4]; + constexpr E() : c("foo"), d("x") {} + }; + // CHECK: @_ZN5Array1eE = constant {{.*}} { [4 x i8] c"foo\00", [4 x i8] c"x\00\00\00" } + extern constexpr E e = E(); +} + +namespace MemberPtr { + struct B1 { + int a, b; + virtual void f(); + void g(); + }; + struct B2 { + int c, d; + virtual void h(); + void i(); + }; + struct C : B1 { + int e; + virtual void j(); + void k(); + }; + struct D : C, B2 { + int z; + virtual void l(); + void m(); + }; + + // CHECK: @_ZN9MemberPtr2daE = constant i64 8 + // CHECK: @_ZN9MemberPtr2dbE = constant i64 12 + // CHECK: @_ZN9MemberPtr2dcE = constant i64 32 + // CHECK: @_ZN9MemberPtr2ddE = constant i64 36 + // CHECK: @_ZN9MemberPtr2deE = constant i64 16 + // CHECK: @_ZN9MemberPtr2dzE = constant i64 40 + extern constexpr int (D::*da) = &B1::a; + extern constexpr int (D::*db) = &C::b; + extern constexpr int (D::*dc) = &B2::c; + extern constexpr int (D::*dd) = &D::d; + extern constexpr int (D::*de) = &C::e; + extern constexpr int (D::*dz) = &D::z; + + // CHECK: @_ZN9MemberPtr2baE = constant i64 8 + // CHECK: @_ZN9MemberPtr2bbE = constant i64 12 + // CHECK: @_ZN9MemberPtr2bcE = constant i64 8 + // CHECK: @_ZN9MemberPtr2bdE = constant i64 12 + // CHECK: @_ZN9MemberPtr2beE = constant i64 16 + // CHECK: @_ZN9MemberPtr3b1zE = constant i64 40 + // CHECK: @_ZN9MemberPtr3b2zE = constant i64 16 + extern constexpr int (B1::*ba) = (int(B1::*))&B1::a; + extern constexpr int (B1::*bb) = (int(B1::*))&C::b; + extern constexpr int (B2::*bc) = (int(B2::*))&B2::c; + extern constexpr int (B2::*bd) = (int(B2::*))&D::d; + extern constexpr int (B1::*be) = (int(B1::*))&C::e; + extern constexpr int (B1::*b1z) = (int(B1::*))&D::z; + extern constexpr int (B2::*b2z) = (int(B2::*))&D::z; + + // CHECK: @_ZN9MemberPtr2dfE = constant {{.*}} { i64 1, i64 0 } + // CHECK: @_ZN9MemberPtr2dgE = constant {{.*}} { i64 {{.*}}2B11gEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr2dhE = constant {{.*}} { i64 1, i64 24 } + // CHECK: @_ZN9MemberPtr2diE = constant {{.*}} { i64 {{.*}}2B21iEv{{.*}}, i64 24 } + // CHECK: @_ZN9MemberPtr2djE = constant {{.*}} { i64 9, i64 0 } + // CHECK: @_ZN9MemberPtr2dkE = constant {{.*}} { i64 {{.*}}1C1kEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr2dlE = constant {{.*}} { i64 17, i64 0 } + // CHECK: @_ZN9MemberPtr2dmE = constant {{.*}} { i64 {{.*}}1D1mEv{{.*}}, i64 0 } + extern constexpr void (D::*df)() = &C::f; + extern constexpr void (D::*dg)() = &B1::g; + extern constexpr void (D::*dh)() = &B2::h; + extern constexpr void (D::*di)() = &D::i; + extern constexpr void (D::*dj)() = &C::j; + extern constexpr void (D::*dk)() = &C::k; + extern constexpr void (D::*dl)() = &D::l; + extern constexpr void (D::*dm)() = &D::m; + + // CHECK: @_ZN9MemberPtr2bfE = constant {{.*}} { i64 1, i64 0 } + // CHECK: @_ZN9MemberPtr2bgE = constant {{.*}} { i64 {{.*}}2B11gEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr2bhE = constant {{.*}} { i64 1, i64 0 } + // CHECK: @_ZN9MemberPtr2biE = constant {{.*}} { i64 {{.*}}2B21iEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr2bjE = constant {{.*}} { i64 9, i64 0 } + // CHECK: @_ZN9MemberPtr2bkE = constant {{.*}} { i64 {{.*}}1C1kEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr3b1lE = constant {{.*}} { i64 17, i64 0 } + // CHECK: @_ZN9MemberPtr3b1mE = constant {{.*}} { i64 {{.*}}1D1mEv{{.*}}, i64 0 } + // CHECK: @_ZN9MemberPtr3b2lE = constant {{.*}} { i64 17, i64 -24 } + // CHECK: @_ZN9MemberPtr3b2mE = constant {{.*}} { i64 {{.*}}1D1mEv{{.*}}, i64 -24 } + extern constexpr void (B1::*bf)() = (void(B1::*)())&C::f; + extern constexpr void (B1::*bg)() = (void(B1::*)())&B1::g; + extern constexpr void (B2::*bh)() = (void(B2::*)())&B2::h; + extern constexpr void (B2::*bi)() = (void(B2::*)())&D::i; + extern constexpr void (B1::*bj)() = (void(B1::*)())&C::j; + extern constexpr void (B1::*bk)() = (void(B1::*)())&C::k; + extern constexpr void (B1::*b1l)() = (void(B1::*)())&D::l; + extern constexpr void (B1::*b1m)() = (void(B1::*)())&D::m; + extern constexpr void (B2::*b2l)() = (void(B2::*)())&D::l; + extern constexpr void (B2::*b2m)() = (void(B2::*)())&D::m; +} + +namespace LiteralReference { + struct Lit { + constexpr Lit() : n(5) {} + int n; + }; + // FIXME: This should have static initialization, but we do not implement + // that yet. For now, just check that we don't set the (pointer) value of + // the reference to 5! + // + // CHECK: @_ZN16LiteralReference3litE = global {{.*}} null + const Lit &lit = Lit(); +} + +namespace NonLiteralConstexpr { + constexpr int factorial(int n) { + return n ? factorial(n-1) * n : 1; + } + extern void f(int *p); + + struct NonTrivialDtor { + constexpr NonTrivialDtor() : n(factorial(5)), p(&n) {} + ~NonTrivialDtor() { + f(p); + } + + int n; + int *p; + }; + static_assert(!__is_literal(NonTrivialDtor), ""); + // CHECK: @_ZN19NonLiteralConstexpr3ntdE = global {{.*}} { i32 120, i32* getelementptr + NonTrivialDtor ntd; + + struct VolatileMember { + constexpr VolatileMember() : n(5) {} + volatile int n; + }; + static_assert(!__is_literal(VolatileMember), ""); + // CHECK: @_ZN19NonLiteralConstexpr2vmE = global {{.*}} { i32 5 } + VolatileMember vm; + + struct Both { + constexpr Both() : n(10) {} + ~Both(); + volatile int n; + }; + // CHECK: @_ZN19NonLiteralConstexpr1bE = global {{.*}} { i32 10 } + Both b; + + void StaticVars() { + // CHECK: @_ZZN19NonLiteralConstexpr10StaticVarsEvE3ntd = {{.*}} { i32 120, i32* getelementptr {{.*}} + // CHECK: @_ZGVZN19NonLiteralConstexpr10StaticVarsEvE3ntd = + static NonTrivialDtor ntd; + // CHECK: @_ZZN19NonLiteralConstexpr10StaticVarsEvE2vm = {{.*}} { i32 5 } + // CHECK-NOT: @_ZGVZN19NonLiteralConstexpr10StaticVarsEvE2vm = + static VolatileMember vm; + // CHECK: @_ZZN19NonLiteralConstexpr10StaticVarsEvE1b = {{.*}} { i32 10 } + // CHECK: @_ZGVZN19NonLiteralConstexpr10StaticVarsEvE1b = + static Both b; + } +} + +// PR12067 +namespace VirtualMembers { + struct A { + constexpr A(double d) : d(d) {} + virtual void f(); + double d; + }; + struct B : A { + constexpr B() : A(2.0), c{'h', 'e', 'l', 'l', 'o'} {} + constexpr B(int n) : A(n), c{'w', 'o', 'r', 'l', 'd'} {} + virtual void g(); + char c[5]; + }; + struct C { + constexpr C() : n(64) {} + int n; + }; + struct D : C, A, B { + constexpr D() : A(1.0), B(), s(5) {} + short s; + }; + struct E : D, B { + constexpr E() : B(3), c{'b','y','e'} {} + char c[3]; + }; + + // CHECK: @_ZN14VirtualMembers1eE = global { i8**, double, i32, i8**, double, [5 x i8], i16, i8**, double, [5 x i8], [3 x i8] } { i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 2), double 1.000000e+00, i32 64, i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 5), double 2.000000e+00, [5 x i8] c"hello", i16 5, i8** getelementptr inbounds ([11 x i8*]* @_ZTVN14VirtualMembers1EE, i64 0, i64 9), double 3.000000e+00, [5 x i8] c"world", [3 x i8] c"bye" } + E e; + + struct nsMemoryImpl { + virtual void f(); + }; + // CHECK: @_ZN14VirtualMembersL13sGlobalMemoryE = internal global { i8** } { i8** getelementptr inbounds ([3 x i8*]* @_ZTVN14VirtualMembers12nsMemoryImplE, i64 0, i64 2) } + static nsMemoryImpl sGlobalMemory; +} + +// Constant initialization tests go before this point, +// dynamic initialization tests go after. + +// We must emit a constant initializer for NonLiteralConstexpr::ntd, but also +// emit an initializer to register its destructor. +// CHECK: define {{.*}}cxx_global_var_init{{.*}} +// CHECK-NOT: NonLiteralConstexpr +// CHECK: call {{.*}}cxa_atexit{{.*}} @_ZN19NonLiteralConstexpr14NonTrivialDtorD1Ev {{.*}} @_ZN19NonLiteralConstexpr3ntdE +// CHECK-NEXT: ret void + +// We don't need to emit any dynamic initialization for NonLiteralConstexpr::vm. +// CHECK-NOT: NonLiteralConstexpr2vm + +// We must emit a constant initializer for NonLiteralConstexpr::b, but also +// emit an initializer to register its destructor. +// CHECK: define {{.*}}cxx_global_var_init{{.*}} +// CHECK-NOT: NonLiteralConstexpr +// CHECK: call {{.*}}cxa_atexit{{.*}} @_ZN19NonLiteralConstexpr4BothD1Ev {{.*}} @_ZN19NonLiteralConstexpr1bE +// CHECK-NEXT: ret void + +// CHECK: define {{.*}}NonLiteralConstexpr10StaticVars +// CHECK-NOT: } +// CHECK: call {{.*}}cxa_atexit{{.*}}@_ZN19NonLiteralConstexpr14NonTrivialDtorD1Ev +// CHECK-NOT: } +// CHECK: call {{.*}}cxa_atexit{{.*}}@_ZN19NonLiteralConstexpr4BothD1Ev + +namespace CrossFuncLabelDiff { + // Make sure we refuse to constant-fold the variable b. + constexpr long a(bool x) { return x ? 0 : (long)&&lbl + (0 && ({lbl: 0;})); } + void test() { static long b = (long)&&lbl - a(false); lbl: return; } + // CHECK: sub nsw i64 ptrtoint (i8* blockaddress(@_ZN18CrossFuncLabelDiff4testEv, {{.*}}) to i64), + // CHECK: store i64 {{.*}}, i64* @_ZZN18CrossFuncLabelDiff4testEvE1b, align 8 +} + +// PR12012 +namespace VirtualBase { + struct B {}; + struct D : virtual B {}; + D d; + // CHECK: call {{.*}}@_ZN11VirtualBase1DC1Ev + + template<typename T> struct X : T { + constexpr X() : T() {} + }; + X<D> x; + // CHECK: call {{.*}}@_ZN11VirtualBase1XINS_1DEEC1Ev +} + +// PR12145 +namespace Unreferenced { + int n; + constexpr int *p = &n; + // We must not emit a load of 'p' here, since it's not odr-used. + int q = *p; + // CHECK-NOT: _ZN12Unreferenced1pE + // CHECK: = load i32* @_ZN12Unreferenced1nE + // CHECK-NEXT: store i32 {{.*}}, i32* @_ZN12Unreferenced1qE + // CHECK-NOT: _ZN12Unreferenced1pE + + // Technically, we are not required to substitute variables of reference types + // initialized by constant expressions, because the special case for odr-use + // of variables in [basic.def.odr]p2 only applies to objects. But we do so + // anyway. + + constexpr int &r = n; + // CHECK-NOT: _ZN12Unreferenced1rE + int s = r; + + const int t = 1; + const int &rt = t; + int f(int); + int u = f(rt); + // CHECK: call i32 @_ZN12Unreferenced1fEi(i32 1) +} + +namespace InitFromConst { + template<typename T> void consume(T); + + const bool b = true; + const int n = 5; + constexpr double d = 4.3; + + struct S { int n = 7; S *p = 0; }; + constexpr S s = S(); + const S &r = s; + constexpr const S *p = &r; + constexpr int S::*mp = &S::n; + constexpr int a[3] = { 1, 4, 9 }; + + void test() { + // CHECK: call void @_ZN13InitFromConst7consumeIbEEvT_(i1 zeroext true) + consume(b); + + // CHECK: call void @_ZN13InitFromConst7consumeIiEEvT_(i32 5) + consume(n); + + // CHECK: call void @_ZN13InitFromConst7consumeIdEEvT_(double 4.300000e+00) + consume(d); + + // CHECK: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE) + consume<const S&>(s); + + // FIXME CHECK-NOT: call void @_ZN13InitFromConst7consumeIRKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE) + // There's no lvalue-to-rvalue conversion here, so 'r' is odr-used, and + // we're permitted to emit a load of it. This seems likely to be a defect + // in the standard. If we start emitting a direct reference to 's', update + // this test. + consume<const S&>(r); + + // CHECK: call void @_ZN13InitFromConst7consumeIPKNS_1SEEEvT_(%"struct.InitFromConst::S"* @_ZN13InitFromConstL1sE) + consume(p); + + // CHECK: call void @_ZN13InitFromConst7consumeIMNS_1SEiEEvT_(i64 0) + consume(mp); + + // CHECK: call void @_ZN13InitFromConst7consumeIPKiEEvT_(i32* getelementptr inbounds ([3 x i32]* @_ZN13InitFromConstL1aE, i32 0, i32 0)) + consume(a); + } +} + +namespace Null { + decltype(nullptr) null(); + // CHECK: call {{.*}} @_ZN4Null4nullEv( + int *p = null(); + struct S {}; + // CHECK: call {{.*}} @_ZN4Null4nullEv( + int S::*q = null(); +} diff --git a/clang/test/CodeGenCXX/const-init.cpp b/clang/test/CodeGenCXX/const-init.cpp new file mode 100644 index 0000000..201ce8f --- /dev/null +++ b/clang/test/CodeGenCXX/const-init.cpp @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s + +// CHECK: @a = global i32 10 +int a = 10; +// CHECK: @ar = constant i32* @a +int &ar = a; + +void f(); +// CHECK: @fr = constant void ()* @_Z1fv +void (&fr)() = f; + +struct S { int& a; }; +// CHECK: @s = global %struct.S { i32* @a } +S s = { a }; + +// PR5581 +namespace PR5581 { +class C { +public: + enum { e0, e1 }; + unsigned f; +}; + +// CHECK: @_ZN6PR55812g0E = global %"class.PR5581::C" { i32 1 } +C g0 = { C::e1 }; +} + +namespace test2 { + struct A { + static const double d = 1.0; + static const float f = d / 2; + static int g(); + } a; + + // CHECK: @_ZN5test22t0E = global double {{1\.0+e\+0+}}, align 8 + // CHECK: @_ZN5test22t1E = global [2 x double] [double {{1\.0+e\+0+}}, double {{5\.0+e-0*}}1], align 16 + // CHECK: @_ZN5test22t2E = global double* @_ZN5test21A1d + // CHECK: @_ZN5test22t3E = global {{.*}} @_ZN5test21A1g + double t0 = A::d; + double t1[] = { A::d, A::f }; + const double *t2 = &a.d; + int (*t3)() = &a.g; +} + +// We don't expect to fold this in the frontend, but make sure it doesn't crash. +// CHECK: @PR9558 = global float 0.000000e+0 +float PR9558 = reinterpret_cast<const float&>("asd"); + +// An initialized const automatic variable cannot be promoted to a constant +// global if it has a mutable member. +struct MutableMember { + mutable int n; +}; +int writeToMutable() { + // CHECK-NOT: {{.*}}MM{{.*}} = {{.*}}constant + const MutableMember MM = { 0 }; + return ++MM.n; +} + +// Make sure we don't try to fold this in the frontend; the backend can't +// handle it. +// CHECK: @PR11705 = global i128 0 +__int128_t PR11705 = (__int128_t)&PR11705; + +// Make sure we don't try to fold this either. +// CHECK: @_ZZ23UnfoldableAddrLabelDiffvE1x = internal global i128 0 +void UnfoldableAddrLabelDiff() { static __int128_t x = (long)&&a-(long)&&b; a:b:return;} + +// But make sure we do fold this. +// CHECK: @_ZZ21FoldableAddrLabelDiffvE1x = internal global i64 sub (i64 ptrtoint (i8* blockaddress(@_Z21FoldableAddrLabelDiffv +void FoldableAddrLabelDiff() { static long x = (long)&&a-(long)&&b; a:b:return;} + +// CHECK: @i = constant i32* bitcast (float* @PR9558 to i32*) +int &i = reinterpret_cast<int&>(PR9558); + +int arr[2]; +// CHECK: @pastEnd = constant i32* bitcast (i8* getelementptr (i8* bitcast ([2 x i32]* @arr to i8*), i64 8) to i32*) +int &pastEnd = arr[2]; diff --git a/clang/test/CodeGenCXX/constructor-attr.cpp b/clang/test/CodeGenCXX/constructor-attr.cpp new file mode 100644 index 0000000..691795f --- /dev/null +++ b/clang/test/CodeGenCXX/constructor-attr.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +// CHECK: @llvm.global_ctors + +// PR6521 +void bar(); +struct Foo { + // CHECK: define linkonce_odr void @_ZN3Foo3fooEv + static void foo() __attribute__((constructor)) { + bar(); + } +}; diff --git a/clang/test/CodeGenCXX/constructor-conversion.cpp b/clang/test/CodeGenCXX/constructor-conversion.cpp new file mode 100644 index 0000000..f503463 --- /dev/null +++ b/clang/test/CodeGenCXX/constructor-conversion.cpp @@ -0,0 +1,55 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +extern "C" int printf(...); + +class X { // ... +public: + X(int) : iX(2), fX(2.3) , name("HELLO\n") { } + + X(const char* arg, int ix=0) { iX = ix; fX = 6.0; name = arg+ix; } + X(): iX(100), fX(1.2) {} + int iX; + float fX; + const char *name; + void pr(void) { + printf("iX = %d fX = %f name = %s\n", iX, fX, name); + } +}; + +void g(X arg) { + arg.pr(); +} + +void f(X arg) { + X a = 1; // a = X(1) + + a.pr(); + + X b = "Jessie"; // b=X("Jessie",0) + + b.pr(); + + + a = 2; // a = X(2) + + a.pr(); +} + + +int main() { + X x; + f(x); + g(3); // g(X(3)) +} + +// CHECK-LP64: callq __ZN1XC1Ei +// CHECK-LP64: callq __ZN1XC1EPKci +// CHECK-LP64: callq __ZN1XC1Ev + +// CHECK-LP32: calll L__ZN1XC1Ei +// CHECK-LP32: calll L__ZN1XC1EPKci +// CHECK-LP32: calll L__ZN1XC1Ev diff --git a/clang/test/CodeGenCXX/constructor-convert.cpp b/clang/test/CodeGenCXX/constructor-convert.cpp new file mode 100644 index 0000000..7feeaa9 --- /dev/null +++ b/clang/test/CodeGenCXX/constructor-convert.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s + +// PR5775 +class Twine { +public: + Twine(const char *Str) { } +}; + +static void error(const Twine &Message) {} + +template<typename> +struct opt_storage { + void f() { + error("cl::location(x) specified more than once!"); + } +}; + +void f(opt_storage<int> o) { + o.f(); +} diff --git a/clang/test/CodeGenCXX/constructor-default-arg.cpp b/clang/test/CodeGenCXX/constructor-default-arg.cpp new file mode 100644 index 0000000..32086c1 --- /dev/null +++ b/clang/test/CodeGenCXX/constructor-default-arg.cpp @@ -0,0 +1,40 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +extern "C" int printf(...); + + +struct C { + C() : iC(6) {} + int iC; +}; + +int foo() { + return 6; +}; + +class X { // ... +public: + X(int) {} + X(const X&, int i = 1, int j = 2, int k = foo()) { + printf("X(const X&, %d, %d, %d)\n", i, j, k); + } +}; + +int main() { + X a(1); + X b(a, 2); + X c = b; + X d(a, 5, 6); +} + +// CHECK-LP64: callq __ZN1XC1ERKS_iii +// CHECK-LP64: callq __ZN1XC1ERKS_iii +// CHECK-LP64: callq __ZN1XC1ERKS_iii + +// CHECK-LP32: calll L__ZN1XC1ERKS_iii +// CHECK-LP32: calll L__ZN1XC1ERKS_iii +// CHECK-LP32: calll L__ZN1XC1ERKS_iii diff --git a/clang/test/CodeGenCXX/constructor-direct-call.cpp b/clang/test/CodeGenCXX/constructor-direct-call.cpp new file mode 100644 index 0000000..75e6f21 --- /dev/null +++ b/clang/test/CodeGenCXX/constructor-direct-call.cpp @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -triple i686-pc-win32 -fms-extensions -Wmicrosoft %s -emit-llvm -o - | FileCheck %s + +class Test1 { +public: + int a; +}; + +void f1() { + Test1 var; + var.Test1::Test1(); + + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* %{{.*}}, i32 4, i32 4, i1 false) + var.Test1::Test1(var); +} + +class Test2 { +public: + Test2() { a = 10; b = 10; } + int a; + int b; +}; + +void f2() { + // CHECK: %var = alloca %class.Test2, align 4 + // CHECK-NEXT: call void @_ZN5Test2C1Ev(%class.Test2* %var) + Test2 var; + + // CHECK-NEXT: call void @_ZN5Test2C1Ev(%class.Test2* %var) + var.Test2::Test2(); + + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i32(i8* %{{.*}}, i8* %{{.*}}, i32 8, i32 4, i1 false) + var.Test2::Test2(var); +} + + + + +class Test3 { +public: + Test3() { a = 10; b = 15; c = 20; } + Test3(const Test3& that) { a = that.a; b = that.b; c = that.c; } + int a; + int b; + int c; +}; + +void f3() { + // CHECK: call void @_ZN5Test3C1Ev(%class.Test3* %var) + Test3 var; + + // CHECK-NEXT: call void @_ZN5Test3C1Ev(%class.Test3* %var2) + Test3 var2; + + // CHECK-NEXT: call void @_ZN5Test3C1Ev(%class.Test3* %var) + var.Test3::Test3(); + + // CHECK-NEXT: call void @_ZN5Test3C1ERKS_(%class.Test3* %var, %class.Test3* %var2) + var.Test3::Test3(var2); +} + diff --git a/clang/test/CodeGenCXX/constructor-for-array-members.cpp b/clang/test/CodeGenCXX/constructor-for-array-members.cpp new file mode 100644 index 0000000..7a365cd --- /dev/null +++ b/clang/test/CodeGenCXX/constructor-for-array-members.cpp @@ -0,0 +1,44 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +extern "C" int printf(...); + +int i = 1234; +float vf = 1.00; + +struct S { + S() : iS(i++), f1(vf++) {printf("S::S()\n");} + ~S(){printf("S::~S(iS = %d f1 = %f)\n", iS, f1); } + int iS; + float f1; +}; + +struct M { + double dM; + S ARR_S[3]; + void pr() { + for (int i = 0; i < 3; i++) + printf("ARR_S[%d].iS = %d ARR_S[%d].f1 = %f\n", i, ARR_S[i].iS, i, ARR_S[i].f1); + + for (int i = 0; i < 2; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 4; k++) + printf("MULTI_ARR[%d][%d][%d].iS = %d MULTI_ARR[%d][%d][%d].f1 = %f\n", + i,j,k, MULTI_ARR[i][j][k].iS, i,j,k, MULTI_ARR[i][j][k].f1); + + } + + S MULTI_ARR[2][3][4]; +}; + +int main() { + M m1; + m1.pr(); +} + +// CHECK-LP64: callq __ZN1SC1Ev + +// CHECK-LP32: calll L__ZN1SC1Ev diff --git a/clang/test/CodeGenCXX/constructor-init-reference.cpp b/clang/test/CodeGenCXX/constructor-init-reference.cpp new file mode 100644 index 0000000..5e75159 --- /dev/null +++ b/clang/test/CodeGenCXX/constructor-init-reference.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | grep "store i32\* @x, i32\*\*" + +int x; +struct A { + int& y; + A() : y(x) {} +}; +A z; + diff --git a/clang/test/CodeGenCXX/constructor-init.cpp b/clang/test/CodeGenCXX/constructor-init.cpp new file mode 100644 index 0000000..9f808f6 --- /dev/null +++ b/clang/test/CodeGenCXX/constructor-init.cpp @@ -0,0 +1,222 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 %s -emit-llvm -o %t +// RUN: FileCheck %s < %t +// RUN: FileCheck -check-prefix=CHECK-PR10720 %s < %t + +extern "C" int printf(...); + +struct M { + M() { printf("M()\n"); } + M(int i) { iM = i; printf("M(%d)\n", i); } + int iM; + void MPR() {printf("iM = %d\n", iM); }; +}; + +struct P { + P() { printf("P()\n"); } + P(int i) { iP = i; printf("P(%d)\n", i); } + int iP; + void PPR() {printf("iP = %d\n", iP); }; +}; + +struct Q { + Q() { printf("Q()\n"); } + Q(int i) { iQ = i; printf("Q(%d)\n", i); } + int iQ; + void QPR() {printf("iQ = %d\n", iQ); }; +}; + +struct N : M , P, Q { + N() : f1(1.314), P(2000), ld(00.1234+f1), M(1000), Q(3000), + d1(3.4567), i1(1234), m1(100) { printf("N()\n"); } + M m1; + M m2; + float f1; + int i1; + float d1; + void PR() { + printf("f1 = %f d1 = %f i1 = %d ld = %f \n", f1,d1,i1, ld); + MPR(); + PPR(); + QPR(); + printf("iQ = %d\n", iQ); + printf("iP = %d\n", iP); + printf("iM = %d\n", iM); + // FIXME. We don't yet support this syntax. + // printf("iQ = %d\n", (*this).iQ); + printf("iQ = %d\n", this->iQ); + printf("iP = %d\n", this->iP); + printf("iM = %d\n", this->iM); + } + float ld; + float ff; + M arr_m[3]; + P arr_p[1][3]; + Q arr_q[2][3][4]; +}; + +int main() { + M m1; + + N n1; + n1.PR(); +} + +// PR5826 +template <class T> struct A { + A() {} + A(int) {} + A(const A&) {} + ~A() {} + operator int() {return 0;} +}; + +// CHECK: define void @_Z1fv() +void f() { + // CHECK: call void @_ZN1AIsEC1Ei + A<short> a4 = 97; + + // CHECK-NEXT: store i32 17 + int i = 17; + + // CHECK-NEXT: call void @_ZN1AIsED1Ev + // CHECK-NOT: call void @_ZN1AIsED1Ev + // CHECK: ret void +} + +// Make sure we initialize the vtable pointer if it's required by a +// base initializer. +namespace InitVTable { + struct A { A(int); }; + struct B : A { + virtual int foo(); + B(); + B(int); + }; + + // CHECK: define void @_ZN10InitVTable1BC2Ev(%"struct.InitVTable::B"* %this) unnamed_addr + // CHECK: [[T0:%.*]] = bitcast [[B:%.*]]* [[THIS:%.*]] to i8*** + // CHECK-NEXT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2), i8*** [[T0]] + // CHECK: [[VTBL:%.*]] = load i32 ([[B]]*)*** {{%.*}} + // CHECK-NEXT: [[FNP:%.*]] = getelementptr inbounds i32 ([[B]]*)** [[VTBL]], i64 0 + // CHECK-NEXT: [[FN:%.*]] = load i32 ([[B]]*)** [[FNP]] + // CHECK-NEXT: [[ARG:%.*]] = call i32 [[FN]]([[B]]* [[THIS]]) + // CHECK-NEXT: call void @_ZN10InitVTable1AC2Ei({{.*}}* {{%.*}}, i32 [[ARG]]) + // CHECK-NEXT: [[T0:%.*]] = bitcast [[B]]* [[THIS]] to i8*** + // CHECK-NEXT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2), i8*** [[T0]] + // CHECK-NEXT: ret void + B::B() : A(foo()) {} + + // CHECK: define void @_ZN10InitVTable1BC2Ei(%"struct.InitVTable::B"* %this, i32 %x) unnamed_addr + // CHECK: [[ARG:%.*]] = add nsw i32 {{%.*}}, 5 + // CHECK-NEXT: call void @_ZN10InitVTable1AC2Ei({{.*}}* {{%.*}}, i32 [[ARG]]) + // CHECK-NEXT: [[T0:%.*]] = bitcast [[B]]* {{%.*}} to i8*** + // CHECK-NEXT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN10InitVTable1BE, i64 0, i64 2), i8*** [[T0]] + // CHECK-NEXT: ret void + B::B(int x) : A(x + 5) {} +} + +namespace rdar9694300 { + struct X { + int x; + }; + + // CHECK: define void @_ZN11rdar96943001fEv + void f() { + // CHECK: alloca + X x; + // CHECK-NEXT: [[I:%.*]] = alloca i32 + // CHECK-NEXT: store i32 17, i32* [[I]] + int i = 17; + // CHECK-NEXT: ret void + } +} + +template<typename T> +struct X { + X(const X &); + + T *start; + T *end; +}; + +template<typename T> struct X; + +// Make sure that the instantiated constructor initializes start and +// end properly. +// CHECK: define linkonce_odr void @_ZN1XIiEC2ERKS0_(%struct.X* %this, %struct.X* %other) unnamed_addr +// CHECK: {{store.*null}} +// CHECK: {{store.*null}} +// CHECK: ret +template<typename T> +X<T>::X(const X &other) : start(0), end(0) { } + +X<int> get_X(X<int> x) { return x; } + +namespace PR10720 { + struct X { + X(const X&); + X(X&&); + X& operator=(const X&); + X& operator=(X&&); + ~X(); + }; + + struct pair2 { + X second[4]; + + // CHECK-PR10720: define linkonce_odr {{.*}} @_ZN7PR107205pair2aSERKS0_ + // CHECK-PR10720: load + // CHECK-PR10720: icmp ne + // CHECK-PR10720-NEXT: br i1 + // CHECK-PR10720: call {{.*}} @_ZN7PR107201XaSERKS0_ + // CHECK-PR10720: ret + pair2 &operator=(const pair2&) = default; + + // CHECK-PR10720: define linkonce_odr {{.*}} @_ZN7PR107205pair2aSEOS0_ + // CHECK-PR10720: load + // CHECK-PR10720: icmp ne + // CHECK-PR10720-NEXT: br i1 + // CHECK-PR10720: call {{.*}} @_ZN7PR107201XaSEOS0_ + // CHECK-PR10720: ret + pair2 &operator=(pair2&&) = default; + + // CHECK-PR10720: define linkonce_odr void @_ZN7PR107205pair2C2EOS0_ + // CHECK-PR10720-NOT: ret + // CHECK-PR10720: load + // CHECK-PR10720: icmp ult + // CHECK-PR10720-NEXT: br i1 + // CHECK-PR10720: call void @_ZN7PR107201XC1EOS0_ + // CHECK-PR10720-NEXT: br label + // CHECK-PR10720: ret void + pair2(pair2&&) = default; + + // CHECK-PR10720: define linkonce_odr void @_ZN7PR107205pair2C2ERKS0_ + // CHECK-PR10720-NOT: ret + // CHECK-PR10720: load + // CHECK-PR10720: icmp ult + // CHECK-PR10720-NEXT: br i1 + // CHECK-PR10720: call void @_ZN7PR107201XC1ERKS0_ + // CHECK-PR10720-NEXT: br label + // CHECK-PR10720: ret void + pair2(const pair2&) = default; + }; + + struct pair : X { // Make the copy constructor non-trivial, so we actually generate it. + int second[4]; + // CHECK-PR10720: define linkonce_odr void @_ZN7PR107204pairC2ERKS0_ + // CHECK-PR10720-NOT: ret + // CHECK-PR10720: call void @llvm.memcpy + // CHECK-PR10720-NEXT: ret void + pair(const pair&) = default; + }; + + void foo(const pair &x, const pair2 &x2) { + pair y(x); + pair2 y2(x2); + pair2 y2m(static_cast<pair2&&>(y2)); + + y2 = x2; + y2m = static_cast<pair2&&>(y2); + } + +} diff --git a/clang/test/CodeGenCXX/constructor-template.cpp b/clang/test/CodeGenCXX/constructor-template.cpp new file mode 100644 index 0000000..fe4687c --- /dev/null +++ b/clang/test/CodeGenCXX/constructor-template.cpp @@ -0,0 +1,54 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +// PR4826 +struct A { + A() { + } +}; + +template<typename T> +struct B { + B(T) {} + + A nodes; +}; + + +// PR4853 +template <typename T> class List { +public: + List(){ } // List<BinomialNode<int>*>::List() remains undefined. + ~List() {} +}; + +template <typename T> class Node { + int i; +public: + Node(){ } // Node<BinomialNode<int>*>::Node() remains undefined. + ~Node() {} +}; + + +template<typename T> class BinomialNode : Node<BinomialNode<T>*> { +public: + BinomialNode(T value) {} + List<BinomialNode<T>*> nodes; +}; + +int main() { + B<int> *n = new B<int>(4); + BinomialNode<int> *node = new BinomialNode<int>(1); + delete node; +} + +// CHECK-LP64: __ZN4NodeIP12BinomialNodeIiEEC2Ev: +// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEEC1Ev: +// CHECK-LP64: __ZN4ListIP12BinomialNodeIiEED1Ev: + +// CHECK-LP32: __ZN4NodeIP12BinomialNodeIiEEC2Ev: +// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEEC1Ev: +// CHECK-LP32: __ZN4ListIP12BinomialNodeIiEED1Ev: diff --git a/clang/test/CodeGenCXX/constructors.cpp b/clang/test/CodeGenCXX/constructors.cpp new file mode 100644 index 0000000..9e2da31 --- /dev/null +++ b/clang/test/CodeGenCXX/constructors.cpp @@ -0,0 +1,115 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s + +struct Member { int x; Member(); Member(int); Member(const Member &); }; +struct VBase { int x; VBase(); VBase(int); VBase(const VBase &); }; + +struct ValueClass { + ValueClass(int x, int y) : x(x), y(y) {} + int x; + int y; +}; // subject to ABI trickery + + + +/* Test basic functionality. */ +struct A { + A(struct Undeclared &); + A(ValueClass); + Member mem; +}; + +A::A(struct Undeclared &ref) : mem(0) {} + +// Check that delegation works. +// CHECK: define void @_ZN1AC1ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr +// CHECK: call void @_ZN1AC2ER10Undeclared( + +// CHECK: define void @_ZN1AC2ER10Undeclared(%struct.A* %this, %struct.Undeclared* %ref) unnamed_addr +// CHECK: call void @_ZN6MemberC1Ei( + +A::A(ValueClass v) : mem(v.y - v.x) {} + +// CHECK: define void @_ZN1AC1E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr +// CHECK: call void @_ZN1AC2E10ValueClass( + +// CHECK: define void @_ZN1AC2E10ValueClass(%struct.A* %this, i64 %v.coerce) unnamed_addr +// CHECK: call void @_ZN6MemberC1Ei( + + +/* Test that things work for inheritance. */ +struct B : A { + B(struct Undeclared &); + Member mem; +}; + +B::B(struct Undeclared &ref) : A(ref), mem(1) {} + +// CHECK: define void @_ZN1BC1ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr +// CHECK: call void @_ZN1BC2ER10Undeclared( + +// CHECK: define void @_ZN1BC2ER10Undeclared(%struct.B* %this, %struct.Undeclared* %ref) unnamed_addr +// CHECK: call void @_ZN1AC2ER10Undeclared( +// CHECK: call void @_ZN6MemberC1Ei( + + + +/* Test that the delegation optimization is disabled for classes with + virtual bases (for now). This is necessary because a vbase + initializer could access one of the parameter variables by + reference. That's a solvable problem, but let's not solve it right + now. */ +struct C : virtual A { + C(int); + Member mem; +}; +C::C(int x) : A(ValueClass(x, x+1)), mem(x * x) {} + +// CHECK: define void @_ZN1CC1Ei(%struct.C* %this, i32 %x) unnamed_addr +// CHECK: call void @_ZN10ValueClassC1Eii( +// CHECK: call void @_ZN1AC2E10ValueClass( +// CHECK: call void @_ZN6MemberC1Ei( + +// CHECK: define void @_ZN1CC2Ei(%struct.C* %this, i8** %vtt, i32 %x) unnamed_addr +// CHECK: call void @_ZN6MemberC1Ei( + + + +/* Test that the delegation optimization is disabled for varargs + constructors. */ +struct D : A { + D(int, ...); + Member mem; +}; + +D::D(int x, ...) : A(ValueClass(x, x+1)), mem(x*x) {} + +// CHECK: define void @_ZN1DC1Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr +// CHECK: call void @_ZN10ValueClassC1Eii( +// CHECK: call void @_ZN1AC2E10ValueClass( +// CHECK: call void @_ZN6MemberC1Ei( + +// CHECK: define void @_ZN1DC2Eiz(%struct.D* %this, i32 %x, ...) unnamed_addr +// CHECK: call void @_ZN10ValueClassC1Eii( +// CHECK: call void @_ZN1AC2E10ValueClass( +// CHECK: call void @_ZN6MemberC1Ei( + + +// PR6622: this shouldn't crash +namespace test0 { + struct A {}; + struct B : virtual A { int x; }; + struct C : B {}; + + void test(C &in) { + C tmp = in; + } +} + +namespace test1 { + struct A { A(); void *ptr; }; + struct B { B(); int x; A a[0]; }; + B::B() {} + // CHECK: define void @_ZN5test11BC2Ev( + // CHECK: [[THIS:%.*]] = load [[B:%.*]]** + // CHECK-NEXT: ret void +} diff --git a/clang/test/CodeGenCXX/conversion-function.cpp b/clang/test/CodeGenCXX/conversion-function.cpp new file mode 100644 index 0000000..76d9e02 --- /dev/null +++ b/clang/test/CodeGenCXX/conversion-function.cpp @@ -0,0 +1,120 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// XFAIL: * +extern "C" int printf(...); +struct S { + operator int(); +}; + +S::operator int() { + return 10; +} + +int f(S s) { + return s; +} + +class X { // ... + public: operator int() { printf("operator int()\n"); return iX; } + public: operator float() { printf("operator float()\n"); return fX; } + X() : iX(100), fX(1.234) {} + int iX; + float fX; +}; + +X x; + +struct Z { + operator X() { printf("perator X()\n"); x.iX += iZ; x.fX += fZ; return x; } + int iZ; + float fZ; + Z() : iZ(1), fZ(1.00) {} +}; + +Z z; + +class Y { // ... + public: operator Z(){printf("perator Z()\n"); return z; } +}; + +Y y; + +int count=0; +class O { // ... +public: + operator int(){ return ++iO; } + O() : iO(count++) {} + int iO; +}; + +void g(O a, O b) { + int i = (a) ? 1+a : 0; + int j = (a&&b) ? a+b : i; + if (a) { } + printf("i = %d j = %d a.iO = %d b.iO = %d\n", i, j, a.iO, b.iO); +} + +int main() { + int c = X(Z(y)); // OK: y.operator Z().operator X().operator int() + printf("c = %d\n", c); + float f = X(Z(y)); + printf("f = %f\n", f); + int i = x; + printf("i = %d float = %f\n", i, float(x)); + i = int(X(Z(y))); + f = float(X(Z(y))); + printf("i = %d float = %f\n", i,f); + f = (float)x; + i = (int)x; + printf("i = %d float = %f\n", i,f); + + int d = (X)((Z)y); + printf("d = %d\n", d); + + int e = (int)((X)((Z)y)); + printf("e = %d\n", e); + O o1, o2; + g(o1, o2); +} + +// Test. Conversion in base class is visible in derived class. +class XB { + int a; +public: + operator int(); +}; + +class Yb : public XB { + double b; +public: + operator char(); +}; + +void f(Yb& a) { + int i = a; // OK. calls XB::operator int(); + char ch = a; // OK. calls Yb::operator char(); +} + +struct A { + operator int() const; +}; + +// CHECK-LP64: .globl __ZN1ScviEv +// CHECK-LP64-NEXT: __ZN1ScviEv: +// CHECK-LP64: callq __ZN1Ycv1ZEv +// CHECK-LP64: callq __ZN1Zcv1XEv +// CHECK-LP64: callq __ZN1XcviEv +// CHECK-LP64: callq __ZN1XcvfEv +// CHECK-LP64: callq __ZN2XBcviEv +// CHECK-LP64: callq __ZN2YbcvcEv + +// CHECK-LP32: .globl __ZN1ScviEv +// CHECK-LP32-NEXT: __ZN1ScviEv: +// CHECK-LP32: call L__ZN1Ycv1ZEv +// CHECK-LP32: call L__ZN1Zcv1XEv +// CHECK-LP32: call L__ZN1XcviEv +// CHECK-LP32: call L__ZN1XcvfEv +// CHECK-LP32: call L__ZN2XBcviEv +// CHECK-LP32: call L__ZN2YbcvcEv diff --git a/clang/test/CodeGenCXX/conversion-operator-base.cpp b/clang/test/CodeGenCXX/conversion-operator-base.cpp new file mode 100644 index 0000000..8fbeadf --- /dev/null +++ b/clang/test/CodeGenCXX/conversion-operator-base.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -emit-llvm-only %s -verify +// PR5730 + +struct A { operator int(); float y; }; +struct B : A { double z; }; +void a() { switch(B()) {} } + diff --git a/clang/test/CodeGenCXX/convert-to-fptr.cpp b/clang/test/CodeGenCXX/convert-to-fptr.cpp new file mode 100644 index 0000000..425f79d --- /dev/null +++ b/clang/test/CodeGenCXX/convert-to-fptr.cpp @@ -0,0 +1,47 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +extern "C" int printf(...); + +int f1(int arg) { return arg; }; + +int f2(float arg) { return int(arg); }; + +typedef int (*fp1)(int); + +typedef int (*fp2)(float); + +struct A { + operator fp1() { return f1; } + operator fp2() { return f2; } +} a; + + +// Test for function reference. +typedef int (&fr1)(int); +typedef int (&fr2)(float); + +struct B { + operator fr1() { return f1; } + operator fr2() { return f2; } +} b; + +int main() +{ + int i = a(10); // Calls f1 via pointer returned from conversion function + printf("i = %d\n", i); + + int j = b(20); // Calls f1 via pointer returned from conversion function + printf("j = %d\n", j); + return 0; +} + +// CHECK-LP64: callq __ZN1AcvPFiiEEv +// CHECK-LP64: callq __ZN1BcvRFiiEEv + +// CHECK-LP32: calll L__ZN1AcvPFiiEEv +// CHECK-LP32: calll L__ZN1BcvRFiiEEv + diff --git a/clang/test/CodeGenCXX/copy-assign-synthesis-1.cpp b/clang/test/CodeGenCXX/copy-assign-synthesis-1.cpp new file mode 100644 index 0000000..46d0483 --- /dev/null +++ b/clang/test/CodeGenCXX/copy-assign-synthesis-1.cpp @@ -0,0 +1,109 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +extern "C" int printf(...); + +struct B { + B() : B1(3.14), B2(3.15), auB2(3.16) {} + float B1; + float B2; + void pr() { + printf("B1 = %f B2 = %f auB1 = %f\n", B1, B2, auB1); + } + + B& operator=(const B& arg) { B1 = arg.B1; B2 = arg.B2; + auB1 = arg.auB1; return *this; } + union { + float auB1; + float auB2; + }; +}; + +struct M { + M() : M1(10), M2(11) , auM1(12) {} + int M1; + int M2; + void pr() { + printf("M1 = %d M2 = %d auM1 = %d auM2 = %d\n", M1, M2, auM1, auM2); + } + union { + int auM1; + int auM2; + }; +}; + +struct N : B { + N() : N1(20), N2(21) {} + int N1; + int N2; + void pr() { + printf("N1 = %d N2 = %d\n", N1, N2); + for (unsigned i = 0; i < 3; i++) + for (unsigned j = 0; j < 2; j++) + printf("arr_b[%d][%d] = %f\n", i,j,arr_b[i][j].B1); + B::pr(); + } + N& operator=(const N& arg) { + N1 = arg.N1; N2 = arg.N2; + for (unsigned i = 0; i < 3; i++) + for (unsigned j = 0; j < 2; j++) + arr_b[i][j] = arg.arr_b[i][j]; + return *this; + } + B arr_b[3][2]; +}; + +struct Q : B { + Q() : Q1(30), Q2(31) {} + int Q1; + int Q2; + void pr() { + printf("Q1 = %d Q2 = %d\n", Q1, Q2); + } +}; + + +struct X : M , N { + X() : d(0.0), d1(1.1), d2(1.2), d3(1.3) {} + double d; + double d1; + double d2; + double d3; + void pr() { + printf("d = %f d1 = %f d2 = %f d3 = %f\n", d, d1,d2,d3); + M::pr(); N::pr(); + q1.pr(); q2.pr(); + } + + Q q1, q2; +}; + + +X srcX; +X dstX; +X dstY; + +int main() { + dstY = dstX = srcX; + srcX.pr(); + dstX.pr(); + dstY.pr(); +} + +// CHECK-LP64: .globl __ZN1XaSERKS_ +// CHECK-LP64: .weak_definition __ZN1XaSERKS_ +// CHECK-LP64: __ZN1XaSERKS_: +// CHECK-LP64: .globl __ZN1QaSERKS_ +// CHECK-LP64: .weak_definition __ZN1QaSERKS_ +// CHECK-LP64: __ZN1QaSERKS_: + +// CHECK-LP32: .globl __ZN1XaSERKS_ +// CHECK-LP32: .weak_definition __ZN1XaSERKS_ +// CHECK-LP32: __ZN1XaSERKS_: +// CHECK-LP32: .globl __ZN1QaSERKS_ +// CHECK-LP32: .weak_definition __ZN1QaSERKS_ +// CHECK-LP32: __ZN1QaSERKS_: + diff --git a/clang/test/CodeGenCXX/copy-assign-synthesis-2.cpp b/clang/test/CodeGenCXX/copy-assign-synthesis-2.cpp new file mode 100644 index 0000000..c25e046 --- /dev/null +++ b/clang/test/CodeGenCXX/copy-assign-synthesis-2.cpp @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s +struct A {}; +A& (A::*x)(const A&) = &A::operator=; +// CHECK: define linkonce_odr %struct.A* @_ZN1AaSERKS_ diff --git a/clang/test/CodeGenCXX/copy-assign-synthesis-3.cpp b/clang/test/CodeGenCXX/copy-assign-synthesis-3.cpp new file mode 100644 index 0000000..ce4640a --- /dev/null +++ b/clang/test/CodeGenCXX/copy-assign-synthesis-3.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -emit-llvm-only -verify %s + +struct A { + A& operator=(A&); +}; + +struct B { + void operator=(B); +}; + +struct C { + A a; + B b; + float c; + int (A::*d)(); + _Complex float e; + int f[10]; + A g[2]; + B h[2]; +}; +void a(C& x, C& y) { + x = y; +} + diff --git a/clang/test/CodeGenCXX/copy-assign-synthesis.cpp b/clang/test/CodeGenCXX/copy-assign-synthesis.cpp new file mode 100644 index 0000000..e9fc0c3 --- /dev/null +++ b/clang/test/CodeGenCXX/copy-assign-synthesis.cpp @@ -0,0 +1,79 @@ +// RUN: %clang_cc1 -emit-llvm -o %t %s +// RUN: grep "_ZN1XaSERK1X" %t | count 0 + +extern "C" int printf(...); + +struct B { + B() : B1(3.14), B2(3.15), auB2(3.16) {} + float B1; + float B2; + void pr() { + printf("B1 = %f B2 = %f auB1 = %f\n", B1, B2, auB1); + } + + union { + float auB1; + float auB2; + }; +}; + +struct M { + M() : M1(10), M2(11) , auM1(12) {} + int M1; + int M2; + void pr() { + printf("M1 = %d M2 = %d auM1 = %d auM2 = %d\n", M1, M2, auM1, auM2); + } + union { + int auM1; + int auM2; + }; +}; + +struct N : B { + N() : N1(20), N2(21) {} + int N1; + int N2; + void pr() { + printf("N1 = %d N2 = %d\n", N1, N2); + B::pr(); + } +}; + +struct Q { + Q() : Q1(30), Q2(31) {} + int Q1; + int Q2; + void pr() { + printf("Q1 = %d Q2 = %d\n", Q1, Q2); + } +}; + + +struct X : M , N { + X() : d(0.0), d1(1.1), d2(1.2), d3(1.3) {} + double d; + double d1; + double d2; + double d3; + void pr() { + printf("d = %f d1 = %f d2 = %f d3 = %f\n", d, d1,d2,d3); + M::pr(); N::pr(); + q1.pr(); q2.pr(); + } + + Q q1, q2; +}; + + +X srcX; +X dstX; +X dstY; + +int main() { + dstY = dstX = srcX; + srcX.pr(); + dstX.pr(); + dstY.pr(); +} + diff --git a/clang/test/CodeGenCXX/copy-assign-volatile-synthesis.cpp b/clang/test/CodeGenCXX/copy-assign-volatile-synthesis.cpp new file mode 100644 index 0000000..eb13503 --- /dev/null +++ b/clang/test/CodeGenCXX/copy-assign-volatile-synthesis.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s +// rdar://9894548 + +typedef unsigned long word_t; +typedef unsigned long u64_t; +typedef unsigned int u32_t; + +class ioapic_redir_t { +public: + union { + struct { + word_t vector : 8; + + word_t delivery_mode : 3; + word_t dest_mode : 1; + + word_t delivery_status : 1; + word_t polarity : 1; + word_t irr : 1; + word_t trigger_mode : 1; + + word_t mask : 1; + word_t _pad0 : 15; + + word_t dest : 8; + }; + volatile u32_t raw[2]; + volatile u64_t raw64; + }; +}; + +struct ioapic_shadow_struct +{ + ioapic_redir_t redirs[24]; +} ioapic_shadow[16]; + +void init_ioapic(unsigned long ioapic_id) +{ + ioapic_redir_t entry; + ioapic_shadow[ioapic_id].redirs[3] = entry; +} + +// CHECK: call void @llvm.memcpy diff --git a/clang/test/CodeGenCXX/copy-constructor-elim-2.cpp b/clang/test/CodeGenCXX/copy-constructor-elim-2.cpp new file mode 100644 index 0000000..9480cbf --- /dev/null +++ b/clang/test/CodeGenCXX/copy-constructor-elim-2.cpp @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +struct A { int x; A(int); ~A(); }; +A f() { return A(0); } +// CHECK: define void @_Z1fv +// CHECK: call {{.*}} @_ZN1AC1Ei +// CHECK-NEXT: ret void + +// Verify that we do not elide copies when constructing a base class. +namespace no_elide_base { + struct Base { + Base(const Base&); + ~Base(); + }; + + struct Other { + operator Base() const; + }; + + struct Derived : public virtual Base { + Derived(const Other &O); + }; + + // CHECK: define {{.*}} @_ZN13no_elide_base7DerivedC1ERKNS_5OtherE(%"struct.no_elide_base::Derived"* %this, %"struct.no_elide_base::Other"* %O) unnamed_addr + Derived::Derived(const Other &O) + // CHECK: call {{.*}} @_ZNK13no_elide_base5OthercvNS_4BaseEEv + // CHECK: call {{.*}} @_ZN13no_elide_base4BaseC2ERKS0_ + // CHECK: call {{.*}} @_ZN13no_elide_base4BaseD1Ev + : Base(O) + { + // CHECK: ret + } +} + +// PR8683. + +namespace PR8683 { + +struct A { + A(); + A(const A&); + A& operator=(const A&); +}; + +struct B { + A a; +}; + +void f() { + // Verify that we don't mark the copy constructor in this expression as elidable. + // CHECK: call {{.*}} @_ZN6PR86831AC1ERKS0_ + A a = (B().a); +} + +} + +namespace PR12139 { + struct A { + A() : value(1) { } + A(A const &, int value = 2) : value(value) { } + int value; + + static A makeA() { A a; a.value = 2; return a; } + }; + + // CHECK: define i32 @_ZN7PR121394testEv + int test() { + // CHECK: call void @_ZN7PR121391A5makeAEv + // CHECK-NEXT: call void @_ZN7PR121391AC1ERKS0_i + A a(A::makeA(), 3); + // CHECK-NEXT: getelementptr inbounds + // CHECK-NEXT: load + // CHECK-NEXT: ret i32 + return a.value; + } +} + diff --git a/clang/test/CodeGenCXX/copy-constructor-elim.cpp b/clang/test/CodeGenCXX/copy-constructor-elim.cpp new file mode 100644 index 0000000..c883584 --- /dev/null +++ b/clang/test/CodeGenCXX/copy-constructor-elim.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -emit-llvm -o %t %s +// RUN: grep "_ZN1CC1ERK1C" %t | count 0 +// RUN: grep "_ZN1SC1ERK1S" %t | count 0 + +extern "C" int printf(...); + + +struct C { + C() : iC(6) {printf("C()\n"); } + C(const C& c) { printf("C(const C& c)\n"); } + int iC; +}; + +C foo() { + return C(); +}; + +class X { // ... +public: + X(int) {} + X(const X&, int i = 1, int j = 2, C c = foo()) { + printf("X(const X&, %d, %d, %d)\n", i, j, c.iC); + } +}; + + +struct S { + S(); +}; + +S::S() { printf("S()\n"); } + +void Call(S) {}; + +int main() { + X a(1); + X b(a, 2); + X c = b; + X d(a, 5, 6); + S s; + Call(s); +} diff --git a/clang/test/CodeGenCXX/copy-constructor-synthesis-2.cpp b/clang/test/CodeGenCXX/copy-constructor-synthesis-2.cpp new file mode 100644 index 0000000..d028a28 --- /dev/null +++ b/clang/test/CodeGenCXX/copy-constructor-synthesis-2.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +struct A { virtual void a(); }; +A x(A& y) { return y; } + +// CHECK: define linkonce_odr {{.*}} @_ZN1AC1ERKS_(%struct.A* %this, %struct.A*) unnamed_addr +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) diff --git a/clang/test/CodeGenCXX/copy-constructor-synthesis.cpp b/clang/test/CodeGenCXX/copy-constructor-synthesis.cpp new file mode 100644 index 0000000..68f6805 --- /dev/null +++ b/clang/test/CodeGenCXX/copy-constructor-synthesis.cpp @@ -0,0 +1,156 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck %s + +extern "C" int printf(...); + +int init = 100; + +struct M { + int iM; + M() : iM(init++) {} +}; + +struct N { + int iN; + N() : iN(200) {} + N(N const & arg){this->iN = arg.iN; } +}; + +struct P { + int iP; + P() : iP(init++) {} +}; + + +// CHECK: define linkonce_odr void @_ZN1XC1ERKS_(%struct.X* %this, %struct.X*) unnamed_addr +struct X : M, N, P { // ... + X() : f1(1.0), d1(2.0), i1(3), name("HELLO"), bf1(0xff), bf2(0xabcd), + au_i1(1234), au1_4("MASKED") {} + P p0; + void pr() { + printf("iM = %d iN = %d, m1.iM = %d\n", iM, iN, m1.iM); + printf("im = %d p0.iP = %d, p1.iP = %d\n", iP, p0.iP, p1.iP); + printf("f1 = %f d1 = %f i1 = %d name(%s) \n", f1, d1, i1, name); + printf("bf1 = %x bf2 = %x\n", bf1, bf2); + printf("au_i2 = %d\n", au_i2); + printf("au1_1 = %s\n", au1_1); + } + M m1; + P p1; + float f1; + double d1; + int i1; + const char *name; + unsigned bf1 : 8; + unsigned bf2 : 16; + int arr[2]; + _Complex float complex; + + union { + int au_i1; + int au_i2; + }; + union { + const char * au1_1; + float au1_2; + int au1_3; + const char * au1_4; + }; +}; + +static int ix = 1; +// class with user-defined copy constructor. +struct S { + S() : iS(ix++) { } + S(const S& arg) { *this = arg; } + int iS; +}; + +// class with trivial copy constructor. +struct I { + I() : iI(ix++) { } + int iI; +}; + +struct XM { + XM() { } + double dXM; + S ARR_S[3][4][2]; + void pr() { + for (unsigned i = 0; i < 3; i++) + for (unsigned j = 0; j < 4; j++) + for (unsigned k = 0; k < 2; k++) + printf("ARR_S[%d][%d][%d] = %d\n", i,j,k, ARR_S[i][j][k].iS); + for (unsigned i = 0; i < 3; i++) + for (unsigned k = 0; k < 2; k++) + printf("ARR_I[%d][%d] = %d\n", i,k, ARR_I[i][k].iI); + } + I ARR_I[3][2]; +}; + +int main() { + X a; + X b(a); + b.pr(); + X x; + X c(x); + c.pr(); + + XM m0; + XM m1 = m0; + m1.pr(); +} + +struct A { +}; + +struct B : A { + A &a; +}; + +void f(const B &b1) { + B b2(b1); +} + +// PR6628 +namespace PR6628 { + +struct T { + T(); + ~T(); + + double d; +}; + +struct A { + A(const A &other, const T &t = T(), const T& t2 = T()); +}; + +struct B : A { + A a1; + A a2; + A a[10]; +}; + +// Force the copy constructor to be synthesized. +void f(B b1) { + B b2 = b1; +} + +// CHECK: define linkonce_odr void @_ZN6PR66281BC2ERKS0_(%"struct.PR6628::B"* %this, %"struct.PR6628::B"*) unnamed_addr +// CHECK: call void @_ZN6PR66281TC1Ev +// CHECK: call void @_ZN6PR66281TC1Ev +// CHECK: call void @_ZN6PR66281AC2ERKS0_RKNS_1TES5_ +// CHECK: call void @_ZN6PR66281TD1Ev +// CHECK: call void @_ZN6PR66281TD1Ev +// CHECK: call void @_ZN6PR66281TC1Ev +// CHECK: call void @_ZN6PR66281TC1Ev +// CHECK: call void @_ZN6PR66281AC1ERKS0_RKNS_1TES5_ +// CHECK: call void @_ZN6PR66281TD1Ev +// CHECK: call void @_ZN6PR66281TD1Ev +// CHECK: call void @_ZN6PR66281TC1Ev +// CHECK: call void @_ZN6PR66281TC1Ev +// CHECK: call void @_ZN6PR66281AC1ERKS0_RKNS_1TES5_ +// CHECK: call void @_ZN6PR66281TD1Ev +// CHECK: call void @_ZN6PR66281TD1Ev +} + diff --git a/clang/test/CodeGenCXX/copy-in-cplus-object.cpp b/clang/test/CodeGenCXX/copy-in-cplus-object.cpp new file mode 100644 index 0000000..bdfca5e --- /dev/null +++ b/clang/test/CodeGenCXX/copy-in-cplus-object.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s + +struct S { + S(const char *); + ~S(); +}; + +struct TestObject +{ + TestObject(const TestObject& inObj, int def = 100, const S &Silly = "silly"); + TestObject(); + ~TestObject(); + TestObject& operator=(const TestObject& inObj); + int version() const; + +}; + +void testRoutine() { + TestObject one; + int (^V)() = ^{ return one.version(); }; +} + +// CHECK: call void @_ZN10TestObjectC1Ev +// CHECK: call void @_ZN1SC1EPKc +// CHECK: call void @_ZN10TestObjectC1ERKS_iRK1S +// CHECK: call void @_ZN1SD1Ev +// CHECK: call void @_ZN10TestObjectD1Ev +// CHECK: call void @_ZN10TestObjectD1Ev diff --git a/clang/test/CodeGenCXX/copy-initialization.cpp b/clang/test/CodeGenCXX/copy-initialization.cpp new file mode 100644 index 0000000..aecd64e --- /dev/null +++ b/clang/test/CodeGenCXX/copy-initialization.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +struct Foo { + Foo(); + Foo(const Foo&); +}; + +struct Bar { + Bar(); + operator const Foo&() const; +}; + +void f(Foo); + +// CHECK: define void @_Z1g3Foo(%struct.Foo* %foo) +void g(Foo foo) { + // CHECK: call void @_ZN3BarC1Ev + // CHECK: @_ZNK3BarcvRK3FooEv + // CHECK: call void @_Z1f3Foo + f(Bar()); + // CHECK: call void @_ZN3FooC1Ev + // CHECK: call void @_Z1f3Foo + f(Foo()); + // CHECK: call void @_ZN3FooC1ERKS_ + // CHECK: call void @_Z1f3Foo + f(foo); + // CHECK: ret +} + diff --git a/clang/test/CodeGenCXX/cxx-apple-kext.cpp b/clang/test/CodeGenCXX/cxx-apple-kext.cpp new file mode 100644 index 0000000..e5ec78b --- /dev/null +++ b/clang/test/CodeGenCXX/cxx-apple-kext.cpp @@ -0,0 +1,36 @@ +// RUN: %clangxx -target x86_64-apple-darwin10 %s -flto -S -o - |\ +// RUN: FileCheck --check-prefix=CHECK-NO-KEXT %s +// RUN: %clangxx -target x86_64-apple-darwin10 %s -fapple-kext -flto -S -o - |\ +// RUN: FileCheck --check-prefix=CHECK-KEXT %s + +// CHECK-NO-KEXT-NOT: _GLOBAL__D_a +// CHECK-NO-KEXT: @is_hosted = global +// CHECK-NO-KEXT: @_ZTI3foo = {{.*}} @_ZTVN10__cxxabiv117 +// CHECK-NO-KEXT: call i32 @__cxa_atexit({{.*}} @_ZN3fooD1Ev +// CHECK-NO-KEXT: declare i32 @__cxa_atexit + +// CHECK-KEXT: @_ZTV3foo = +// CHECK-KEXT-NOT: @_ZTVN10__cxxabiv117 +// CHECK-KEXT-NOT: call i32 @__cxa_atexit({{.*}} @_ZN3fooD1Ev +// CHECK-KEXT-NOT: declare i32 @__cxa_atexit +// CHECK-KEXT: @is_freestanding = global +// CHECK-KEXT: _GLOBAL__D_a +// CHECK-KEXT: call void @_ZN3fooD1Ev(%class.foo* @a) + +class foo { +public: + foo(); + virtual ~foo(); +}; + +foo a; +foo::~foo() {} + +#if !(__STDC_HOSTED__ == 1) +int is_freestanding = 1; +#else +int is_hosted = 1; +#endif + +extern "C" void f1() { +} diff --git a/clang/test/CodeGenCXX/cxx-block-objects.cpp b/clang/test/CodeGenCXX/cxx-block-objects.cpp new file mode 100644 index 0000000..b989065 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx-block-objects.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s +// rdar://8594790 + +extern "C" { +extern "C" void *_Block_copy(const void *aBlock); +extern "C" void _Block_release(const void *aBlock); +} + +class A { +public: + int x; + A(const A &o); + A(); + virtual ~A(); + void hello() const; +}; + +int +main() +{ + A a; + void (^c)(void) = ((__typeof(^{ a.hello(); }))_Block_copy((const void *)(^{ a.hello(); }))); + c(); + _Block_release((const void *)(c)); + return 0; +} + +// CHECK: define internal void @__copy_helper_block_ +// CHECK: call void @_ZN1AC1ERKS_ + + +// CHECK:define internal void @__destroy_helper_block_ +// CHECK: call void @_ZN1AD1Ev diff --git a/clang/test/CodeGenCXX/cxx0x-defaulted-templates.cpp b/clang/test/CodeGenCXX/cxx0x-defaulted-templates.cpp new file mode 100644 index 0000000..f4d5ccc --- /dev/null +++ b/clang/test/CodeGenCXX/cxx0x-defaulted-templates.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s + +template <typename T> +struct X { + X(); +}; + +// CHECK: define {{.*}} @_ZN1XIbEC1Ev +// CHECK: define {{.*}} @_ZN1XIbEC2Ev +template <> X<bool>::X() = default; + +// CHECK: define weak_odr {{.*}} @_ZN1XIiEC1Ev +// CHECK: define weak_odr {{.*}} @_ZN1XIiEC2Ev +template <typename T> X<T>::X() = default; +template X<int>::X(); + +// CHECK: define linkonce_odr {{.*}} @_ZN1XIcEC1Ev +// CHECK: define linkonce_odr {{.*}} @_ZN1XIcEC2Ev +X<char> x; diff --git a/clang/test/CodeGenCXX/cxx0x-delegating-ctors.cpp b/clang/test/CodeGenCXX/cxx0x-delegating-ctors.cpp new file mode 100644 index 0000000..f5684d9 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx0x-delegating-ctors.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -emit-llvm -fexceptions -fcxx-exceptions -std=c++11 -o - %s | FileCheck %s + +struct non_trivial { + non_trivial(); + ~non_trivial() noexcept(false); +}; +non_trivial::non_trivial() {} +non_trivial::~non_trivial() noexcept(false) {} + +// We use a virtual base to ensure that the constructor +// delegation optimization (complete->base) can't be +// performed. +struct delegator { + non_trivial n; + delegator(); + delegator(int); + delegator(char); + delegator(bool); +}; + +delegator::delegator() { + throw 0; +} + + +delegator::delegator(bool) +{} + +// CHECK: define {{.*}} @_ZN9delegatorC1Ec +// CHECK: {{.*}} @_ZN9delegatorC1Eb +// CHECK: void @__cxa_throw +// CHECK: void @_ZSt9terminatev +// CHECK: {{.*}} @_ZN9delegatorD1Ev +// CHECK: define {{.*}} @_ZN9delegatorC2Ec +// CHECK: {{.*}} @_ZN9delegatorC2Eb +// CHECK: void @__cxa_throw +// CHECK: void @_ZSt9terminatev +// CHECK: {{.*}} @_ZN9delegatorD2Ev +delegator::delegator(char) + : delegator(true) { + throw 0; +} + +// CHECK: define {{.*}} @_ZN9delegatorC1Ei +// CHECK: {{.*}} @_ZN9delegatorC1Ev +// CHECK-NOT: void @_ZSt9terminatev +// CHECK: ret +// CHECK-NOT: void @_ZSt9terminatev +// CHECK: define {{.*}} @_ZN9delegatorC2Ei +// CHECK: {{.*}} @_ZN9delegatorC2Ev +// CHECK-NOT: void @_ZSt9terminatev +// CHECK: ret +// CHECK-NOT: void @_ZSt9terminatev +delegator::delegator(int) + : delegator() +{} diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-array.cpp b/clang/test/CodeGenCXX/cxx0x-initializer-array.cpp new file mode 100644 index 0000000..b773178 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx0x-initializer-array.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s + +struct A { int a[1]; }; +typedef A x[]; +int f() { + x{{{1}}}; + // CHECK: define i32 @_Z1fv + // CHECK: store i32 1 + // (It's okay if the output changes here, as long as we don't crash.) +} diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-references.cpp b/clang/test/CodeGenCXX/cxx0x-initializer-references.cpp new file mode 100644 index 0000000..4c847b8 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx0x-initializer-references.cpp @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s + +namespace reference { + struct A { + int i1, i2; + }; + + void single_init() { + // No superfluous instructions allowed here, they could be + // hiding extra temporaries. + + // CHECK: store i32 1, i32* + // CHECK-NEXT: store i32* %{{.*}}, i32** + const int &cri2a = 1; + + // CHECK-NEXT: store i32 1, i32* + // CHECK-NEXT: store i32* %{{.*}}, i32** + const int &cri1a = {1}; + + // CHECK-NEXT: store i32 1, i32* + int i = 1; + // CHECK-NEXT: store i32* %{{.*}}, i32** + int &ri1a = {i}; + + // CHECK-NEXT: bitcast + // CHECK-NEXT: memcpy + A a{1, 2}; + // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** % + A &ra1a = {a}; + + // CHECK-NEXT: ret + } + + void reference_to_aggregate() { + // CHECK: getelementptr {{.*}}, i32 0, i32 0 + // CHECK-NEXT: store i32 1 + // CHECK-NEXT: getelementptr {{.*}}, i32 0, i32 1 + // CHECK-NEXT: store i32 2 + // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** %{{.*}}, align + const A &ra1{1, 2}; + + // CHECK-NEXT: getelementptr inbounds [3 x i32]* %{{.*}}, i{{32|64}} 0, i{{32|64}} 0 + // CHECK-NEXT: store i32 1 + // CHECK-NEXT: getelementptr inbounds i32* %{{.*}}, i{{32|64}} 1 + // CHECK-NEXT: store i32 2 + // CHECK-NEXT: getelementptr inbounds i32* %{{.*}}, i{{32|64}} 1 + // CHECK-NEXT: store i32 3 + // CHECK-NEXT: store [3 x i32]* %{{.*}}, [3 x i32]** %{{.*}}, align + const int (&arrayRef)[] = {1, 2, 3}; + + // CHECK-NEXT: ret + } + + struct B { + B(); + ~B(); + }; + + void single_init_temp_cleanup() + { + // Ensure lifetime extension. + + // CHECK: call void @_ZN9reference1BC1Ev + // CHECK-NEXT: store %{{.*}}* %{{.*}}, %{{.*}}** % + const B &rb{ B() }; + // CHECK: call void @_ZN9reference1BD1Ev + } + +} diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-scalars.cpp b/clang/test/CodeGenCXX/cxx0x-initializer-scalars.cpp new file mode 100644 index 0000000..10c6966 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx0x-initializer-scalars.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s + +void f() +{ + // CHECK: store i32 0 + int i{}; +} diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp new file mode 100644 index 0000000..14d2f77 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-pr12086.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - -verify %s + +namespace std { + typedef decltype(sizeof(int)) size_t; + + // libc++'s implementation + template <class _E> + class initializer_list + { + const _E* __begin_; + size_t __size_; + + initializer_list(const _E* __b, size_t __s) + : __begin_(__b), + __size_(__s) + {} + + public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + + typedef const _E* iterator; + typedef const _E* const_iterator; + + initializer_list() : __begin_(nullptr), __size_(0) {} + + size_t size() const {return __size_;} + const _E* begin() const {return __begin_;} + const _E* end() const {return __begin_ + __size_;} + }; +} + +std::initializer_list<std::initializer_list<int>> pleasefail = { + {1, 2}, {3, 4}, {5, 6} // expected-error {{cannot compile}} +}; diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp new file mode 100644 index 0000000..c533e45 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist-startend.cpp @@ -0,0 +1,85 @@ +// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s + +namespace std { + typedef decltype(sizeof(int)) size_t; + + // libc++'s implementation with __size_ replaced by __end_ + template <class _E> + class initializer_list + { + const _E* __begin_; + const _E* __end_; + + initializer_list(const _E* __b, const _E* __e) + : __begin_(__b), + __end_(__e) + {} + + public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + + typedef const _E* iterator; + typedef const _E* const_iterator; + + initializer_list() : __begin_(nullptr), __end_(nullptr) {} + + size_t size() const {return __end_ - __begin_;} + const _E* begin() const {return __begin_;} + const _E* end() const {return __end_;} + }; +} + +// CHECK: @_ZL25globalInitList1__initlist = internal global [3 x i32] [i32 1, i32 2, i32 3] +// CHECK: @globalInitList1 = global {{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, {{[^)]*}}), i32* +std::initializer_list<int> globalInitList1 = {1, 2, 3}; + +void fn1(int i) { + // CHECK: define void @_Z3fn1i + // temporary array + // CHECK: [[array:%[^ ]+]] = alloca [3 x i32] + // CHECK: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0 + // CHECK-NEXT: store i32 1, i32* + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store + // CHECK-NEXT: getelementptr + // CHECK-NEXT: load + // CHECK-NEXT: store + // init the list + // CHECK-NEXT: getelementptr + // CHECK-NEXT: getelementptr inbounds [3 x i32]* + // CHECK-NEXT: store i32* + // CHECK-NEXT: getelementptr + // CHECK-NEXT: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0, i{{32|64}} 3 + // CHECK-NEXT: store i32* + std::initializer_list<int> intlist{1, 2, i}; +} + +struct destroyme1 { + ~destroyme1(); +}; +struct destroyme2 { + ~destroyme2(); +}; + + +void fn2() { + // CHECK: define void @_Z3fn2v + void target(std::initializer_list<destroyme1>); + // objects should be destroyed before dm2, after call returns + target({ destroyme1(), destroyme1() }); + // CHECK: call void @_ZN10destroyme1D1Ev + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev +} + +void fn3() { + // CHECK: define void @_Z3fn3v + // objects should be destroyed after dm2 + auto list = { destroyme1(), destroyme1() }; + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev + // CHECK: call void @_ZN10destroyme1D1Ev +} diff --git a/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp new file mode 100644 index 0000000..81ce559 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -0,0 +1,252 @@ +// RUN: %clang_cc1 -std=c++11 -S -emit-llvm -o - %s | FileCheck %s + +namespace std { + typedef decltype(sizeof(int)) size_t; + + // libc++'s implementation + template <class _E> + class initializer_list + { + const _E* __begin_; + size_t __size_; + + initializer_list(const _E* __b, size_t __s) + : __begin_(__b), + __size_(__s) + {} + + public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + + typedef const _E* iterator; + typedef const _E* const_iterator; + + initializer_list() : __begin_(nullptr), __size_(0) {} + + size_t size() const {return __size_;} + const _E* begin() const {return __begin_;} + const _E* end() const {return __begin_ + __size_;} + }; +} + +struct destroyme1 { + ~destroyme1(); +}; +struct destroyme2 { + ~destroyme2(); +}; +struct witharg1 { + witharg1(const destroyme1&); + ~witharg1(); +}; +struct wantslist1 { + wantslist1(std::initializer_list<destroyme1>); + ~wantslist1(); +}; + +// CHECK: @_ZL25globalInitList1__initlist = internal global [3 x i32] [i32 1, i32 2, i32 3] +// CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32]* @_ZL25globalInitList1__initlist, i32 0, i32 0), i{{32|64}} 3 } +std::initializer_list<int> globalInitList1 = {1, 2, 3}; + +// CHECK: @_ZL25globalInitList2__initlist = internal global [2 x %{{[^ ]*}}] zeroinitializer +// CHECK: @globalInitList2 = global %{{[^ ]+}} { %[[WITHARG:[^ *]+]]* getelementptr inbounds ([2 x +// CHECK: appending global +// CHECK: define internal void +// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZL25globalInitList2__initlist, i{{32|64}} 0, i{{32|64}} 0 +// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]]* @_ZL25globalInitList2__initlist, i{{32|64}} 0, i{{32|64}} 1 +// CHECK: __cxa_atexit +// CHECK: call void @_ZN10destroyme1D1Ev +// CHECK: call void @_ZN10destroyme1D1Ev +std::initializer_list<witharg1> globalInitList2 = { + witharg1(destroyme1()), witharg1(destroyme1()) +}; + +void fn1(int i) { + // CHECK: define void @_Z3fn1i + // temporary array + // CHECK: [[array:%[^ ]+]] = alloca [3 x i32] + // CHECK: getelementptr inbounds [3 x i32]* [[array]], i{{32|64}} 0 + // CHECK-NEXT: store i32 1, i32* + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store + // CHECK-NEXT: getelementptr + // CHECK-NEXT: load + // CHECK-NEXT: store + // init the list + // CHECK-NEXT: getelementptr + // CHECK-NEXT: getelementptr inbounds [3 x i32]* + // CHECK-NEXT: store i32* + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store i{{32|64}} 3 + std::initializer_list<int> intlist{1, 2, i}; +} + +void fn2() { + // CHECK: define void @_Z3fn2v + void target(std::initializer_list<destroyme1>); + // objects should be destroyed before dm2, after call returns + // CHECK: call void @_Z6targetSt16initializer_listI10destroyme1E + target({ destroyme1(), destroyme1() }); + // CHECK: call void @_ZN10destroyme1D1Ev + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev +} + +void fn3() { + // CHECK: define void @_Z3fn3v + // objects should be destroyed after dm2 + auto list = { destroyme1(), destroyme1() }; + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev + // CHECK: call void @_ZN10destroyme1D1Ev +} + +void fn4() { + // CHECK: define void @_Z3fn4v + void target(std::initializer_list<witharg1>); + // objects should be destroyed before dm2, after call returns + // CHECK: call void @_ZN8witharg1C1ERK10destroyme1 + // CHECK: call void @_Z6targetSt16initializer_listI8witharg1E + target({ witharg1(destroyme1()), witharg1(destroyme1()) }); + // CHECK: call void @_ZN8witharg1D1Ev + // CHECK: call void @_ZN10destroyme1D1Ev + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev +} + +void fn5() { + // CHECK: define void @_Z3fn5v + // temps should be destroyed before dm2 + // objects should be destroyed after dm2 + // CHECK: call void @_ZN8witharg1C1ERK10destroyme1 + auto list = { witharg1(destroyme1()), witharg1(destroyme1()) }; + // CHECK: call void @_ZN10destroyme1D1Ev + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev + // CHECK: call void @_ZN8witharg1D1Ev +} + +void fn6() { + // CHECK: define void @_Z3fn6v + void target(const wantslist1&); + // objects should be destroyed before dm2, after call returns + // CHECK: call void @_ZN10wantslist1C1ESt16initializer_listI10destroyme1E + // CHECK: call void @_Z6targetRK10wantslist1 + target({ destroyme1(), destroyme1() }); + // CHECK: call void @_ZN10wantslist1D1Ev + // CHECK: call void @_ZN10destroyme1D1Ev + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev +} + +void fn7() { + // CHECK: define void @_Z3fn7v + // temps should be destroyed before dm2 + // object should be destroyed after dm2 + // CHECK: call void @_ZN10wantslist1C1ESt16initializer_listI10destroyme1E + wantslist1 wl = { destroyme1(), destroyme1() }; + // CHECK: call void @_ZN10destroyme1D1Ev + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev + // CHECK: call void @_ZN10wantslist1D1Ev +} + +void fn8() { + // CHECK: define void @_Z3fn8v + void target(std::initializer_list<std::initializer_list<destroyme1>>); + // objects should be destroyed before dm2, after call returns + // CHECK: call void @_Z6targetSt16initializer_listIS_I10destroyme1EE + std::initializer_list<destroyme1> inner; + target({ inner, { destroyme1() } }); + // CHECK: call void @_ZN10destroyme1D1Ev + // Only one destroy loop, since only one inner init list is directly inited. + // CHECK-NOT: call void @_ZN10destroyme1D1Ev + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev +} + +void fn9() { + // CHECK: define void @_Z3fn9v + // objects should be destroyed after dm2 + std::initializer_list<destroyme1> inner; + std::initializer_list<std::initializer_list<destroyme1>> list = + { inner, { destroyme1() } }; + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev + // CHECK: call void @_ZN10destroyme1D1Ev + // Only one destroy loop, since only one inner init list is directly inited. + // CHECK-NOT: call void @_ZN10destroyme1D1Ev + // CHECK: ret void +} + +struct haslist1 { + std::initializer_list<int> il; + haslist1(); +}; + +// CHECK: define void @_ZN8haslist1C2Ev +haslist1::haslist1() +// CHECK: alloca [3 x i32] +// CHECK: store i32 1 +// CHECK: store i32 2 +// CHECK: store i32 3 +// CHECK: store i{{32|64}} 3 + : il{1, 2, 3} +{ + destroyme2 dm2; +} + +struct haslist2 { + std::initializer_list<destroyme1> il; + haslist2(); +}; + +// CHECK: define void @_ZN8haslist2C2Ev +haslist2::haslist2() + : il{destroyme1(), destroyme1()} +{ + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev + // CHECK: call void @_ZN10destroyme1D1Ev +} + +void fn10() { + // CHECK: define void @_Z4fn10v + // CHECK: alloca [3 x i32] + // CHECK: call noalias i8* @_Znw{{[jm]}} + // CHECK: store i32 1 + // CHECK: store i32 2 + // CHECK: store i32 3 + // CHECK: store i32* + // CHECK: store i{{32|64}} 3 + (void) new std::initializer_list<int> {1, 2, 3}; +} + +void fn11() { + // CHECK: define void @_Z4fn11v + (void) new std::initializer_list<destroyme1> {destroyme1(), destroyme1()}; + // CHECK: call void @_ZN10destroyme1D1Ev + destroyme2 dm2; + // CHECK: call void @_ZN10destroyme2D1Ev +} + +namespace PR12178 { + struct string { + string(int); + ~string(); + }; + + struct pair { + string a; + int b; + }; + + struct map { + map(std::initializer_list<pair>); + }; + + map m{ {1, 2}, {3, 4} }; +} diff --git a/clang/test/CodeGenCXX/cxx11-exception-spec.cpp b/clang/test/CodeGenCXX/cxx11-exception-spec.cpp new file mode 100644 index 0000000..194b80c --- /dev/null +++ b/clang/test/CodeGenCXX/cxx11-exception-spec.cpp @@ -0,0 +1,120 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -verify -fexceptions -fcxx-exceptions -triple x86_64-linux-gnu | FileCheck %s + +void h(); + +template<typename T> void f() noexcept(sizeof(T) == 4) { h(); } +template<typename T> void g() noexcept(sizeof(T) == 4); + +template<typename T> struct S { + static void f() noexcept(sizeof(T) == 4) { h(); } + static void g() noexcept(sizeof(T) == 4); +}; + +// CHECK: define {{.*}} @_Z1fIsEvv() { +template<> void f<short>() { h(); } +// CHECK: define {{.*}} @_Z1fIA2_sEvv() nounwind { +template<> void f<short[2]>() noexcept { h(); } + +// CHECK: define {{.*}} @_ZN1SIsE1fEv() +// CHECK-NOT: nounwind +template<> void S<short>::f() { h(); } +// CHECK: define {{.*}} @_ZN1SIA2_sE1fEv() nounwind +template<> void S<short[2]>::f() noexcept { h(); } + +// CHECK: define {{.*}} @_Z1fIDsEvv() { +template void f<char16_t>(); +// CHECK: define {{.*}} @_Z1fIA2_DsEvv() nounwind { +template void f<char16_t[2]>(); + +// CHECK: define {{.*}} @_ZN1SIDsE1fEv() +// CHECK-NOT: nounwind +template void S<char16_t>::f(); +// CHECK: define {{.*}} @_ZN1SIA2_DsE1fEv() nounwind +template void S<char16_t[2]>::f(); + +void h() { + // CHECK: define {{.*}} @_Z1fIiEvv() nounwind { + f<int>(); + // CHECK: define {{.*}} @_Z1fIA2_iEvv() { + f<int[2]>(); + + // CHECK: define {{.*}} @_ZN1SIiE1fEv() nounwind + S<int>::f(); + // CHECK: define {{.*}} @_ZN1SIA2_iE1fEv() + // CHECK-NOT: nounwind + S<int[2]>::f(); + + // CHECK: define {{.*}} @_Z1fIfEvv() nounwind { + void (*f1)() = &f<float>; + // CHECK: define {{.*}} @_Z1fIdEvv() { + void (*f2)() = &f<double>; + + // CHECK: define {{.*}} @_ZN1SIfE1fEv() nounwind + void (*f3)() = &S<float>::f; + // CHECK: define {{.*}} @_ZN1SIdE1fEv() + // CHECK-NOT: nounwind + void (*f4)() = &S<double>::f; + + // CHECK: define {{.*}} @_Z1fIA4_cEvv() nounwind { + (void)&f<char[4]>; + // CHECK: define {{.*}} @_Z1fIcEvv() { + (void)&f<char>; + + // CHECK: define {{.*}} @_ZN1SIA4_cE1fEv() nounwind + (void)&S<char[4]>::f; + // CHECK: define {{.*}} @_ZN1SIcE1fEv() + // CHECK-NOT: nounwind + (void)&S<char>::f; +} + +// CHECK: define {{.*}} @_Z1iv +void i() { + // CHECK: declare {{.*}} @_Z1gIiEvv() nounwind + g<int>(); + // CHECK: declare {{.*}} @_Z1gIA2_iEvv() + // CHECK-NOT: nounwind + g<int[2]>(); + + // CHECK: declare {{.*}} @_ZN1SIiE1gEv() nounwind + S<int>::g(); + // CHECK: declare {{.*}} @_ZN1SIA2_iE1gEv() + // CHECK-NOT: nounwind + S<int[2]>::g(); + + // CHECK: declare {{.*}} @_Z1gIfEvv() nounwind + void (*g1)() = &g<float>; + // CHECK: declare {{.*}} @_Z1gIdEvv() + // CHECK-NOT: nounwind + void (*g2)() = &g<double>; + + // CHECK: declare {{.*}} @_ZN1SIfE1gEv() nounwind + void (*g3)() = &S<float>::g; + // CHECK: declare {{.*}} @_ZN1SIdE1gEv() + // CHECK-NOT: nounwind + void (*g4)() = &S<double>::g; + + // CHECK: declare {{.*}} @_Z1gIA4_cEvv() nounwind + (void)&g<char[4]>; + // CHECK: declare {{.*}} @_Z1gIcEvv() + // CHECK-NOT: nounwind + (void)&g<char>; + + // CHECK: declare {{.*}} @_ZN1SIA4_cE1gEv() nounwind + (void)&S<char[4]>::g; + // CHECK: declare {{.*}} @_ZN1SIcE1gEv() + // CHECK-NOT: nounwind + (void)&S<char>::g; +} + +template<typename T> struct Nested { + template<bool b, typename U> void f() noexcept(sizeof(T) == sizeof(U)); +}; + +// CHECK: define {{.*}} @_Z1jv +void j() { + // CHECK: declare {{.*}} @_ZN6NestedIiE1fILb1EcEEvv( + // CHECK-NOT: nounwind + Nested<int>().f<true, char>(); + // CHECK: declare {{.*}} @_ZN6NestedIlE1fILb0ElEEvv({{.*}}) nounwind + Nested<long>().f<false, long>(); +} diff --git a/clang/test/CodeGenCXX/cxx11-unrestricted-union.cpp b/clang/test/CodeGenCXX/cxx11-unrestricted-union.cpp new file mode 100644 index 0000000..0397775 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx11-unrestricted-union.cpp @@ -0,0 +1,76 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - | FileCheck %s + +struct A { + A(); A(const A&); A(A&&); A &operator=(const A&); A &operator=(A&&); ~A(); +}; +struct B { + B(); B(const B&); B(B&&); B &operator=(const B&); B &operator=(B&&); ~B(); +}; + +union U { + U(); + U(const U &); + U(U &&); + U &operator=(const U&); + U &operator=(U&&); + ~U(); + + A a; + int n; +}; + +// CHECK-NOT: _ZN1A +U::U() {} +U::U(const U&) {} +U::U(U&&) {} +U &U::operator=(const U&) { return *this; } +U &U::operator=(U &&) { return *this; } +U::~U() {} + +struct S { + S(); + S(const S &); + S(S &&); + S &operator=(const S&); + S &operator=(S&&); + ~S(); + + union { + A a; + int n; + }; + B b; + int m; +}; + +// CHECK: _ZN1SC2Ev +// CHECK-NOT: _ZN1A +// CHECK: _ZN1BC1Ev +S::S() {} + +// CHECK-NOT: _ZN1A + +// CHECK: _ZN1SC2ERKS_ +// CHECK-NOT: _ZN1A +// CHECK: _ZN1BC1Ev +S::S(const S&) {} + +// CHECK-NOT: _ZN1A + +// CHECK: _ZN1SC2EOS_ +// CHECK-NOT: _ZN1A +// CHECK: _ZN1BC1Ev +S::S(S&&) {} + +// CHECK-NOT: _ZN1A +// CHECK-NOT: _ZN1B +S &S::operator=(const S&) { return *this; } + +S &S::operator=(S &&) { return *this; } + +// CHECK: _ZN1SD2Ev +// CHECK-NOT: _ZN1A +// CHECK: _ZN1BD1Ev +S::~S() {} + +// CHECK-NOT: _ZN1A diff --git a/clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp b/clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp new file mode 100644 index 0000000..347ffe9 --- /dev/null +++ b/clang/test/CodeGenCXX/cxx11-user-defined-literal.cpp @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s + +struct S { S(); ~S(); S(const S &); void operator()(int); }; +using size_t = decltype(sizeof(int)); +S operator"" _x(const char *, size_t); +S operator"" _y(wchar_t); +S operator"" _z(unsigned long long); +S operator"" _f(long double); +S operator"" _r(const char *); +template<char...Cs> S operator"" _t() { return S(); } + +// CHECK: @[[s_foo:.*]] = {{.*}} constant [4 x i8] c"foo\00" +// CHECK: @[[s_bar:.*]] = {{.*}} constant [4 x i8] c"bar\00" +// CHECK: @[[s_123:.*]] = {{.*}} constant [4 x i8] c"123\00" +// CHECK: @[[s_4_9:.*]] = {{.*}} constant [4 x i8] c"4.9\00" +// CHECK: @[[s_0xffffeeee:.*]] = {{.*}} constant [11 x i8] c"0xffffeeee\00" + +void f() { + // CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_foo]], i32 0, i32 0), i64 3) + // CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_bar]], i32 0, i32 0), i64 3) + // CHECK: call void @_Zli2_yw({{.*}} 97) + // CHECK: call void @_Zli2_zy({{.*}} 42) + // CHECK: call void @_Zli2_fe({{.*}} x86_fp80 0xK3FFF8000000000000000) + // CHECK: call void @_ZN1SD1Ev({{.*}}) + // CHECK: call void @_ZN1SD1Ev({{.*}}) + // CHECK: call void @_ZN1SD1Ev({{.*}}) + // CHECK: call void @_ZN1SD1Ev({{.*}}) + // CHECK: call void @_ZN1SD1Ev({{.*}}) + "foo"_x, "bar"_x, L'a'_y, 42_z, 1.0_f; + + // CHECK: call void @_Zli2_rPKc({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_123]], i32 0, i32 0)) + // CHECK: call void @_Zli2_rPKc({{.*}}, i8* getelementptr inbounds ([4 x i8]* @[[s_4_9]], i32 0, i32 0)) + // CHECK: call void @_Zli2_rPKc({{.*}}, i8* getelementptr inbounds ([11 x i8]* @[[s_0xffffeeee]], i32 0, i32 0)) + // CHECK: call void @_ZN1SD1Ev({{.*}}) + // CHECK: call void @_ZN1SD1Ev({{.*}}) + // CHECK: call void @_ZN1SD1Ev({{.*}}) + 123_r, 4.9_r, 0xffff\ +eeee_r; + + // FIXME: This mangling is insane. Maybe we should have a special case for + // char parameter packs? + // CHECK: call void @_Zli2_tIJLc48ELc120ELc49ELc50ELc51ELc52ELc53ELc54ELc55ELc56EEE1Sv({{.*}}) + // CHECK: call void @_ZN1SD1Ev({{.*}}) + 0x12345678_t; +} + +// CHECK: define {{.*}} @_Zli2_tIJLc48ELc120ELc49ELc50ELc51ELc52ELc53ELc54ELc55ELc56EEE1Sv( + +template<typename T> auto g(T t) -> decltype("foo"_x(t)) { return "foo"_x(t); } +template<typename T> auto i(T t) -> decltype(operator"" _x("foo", 3)(t)) { return operator"" _x("foo", 3)(t); } + +void h() { + g(42); + i(42); +} + +// CHECK: define {{.*}} @_Z1hv() +// CHECK: call void @_Z1gIiEDTclclL_Zli2_xPKcmELA4_S0_ELm3EEfp_EET_(i32 42) +// CHECK: call void @_Z1iIiEDTclclL_Zli2_xPKcmELA4_S0_ELi3EEfp_EET_(i32 42) + +// CHECK: define {{.*}} @_Z1gIiEDTclclL_Zli2_xPKcmELA4_S0_ELm3EEfp_EET_(i32 +// CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3) +// CHECK: call void @_ZN1SclEi +// CHECK: call void @_ZN1SD1Ev + +// CHECK: define {{.*}} @_Z1iIiEDTclclL_Zli2_xPKcmELA4_S0_ELi3EEfp_EET_(i32 +// CHECK: call void @_Zli2_xPKcm({{.*}}, i8* getelementptr inbounds ([4 x i8]* @{{.*}}, i32 0, i32 0), i64 3) +// CHECK: call void @_ZN1SclEi +// CHECK: call void @_ZN1SD1Ev diff --git a/clang/test/CodeGenCXX/debug-info-artificial-arg.cpp b/clang/test/CodeGenCXX/debug-info-artificial-arg.cpp new file mode 100644 index 0000000..92d1b16 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-artificial-arg.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s + +template<class X> class B { +public: + explicit B(X* p = 0); +}; + +class A +{ +public: + A(int value) : m_a_value(value) {}; + A(int value, A* client_A) : m_a_value (value), m_client_A (client_A) {} + + virtual ~A() {} + +private: + int m_a_value; + B<A> m_client_A; +}; + +int main(int argc, char **argv) { + A reallyA (500); +} + +// FIXME: The numbers are truly awful. +// CHECK: !18 = metadata !{i32 {{.*}}, i32 0, metadata !"", i32 0, i32 0, i64 64, i64 64, i64 0, i32 64, metadata !19} ; [ DW_TAG_pointer_type ] +// CHECK: !19 = metadata !{i32 {{.*}}, null, metadata !"A", metadata !6, i32 8, i64 128, i64 64, i32 0, i32 0, null, metadata !20, i32 0, metadata !19, null} ; [ DW_TAG_class_type ] +// CHECK: metadata !19, metadata !"A", metadata !"A", metadata !"", metadata !6, i32 12, metadata !45, i1 false, i1 false, i32 0, i32 0, null, i32 256, i1 false, null, null, i32 0, metadata !47, i32 12} ; [ DW_TAG_subprogram ] +// CHECK: metadata !"", i32 0, i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !46, i32 0, i32 0} ; [ DW_TAG_subroutine_type ] +// CHECK: !46 = metadata !{null, metadata !18, metadata !9, metadata !34} diff --git a/clang/test/CodeGenCXX/debug-info-byval.cpp b/clang/test/CodeGenCXX/debug-info-byval.cpp new file mode 100644 index 0000000..56ffe13 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-byval.cpp @@ -0,0 +1,31 @@ +// RUN: %clang -g -S %s -o - | FileCheck %s +// Test to check presence of debug info for byval parameter. +// Radar 8350436. +class DAG { +public: + int i; + int j; +}; + +class EVT { +public: + int a; + int b; + int c; +}; + +class VAL { +public: + int x; + int y; +}; +void foo(EVT e); +EVT bar(); + +void get(int *i, unsigned dl, VAL v, VAL *p, unsigned n, EVT missing_arg) { +//CHECK: .asciz "missing_arg" + EVT e = bar(); + if (dl == n) + foo(missing_arg); +} + diff --git a/clang/test/CodeGenCXX/debug-info-char16.cpp b/clang/test/CodeGenCXX/debug-info-char16.cpp new file mode 100644 index 0000000..24216f9 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-char16.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -emit-llvm -std=c++11 -g %s -o -| FileCheck %s + +// 16 is DW_ATE_UTF (0x10) encoding attribute. +char16_t char_a = u'h'; + +// CHECK: !7 = metadata !{i32 {{.*}}, null, metadata !"char16_t", null, i32 0, i64 16, i64 16, i64 0, i32 0, i32 16} ; [ DW_TAG_base_type ] diff --git a/clang/test/CodeGenCXX/debug-info-class.cpp b/clang/test/CodeGenCXX/debug-info-class.cpp new file mode 100644 index 0000000..151c5f9 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-class.cpp @@ -0,0 +1,12 @@ +// RUN: %clang -emit-llvm -g -S %s -o - | grep HdrSize +struct A { + int one; + static const int HdrSize = 52; + int two; + A() { + int x = 1; + } +}; +int main() { + A a; +} diff --git a/clang/test/CodeGenCXX/debug-info-context.cpp b/clang/test/CodeGenCXX/debug-info-context.cpp new file mode 100644 index 0000000..d6d44a1 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-context.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s +// PR11345 + +class locale { +private: + void _M_add_reference() const throw() { + } +}; +class ios_base { + locale _M_ios_locale; +public: + class Init { + }; +}; +static ios_base::Init __ioinit; + +// CHECK-NOT: _M_ios_locale diff --git a/clang/test/CodeGenCXX/debug-info-ctor.cpp b/clang/test/CodeGenCXX/debug-info-ctor.cpp new file mode 100644 index 0000000..c31eebe --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-ctor.cpp @@ -0,0 +1,14 @@ +// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s + +struct X { + X(int v); + + int value; +}; + +X::X(int v) { + // CHECK_TEMPORARILY_DISABLED: call void @_ZN1XC2Ei(%struct.X* %this1, i32 %tmp), !dbg + // TEMPORARY CHECK: X + value = v; +} + diff --git a/clang/test/CodeGenCXX/debug-info-ctor2.cpp b/clang/test/CodeGenCXX/debug-info-ctor2.cpp new file mode 100644 index 0000000..19bd64b --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-ctor2.cpp @@ -0,0 +1,15 @@ +// RUN: %clang -fverbose-asm -g -S %s -o - | grep AT_explicit + + +class MyClass +{ +public: + explicit MyClass (int i) : + m_i (i) + {} +private: + int m_i; +}; + +MyClass m(1); + diff --git a/clang/test/CodeGenCXX/debug-info-cxx0x.cpp b/clang/test/CodeGenCXX/debug-info-cxx0x.cpp new file mode 100644 index 0000000..37ccdb0 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-cxx0x.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -emit-llvm-only -std=c++11 -g %s + +namespace PR9414 { + int f() { + auto x = 0; + return x; + } +} diff --git a/clang/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp b/clang/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp new file mode 100644 index 0000000..e67987b --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-dup-fwd-decl.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin -fno-limit-debug-info %s -o - | FileCheck %s + +class Test +{ +public: + Test () : reserved (new data()) {} + + unsigned + getID() const + { + return reserved->objectID; + } +protected: + struct data { + unsigned objectID; + }; + data* reserved; +}; + +Test t; + +// CHECK: metadata !"", null, i32 0, i64 64, i64 64, i64 0, i32 0, metadata {{.*}} [ DW_TAG_pointer_type ] +// CHECK: metadata !"data", metadata !6, i32 14, i64 32, i64 32, i32 0, i32 0 +// CHECK-NOT: metadata !"data", metadata {{.*}}, i32 14, i64 0, i64 0, i32 0, i32 4, diff --git a/clang/test/CodeGenCXX/debug-info-enum.cpp b/clang/test/CodeGenCXX/debug-info-enum.cpp new file mode 100644 index 0000000..c08fc35 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-enum.cpp @@ -0,0 +1,8 @@ +// RUN: %clang -fverbose-asm -S -g %s -o - | grep DW_TAG_enumeration_type + +int v; +enum index { MAX }; +void foo(void) +{ + v = MAX; +} diff --git a/clang/test/CodeGenCXX/debug-info-fn-template.cpp b/clang/test/CodeGenCXX/debug-info-fn-template.cpp new file mode 100644 index 0000000..bef9fe1 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-fn-template.cpp @@ -0,0 +1,15 @@ +// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s + +template<typename T> +struct XF { + T member; +}; + +template<typename T> +T fx(XF<T> xi) { + return xi.member; +} + +//CHECK: XF<int> +//CHECK: DW_TAG_template_type_parameter +template int fx(XF<int>); diff --git a/clang/test/CodeGenCXX/debug-info-friend.cpp b/clang/test/CodeGenCXX/debug-info-friend.cpp new file mode 100644 index 0000000..c50f281 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-friend.cpp @@ -0,0 +1,11 @@ +// RUN: %clang -fverbose-asm -S -g %s -o - | grep DW_TAG_friend + +class MyFriend; + +class SomeClass +{ + friend class MyFriend; +}; + +SomeClass sc; + diff --git a/clang/test/CodeGenCXX/debug-info-fwd-ref.cpp b/clang/test/CodeGenCXX/debug-info-fwd-ref.cpp new file mode 100644 index 0000000..5480c6b --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-fwd-ref.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s + +struct baz { + int h; + baz(int a) : h(a) {} +}; + +struct bar { + baz b; + baz& b_ref; + bar(int x) : b(x), b_ref(b) {} +}; + +int main(int argc, char** argv) { + bar myBar(1); + return 0; +} + +// Make sure we have two DW_TAG_class_types for baz and bar and no forward +// references. +// FIXME: These should be struct types to match the declaration. +// CHECK: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 8, i64 128, i64 64, i32 0, i32 0, null, metadata !20, i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK: metadata !{i32 {{.*}}, null, metadata !"baz", metadata !6, i32 3, i64 32, i64 32, i32 0, i32 0, null, metadata !23, i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK-NOT: metadata !{i32 {{.*}}, null, metadata !"bar", metadata !6, i32 9, i64 0, i64 0, i32 0, i32 4, i32 0, null, i32 0, i32 0} ; [ DW_TAG_class_type ] +// CHECK-NOT: metadata !{i32 {{.*}}, null, metadata !"baz", metadata !6, i32 3, i64 0, i64 0, i32 0, i32 4, null, null, i32 0, null, null} ; [ DW_TAG_class_type ] + diff --git a/clang/test/CodeGenCXX/debug-info-large-constant.cpp b/clang/test/CodeGenCXX/debug-info-large-constant.cpp new file mode 100644 index 0000000..2daa189 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-large-constant.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -g -triple=x86_64-apple-darwin %s -o /dev/null +// PR 8913 + +typedef __uint128_t word128; +static const word128 m126 = 0xffffffffffffffffULL; +word128 foo() { + return m126; +} diff --git a/clang/test/CodeGenCXX/debug-info-limit-type.cpp b/clang/test/CodeGenCXX/debug-info-limit-type.cpp new file mode 100644 index 0000000..e03024f --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-limit-type.cpp @@ -0,0 +1,24 @@ +// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s +// XFAIL: * + +class B { +public: + int bb; + void fn2() {} +}; + +class A { +public: + int aa; + void fn1(B b) { b.fn2(); } +}; + +void foo(A *aptr) { +} + +void bar() { + A a; +} + +// B should only be emitted as a forward reference (i32 4). +// CHECK: metadata !"B", metadata !6, i32 3, i32 0, i32 0, i32 0, i32 4} ; [ DW_TAG_class_type ] diff --git a/clang/test/CodeGenCXX/debug-info-limit.cpp b/clang/test/CodeGenCXX/debug-info-limit.cpp new file mode 100644 index 0000000..bca887b --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-limit.cpp @@ -0,0 +1,14 @@ +// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s + +// TAG_member is used to encode debug info for class constructor. +// CHECK: TAG_member +class A { +public: + int z; +}; + +A *foo (A* x) { + A *a = new A(*x); + return a; +} + diff --git a/clang/test/CodeGenCXX/debug-info-member.cpp b/clang/test/CodeGenCXX/debug-info-member.cpp new file mode 100644 index 0000000..8c2e3eb --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-member.cpp @@ -0,0 +1,6 @@ +// RUN: %clang -fverbose-asm -g -S %s -o - | grep DW_ACCESS_public +class A { +public: + int x; +}; +A a; diff --git a/clang/test/CodeGenCXX/debug-info-method-spec.cpp b/clang/test/CodeGenCXX/debug-info-method-spec.cpp new file mode 100644 index 0000000..2068c5c --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-method-spec.cpp @@ -0,0 +1,10 @@ +// RUN: %clang -fverbose-asm -g -S %s -o - | grep DW_AT_specification +// Radar 9254491 +class A { +public: + void doSomething(int i) { ++i; } +}; + +void foo(A *a) { + a->doSomething(2); +} diff --git a/clang/test/CodeGenCXX/debug-info-method.cpp b/clang/test/CodeGenCXX/debug-info-method.cpp new file mode 100644 index 0000000..cb022bc --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-method.cpp @@ -0,0 +1,6 @@ +// RUN: %clang -fverbose-asm -g -S %s -o - | grep DW_ACCESS_protected +class A { +protected: + int foo(); +}; +A a; diff --git a/clang/test/CodeGenCXX/debug-info-method2.cpp b/clang/test/CodeGenCXX/debug-info-method2.cpp new file mode 100644 index 0000000..a927c49 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-method2.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -flimit-debug-info -x c++ -g -S -emit-llvm < %s | FileCheck %s +// rdar://10336845 +// Preserve type qualifiers in -flimit-debug-info mode. + +// CHECK: DW_TAG_const_type +class A { +public: + int bar(int arg) const; +}; + +int A::bar(int arg) const{ + return arg+2; +} + +int main() { + A a; + int i = a.bar(2); + return i; +} diff --git a/clang/test/CodeGenCXX/debug-info-namespace.cpp b/clang/test/CodeGenCXX/debug-info-namespace.cpp new file mode 100644 index 0000000..27f5eae --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-namespace.cpp @@ -0,0 +1,12 @@ +// RUN: %clang -g -S -fverbose-asm %s -o - | FileCheck %s + +// CHECK: TAG_namespace +namespace A { + enum numbers { + ZERO, + ONE + }; +} + +using namespace A; +numbers n; diff --git a/clang/test/CodeGenCXX/debug-info-nullptr.cpp b/clang/test/CodeGenCXX/debug-info-nullptr.cpp new file mode 100644 index 0000000..5540a92 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-nullptr.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -emit-llvm -std=c++11 -g %s -o -| FileCheck %s + +void foo() { + decltype(nullptr) t = 0; +} + +// CHECK: !13 = metadata !{i32 {{.*}}, null, metadata !"nullptr_t", null, i32 0, i64 0, i64 0, i64 0, i32 0, i32 0} ; [ DW_TAG_unspecified_type ] diff --git a/clang/test/CodeGenCXX/debug-info-pubtypes.cpp b/clang/test/CodeGenCXX/debug-info-pubtypes.cpp new file mode 100644 index 0000000..a7abade --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-pubtypes.cpp @@ -0,0 +1,17 @@ +// REQUIRES: x86-64-registered-target +// RUN: %clang -cc1 -triple x86_64-apple-darwin10 -g -fno-limit-debug-info -S %s -o %t +// RUN: FileCheck %s < %t + +// FIXME: This testcase shouldn't rely on assembly emission. +//CHECK: Lpubtypes_begin1: +//CHECK: .asciz "G" +//CHECK-NEXT: .long 0 +//CHECK-NEXT: Lpubtypes_end1: + +class G { +public: + void foo(); +}; + +void G::foo() { +} diff --git a/clang/test/CodeGenCXX/debug-info-static-fns.cpp b/clang/test/CodeGenCXX/debug-info-static-fns.cpp new file mode 100644 index 0000000..485d28a --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-static-fns.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s + +namespace A { + static int a(int b) { return b + 4; } + + int b(int c) { return c + a(c); } +} + +// Verify that a is present and mangled. +// CHECK: metadata !{i32 786478, i32 0, metadata !6, metadata !"a", metadata !"a", metadata !"_ZN1AL1aEi", metadata !7, i32 4, metadata !8, i1 true, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_ZN1AL1aEi, null, null, metadata !14, i32 4} ; [ DW_TAG_subprogram ] diff --git a/clang/test/CodeGenCXX/debug-info-template-limit.cpp b/clang/test/CodeGenCXX/debug-info-template-limit.cpp new file mode 100644 index 0000000..796a80f --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-template-limit.cpp @@ -0,0 +1,15 @@ +// RUN: %clang -flimit-debug-info -emit-llvm -g -S %s -o - | FileCheck %s + +// Check that this pointer type is TC<int> +// CHECK: !10} ; [ DW_TAG_pointer_type +// CHECK-NEXT: !10 ={{.*}}"TC<int>" + +template<typename T> +class TC { +public: + TC(const TC &) {} + TC() {} +}; + +TC<int> tci; + diff --git a/clang/test/CodeGenCXX/debug-info-template-member.cpp b/clang/test/CodeGenCXX/debug-info-template-member.cpp new file mode 100644 index 0000000..6208c80 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-template-member.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s + +class MyClass +{ +public: + int add2(int j) + { + return add<2>(j); + } +private: + template <int i> int add(int j) + { + return i + j; + } +}; + +MyClass m; + +// CHECK: metadata !{i32 {{.*}}, null, metadata !"MyClass", metadata {{.*}}, i32 {{.*}}, i64 8, i64 8, i32 0, i32 0, null, metadata [[C_MEM:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK: [[C_MEM]] = metadata !{metadata {{.*}}, metadata [[C_TEMP:.*]], metadata {{.*}}} +// CHECK: [[C_TEMP]] = metadata !{i32 {{.*}}, i32 0, metadata {{.*}}, metadata !"add<2>", metadata !"add<2>", metadata !"_ZN7MyClass3addILi2EEEii", metadata {{.*}} diff --git a/clang/test/CodeGenCXX/debug-info-template-recursive.cpp b/clang/test/CodeGenCXX/debug-info-template-recursive.cpp new file mode 100644 index 0000000..ef04d03 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-template-recursive.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -emit-llvm -g -triple x86_64-apple-darwin %s -o - | FileCheck %s + +class base { }; + +template <class T> class foo : public base { + void operator=(const foo r) { } +}; + +class bar : public foo<void> { }; +bar filters; + +// For now check that it simply doesn't crash. +// CHECK: {{.*}} diff --git a/clang/test/CodeGenCXX/debug-info-template.cpp b/clang/test/CodeGenCXX/debug-info-template.cpp new file mode 100644 index 0000000..9d52159 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-template.cpp @@ -0,0 +1,46 @@ +// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s + +//CHECK: TC<int> +//CHECK: DW_TAG_template_type_parameter + +template<typename T> +class TC { +public: + TC(const TC &) {} + TC() {} +}; + +TC<int> tci; + +//CHECK: TU<2> +//CHECK: DW_TAG_template_value_parameter +template<unsigned > +class TU { + int b; +}; + +TU<2> u2; + +// PR9600 +template<typename T> class vector {}; +class Foo; +typedef vector<Foo*> FooVector[3]; +struct Test { + virtual void foo(FooVector *); +}; +static Test test; + +// PR9608 +template <int i> struct TheTemplate { + struct Empty2 {}; + typedef const Empty2 DependentType[i]; + TheTemplate() {} +}; + +class TheTemplateTest : public TheTemplate<42> { + TheTemplateTest(); + void method(const TheTemplate<42>::DependentType *) {} +}; + +TheTemplateTest::TheTemplateTest() : TheTemplate<42>() {} + diff --git a/clang/test/CodeGenCXX/debug-info-this.cpp b/clang/test/CodeGenCXX/debug-info-this.cpp new file mode 100644 index 0000000..a2842d0 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-this.cpp @@ -0,0 +1,15 @@ +// RUN: %clang -emit-llvm -g -S %s -o - | FileCheck %s +// Radar 9239104 +class Class +{ +public: +//CHECK: DW_TAG_const_type + int foo (int p) const { + return p+m_int; + } + +protected: + int m_int; +}; + +Class c; diff --git a/clang/test/CodeGenCXX/debug-info-use-after-free.cpp b/clang/test/CodeGenCXX/debug-info-use-after-free.cpp new file mode 100644 index 0000000..9757ca4 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-use-after-free.cpp @@ -0,0 +1,312 @@ +// RUN: %clang_cc1 -g -emit-llvm-only %s +// Check that we don't crash. +// PR12305, PR12315 + +# 1 "a.h" 3 +template < typename T1 > struct Types1 +{ + typedef T1 Head; +}; +template < typename > struct Types; +template < template < typename > class Tmpl > struct TemplateSel +{ + template < typename T > struct Bind + { + typedef Tmpl < T > type; + }; +}; +template < typename > struct NoneT; +template < template < typename > class T1, template < typename > class > struct Templates2 +{ + typedef TemplateSel < T1 > Head; +}; +template < template < typename > class, template < typename > class = + NoneT, template < typename > class = NoneT, template < typename > class = + NoneT > struct Templates; +template < template < typename > class T1, + template < typename > class T2 > struct Templates <T1, T2 > +{ + typedef Templates2 < T1, T2 > type; +}; +template < typename T > struct TypeList +{ + typedef Types1 < T > type; +}; +template < template < typename > class, class TestSel, + typename Types > class TypeParameterizedTest +{ +public:static bool Register () + { + typedef typename Types::Head Type; + typename TestSel::template Bind < Type >::type TestClass; +}}; + +template < template < typename > class Fixture, typename Tests, + typename Types > class TypeParameterizedTestCase +{ +public:static bool Register (char *, char *, int *) + { + typedef typename Tests::Head Head; + TypeParameterizedTest < Fixture, Head, Types >::Register; +}}; + +template < typename > class TypedTestP1 +{ +}; + +namespace gtest_case_TypedTestP1_ +{ + template < typename gtest_TypeParam_ > class A:TypedTestP1 < + gtest_TypeParam_ > + { + }; +template < typename gtest_TypeParam_ > class B:TypedTestP1 < + gtest_TypeParam_ > + { + }; + typedef Templates < A >::type gtest_AllTests_; +} + +template < typename > class TypedTestP2 +{ +}; + +namespace gtest_case_TypedTestP2_ +{ + template < typename gtest_TypeParam_ > class A:TypedTestP2 < + gtest_TypeParam_ > + { + }; + typedef Templates < A >::type gtest_AllTests_; +} + +bool gtest_Int_TypedTestP1 = + TypeParameterizedTestCase < TypedTestP1, + gtest_case_TypedTestP1_::gtest_AllTests_, + TypeList < int >::type >::Register ("Int", "TypedTestP1", 0); +bool gtest_Int_TypedTestP2 = + TypeParameterizedTestCase < TypedTestP2, + gtest_case_TypedTestP2_::gtest_AllTests_, + TypeList < Types < int > >::type >::Register ("Int", "TypedTestP2", 0); + +template < typename _Tp > struct new_allocator +{ + typedef _Tp *pointer; + template < typename > struct rebind { + typedef new_allocator other; + }; +}; +template < typename _Tp > struct allocator:new_allocator < _Tp > { +}; +template < typename _Tp, typename _Alloc > struct _Vector_base { + typedef typename _Alloc::template rebind < _Tp >::other _Tp_alloc_type; + struct _Vector_impl { + typename _Tp_alloc_type::pointer _M_end_of_storage; + }; + _Vector_base () { + foo((int *) this->_M_impl._M_end_of_storage); + } + void foo(int *); + _Vector_impl _M_impl; +}; +template < typename _Tp, typename _Alloc = +allocator < _Tp > >struct vector:_Vector_base < _Tp, _Alloc > { }; + + +template < class T> struct HHH {}; +struct DDD { int x_;}; +struct Data; +struct X1; +struct CCC:DDD { virtual void xxx (HHH < X1 >); }; +template < class SSS > struct EEE:vector < HHH < SSS > > { }; +template < class SSS, class = EEE < SSS > >class FFF { }; +template < class SSS, class GGG = EEE < SSS > >class AAA:FFF <GGG> { }; +class BBB:virtual CCC { + void xxx (HHH < X1 >); + vector < HHH < X1 > >aaa; +}; +class ZZZ:AAA < Data >, BBB { virtual ZZZ *ppp () ; }; +ZZZ * ZZZ::ppp () { return new ZZZ; } + +namespace std +{ + template < class, class > struct pair; +} +namespace __gnu_cxx { +template < typename > class new_allocator; +} +namespace std { +template < typename _Tp > class allocator:__gnu_cxx::new_allocator < _Tp > { +}; +template < typename, typename > struct _Vector_base { +}; +template < typename _Tp, typename _Alloc = std::allocator < _Tp > >class vector:_Vector_base < _Tp, + _Alloc + > { + }; +} + +namespace +std { + template < + typename, + typename > struct unary_function; + template < + typename, + typename, + typename > struct binary_function; + template < + typename + _Tp > struct equal_to: + binary_function < + _Tp, + _Tp, + bool > { + }; + template < + typename + _Pair > struct _Select1st: + unary_function < + _Pair, + typename + _Pair::first_type > { + }; +} +# 1 "f.h" 3 +using +std::pair; +namespace +__gnu_cxx { + template < + class > struct hash; + template < + class, + class, + class, + class, + class + _EqualKey, + class > + class + hashtable { + public: + typedef _EqualKey + key_equal; + }; + using + std::equal_to; + using + std::allocator; + using + std::_Select1st; + template < class _Key, class _Tp, class _HashFn = + hash < _Key >, class _EqualKey = equal_to < _Key >, class _Alloc = + allocator < _Tp > >class hash_map { + typedef + hashtable < + pair < + _Key, + _Tp >, + _Key, + _HashFn, + _Select1st < + pair < + _Key, + _Tp > >, + _EqualKey, + _Alloc > + _Ht; + public: + typename _Ht::key_type; + typedef typename + _Ht::key_equal + key_equal; + }; +} +using +__gnu_cxx::hash_map; +class +C2; +template < class > class scoped_ptr { +}; +namespace { +class + AAA { + virtual ~ + AAA () { + }}; +} +template < typename > class EEE; +template < typename CCC, typename = +typename CCC::key_equal, typename = +EEE < CCC > >class III { +}; +namespace +util { + class + EEE { + }; +} +namespace { +class + C1: + util::EEE { + public: + class + C3: + AAA { + struct FFF; + typedef + III < + hash_map < + C2, + FFF > > + GGG; + GGG + aaa; + friend + C1; + }; + void + HHH (C3::GGG &); + }; +} +namespace +n1 { + class + Test { + }; + template < + typename > + class + C7 { + }; + class + C4: + n1::Test { + vector < + C1::C3 * > + a1; + }; + enum C5 { }; + class + C6: + C4, + n1::C7 < + C5 > { + }; + class + C8: + C6 { + }; + class + C9: + C8 { + void + TestBody (); + }; + void + C9::TestBody () { + scoped_ptr < C1::C3 > context; + } +} diff --git a/clang/test/CodeGenCXX/debug-info-wchar.cpp b/clang/test/CodeGenCXX/debug-info-wchar.cpp new file mode 100644 index 0000000..6f53849 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-wchar.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -emit-llvm -g %s -o -| FileCheck %s +void foo() { +// CHECK: metadata !"wchar_t", + const wchar_t w = L'x'; +} diff --git a/clang/test/CodeGenCXX/debug-info.cpp b/clang/test/CodeGenCXX/debug-info.cpp new file mode 100644 index 0000000..33b5278 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info.cpp @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -emit-llvm-only -g %s +template<typename T> struct Identity { + typedef T Type; +}; + +void f(Identity<int>::Type a) {} +void f(Identity<int> a) {} +void f(int& a) { } + +template<typename T> struct A { + A<T> *next; +}; +void f(A<int>) { } + +struct B { }; + +void f() { + int B::*a = 0; + void (B::*b)() = 0; +} + +namespace EmptyNameCrash { + struct A { A(); }; + typedef struct { A x; } B; + B x; +} + +// PR4890 +namespace PR4890 { + struct X { + ~X(); + }; + + X::~X() { } +} + +namespace VirtualDtor { + struct Y { + virtual ~Y(); + }; + + Y::~Y() { } +} + +namespace VirtualBase { + struct A { }; + struct B : virtual A { }; + + void f() { + B b; + } +} + +void foo() { + const wchar_t c = L'x'; + wchar_t d = c; +} + +namespace b5249287 { +template <typename T> class A { + struct B; +}; + +class Cls { + template <typename T> friend class A<T>::B; +}; + +Cls obj; +} diff --git a/clang/test/CodeGenCXX/debug-lambda-expressions.cpp b/clang/test/CodeGenCXX/debug-lambda-expressions.cpp new file mode 100644 index 0000000..859a71b --- /dev/null +++ b/clang/test/CodeGenCXX/debug-lambda-expressions.cpp @@ -0,0 +1,71 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 -g | FileCheck %s + +auto var = [](int i) { return i+1; }; + +extern "C" auto cvar = []{}; + +int a() { return []{ return 1; }(); } + +int b(int x) { return [x]{return x;}(); } + +int c(int x) { return [&x]{return x;}(); } + +struct D { D(); D(const D&); int x; }; +int d(int x) { D y[10]; [x,y] { return y[x].x; }(); } + + +// A: 5 +// CHECK: [[A_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE:.*]], metadata !"a", metadata !"a", metadata !"_Z1av", metadata {{.*}}, i32 [[A_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 ()* @_Z1av, null, null, {{.*}} [ DW_TAG_subprogram ] + +// Randomness for file. -- 6 +// CHECK: [[FILE]] = metadata !{i32 {{.*}}, metadata !{{.*}}debug-lambda-expressions.cpp{{.*}}; [ DW_TAG_file_type ] + +// B: 12 +// CHECK: [[B_FUNC:.*]] = metadata !{i32 786478, i32 0, metadata [[FILE]], metadata !"b", metadata !"b", metadata !"_Z1bi", metadata [[FILE]], i32 [[B_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1bi, null, null, {{.*}} ; [ DW_TAG_subprogram ] + +// C: 17 +// CHECK: [[C_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE]], metadata !"c", metadata !"c", metadata !"_Z1ci", metadata [[FILE]], i32 [[C_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1ci, null, null, metadata {{.*}} ; [ DW_TAG_subprogram ] + +// D: 20 +// CHECK: [[D_FUNC:.*]] = metadata !{i32 {{.*}}, i32 0, metadata [[FILE]], metadata !"d", metadata !"d", metadata !"_Z1di", metadata [[FILE]], i32 [[D_LINE:.*]], metadata {{.*}}, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32)* @_Z1di, null, null, metadata {{.*}} ; [ DW_TAG_subprogram ] + +// Back to D. -- 120 +// CHECK: [[LAM_D:.*]] = metadata !{i32 {{.*}}, metadata [[D_FUNC]], metadata !"", metadata [[FILE]], i32 [[D_LINE]], i64 352, i64 32, i32 0, i32 0, null, metadata [[LAM_D_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]], metadata [[DES_LAM_D:.*]]} +// CHECK: [[CAP_D_X]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"x", metadata [[FILE]], i32 14, i64 32, i64 32, i64 0, i32 1, metadata {{.*}} ; [ DW_TAG_member ] +// CHECK: [[CAP_D_Y]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"y", metadata [[FILE]], i32 14, i64 320, i64 32, i64 32, i32 1, metadata {{.*}} ; [ DW_TAG_member ] +// CHECK: [[CON_LAM_D]] = metadata {{.*}}[[LAM_D]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ] +// CHECK: [[DES_LAM_D]] = metadata {{.*}}[[LAM_D]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ] + + +// Back to C. -- 159 +// CHECK: [[LAM_C:.*]] = metadata !{i32 {{.*}}, metadata [[C_FUNC]], metadata !"", metadata [[FILE]], i32 [[C_LINE]], i64 64, i64 64, i32 0, i32 0, null, metadata [[LAM_C_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK: [[LAM_C_ARGS]] = metadata !{metadata [[CAP_C:.*]], metadata [[CON_LAM_C:.*]], metadata [[DES_LAM_C:.*]]} +// Ignoring the member type for now. +// CHECK: [[CAP_C]] = metadata !{i32 {{.*}}, metadata [[LAM_C]], metadata !"x", metadata [[FILE]], i32 [[C_LINE]], i64 64, i64 64, i64 0, i32 1, metadata {{.*}}} ; [ DW_TAG_member ] +// CHECK: [[CON_LAM_C]] = metadata {{.*}}[[LAM_C]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ] +// CHECK: [[DES_LAM_C]] = metadata {{.*}}[[LAM_C]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ] + + +// Back to B. -- 179 +// CHECK: [[LAM_B:.*]] = metadata !{i32 {{.*}}, metadata [[B_FUNC]], metadata !"", metadata [[FILE]], i32 [[B_LINE]], i64 32, i64 32, i32 0, i32 0, null, metadata [[LAM_B_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK: [[LAM_B_ARGS]] = metadata !{metadata [[CAP_B:.*]], metadata [[CON_LAM_B:.*]], metadata [[DES_LAM_B:.*]]} +// CHECK: [[CAP_B]] = metadata !{i32 {{.*}}, metadata [[LAM_B]], metadata !"x", metadata [[FILE]], i32 [[B_LINE]], i64 32, i64 32, i64 0, i32 1, metadata {{.*}}} ; [ DW_TAG_member ] +// CHECK: [[CON_LAM_B]] = metadata {{.*}}[[LAM_B]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ] +// CHECK: [[DES_LAM_B]] = metadata {{.*}}[[LAM_B]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ] + +// Back to A. -- 204 +// CHECK: [[LAM_A:.*]] = metadata !{i32 {{.*}}, metadata [[A_FUNC]], metadata !"", metadata [[FILE]], i32 [[A_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata [[LAM_A_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK: [[LAM_A_ARGS]] = metadata !{metadata [[CON_LAM_A:.*]], metadata [[DES_LAM_A:.*]]} +// CHECK: [[CON_LAM_A]] = metadata {{.*}}[[LAM_A]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ] +// CHECK: [[DES_LAM_A]] = metadata {{.*}}[[LAM_A]], metadata !"~", metadata !"~"{{.*}}[ DW_TAG_subprogram ] + +// VAR: +// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"var", metadata !"var", metadata !"", metadata [[FILE]], i32 [[VAR_LINE:.*]], metadata ![[VAR_T:.*]], i32 1, i32 1, %class.anon* @var} ; [ DW_TAG_variable ] +// CHECK: [[VAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[VAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[VAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}} + +// CVAR: +// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"cvar", metadata !"cvar", metadata !"", metadata [[FILE]], i32 [[CVAR_LINE:.*]], metadata ![[CVAR_T:.*]], i32 0, i32 1, %class.anon.0* @cvar} ; [ DW_TAG_variable ] +// CHECK: [[CVAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[CVAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[CVAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ] +// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}, metadata !{{.*}}, metadata !{{.*}}} diff --git a/clang/test/CodeGenCXX/decl-ref-init.cpp b/clang/test/CodeGenCXX/decl-ref-init.cpp new file mode 100644 index 0000000..a066fbb --- /dev/null +++ b/clang/test/CodeGenCXX/decl-ref-init.cpp @@ -0,0 +1,31 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +struct A {}; + +struct B +{ + operator A&(); +}; + + +struct D : public B { + operator A(); +}; + +extern B f(); +extern D d(); + +int main() { + const A& rca = f(); + const A& rca2 = d(); +} + +// CHECK-LP64: callq __ZN1BcvR1AEv +// CHECK-LP64: callq __ZN1BcvR1AEv + +// CHECK-LP32: calll L__ZN1BcvR1AEv +// CHECK-LP32: calll L__ZN1BcvR1AEv diff --git a/clang/test/CodeGenCXX/default-arg-temps.cpp b/clang/test/CodeGenCXX/default-arg-temps.cpp new file mode 100644 index 0000000..3d741d5 --- /dev/null +++ b/clang/test/CodeGenCXX/default-arg-temps.cpp @@ -0,0 +1,73 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s + +struct T { + T(); + ~T(); +}; + +void f(const T& t = T()); + +class X { // ... +public: + X(); + X(const X&, const T& t = T()); +}; + +// CHECK: define void @_Z1gv() +void g() { + // CHECK: call void @_ZN1TC1Ev([[T:%.*]]* [[AGG1:%.*]]) + // CHECK-NEXT: call void @_Z1fRK1T([[T]]* [[AGG1]]) + // CHECK-NEXT: call void @_ZN1TD1Ev([[T]]* [[AGG1]]) + f(); + + // CHECK-NEXT: call void @_ZN1TC1Ev([[T:%.*]]* [[AGG2:%.*]]) + // CHECK-NEXT: call void @_Z1fRK1T([[T]]* [[AGG2]]) + // CHECK-NEXT: call void @_ZN1TD1Ev([[T]]* [[AGG2]]) + f(); + + // CHECK-NEXT: call void @_ZN1XC1Ev( + X a; + + // CHECK-NEXT: call void @_ZN1TC1Ev( + // CHECK-NEXT: call void @_ZN1XC1ERKS_RK1T( + // CHECK-NEXT: call void @_ZN1TD1Ev( + X b(a); + + // CHECK-NEXT: call void @_ZN1TC1Ev( + // CHECK-NEXT: call void @_ZN1XC1ERKS_RK1T( + // CHECK-NEXT: call void @_ZN1TD1Ev( + X c = a; +} + + +class obj{ int a; float b; double d; }; +// CHECK: define void @_Z1hv() +void h() { + // CHECK: call void @llvm.memset.p0i8.i64( + obj o = obj(); +} + +// PR7028 - mostly this shouldn't crash +namespace test1 { + struct A { A(); }; + struct B { B(); ~B(); }; + + struct C { + C(const B &file = B()); + }; + C::C(const B &file) {} + + struct D { + C c; + A a; + + // CHECK: define linkonce_odr void @_ZN5test11DC2Ev(%"struct.test1::D"* %this) unnamed_addr + // CHECK: call void @_ZN5test11BC1Ev( + // CHECK-NEXT: call void @_ZN5test11CC1ERKNS_1BE( + // CHECK-NEXT: call void @_ZN5test11BD1Ev( + // CHECK: call void @_ZN5test11AC1Ev( + D() : c(), a() {} + }; + + D d; +} diff --git a/clang/test/CodeGenCXX/default-arguments.cpp b/clang/test/CodeGenCXX/default-arguments.cpp new file mode 100644 index 0000000..206d4d6 --- /dev/null +++ b/clang/test/CodeGenCXX/default-arguments.cpp @@ -0,0 +1,76 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// PR5484 +namespace PR5484 { +struct A { }; +extern A a; + +void f(const A & = a); + +void g() { + f(); +} +} + +struct A1 { + A1(); + ~A1(); +}; + +struct A2 { + A2(); + ~A2(); +}; + +struct B { + B(const A1& = A1(), const A2& = A2()); +}; + +// CHECK: define void @_Z2f1v() +void f1() { + + // CHECK: call void @_ZN2A1C1Ev( + // CHECK: call void @_ZN2A2C1Ev( + // CHECK: call void @_ZN1BC1ERK2A1RK2A2( + // CHECK: call void @_ZN2A2D1Ev + // CHECK: call void @_ZN2A1D1Ev + B bs[2]; +} + +struct C { + B bs[2]; + C(); +}; + +// CHECK: define void @_ZN1CC1Ev(%struct.C* %this) unnamed_addr +// CHECK: call void @_ZN1CC2Ev( + +// CHECK: define void @_ZN1CC2Ev(%struct.C* %this) unnamed_addr +// CHECK: call void @_ZN2A1C1Ev( +// CHECK: call void @_ZN2A2C1Ev( +// CHECK: call void @_ZN1BC1ERK2A1RK2A2( +// CHECK: call void @_ZN2A2D1Ev +// CHECK: call void @_ZN2A1D1Ev +C::C() { } + +// CHECK: define void @_Z2f3v() +void f3() { + // CHECK: call void @_ZN2A1C1Ev( + // CHECK: call void @_ZN2A2C1Ev( + // CHECK: call void @_ZN1BC1ERK2A1RK2A2( + // CHECK: call void @_ZN2A2D1Ev + // CHECK: call void @_ZN2A1D1Ev + B *bs = new B[2]; + delete bs; +} + +void f4() { + void g4(int a, int b = 7); + { + void g4(int a, int b = 5); + } + void g4(int a = 5, int b); + + // CHECK: call void @_Z2g4ii(i32 5, i32 7) + g4(); +} diff --git a/clang/test/CodeGenCXX/default-constructor-default-argument.cpp b/clang/test/CodeGenCXX/default-constructor-default-argument.cpp new file mode 100644 index 0000000..374a967 --- /dev/null +++ b/clang/test/CodeGenCXX/default-constructor-default-argument.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +// Check that call to constructor for struct A is generated correctly. +struct A { A(int x = 2); }; +struct B : public A {}; +B x; + +// CHECK: call {{.*}} @_ZN1AC2Ei diff --git a/clang/test/CodeGenCXX/default-constructor-for-members.cpp b/clang/test/CodeGenCXX/default-constructor-for-members.cpp new file mode 100644 index 0000000..714811f --- /dev/null +++ b/clang/test/CodeGenCXX/default-constructor-for-members.cpp @@ -0,0 +1,24 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +extern "C" int printf(...); + +struct S { + S() { printf("S::S()\n"); } + int iS; +}; + +struct M { + S ARR_S; +}; + +int main() { + M m1; +} + +// CHECK-LP64: callq __ZN1SC1Ev + +// CHECK-LP32: calll L__ZN1SC1Ev diff --git a/clang/test/CodeGenCXX/default-constructor-template-member.cpp b/clang/test/CodeGenCXX/default-constructor-template-member.cpp new file mode 100644 index 0000000..0dd64df --- /dev/null +++ b/clang/test/CodeGenCXX/default-constructor-template-member.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +template <class T> struct A { A(); }; +struct B { A<int> x; }; +void a() { + B b; +} +// CHECK: call {{.*}} @_ZN1BC1Ev +// CHECK: define linkonce_odr {{.*}} @_ZN1BC1Ev(%struct.B* %this) unnamed_addr +// CHECK: call {{.*}} @_ZN1AIiEC1Ev diff --git a/clang/test/CodeGenCXX/default-destructor-nested.cpp b/clang/test/CodeGenCXX/default-destructor-nested.cpp new file mode 100644 index 0000000..565a727 --- /dev/null +++ b/clang/test/CodeGenCXX/default-destructor-nested.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -emit-llvm-only +// PR6294 + +class A { +public: virtual ~A(); +}; +class B { + class C; +}; +class B::C : public A { + C(); +}; +B::C::C() {} diff --git a/clang/test/CodeGenCXX/default-destructor-synthesis.cpp b/clang/test/CodeGenCXX/default-destructor-synthesis.cpp new file mode 100644 index 0000000..fac5cc0 --- /dev/null +++ b/clang/test/CodeGenCXX/default-destructor-synthesis.cpp @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -O2 -o - | FileCheck %s +static int count = 0; + +struct S { + S() { count++; } + ~S() { count--; } +}; + +struct P { + P() { count++; } + ~P() { count--; } +}; + +struct Q { + Q() { count++; } + ~Q() { count--; } +}; + +struct M : Q, P { + S s; + Q q; + P p; + P p_arr[3]; + Q q_arr[2][3]; +}; + +// CHECK: define i32 @_Z1fv() nounwind +int f() { + { + count = 1; + M a; + } + + // CHECK: ret i32 1 + return count; +} diff --git a/clang/test/CodeGenCXX/deferred-global-init.cpp b/clang/test/CodeGenCXX/deferred-global-init.cpp new file mode 100644 index 0000000..24c8c67 --- /dev/null +++ b/clang/test/CodeGenCXX/deferred-global-init.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// PR5967 + +extern void* foo; +static void* const a = foo; +void* bar() { return a; } + +// CHECK: @_ZL1a = internal global i8* null + +// CHECK: define internal void @__cxx_global_var_init +// CHECK: load i8** @foo +// CHECK: ret void + +// CHECK: define internal void @_GLOBAL__I_a +// CHECK: call void @__cxx_global_var_init() +// CHECK: ret void diff --git a/clang/test/CodeGenCXX/delete-two-arg.cpp b/clang/test/CodeGenCXX/delete-two-arg.cpp new file mode 100644 index 0000000..b82e9ba --- /dev/null +++ b/clang/test/CodeGenCXX/delete-two-arg.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -triple i686-pc-linux-gnu %s -o - -emit-llvm -verify | FileCheck %s + +typedef __typeof(sizeof(int)) size_t; + +namespace test1 { + struct A { void operator delete(void*,size_t); int x; }; + + // CHECK: define void @_ZN5test11aEPNS_1AE( + void a(A *x) { + // CHECK: load + // CHECK-NEXT: icmp eq {{.*}}, null + // CHECK-NEXT: br i1 + // CHECK: call void @_ZN5test11AdlEPvj(i8* %{{.*}}, i32 4) + delete x; + } +} + +// Check that we make cookies for the two-arg delete even when using +// the global allocator and deallocator. +namespace test2 { + struct A { + int x; + void *operator new[](size_t); + void operator delete[](void *, size_t); + }; + + // CHECK: define [[A:%.*]]* @_ZN5test24testEv() + A *test() { + // CHECK: [[NEW:%.*]] = call noalias i8* @_Znaj(i32 44) + // CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[NEW]] to i32* + // CHECK-NEXT: store i32 10, i32* [[T0]] + // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds i8* [[NEW]], i64 4 + // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[A]]* + // CHECK-NEXT: ret [[A]]* [[T2]] + return ::new A[10]; + } + + // CHECK: define void @_ZN5test24testEPNS_1AE( + void test(A *p) { + // CHECK: [[P:%.*]] = alloca [[A]]*, align 4 + // CHECK-NEXT: store [[A]]* {{%.*}}, [[A]]** [[P]], align 4 + // CHECK-NEXT: [[T0:%.*]] = load [[A]]** [[P]], align 4 + // CHECK-NEXT: [[T1:%.*]] = icmp eq [[A]]* [[T0]], null + // CHECK-NEXT: br i1 [[T1]], + // CHECK: [[T2:%.*]] = bitcast [[A]]* [[T0]] to i8* + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 -4 + // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i32* + // CHECK-NEXT: [[T5:%.*]] = load i32* [[T4]] + // CHECK-NEXT: call void @_ZdaPv(i8* [[T3]]) + // CHECK-NEXT: br label + ::delete[] p; + } +} + +// rdar://problem/8913519 +namespace test3 { + struct A { + int x; + void operator delete[](void *, size_t); + }; + struct B : A {}; + + // CHECK: define void @_ZN5test34testEv() + void test() { + // CHECK: call noalias i8* @_Znaj(i32 24) + // CHECK-NEXT: bitcast + // CHECK-NEXT: store i32 5 + (void) new B[5]; + } +} diff --git a/clang/test/CodeGenCXX/delete.cpp b/clang/test/CodeGenCXX/delete.cpp new file mode 100644 index 0000000..5a88f9f --- /dev/null +++ b/clang/test/CodeGenCXX/delete.cpp @@ -0,0 +1,135 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 %s -emit-llvm -o - | FileCheck %s + +void t1(int *a) { + delete a; +} + +struct S { + int a; +}; + +// POD types. +void t3(S *s) { + delete s; +} + +// Non-POD +struct T { + ~T(); + int a; +}; + +// CHECK: define void @_Z2t4P1T +void t4(T *t) { + // CHECK: call void @_ZN1TD1Ev + // CHECK-NEXT: bitcast + // CHECK-NEXT: call void @_ZdlPv + delete t; +} + +// PR5102 +template <typename T> +class A { + public: operator T *() const; +}; + +void f() { + A<char*> a; + + delete a; +} + +namespace test0 { + struct A { + void *operator new(__SIZE_TYPE__ sz); + void operator delete(void *p) { ::operator delete(p); } + ~A() {} + }; + + // CHECK: define void @_ZN5test04testEPNS_1AE( + void test(A *a) { + // CHECK: call void @_ZN5test01AD1Ev + // CHECK-NEXT: bitcast + // CHECK-NEXT: call void @_ZN5test01AdlEPv + delete a; + } + + // CHECK: define linkonce_odr void @_ZN5test01AD1Ev(%"struct.test0::A"* %this) unnamed_addr + // CHECK: define linkonce_odr void @_ZN5test01AdlEPv +} + +namespace test1 { + struct A { + int x; + ~A(); + }; + + // CHECK: define void @_ZN5test14testEPA10_A20_NS_1AE( + void test(A (*arr)[10][20]) { + delete [] arr; + // CHECK: icmp eq [10 x [20 x [[A:%.*]]]]* [[PTR:%.*]], null + // CHECK-NEXT: br i1 + + // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]]* [[PTR]], i32 0, i32 0, i32 0 + // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[BEGIN]] to i8* + // CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds i8* [[T0]], i64 -8 + // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[ALLOC]] to i64* + // CHECK-NEXT: [[COUNT:%.*]] = load i64* [[T1]] + // CHECK: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 [[COUNT]] + // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[END]] + // CHECK-NEXT: br i1 [[ISEMPTY]], + // CHECK: [[PAST:%.*]] = phi [[A]]* [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[PAST]], i64 -1 + // CHECK-NEXT: call void @_ZN5test11AD1Ev([[A]]* [[CUR]]) + // CHECK-NEXT: [[ISDONE:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]] + // CHECK-NEXT: br i1 [[ISDONE]] + // CHECK: call void @_ZdaPv(i8* [[ALLOC]]) + } +} + +namespace test2 { + // CHECK: define void @_ZN5test21fEPb + void f(bool *b) { + // CHECK: call void @_ZdlPv(i8* + delete b; + // CHECK: call void @_ZdaPv(i8* + delete [] b; + } +} + +namespace test3 { + void f(int a[10][20]) { + // CHECK: call void @_ZdaPv(i8* + delete a; + } +} + +namespace test4 { + // PR10341: ::delete with a virtual destructor + struct X { + virtual ~X(); + void operator delete (void *); + }; + + // CHECK: define void @_ZN5test421global_delete_virtualEPNS_1XE + void global_delete_virtual(X *xp) { + // CHECK: [[VTABLE:%.*]] = load void ([[X:%.*]])*** + // CHECK-NEXT: [[VFN:%.*]] = getelementptr inbounds void ([[X]])** [[VTABLE]], i64 0 + // CHECK-NEXT: [[VFNPTR:%.*]] = load void ([[X]])** [[VFN]] + // CHECK-NEXT: call void [[VFNPTR]]([[X]] [[OBJ:%.*]]) + // CHECK-NEXT: [[OBJVOID:%.*]] = bitcast [[X]] [[OBJ]] to i8* + // CHECK-NEXT: call void @_ZdlPv(i8* [[OBJVOID]]) nounwind + ::delete xp; + } +} + +namespace test5 { + struct Incomplete; + // CHECK: define void @_ZN5test523array_delete_incompleteEPNS_10IncompleteES1_ + void array_delete_incomplete(Incomplete *p1, Incomplete *p2) { + // CHECK: call void @_ZdlPv + delete p1; + // CHECK: call void @_ZdaPv + delete [] p2; + } +} diff --git a/clang/test/CodeGenCXX/dependent-type-member-pointer.cpp b/clang/test/CodeGenCXX/dependent-type-member-pointer.cpp new file mode 100644 index 0000000..41bb5e2 --- /dev/null +++ b/clang/test/CodeGenCXX/dependent-type-member-pointer.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -emit-llvm-only -verify %s +// PR7736 + +template <class scriptmemberptr> int InitMember(scriptmemberptr); + +template <class> +struct contentmap +{ + static void InitDataMap() + { InitMember(&contentmap::SizeHolder); } + int SizeHolder; +}; + +void ReadFrom( ) +{ + contentmap<int>::InitDataMap(); +} + diff --git a/clang/test/CodeGenCXX/derived-to-base-conv.cpp b/clang/test/CodeGenCXX/derived-to-base-conv.cpp new file mode 100644 index 0000000..8c51809 --- /dev/null +++ b/clang/test/CodeGenCXX/derived-to-base-conv.cpp @@ -0,0 +1,85 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s + +extern "C" int printf(...); +extern "C" void exit(int); + +struct A { + A (const A&) { printf("A::A(const A&)\n"); } + A() {}; + ~A() { printf("A::~A()\n"); } +}; + +struct B : public A { + B() {}; + B(const B& Other) : A(Other) { printf("B::B(const B&)\n"); } + ~B() { printf("B::~B()\n"); } +}; + +struct C : public B { + C() {}; + C(const C& Other) : B(Other) { printf("C::C(const C&)\n"); } + ~C() { printf("C::~C()\n"); } +}; + +struct X { + operator B&() {printf("X::operator B&()\n"); return b; } + operator C&() {printf("X::operator C&()\n"); return c; } + X (const X&) { printf("X::X(const X&)\n"); } + X () { printf("X::X()\n"); } + ~X () { printf("X::~X()\n"); } + B b; + C c; +}; + +void f(A) { + printf("f(A)\n"); +} + + +void func(X x) +{ + f (x); +} + +int main() +{ + X x; + func(x); +} + +struct Base; + +struct Root { + operator Base&() { exit(1); } +}; + +struct Derived; + +struct Base : Root { + Base(const Base&) { printf("Base::(const Base&)\n"); } + Base() { printf("Base::Base()\n"); } + operator Derived&() { exit(1); } +}; + +struct Derived : Base { +}; + +void foo(Base) {} + +void test(Derived bb) +{ + // CHECK-LP64-NOT: callq __ZN4BasecvR7DerivedEv + // CHECK-LP32-NOT: callq L__ZN4BasecvR7DerivedEv + foo(bb); +} +// CHECK-LP64: callq __ZN1XcvR1BEv +// CHECK-LP64: callq __ZN1AC1ERKS_ + +// CHECK-LP32: calll L__ZN1XcvR1BEv +// CHECK-LP32: calll L__ZN1AC1ERKS_ + + diff --git a/clang/test/CodeGenCXX/derived-to-base.cpp b/clang/test/CodeGenCXX/derived-to-base.cpp new file mode 100644 index 0000000..76b79fc --- /dev/null +++ b/clang/test/CodeGenCXX/derived-to-base.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +struct A { + void f(); + + int a; +}; + +struct B : A { + double b; +}; + +void f() { + B b; + + b.f(); +} + +// CHECK: define %struct.B* @_Z1fP1A(%struct.A* %a) nounwind +B *f(A *a) { + // CHECK-NOT: br label + // CHECK: ret %struct.B* + return static_cast<B*>(a); +} + +// PR5965 +namespace PR5965 { + +// CHECK: define %struct.A* @_ZN6PR59651fEP1B(%struct.B* %b) nounwind +A *f(B* b) { + // CHECK-NOT: br label + // CHECK: ret %struct.A* + return b; +} + +} + +// Don't crash on a derived-to-base conversion of an r-value +// aggregate. +namespace test3 { + struct A {}; + struct B : A {}; + + void foo(A a); + void test() { + foo(B()); + } +} diff --git a/clang/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp b/clang/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp new file mode 100644 index 0000000..0e15302 --- /dev/null +++ b/clang/test/CodeGenCXX/derived-to-virtual-base-class-calls-final.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +struct A { int i; }; +struct B { char j; }; +struct C : A, B { int k; }; + +struct D final : virtual C { + D(); + virtual void f(); +}; + +// CHECK: define %struct.B* @_Z1fR1D +B &f(D &d) { + // CHECK-NOT: load i8** + return d; +} diff --git a/clang/test/CodeGenCXX/destructor-calls.cpp b/clang/test/CodeGenCXX/destructor-calls.cpp new file mode 100644 index 0000000..4da46a4 --- /dev/null +++ b/clang/test/CodeGenCXX/destructor-calls.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 %s -emit-llvm -o %t + +extern "C" int printf(...); + +static int val; + +struct B { + B() : iB(++val) { printf("B()\n"); } + int iB; + ~B() { printf("~B(%d)\n", iB); --val; } +}; + +struct M : B { + M() : iM(++val) { printf("M()\n"); } + int iM; + ~M() { printf("~M(%d)\n", iM); --val; } +}; + +struct P { + P() : iP(++val) { printf("P()\n"); } + int iP; + ~P() { printf("~P(%d)\n", iP); --val; } +}; + +struct N : M, P { + N() { printf("N()\n"); iN = ++val; } + ~N() { printf("~N(%d) val = %d\n", iN, --val); } + int iN; + M m; + P p; +}; + +struct O : B { + ~O() { return; } +}; + +int main() { + N n1; + N n2; + O o; +} diff --git a/clang/test/CodeGenCXX/destructor-debug-info.cpp b/clang/test/CodeGenCXX/destructor-debug-info.cpp new file mode 100644 index 0000000..9e32275 --- /dev/null +++ b/clang/test/CodeGenCXX/destructor-debug-info.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -g -S -emit-llvm -o %t %s +// RUN: grep "i32 20, i32 3, metadata" %t | count 1 +// Check there is a line number entry for line 20 where b1 is destructed. +class A { int a; }; +class B { +public: + B() { a = new A; } + ~B() { delete a; } +private: + A *a; +}; + +void fn(B b); + +int i; +void foo() { + if (i) { + B b1; + fn (b1); + } +} diff --git a/clang/test/CodeGenCXX/destructors.cpp b/clang/test/CodeGenCXX/destructors.cpp new file mode 100644 index 0000000..d9962e6 --- /dev/null +++ b/clang/test/CodeGenCXX/destructors.cpp @@ -0,0 +1,403 @@ +// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - -mconstructor-aliases -fcxx-exceptions -fexceptions | FileCheck %s + +// CHECK: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev +// CHECK: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev +// CHECK: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev + +// CHECK: @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev +// CHECK: @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev +// CHECK: @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev + +struct A { + int a; + + ~A(); +}; + +// Base with non-trivial destructor +struct B : A { + ~B(); +}; + +B::~B() { } + +// Field with non-trivial destructor +struct C { + A a; + + ~C(); +}; + +C::~C() { } + +namespace PR7526 { + extern void foo(); + struct allocator { + ~allocator() throw(); + }; + + struct allocator_derived : allocator { }; + + // CHECK: define void @_ZN6PR75269allocatorD2Ev(%"struct.PR7526::allocator"* %this) unnamed_addr + // CHECK: call void @__cxa_call_unexpected + allocator::~allocator() throw() { foo(); } + + // CHECK: define linkonce_odr void @_ZN6PR752617allocator_derivedD1Ev(%"struct.PR7526::allocator_derived"* %this) unnamed_addr + // CHECK-NOT: call void @__cxa_call_unexpected + // CHECK: } + void foo() { + allocator_derived ad; + } +} + +// PR5084 +template<typename T> +class A1 { + ~A1(); +}; + +template<> A1<char>::~A1(); + +// PR5529 +namespace PR5529 { + struct A { + ~A(); + }; + + A::~A() { } + struct B : A { + virtual ~B(); + }; + + B::~B() {} +} + +// FIXME: there's a known problem in the codegen here where, if one +// destructor throws, the remaining destructors aren't run. Fix it, +// then make this code check for it. +namespace test0 { + void foo(); + struct VBase { ~VBase(); }; + struct Base { ~Base(); }; + struct Member { ~Member(); }; + + struct A : Base { + Member M; + ~A(); + }; + + // The function-try-block won't suppress -mconstructor-aliases here. + A::~A() try { } catch (int i) {} + +// complete destructor alias tested above + +// CHECK: define void @_ZN5test01AD2Ev(%"struct.test0::A"* %this) unnamed_addr +// CHECK: invoke void @_ZN5test06MemberD1Ev +// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test04BaseD2Ev +// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]] + + struct B : Base, virtual VBase { + Member M; + ~B(); + }; + B::~B() try { } catch (int i) {} + // It will suppress the delegation optimization here, though. + +// CHECK: define void @_ZN5test01BD1Ev(%"struct.test0::B"* %this) unnamed_addr +// CHECK: invoke void @_ZN5test06MemberD1Ev +// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test04BaseD2Ev +// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test05VBaseD2Ev +// CHECK: unwind label [[VBASE_UNWIND:%[a-zA-Z0-9.]+]] + +// CHECK: define void @_ZN5test01BD2Ev(%"struct.test0::B"* %this, i8** %vtt) unnamed_addr +// CHECK: invoke void @_ZN5test06MemberD1Ev +// CHECK: unwind label [[MEM_UNWIND:%[a-zA-Z0-9.]+]] +// CHECK: invoke void @_ZN5test04BaseD2Ev +// CHECK: unwind label [[BASE_UNWIND:%[a-zA-Z0-9.]+]] +} + +// Test base-class aliasing. +namespace test1 { + struct A { ~A(); char ***m; }; // non-trivial destructor + struct B { ~B(); }; // non-trivial destructor + struct Empty { }; // trivial destructor, empty + struct NonEmpty { int x; }; // trivial destructor, non-empty + + // There must be a definition in this translation unit for the alias + // optimization to apply. + A::~A() { delete m; } + + struct M : A { ~M(); }; + M::~M() {} // alias tested above + + struct N : A, Empty { ~N(); }; + N::~N() {} // alias tested above + + struct O : Empty, A { ~O(); }; + O::~O() {} // alias tested above + + struct P : NonEmpty, A { ~P(); }; + P::~P() {} // CHECK: define void @_ZN5test11PD2Ev(%"struct.test1::P"* %this) unnamed_addr + + struct Q : A, B { ~Q(); }; + Q::~Q() {} // CHECK: define void @_ZN5test11QD2Ev(%"struct.test1::Q"* %this) unnamed_addr + + struct R : A { ~R(); }; + R::~R() { A a; } // CHECK: define void @_ZN5test11RD2Ev(%"struct.test1::R"* %this) unnamed_addr + + struct S : A { ~S(); int x; }; + S::~S() {} // alias tested above + + struct T : A { ~T(); B x; }; + T::~T() {} // CHECK: define void @_ZN5test11TD2Ev(%"struct.test1::T"* %this) unnamed_addr + + // The VTT parameter prevents this. We could still make this work + // for calling conventions that are safe against extra parameters. + struct U : A, virtual B { ~U(); }; + U::~U() {} // CHECK: define void @_ZN5test11UD2Ev(%"struct.test1::U"* %this, i8** %vtt) unnamed_addr +} + +// PR6471 +namespace test2 { + struct A { ~A(); char ***m; }; + struct B : A { ~B(); }; + + B::~B() {} + // CHECK: define void @_ZN5test21BD2Ev(%"struct.test2::B"* %this) unnamed_addr + // CHECK: call void @_ZN5test21AD2Ev +} + +// PR7142 +namespace test3 { + struct A { virtual ~A(); }; + struct B { virtual ~B(); }; + namespace { // internal linkage => deferred + struct C : A, B {}; // ~B() in D requires a this-adjustment thunk + struct D : C {}; // D::~D() is an alias to C::~C() + } + + void test() { + new D; // Force emission of D's vtable + } + + // Checked at top of file: + // @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev + + // More checks at end of file. + +} + +namespace test4 { + struct A { ~A(); }; + + // CHECK: define void @_ZN5test43fooEv() + // CHECK: call void @_ZN5test41AD1Ev + // CHECK: ret void + void foo() { + { + A a; + goto failure; + } + + failure: + return; + } + + // CHECK: define void @_ZN5test43barEi( + // CHECK: [[X:%.*]] = alloca i32 + // CHECK-NEXT: [[A:%.*]] = alloca + // CHECK: br label + // CHECK: [[TMP:%.*]] = load i32* [[X]] + // CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP]], 0 + // CHECK-NEXT: br i1 + // CHECK: call void @_ZN5test41AD1Ev( + // CHECK: br label + // CHECK: [[TMP:%.*]] = load i32* [[X]] + // CHECK: [[TMP2:%.*]] = add nsw i32 [[TMP]], -1 + // CHECK: store i32 [[TMP2]], i32* [[X]] + // CHECK: br label + // CHECK: ret void + void bar(int x) { + for (A a; x; ) { + x--; + } + } +} + +// PR7575 +namespace test5 { + struct A { ~A(); }; + + // CHECK: define void @_ZN5test53fooEv() + // CHECK: [[ELEMS:%.*]] = alloca [5 x [[A:%.*]]], align + // CHECK-NEXT: [[EXN:%.*]] = alloca i8* + // CHECK-NEXT: [[SEL:%.*]] = alloca i32 + // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x [[A]]]* [[ELEMS]], i32 0, i32 0 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 5 + // CHECK-NEXT: br label + // CHECK: [[POST:%.*]] = phi [[A]]* [ [[END]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ] + // CHECK-NEXT: [[ELT]] = getelementptr inbounds [[A]]* [[POST]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[ELT]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[ELT]], [[BEGIN]] + // CHECK-NEXT: br i1 [[T0]], + // CHECK: ret void + // lpad + // CHECK: [[EMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[ELT]] + // CHECK-NEXT: br i1 [[EMPTY]] + // CHECK: [[AFTER:%.*]] = phi [[A]]* [ [[ELT]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[CUR]]) + // CHECK: [[DONE:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]] + // CHECK-NEXT: br i1 [[DONE]], + void foo() { + A elems[5]; + } +} + +namespace test6 { + void opaque(); + + struct A { ~A(); }; + template <unsigned> struct B { B(); ~B(); int _; }; + struct C : B<0>, B<1>, virtual B<2>, virtual B<3> { + A x, y, z; + + C(); + ~C(); + }; + + C::C() { opaque(); } + // CHECK: define void @_ZN5test61CC1Ev(%"struct.test6::C"* %this) unnamed_addr + // CHECK: call void @_ZN5test61BILj2EEC2Ev + // CHECK: invoke void @_ZN5test61BILj3EEC2Ev + // CHECK: invoke void @_ZN5test61BILj0EEC2Ev + // CHECK: invoke void @_ZN5test61BILj1EEC2Ev + // CHECK: invoke void @_ZN5test66opaqueEv + // CHECK: ret void + // FIXME: way too much EH cleanup code follows + + C::~C() { opaque(); } + // CHECK: define void @_ZN5test61CD1Ev(%"struct.test6::C"* %this) unnamed_addr + // CHECK: invoke void @_ZN5test61CD2Ev + // CHECK: invoke void @_ZN5test61BILj3EED2Ev + // CHECK: call void @_ZN5test61BILj2EED2Ev + // CHECK: ret void + // CHECK: invoke void @_ZN5test61BILj3EED2Ev + // CHECK: invoke void @_ZN5test61BILj2EED2Ev + + // CHECK: define void @_ZN5test61CD2Ev(%"struct.test6::C"* %this, i8** %vtt) unnamed_addr + // CHECK: invoke void @_ZN5test66opaqueEv + // CHECK: invoke void @_ZN5test61AD1Ev + // CHECK: invoke void @_ZN5test61AD1Ev + // CHECK: invoke void @_ZN5test61AD1Ev + // CHECK: invoke void @_ZN5test61BILj1EED2Ev + // CHECK: call void @_ZN5test61BILj0EED2Ev + // CHECK: ret void + // CHECK: invoke void @_ZN5test61AD1Ev + // CHECK: invoke void @_ZN5test61AD1Ev + // CHECK: invoke void @_ZN5test61AD1Ev + // CHECK: invoke void @_ZN5test61BILj1EED2Ev + // CHECK: invoke void @_ZN5test61BILj0EED2Ev +} + +// PR 9197 +namespace test7 { + struct D { ~D(); }; + + struct A { ~A(); }; + A::~A() { } + + struct B : public A { + ~B(); + D arr[1]; + }; + + // Verify that this doesn't get emitted as an alias + // CHECK: define void @_ZN5test71BD2Ev( + // CHECK: invoke void @_ZN5test71DD1Ev( + // CHECK: call void @_ZN5test71AD2Ev( + B::~B() {} +} + +// PR10467 +namespace test8 { + struct A { A(); ~A(); }; + + void die() __attribute__((noreturn)); + void test() { + A x; + while (1) { + A y; + goto l; + } + l: die(); + } + + // CHECK: define void @_ZN5test84testEv() + // CHECK: [[X:%.*]] = alloca [[A:%.*]], align 1 + // CHECK-NEXT: [[Y:%.*]] = alloca [[A:%.*]], align 1 + // CHECK: call void @_ZN5test81AC1Ev([[A]]* [[X]]) + // CHECK-NEXT: br label + // CHECK: invoke void @_ZN5test81AC1Ev([[A]]* [[Y]]) + // CHECK: invoke void @_ZN5test81AD1Ev([[A]]* [[Y]]) + // CHECK-NOT: switch + // CHECK: invoke void @_ZN5test83dieEv() + // CHECK: unreachable +} + +// Checks from test3: + + // CHECK: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(%"struct.test3::<anonymous namespace>::D"* %this) unnamed_addr + // CHECK: invoke void @_ZN5test312_GLOBAL__N_11DD1Ev( + // CHECK: call void @_ZdlPv({{.*}}) nounwind + // CHECK: ret void + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: cleanup + // CHECK: call void @_ZdlPv({{.*}}) nounwind + // CHECK: resume { i8*, i32 } + + // Checked at top of file: + // @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev + // @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev + + // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD1Ev( + // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK: call void @_ZN5test312_GLOBAL__N_11DD1Ev( + // CHECK: ret void + + // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11DD0Ev( + // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK: call void @_ZN5test312_GLOBAL__N_11DD0Ev( + // CHECK: ret void + + // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD2Ev(%"struct.test3::<anonymous namespace>::C"* %this) unnamed_addr + // CHECK: invoke void @_ZN5test31BD2Ev( + // CHECK: call void @_ZN5test31AD2Ev( + // CHECK: ret void + + // CHECK: declare void @_ZN5test31BD2Ev( + // CHECK: declare void @_ZN5test31AD2Ev( + + // CHECK: define internal void @_ZN5test312_GLOBAL__N_11CD0Ev(%"struct.test3::<anonymous namespace>::C"* %this) unnamed_addr + // CHECK: invoke void @_ZN5test312_GLOBAL__N_11CD1Ev( + // CHECK: call void @_ZdlPv({{.*}}) nounwind + // CHECK: ret void + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: cleanup + // CHECK: call void @_ZdlPv({{.*}}) nounwind + // CHECK: resume { i8*, i32 } + + // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev( + // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK: call void @_ZN5test312_GLOBAL__N_11CD1Ev( + // CHECK: ret void + + // CHECK: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev( + // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK: call void @_ZN5test312_GLOBAL__N_11CD0Ev( + // CHECK: ret void diff --git a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp new file mode 100644 index 0000000..3de75ed --- /dev/null +++ b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +namespace Test1 { + struct A { + virtual int f() final; + }; + + // CHECK: define i32 @_ZN5Test11fEPNS_1AE + int f(A *a) { + // CHECK: call i32 @_ZN5Test11A1fEv + return a->f(); + } +} + +namespace Test2 { + struct A final { + virtual int f(); + }; + + // CHECK: define i32 @_ZN5Test21fEPNS_1AE + int f(A *a) { + // CHECK: call i32 @_ZN5Test21A1fEv + return a->f(); + } +} + +namespace Test3 { + struct A { + virtual int f(); + }; + + struct B final : A { }; + + // CHECK: define i32 @_ZN5Test31fEPNS_1BE + int f(B *b) { + // CHECK: call i32 @_ZN5Test31A1fEv + return b->f(); + } + + // CHECK: define i32 @_ZN5Test31fERNS_1BE + int f(B &b) { + // CHECK: call i32 @_ZN5Test31A1fEv + return b.f(); + } + + // CHECK: define i32 @_ZN5Test31fEPv + int f(void *v) { + // CHECK: call i32 @_ZN5Test31A1fEv + return static_cast<B*>(v)->f(); + } +} diff --git a/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp new file mode 100644 index 0000000..5eede66 --- /dev/null +++ b/clang/test/CodeGenCXX/devirtualize-virtual-function-calls.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +struct A { + virtual void f(); + virtual void f_const() const; + + A h(); +}; + +A g(); + +void f(A a, A *ap, A& ar) { + // This should not be a virtual function call. + + // CHECK: call void @_ZN1A1fEv(%struct.A* %a) + a.f(); + + // CHECK: call void % + ap->f(); + + // CHECK: call void % + ar.f(); + + // CHECK: call void @_ZN1A1fEv + A().f(); + + // CHECK: call void @_ZN1A1fEv + g().f(); + + // CHECK: call void @_ZN1A1fEv + a.h().f(); + + // CHECK: call void @_ZNK1A7f_constEv + a.f_const(); + + // CHECK: call void @_ZN1A1fEv + (a).f(); +} + +struct B { + virtual void f(); + ~B(); + + B h(); +}; + + +void f() { + // CHECK: call void @_ZN1B1fEv + B().f(); + + // CHECK: call void @_ZN1B1fEv + B().h().f(); +} + diff --git a/clang/test/CodeGenCXX/dynamic-cast-always-null.cpp b/clang/test/CodeGenCXX/dynamic-cast-always-null.cpp new file mode 100644 index 0000000..2c3ea13 --- /dev/null +++ b/clang/test/CodeGenCXX/dynamic-cast-always-null.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -std=c++11 -o - | FileCheck %s +struct A { virtual ~A(); }; +struct B final : A { }; +struct C { virtual ~C(); int c; }; + +// CHECK: @_Z1fP1B +C *f(B* b) { + // CHECK-NOT: call i8* @__dynamic_cast + // CHECK: ret %struct.C* null + return dynamic_cast<C*>(b); +} + +// CHECK: @_Z1fR1B +C &f(B& b) { + // CHECK-NOT: call i8* @__dynamic_cast + // CHECK: call void @__cxa_bad_cast() noreturn + // CHECK: ret %struct.C* undef + return dynamic_cast<C&>(b); +} diff --git a/clang/test/CodeGenCXX/dynamic-cast.cpp b/clang/test/CodeGenCXX/dynamic-cast.cpp new file mode 100644 index 0000000..813e36e --- /dev/null +++ b/clang/test/CodeGenCXX/dynamic-cast.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -o - | FileCheck %s +struct A { virtual void f(); }; +struct B : A { }; + +// CHECK: {{define.*@_Z1fP1A}} +B fail; +const B& f(A *a) { + try { + // CHECK: call i8* @__dynamic_cast + // CHECK: br i1 + // CHECK: invoke void @__cxa_bad_cast() noreturn + dynamic_cast<const B&>(*a); + } catch (...) { + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: catch i8* null + } + return fail; +} diff --git a/clang/test/CodeGenCXX/eh.cpp b/clang/test/CodeGenCXX/eh.cpp new file mode 100644 index 0000000..584af40 --- /dev/null +++ b/clang/test/CodeGenCXX/eh.cpp @@ -0,0 +1,446 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin -std=c++11 -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s + +struct test1_D { + double d; +} d1; + +void test1() { + throw d1; +} + +// CHECK: define void @_Z5test1v() +// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8) +// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]] +// CHECK-NEXT: [[EXN2:%.*]] = bitcast [[DSTAR]] [[EXN]] to i8* +// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[EXN2]], i8* bitcast ([[DSTAR]] @d1 to i8*), i64 8, i32 8, i1 false) +// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8* }* @_ZTI7test1_D to i8*), i8* null) noreturn +// CHECK-NEXT: unreachable + + +struct test2_D { + test2_D(const test2_D&o); + test2_D(); + virtual void bar() { } + int i; int j; +} d2; + +void test2() { + throw d2; +} + +// CHECK: define void @_Z5test2v() +// CHECK: [[EXNVAR:%.*]] = alloca i8* +// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32 +// CHECK-NEXT: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 16) +// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[DSTAR:%[^*]*\*]] +// CHECK-NEXT: invoke void @_ZN7test2_DC1ERKS_([[DSTAR]] [[EXN]], [[DSTAR]] @d2) +// CHECK-NEXT: to label %[[CONT:.*]] unwind label %{{.*}} +// : [[CONT]]: (can't check this in Release-Asserts builds) +// CHECK: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTI7test2_D to i8*), i8* null) noreturn +// CHECK-NEXT: unreachable + + +struct test3_D { + test3_D() { } + test3_D(volatile test3_D&o); + virtual void bar(); +}; + +void test3() { + throw (volatile test3_D *)0; +} + +// CHECK: define void @_Z5test3v() +// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 8) +// CHECK-NEXT: [[EXN:%.*]] = bitcast i8* [[EXNOBJ]] to [[D:%[^*]+]]** +// CHECK-NEXT: store [[D]]* null, [[D]]** [[EXN]] +// CHECK-NEXT: call void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({ i8*, i8*, i32, i8* }* @_ZTIPV7test3_D to i8*), i8* null) noreturn +// CHECK-NEXT: unreachable + + +void test4() { + throw; +} + +// CHECK: define void @_Z5test4v() +// CHECK: call void @__cxa_rethrow() noreturn +// CHECK-NEXT: unreachable + + +// rdar://problem/7696549 +namespace test5 { + struct A { + A(); + A(const A&); + ~A(); + }; + + void test() { + try { throw A(); } catch (A &x) {} + } +// CHECK: define void @_ZN5test54testEv() +// CHECK: [[EXNOBJ:%.*]] = call i8* @__cxa_allocate_exception(i64 1) +// CHECK: [[EXNCAST:%.*]] = bitcast i8* [[EXNOBJ]] to [[A:%[^*]*]]* +// CHECK-NEXT: invoke void @_ZN5test51AC1Ev([[A]]* [[EXNCAST]]) +// CHECK: invoke void @__cxa_throw(i8* [[EXNOBJ]], i8* bitcast ({{.*}}* @_ZTIN5test51AE to i8*), i8* bitcast (void ([[A]]*)* @_ZN5test51AD1Ev to i8*)) noreturn +// CHECK-NEXT: to label {{%.*}} unwind label %[[HANDLER:[^ ]*]] +// : [[HANDLER]]: (can't check this in Release-Asserts builds) +// CHECK: {{%.*}} = call i32 @llvm.eh.typeid.for(i8* bitcast ({{.*}}* @_ZTIN5test51AE to i8*)) +} + +namespace test6 { + template <class T> struct allocator { + ~allocator() throw() { } + }; + + void foo() { + allocator<int> a; + } +} + +// PR7127 +namespace test7 { +// CHECK: define i32 @_ZN5test73fooEv() + int foo() { +// CHECK: [[CAUGHTEXNVAR:%.*]] = alloca i8* +// CHECK-NEXT: [[SELECTORVAR:%.*]] = alloca i32 +// CHECK-NEXT: [[INTCATCHVAR:%.*]] = alloca i32 + try { + try { +// CHECK-NEXT: [[EXNALLOC:%.*]] = call i8* @__cxa_allocate_exception +// CHECK-NEXT: bitcast i8* [[EXNALLOC]] to i32* +// CHECK-NEXT: store i32 1, i32* +// CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXNALLOC]], i8* bitcast (i8** @_ZTIi to i8*), i8* null + throw 1; + } + +// CHECK: [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) +// CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*) +// CHECK-NEXT: catch i8* null +// CHECK-NEXT: [[CAUGHTEXN:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 0 +// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]] +// CHECK-NEXT: [[SELECTOR:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 1 +// CHECK-NEXT: store i32 [[SELECTOR]], i32* [[SELECTORVAR]] +// CHECK-NEXT: br label +// CHECK: [[SELECTOR:%.*]] = load i32* [[SELECTORVAR]] +// CHECK-NEXT: [[T0:%.*]] = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) +// CHECK-NEXT: icmp eq i32 [[SELECTOR]], [[T0]] +// CHECK-NEXT: br i1 +// CHECK: [[T0:%.*]] = load i8** [[CAUGHTEXNVAR]] +// CHECK-NEXT: [[T1:%.*]] = call i8* @__cxa_begin_catch(i8* [[T0]]) +// CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to i32* +// CHECK-NEXT: [[T3:%.*]] = load i32* [[T2]] +// CHECK-NEXT: store i32 [[T3]], i32* {{%.*}}, align 4 +// CHECK-NEXT: invoke void @__cxa_rethrow + catch (int) { + throw; + } + } +// CHECK: [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) +// CHECK-NEXT: catch i8* null +// CHECK-NEXT: [[CAUGHTEXN:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 0 +// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]] +// CHECK-NEXT: [[SELECTOR:%.*]] = extractvalue { i8*, i32 } [[CAUGHTVAL]], 1 +// CHECK-NEXT: store i32 [[SELECTOR]], i32* [[SELECTORVAR]] +// CHECK-NEXT: call void @__cxa_end_catch() +// CHECK-NEXT: br label +// CHECK: load i8** [[CAUGHTEXNVAR]] +// CHECK-NEXT: call i8* @__cxa_begin_catch +// CHECK-NEXT: call void @__cxa_end_catch + catch (...) { + } +// CHECK: ret i32 0 + return 0; + } +} + +// Ordering of destructors in a catch handler. +namespace test8 { + struct A { A(const A&); ~A(); }; + void bar(); + + // CHECK: define void @_ZN5test83fooEv() + void foo() { + try { + // CHECK: invoke void @_ZN5test83barEv() + bar(); + } catch (A a) { + // CHECK: call i8* @__cxa_get_exception_ptr + // CHECK-NEXT: bitcast + // CHECK-NEXT: invoke void @_ZN5test81AC1ERKS0_( + // CHECK: call i8* @__cxa_begin_catch + // CHECK-NEXT: call void @_ZN5test81AD1Ev( + // CHECK: call void @__cxa_end_catch() + // CHECK: ret void + } + } +} + +// Constructor function-try-block must rethrow on fallthrough. +// rdar://problem/7696603 +namespace test9 { + void opaque(); + + struct A { A(); }; + + // CHECK: define void @_ZN5test91AC1Ev(%"struct.test9::A"* %this) unnamed_addr + // CHECK: call void @_ZN5test91AC2Ev + // CHECK-NEXT: ret void + + // CHECK: define void @_ZN5test91AC2Ev(%"struct.test9::A"* %this) unnamed_addr + A::A() try { + // CHECK: invoke void @_ZN5test96opaqueEv() + opaque(); + } catch (int x) { + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: catch i8* bitcast (i8** @_ZTIi to i8*) + + // CHECK: call i8* @__cxa_begin_catch + // CHECK: invoke void @_ZN5test96opaqueEv() + // CHECK: invoke void @__cxa_rethrow() + opaque(); + } +} + +// __cxa_end_catch can throw for some kinds of caught exceptions. +namespace test10 { + void opaque(); + + struct A { ~A(); }; + struct B { int x; }; + + // CHECK: define void @_ZN6test103fooEv() + void foo() { + A a; // force a cleanup context + + try { + // CHECK: invoke void @_ZN6test106opaqueEv() + opaque(); + } catch (int i) { + // CHECK: call i8* @__cxa_begin_catch + // CHECK-NEXT: bitcast + // CHECK-NEXT: load i32* + // CHECK-NEXT: store i32 + // CHECK-NEXT: call void @__cxa_end_catch() nounwind + } catch (B a) { + // CHECK: call i8* @__cxa_begin_catch + // CHECK-NEXT: bitcast + // CHECK-NEXT: bitcast + // CHECK-NEXT: bitcast + // CHECK-NEXT: call void @llvm.memcpy + // CHECK-NEXT: invoke void @__cxa_end_catch() + } catch (...) { + // CHECK: call i8* @__cxa_begin_catch + // CHECK-NEXT: invoke void @__cxa_end_catch() + } + + // CHECK: call void @_ZN6test101AD1Ev( + } +} + +// __cxa_begin_catch returns pointers by value, even when catching by reference +// <rdar://problem/8212123> +namespace test11 { + void opaque(); + + // CHECK: define void @_ZN6test113fooEv() + void foo() { + try { + // CHECK: invoke void @_ZN6test116opaqueEv() + opaque(); + } catch (int**&p) { + // CHECK: [[EXN:%.*]] = load i8** + // CHECK-NEXT: call i8* @__cxa_begin_catch(i8* [[EXN]]) nounwind + // CHECK-NEXT: [[ADJ1:%.*]] = getelementptr i8* [[EXN]], i32 32 + // CHECK-NEXT: [[ADJ2:%.*]] = bitcast i8* [[ADJ1]] to i32*** + // CHECK-NEXT: store i32*** [[ADJ2]], i32**** [[P:%.*]] + // CHECK-NEXT: call void @__cxa_end_catch() nounwind + } + } + + struct A {}; + + // CHECK: define void @_ZN6test113barEv() + void bar() { + try { + // CHECK: [[EXNSLOT:%.*]] = alloca i8* + // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32 + // CHECK-NEXT: [[P:%.*]] = alloca [[A:%.*]]**, + // CHECK-NEXT: [[TMP:%.*]] = alloca [[A]]* + // CHECK-NEXT: invoke void @_ZN6test116opaqueEv() + opaque(); + } catch (A*&p) { + // CHECK: [[EXN:%.*]] = load i8** [[EXNSLOT]] + // CHECK-NEXT: [[ADJ1:%.*]] = call i8* @__cxa_begin_catch(i8* [[EXN]]) nounwind + // CHECK-NEXT: [[ADJ2:%.*]] = bitcast i8* [[ADJ1]] to [[A]]* + // CHECK-NEXT: store [[A]]* [[ADJ2]], [[A]]** [[TMP]] + // CHECK-NEXT: store [[A]]** [[TMP]], [[A]]*** [[P]] + // CHECK-NEXT: call void @__cxa_end_catch() nounwind + } + } +} + +// PR7686 +namespace test12 { + struct A { ~A() noexcept(false); }; + bool opaque(const A&); + + // CHECK: define void @_ZN6test124testEv() + void test() { + // CHECK: [[X:%.*]] = alloca [[A:%.*]], + // CHECK: [[EHCLEANUPDEST:%.*]] = alloca i32 + // CHECK: [[Y:%.*]] = alloca [[A]] + // CHECK: [[Z:%.*]] = alloca [[A]] + // CHECK: [[CLEANUPDEST:%.*]] = alloca i32 + + A x; + // CHECK: invoke zeroext i1 @_ZN6test126opaqueERKNS_1AE( + if (opaque(x)) { + A y; + A z; + + // CHECK: invoke void @_ZN6test121AD1Ev([[A]]* [[Z]]) + // CHECK: invoke void @_ZN6test121AD1Ev([[A]]* [[Y]]) + // CHECK-NOT: switch + goto success; + } + + success: + bool _ = true; + + // CHECK: call void @_ZN6test121AD1Ev([[A]]* [[X]]) + // CHECK-NEXT: ret void + } +} + +// Reduced from some TableGen code that was causing a self-host crash. +namespace test13 { + struct A { ~A(); }; + + void test0(int x) { + try { + switch (x) { + case 0: + break; + case 1:{ + A a; + break; + } + default: + return; + } + return; + } catch (int x) { + } + return; + } + + void test1(int x) { + A y; + try { + switch (x) { + default: break; + } + } catch (int x) {} + } +} + +// rdar://problem/8231514 +namespace test14 { + struct A { ~A(); }; + struct B { ~B(); }; + + B b(); + void opaque(); + + void foo() { + A a; + try { + B str = b(); + opaque(); + } catch (int x) { + } + } +} + +// rdar://problem/8231514 +// JumpDests shouldn't get confused by scopes that aren't normal cleanups. +namespace test15 { + struct A { ~A(); }; + + bool opaque(int); + + // CHECK: define void @_ZN6test153fooEv() + void foo() { + A a; + + try { + // CHECK: [[X:%.*]] = alloca i32 + // CHECK: store i32 10, i32* [[X]] + // CHECK-NEXT: br label + // -> while.cond + int x = 10; + + while (true) { + // CHECK: load i32* [[X]] + // CHECK-NEXT: [[COND:%.*]] = invoke zeroext i1 @_ZN6test156opaqueEi + // CHECK: br i1 [[COND]] + if (opaque(x)) + // CHECK: br label + break; + + // CHECK: br label + } + // CHECK: br label + } catch (int x) { } + + // CHECK: call void @_ZN6test151AD1Ev + } +} + +namespace test16 { + struct A { A(); ~A() noexcept(false); }; + struct B { int x; B(const A &); ~B() noexcept(false); }; + void foo(); + bool cond(); + + // CHECK: define void @_ZN6test163barEv() + void bar() { + // CHECK: [[EXN_SAVE:%.*]] = alloca i8* + // CHECK-NEXT: [[EXN_ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: [[TEMP:%.*]] = alloca [[A:%.*]], + // CHECK-NEXT: [[EXNSLOT:%.*]] = alloca i8* + // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32 + // CHECK-NEXT: [[TEMP_ACTIVE:%.*]] = alloca i1 + + cond() ? throw B(A()) : foo(); + + // CHECK-NEXT: [[COND:%.*]] = call zeroext i1 @_ZN6test164condEv() + // CHECK-NEXT: store i1 false, i1* [[EXN_ACTIVE]] + // CHECK-NEXT: store i1 false, i1* [[TEMP_ACTIVE]] + // CHECK-NEXT: br i1 [[COND]], + + // CHECK: [[EXN:%.*]] = call i8* @__cxa_allocate_exception(i64 4) + // CHECK-NEXT: store i8* [[EXN]], i8** [[EXN_SAVE]] + // CHECK-NEXT: store i1 true, i1* [[EXN_ACTIVE]] + // CHECK-NEXT: [[T0:%.*]] = bitcast i8* [[EXN]] to [[B:%.*]]* + // CHECK-NEXT: invoke void @_ZN6test161AC1Ev([[A]]* [[TEMP]]) + // CHECK: store i1 true, i1* [[TEMP_ACTIVE]] + // CHECK-NEXT: invoke void @_ZN6test161BC1ERKNS_1AE([[B]]* [[T0]], [[A]]* [[TEMP]]) + // CHECK: store i1 false, i1* [[EXN_ACTIVE]] + // CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXN]], + + // CHECK: invoke void @_ZN6test163fooEv() + // CHECK: br label + + // CHECK: invoke void @_ZN6test161AD1Ev([[A]]* [[TEMP]]) + // CHECK: ret void + + // CHECK: [[T0:%.*]] = load i1* [[EXN_ACTIVE]] + // CHECK-NEXT: br i1 [[T0]] + // CHECK: [[T1:%.*]] = load i8** [[EXN_SAVE]] + // CHECK-NEXT: call void @__cxa_free_exception(i8* [[T1]]) + // CHECK-NEXT: br label + } +} diff --git a/clang/test/CodeGenCXX/elide-call-reference.cpp b/clang/test/CodeGenCXX/elide-call-reference.cpp new file mode 100644 index 0000000..55d30e2 --- /dev/null +++ b/clang/test/CodeGenCXX/elide-call-reference.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// PR5695 + +struct A { A(const A&); ~A(); }; +A& a(); +void b() { + A x = a(); +} + +// CHECK: call {{.*}} @_ZN1AC1ERKS_ +// CHECK: call {{.*}} @_ZN1AD1Ev diff --git a/clang/test/CodeGenCXX/empty-classes.cpp b/clang/test/CodeGenCXX/empty-classes.cpp new file mode 100644 index 0000000..1ce1dad --- /dev/null +++ b/clang/test/CodeGenCXX/empty-classes.cpp @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s + +struct Empty { }; + +struct A { + explicit A(unsigned a = 0xffffffff) : a(a) { } + + unsigned a; +}; + +struct B : A, Empty { + B() : A(), Empty() { } +}; + +struct C : A, Empty { + C() : A(), Empty() { } + C(const C& other) : A(0x12345678), Empty(other) { } +}; + +struct D : A, Empty { + D& operator=(const D& other) { + a = 0x87654321; + Empty::operator=(other); + + return *this; + } +}; + +#define CHECK(x) if (!(x)) return __LINE__ + +// PR7012 +// CHECK: define i32 @_Z1fv() +int f() { + B b1; + + // Check that A::a is not overwritten by the Empty default constructor. + CHECK(b1.a == 0xffffffff); + + C c1; + C c2(c1); + + // Check that A::a has the value set in the C::C copy constructor. + CHECK(c2.a == 0x12345678); + + D d1, d2; + d2 = d1; + + // Check that A::as has the value set in the D copy assignment operator. + CHECK(d2.a == 0x87654321); + + // Success! + // CHECK: ret i32 0 + return 0; +} + +namespace PR8796 { + struct FreeCell { + }; + union ThingOrCell { + FreeCell t; + FreeCell cell; + }; + struct Things { + ThingOrCell things; + }; + Things x; +} + +#ifdef HARNESS +extern "C" void printf(const char *, ...); + +int main() { + int result = f(); + + if (result == 0) + printf("success!\n"); + else + printf("test on line %d failed!\n", result); + + return result; +} +#endif diff --git a/clang/test/CodeGenCXX/empty-union.cpp b/clang/test/CodeGenCXX/empty-union.cpp new file mode 100644 index 0000000..7f3e6cc --- /dev/null +++ b/clang/test/CodeGenCXX/empty-union.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s + +union sigval { }; +union sigval Test1; + +union NonPODUnion { ~NonPODUnion(); }; +union NonPODUnion Test2; diff --git a/clang/test/CodeGenCXX/enum.cpp b/clang/test/CodeGenCXX/enum.cpp new file mode 100644 index 0000000..cfcd264 --- /dev/null +++ b/clang/test/CodeGenCXX/enum.cpp @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -emit-llvm-only -verify %s + +enum A { a } __attribute((packed)); +int func(A x) { return x==a; } diff --git a/clang/test/CodeGenCXX/eval-recursive-constant.cpp b/clang/test/CodeGenCXX/eval-recursive-constant.cpp new file mode 100644 index 0000000..608c95d --- /dev/null +++ b/clang/test/CodeGenCXX/eval-recursive-constant.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 %s -emit-llvm-only + +extern const int a,b; +const int a=b,b=a; +int c() { if (a) return 1; return 0; } diff --git a/clang/test/CodeGenCXX/exceptions-no-rtti.cpp b/clang/test/CodeGenCXX/exceptions-no-rtti.cpp new file mode 100644 index 0000000..902d6ac --- /dev/null +++ b/clang/test/CodeGenCXX/exceptions-no-rtti.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -fno-rtti -fcxx-exceptions -fexceptions %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// CHECK: @_ZTIN5test11AE = linkonce_odr unnamed_addr constant +// CHECK: @_ZTIN5test11BE = linkonce_odr unnamed_addr constant +// CHECK: @_ZTIN5test11CE = linkonce_odr unnamed_addr constant +// CHECK: @_ZTIN5test11DE = linkonce_odr unnamed_addr constant +// CHECK: @_ZTIPN5test11DE = linkonce_odr unnamed_addr constant {{.*}} @_ZTIN5test11DE + +// PR6974: this shouldn't crash +namespace test0 { + class err {}; + + void f(void) { + try { + } catch (err &) { + } + } +} + +namespace test1 { + // These classes have key functions defined out-of-line. Under + // normal circumstances, we wouldn't generate RTTI for them; under + // -fno-rtti, we generate RTTI only when required by EH. But + // everything gets hidden visibility because we assume that all + // users are also compiled under -fno-rtti and therefore will be + // emitting RTTI regardless of key function. + class A { virtual void foo(); }; + class B { virtual void foo(); }; + class C { virtual void foo(); }; + class D { virtual void foo(); }; + + void opaque(); + + void test0() { + throw A(); + } + + void test1() throw(B) { + opaque(); + } + + void test2() { + try { + opaque(); + } catch (C&) {} + } + + void test3(D *ptr) { + throw ptr; + }; +} diff --git a/clang/test/CodeGenCXX/exceptions.cpp b/clang/test/CodeGenCXX/exceptions.cpp new file mode 100644 index 0000000..079c1e5 --- /dev/null +++ b/clang/test/CodeGenCXX/exceptions.cpp @@ -0,0 +1,416 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s + +typedef typeof(sizeof(0)) size_t; + +// This just shouldn't crash. +namespace test0 { + struct allocator { + allocator(); + allocator(const allocator&); + ~allocator(); + }; + + void f(); + void g(bool b, bool c) { + if (b) { + if (!c) + throw allocator(); + + return; + } + f(); + } +} + +namespace test1 { + struct A { A(int); A(int, int); ~A(); void *p; }; + + A *a() { + // CHECK: define [[A:%.*]]* @_ZN5test11aEv() + // CHECK: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 5) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + return new A(5); + } + + A *b() { + // CHECK: define [[A:%.*]]* @_ZN5test11bEv() + // CHECK: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: [[FOO:%.*]] = invoke i32 @_ZN5test13fooEv() + // CHECK: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[FOO]]) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + extern int foo(); + return new A(foo()); + } + + struct B { B(); ~B(); operator int(); int x; }; + B makeB(); + + A *c() { + // CHECK: define [[A:%.*]]* @_ZN5test11cEv() + // CHECK: [[ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: store i1 true, i1* [[ACTIVE]] + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test11BC1Ev([[B:%.*]]* [[T0:%.*]]) + // CHECK: [[T1:%.*]] = getelementptr inbounds [[B]]* [[T0]], i32 0, i32 0 + // CHECK-NEXT: [[T2:%.*]] = load i32* [[T1]], align 4 + // CHECK-NEXT: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[T2]]) + // CHECK: store i1 false, i1* [[ACTIVE]] + // CHECK-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]]) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: [[ISACTIVE:%.*]] = load i1* [[ACTIVE]] + // CHECK-NEXT: br i1 [[ISACTIVE]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + return new A(B().x); + } + + A *d() { + // CHECK: define [[A:%.*]]* @_ZN5test11dEv() + // CHECK: [[ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: store i1 true, i1* [[ACTIVE]] + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test11BC1Ev([[B:%.*]]* [[T0:%.*]]) + // CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]]) + // CHECK: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[T1]]) + // CHECK: store i1 false, i1* [[ACTIVE]] + // CHECK-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]]) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: [[ISACTIVE:%.*]] = load i1* [[ACTIVE]] + // CHECK-NEXT: br i1 [[ISACTIVE]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + return new A(B()); + } + + A *e() { + // CHECK: define [[A:%.*]]* @_ZN5test11eEv() + // CHECK: [[ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: store i1 true, i1* [[ACTIVE]] + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test11BC1Ev([[B:%.*]]* [[T0:%.*]]) + // CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]]) + // CHECK: invoke void @_ZN5test11BC1Ev([[B]]* [[T2:%.*]]) + // CHECK: [[T3:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T2]]) + // CHECK: invoke void @_ZN5test11AC1Eii([[A]]* [[CAST]], i32 [[T1]], i32 [[T3]]) + // CHECK: store i1 false, i1* [[ACTIVE]] + // CHECK-NEXT: invoke void @_ZN5test11BD1Ev([[B]]* [[T2]]) + // CHECK: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]]) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: [[ISACTIVE:%.*]] = load i1* [[ACTIVE]] + // CHECK-NEXT: br i1 [[ISACTIVE]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + return new A(B(), B()); + } + A *f() { + return new A(makeB().x); + } + A *g() { + return new A(makeB()); + } + A *h() { + return new A(makeB(), makeB()); + } + + A *i() { + // CHECK: define [[A:%.*]]* @_ZN5test11iEv() + // CHECK: [[X:%.*]] = alloca [[A]]*, align 8 + // CHECK: [[ACTIVE:%.*]] = alloca i1 + // CHECK: [[NEW:%.*]] = call noalias i8* @_Znwm(i64 8) + // CHECK-NEXT: store i1 true, i1* [[ACTIVE]] + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret [[T0:%.*]]) + // CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]]) + // CHECK: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[T1]]) + // CHECK: store i1 false, i1* [[ACTIVE]] + // CHECK-NEXT: store [[A]]* [[CAST]], [[A]]** [[X]], align 8 + // CHECK: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret [[T2:%.*]]) + // CHECK: [[RET:%.*]] = load [[A]]** [[X]], align 8 + // CHECK: invoke void @_ZN5test11BD1Ev([[B]]* [[T2]]) + // CHECK: invoke void @_ZN5test11BD1Ev([[B]]* [[T0]]) + // CHECK: ret [[A]]* [[RET]] + // CHECK: [[ISACTIVE:%.*]] = load i1* [[ACTIVE]] + // CHECK-NEXT: br i1 [[ISACTIVE]] + // CHECK: call void @_ZdlPv(i8* [[NEW]]) + A *x; + return (x = new A(makeB()), makeB(), x); + } +} + +namespace test2 { + struct A { + A(int); A(int, int); ~A(); + void *p; + void *operator new(size_t); + void operator delete(void*, size_t); + }; + + A *a() { + // CHECK: define [[A:%.*]]* @_ZN5test21aEv() + // CHECK: [[NEW:%.*]] = call i8* @_ZN5test21AnwEm(i64 8) + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test21AC1Ei([[A]]* [[CAST]], i32 5) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: invoke void @_ZN5test21AdlEPvm(i8* [[NEW]], i64 8) + // CHECK: call void @_ZSt9terminatev() + return new A(5); + } +} + +namespace test3 { + struct A { + A(int); A(int, int); A(const A&); ~A(); + void *p; + void *operator new(size_t, void*, double); + void operator delete(void*, void*, double); + }; + + void *foo(); + double bar(); + A makeA(), *makeAPtr(); + + A *a() { + // CHECK: define [[A:%.*]]* @_ZN5test31aEv() + // CHECK: [[FOO:%.*]] = call i8* @_ZN5test33fooEv() + // CHECK: [[BAR:%.*]] = call double @_ZN5test33barEv() + // CHECK: [[NEW:%.*]] = call i8* @_ZN5test31AnwEmPvd(i64 8, i8* [[FOO]], double [[BAR]]) + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test31AC1Ei([[A]]* [[CAST]], i32 5) + // CHECK: ret [[A]]* [[CAST]] + // CHECK: invoke void @_ZN5test31AdlEPvS1_d(i8* [[NEW]], i8* [[FOO]], double [[BAR]]) + // CHECK: call void @_ZSt9terminatev() + return new(foo(),bar()) A(5); + } + + // rdar://problem/8439196 + A *b(bool cond) { + + // CHECK: define [[A:%.*]]* @_ZN5test31bEb(i1 zeroext + // CHECK: [[SAVED0:%.*]] = alloca i8* + // CHECK-NEXT: [[SAVED1:%.*]] = alloca i8* + // CHECK-NEXT: [[CLEANUPACTIVE:%.*]] = alloca i1 + + // CHECK: [[COND:%.*]] = trunc i8 {{.*}} to i1 + // CHECK-NEXT: store i1 false, i1* [[CLEANUPACTIVE]] + // CHECK-NEXT: br i1 [[COND]] + return (cond ? + + // CHECK: [[FOO:%.*]] = call i8* @_ZN5test33fooEv() + // CHECK-NEXT: [[NEW:%.*]] = call i8* @_ZN5test31AnwEmPvd(i64 8, i8* [[FOO]], double [[CONST:.*]]) + // CHECK-NEXT: store i8* [[NEW]], i8** [[SAVED0]] + // CHECK-NEXT: store i8* [[FOO]], i8** [[SAVED1]] + // CHECK-NEXT: store i1 true, i1* [[CLEANUPACTIVE]] + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: invoke void @_ZN5test35makeAEv([[A]]* sret [[CAST]]) + // CHECK: br label + // -> cond.end + new(foo(),10.0) A(makeA()) : + + // CHECK: [[MAKE:%.*]] = call [[A]]* @_ZN5test38makeAPtrEv() + // CHECK: br label + // -> cond.end + makeAPtr()); + + // cond.end: + // CHECK: [[RESULT:%.*]] = phi [[A]]* {{.*}}[[CAST]]{{.*}}[[MAKE]] + // CHECK: ret [[A]]* [[RESULT]] + + // in the EH path: + // CHECK: [[ISACTIVE:%.*]] = load i1* [[CLEANUPACTIVE]] + // CHECK-NEXT: br i1 [[ISACTIVE]] + // CHECK: [[V0:%.*]] = load i8** [[SAVED0]] + // CHECK-NEXT: [[V1:%.*]] = load i8** [[SAVED1]] + // CHECK-NEXT: invoke void @_ZN5test31AdlEPvS1_d(i8* [[V0]], i8* [[V1]], double [[CONST]]) + } +} + +namespace test4 { + struct A { + A(int); A(int, int); ~A(); + void *p; + void *operator new(size_t, void*, void*); + void operator delete(void*, size_t, void*, void*); // not a match + }; + + A *a() { + // CHECK: define [[A:%.*]]* @_ZN5test41aEv() + // CHECK: [[FOO:%.*]] = call i8* @_ZN5test43fooEv() + // CHECK-NEXT: [[BAR:%.*]] = call i8* @_ZN5test43barEv() + // CHECK-NEXT: [[NEW:%.*]] = call i8* @_ZN5test41AnwEmPvS1_(i64 8, i8* [[FOO]], i8* [[BAR]]) + // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* + // CHECK-NEXT: call void @_ZN5test41AC1Ei([[A]]* [[CAST]], i32 5) + // CHECK-NEXT: ret [[A]]* [[CAST]] + extern void *foo(), *bar(); + + return new(foo(),bar()) A(5); + } +} + +// PR7908 +namespace test5 { + struct T { T(); ~T(); }; + + struct A { + A(const A &x, const T &t = T()); + ~A(); + }; + + void foo(); + + // CHECK: define void @_ZN5test54testEv() + // CHECK: [[EXNSLOT:%.*]] = alloca i8* + // CHECK-NEXT: [[SELECTORSLOT:%.*]] = alloca i32 + // CHECK-NEXT: [[A:%.*]] = alloca [[A_T:%.*]], align 1 + // CHECK-NEXT: [[T:%.*]] = alloca [[T_T:%.*]], align 1 + // CHECK-NEXT: invoke void @_ZN5test53fooEv() + // CHECK: [[EXN:%.*]] = load i8** [[EXNSLOT]] + // CHECK-NEXT: [[ADJ:%.*]] = call i8* @__cxa_get_exception_ptr(i8* [[EXN]]) + // CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[ADJ]] to [[A_T]]* + // CHECK-NEXT: invoke void @_ZN5test51TC1Ev([[T_T]]* [[T]]) + // CHECK: invoke void @_ZN5test51AC1ERKS0_RKNS_1TE([[A_T]]* [[A]], [[A_T]]* [[SRC]], [[T_T]]* [[T]]) + // CHECK: invoke void @_ZN5test51TD1Ev([[T_T]]* [[T]]) + // CHECK: call i8* @__cxa_begin_catch(i8* [[EXN]]) nounwind + // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A_T]]* [[A]]) + // CHECK: call void @__cxa_end_catch() + void test() { + try { + foo(); + } catch (A a) { + } + } +} + +// PR9303: invalid assert on this +namespace test6 { + bool cond(); + void test() { + try { + lbl: + if (cond()) goto lbl; + } catch (...) { + } + } +} + +// PR9298 +namespace test7 { + struct A { A(); ~A(); }; + struct B { + // The throw() operator means that a bad allocation is signalled + // with a null return, which means that the initializer is + // evaluated conditionally. + static void *operator new(size_t size) throw(); + B(const A&, B*); + ~B(); + }; + + B *test() { + // CHECK: define [[B:%.*]]* @_ZN5test74testEv() + // CHECK: [[OUTER_NEW:%.*]] = alloca i1 + // CHECK-NEXT: alloca [[A:%.*]], + // CHECK-NEXT: alloca i8* + // CHECK-NEXT: alloca i32 + // CHECK-NEXT: [[OUTER_A:%.*]] = alloca i1 + // CHECK-NEXT: alloca i8* + // CHECK-NEXT: [[INNER_NEW:%.*]] = alloca i1 + // CHECK-NEXT: alloca [[A]] + // CHECK-NEXT: [[INNER_A:%.*]] = alloca i1 + + // Allocate the outer object. + // CHECK-NEXT: [[NEW:%.*]] = call i8* @_ZN5test71BnwEm( + // CHECK-NEXT: icmp eq i8* [[NEW]], null + + // These stores, emitted before the outermost conditional branch, + // deactivate the temporary cleanups. + // CHECK-NEXT: store i1 false, i1* [[OUTER_NEW]] + // CHECK-NEXT: store i1 false, i1* [[OUTER_A]] + // CHECK-NEXT: store i1 false, i1* [[INNER_NEW]] + // CHECK-NEXT: store i1 false, i1* [[INNER_A]] + // CHECK-NEXT: br i1 + + // We passed the first null check; activate that cleanup and continue. + // CHECK: store i1 true, i1* [[OUTER_NEW]] + // CHECK-NEXT: bitcast + + // Create the first A temporary and activate that cleanup. + // CHECK-NEXT: invoke void @_ZN5test71AC1Ev( + // CHECK: store i1 true, i1* [[OUTER_A]] + + // Allocate the inner object. + // CHECK-NEXT: [[NEW:%.*]] = call i8* @_ZN5test71BnwEm( + // CHECK-NEXT: icmp eq i8* [[NEW]], null + // CHECK-NEXT: br i1 + + // We passed the second null check; save that pointer, activate + // that cleanup, and continue. + // CHECK: store i8* [[NEW]] + // CHECK-NEXT: store i1 true, i1* [[INNER_NEW]] + // CHECK-NEXT: bitcast + + // Build the second A temporary and activate that cleanup. + // CHECK-NEXT: invoke void @_ZN5test71AC1Ev( + // CHECK: store i1 true, i1* [[INNER_A]] + + // Build the inner B object and deactivate the inner delete cleanup. + // CHECK-NEXT: invoke void @_ZN5test71BC1ERKNS_1AEPS0_( + // CHECK: store i1 false, i1* [[INNER_NEW]] + // CHECK: phi + + // Build the outer B object and deactivate the outer delete cleanup. + // CHECK-NEXT: invoke void @_ZN5test71BC1ERKNS_1AEPS0_( + // CHECK: store i1 false, i1* [[OUTER_NEW]] + // CHECK: phi + + // Destroy the inner A object. + // CHECK-NEXT: load i1* [[INNER_A]] + // CHECK-NEXT: br i1 + // CHECK: invoke void @_ZN5test71AD1Ev( + + // Destroy the outer A object. + // CHECK: load i1* [[OUTER_A]] + // CHECK-NEXT: br i1 + // CHECK: invoke void @_ZN5test71AD1Ev( + + return new B(A(), new B(A(), 0)); + } +} + +// Just don't crash. +namespace test8 { + struct A { + // Having both of these is required to trigger the assert we're + // trying to avoid. + A(const A&); + A&operator=(const A&); + + ~A(); + }; + + A makeA(); + void test() { + throw makeA(); + } + // CHECK: define void @_ZN5test84testEv +} + +// Make sure we generate the correct code for the delete[] call which +// happens if A::A() throws. (We were previously calling delete[] on +// a pointer to the first array element, not the pointer returned by new[].) +// PR10870 +namespace test9 { + struct A { + A(); + ~A(); + }; + A* test() { + return new A[10]; + } + // CHECK: define {{%.*}}* @_ZN5test94testEv + // CHECK: [[TEST9_NEW:%.*]] = call noalias i8* @_Znam + // CHECK: call void @_ZdaPv(i8* [[TEST9_NEW]]) +} diff --git a/clang/test/CodeGenCXX/explicit-instantiation.cpp b/clang/test/CodeGenCXX/explicit-instantiation.cpp new file mode 100644 index 0000000..8daf3c6 --- /dev/null +++ b/clang/test/CodeGenCXX/explicit-instantiation.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -emit-llvm -triple i686-pc-linux-gnu -o - %s | FileCheck %s + +// This check logically is attached to 'template int S<int>::i;' below. +// CHECK: @_ZN1SIiE1iE = weak_odr global i32 + +template<typename T, typename U, typename Result> +struct plus { + Result operator()(const T& t, const U& u) const; +}; + +template<typename T, typename U, typename Result> +Result plus<T, U, Result>::operator()(const T& t, const U& u) const { + return t + u; +} + +// CHECK: define weak_odr i32 @_ZNK4plusIillEclERKiRKl +template struct plus<int, long, long>; + +// Check that we emit definitions from explicit instantiations even when they +// occur prior to the definition itself. +template <typename T> struct S { + void f(); + static void g(); + static int i; + struct S2 { + void h(); + }; +}; + +// CHECK: define weak_odr void @_ZN1SIiE1fEv +template void S<int>::f(); + +// CHECK: define weak_odr void @_ZN1SIiE1gEv +template void S<int>::g(); + +// See the check line at the top of the file. +template int S<int>::i; + +// CHECK: define weak_odr void @_ZN1SIiE2S21hEv +template void S<int>::S2::h(); + +template <typename T> void S<T>::f() {} +template <typename T> void S<T>::g() {} +template <typename T> int S<T>::i; +template <typename T> void S<T>::S2::h() {} diff --git a/clang/test/CodeGenCXX/expr.cpp b/clang/test/CodeGenCXX/expr.cpp new file mode 100644 index 0000000..33e8e63 --- /dev/null +++ b/clang/test/CodeGenCXX/expr.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -emit-llvm -x c++ < %s + +void test0(int x) { + if (x != 0) return; +} + + +// PR5211 +void test1() { + char *xpto; + while ( true && xpto[0] ); +} + +// PR5514 +int a; +void test2() { ++a+=10; } + +// PR7892 +int test3(const char*); +int test3g = test3(__PRETTY_FUNCTION__); + + +// PR7889 +struct test4A { + int j : 2; +}; +int test4() { + test4A a; + (a.j = 2) = 3; +} + +// Incomplete type in conditional operator. +// Check operations on incomplete types. +struct s5; +struct s5 &f5_0(bool cond, struct s5 &a, struct s5 &b) { + return cond ? a : b; +} diff --git a/clang/test/CodeGenCXX/extern-c.cpp b/clang/test/CodeGenCXX/extern-c.cpp new file mode 100644 index 0000000..ca5cd73 --- /dev/null +++ b/clang/test/CodeGenCXX/extern-c.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -emit-llvm %s -o %t +namespace foo { + +// RUN: not grep "@a = global i32" %t +extern "C" int a; + +// RUN: not grep "@_ZN3foo1bE = global i32" %t +extern int b; + +// RUN: grep "@_ZN3foo1cE = global i32" %t | count 1 +int c = 5; + +// RUN: not grep "@_ZN3foo1dE" %t +extern "C" struct d; + +} diff --git a/clang/test/CodeGenCXX/field-access-debug-info.cpp b/clang/test/CodeGenCXX/field-access-debug-info.cpp new file mode 100644 index 0000000..fd899ed --- /dev/null +++ b/clang/test/CodeGenCXX/field-access-debug-info.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -g -S -masm-verbose -o - %s | FileCheck %s + +// CHECK: abbrev_begin: +// CHECK: DW_AT_accessibility +// CHECK-NEXT: DW_FORM_data1 + +class A { +public: + int p; +private: + int pr; +}; + +A a; diff --git a/clang/test/CodeGenCXX/for-range-temporaries.cpp b/clang/test/CodeGenCXX/for-range-temporaries.cpp new file mode 100644 index 0000000..a03bb0a --- /dev/null +++ b/clang/test/CodeGenCXX/for-range-temporaries.cpp @@ -0,0 +1,146 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR %s | opt -instnamer -S | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR %s | opt -instnamer -S | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE %s | opt -instnamer -S | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE %s | opt -instnamer -S | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -UDESUGAR -DTEMPLATE -DDEPENDENT %s | opt -instnamer -S | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - -DDESUGAR -DTEMPLATE -DDEPENDENT %s | opt -instnamer -S | FileCheck %s + +struct A { + A(); + A(const A &); + ~A(); +}; + +struct B { + B(); + B(const B &); + ~B(); +}; + +struct C { + C(const B &); + C(const C &); + ~C(); +}; + +struct E; +struct D { + D(const C &); + D(const D &); + ~D(); +}; +E begin(D); +E end(D); + +struct F; +struct G; +struct H; +struct E { + E(const E &); + ~E(); + F operator*(); + G operator++(); + H operator!=(const E &o); +}; + +struct I; +struct F { + F(const F &); + ~F(); + operator I(); +}; + +struct G { + G(const G &); + ~G(); + operator bool(); +}; + +struct H { + H(const H &); + ~H(); + operator bool(); +}; + +struct I { + I(const I &); + ~I(); +}; + +void body(const I &); + +#ifdef TEMPLATE +#ifdef DEPENDENT +template<typename D> +#else +template<typename> +#endif +#endif +void for_temps() { + A a; +#ifdef DESUGAR + { + auto && __range = D(B()); + for (auto __begin = begin(__range), __end = end(__range); + __begin != __end; ++__begin) { + I i = *__begin; + body(i); + } + } +#else + for (I i : D(B())) { + body(i); + } +#endif +} + +#ifdef TEMPLATE +template void for_temps<D>(); +#endif + +// CHECK: define {{.*}}for_temps +// CHECK: call void @_ZN1AC1Ev( +// CHECK: call void @_ZN1BC1Ev( +// CHECK: call void @_ZN1CC1ERK1B( +// CHECK: call void @_ZN1DC1ERK1C( +// CHECK: call void @_ZN1CD1Ev( +// CHECK: call void @_ZN1BD1Ev( +// CHECK: call void @_ZN1DC1ERKS_( +// CHECK: call void @_Z5begin1D( +// CHECK: call void @_ZN1DD1Ev( +// CHECK: call void @_ZN1DC1ERKS_( +// CHECK: call void @_Z3end1D( +// CHECK: call void @_ZN1DD1Ev( +// CHECK: br label %[[COND:.*]] + +// CHECK: [[COND]]: +// CHECK: call void @_ZN1EneERKS_( +// CHECK: %[[CMP:.*]] = call zeroext i1 @_ZN1HcvbEv( +// CHECK: call void @_ZN1HD1Ev( +// CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]] + +// CHECK: [[CLEANUP]]: +// CHECK: call void @_ZN1ED1Ev( +// CHECK: call void @_ZN1ED1Ev( +// In for-range: +// call void @_ZN1DD1Ev( +// CHECK: br label %[[END:.*]] + +// CHECK: [[BODY]]: +// CHECK: call void @_ZN1EdeEv( +// CHECK: call void @_ZN1Fcv1IEv( +// CHECK: call void @_ZN1FD1Ev( +// CHECK: call void @_Z4bodyRK1I( +// CHECK: call void @_ZN1ID1Ev( +// CHECK: br label %[[INC:.*]] + +// CHECK: [[INC]]: +// CHECK: call void @_ZN1EppEv( +// CHECK: call void @_ZN1GD1Ev( +// CHECK: br label %[[COND]] + +// CHECK: [[END]]: +// In desugared version: +// call void @_ZN1DD1Ev( +// CHECK: call void @_ZN1AD1Ev( +// CHECK: ret void diff --git a/clang/test/CodeGenCXX/for-range.cpp b/clang/test/CodeGenCXX/for-range.cpp new file mode 100644 index 0000000..0f35dda7 --- /dev/null +++ b/clang/test/CodeGenCXX/for-range.cpp @@ -0,0 +1,128 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -std=c++11 -emit-llvm -o - %s | opt -instnamer -S | FileCheck %s + +struct A { + A(); + A(const A&); + ~A(); +}; + +struct B { + B(); + B(const B&); + ~B(); +}; + +struct C { + C(); + C(const C&); + ~C(); +}; + +struct D { + D(); + D(const D&); + ~D(); + + B *begin(); + B *end(); +}; + +namespace std { + B *begin(C&); + B *end(C&); +} + +extern B array[5]; + +// CHECK: define void @_Z9for_arrayv( +void for_array() { + // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]]) + A a; + for (B b : array) { + // CHECK-NOT: 5begin + // CHECK-NOT: 3end + // CHECK: getelementptr {{.*}}, i32 0 + // CHECK: getelementptr {{.*}}, i64 5 + // CHECK: br label %[[COND:.*]] + + // CHECK: [[COND]]: + // CHECK: %[[CMP:.*]] = icmp ne + // CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[END:.*]] + + // CHECK: [[BODY]]: + // CHECK: call void @_ZN1BC1ERKS_( + // CHECK: call void @_ZN1BD1Ev( + // CHECK: br label %[[INC:.*]] + + // CHECK: [[INC]]: + // CHECK: getelementptr {{.*}} i32 1 + // CHECK: br label %[[COND]] + } + // CHECK: [[END]]: + // CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]]) + // CHECK: ret void +} + +// CHECK: define void @_Z9for_rangev( +void for_range() { + // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]]) + A a; + for (B b : C()) { + // CHECK: call void @_ZN1CC1Ev( + // CHECK: = call %struct.B* @_ZSt5beginR1C( + // CHECK: = call %struct.B* @_ZSt3endR1C( + // CHECK: br label %[[COND:.*]] + + // CHECK: [[COND]]: + // CHECK: %[[CMP:.*]] = icmp ne + // CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]] + + // CHECK: [[CLEANUP]]: + // CHECK: call void @_ZN1CD1Ev( + // CHECK: br label %[[END:.*]] + + // CHECK: [[BODY]]: + // CHECK: call void @_ZN1BC1ERKS_( + // CHECK: call void @_ZN1BD1Ev( + // CHECK: br label %[[INC:.*]] + + // CHECK: [[INC]]: + // CHECK: getelementptr {{.*}} i32 1 + // CHECK: br label %[[COND]] + } + // CHECK: [[END]]: + // CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]]) + // CHECK: ret void +} + +// CHECK: define void @_Z16for_member_rangev( +void for_member_range() { + // CHECK: call void @_ZN1AC1Ev(%struct.A* [[A:.*]]) + A a; + for (B b : D()) { + // CHECK: call void @_ZN1DC1Ev( + // CHECK: = call %struct.B* @_ZN1D5beginEv( + // CHECK: = call %struct.B* @_ZN1D3endEv( + // CHECK: br label %[[COND:.*]] + + // CHECK: [[COND]]: + // CHECK: %[[CMP:.*]] = icmp ne + // CHECK: br i1 %[[CMP]], label %[[BODY:.*]], label %[[CLEANUP:.*]] + + // CHECK: [[CLEANUP]]: + // CHECK: call void @_ZN1DD1Ev( + // CHECK: br label %[[END:.*]] + + // CHECK: [[BODY]]: + // CHECK: call void @_ZN1BC1ERKS_( + // CHECK: call void @_ZN1BD1Ev( + // CHECK: br label %[[INC:.*]] + + // CHECK: [[INC]]: + // CHECK: getelementptr {{.*}} i32 1 + // CHECK: br label %[[COND]] + } + // CHECK: [[END]]: + // CHECK: call void @_ZN1AD1Ev(%struct.A* [[A]]) + // CHECK: ret void +} diff --git a/clang/test/CodeGenCXX/forward-enum.cpp b/clang/test/CodeGenCXX/forward-enum.cpp new file mode 100644 index 0000000..c1169e0 --- /dev/null +++ b/clang/test/CodeGenCXX/forward-enum.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin11.0.0 -emit-llvm -o - %s | FileCheck %s + +enum MyEnum : char; +void bar(MyEnum value) { } + +// CHECK: define void @_Z3foo6MyEnum +void foo(MyEnum value) +{ + // CHECK: call void @_Z3bar6MyEnum(i8 signext + bar(value); +} diff --git a/clang/test/CodeGenCXX/fp16-mangle.cpp b/clang/test/CodeGenCXX/fp16-mangle.cpp new file mode 100644 index 0000000..4a056d6 --- /dev/null +++ b/clang/test/CodeGenCXX/fp16-mangle.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi %s | FileCheck %s + +// CHECK: @_ZN1SIDhDhE1iE = global i32 3 +template <typename T, typename U> struct S { static int i; }; +template <> int S<__fp16, __fp16>::i = 3; + +// CHECK: define void @_Z1fPDh(i16* %x) +void f (__fp16 *x) { } + +// CHECK: define void @_Z1gPDhS_(i16* %x, i16* %y) +void g (__fp16 *x, __fp16 *y) { } + diff --git a/clang/test/CodeGenCXX/fp16-overload.cpp b/clang/test/CodeGenCXX/fp16-overload.cpp new file mode 100644 index 0000000..7562210 --- /dev/null +++ b/clang/test/CodeGenCXX/fp16-overload.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -emit-llvm -o - -triple arm-none-linux-gnueabi %s | FileCheck %s + +extern int foo(float x); +extern int foo(double x); + +__fp16 a; + +// CHECK: call i32 @_Z3foof +// CHECK-NOT: call i32 @_Z3food +int bar (void) { return foo(a); } diff --git a/clang/test/CodeGenCXX/friend-redecl.cpp b/clang/test/CodeGenCXX/friend-redecl.cpp new file mode 100644 index 0000000..18292cd --- /dev/null +++ b/clang/test/CodeGenCXX/friend-redecl.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s +// PR8864 + +struct Foo { + friend bool TryFoo(Foo *f2) { return TryFoo(0, f2); } + +// CHECK: define{{.*}}Z6TryFooP3Foo +// CHECK-NOT: ret +// CHECK: call{{.*}}Z6TryFooiP3Foo +// CHECK: ret + + friend bool TryFoo(int, Foo *f3); +}; +bool TryFoo(Foo *f5); +int main(void) { + Foo f; + TryFoo(&f); +} diff --git a/clang/test/CodeGenCXX/function-template-explicit-specialization.cpp b/clang/test/CodeGenCXX/function-template-explicit-specialization.cpp new file mode 100644 index 0000000..21f0127 --- /dev/null +++ b/clang/test/CodeGenCXX/function-template-explicit-specialization.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +template<typename T> void a(T); +template<> void a(int) {} + +// CHECK: define void @_Z1aIiEvT_ + +namespace X { +template<typename T> void b(T); +template<> void b(int) {} +} + +// CHECK: define void @_ZN1X1bIiEEvT_ diff --git a/clang/test/CodeGenCXX/function-template-specialization.cpp b/clang/test/CodeGenCXX/function-template-specialization.cpp new file mode 100644 index 0000000..4a79fb1 --- /dev/null +++ b/clang/test/CodeGenCXX/function-template-specialization.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s +template<typename T, typename U> +T* next(T* ptr, const U& diff); + +template<typename T, typename U> +T* next(T* ptr, const U& diff) { + return ptr + diff; +} + +void test(int *iptr, float *fptr, int diff) { + // CHECK: _Z4nextIiiEPT_S1_RKT0_ + iptr = next(iptr, diff); + + // CHECK: _Z4nextIfiEPT_S1_RKT0_ + fptr = next(fptr, diff); +} + +template<typename T, typename U> +T* next(T* ptr, const U& diff); + +void test2(int *iptr, double *dptr, int diff) { + iptr = next(iptr, diff); + + // CHECK: _Z4nextIdiEPT_S1_RKT0_ + dptr = next(dptr, diff); +} diff --git a/clang/test/CodeGenCXX/global-array-destruction.cpp b/clang/test/CodeGenCXX/global-array-destruction.cpp new file mode 100644 index 0000000..5b5dfac --- /dev/null +++ b/clang/test/CodeGenCXX/global-array-destruction.cpp @@ -0,0 +1,34 @@ +// REQUIRES: x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s + +extern "C" int printf(...); + +int count; + +struct S { + S() : iS(++count) { printf("S::S(%d)\n", iS); } + ~S() { printf("S::~S(%d)\n", iS); } + int iS; +}; + + +S arr[2][1]; +S s1; +S arr1[3]; +static S sarr[4]; + +int main () {} +S arr2[2]; +static S sarr1[4]; +S s2; +S arr3[3]; + +// CHECK-LP64: callq ___cxa_atexit +// CHECK-LP64: callq ___cxa_atexit +// CHECK-LP64: callq ___cxa_atexit +// CHECK-LP64: callq ___cxa_atexit +// CHECK-LP64: callq ___cxa_atexit +// CHECK-LP64: callq ___cxa_atexit +// CHECK-LP64: callq ___cxa_atexit +// CHECK-LP64: callq ___cxa_atexit diff --git a/clang/test/CodeGenCXX/global-dtor-no-atexit.cpp b/clang/test/CodeGenCXX/global-dtor-no-atexit.cpp new file mode 100644 index 0000000..def97b2 --- /dev/null +++ b/clang/test/CodeGenCXX/global-dtor-no-atexit.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -triple x86_64 %s -fno-use-cxa-atexit -emit-llvm -o - | FileCheck %s + +// PR7097 +// RUN: %clang_cc1 -triple x86_64 %s -fno-use-cxa-atexit -mconstructor-aliases -emit-llvm -o - | FileCheck %s + +// CHECK: call void @_ZN1AC1Ev([[A:%.*]]* @a) +// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_a) +// CHECK: define internal void @__dtor_a() nounwind +// CHECK: call void @_ZN1AD1Ev([[A]]* @a) + +// CHECK: call void @_ZN1AC1Ev([[A]]* @b) +// CHECK-NEXT: call i32 @atexit(void ()* @__dtor_b) +// CHECK: define internal void @__dtor_b() nounwind +// CHECK: call void @_ZN1AD1Ev([[A]]* @b) + +class A { +public: + A(); + ~A(); +}; + +A a, b; + +// PR9593 +// CHECK: define void @_Z4funcv() +// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ4funcvE2a1) +// CHECK: call void @_ZN1AC1Ev([[A]]* @_ZZ4funcvE2a1) +// CHECK-NEXT: call i32 @atexit(void ()* @__dtor__ZZ4funcvE2a1) +// CHECK-NEXT: call void @__cxa_guard_release(i64* @_ZGVZ4funcvE2a1) + +// CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ4funcvE2a2) +// CHECK: call void @_ZN1AC1Ev([[A]]* @_ZZ4funcvE2a2) +// CHECK-NEXT: call i32 @atexit(void ()* @__dtor__ZZ4funcvE2a2) +// CHECK-NEXT: call void @__cxa_guard_release(i64* @_ZGVZ4funcvE2a2) + +// CHECK: define internal void @__dtor__ZZ4funcvE2a1() nounwind +// CHECK: call void @_ZN1AD1Ev([[A]]* @_ZZ4funcvE2a1) + +// CHECK: define internal void @__dtor__ZZ4funcvE2a2() nounwind +// CHECK: call void @_ZN1AD1Ev([[A]]* @_ZZ4funcvE2a2) + +void func() { + static A a1, a2; +} diff --git a/clang/test/CodeGenCXX/global-init-darwin.cpp b/clang/test/CodeGenCXX/global-init-darwin.cpp new file mode 100644 index 0000000..20c13c6 --- /dev/null +++ b/clang/test/CodeGenCXX/global-init-darwin.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm %s -o - |FileCheck %s + +struct A { + A(); + ~A(); +}; + +A a; +A as[2]; + +struct B { + B(); + ~B(); + int f(); +}; + +int i = B().f(); + +// CHECK: "__TEXT,__StaticInit,regular,pure_instructions" { +// CHECK: "__TEXT,__StaticInit,regular,pure_instructions" { +// CHECK: "__TEXT,__StaticInit,regular,pure_instructions" { +// CHECK: "__TEXT,__StaticInit,regular,pure_instructions" { +// CHECK: "__TEXT,__StaticInit,regular,pure_instructions" { diff --git a/clang/test/CodeGenCXX/global-init.cpp b/clang/test/CodeGenCXX/global-init.cpp new file mode 100644 index 0000000..8e6ef77 --- /dev/null +++ b/clang/test/CodeGenCXX/global-init.cpp @@ -0,0 +1,122 @@ +// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -fexceptions %s -o - |FileCheck %s +// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm %s -o - |FileCheck -check-prefix NOEXC %s + +struct A { + A(); + ~A(); +}; + +struct B { B(); ~B(); }; + +struct C { void *field; }; + +struct D { ~D(); }; + +// CHECK: @__dso_handle = external unnamed_addr global i8 +// CHECK: @c = global %struct.C zeroinitializer, align 8 + +// It's okay if we ever implement the IR-generation optimization to remove this. +// CHECK: @_ZN5test3L3varE = internal constant i8* getelementptr inbounds ([7 x i8]* + +// PR6205: The casts should not require global initializers +// CHECK: @_ZN6PR59741cE = external global %"struct.PR5974::C" +// CHECK: @_ZN6PR59741aE = global %"struct.PR5974::A"* getelementptr inbounds (%"struct.PR5974::C"* @_ZN6PR59741cE, i32 0, i32 0) +// CHECK: @_ZN6PR59741bE = global %"struct.PR5974::B"* bitcast (i8* getelementptr (i8* bitcast (%"struct.PR5974::C"* @_ZN6PR59741cE to i8*), i64 4) to %"struct.PR5974::B"*), align 8 + +// CHECK: call void @_ZN1AC1Ev(%struct.A* @a) +// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @a, i32 0, i32 0), i8* @__dso_handle) +A a; + +// CHECK: call void @_ZN1BC1Ev(%struct.B* @b) +// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.B*)* @_ZN1BD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.B* @b, i32 0, i32 0), i8* @__dso_handle) +B b; + +// PR6205: this should not require a global initializer +// CHECK-NOT: call void @_ZN1CC1Ev(%struct.C* @c) +C c; + +// CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.D*)* @_ZN1DD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.D* @d, i32 0, i32 0), i8* @__dso_handle) +D d; + +// <rdar://problem/7458115> +namespace test1 { + int f(); + const int x = f(); // This has side-effects and gets emitted immediately. + const int y = x - 1; // This gets deferred. + const int z = ~y; // This also gets deferred, but gets "undeferred" before y. + int test() { return z; } +// CHECK: define i32 @_ZN5test14testEv() + + // All of these initializers end up delayed, so we check them later. +} + +// <rdar://problem/8246444> +namespace test2 { + struct allocator { allocator(); ~allocator(); }; + struct A { A(const allocator &a = allocator()); ~A(); }; + + A a; +// CHECK: call void @_ZN5test29allocatorC1Ev( +// CHECK: invoke void @_ZN5test21AC1ERKNS_9allocatorE( +// CHECK: call void @_ZN5test29allocatorD1Ev( +// CHECK: call i32 @__cxa_atexit({{.*}} @_ZN5test21AD1Ev {{.*}} @_ZN5test21aE +} + +namespace test3 { + // Tested at the beginning of the file. + const char * const var = "string"; + extern const char * const var; + + const char *test() { return var; } +} + +namespace test6 { + struct A { + A(); + }; + extern int foo(); + + // This needs an initialization function and guard variables. + // CHECK: load i8* bitcast (i64* @_ZGVN5test61xE + // CHECK: [[CALL:%.*]] = call i32 @_ZN5test63fooEv + // CHECK-NEXT: store i32 [[CALL]], i32* @_ZN5test61xE + // CHECK-NEXT: store i64 1, i64* @_ZGVN5test61xE + __attribute__((weak)) int x = foo(); +} + +namespace PR5974 { + struct A { int a; }; + struct B { int b; }; + struct C : A, B { int c; }; + + extern C c; + + // These should not require global initializers. + A* a = &c; + B* b = &c; +} +// CHECK: define internal void [[TEST1_Z_INIT:@.*]]() +// CHECK: load i32* @_ZN5test1L1yE +// CHECK-NEXT: xor +// CHECK-NEXT: store i32 {{.*}}, i32* @_ZN5test1L1zE +// CHECK: define internal void [[TEST1_Y_INIT:@.*]]() +// CHECK: load i32* @_ZN5test1L1xE +// CHECK-NEXT: sub +// CHECK-NEXT: store i32 {{.*}}, i32* @_ZN5test1L1yE + +// PR9570: the indirect field shouldn't crash IR gen. +namespace test5 { + static union { + unsigned bar[4096] __attribute__((aligned(128))); + }; +} + + +// At the end of the file, we check that y is initialized before z. + +// CHECK: define internal void @_GLOBAL__I_a() section "__TEXT,__StaticInit,regular,pure_instructions" { +// CHECK: call void [[TEST1_Y_INIT]] +// CHECK: call void [[TEST1_Z_INIT]] + +// rdar://problem/8090834: this should be nounwind +// CHECK-NOEXC: define internal void @_GLOBAL__I_a() nounwind section "__TEXT,__StaticInit,regular,pure_instructions" { diff --git a/clang/test/CodeGenCXX/global-llvm-constant.cpp b/clang/test/CodeGenCXX/global-llvm-constant.cpp new file mode 100644 index 0000000..2bd43b9 --- /dev/null +++ b/clang/test/CodeGenCXX/global-llvm-constant.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +struct A { + A() { x = 10; } + int x; +}; + +const A x; + +// CHECK: @_ZL1x = internal global + +struct X { + int (*fp)(int, int); +}; + +int add(int x, int y) { return x + y; } + +// CHECK: @x2 = constant +extern const X x2; +const X x2 = { &add }; + +struct X1 { + mutable int i; +}; + +struct X2 { + X1 array[3]; +}; + +// CHECK: @x2b = global +extern const X2 x2b; +const X2 x2b = { { { 1 }, { 2 }, { 3 } } }; diff --git a/clang/test/CodeGenCXX/goto.cpp b/clang/test/CodeGenCXX/goto.cpp new file mode 100644 index 0000000..77b6166 --- /dev/null +++ b/clang/test/CodeGenCXX/goto.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fcxx-exceptions -fexceptions -emit-llvm -o - | FileCheck %s + +// Reduced from a crash on boost::interprocess's node_allocator_test.cpp. +namespace test0 { + struct A { A(); ~A(); }; + struct V { V(const A &a = A()); ~V(); }; + + // CHECK: define linkonce_odr i32 @_ZN5test04testILi0EEEii + template<int X> int test(int x) { + // CHECK: [[RET:%.*]] = alloca i32 + // CHECK-NEXT: [[X:%.*]] = alloca i32 + // CHECK-NEXT: [[Y:%.*]] = alloca [[A:%.*]], + // CHECK-NEXT: [[Z:%.*]] = alloca [[A]] + // CHECK-NEXT: [[EXN:%.*]] = alloca i8* + // CHECK-NEXT: [[SEL:%.*]] = alloca i32 + // CHECK-NEXT: [[V:%.*]] = alloca [[V:%.*]]*, + // CHECK-NEXT: [[TMP:%.*]] = alloca [[A]] + // CHECK-NEXT: [[CLEANUPACTIVE:%.*]] = alloca i1 + // CHECK: call void @_ZN5test01AC1Ev([[A]]* [[Y]]) + // CHECK-NEXT: invoke void @_ZN5test01AC1Ev([[A]]* [[Z]]) + // CHECK: [[NEW:%.*]] = invoke noalias i8* @_Znwm(i64 1) + // CHECK: store i1 true, i1* [[CLEANUPACTIVE]] + // CHECK: [[NEWCAST:%.*]] = bitcast i8* [[NEW]] to [[V]]* + // CHECK-NEXT: invoke void @_ZN5test01AC1Ev([[A]]* [[TMP]]) + // CHECK: invoke void @_ZN5test01VC1ERKNS_1AE([[V]]* [[NEWCAST]], [[A]]* [[TMP]]) + // CHECK: store i1 false, i1* [[CLEANUPACTIVE]] + // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[TMP]]) + A y; + try { + A z; + V *v = new V(); + + if (x) return 1; + } catch (int ex) { + return 1; + } + return 0; + } + + int test() { + return test<0>(5); + } +} diff --git a/clang/test/CodeGenCXX/implicit-copy-assign-operator.cpp b/clang/test/CodeGenCXX/implicit-copy-assign-operator.cpp new file mode 100644 index 0000000..0ec89fc --- /dev/null +++ b/clang/test/CodeGenCXX/implicit-copy-assign-operator.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10.0.0 -o - %s | FileCheck %s +struct A { + A &operator=(const A&); + A &operator=(A&); +}; + +struct B { + B &operator=(B&); +}; + +struct C { + virtual C& operator=(const C&); +}; + +struct POD { + int array[3][4]; +}; + +struct CopyByValue { + CopyByValue(const CopyByValue&); + CopyByValue &operator=(CopyByValue); +}; + +struct D : A, B, virtual C { + int scalar; + int scalar_array[2][3]; + B class_member; + C class_member_array[2][3]; + POD pod_array[2][3]; + + union { + int x; + float f[3]; + }; + + CopyByValue by_value; +}; + +void test_D(D d1, D d2) { + d1 = d2; +} + +// CHECK: define linkonce_odr %struct.D* @_ZN1DaSERS_ +// CHECK: {{call.*_ZN1AaSERS_}} +// CHECK: {{call.*_ZN1BaSERS_}} +// CHECK: {{call.*_ZN1CaSERKS_}} +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}} +// CHECK: {{call.*_ZN1BaSERS_}} +// CHECK: br +// CHECK: {{call.*_ZN1CaSERKS_}} +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 288}} +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}} +// CHECK: call void @_ZN11CopyByValueC1ERKS_ +// CHECK: {{call.*_ZN11CopyByValueaSES_}} +// CHECK: ret + diff --git a/clang/test/CodeGenCXX/implicit-copy-constructor.cpp b/clang/test/CodeGenCXX/implicit-copy-constructor.cpp new file mode 100644 index 0000000..8bc84a5 --- /dev/null +++ b/clang/test/CodeGenCXX/implicit-copy-constructor.cpp @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +struct A { + A(); + A(const A&); + A(A&); + ~A(); +}; + +struct B { + B(); + B(B&); +}; + +struct C { + C() {} + C(C& other, A a = A()); + int i, j; +}; + +struct POD { + int array[3][4]; +}; + +struct D : A, B, virtual C { + D(); + int scalar; + int scalar_array[2][3]; + B class_member; + C class_member_array[2][3]; + POD pod_array[2][3]; + + union { + int x; + float f[3]; + }; +}; + +void f(D d) { + D d2(d); +} + +// CHECK: define linkonce_odr void @_ZN1DC1ERS_(%struct.D* %this, %struct.D*) unnamed_addr +// CHECK: call void @_ZN1AC1Ev +// CHECK: call void @_ZN1CC2ERS_1A +// CHECK: call void @_ZN1AD1Ev +// CHECK: call void @_ZN1AC2ERS_ +// CHECK: call void @_ZN1BC2ERS_ +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 24}} +// CHECK: call void @_ZN1BC1ERS_ +// CHECK: br +// CHECK: {{icmp ult.*, 2}} +// CHECK: {{icmp ult.*, 3}} +// CHECK: call void @_ZN1AC1Ev +// CHECK: call void @_ZN1CC1ERS_1A +// CHECK: call void @_ZN1AD1Ev +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 288}} +// CHECK: {{call void @llvm.memcpy.p0i8.p0i8.i64.*i64 12}} +// CHECK: ret void + + +template<class T> struct X0 { void f0(T * ) { } }; +template <class > struct X1 { X1( X1& , int = 0 ) { } }; +struct X2 { X1<int> result; }; +void test_X2() +{ + typedef X2 impl; + typedef X0<impl> pimpl; + impl* i; + pimpl pdata; + pdata.f0( new impl(*i)); +} + +// rdar://problem/9598341 +namespace test3 { + struct A { A(const A&); A&operator=(const A&); }; + struct B { A a; unsigned : 0; }; + void test(const B &x) { + B y = x; + y = x; + } +} diff --git a/clang/test/CodeGenCXX/implicit-instantiation-1.cpp b/clang/test/CodeGenCXX/implicit-instantiation-1.cpp new file mode 100644 index 0000000..0c826e4 --- /dev/null +++ b/clang/test/CodeGenCXX/implicit-instantiation-1.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -emit-llvm %s -o %t + +template<typename T> +struct X { + void f(T) { } + void f(char) { } + + void g(T) { } + + void h(T) { } +}; + +void foo(X<int> &xi, X<float> *xfp, int i, float f) { + // RUN: grep "linkonce_odr.*_ZN1XIiE1fEi" %t | count 1 + xi.f(i); + + // RUN: grep "linkonce_odr.*_ZN1XIiE1gEi" %t | count 1 + xi.g(f); + + // RUN: grep "linkonce_odr.*_ZN1XIfE1fEf" %t | count 1 + xfp->f(f); + + // RUN: grep "linkonce_odr.*_ZN1XIfE1hEf" %t | count 0 + +} + + + diff --git a/clang/test/CodeGenCXX/incomplete-member-function-pointer.cpp b/clang/test/CodeGenCXX/incomplete-member-function-pointer.cpp new file mode 100644 index 0000000..b97e44c --- /dev/null +++ b/clang/test/CodeGenCXX/incomplete-member-function-pointer.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 %s -emit-llvm-only +// PR7040 +struct fake_tuple; +struct connection { + void bar(fake_tuple); +}; +void (connection::*a)(fake_tuple) = &connection::bar; +void f() { + void (connection::*b)(fake_tuple) = &connection::bar; +} diff --git a/clang/test/CodeGenCXX/incomplete-types.cpp b/clang/test/CodeGenCXX/incomplete-types.cpp new file mode 100644 index 0000000..1d4f430 --- /dev/null +++ b/clang/test/CodeGenCXX/incomplete-types.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 %s -emit-llvm-only -verify +// PR5489 + +template<typename E> +struct Bar { + int x_; +}; + +static struct Bar<int> bar[1] = { + { 0 } +}; + + + +namespace incomplete_type_refs { + struct A; + extern A g[]; + void foo(A*); + void f(void) { + foo(g); // Reference to array with unknown element type. + } + + struct A { // define the element type. + int a,b,c; + }; + + A *f2() { + return &g[1]; + } + +} + +namespace PR10395 { + struct T; + extern T x[]; + T* f() { return x; } +} + +namespace PR10384 { + struct X; + extern X x[1]; + X* f() { return x; } +} diff --git a/clang/test/CodeGenCXX/inheriting-constructor.cpp b/clang/test/CodeGenCXX/inheriting-constructor.cpp new file mode 100644 index 0000000..a998402 --- /dev/null +++ b/clang/test/CodeGenCXX/inheriting-constructor.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +// XFAIL: * + +// PR12219 +struct A { A(int); virtual ~A(); }; +struct B : A { using A::A; ~B(); }; +B::~B() {} +// CHECK: define void @_ZN1BD0Ev +// CHECK: define void @_ZN1BD1Ev +// CHECK: define void @_ZN1BD2Ev diff --git a/clang/test/CodeGenCXX/init-invariant.cpp b/clang/test/CodeGenCXX/init-invariant.cpp new file mode 100644 index 0000000..9eb1989 --- /dev/null +++ b/clang/test/CodeGenCXX/init-invariant.cpp @@ -0,0 +1,60 @@ +// RUN: %clang_cc1 -triple i686-linux-gnu -emit-llvm %s -O0 -o - | FileCheck %s --check-prefix=CHECK-O0 +// RUN: %clang_cc1 -triple i686-linux-gnu -emit-llvm %s -O1 -o - | FileCheck %s + +// Check that we add an llvm.invariant.start to mark when a global becomes +// read-only. If globalopt can fold the initializer, it will then mark the +// variable as constant. + +// Do not produce markers at -O0. +// CHECK-O0-NOT: llvm.invariant.start + +struct A { + A(); + int n; +}; + +// CHECK: @a = global {{.*}} zeroinitializer +extern const A a = A(); + +struct B { + B(); + mutable int n; +}; + +// CHECK: @b = global {{.*}} zeroinitializer +extern const B b = B(); + +struct C { + C(); + ~C(); + int n; +}; + +// CHECK: @c = global {{.*}} zeroinitializer +extern const C c = C(); + +int f(); +// CHECK: @d = global i32 0 +extern const int d = f(); + +void e() { + static const A a = A(); +} + +// CHECK: call void @_ZN1AC1Ev({{.*}}* @a) +// CHECK: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @a to i8*)) + +// CHECK: call void @_ZN1BC1Ev({{.*}}* @b) +// CHECK-NOT: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @b to i8*)) + +// CHECK: call void @_ZN1CC1Ev({{.*}}* @c) +// CHECK-NOT: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @c to i8*)) + +// CHECK: call i32 @_Z1fv( +// CHECK: store {{.*}}, i32* @d +// CHECK: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @d to i8*)) + +// CHECK: define void @_Z1ev( +// CHECK: call void @_ZN1AC1Ev(%struct.A* @_ZZ1evE1a) +// CHECK: call {{.*}}@llvm.invariant.start(i64 4, i8* bitcast ({{.*}} @_ZZ1evE1a to i8*)) +// CHECK-NOT: llvm.invariant.end diff --git a/clang/test/CodeGenCXX/inline-functions.cpp b/clang/test/CodeGenCXX/inline-functions.cpp new file mode 100644 index 0000000..69dfe0d --- /dev/null +++ b/clang/test/CodeGenCXX/inline-functions.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// CHECK: ; ModuleID + +struct A { + inline void f(); +}; + +// CHECK-NOT: define void @_ZN1A1fEv +void A::f() { } + +template<typename> struct B { }; + +template<> struct B<char> { + inline void f(); +}; + +// CHECK-NOT: _ZN1BIcE1fEv +void B<char>::f() { } + +// We need a final CHECK line here. + +// CHECK: define void @_Z1fv +void f() { } + +// <rdar://problem/8740363> +inline void f1(int); + +// CHECK: define linkonce_odr void @_Z2f1i +void f1(int) { } + +void test_f1() { f1(17); } + +// PR8789 +namespace test1 { + template <typename T> class ClassTemplate { + private: + friend void T::func(); + void g() {} + }; + + // CHECK: define linkonce_odr void @_ZN5test11C4funcEv( + + class C { + public: + void func() { + ClassTemplate<C> ct; + ct.g(); + } + }; + + void f() { + C c; + c.func(); + } +} diff --git a/clang/test/CodeGenCXX/instantiate-blocks.cpp b/clang/test/CodeGenCXX/instantiate-blocks.cpp new file mode 100644 index 0000000..e206582 --- /dev/null +++ b/clang/test/CodeGenCXX/instantiate-blocks.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -fblocks -emit-llvm -o - %s +// rdar : // 6182276 + +template <typename T> T foo(T t) +{ + void (^block)(int); + return 1; +} + +int test1(void) +{ + int i = 1; + int b = 2; + i = foo(b); + return 0; +} + +template <typename T, typename T1> void foo(T t, T1 r) +{ + T block_arg; + __block T1 byref_block_arg; + + T1 (^block)(char, T, T1, double) = + ^ T1 (char ch, T arg, T1 arg2, double d1) { byref_block_arg = arg2; + return byref_block_arg + block_arg + arg; }; + + void (^block2)() = ^{}; +} + +void test2(void) +{ + foo(100, 'a'); +} + +namespace rdar6182276 { +extern "C" { +int printf(const char *, ...); +} + +template <typename T> T foo(T t) +{ + void (^testing)(int) = ^(int bar) { printf("bar is %d\n", bar); }; + printf("bar is\n"); + return 1; +} + +template <typename T> void gorf(T t) +{ + foo(t); +} + + +void test(void) +{ + gorf(2); +} +} + + diff --git a/clang/test/CodeGenCXX/instantiate-init-list.cpp b/clang/test/CodeGenCXX/instantiate-init-list.cpp new file mode 100644 index 0000000..49c6f51 --- /dev/null +++ b/clang/test/CodeGenCXX/instantiate-init-list.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -emit-llvm-only -verify + +struct F { + void (*x)(); +}; +void G(); +template<class T> class A { +public: A(); +}; +template<class T> A<T>::A() { + static F f = { G }; +} +A<int> a; diff --git a/clang/test/CodeGenCXX/instantiate-temporaries.cpp b/clang/test/CodeGenCXX/instantiate-temporaries.cpp new file mode 100644 index 0000000..29cfc07 --- /dev/null +++ b/clang/test/CodeGenCXX/instantiate-temporaries.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s | FileCheck %s + +struct X { + X(); + ~X(); +}; + +struct Y { + X get(); +}; + +struct X2 { + X x; +}; + +template<typename T> +void call() { + Y().get(); +} + +// CHECK: define weak_odr void @_Z4callIiEvv +// CHECK: call void @_ZN1Y3getEv +// CHECK-NEXT: call void @_ZN1XD1Ev +// CHECK-NEXT: ret void +template void call<int>(); + +template<typename T> +void compound_literal() { + (X2){}; +} + +// CHECK: define weak_odr void @_Z16compound_literalIiEvv +// CHECK: call void @_ZN1XC1Ev +// CHECK-NEXT: call void @_ZN2X2D1Ev +// CHECK-NEXT: ret void +template void compound_literal<int>(); + diff --git a/clang/test/CodeGenCXX/instrument-functions.cpp b/clang/test/CodeGenCXX/instrument-functions.cpp new file mode 100644 index 0000000..253e096 --- /dev/null +++ b/clang/test/CodeGenCXX/instrument-functions.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -S -emit-llvm -o - %s -finstrument-functions | FileCheck %s + +// CHECK: @_Z5test1i +int test1(int x) { +// CHECK: __cyg_profile_func_enter +// CHECK: __cyg_profile_func_exit +// CHECK: ret + return x; +} + +// CHECK: @_Z5test2i +int test2(int) __attribute__((no_instrument_function)); +int test2(int x) { +// CHECK-NOT: __cyg_profile_func_enter +// CHECK-NOT: __cyg_profile_func_exit +// CHECK: ret + return x; +} + +// This test case previously crashed code generation. It exists solely +// to test -finstrument-function does not crash codegen for this trivial +// case. +namespace rdar9445102 { + class Rdar9445102 { + public: + Rdar9445102(); + }; +} +static rdar9445102::Rdar9445102 s_rdar9445102Initializer; + diff --git a/clang/test/CodeGenCXX/internal-linkage.cpp b/clang/test/CodeGenCXX/internal-linkage.cpp new file mode 100644 index 0000000..56cb810 --- /dev/null +++ b/clang/test/CodeGenCXX/internal-linkage.cpp @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +struct Global { Global(); }; +template<typename T> struct X { X() {} }; + + +namespace { + struct Anon { Anon() {} }; + + // CHECK: @_ZN12_GLOBAL__N_15anon0E = internal global + Global anon0; +} + +// CHECK: @anon1 = internal global +Anon anon1; + +// CHECK: @anon2 = internal global +X<Anon> anon2; + +// rdar: // 8071804 +char const * const xyzzy = "Hello, world!"; +extern char const * const xyzzy; + +char const * const *test1() +{ + // CHECK: @_ZL5xyzzy = internal constant + return &xyzzy; +} + +static char const * const static_xyzzy = "Hello, world!"; +extern char const * const static_xyzzy; + +char const * const *test2() +{ + // CHECK: @_ZL12static_xyzzy = internal constant + return &static_xyzzy; +} + +static char const * static_nonconst_xyzzy = "Hello, world!"; +extern char const * static_nonconst_xyzzy; + +char const * *test3() +{ + // CHECK: @_ZL21static_nonconst_xyzzy = internal global + return &static_nonconst_xyzzy; +} + + +char const * extern_nonconst_xyzzy = "Hello, world!"; +extern char const * extern_nonconst_xyzzy; + +char const * *test4() +{ + // CHECK: @extern_nonconst_xyzzy = global + return &extern_nonconst_xyzzy; +} + +// PR10120 +template <typename T> class klass { + virtual void f(); +}; +namespace { struct S; } +void foo () { klass<S> x; } +// CHECK: @_ZTV5klassIN12_GLOBAL__N_11SEE = internal unnamed_addr constant diff --git a/clang/test/CodeGenCXX/key-function-vtable.cpp b/clang/test/CodeGenCXX/key-function-vtable.cpp new file mode 100644 index 0000000..8e474bd --- /dev/null +++ b/clang/test/CodeGenCXX/key-function-vtable.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +// Simple key function test +struct testa { virtual void a(); }; +void testa::a() {} + +// Simple key function test +struct testb { virtual void a() {} }; +testb *testbvar = new testb; + +// Key function with out-of-line inline definition +struct testc { virtual void a(); }; +inline void testc::a() {} + +// Functions with inline specifier are not key functions (PR5705) +struct testd { inline virtual void a(); }; +void testd::a() {} + +// Functions with inline specifier are not key functions (PR5705) +struct teste { inline virtual void a(); }; +teste *testevar = new teste; + +// Key functions with namespace (PR5711) +namespace { + struct testf { virtual void a(); }; +} +void testf::a() {} + +// Key functions with namespace (PR5711) +namespace { + struct testg { virtual void a(); }; +} +void testg::a() {} +testg *testgvar = new testg; + +struct X0 { virtual ~X0(); }; +struct X1 : X0 { + virtual void f(); +}; + +inline void X1::f() { } + +void use_X1(X1 *x1) { x1->f(); } + +// FIXME: The checks are extremely difficult to get right when the globals +// aren't alphabetized +// CHECK: @_ZTV2X1 = linkonce_odr unnamed_addr constant +// CHECK: @_ZTV5testa = unnamed_addr constant [3 x i8*] [i8* null +// CHECK: @_ZTV5testc = linkonce_odr unnamed_addr constant [3 x i8*] [i8* null +// CHECK: @_ZTVN12_GLOBAL__N_15testgE = internal unnamed_addr constant [3 x i8*] [i8* null +// CHECK: @_ZTV5teste = linkonce_odr unnamed_addr constant [3 x i8*] [i8* null +// CHECK: @_ZTV5testb = linkonce_odr unnamed_addr constant [3 x i8*] [i8* null diff --git a/clang/test/CodeGenCXX/lambda-expressions.cpp b/clang/test/CodeGenCXX/lambda-expressions.cpp new file mode 100644 index 0000000..797cbf4 --- /dev/null +++ b/clang/test/CodeGenCXX/lambda-expressions.cpp @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 | FileCheck %s + +// CHECK: @var = internal global +auto var = [](int i) { return i+1; }; + +// CHECK: @cvar = global +extern "C" auto cvar = []{}; + +int a() { return []{ return 1; }(); } +// CHECK: define i32 @_Z1av +// CHECK: call i32 @"_ZZ1avENK3$_0clEv" +// CHECK: define internal i32 @"_ZZ1avENK3$_0clEv" +// CHECK: ret i32 1 + +int b(int x) { return [x]{return x;}(); } +// CHECK: define i32 @_Z1bi +// CHECK: store i32 +// CHECK: load i32* +// CHECK: store i32 +// CHECK: call i32 @"_ZZ1biENK3$_1clEv" +// CHECK: define internal i32 @"_ZZ1biENK3$_1clEv" +// CHECK: load i32* +// CHECK: ret i32 + +int c(int x) { return [&x]{return x;}(); } +// CHECK: define i32 @_Z1ci +// CHECK: store i32 +// CHECK: store i32* +// CHECK: call i32 @"_ZZ1ciENK3$_2clEv" +// CHECK: define internal i32 @"_ZZ1ciENK3$_2clEv" +// CHECK: load i32** +// CHECK: load i32* +// CHECK: ret i32 + +struct D { D(); D(const D&); int x; }; +int d(int x) { D y[10]; [x,y] { return y[x].x; }(); } + +// CHECK: define i32 @_Z1di +// CHECK: call void @_ZN1DC1Ev +// CHECK: icmp ult i64 %{{.*}}, 10 +// CHECK: call void @_ZN1DC1ERKS_ +// CHECK: call i32 @"_ZZ1diENK3$_3clEv" +// CHECK: define internal i32 @"_ZZ1diENK3$_3clEv" +// CHECK: load i32* +// CHECK: load i32* +// CHECK: ret i32 + +struct E { E(); E(const E&); ~E(); int x; }; +int e(E a, E b, bool cond) { [a,b,cond](){ return (cond ? a : b).x; }(); } +// CHECK: define i32 @_Z1e1ES_b +// CHECK: call void @_ZN1EC1ERKS_ +// CHECK: invoke void @_ZN1EC1ERKS_ +// CHECK: invoke i32 @"_ZZ1e1ES_bENK3$_4clEv" +// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev" +// CHECK: call void @"_ZZ1e1ES_bEN3$_4D1Ev" + +// CHECK: define internal i32 @"_ZZ1e1ES_bENK3$_4clEv" +// CHECK: trunc i8 +// CHECK: load i32* +// CHECK: ret i32 + +void f() { + // CHECK: define void @_Z1fv() + // CHECK: @"_ZZ1fvENK3$_5cvPFiiiEEv" + // CHECK-NEXT: store i32 (i32, i32)* + // CHECK-NEXT: ret void + int (*fp)(int, int) = [](int x, int y){ return x + y; }; +} + +// CHECK: define internal i32 @"_ZZ1fvEN3$_58__invokeEii" +// CHECK: store i32 +// CHECK-NEXT: store i32 +// CHECK-NEXT: load i32* +// CHECK-NEXT: load i32* +// CHECK-NEXT: call i32 @"_ZZ1fvENK3$_5clEii" +// CHECK-NEXT: ret i32 + +// CHECK: define internal void @"_ZZ1e1ES_bEN3$_4D2Ev" diff --git a/clang/test/CodeGenCXX/lvalue-bitcasts.cpp b/clang/test/CodeGenCXX/lvalue-bitcasts.cpp new file mode 100644 index 0000000..8c5fa4a --- /dev/null +++ b/clang/test/CodeGenCXX/lvalue-bitcasts.cpp @@ -0,0 +1,163 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s + +struct X { int i; float f; }; +struct Y { X x; }; + +// CHECK: define void @_Z21reinterpret_cast_testRiRfR1X +void reinterpret_cast_test(int &ir, float &fr, X &xr) { + // CHECK: load float** + // CHECK: bitcast float* + // CHECK: load i32* + ir = reinterpret_cast<int&>(fr); + // CHECK: load + // CHECK: {{bitcast.*to i32\*}} + // CHECK: load i32* + ir = reinterpret_cast<int&>(xr); + // CHECK: load i32 + // CHECK: {{bitcast.*to float\*}} + // CHECK: load float* + fr = reinterpret_cast<float&>(ir); + // CHECK: load + // CHECK: {{bitcast.*to float\*}} + // CHECK: load float* + fr = reinterpret_cast<float&>(xr); + // CHECK: load i32** + // CHECK: bitcast i32* + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 + xr = reinterpret_cast<X&>(ir); + // CHECK: load float** + // CHECK: bitcast float* + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 + xr = reinterpret_cast<X&>(fr); + _Complex float cf; + _Complex float &cfr = cf; + // CHECK: load i32** + // CHECK: bitcast i32* + // CHECK: load float* + // CHECK: load float* + cfr = reinterpret_cast<_Complex float&>(ir); + // CHECK: load float** + // CHECK: bitcast float* + // CHECK: load float* + // CHECK: load float* + cfr = reinterpret_cast<_Complex float&>(fr); + // CHECK: bitcast + // CHECK: load float* + // CHECK: load float* + cfr = reinterpret_cast<_Complex float&>(xr); + // CHECK: ret void +} + +// CHECK: define void @_Z6c_castRiRfR1X +void c_cast(int &ir, float &fr, X &xr) { + // CHECK: load float** + // CHECK: bitcast float* + // CHECK: load i32* + ir = (int&)fr; + // CHECK: load + // CHECK: {{bitcast.*to i32\*}} + // CHECK: load i32* + ir = (int&)xr; + // CHECK: load i32 + // CHECK: {{bitcast.*to float\*}} + // CHECK: load float* + fr = (float&)ir; + // CHECK: load + // CHECK: {{bitcast.*to float\*}} + // CHECK: load float* + fr = (float&)xr; + // CHECK: load i32** + // CHECK: bitcast i32* + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 + xr = (X&)ir; + // CHECK: load float** + // CHECK: bitcast float* + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 + xr = (X&)fr; + _Complex float cf; + _Complex float &cfr = cf; + // CHECK: load i32** + // CHECK: bitcast i32* + // CHECK: load float* + // CHECK: load float* + cfr = (_Complex float&)ir; + // CHECK: load float** + // CHECK: bitcast float* + // CHECK: load float* + // CHECK: load float* + cfr = (_Complex float&)fr; + // CHECK: bitcast + // CHECK: load float* + // CHECK: load float* + cfr = (_Complex float&)xr; + // CHECK: ret void +} + +// CHECK: define void @_Z15functional_castRiRfR1X +void functional_cast(int &ir, float &fr, X &xr) { + typedef int &intref; + typedef float &floatref; + typedef X &Xref; + // CHECK: load float** + // CHECK: bitcast float* + // CHECK: load i32* + ir = intref(fr); + // CHECK: load + // CHECK: {{bitcast.*to i32\*}} + // CHECK: load i32* + ir = intref(xr); + // CHECK: load i32 + // CHECK: {{bitcast.*to float\*}} + // CHECK: load float* + fr = floatref(ir); + // CHECK: load + // CHECK: {{bitcast.*to float\*}} + // CHECK: load float* + fr = floatref(xr); + // CHECK: load i32** + // CHECK: bitcast i32* + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 + xr = Xref(ir); + // CHECK: load float** + // CHECK: bitcast float* + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 + xr = Xref(fr); + typedef _Complex float &complex_float_ref; + _Complex float cf; + _Complex float &cfr = cf; + // CHECK: load i32** + // CHECK: bitcast i32* + // CHECK: load float* + // CHECK: load float* + cfr = complex_float_ref(ir); + // CHECK: load float** + // CHECK: bitcast float* + // CHECK: load float* + // CHECK: load float* + cfr = complex_float_ref(fr); + // CHECK: bitcast + // CHECK: load float* + // CHECK: load float* + cfr = complex_float_ref(xr); + // CHECK: ret void +} + +namespace PR6437 { + struct in_addr {}; + void copy( const struct in_addr &new_addr ) { + int addr = (int&)new_addr; + } +} + +namespace PR7593 { + void foo(double &X, char *A) { + X = reinterpret_cast<double&>(A[4]); + } +} + +namespace PR7344 { + void serialize_annotatable_id( void*& id ) + { + unsigned long l_id = (unsigned long&)id; + } +} diff --git a/clang/test/CodeGenCXX/m64-ptr.cpp b/clang/test/CodeGenCXX/m64-ptr.cpp new file mode 100644 index 0000000..29916bf --- /dev/null +++ b/clang/test/CodeGenCXX/m64-ptr.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -emit-llvm -triple x86_64-apple-darwin -o - | FileCheck %s + +// Make sure pointers are passed as pointers, not converted to int. +// The first load should be of type i8** in either 32 or 64 bit mode. +// This formerly happened on x86-64, 7375899. + +class StringRef { +public: + const char *Data; + long Len; +}; +void foo(StringRef X); +void bar(StringRef &A) { +// CHECK: @_Z3barR9StringRef +// CHECK: load i8** + foo(A); +// CHECK: ret void +} diff --git a/clang/test/CodeGenCXX/mangle-98.cpp b/clang/test/CodeGenCXX/mangle-98.cpp new file mode 100644 index 0000000..a9ab6ca --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-98.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -std=c++98 | FileCheck %s + +template <bool B> struct S3 {}; + +// CHECK: define void @_Z1f2S3ILb1EE +void f(S3<true>) {} + +// CHECK: define void @_Z1f2S3ILb0EE +void f(S3<false>) {} + +// CHECK: define void @_Z2f22S3ILb1EE +void f2(S3<100>) {} diff --git a/clang/test/CodeGenCXX/mangle-abi-examples.cpp b/clang/test/CodeGenCXX/mangle-abi-examples.cpp new file mode 100644 index 0000000..7124078 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-abi-examples.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +// CHECK: @_ZTVZ3foovEN1C1DE = +// CHECK: @_ZTVZN1A3fooEiE1B = +// CHECK: define {{.*}} @_ZZZ3foovEN1C3barEvEN1E3bazEv( + +// Itanium C++ ABI examples. +struct A { + void foo (int) { + struct B { virtual ~B() {} }; + B(); + } +}; +void foo () { + struct C { + struct D { virtual ~D() {} }; + void bar () { + struct E { + void baz() { } + }; + E().baz(); + } + }; + A().foo(0); + C::D(); + C().bar(); +} diff --git a/clang/test/CodeGenCXX/mangle-address-space.cpp b/clang/test/CodeGenCXX/mangle-address-space.cpp new file mode 100644 index 0000000..ff23c20 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-address-space.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +// CHECK: define void @_Z2f0Pc +void f0(char *p) { } +// CHECK: define void @_Z2f0PU3AS1c +void f0(char __attribute__((address_space(1))) *p) { } + +struct OpaqueType; +typedef OpaqueType __attribute__((address_space(100))) * OpaqueTypePtr; + +// CHECK: define void @_Z2f0PU5AS10010OpaqueType +void f0(OpaqueTypePtr) { } diff --git a/clang/test/CodeGenCXX/mangle-alias-template.cpp b/clang/test/CodeGenCXX/mangle-alias-template.cpp new file mode 100644 index 0000000..5ace0b0 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-alias-template.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +template<typename T> struct alloc {}; +template<typename T> using Alloc = alloc<T>; +template<typename T, typename A = Alloc<T>> struct vector {}; + +template<typename T> using Vec = vector<T>; + +template<typename T> void f(Vec<T> v); +template<typename T> void g(T); + +template<template<typename> class F> void h(F<int>); + +template<typename,typename,typename> struct S {}; +template<typename T, typename U> using U = S<T, int, U>; +template<typename...Ts> void h(U<Ts...>, Ts...); + +// CHECK: define void @_Z1zv( +void z() { + vector<int> VI; + f(VI); + // CHECK: call void @_Z1fIiEv6vectorIT_5allocIS1_EE( + + Vec<double> VD; + g(VD); + // CHECK: call void @_Z1gI6vectorId5allocIdEEEvT_( + + h<Vec>(VI); + // CHECK: call void @_Z1hI3VecEvT_IiE( + + Alloc<int> AC; + h(AC); + // CHECK: call void @_Z1hI5allocEvT_IiE( + + h<Alloc>(AC); + // CHECK: call void @_Z1hI5AllocEvT_IiE( + + Vec<char> VC; + g<Vec<char>>(VC); + // CHECK: call void @_Z1gI6vectorIc5allocIcEEEvT_( + + Vec<Vec<int>> VVI; + g(VVI); + // CHECK: call void @_Z1gI6vectorIS0_Ii5allocIiEES1_IS3_EEEvT_( + + // CHECK: call void @_Z1hIJidEEv1UIDpT_ES2_ + h({}, 0, 0.0); +} diff --git a/clang/test/CodeGenCXX/mangle-exprs.cpp b/clang/test/CodeGenCXX/mangle-exprs.cpp new file mode 100644 index 0000000..30da4fb --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-exprs.cpp @@ -0,0 +1,193 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s + +namespace std { + typedef decltype(sizeof(int)) size_t; + + // libc++'s implementation + template <class _E> + class initializer_list + { + const _E* __begin_; + size_t __size_; + + initializer_list(const _E* __b, size_t __s) + : __begin_(__b), + __size_(__s) + {} + + public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + + typedef const _E* iterator; + typedef const _E* const_iterator; + + initializer_list() : __begin_(nullptr), __size_(0) {} + + size_t size() const {return __size_;} + const _E* begin() const {return __begin_;} + const _E* end() const {return __begin_ + __size_;} + }; +} + +template < bool condition, typename T = void > +struct enable_if { typedef T type; }; + +template< typename T > +struct enable_if< false, T > {}; + +// PR5876 +namespace Casts { + template< unsigned O > + void implicit(typename enable_if< O <= 4 >::type* = 0) { + } + + template< unsigned O > + void cstyle(typename enable_if< O <= (unsigned)4 >::type* = 0) { + } + + template< unsigned O > + void functional(typename enable_if< O <= unsigned(4) >::type* = 0) { + } + + template< unsigned O > + void static_(typename enable_if< O <= static_cast<unsigned>(4) >::type* = 0) { + } + + template< typename T > + void auto_(decltype(new auto(T()))) { + } + + template< typename T > + void scalar_(decltype(T(), int())) { + } + + // FIXME: Test const_cast, reinterpret_cast, dynamic_cast, which are + // a bit harder to use in template arguments. + template <unsigned N> struct T {}; + + template <int N> T<N> f() { return T<N>(); } + + // CHECK: define weak_odr void @_ZN5Casts8implicitILj4EEEvPN9enable_ifIXleT_Li4EEvE4typeE + template void implicit<4>(void*); + // CHECK: define weak_odr void @_ZN5Casts6cstyleILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + template void cstyle<4>(void*); + // CHECK: define weak_odr void @_ZN5Casts10functionalILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + template void functional<4>(void*); + // CHECK: define weak_odr void @_ZN5Casts7static_ILj4EEEvPN9enable_ifIXleT_cvjLi4EEvE4typeE + template void static_<4>(void*); + + // CHECK: define weak_odr void @_ZN5Casts1fILi6EEENS_1TIXT_EEEv + template T<6> f<6>(); + + // CHECK: define weak_odr void @_ZN5Casts5auto_IiEEvDTnw_DapicvT__EEE( + template void auto_<int>(int*); + + // CHECK: define weak_odr void @_ZN5Casts7scalar_IiEEvDTcmcvT__Ecvi_EE( + template void scalar_<int>(int); +} + +namespace test1 { + short foo(short); + int foo(int); + + // CHECK: define linkonce_odr signext i16 @_ZN5test11aIsEEDTcl3foocvT__EEES1_( + template <class T> auto a(T t) -> decltype(foo(T())) { return foo(t); } + + // CHECK: define linkonce_odr signext i16 @_ZN5test11bIsEEDTcp3foocvT__EEES1_( + template <class T> auto b(T t) -> decltype((foo)(T())) { return (foo)(t); } + + void test(short s) { + a(s); + b(s); + } +} + +namespace test2 { + template <class T> void a(T x, decltype(x()) y) {} + template <class T> auto b(T x) -> decltype(x()) { return x(); } + template <class T> void c(T x, void (*p)(decltype(x()))) {} + template <class T> void d(T x, auto (*p)() -> decltype(x())) {} + template <class T> void e(auto (*p)(T y) -> decltype(y())) {} + template <class T> void f(void (*p)(T x, decltype(x()) y)) {} + template <class T> void g(T x, decltype(x()) y) { + static decltype(x()) variable; + variable = 0; + } + template <class T> void h(T x, decltype((decltype(x())(*)()) 0) y) {} + template <class T> void i(decltype((auto (*)(T x) -> decltype(x())) 0) y) {} + + float foo(); + void bar(float); + float baz(float(*)()); + void fred(float(*)(), float); + + // CHECK: define void @_ZN5test211instantiateEv + void instantiate() { + // CHECK: call void @_ZN5test21aIPFfvEEEvT_DTclfL0p_EE( + a(foo, 0.0f); + // CHECK: call float @_ZN5test21bIPFfvEEEDTclfp_EET_( + (void) b(foo); + // CHECK: call void @_ZN5test21cIPFfvEEEvT_PFvDTclfL1p_EEE( + c(foo, bar); + // CHECK: call void @_ZN5test21dIPFfvEEEvT_PFDTclfL0p_EEvE( + d(foo, foo); + // CHECK: call void @_ZN5test21eIPFfvEEEvPFDTclfp_EET_E( + e(baz); + // CHECK: call void @_ZN5test21fIPFfvEEEvPFvT_DTclfL0p_EEE( + f(fred); + // CHECK: call void @_ZN5test21gIPFfvEEEvT_DTclfL0p_EE( + g(foo, 0.0f); + // CHECK: call void @_ZN5test21hIPFfvEEEvT_DTcvPFDTclfL0p_EEvELi0EE( + h(foo, foo); + // CHECK: call void @_ZN5test21iIPFfvEEEvDTcvPFDTclfp_EET_ELi0EE( + i<float(*)()>(baz); + } + + // CHECK: store float {{.*}}, float* @_ZZN5test21gIPFfvEEEvT_DTclfL0p_EEE8variable, +} + +namespace test3 { + template <class T, class U> void a(T x, U y, decltype(x.*y) z) {} + + struct X { + int *member; + }; + + // CHECK: define void @_ZN5test311instantiateEv + void instantiate() { + X x; + int *ip; + // CHECK: call void @_ZN5test31aINS_1XEMS1_PiEEvT_T0_DTdsfL0p_fL0p0_E + a(x, &X::member, ip); + } +} + +namespace test4 { + struct X { + X(int); + }; + + template <typename T> + void tf1(decltype(new T(1)) p) + {} + + template <typename T> + void tf2(decltype(new T({1})) p) + {} + + template <typename T> + void tf3(decltype(new T{1}) p) + {} + + // CHECK: void @_ZN5test43tf1INS_1XEEEvDTnw_T_piLi1EEE + template void tf1<X>(X*); + + // CHECK: void @_ZN5test43tf2INS_1XEEEvDTnw_T_piilLi1EEEE + template void tf2<X>(X*); + + // CHECK: void @_ZN5test43tf3INS_1XEEEvDTnw_T_ilLi1EEE + template void tf3<X>(X*); +} diff --git a/clang/test/CodeGenCXX/mangle-extern-local.cpp b/clang/test/CodeGenCXX/mangle-extern-local.cpp new file mode 100644 index 0000000..ed91da4 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-extern-local.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +// CHECK: @var1 = external global i32 +// CHECK: @_ZN1N4var2E = external global i32 +// CHECK: @var5 = external global i32 +// CHECK: @_ZN1N4var3E = external global i32 +// CHECK: @_ZN1N4var4E = external global i32 + +// CHECK: declare i32 @_Z5func1v() +// CHECK: declare i32 @_ZN1N5func2Ev() +// CHECK: declare i32 @func4() +// CHECK: declare i32 @_ZN1N5func3Ev() + +int f1() { + extern int var1, func1(); + return var1 + func1(); +} + +namespace N { + +int f2() { + extern int var2, func2(); + return var2 + func2(); +} + +struct S { + static int f3() { + extern int var3, func3(); + struct LC { int localfunc() { extern int var4; return var4; } }; + LC localobj; + return var3 + func3() + localobj.localfunc(); + } +}; + +int anchorf3() { return S::f3(); } + +extern "C" { +int f4() { + extern int var5, func4(); + return var5 + func4(); +} +} + +} + diff --git a/clang/test/CodeGenCXX/mangle-extreme.cpp b/clang/test/CodeGenCXX/mangle-extreme.cpp new file mode 100644 index 0000000..ef2d466 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-extreme.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s + +struct X { }; + +// CHECK: define void @_Z1fPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP1XS13_S12_S11_S10_SZ_SY_SX_SW_SV_SU_ST_SS_SR_SQ_SP_SO_SN_SM_SL_SK_SJ_SI_SH_SG_SF_SE_SD_SC_SB_SA_S9_S8_S7_S6_S5_S4_S3_S2_S1_S0_S_( +void f(X****************************************, + X****************************************, + X***************************************, + X**************************************, + X*************************************, + X************************************, + X***********************************, + X**********************************, + X*********************************, + X********************************, + X*******************************, + X******************************, + X*****************************, + X****************************, + X***************************, + X**************************, + X*************************, + X************************, + X***********************, + X**********************, + X*********************, + X********************, + X*******************, + X******************, + X*****************, + X****************, + X***************, + X**************, + X*************, + X************, + X***********, + X**********, + X*********, + X********, + X*******, + X******, + X*****, + X****, + X***, + X**, + X*, + X) { } diff --git a/clang/test/CodeGenCXX/mangle-lambdas.cpp b/clang/test/CodeGenCXX/mangle-lambdas.cpp new file mode 100644 index 0000000..cc53b01 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-lambdas.cpp @@ -0,0 +1,202 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-macosx10.7.0 -emit-llvm -o - %s | FileCheck %s + +// CHECK: define linkonce_odr void @_Z11inline_funci +inline void inline_func(int n) { + // CHECK: call i32 @_ZZ11inline_funciENKUlvE_clEv + int i = []{ return 1; }(); + + // CHECK: call i32 @_ZZ11inline_funciENKUlvE0_clEv + int j = [=] { return n + i; }(); + + // CHECK: call double @_ZZ11inline_funciENKUlvE1_clEv + int k = [=] () -> double { return n + i; }(); + + // CHECK: call i32 @_ZZ11inline_funciENKUliE_clEi + int l = [=] (int x) -> int { return x + i; }(n); + + int inner(int i = []{ return 17; }()); + // CHECK: call i32 @_ZZ11inline_funciENKUlvE2_clEv + // CHECK-NEXT: call i32 @_Z5inneri + inner(); + + // CHECK-NEXT: ret void +} + +void call_inline_func() { + inline_func(17); +} + +struct S { + void f(int = []{return 1;}() + + []{return 2;}(), + int = []{return 3;}()); + void g(int, int); +}; + +void S::g(int i = []{return 1;}(), + int j = []{return 2; }()) {} + +// CHECK: define void @_Z6test_S1S +void test_S(S s) { + // CHECK: call i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv + // CHECK-NEXT: call i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv + // CHECK-NEXT: add nsw i32 + // CHECK-NEXT: call i32 @_ZZN1S1fEiiEd_NKUlvE_clEv + // CHECK-NEXT: call void @_ZN1S1fEii + s.f(); + + // NOTE: These manglings don't actually matter that much, because + // the lambdas in the default arguments of g() won't be seen by + // multiple translation units. We check them mainly to ensure that they don't + // get the special mangling for lambdas in in-class default arguments. + // CHECK: call i32 @"_ZNK1S3$_0clEv" + // CHECK-NEXT: call i32 @"_ZNK1S3$_1clEv" + // CHECK-NEXT: call void @_ZN1S1gEi + s.g(); + + // CHECK-NEXT: ret void +} + +// Check the linkage of the lambda call operators used in test_S. +// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE_clEv +// CHECK: ret i32 1 +// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd0_NKUlvE0_clEv +// CHECK: ret i32 2 +// CHECK: define linkonce_odr i32 @_ZZN1S1fEiiEd_NKUlvE_clEv +// CHECK: ret i32 3 +// CHECK: define internal i32 @"_ZNK1S3$_0clEv" +// CHECK: ret i32 1 +// CHECK: define internal i32 @"_ZNK1S3$_1clEv" +// CHECK: ret i32 2 + +template<typename T> +struct ST { + void f(T = []{return T() + 1;}() + + []{return T() + 2;}(), + T = []{return T(3);}()); +}; + +// CHECK: define void @_Z7test_ST2STIdE +void test_ST(ST<double> st) { + // CHECK: call double @_ZZN2ST1fET_S0_Ed0_NKUlvE_clEv + // CHECK-NEXT: call double @_ZZN2ST1fET_S0_Ed0_NKUlvE0_clEv + // CHECK-NEXT: fadd double + // CHECK-NEXT: call double @_ZZN2ST1fET_S0_Ed_NKUlvE_clEv + // CHECK-NEXT: call void @_ZN2STIdE1fEdd + st.f(); + + // CHECK-NEXT: ret void +} + +// Check the linkage of the lambda call operators used in test_ST. +// CHECK: define linkonce_odr double @_ZZN2ST1fET_S0_Ed0_NKUlvE_clEv +// CHECK: ret double 1 +// CHECK: define linkonce_odr double @_ZZN2ST1fET_S0_Ed0_NKUlvE0_clEv +// CHECK: ret double 2 +// CHECK: define linkonce_odr double @_ZZN2ST1fET_S0_Ed_NKUlvE_clEv +// CHECK: ret double 3 + +template<typename T> +struct StaticMembers { + static T x; + static T y; + static T z; +}; + +template<typename T> int accept_lambda(T); + +template<typename T> +T StaticMembers<T>::x = []{return 1;}() + []{return 2;}(); + +template<typename T> +T StaticMembers<T>::y = []{return 3;}(); + +template<typename T> +T StaticMembers<T>::z = accept_lambda([]{return 4;}); + +// CHECK: define internal void @__cxx_global_var_init() +// CHECK: call i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv +// CHECK-NEXT: call i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv +// CHECK-NEXT: add nsw +// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE_clEv +// CHECK: ret i32 1 +// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1xMUlvE0_clEv +// CHECK: ret i32 2 +template float StaticMembers<float>::x; + +// CHECK: define internal void @__cxx_global_var_init1() +// CHECK: call i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv +// CHECK: define linkonce_odr i32 @_ZNK13StaticMembersIfE1yMUlvE_clEv +// CHECK: ret i32 3 +template float StaticMembers<float>::y; + +// CHECK: define internal void @__cxx_global_var_init2() +// CHECK: call i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_ +// CHECK: declare i32 @_Z13accept_lambdaIN13StaticMembersIfE1zMUlvE_EEiT_() +template float StaticMembers<float>::z; + +// CHECK: define internal void @__cxx_global_var_init3 +// CHECK: call i32 @"_ZNK13StaticMembersIdE3$_2clEv" +// CHECK: define internal i32 @"_ZNK13StaticMembersIdE3$_2clEv" +// CHECK: ret i32 42 +template<> double StaticMembers<double>::z = []{return 42; }(); + +template<typename T> +void func_template(T = []{ return T(); }()); + +// CHECK: define void @_Z17use_func_templatev() +void use_func_template() { + // CHECK: call i32 @"_ZZ13func_templateIiEvT_ENKS_IiE3$_3clEv" + func_template<int>(); +} + +// CHECK: define linkonce_odr void @_Z1fIZZNK23TestNestedInstantiationclEvENKUlvE_clEvEUlvE_EvT_ + +struct Members { + int x = [] { return 1; }() + [] { return 2; }(); + int y = [] { return 3; }(); +}; + +void test_Members() { + // CHECK: define linkonce_odr void @_ZN7MembersC2Ev + // CHECK: call i32 @_ZNK7Members1xMUlvE_clEv + // CHECK-NEXT: call i32 @_ZNK7Members1xMUlvE0_clE + // CHECK-NEXT: add nsw i32 + // CHECK: call i32 @_ZNK7Members1yMUlvE_clEv + Members members; + // CHECK: ret void +} + +template<typename P> void f(P) { } + +struct TestNestedInstantiation { + void operator()() const { + []() -> void { + return f([]{}); + }(); + } +}; + +void test_NestedInstantiation() { + TestNestedInstantiation()(); +} + +// Check the linkage of the lambdas used in test_Members. +// CHECK: define linkonce_odr i32 @_ZNK7Members1xMUlvE_clEv +// CHECK: ret i32 1 +// CHECK: define linkonce_odr i32 @_ZNK7Members1xMUlvE0_clEv +// CHECK: ret i32 2 +// CHECK: define linkonce_odr i32 @_ZNK7Members1yMUlvE_clEv +// CHECK: ret i32 3 + +// Check linkage of the various lambdas. +// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE_clEv +// CHECK: ret i32 1 +// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE0_clEv +// CHECK: ret i32 +// CHECK: define linkonce_odr double @_ZZ11inline_funciENKUlvE1_clEv +// CHECK: ret double +// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUliE_clEi +// CHECK: ret i32 +// CHECK: define linkonce_odr i32 @_ZZ11inline_funciENKUlvE2_clEv +// CHECK: ret i32 17 diff --git a/clang/test/CodeGenCXX/mangle-local-class-names.cpp b/clang/test/CodeGenCXX/mangle-local-class-names.cpp new file mode 100644 index 0000000..3321460 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-local-class-names.cpp @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +// CHECK: @_ZZ4FUNCvEN4SSSSC1ERKf +// CHECK: @_ZZ4FUNCvEN4SSSSC2E_0RKf +// CHECK: @_ZZ4GORFfEN4SSSSC1ERKf +// CHECK: @_ZZ4GORFfEN4SSSSC2E_0RKf + +void FUNC () +{ + { + float IVAR1 ; + + struct SSSS + { + float bv; + SSSS( const float& from): bv(from) { } + }; + + SSSS VAR1(IVAR1); + } + + { + float IVAR2 ; + + struct SSSS + { + SSSS( const float& from) {} + }; + + SSSS VAR2(IVAR2); + } +} + +void GORF (float IVAR1) +{ + { + struct SSSS + { + float bv; + SSSS( const float& from): bv(from) { } + }; + + SSSS VAR1(IVAR1); + } + + { + float IVAR2 ; + + struct SSSS + { + SSSS( const float& from) {} + }; + + SSSS VAR2(IVAR2); + } +} + diff --git a/clang/test/CodeGenCXX/mangle-local-class-vtables.cpp b/clang/test/CodeGenCXX/mangle-local-class-vtables.cpp new file mode 100644 index 0000000..d9d3afe --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-local-class-vtables.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +// CHECK: @_ZTVZN1J1KEvE1C = {{.*}} @_ZTIZN1J1KEvE1C {{.*}} @_ZZN1J1KEvENK1C1FEv +// CHECK: @_ZTIZN1J1KEvE1C = {{.*}} @_ZTSZN1J1KEvE1C +// CHECK: @_ZTVZ1GvE1C_1 = {{.*}} @_ZTIZ1GvE1C_1 {{.*}} @_ZZ1GvENK1C1FE_1v +// CHECK: @_ZTIZ1GvE1C_1 = {{.*}} @_ZTSZ1GvE1C_1 +// CHECK: @_ZTVZ1GvE1C_0 = {{.*}} @_ZTIZ1GvE1C_0 {{.*}} @_ZZ1GvENK1C1FE_0v +// CHECK: @_ZTIZ1GvE1C_0 = {{.*}} @_ZTSZ1GvE1C_0 +// CHECK: @_ZTVZ1GvE1C = {{.*}} @_ZTIZ1GvE1C {{.*}} @_ZZ1GvENK1C1FEv +// CHECK: @_ZTIZ1GvE1C = {{.*}} @_ZTSZ1GvE1C + +// CHECK: define {{.*}} @_ZZN1J1KEvEN1CC2Ev( +// CHECK: define {{.*}} @_ZZN1J1KEvENK1C1FEv( +// CHECK: define {{.*}} @_ZZ1GvEN1CC2E_1v( +// CHECK: define {{.*}} @_ZZ1GvENK1C1FE_1v( +// CHECK: define {{.*}} @_ZZ1GvENK1C1HE_1v( +// CHECK: define {{.*}} @_ZZ1GvEN1CC2E_0v( +// CHECK: define {{.*}} @_ZZ1GvENK1C1FE_0v( +// CHECK: define {{.*}} @_ZZ1GvENK1C1GE_0v( +// CHECK: define {{.*}} @_ZZ1GvEN1CC2Ev( +// CHECK: define {{.*}} @_ZZ1GvENK1C1FEv( + +struct I { + virtual void F() const = 0; +}; + +void Go(const I &i); + +void G() { + { + struct C : I { + void F() const {} + }; + Go(C()); + } + { + struct C : I { + void F() const { G(); } + void G() const {} + }; + Go(C()); + } + { + struct C : I { + void F() const { H(); } + void H() const {} + }; + Go(C()); + } +} + +struct J { + void K(); +}; + +void J::K() { + struct C : I { + void F() const {} + }; + Go(C()); +} diff --git a/clang/test/CodeGenCXX/mangle-local-classes-nested.cpp b/clang/test/CodeGenCXX/mangle-local-classes-nested.cpp new file mode 100644 index 0000000..fafa5d4 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-local-classes-nested.cpp @@ -0,0 +1,81 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +// CHECK: @_ZTVZZ1HvEN1S1IEvE1S = + +// CHECK: define {{.*}} @_Z2L1v( +// CHECK: define {{.*}} @_ZZ2L1vEN1S2L2Ev( +// CHECK: define {{.*}} @_ZZ2L1vEN1S2L2E_0v( +// CHECK: define {{.*}} @_ZZ1FvEN1S1T1S1T1GEv( +// CHECK: define {{.*}} @_ZZZ2L1vEN1S2L2E_0vEN1S3L3cEv( +// CHECK: define {{.*}} @_ZZZ2L1vEN1S2L2E_0vEN1S3L3dE_0v( +// CHECK: define {{.*}} @_ZZZ2L1vEN1S2L2EvEN1S3L3aEv( +// CHECK: define {{.*}} @_ZZZ2L1vEN1S2L2EvEN1S3L3bE_0v( + +void L1() { + { + struct S { + void L2() { + { + struct S { + void L3a() {} + }; + S().L3a(); + } + { + struct S { + void L3b() {} + }; + S().L3b(); + } + } + }; + S().L2(); + } + { + struct S { + void L2() { + { + struct S { + void L3c() {} + }; + S().L3c(); + } + { + struct S { + void L3d() {} + }; + S().L3d(); + } + } + }; + S().L2(); + } +} + +void F() { + struct S { + struct T { + struct S { + struct T { + void G() {} + }; + }; + }; + }; + S::T::S::T().G(); +} + +struct B { virtual void Foo() = 0; }; +void G(const B &); + +void H() { + struct S { + void I() { + struct S : B { + virtual void Foo() {} + }; + G(S()); + } + }; + S().I(); +} diff --git a/clang/test/CodeGenCXX/mangle-ms.cpp b/clang/test/CodeGenCXX/mangle-ms.cpp new file mode 100644 index 0000000..fe5fde1 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-ms.cpp @@ -0,0 +1,105 @@ +// RUN: %clang_cc1 -fms-extensions -fblocks -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s + +// CHECK: @"\01?a@@3HA" +// CHECK: @"\01?b@N@@3HA" +// CHECK: @c +// CHECK: @"\01?d@foo@@0FB" +// CHECK: @"\01?e@foo@@1JC" +// CHECK: @"\01?f@foo@@2DD" +// CHECK: @"\01?g@bar@@2HA" +// CHECK: @"\01?h@@3QAHA" +// CHECK: @"\01?i@@3PAY0BE@HA" +// CHECK: @"\01?j@@3P6GHCE@ZA" +// CHECK: @"\01?k@@3PTfoo@@DA" +// CHECK: @"\01?l@@3P8foo@@AEHH@ZA" + +int a; + +namespace N { int b; } + +static int c; +int _c(void) {return c;} +// CHECK: @"\01?_c@@YAHXZ" + +class foo { + static const short d; +protected: + static volatile long e; +public: + static const volatile char f; + int operator+(int a); + foo(){} +//CHECK: @"\01??0foo@@QAE@XZ" + + ~foo(){} +//CHECK: @"\01??1foo@@QAE@XZ" + + foo(int i){} +//CHECK: @"\01??0foo@@QAE@H@Z" + + foo(char *q){} +//CHECK: @"\01??0foo@@QAE@PAD@Z" +}f,s1(1),s2((char*)0); + +struct bar { + static int g; +}; + +union baz { + int a; + char b; + double c; +}; + +enum quux { + qone, + qtwo, + qthree +}; + +int foo::operator+(int a) {return a;} +// CHECK: @"\01??Hfoo@@QAEHH@Z" + +const short foo::d = 0; +volatile long foo::e; +const volatile char foo::f = 'C'; + +int bar::g; + +extern int * const h = &a; + +int i[10][20]; + +int (__stdcall *j)(signed char, unsigned char); + +const volatile char foo::*k; + +int (foo::*l)(int); + +// Static functions are mangled, too. +// Also make sure calling conventions, arglists, and throw specs work. +static void __stdcall alpha(float a, double b) throw() {} +bool __fastcall beta(long long a, wchar_t b) throw(signed char, unsigned char) { +// CHECK: @"\01?beta@@YI_N_J_W@Z" + alpha(0.f, 0.0); + return false; +} + +// CHECK: @"\01?alpha@@YGXMN@Z" + +// Make sure tag-type mangling works. +void gamma(class foo, struct bar, union baz, enum quux) {} +// CHECK: @"\01?gamma@@YAXVfoo@@Ubar@@Tbaz@@W4quux@@@Z" + +// Make sure pointer/reference-type mangling works. +void delta(int * const a, const long &) {} +// CHECK: @"\01?delta@@YAXQAHABJ@Z" + +// Array mangling. +void epsilon(int a[][10][20]) {} +// CHECK: @"\01?epsilon@@YAXQAY19BE@H@Z" + +// Blocks mangling (Clang extension). +void zeta(int (^)(int, int)) {} +// CHECK: @"\01?zeta@@YAXP_EAHHH@Z@Z" + diff --git a/clang/test/CodeGenCXX/mangle-neon-vectors.cpp b/clang/test/CodeGenCXX/mangle-neon-vectors.cpp new file mode 100644 index 0000000..3723deb --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-neon-vectors.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +typedef float float32_t; +typedef signed char poly8_t; +typedef short poly16_t; +typedef unsigned long long uint64_t; + +typedef __attribute__((neon_vector_type(2))) int int32x2_t; +typedef __attribute__((neon_vector_type(4))) int int32x4_t; +typedef __attribute__((neon_vector_type(1))) uint64_t uint64x1_t; +typedef __attribute__((neon_vector_type(2))) uint64_t uint64x2_t; +typedef __attribute__((neon_vector_type(2))) float32_t float32x2_t; +typedef __attribute__((neon_vector_type(4))) float32_t float32x4_t; +typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t; +typedef __attribute__((neon_polyvector_type(8))) poly16_t poly16x8_t; + +// CHECK: 16__simd64_int32_t +void f1(int32x2_t v) { } +// CHECK: 17__simd128_int32_t +void f2(int32x4_t v) { } +// CHECK: 17__simd64_uint64_t +void f3(uint64x1_t v) { } +// CHECK: 18__simd128_uint64_t +void f4(uint64x2_t v) { } +// CHECK: 18__simd64_float32_t +void f5(float32x2_t v) { } +// CHECK: 19__simd128_float32_t +void f6(float32x4_t v) { } +// CHECK: 17__simd128_poly8_t +void f7(poly8x16_t v) { } +// CHECK: 18__simd128_poly16_t +void f8(poly16x8_t v) { } diff --git a/clang/test/CodeGenCXX/mangle-nullptr-arg.cpp b/clang/test/CodeGenCXX/mangle-nullptr-arg.cpp new file mode 100644 index 0000000..393de0b --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-nullptr-arg.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s + +template<int *ip> struct IP {}; + +// CHECK: define void @_Z5test12IPILPi0EE +void test1(IP<nullptr>) {} + +struct X{ }; +template<int X::*pm> struct PM {}; + +// CHECK: define void @_Z5test22PMILM1Xi0EE +void test2(PM<nullptr>) { } + diff --git a/clang/test/CodeGenCXX/mangle-ref-qualifiers.cpp b/clang/test/CodeGenCXX/mangle-ref-qualifiers.cpp new file mode 100644 index 0000000..568cf9f --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-ref-qualifiers.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +struct X { + int f() &; + int g() &&; + int h() const &&; +}; + +// CHECK: define i32 @_ZNR1X1fEv +int X::f() & { return 0; } +// CHECK: define i32 @_ZNO1X1gEv +int X::g() && { return 0; } +// CHECK: define i32 @_ZNKO1X1hEv +int X::h() const && { return 0; } + +// CHECK: define void @_Z1fM1XRFivEMS_OFivEMS_KOFivE +void f(int (X::*)() &, int (X::*)() &&, int (X::*)() const&&) { } diff --git a/clang/test/CodeGenCXX/mangle-std-externc.cpp b/clang/test/CodeGenCXX/mangle-std-externc.cpp new file mode 100644 index 0000000..a478dee --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-std-externc.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 %s -DNS=std -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-STD +// RUN: %clang_cc1 %s -DNS=n -emit-llvm -o - | FileCheck %s --check-prefix=CHECK-N + +// _ZNSt1DISt1CE1iE = std::D<std::C>::i +// CHECK-STD: @_ZNSt1DISt1CE1iE = + +// _ZN1n1DINS_1CEE1iE == n::D<n::C>::i +// CHECK-N: @_ZN1n1DINS_1CEE1iE = + +namespace NS { + extern "C" { + class C { + }; + } + + template <class T> + class D { + public: + static int i; + }; + +} + + +int f() { + return NS::D<NS::C>::i; +} diff --git a/clang/test/CodeGenCXX/mangle-subst-std.cpp b/clang/test/CodeGenCXX/mangle-subst-std.cpp new file mode 100644 index 0000000..04e3e84 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-subst-std.cpp @@ -0,0 +1,112 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s + +// Check mangling of Vtables, VTTs, and construction vtables that +// involve standard substitutions. + +// CHECK: @_ZTVSd = linkonce_odr unnamed_addr constant +// CHECK: @_ZTTSd = linkonce_odr unnamed_addr constant +// CHECK: @_ZTCSd0_Si = linkonce_odr unnamed_addr constant +// CHECK: @_ZTCSd16_So = linkonce_odr unnamed_addr constant +// CHECK: @_ZTVSo = linkonce_odr unnamed_addr constant +// CHECK: @_ZTTSo = linkonce_odr unnamed_addr constant +// CHECK: @_ZTVSi = linkonce_odr unnamed_addr constant +// CHECK: @_ZTTSi = linkonce_odr unnamed_addr constant + +namespace std { + struct A { A(); }; + + // CHECK: define void @_ZNSt1AC1Ev(%"struct.std::A"* %this) unnamed_addr + // CHECK: define void @_ZNSt1AC2Ev(%"struct.std::A"* %this) unnamed_addr + A::A() { } +}; + +namespace std { + template<typename> struct allocator { }; +} + +// CHECK: define void @_Z1fSaIcESaIiE +void f(std::allocator<char>, std::allocator<int>) { } + +namespace std { + template<typename, typename, typename> struct basic_string { }; +} + +// CHECK: define void @_Z1fSbIcciE +void f(std::basic_string<char, char, int>) { } + +namespace std { + template<typename> struct char_traits { }; + + typedef std::basic_string<char, std::char_traits<char>, std::allocator<char> > string; +} + +// CHECK: _Z1fSs +void f(std::string) { } + +namespace std { + template<typename, typename> struct basic_ios { + basic_ios(int); + virtual ~basic_ios(); + }; + template<typename charT, typename traits = char_traits<charT> > + struct basic_istream : virtual public basic_ios<charT, traits> { + basic_istream(int x) : basic_ios<charT, traits>(x), stored(x) { } + + int stored; + }; + template<typename charT, typename traits = char_traits<charT> > + struct basic_ostream : virtual public basic_ios<charT, traits> { + basic_ostream(int x) : basic_ios<charT, traits>(x), stored(x) { } + + float stored; + }; + + template<typename charT, typename traits = char_traits<charT> > + struct basic_iostream : public basic_istream<charT, traits>, + public basic_ostream<charT, traits> { + basic_iostream(int x) : basic_istream<charT, traits>(x), + basic_ostream<charT, traits>(x), + basic_ios<charT, traits>(x) { } + }; +} + +// CHECK: _Z1fSi +void f(std::basic_istream<char, std::char_traits<char> >) { } + +// CHECK: _Z1fSo +void f(std::basic_ostream<char, std::char_traits<char> >) { } + +// CHECK: _Z1fSd +void f(std::basic_iostream<char, std::char_traits<char> >) { } + +extern "C++" { +namespace std +{ + typedef void (*terminate_handler) (); + + // CHECK: _ZSt13set_terminatePFvvE + terminate_handler set_terminate(terminate_handler) { return 0; } +} +} + +// Make sure we don't treat the following like std::string +// CHECK: define void @_Z1f12basic_stringIcSt11char_traitsIcESaIcEE +template<typename, typename, typename> struct basic_string { }; +typedef basic_string<char, std::char_traits<char>, std::allocator<char> > not_string; +void f(not_string) { } + +// Manglings for instantiations caused by this function are at the +// top of the test. +void create_streams() { + std::basic_iostream<char> bio(17); +} + +// Make sure we don't mangle 'std' as 'St' here. +namespace N { + namespace std { + struct A { void f(); }; + + // CHECK: define void @_ZN1N3std1A1fEv + void A::f() { } + } +} diff --git a/clang/test/CodeGenCXX/mangle-subst.cpp b/clang/test/CodeGenCXX/mangle-subst.cpp new file mode 100644 index 0000000..d83a081 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-subst.cpp @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s + +struct X {}; + +// CHECK: define void @_Z1f1XS_( +void f(X, X) { } + +// CHECK: define void @_Z1fR1XS0_( +void f(X&, X&) { } + +// CHECK: define void @_Z1fRK1XS1_( +void f(const X&, const X&) { } + +typedef void T(); +struct S {}; + +// CHECK: define void @_Z1fPFvvEM1SFvvE( +void f(T*, T (S::*)) {} + +namespace A { + struct A { }; + struct B { }; +}; + +// CHECK: define void @_Z1fN1A1AENS_1BE( +void f(A::A a, A::B b) { } + +struct C { + struct D { }; +}; + +// CHECK: define void @_Z1fN1C1DERS_PS_S1_( +void f(C::D, C&, C*, C&) { } + +template<typename T> +struct V { + typedef int U; +}; + +template <typename T> void f1(typename V<T>::U, V<T>) { } + +// CHECK: @_Z2f1IiEvN1VIT_E1UES2_ +template void f1<int>(int, V<int>); + +template <typename T> void f2(V<T>, typename V<T>::U) { } + +// CHECK: @_Z2f2IiEv1VIT_ENS2_1UE +template void f2<int>(V<int>, int); + +namespace NS { +template <typename T> struct S1 {}; +template<typename T> void ft3(S1<T>, S1<char>) { } + +// CHECK: @_ZN2NS3ft3IiEEvNS_2S1IT_EENS1_IcEE +template void ft3<int>(S1<int>, S1<char>); +} + +// PR5196 +// CHECK: @_Z1fPKcS0_ +void f(const char*, const char*) {} + +namespace NS { + class C; +} + +namespace NS { + // CHECK: @_ZN2NS1fERNS_1CE + void f(C&) { } +} + +namespace Test1 { + +struct A { }; +struct B { }; + +// CHECK: @_ZN5Test11fEMNS_1BEFvvENS_1AES3_ +void f(void (B::*)(), A, A) { } + +// CHECK: @_ZN5Test11fEMNS_1BEFvvENS_1AES3_MS0_FvS3_EMS3_FvvE +void f(void (B::*)(), A, A, void (B::*)(A), void (A::*)()) { } + +} diff --git a/clang/test/CodeGenCXX/mangle-system-header.cpp b/clang/test/CodeGenCXX/mangle-system-header.cpp new file mode 100644 index 0000000..6716b58 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-system-header.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s + +// PR5420 + +# 1 "fake_system_header.h" 1 3 4 +// CHECK: define void @_ZdlPvS_( +void operator delete (void*, void*) {} + +// PR6217 +// CHECK: define void @_Z3barv() +void bar() { } diff --git a/clang/test/CodeGenCXX/mangle-template.cpp b/clang/test/CodeGenCXX/mangle-template.cpp new file mode 100644 index 0000000..05c3a58 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-template.cpp @@ -0,0 +1,172 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s +namespace test1 { +int x; +template <int& D> class T { }; +// CHECK: void @_ZN5test12f0ENS_1TILZNS_1xEEEE( +void f0(T<x> a0) {} +} + +namespace test1 { +// CHECK: void @_ZN5test12f0Ef +void f0(float) {} +template<void (&)(float)> struct t1 {}; +// CHECK: void @_ZN5test12f1ENS_2t1ILZNS_2f0EfEEE( +void f1(t1<f0> a0) {} +} + +namespace test2 { +// CHECK: void @_ZN5test22f0Ef +void f0(float) {} +template<void (*)(float)> struct t1 {}; +// FIXME: Fails because we don't treat as an expression. +// CHECK-FIXME: void @_ZN5test22f1ENS_2t1IXadL_ZNS_2f0EfEEEE( +void f1(t1<f0> a0) {} +} + +namespace test3 { +// CHECK: void @test3_f0 +extern "C" void test3_f0(float) {} +template<void (&)(float)> struct t1 {}; +// FIXME: Fails because we tack on a namespace. +// CHECK-FIXME: void @_ZN5test32f1ENS_2t1ILZ8test3_f0EEE( +void f1(t1<test3_f0> a0) {} +} + +namespace test4 { +// CHECK: void @test4_f0 +extern "C" void test4_f0(float) {} +template<void (*)(float)> struct t1 {}; +// FIXME: Fails because we don't treat as an expression. +// CHECK-FIXME: void @_ZN5test42f1ENS_2t1IXadL_Z8test4_f0EEEE( +void f1(t1<test4_f0> a0) {} +} + +// CHECK: void @test5_f0 +extern "C" void test5_f0(float) {} +int main(int) {} + +namespace test5 { +template<void (&)(float)> struct t1 {}; +// CHECK: void @_ZN5test52f1ENS_2t1ILZ8test5_f0EEE( +void f1(t1<test5_f0> a0) {} + +template<int (&)(int)> struct t2 {}; +// CHECK: void @_ZN5test52f2ENS_2t2ILZ4mainEEE +void f2(t2<main> a0) {} +} + +// FIXME: This fails. +namespace test6 { +struct A { void im0(float); }; +// CHECK: void @_ZN5test61A3im0Ef +void A::im0(float) {} +template <void(A::*)(float)> class T { }; +// FIXME: Fails because we don't treat as an expression. +// CHECK-FAIL: void @_ZN5test62f0ENS_1TIXadL_ZNS_1A3im0EfEEEE( +void f0(T<&A::im0> a0) {} +} + +namespace test7 { + template<typename T> + struct meta { + static const unsigned value = sizeof(T); + }; + + template<unsigned> struct int_c { + typedef float type; + }; + + template<typename T> + struct X { + template<typename U> + X(U*, typename int_c<(meta<T>::value + meta<U>::value)>::type *) { } + }; + + // CHECK: define weak_odr {{.*}} @_ZN5test71XIiEC1IdEEPT_PNS_5int_cIXplL_ZNS_4metaIiE5valueEEsr4metaIS3_EE5valueEE4typeE(%"struct.test7::X"* %this, double*, float*) unnamed_addr + template X<int>::X(double*, float*); +} + +namespace test8 { + template<typename T> + struct meta { + struct type { + static const unsigned value = sizeof(T); + }; + }; + + template<unsigned> struct int_c { + typedef float type; + }; + + template<typename T> + void f(int_c<meta<T>::type::value>) { } + + // CHECK: define weak_odr void @_ZN5test81fIiEEvNS_5int_cIXsr4metaIT_E4typeE5valueEEE + template void f<int>(int_c<sizeof(int)>); +} + +namespace test9 { + template<typename T> + struct supermeta { + template<typename U> + struct apply { + typedef T U::*type; + }; + }; + + struct X { }; + + template<typename T, typename U> + typename supermeta<T>::template apply<U>::type f(); + + void test_f() { + // CHECK: @_ZN5test91fIiNS_1XEEENS_9supermetaIT_E5applyIT0_E4typeEv() + // Note: GCC incorrectly mangles this as + // _ZN5test91fIiNS_1XEEENS_9supermetaIT_E5apply4typeEv, while EDG + // gets it right. + f<int, X>(); + } +} + +namespace test10 { + template<typename T> + struct X { + template<typename U> + struct definition { + }; + }; + + // CHECK: _ZN6test101fIidEENS_1XIT_E10definitionIT0_EES2_S5_ + template<typename T, typename U> + typename X<T>::template definition<U> f(T, U) { } + + void g(int i, double d) { + f(i, d); + } +} + +// Report from Jason Merrill on cxx-abi-dev, 2012.01.04. +namespace test11 { + int cmp(char a, char b); + template <typename T, int (*cmp)(T, T)> struct A {}; + template <typename T> void f(A<T,cmp> &) {} + template void f<char>(A<char,cmp> &); + // CHECK: @_ZN6test111fIcEEvRNS_1AIT_L_ZNS_3cmpEccEEE( +} + +namespace test12 { + // Make sure we can mangle non-type template args with internal linkage. + static int f(); + const int n = 10; + template<typename T, T v> void test() {} + void use() { + // CHECK: define internal void @_ZN6test124testIFivEXadL_ZNS_L1fEvEEEEvv( + test<int(), &f>(); + // CHECK: define internal void @_ZN6test124testIRFivEXadL_ZNS_L1fEvEEEEvv( + test<int(&)(), f>(); + // CHECK: define internal void @_ZN6test124testIPKiXadL_ZNS_L1nEEEEEvv( + test<const int*, &n>(); + // CHECK: define internal void @_ZN6test124testIRKiXadL_ZNS_L1nEEEEEvv( + test<const int&, n>(); + } +} diff --git a/clang/test/CodeGenCXX/mangle-this-cxx11.cpp b/clang/test/CodeGenCXX/mangle-this-cxx11.cpp new file mode 100644 index 0000000..f9e9479 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-this-cxx11.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s + +struct B { + template <class U> U f(); +}; + +struct A { + B b; + // implicitly rewritten to (*this).b.f<U>() + template <class U> auto f() -> decltype (b.f<U>()); + template <class U> auto g() -> decltype (this->b.f<U>()); +}; + +int main() { + A a; + // CHECK: call i32 @_ZN1A1fIiEEDTcldtdtdefpT1b1fIT_EEEv + a.f<int>(); + // CHECK: call i32 @_ZN1A1gIiEEDTcldtptfpT1b1fIT_EEEv + a.g<int>(); +} diff --git a/clang/test/CodeGenCXX/mangle-unnameable-conversions.cpp b/clang/test/CodeGenCXX/mangle-unnameable-conversions.cpp new file mode 100644 index 0000000..2ecded0 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-unnameable-conversions.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +template<typename T> using id = T; +struct S { + template<typename T, int N> + operator id<T[N]>&(); + template<typename T, typename U> + operator id<T (U::*)()>() const; +}; + +void f() { + int (&a)[42] = S(); // CHECK: @_ZN1ScvRAT0__T_IiLi42EEEv( + char (S::*fp)() = S(); // CHECK: @_ZNK1ScvMT0_FT_vEIcS_EEv( +}; diff --git a/clang/test/CodeGenCXX/mangle-unnamed.cpp b/clang/test/CodeGenCXX/mangle-unnamed.cpp new file mode 100644 index 0000000..53f381c --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-unnamed.cpp @@ -0,0 +1,92 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s + +struct S { + virtual ~S() { } +}; + +// PR5706 +// Make sure this doesn't crash; the mangling doesn't matter because the name +// doesn't have linkage. +static struct : S { } obj8; + +void f() { + // Make sure this doesn't crash; the mangling doesn't matter because the + // generated vtable/etc. aren't modifiable (although it would be nice for + // codesize to make it consistent inside inline functions). + static struct : S { } obj8; +} + +inline int f2() { + // FIXME: We don't mangle the names of a or x correctly! + static struct { int a() { static int x; return ++x; } } obj; + return obj.a(); +} + +int f3() { return f2(); } + +struct A { + typedef struct { int x; } *ptr; + ptr m; + int a() { + static struct x { + // FIXME: We don't mangle the names of a or x correctly! + int a(ptr A::*memp) { static int x; return ++x; } + } a; + return a.a(&A::m); + } +}; + +int f4() { return A().a(); } + +int f5() { + static union { + int a; + }; + + // CHECK: _ZZ2f5vE1a + return a; +} + +int f6() { + static union { + union { + int : 1; + }; + int b; + }; + + // CHECK: _ZZ2f6vE1b + return b; +} + +int f7() { + static union { + union { + int b; + } a; + }; + + // CHECK: _ZZ2f7vE1a + return a.b; +} + +// This used to cause an assert because the typedef-for-anonymous-tag +// code was trying to claim the enum for the template. +enum { T8 }; +template <class T> struct Test8 { + typedef T type; + Test8(type t) {} // tested later +}; +template <class T> void make_test8(T value) { Test8<T> t(value); } +void test8() { make_test8(T8); } + +// CHECK: define internal void @"_ZNV3$_35test9Ev"( +typedef volatile struct { + void test9() volatile {} +} Test9; +void test9() { + Test9 a; + a.test9(); +} + +// CHECK: define internal void @"_ZN5Test8I3$_2EC1ES0_"( diff --git a/clang/test/CodeGenCXX/mangle-variadic-templates.cpp b/clang/test/CodeGenCXX/mangle-variadic-templates.cpp new file mode 100644 index 0000000..b5bdae2 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-variadic-templates.cpp @@ -0,0 +1,67 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -triple=x86_64-apple-darwin9 -o - %s | FileCheck %s + +template<unsigned I, typename ...Types> +struct X { }; + +template<typename T> struct identity { }; +template<typename T> struct add_reference; +template<typename ...Types> struct tuple { }; +template<int ...Values> struct int_tuple { }; +template<template<typename> class ...Templates> struct template_tuple { }; + +// CHECK: define weak_odr void @_Z2f0IJEEv1XIXsZT_EJDpRT_EE +template<typename ...Types> +void f0(X<sizeof...(Types), Types&...>) { } + +template void f0(X<0>); + +// CHECK: define weak_odr void @_Z2f0IJifdEEv1XIXsZT_EJDpRT_EE +template void f0<int, float, double>(X<3, int&, float&, double&>); + +// Mangling for template argument packs +template<typename ...Types> void f1() {} +// CHECK: define weak_odr void @_Z2f1IJEEvv +template void f1<>(); +// CHECK: define weak_odr void @_Z2f1IJiEEvv +template void f1<int>(); +// CHECK: define weak_odr void @_Z2f1IJifEEvv +template void f1<int, float>(); + +// Mangling function parameter packs +template<typename ...Types> void f2(Types...) {} +// CHECK: define weak_odr void @_Z2f2IJEEvDpT_ +template void f2<>(); +// CHECK: define weak_odr void @_Z2f2IJiEEvDpT_ +template void f2<int>(int); +// CHECK: define weak_odr void @_Z2f2IJifEEvDpT_ +template void f2<int, float>(int, float); + +// Mangling non-trivial function parameter packs +template<typename ...Types> void f3(const Types *...) {} +// CHECK: define weak_odr void @_Z2f3IJEEvDpPKT_ +template void f3<>(); +// CHECK: define weak_odr void @_Z2f3IJiEEvDpPKT_ +template void f3<int>(const int*); +// CHECK: define weak_odr void @_Z2f3IJifEEvDpPKT_ +template void f3<int, float>(const int*, const float*); + +// Mangling of type pack expansions in a template argument +template<typename ...Types> tuple<Types...> f4() {} +// CHECK: define weak_odr void @_Z2f4IJifdEE5tupleIJDpT_EEv +template tuple<int, float, double> f4(); + +// Mangling of type pack expansions in a function type +template<typename R, typename ...ArgTypes> identity<R(ArgTypes...)> f5() {} +// CHECK: define weak_odr void @_Z2f5IiJifdEE8identityIFT_DpT0_EEv +template identity<int(int, float, double)> f5(); + +// Mangling of non-type template argument expansions +template<int ...Values> int_tuple<Values...> f6() {} +// CHECK: define weak_odr void @_Z2f6IJLi1ELi2ELi3EEE9int_tupleIJXspT_EEEv +template int_tuple<1, 2, 3> f6(); + +// Mangling of template template argument expansions +template<template<typename> class ...Templates> +template_tuple<Templates...> f7() {} +// CHECK: define weak_odr void @_Z2f7IJ8identity13add_referenceEE14template_tupleIJDpT_EEv +template template_tuple<identity, add_reference> f7(); diff --git a/clang/test/CodeGenCXX/mangle.cpp b/clang/test/CodeGenCXX/mangle.cpp new file mode 100644 index 0000000..ba1b3bf --- /dev/null +++ b/clang/test/CodeGenCXX/mangle.cpp @@ -0,0 +1,854 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 -fblocks -std=c++11 | FileCheck %s +struct X { }; +struct Y { }; + +// CHECK: @unmangled_variable = global +// CHECK: @_ZN1N1iE = global +// CHECK: @_ZZN1N1fEiiE1b = internal global +// CHECK: @_ZZN1N1gEvE1a = internal global +// CHECK: @_ZGVZN1N1gEvE1a = internal global + +//CHECK: @pr5966_i = external global +//CHECK: @_ZL8pr5966_i = internal global + +// CHECK: define zeroext i1 @_ZplRK1YRA100_P1X +bool operator+(const Y&, X* (&xs)[100]) { return false; } + +// CHECK: define void @_Z1f1s +typedef struct { int a; } s; +void f(s) { } + +// CHECK: define void @_Z1f1e +typedef enum { foo } e; +void f(e) { } + +// CHECK: define void @_Z1f1u +typedef union { int a; } u; +void f(u) { } + +// CHECK: define void @_Z1f1x +typedef struct { int a; } x,y; +void f(y) { } + +// CHECK: define void @_Z1fv +void f() { } + +// CHECK: define void @_ZN1N1fEv +namespace N { void f() { } } + +// CHECK: define void @_ZN1N1N1fEv +namespace N { namespace N { void f() { } } } + +// CHECK: define void @unmangled_function +extern "C" { namespace N { void unmangled_function() { } } } + +extern "C" { namespace N { int unmangled_variable = 10; } } + +namespace N { int i; } + +namespace N { int f(int, int) { static int b; return b; } } + +namespace N { int h(); void g() { static int a = h(); } } + +// CHECK: define void @_Z1fno +void f(__int128_t, __uint128_t) { } + +template <typename T> struct S1 {}; + +// CHECK: define void @_Z1f2S1IiE +void f(S1<int>) {} + +// CHECK: define void @_Z1f2S1IdE +void f(S1<double>) {} + +template <int N> struct S2 {}; +// CHECK: define void @_Z1f2S2ILi100EE +void f(S2<100>) {} + +// CHECK: define void @_Z1f2S2ILin100EE +void f(S2<-100>) {} + +template <bool B> struct S3 {}; + +// CHECK: define void @_Z1f2S3ILb1EE +void f(S3<true>) {} + +// CHECK: define void @_Z1f2S3ILb0EE +void f(S3<false>) {} + +struct S; + +// CHECK: define void @_Z1fM1SKFvvE +void f(void (S::*)() const) {} + +// CHECK: define void @_Z1fM1SFvvE +void f(void (S::*)()) {} + +// CHECK: define void @_Z1fi +void f(const int) { } + +template<typename T, typename U> void ft1(U u, T t) { } + +template<typename T> void ft2(T t, void (*)(T), void (*)(T)) { } + +template<typename T, typename U = S1<T> > struct S4 { }; +template<typename T> void ft3(S4<T>*) { } + +namespace NS { + template<typename T> void ft1(T) { } +} + +void g1() { + // CHECK: @_Z3ft1IidEvT0_T_ + ft1<int, double>(1, 0); + + // CHECK: @_Z3ft2IcEvT_PFvS0_ES2_ + ft2<char>(1, 0, 0); + + // CHECK: @_Z3ft3IiEvP2S4IT_2S1IS1_EE + ft3<int>(0); + + // CHECK: @_ZN2NS3ft1IiEEvT_ + NS::ft1<int>(1); +} + +// Expressions +template<int I> struct S5 { }; + +template<int I> void ft4(S5<I>) { } +void g2() { + // CHECK: @_Z3ft4ILi10EEv2S5IXT_EE + ft4(S5<10>()); + + // CHECK: @_Z3ft4ILi20EEv2S5IXT_EE + ft4(S5<20>()); +} + +extern "C++" { + // CHECK: @_Z1hv + void h() { } +} + +// PR5019 +extern "C" { struct a { int b; }; } + +// CHECK: @_Z1fP1a +int f(struct a *x) { + return x->b; +} + +// PR5017 +extern "C" { +struct Debug { + const Debug& operator<< (unsigned a) const { return *this; } +}; +Debug dbg; +// CHECK: @_ZNK5DebuglsEj +int main(void) { dbg << 32 ;} +} + +template<typename T> struct S6 { + typedef int B; +}; + +template<typename T> void ft5(typename S6<T>::B) { } +// CHECK: @_Z3ft5IiEvN2S6IT_E1BE +template void ft5<int>(int); + +template<typename T> class A {}; + +namespace NS { +template<typename T> bool operator==(const A<T>&, const A<T>&) { return true; } +} + +// CHECK: @_ZN2NSeqIcEEbRK1AIT_ES5_ +template bool NS::operator==(const ::A<char>&, const ::A<char>&); + +namespace std { +template<typename T> bool operator==(const A<T>&, const A<T>&) { return true; } +} + +// CHECK: @_ZSteqIcEbRK1AIT_ES4_ +template bool std::operator==(const ::A<char>&, const ::A<char>&); + +struct S { + typedef int U; +}; + +template <typename T> typename T::U ft6(const T&) { return 0; } + +// CHECK: @_Z3ft6I1SENT_1UERKS1_ +template int ft6<S>(const S&); + +template<typename> struct __is_scalar_type { + enum { __value = 1 }; +}; + +template<bool, typename> struct __enable_if { }; + +template<typename T> struct __enable_if<true, T> { + typedef T __type; +}; + +// PR5063 +template<typename T> typename __enable_if<__is_scalar_type<T>::__value, void>::__type ft7() { } + +// CHECK: @_Z3ft7IiEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv +template void ft7<int>(); +// CHECK: @_Z3ft7IPvEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv +template void ft7<void*>(); + +// PR5144 +extern "C" { +void extern_f(void); +}; + +// CHECK: @extern_f +void extern_f(void) { } + +struct S7 { + S7(); + + struct S { S(); }; + struct { + S s; + } a; +}; + +// PR5139 +// CHECK: @_ZN2S7C1Ev +// CHECK: @_ZN2S7C2Ev +// CHECK: @"_ZN2S73$_0C1Ev" +S7::S7() {} + +// PR5063 +template<typename T> typename __enable_if<(__is_scalar_type<T>::__value), void>::__type ft8() { } +// CHECK: @_Z3ft8IiEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv +template void ft8<int>(); +// CHECK: @_Z3ft8IPvEN11__enable_ifIXsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv +template void ft8<void*>(); + +// PR5796 +namespace PR5796 { +template<typename> struct __is_scalar_type { + enum { __value = 0 }; +}; + +template<bool, typename> struct __enable_if {}; +template<typename T> struct __enable_if<true, T> { typedef T __type; }; +template<typename T> + +// CHECK: define linkonce_odr void @_ZN6PR57968__fill_aIiEENS_11__enable_ifIXntsr16__is_scalar_typeIT_EE7__valueEvE6__typeEv +typename __enable_if<!__is_scalar_type<T>::__value, void>::__type __fill_a() { }; + +void f() { __fill_a<int>(); } +} + +namespace Expressions { +// Unary operators. + +// CHECK: define weak_odr void @_ZN11Expressions2f1ILi1EEEvPAplngT_Li2E_i +template <int i> void f1(int (*)[(-i) + 2]) { }; +template void f1<1>(int (*)[1]); + +// CHECK: define weak_odr void @_ZN11Expressions2f2ILi1EEEvPApsT__i +template <int i> void f2(int (*)[+i]) { }; +template void f2<1>(int (*)[1]); + +// Binary operators. + +// CHECK: define weak_odr void @_ZN11Expressions2f3ILi1EEEvPAplT_T__i +template <int i> void f3(int (*)[i+i]) { }; +template void f3<1>(int (*)[2]); + +// CHECK: define weak_odr void @_ZN11Expressions2f4ILi1EEEvPAplplLi2ET_T__i +template <int i> void f4(int (*)[2 + i+i]) { }; +template void f4<1>(int (*)[4]); + +// The ternary operator. +// CHECK: define weak_odr void @_ZN11Expressions2f4ILb1EEEvPAquT_Li1ELi2E_i +template <bool b> void f4(int (*)[b ? 1 : 2]) { }; +template void f4<true>(int (*)[1]); +} + +struct Ops { + Ops& operator+(const Ops&); + Ops& operator-(const Ops&); + Ops& operator&(const Ops&); + Ops& operator*(const Ops&); + + void *v; +}; + +// CHECK: define %struct.Ops* @_ZN3OpsplERKS_ +Ops& Ops::operator+(const Ops&) { return *this; } +// CHECK: define %struct.Ops* @_ZN3OpsmiERKS_ +Ops& Ops::operator-(const Ops&) { return *this; } +// CHECK: define %struct.Ops* @_ZN3OpsanERKS_ +Ops& Ops::operator&(const Ops&) { return *this; } +// CHECK: define %struct.Ops* @_ZN3OpsmlERKS_ +Ops& Ops::operator*(const Ops&) { return *this; } + +// PR5861 +namespace PR5861 { +template<bool> class P; +template<> class P<true> {}; + +template<template <bool> class, bool> +struct Policy { }; + +template<typename T, typename = Policy<P, true> > class Alloc +{ + T *allocate(int, const void*) { return 0; } +}; + +// CHECK: define weak_odr i8* @_ZN6PR58615AllocIcNS_6PolicyINS_1PELb1EEEE8allocateEiPKv +template class Alloc<char>; +} + +// CHECK: define void @_Z1fU13block_pointerFiiiE +void f(int (^)(int, int)) { } + +void pr5966_foo() { + extern int pr5966_i; + pr5966_i = 0; +} + +static int pr5966_i; + +void pr5966_bar() { + pr5966_i = 0; +} + +namespace test0 { + int ovl(int x); + char ovl(double x); + + template <class T> void f(T, char (&buffer)[sizeof(ovl(T()))]) {} + + void test0() { + char buffer[1]; + f(0.0, buffer); + } + // CHECK: define void @_ZN5test05test0Ev() + // CHECK: define linkonce_odr void @_ZN5test01fIdEEvT_RAszcl3ovlcvS1__EE_c( + + void test1() { + char buffer[sizeof(int)]; + f(1, buffer); + } + // CHECK: define void @_ZN5test05test1Ev() + // CHECK: define linkonce_odr void @_ZN5test01fIiEEvT_RAszcl3ovlcvS1__EE_c( + + template <class T> void g(char (&buffer)[sizeof(T() + 5.0f)]) {} + void test2() { + char buffer[sizeof(float)]; + g<float>(buffer); + } + // CHECK: define linkonce_odr void @_ZN5test01gIfEEvRAszplcvT__ELf40a00000E_c( + + template <class T> void h(char (&buffer)[sizeof(T() + 5.0)]) {} + void test3() { + char buffer[sizeof(double)]; + h<float>(buffer); + } + // CHECK: define linkonce_odr void @_ZN5test01hIfEEvRAszplcvT__ELd4014000000000000E_c( + + template <class T> void j(char (&buffer)[sizeof(T().buffer)]) {} + struct A { double buffer[128]; }; + void test4() { + char buffer[1024]; + j<A>(buffer); + } + // CHECK: define linkonce_odr void @_ZN5test01jINS_1AEEEvRAszdtcvT__E6buffer_c( + + template <class T> void k(char (&buffer)[sizeof(T() + 0.0f)]) {} + void test5() { + char buffer[sizeof(float)]; + k<float>(buffer); + } + // CHECK: define linkonce_odr void @_ZN5test01kIfEEvRAszplcvT__ELf00000000E_c( + +} + +namespace test1 { + template<typename T> struct X { }; + template<template<class> class Y, typename T> void f(Y<T>) { } + // CHECK: define weak_odr void @_ZN5test11fINS_1XEiEEvT_IT0_E + template void f(X<int>); +} + +// CHECK: define internal void @_ZL27functionWithInternalLinkagev() +static void functionWithInternalLinkage() { } +void g() { functionWithInternalLinkage(); } + +namespace test2 { + template <class T> decltype(((T*) 0)->member) read_member(T& obj) { + return obj.member; + } + + struct A { int member; } obj; + int test() { + return read_member(obj); + } + + // CHECK: define linkonce_odr i32 @_ZN5test211read_memberINS_1AEEEDtptcvPT_Li0E6memberERS2_( +} + +// rdar://problem/9280586 +namespace test3 { + struct AmbiguousBase { int ab; }; + struct Path1 : AmbiguousBase { float p; }; + struct Path2 : AmbiguousBase { double p; }; + struct Derived : Path1, Path2 { }; + + // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E2abERS2_( + template <class T> decltype(((T*) 0)->Path1::ab) get_ab_1(T &ref) { return ref.Path1::ab; } + + // CHECK: define linkonce_odr i32 @_ZN5test38get_ab_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E2abERS2_( + template <class T> decltype(((T*) 0)->Path2::ab) get_ab_2(T &ref) { return ref.Path2::ab; } + + // CHECK: define linkonce_odr float @_ZN5test37get_p_1INS_7DerivedEEEDtptcvPT_Li0Esr5Path1E1pERS2_( + template <class T> decltype(((T*) 0)->Path1::p) get_p_1(T &ref) { return ref.Path1::p; } + + // CHECK: define linkonce_odr double @_ZN5test37get_p_2INS_7DerivedEEEDtptcvPT_Li0Esr5Path2E1pERS2_( + template <class T> decltype(((T*) 0)->Path2::p) get_p_2(T &ref) { return ref.Path2::p; } + + Derived obj; + void test() { + get_ab_1(obj); + get_ab_2(obj); + get_p_1(obj); + get_p_2(obj); + } +} + +// CHECK: define void @_ZN5test41gEPNS_3zedIXadL_ZNS_3foo3barEEEEE +namespace test4 { + struct foo { int bar; }; + template <int (foo::*)> + struct zed {}; + void g(zed<&foo::bar>*) + {} +} +// CHECK: define void @_ZN5test51gEPNS_3zedIXadL_ZNS_3foo3barEEEEE +namespace test5 { + struct foo { static int bar; }; + template <int *> + struct zed {}; + void g(zed<&foo::bar>*) + {} +} +// CHECK: define void @_ZN5test61gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE +namespace test6 { + struct foo { int bar(); }; + template <int (foo::*)()> + struct zed {}; + void g(zed<&foo::bar>*) + {} +} +// CHECK: define void @_ZN5test71gEPNS_3zedIXadL_ZNS_3foo3barEvEEEE +namespace test7 { + struct foo { static int bar(); }; + template <int (*f)()> + struct zed {}; + void g(zed<&foo::bar>*) + {} +} +// CHECK: define weak_odr void @_ZN5test81AILZNS_1B5valueEEE3incEv +namespace test8 { + template <int &counter> class A { void inc() { counter++; } }; + class B { public: static int value; }; + template class A<B::value>; +} +// CHECK: declare void @_ZN5test91fIiNS_3barEEEvRKNT0_3baz1XE +namespace test9 { + template<class T> + struct foo { + typedef T X; + }; + struct bar { + typedef foo<int> baz; + }; + template <class zaz, class zed> + void f(const typename zed::baz::X&); + void g() { + f<int, bar>( 0); + } +} + +// <rdar://problem/7825453> +namespace test10 { + template <char P1> struct S {}; + template <char P2> void f(struct S<false ? 'a' : P2> ) {} + + // CHECK: define weak_odr void @_ZN6test101fILc3EEEvNS_1SIXquLb0ELc97ET_EEE( + template void f<(char) 3>(struct S<3>); +} + +namespace test11 { + // CHECK: @_ZN6test111fEz + void f(...) { } + + struct A { + void f(...); + }; + + // CHECK: @_ZN6test111A1fEz + void A::f(...) { } +} + +namespace test12 { + + // CHECK: _ZN6test121fENS_1AILt33000EEE + template <unsigned short> struct A { }; + void f(A<33000>) { } +} + +// PR7446 +namespace test13 { + template <template <class> class T> class A {}; + template <class U> class B {}; + + template <template<class> class T> void foo(const A<T> &a) {} + + // CHECK: define weak_odr void @_ZN6test133fooINS_1BEEEvRKNS_1AIT_EE( + template void foo(const A<B> &a); +} + +namespace test14 { + extern "C" { + struct S { + static int a(), x; + }; + // CHECK: define i32 @_ZN6test141S1aEv + // CHECK: load i32* @_ZN6test141S1xE + int S::a() { return S::x; } + } +} + +// rdar://problem/8204122 +namespace test15 { + enum E { e = 3 }; + template <int I> struct S {}; + + template <int I> void f(S<I + e>) {} + + // CHECK: define weak_odr void @_ZN6test151fILi7EEEvNS_1SIXplT_LNS_1EE3EEEE( + template void f<7>(S<7 + e>); +} + +// rdar://problem/8302148 +namespace test17 { + template <int N> struct A {}; + + struct B { + static int foo(void); + }; + + template <class T> A<sizeof(T::foo())> func(void); + + // CHECK: define void @_ZN6test174testEv() + // CHECK: call {{.*}} @_ZN6test174funcINS_1BEEENS_1AIXszclsrT_3fooEEEEv() + void test() { + func<B>(); + } +} + +// PR7891 +namespace test18 { + struct A { + int operator+(); + int operator-(); + int operator*(); + int operator&(); + }; + template <int (A::*)()> struct S {}; + + template <typename T> void f(S<&T::operator+>) {} + template void f<A>(S<&A::operator+>); + + template <typename T> void f(S<&T::operator- >) {} + template void f<A>(S<&A::operator- >); + + template <typename T> void f(S<&T::operator*>) {} + template void f<A>(S<&A::operator*>); + + template <typename T> void f(S<&T::operator&>) {} + template void f<A>(S<&A::operator&>); + + // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_plEEE + // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_miEEE + // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_mlEEE + // CHECK: define weak_odr void @_ZN6test181fINS_1AEEEvNS_1SIXadsrT_anEEE +} + +// rdar://problem/8332117 +namespace test19 { + struct A { + template <typename T> int f(); + int operator+(); + operator int(); + template <typename T> int operator-(); + }; + + template <int (A::*)()> struct S {}; + + template <typename T> void g (S<&T::template f<int> >) {} + template <typename T> void g (S<&T::operator+ >) {} + template <typename T> void g (S<&T::operator int>) {} + template <typename T> void g (S<&T::template operator- <double> >) {} + + // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_1fIiEEEE( + template void g<A>(S<&A::f<int> >); + // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_plEEE( + template void g<A>(S<&A::operator+>); + // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_cviEEE( + template void g<A>(S<&A::operator int>); + // CHECK: define weak_odr void @_ZN6test191gINS_1AEEEvNS_1SIXadsrT_miIdEEEE( + template void g<A>(S<&A::operator-<double> >); +} + +namespace test20 { + template <class T> T *f(const T&); + template <class T> T *f(T*); + + // CHECK: define weak_odr void @_ZN6test205test0IiEEvDTcl1fIPT_ELi0EEE( + template <class T> void test0(decltype(f<T*>(0))) {} + template void test0<int>(decltype(f<int*>(0))); + + // CHECK: define weak_odr void @_ZN6test205test1IiEEvDTcl1fIEcvT__EEE( + template <class T> void test1(decltype(f<>(T()))) {} + template void test1<int>(decltype(f<>(int()))); +} + +// rdar:// 8620510 +namespace test21 { + // CHECK: define void @_ZN6test2112vla_arg_funcEiPA_i( + void vla_arg_func(int X, int a[X][X]) {} +} + +namespace test22 { + // CHECK: define void @_ZN6test221fEDn( + void f(decltype(nullptr)) { } +} + +// rdar://problem/8913416 +namespace test23 { + typedef void * const vpc; + + // CHECK: define void @_ZN6test231fERA10_KPv( + void f(vpc (&)[10]) {} + + typedef vpc vpca5[5]; + void f(vpca5 volatile (&)[10]) {} + // CHECK: define void @_ZN6test231fERA10_A5_VKPv( +} + +namespace test24 { + void test0() { + extern int foo(); + // CHECK: call i32 @_ZN6test243fooEv() + foo(); + } + + static char foo() {} + void test1() { + // CHECK: call signext i8 @_ZN6test24L3fooEv() + foo(); + } +} + +// rdar://problem/8806641 +namespace test25 { + template <void (*fn)()> struct A { + static void call() { fn(); } + }; + void foo(); + void test() { + // CHECK: call void @_ZN6test251AIXadL_ZNS_3fooEvEEE4callEv() + A<foo>::call(); + } +} + +namespace test26 { + template <template <class> class T> void foo(decltype(T<float>::object) &object) {} + + template <class T> struct holder { static T object; }; + + void test() { + float f; + + // CHECK: call void @_ZN6test263fooINS_6holderEEEvRDtsrT_IfE6objectE( + foo<holder>(f); + } +} + +namespace test27 { + struct A { + struct inner { + float object; + }; + + float meth(); + }; + typedef A Alias; + + template <class T> void a(decltype(T::inner::object) &object) {} + template <class T> void b(decltype(T().Alias::meth()) &object) {} + + void test() { + float f; + // CHECK: call void @_ZN6test271aINS_1AEEEvRDtsrNT_5innerE6objectE( + a<A>(f); + // CHECK: call void @_ZN6test271bINS_1AEEEvRDTcldtcvT__Esr5AliasE4methEE( + b<A>(f); + } +} + +// An injected class name type in a unresolved-name. +namespace test28 { + template <class T> struct A { + enum { bit }; + }; + + template <class T> void foo(decltype(A<T>::A::bit) x); + + void test() { + foo<char>(A<char>::bit); + // CHECK: call void @_ZN6test283fooIcEEvDtsr1AIT_E1AE3bitE( + } +} + +// An enclosing template type parameter in an unresolved-name. +namespace test29 { + template <class T> struct A { + template <class U> static void foo(decltype(T::fn(U())) x); + }; + struct B { static int fn(int); static long fn(long); }; + + void test() { + A<B>::foo<int>(0); + // CHECK: call void @_ZN6test291AINS_1BEE3fooIiEEvDTclsrS1_2fncvT__EEE( + } +} + +// An enclosing template template parameter in an unresolved-name. +namespace test30 { + template <template <class> class T> struct A { + template <class U> static void foo(decltype(T<U>::fn()) x); + }; + template <class T> struct B { static T fn(); }; + + void test() { + A<B>::foo<int>(0); + // CHECK: call void @_ZN6test301AINS_1BEE3fooIiEEvDTclsrS1_IT_EE2fnEE( + } +} + +namespace test31 { // instantiation-dependent mangling of decltype + int x; + template<class T> auto f1(T p)->decltype(x) { return 0; } + // The return type in the mangling of the template signature + // is encoded as "i". + template<class T> auto f2(T p)->decltype(p) { return 0; } + // The return type in the mangling of the template signature + // is encoded as "Dtfp_E". + void g(int); + template<class T> auto f3(T p)->decltype(g(p)) {} + + // CHECK: define weak_odr i32 @_ZN6test312f1IiEEiT_( + template int f1(int); + // CHECK: define weak_odr i32 @_ZN6test312f2IiEEDtfp_ET_ + template int f2(int); + // CHECK: define weak_odr void @_ZN6test312f3IiEEDTcl1gfp_EET_ + template void f3(int); +} + +// PR10205 +namespace test32 { + template<typename T, int=T::value> struct A { + typedef int type; + }; + struct B { enum { value = 4 }; }; + + template <class T> typename A<T>::type foo() { return 0; } + void test() { + foo<B>(); + // CHECK: call i32 @_ZN6test323fooINS_1BEEENS_1AIT_XsrS3_5valueEE4typeEv() + } +} + +namespace test33 { + template <class T> struct X { + enum { value = T::value }; + }; + + template<typename T, int=X<T>::value> struct A { + typedef int type; + }; + struct B { enum { value = 4 }; }; + + template <class T> typename A<T>::type foo() { return 0; } + + void test() { + foo<B>(); + // CHECK: call i32 @_ZN6test333fooINS_1BEEENS_1AIT_Xsr1XIS3_EE5valueEE4typeEv() + } +} + +namespace test34 { + // Mangling for instantiation-dependent decltype expressions. + template<typename T> + void f(decltype(sizeof(decltype(T() + T())))) {} + + // CHECK: define weak_odr void @_ZN6test341fIiEEvDTstDTplcvT__EcvS1__EEE + template void f<int>(decltype(sizeof(1))); + + // Mangling for non-instantiation-dependent sizeof expressions. + template<unsigned N> + void f2(int (&)[N + sizeof(int*)]) {} + + // CHECK: define weak_odr void @_ZN6test342f2ILj4EEEvRAplT_Lm8E_i + template void f2<4>(int (&)[4 + sizeof(int*)]); + + // Mangling for non-instantiation-dependent sizeof expressions + // involving an implicit conversion of the result of the sizeof. + template<unsigned long long N> + void f3(int (&)[N + sizeof(int*)]) {} + + // CHECK: define weak_odr void @_ZN6test342f3ILy4EEEvRAplT_Ly8E_i + template void f3<4>(int (&)[4 + sizeof(int*)]); + + // Mangling for instantiation-dependent sizeof() expressions as + // template arguments. + template<unsigned> struct A { }; + + template<typename T> void f4(::test34::A<sizeof(sizeof(decltype(T() + T())))>) { } + + // CHECK: define weak_odr void @_ZN6test342f4IiEEvNS_1AIXszstDTplcvT__EcvS2__EEEEE + template void f4<int>(A<sizeof(sizeof(int))>); +} + +namespace test35 { + // Dependent operator names of unknown arity. + struct A { + template<typename U> A operator+(U) const; + }; + + template<typename T> + void f1(decltype(sizeof(&T::template operator+<int>))) {} + + // CHECK: define weak_odr void @_ZN6test352f1INS_1AEEEvDTszadsrT_plIiEE + template void f1<A>(__SIZE_TYPE__); +} + +namespace test36 { + template<unsigned> struct A { }; + + template<typename ...Types> + auto f1(Types... values) -> A<sizeof...(values)> { } + + // CHECK: define weak_odr {{.*}} @_ZN6test362f1IJifEEENS_1AIXsZfp_EEEDpT_ + template A<2> f1(int, float); +} diff --git a/clang/test/CodeGenCXX/member-alignment.cpp b/clang/test/CodeGenCXX/member-alignment.cpp new file mode 100644 index 0000000..8e120f7 --- /dev/null +++ b/clang/test/CodeGenCXX/member-alignment.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s +// XFAIL: arm,powerpc + +// rdar://7268289 + +class t { +public: + virtual void foo(void); + void bar(void); +}; + +void +t::bar(void) { +// CHECK: _ZN1t3barEv{{.*}} align 2 +} + +void +t::foo(void) { +// CHECK: _ZN1t3fooEv{{.*}} align 2 +} diff --git a/clang/test/CodeGenCXX/member-call-parens.cpp b/clang/test/CodeGenCXX/member-call-parens.cpp new file mode 100644 index 0000000..2054137 --- /dev/null +++ b/clang/test/CodeGenCXX/member-call-parens.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm-only -verify %s + +struct A { int a(); }; +typedef int B; +void a() { + A x; + ((x.a))(); + ((x.*&A::a))(); + B y; + // FIXME: Sema doesn't like this for some reason... + //(y.~B)(); +} diff --git a/clang/test/CodeGenCXX/member-expressions.cpp b/clang/test/CodeGenCXX/member-expressions.cpp new file mode 100644 index 0000000..d9fb394 --- /dev/null +++ b/clang/test/CodeGenCXX/member-expressions.cpp @@ -0,0 +1,86 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 | FileCheck %s + +// PR5392 +namespace PR5392 { +struct A +{ + static int a; +}; + +A a1; +void f() +{ + // CHECK: store i32 10, i32* @_ZN6PR53921A1aE + a1.a = 10; + // CHECK: store i32 20, i32* @_ZN6PR53921A1aE + A().a = 20; +} + +} + +struct A { + A(); + ~A(); + enum E { Foo }; +}; + +A *g(); + +void f(A *a) { + A::E e1 = a->Foo; + + // CHECK: call %struct.A* @_Z1gv() + A::E e2 = g()->Foo; + // CHECK: call void @_ZN1AC1Ev( + // CHECK: call void @_ZN1AD1Ev( + A::E e3 = A().Foo; +} + +namespace test3 { +struct A { + static int foo(); +}; +int f() { + return A().foo(); +} +} + +namespace test4 { + struct A { + int x; + }; + struct B { + int x; + void foo(); + }; + struct C : A, B { + }; + + extern C *c_ptr; + + // CHECK: define i32 @_ZN5test44testEv() + int test() { + // CHECK: load {{.*}} @_ZN5test45c_ptrE + // CHECK-NEXT: bitcast + // CHECK-NEXT: getelementptr + // CHECK-NEXT: bitcast + // CHECK-NEXT: call void @_ZN5test41B3fooEv + c_ptr->B::foo(); + + // CHECK: load {{.*}} @_ZN5test45c_ptrE + // CHECK-NEXT: bitcast + // CHECK-NEXT: getelementptr + // CHECK-NEXT: bitcast + // CHECK-NEXT: getelementptr + // CHECK-NEXT: store i32 5 + c_ptr->B::x = 5; + + // CHECK: load {{.*}} @_ZN5test45c_ptrE + // CHECK-NEXT: bitcast + // CHECK-NEXT: getelementptr + // CHECK-NEXT: bitcast + // CHECK-NEXT: getelementptr + // CHECK-NEXT: load i32* + return c_ptr->B::x; + } +} diff --git a/clang/test/CodeGenCXX/member-function-pointer-calls.cpp b/clang/test/CodeGenCXX/member-function-pointer-calls.cpp new file mode 100644 index 0000000..f8960aa --- /dev/null +++ b/clang/test/CodeGenCXX/member-function-pointer-calls.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s +struct A { + virtual int vf1() { return 1; } + virtual int vf2() { return 2; } +}; + +int f(A* a, int (A::*fp)()) { + return (a->*fp)(); +} + +// CHECK: define i32 @_Z2g1v() +// CHECK: ret i32 1 +int g1() { + A a; + return f(&a, &A::vf1); +} + +// CHECK: define i32 @_Z2g2v() +// CHECK: ret i32 2 +int g2() { + A a; + return f(&a, &A::vf2); +} diff --git a/clang/test/CodeGenCXX/member-function-pointers.cpp b/clang/test/CodeGenCXX/member-function-pointers.cpp new file mode 100644 index 0000000..2417aa4 --- /dev/null +++ b/clang/test/CodeGenCXX/member-function-pointers.cpp @@ -0,0 +1,274 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin9 | FileCheck %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-apple-darwin9 | FileCheck -check-prefix LP32 %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-unknown | FileCheck -check-prefix ARM %s + +struct A { int a; void f(); virtual void vf1(); virtual void vf2(); }; +struct B { int b; virtual void g(); }; +struct C : B, A { }; + +void (A::*pa)(); +void (A::*volatile vpa)(); +void (B::*pb)(); +void (C::*pc)(); + +// CHECK: @pa2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }, align 8 +void (A::*pa2)() = &A::f; + +// CHECK: @pa3 = global { i64, i64 } { i64 1, i64 0 }, align 8 +// CHECK-LP32: @pa3 = global { i32, i32 } { i32 1, i32 0 }, align 4 +void (A::*pa3)() = &A::vf1; + +// CHECK: @pa4 = global { i64, i64 } { i64 9, i64 0 }, align 8 +// CHECK-LP32: @pa4 = global { i32, i32 } { i32 5, i32 0 }, align 4 +void (A::*pa4)() = &A::vf2; + +// CHECK: @pc2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 16 }, align 8 +void (C::*pc2)() = &C::f; + +// CHECK: @pc3 = global { i64, i64 } { i64 1, i64 0 }, align 8 +void (A::*pc3)() = &A::vf1; + +// Tests for test10. +// CHECK: @_ZN6test101aE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 0 }, align 8 +// CHECK: @_ZN6test101bE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8 +// CHECK: @_ZN6test101cE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8 +// CHECK: @_ZN6test101dE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 16 }, align 8 +// CHECK-LP32: @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4 +// CHECK-LP32: @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4 +// CHECK-LP32: @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4 +// CHECK-LP32: @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 + +void f() { + // CHECK: store { i64, i64 } zeroinitializer, { i64, i64 }* @pa + pa = 0; + + // Is this okay? What are LLVM's volatile semantics for structs? + // CHECK: store volatile { i64, i64 } zeroinitializer, { i64, i64 }* @vpa + vpa = 0; + + // CHECK: [[TMP:%.*]] = load { i64, i64 }* @pa, align 8 + // CHECK: [[TMPADJ:%.*]] = extractvalue { i64, i64 } [[TMP]], 1 + // CHECK: [[ADJ:%.*]] = add nsw i64 [[TMPADJ]], 16 + // CHECK: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1 + // CHECK: store { i64, i64 } [[RES]], { i64, i64 }* @pc, align 8 + pc = pa; + + // CHECK: [[TMP:%.*]] = load { i64, i64 }* @pc, align 8 + // CHECK: [[TMPADJ:%.*]] = extractvalue { i64, i64 } [[TMP]], 1 + // CHECK: [[ADJ:%.*]] = sub nsw i64 [[TMPADJ]], 16 + // CHECK: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1 + // CHECK: store { i64, i64 } [[RES]], { i64, i64 }* @pa, align 8 + pa = static_cast<void (A::*)()>(pc); +} + +void f2() { + // CHECK: store { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 } + void (A::*pa2)() = &A::f; + + // CHECK: store { i64, i64 } { i64 1, i64 0 } + // CHECK-LP32: store { i32, i32 } { i32 1, i32 0 } + void (A::*pa3)() = &A::vf1; + + // CHECK: store { i64, i64 } { i64 9, i64 0 } + // CHECK-LP32: store { i32, i32 } { i32 5, i32 0 } + void (A::*pa4)() = &A::vf2; +} + +void f3(A *a, A &ar) { + (a->*pa)(); + (ar.*pa)(); +} + +bool f4() { + return pa; +} + +// PR5177 +namespace PR5177 { + struct A { + bool foo(int*) const; + } a; + + struct B1 { + bool (A::*pmf)(int*) const; + const A* pa; + + B1() : pmf(&A::foo), pa(&a) {} + bool operator()() const { return (pa->*pmf)(new int); } + }; + + void bar(B1 b2) { while (b2()) ; } +} + +// PR5138 +namespace PR5138 { + struct foo { + virtual void bar(foo *); + }; + + extern "C" { + void baz(foo *); + } + + void (foo::*ptr1)(void *) = (void (foo::*)(void *))&foo::bar; + void (*ptr2)(void *) = (void (*)(void *))&baz; + + void (foo::*ptr3)(void) = (void (foo::*)(void))&foo::bar; +} + +// PR5593 +namespace PR5593 { + struct A { }; + + bool f(void (A::*f)()) { + return f && f; + } +} + +namespace PR5718 { + struct A { }; + + bool f(void (A::*f)(), void (A::*g)()) { + return f == g; + } +} + +namespace BoolMemberPointer { + struct A { }; + + bool f(void (A::*f)()) { + return !f; + } + + bool g(void (A::*f)()) { + if (!!f) + return true; + return false; + } +} + +// PR5940 +namespace PR5940 { + class foo { + public: + virtual void baz(void); + }; + + void foo::baz(void) { + void (foo::*ptr)(void) = &foo::baz; + } +} + +namespace MemberPointerImpCast { + struct A { + int x; + }; + struct B : public A { + }; + void f(B* obj, void (A::*method)()) { + (obj->*method)(); + } +} + +// PR6258 +namespace PR6258 { + + struct A { + void f(bool); + }; + + void (A::*pf)(bool) = &A::f; + + void f() { + void (A::*pf)(bool) = &A::f; + } +} + +// PR7027 +namespace PR7027 { + struct X { void test( ); }; + void testX() { &X::test; } +} + +namespace test7 { + struct A { void foo(); virtual void vfoo(); }; + struct B { void foo(); virtual void vfoo(); }; + struct C : A, B { void foo(); virtual void vfoo(); }; + + // CHECK-ARM: @_ZN5test74ptr0E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71A3fooEv to i32), i32 0 } + // CHECK-ARM: @_ZN5test74ptr1E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71B3fooEv to i32), i32 8 } + // CHECK-ARM: @_ZN5test74ptr2E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71C3fooEv to i32), i32 0 } + // CHECK-ARM: @_ZN5test74ptr3E = global {{.*}} { i32 0, i32 1 } + // CHECK-ARM: @_ZN5test74ptr4E = global {{.*}} { i32 0, i32 9 } + // CHECK-ARM: @_ZN5test74ptr5E = global {{.*}} { i32 0, i32 1 } + void (C::*ptr0)() = &A::foo; + void (C::*ptr1)() = &B::foo; + void (C::*ptr2)() = &C::foo; + void (C::*ptr3)() = &A::vfoo; + void (C::*ptr4)() = &B::vfoo; + void (C::*ptr5)() = &C::vfoo; +} + +namespace test8 { + struct X { }; + typedef int (X::*pmf)(int); + + // CHECK: {{define.*_ZN5test81fEv}} + pmf f() { + // CHECK: {{ret.*zeroinitializer}} + return pmf(); + } +} + +namespace test9 { + struct A { + void foo(); + }; + struct B : A { + void foo(); + }; + + typedef void (A::*fooptr)(); + + struct S { + fooptr p; + }; + + // CHECK: define void @_ZN5test94testEv( + // CHECK: alloca i32 + // CHECK-NEXT: ret void + void test() { + int x; + static S array[] = { (fooptr) &B::foo }; + } +} + +// rdar://problem/10815683 - Verify that we can emit reinterprets of +// member pointers as constant initializers. For added trickiness, +// we also add some non-trivial adjustments. +namespace test10 { + struct A { + int nonEmpty; + void foo(); + }; + struct B : public A { + virtual void requireNonZeroAdjustment(); + }; + struct C { + int nonEmpty; + }; + struct D : public C { + virtual void requireNonZeroAdjustment(); + }; + + // Non-ARM tests at top of file. + void (A::*a)() = &A::foo; + void (B::*b)() = (void (B::*)()) &A::foo; + void (C::*c)() = (void (C::*)()) (void (B::*)()) &A::foo; + void (D::*d)() = (void (C::*)()) (void (B::*)()) &A::foo; +} +// It's not that the offsets are doubled on ARM, it's that they're left-shifted by 1. +// CHECK-ARM: @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4 +// CHECK-ARM: @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 +// CHECK-ARM: @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4 +// CHECK-ARM: @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 16 }, align 4 diff --git a/clang/test/CodeGenCXX/member-functions.cpp b/clang/test/CodeGenCXX/member-functions.cpp new file mode 100644 index 0000000..b95763c --- /dev/null +++ b/clang/test/CodeGenCXX/member-functions.cpp @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -emit-llvm %s -triple x86_64-apple-darwin9 -o %t +struct C { + void f(); + void g(int, ...); +}; + +// RUN: grep "define void @_ZN1C1fEv" %t | count 1 +void C::f() { +} + +void test1() { + C c; + +// RUN: grep "call void @_ZN1C1fEv" %t | count 1 + c.f(); + +// RUN: grep "call void (.struct.C\*, i32, ...)\* @_ZN1C1gEiz" %t | count 1 + c.g(1, 2, 3); +} + + +struct S { + // RUN: grep "define linkonce_odr void @_ZN1SC1Ev.*unnamed_addr" %t + inline S() { } + // RUN: grep "define linkonce_odr void @_ZN1SC1Ev.*unnamed_addr" %t + inline ~S() { } + + + // RUN: grep "define linkonce_odr void @_ZN1S9f_inline1Ev" %t + void f_inline1() { } + // RUN: grep "define linkonce_odr void @_ZN1S9f_inline2Ev" %t + inline void f_inline2() { } + + // RUN: grep "define linkonce_odr void @_ZN1S1gEv" %t + static void g() { } + + static void f(); +}; + +// RUN: grep "define void @_ZN1S1fEv" %t +void S::f() { +} + +void test2() { + S s; + + s.f_inline1(); + s.f_inline2(); + + S::g(); + +} + +struct T { + T operator+(const T&); +}; + +void test3() { + T t1, t2; + + // RUN: grep "call void @_ZN1TplERKS_" %t + T result = t1 + t2; +} diff --git a/clang/test/CodeGenCXX/member-init-anon-union.cpp b/clang/test/CodeGenCXX/member-init-anon-union.cpp new file mode 100644 index 0000000..1ff7537 --- /dev/null +++ b/clang/test/CodeGenCXX/member-init-anon-union.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s + +// PR10531. + +static union { + int a = 42; + char *b; +}; + +int f() { return a; } + +// CHECK: define internal void @__cxx_global_var_init +// CHECK-NOT: } +// CHECK: call {{.*}}@"[[CONSTRUCT_GLOBAL:.*]]C1Ev" + + +int g() { + union { + int a; + int b = 81; + }; + // CHECK: define {{.*}}_Z1gv + // CHECK-NOT: } + // CHECK: call {{.*}}@"[[CONSTRUCT_LOCAL:.*]]C1Ev" + return b; +} + + +// CHECK: define {{.*}}@"[[CONSTRUCT_LOCAL]]C2Ev" +// CHECK-NOT: } +// CHECK: store i32 81 + +// CHECK: define {{.*}}@"[[CONSTRUCT_GLOBAL]]C2Ev" +// CHECK-NOT: } +// CHECK: store i32 42 diff --git a/clang/test/CodeGenCXX/member-init-assignment.cpp b/clang/test/CodeGenCXX/member-init-assignment.cpp new file mode 100644 index 0000000..84c4a36 --- /dev/null +++ b/clang/test/CodeGenCXX/member-init-assignment.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// PR7291 + +struct Foo { + unsigned file_id; + + Foo(unsigned arg); +}; + +Foo::Foo(unsigned arg) : file_id(arg = 42) +{ } + +// CHECK: define {{.*}} @_ZN3FooC2Ej(%struct.Foo* %this, i32 %arg) unnamed_addr +// CHECK: [[ARG:%.*]] = alloca i32 +// CHECK: store i32 42, i32* [[ARG]] +// CHECK: store i32 42, i32* %{{.*}} +// CHECK: ret {{void|%struct.Foo}} diff --git a/clang/test/CodeGenCXX/member-init-ctor.cpp b/clang/test/CodeGenCXX/member-init-ctor.cpp new file mode 100644 index 0000000..2172394 --- /dev/null +++ b/clang/test/CodeGenCXX/member-init-ctor.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 %s -std=c++11 -emit-llvm -o - | FileCheck %s + +bool b(); +struct S { + int n = b() ? S().n + 1 : 0; +}; + +S s; + +// CHECK: define {{.*}} @_ZN1SC2Ev( +// CHECK-NOT } +// CHECK: call {{.*}} @_Z1bv() +// CHECK-NOT } +// CHECK: call {{.*}} @_ZN1SC1Ev( diff --git a/clang/test/CodeGenCXX/member-init-struct.cpp b/clang/test/CodeGenCXX/member-init-struct.cpp new file mode 100644 index 0000000..688d92d --- /dev/null +++ b/clang/test/CodeGenCXX/member-init-struct.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -emit-llvm-only -verify + +struct A {int a;}; +struct B {float a;}; +struct C { + union { + A a; + B b[10]; + }; + _Complex float c; + int d[10]; + void (C::*e)(); + C() : a(), c(), d(), e() {} + C(A x) : a(x) {} + C(void (C::*x)(), int y) : b(), c(y), e(x) {} +}; +A x; +C a, b(x), c(0, 2); diff --git a/clang/test/CodeGenCXX/member-init-union.cpp b/clang/test/CodeGenCXX/member-init-union.cpp new file mode 100644 index 0000000..2c50e18 --- /dev/null +++ b/clang/test/CodeGenCXX/member-init-union.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 %s -emit-llvm-only -verify + +union x { + int a; + float b; + x(float y) : b(y) {} + x(int y) : a(y) {} +}; +x a(1), b(1.0f); + diff --git a/clang/test/CodeGenCXX/member-initializers.cpp b/clang/test/CodeGenCXX/member-initializers.cpp new file mode 100644 index 0000000..244a164 --- /dev/null +++ b/clang/test/CodeGenCXX/member-initializers.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -O3 | FileCheck %s + +struct A { + virtual int f() { return 1; } +}; + +struct B : A { + B() : i(f()) { } + + virtual int f() { return 2; } + + int i; +}; + +// CHECK: define i32 @_Z1fv() nounwind +int f() { + B b; + + // CHECK: ret i32 2 + return b.i; +} + +// Test that we don't try to fold the default value of j when initializing i. +// CHECK: define i32 @_Z9test_foldv() nounwind +int test_fold() { + struct A { + A(const int j = 1) : i(j) { } + int i; + }; + + // CHECK: ret i32 2 + return A(2).i; +} + diff --git a/clang/test/CodeGenCXX/member-pointer-type-convert.cpp b/clang/test/CodeGenCXX/member-pointer-type-convert.cpp new file mode 100644 index 0000000..2970a2e --- /dev/null +++ b/clang/test/CodeGenCXX/member-pointer-type-convert.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s + +struct A; +typedef int A::*param_t; +struct { + const char *name; + param_t par; +} *ptr; +void test_ptr() { (void) ptr; } // forced use + +// CHECK: type { i8*, {{i..}} } diff --git a/clang/test/CodeGenCXX/member-templates.cpp b/clang/test/CodeGenCXX/member-templates.cpp new file mode 100644 index 0000000..7e4bdca --- /dev/null +++ b/clang/test/CodeGenCXX/member-templates.cpp @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// CHECK: ; ModuleID +struct A { + template<typename T> + A(T); +}; + +template<typename T> A::A(T) {} + +struct B { + template<typename T> + B(T); +}; + +template<typename T> B::B(T) {} + +// CHECK: define weak_odr void @_ZN1BC1IiEET_(%struct.B* %this, i32) unnamed_addr +// CHECK: define weak_odr void @_ZN1BC2IiEET_(%struct.B* %this, i32) unnamed_addr +template B::B(int); + +template<typename T> +struct C { + void f() { + int a[] = { 1, 2, 3 }; + } +}; + +void f(C<int>& c) { + c.f(); +} diff --git a/clang/test/CodeGenCXX/multi-dim-operator-new.cpp b/clang/test/CodeGenCXX/multi-dim-operator-new.cpp new file mode 100644 index 0000000..7a235e8 --- /dev/null +++ b/clang/test/CodeGenCXX/multi-dim-operator-new.cpp @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 %s -triple x86_64-unknown-unknown -emit-llvm -o - | FileCheck %s +// PR6641 + +extern "C" int printf(const char *, ...); + +struct Foo { + Foo() : iFoo (2) { + printf("%p\n", this); + } + int iFoo; +}; + + +typedef Foo (*T)[3][4]; + +T bar() { + return new Foo[2][3][4]; +} + +T bug(int i) { + return new Foo[i][3][4]; +} + +void pr(T a) { + for (int i = 0; i < 3; i++) + for (int j = 0; j < 4; j++) + printf("%p\n", a[i][j]); +} + +Foo *test() { + return new Foo[5]; +} + +int main() { + T f = bar(); + pr(f); + f = bug(3); + pr(f); + + Foo * g = test(); + for (int i = 0; i < 5; i++) + printf("%d\n", g[i].iFoo); + return 0; +} + +// CHECK: call noalias i8* @_Znam +// CHECK: call noalias i8* @_Znam +// CHECK: call noalias i8* @_Znam + diff --git a/clang/test/CodeGenCXX/namespace-aliases.cpp b/clang/test/CodeGenCXX/namespace-aliases.cpp new file mode 100644 index 0000000..8624eb7 --- /dev/null +++ b/clang/test/CodeGenCXX/namespace-aliases.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-llvm-only %s +namespace A { } +namespace B = A; + +namespace b {} + +void foo() { + namespace a = b; +} diff --git a/clang/test/CodeGenCXX/nested-base-member-access.cpp b/clang/test/CodeGenCXX/nested-base-member-access.cpp new file mode 100644 index 0000000..f1c7dd9 --- /dev/null +++ b/clang/test/CodeGenCXX/nested-base-member-access.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 %s -emit-llvm -o %t + +extern "C" int printf(...); + +struct M { + M(int i){ iM = i; } + int iM; + void MPR() { printf("iM = %d\n", iM); } + +}; + +struct Q { + Q(int i){ iQ = i; } + int iQ; + void QPR() { printf("iQ = %d\n", iQ); } +}; + +struct IQ { + IQ(int i) { iIQ = i; } + void IQPR() { printf("iIQ = %d\n", iIQ); } + int iIQ; +}; + +struct L : IQ { + L(int i) : IQ(i+100) { iL = i; } + int iL; +}; + +struct P : Q, L { + P(int i) : Q(i+100), L(i+200) { iP = i; } + int iP; + void PPR() { printf("iP = %d\n", iP); } +}; + + +struct N : M,P { + N() : M(100), P(200) {} + void PR() { + this->MPR(); this->PPR(); this->QPR(); + IQPR(); + printf("iM = %d\n", iM); + printf("iP = %d\n", iP); + printf("iQ = %d\n", iQ); + printf("iL = %d\n", iL); + printf("iIQ = %d\n", iIQ); + } +}; + +int main() { + N n1; + n1.PR(); +} diff --git a/clang/test/CodeGenCXX/new-array-init-exceptions.cpp b/clang/test/CodeGenCXX/new-array-init-exceptions.cpp new file mode 100644 index 0000000..5d9cc9f --- /dev/null +++ b/clang/test/CodeGenCXX/new-array-init-exceptions.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -std=c++11 -triple i386-unknown-unknown -fexceptions -fcxx-exceptions %s -emit-llvm -o - | FileCheck %s +// REQUIRES: asserts + +struct Throws { + Throws(int); + Throws(); + ~Throws(); +}; + +// CHECK: define void @_Z7cleanupi +void cleanup(int n) { + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD:[^ ]+]] + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD]] + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD]] + // CHECK: invoke void @_ZN6ThrowsC1Ev + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD]] + new Throws[n] { 1, 2, 3 }; + // CHECK: [[LPAD]]: + // CHECK-NEXT: landingpad + // CHECK: call void @_ZN6ThrowsD1Ev + // CHECK: call void @_ZdaPv +} + + +// CHECK: define void @_Z7cleanupv +void cleanup() { + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD2:[^ ]+]] + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD2]] + // CHECK: invoke void @_ZN6ThrowsC1Ei + // CHECK-NEXT: to label %{{[^ ]+}} unwind label %[[LPAD2]] + new Throws[3] { 1, 2, 3 }; + // CHECK: [[LPAD2]]: + // CHECK-NEXT: landingpad + // CHECK: call void @_ZN6ThrowsD1Ev + // CHECK: call void @_ZdaPv +} diff --git a/clang/test/CodeGenCXX/new-array-init.cpp b/clang/test/CodeGenCXX/new-array-init.cpp new file mode 100644 index 0000000..231df24 --- /dev/null +++ b/clang/test/CodeGenCXX/new-array-init.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -std=c++11 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s + +// CHECK: define void @_Z2fni +void fn(int n) { + // CHECK: icmp ult i{{32|64}} %{{[^ ]+}}, 3 + // CHECK: store i32 1 + // CHECK: store i32 2 + // CHECK: store i32 3 + // CHECK: icmp eq i32* + // CHECK-NEXT: br i1 + new int[n] { 1, 2, 3 }; +} + +// CHECK: define void @_Z15const_underflowv +void const_underflow() { + // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3 + // CHECK: call noalias i8* @_Zna{{.}}(i{{32|64}} -1) + new int[2] { 1, 2, 3 }; +} + +// CHECK: define void @_Z11const_exactv +void const_exact() { + // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3 + // CHECK-NOT: icmp eq i32* + new int[3] { 1, 2, 3 }; +} + +// CHECK: define void @_Z16const_sufficientv +void const_sufficient() { + // CHECK-NOT: icmp ult i{{32|64}} %{{[^ ]+}}, 3 + new int[4] { 1, 2, 3 }; + // CHECK: ret void +} diff --git a/clang/test/CodeGenCXX/new-operator-phi.cpp b/clang/test/CodeGenCXX/new-operator-phi.cpp new file mode 100644 index 0000000..49859ac --- /dev/null +++ b/clang/test/CodeGenCXX/new-operator-phi.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm-only -verify %s +// PR5454 +#include <stddef.h> + +struct X {static void * operator new(size_t size) throw(); X(int); }; +int a(), b(); +void b(int x) +{ + new X(x ? a() : b()); +} + diff --git a/clang/test/CodeGenCXX/new-overflow.cpp b/clang/test/CodeGenCXX/new-overflow.cpp new file mode 100644 index 0000000..68f89c3 --- /dev/null +++ b/clang/test/CodeGenCXX/new-overflow.cpp @@ -0,0 +1,209 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s + +// rdar://problem/9246208 + +// Basic test. +namespace test0 { + struct A { + A(); + int x; + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test04testEs(i16 signext + // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 4) + // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0 + // CHECK-NEXT: [[T3:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T3]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[N]] + elt *test(short s) { + return new elt[s]; + } +} + +// test0 with a nested array. +namespace test1 { + struct A { + A(); + int x; + }; + + typedef A elt[100]; + + // CHECK: define [100 x [[A:%.*]]]* @_ZN5test14testEs(i16 signext + // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400) + // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0 + // CHECK-NEXT: [[T3:%.*]] = mul i32 [[N]], 100 + // CHECK-NEXT: [[T4:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T4]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[T3]] + elt *test(short s) { + return new elt[s]; + } +} + +// test1 with an array cookie. +namespace test2 { + struct A { + A(); + ~A(); + int x; + }; + + typedef A elt[100]; + + // CHECK: define [100 x [[A:%.*]]]* @_ZN5test24testEs(i16 signext + // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400) + // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0 + // CHECK-NEXT: [[T3:%.*]] = mul i32 [[N]], 100 + // CHECK-NEXT: [[T4:%.*]] = call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[T2]], i32 4) + // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T4]], 1 + // CHECK-NEXT: [[T6:%.*]] = or i1 [[T1]], [[T5]] + // CHECK-NEXT: [[T7:%.*]] = extractvalue { i32, i1 } [[T4]], 0 + // CHECK-NEXT: [[T8:%.*]] = select i1 [[T6]], i32 -1, i32 [[T7]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T8]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[T3]] + elt *test(short s) { + return new elt[s]; + } +} + +// test0 with a 1-byte element. +namespace test4 { + struct A { + A(); + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test44testEs(i16 signext + // CHECK: [[N:%.*]] = sext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = icmp slt i32 [[N]], 0 + // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i32 -1, i32 [[N]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T1]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[N]] + elt *test(short s) { + return new elt[s]; + } +} + +// test4 with no sext required. +namespace test5 { + struct A { + A(); + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test54testEi(i32 + // CHECK: [[N:%.*]] = load i32* + // CHECK-NEXT: [[T0:%.*]] = icmp slt i32 [[N]], 0 + // CHECK-NEXT: [[T1:%.*]] = select i1 [[T0]], i32 -1, i32 [[N]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T1]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[N]] + elt *test(int s) { + return new elt[s]; + } +} + +// test0 with an unsigned size. +namespace test6 { + struct A { + A(); + int x; + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test64testEt(i16 zeroext + // CHECK: [[N:%.*]] = zext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 4) + // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0 + // CHECK-NEXT: [[T3:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T3]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[N]] + elt *test(unsigned short s) { + return new elt[s]; + } +} + +// test1 with an unsigned size. +namespace test7 { + struct A { + A(); + int x; + }; + + typedef A elt[100]; + + // CHECK: define [100 x [[A:%.*]]]* @_ZN5test74testEt(i16 zeroext + // CHECK: [[N:%.*]] = zext i16 {{%.*}} to i32 + // CHECK-NEXT: [[T0:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[N]], i32 400) + // CHECK-NEXT: [[T1:%.*]] = extractvalue { i32, i1 } [[T0]], 1 + // CHECK-NEXT: [[T2:%.*]] = extractvalue { i32, i1 } [[T0]], 0 + // CHECK-NEXT: [[T3:%.*]] = mul i32 [[N]], 100 + // CHECK-NEXT: [[T4:%.*]] = select i1 [[T1]], i32 -1, i32 [[T2]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T4]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[T3]] + elt *test(unsigned short s) { + return new elt[s]; + } +} + +// test0 with a signed type larger than size_t. +namespace test8 { + struct A { + A(); + int x; + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test84testEx(i64 + // CHECK: [[N:%.*]] = load i64* + // CHECK-NEXT: [[T0:%.*]] = icmp uge i64 [[N]], 4294967296 + // CHECK-NEXT: [[T1:%.*]] = trunc i64 [[N]] to i32 + // CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[T1]], i32 4) + // CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 1 + // CHECK-NEXT: [[T4:%.*]] = or i1 [[T0]], [[T3]] + // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T2]], 0 + // CHECK-NEXT: [[T6:%.*]] = select i1 [[T4]], i32 -1, i32 [[T5]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T6]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[T1]] + elt *test(long long s) { + return new elt[s]; + } +} + +// test8 with an unsigned type. +namespace test9 { + struct A { + A(); + int x; + }; + + typedef A elt; + + // CHECK: define [[A:%.*]]* @_ZN5test94testEy(i64 + // CHECK: [[N:%.*]] = load i64* + // CHECK-NEXT: [[T0:%.*]] = icmp uge i64 [[N]], 4294967296 + // CHECK-NEXT: [[T1:%.*]] = trunc i64 [[N]] to i32 + // CHECK-NEXT: [[T2:%.*]] = call { i32, i1 } @llvm.umul.with.overflow.i32(i32 [[T1]], i32 4) + // CHECK-NEXT: [[T3:%.*]] = extractvalue { i32, i1 } [[T2]], 1 + // CHECK-NEXT: [[T4:%.*]] = or i1 [[T0]], [[T3]] + // CHECK-NEXT: [[T5:%.*]] = extractvalue { i32, i1 } [[T2]], 0 + // CHECK-NEXT: [[T6:%.*]] = select i1 [[T4]], i32 -1, i32 [[T5]] + // CHECK-NEXT: call noalias i8* @_Znaj(i32 [[T6]]) + // CHECK: getelementptr inbounds {{.*}}, i32 [[T1]] + elt *test(unsigned long long s) { + return new elt[s]; + } +} diff --git a/clang/test/CodeGenCXX/new-with-default-arg.cpp b/clang/test/CodeGenCXX/new-with-default-arg.cpp new file mode 100644 index 0000000..248cc9e --- /dev/null +++ b/clang/test/CodeGenCXX/new-with-default-arg.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s +// pr5547 + +struct A { + void* operator new(__typeof(sizeof(int))); + A(); +}; + +A* x() { + return new A; +} + +struct B { + void* operator new(__typeof(sizeof(int)), int = 1, int = 4); + B(float); +}; + +B* y() { + new (3,4) B(1); + return new(1) B(2); +} + +struct C { + void* operator new(__typeof(sizeof(int)), int, int = 4); + C(); +}; + +C* z() { + new (3,4) C; + return new(1) C; +} + + diff --git a/clang/test/CodeGenCXX/new.cpp b/clang/test/CodeGenCXX/new.cpp new file mode 100644 index 0000000..8d9f641 --- /dev/null +++ b/clang/test/CodeGenCXX/new.cpp @@ -0,0 +1,252 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -emit-llvm -o - | FileCheck %s + +typedef __typeof__(sizeof(0)) size_t; + +void t1() { + int* a = new int; +} + +// Declare the reserved placement operators. +void *operator new(size_t, void*) throw(); +void operator delete(void*, void*) throw(); +void *operator new[](size_t, void*) throw(); +void operator delete[](void*, void*) throw(); + +void t2(int* a) { + int* b = new (a) int; +} + +struct S { + int a; +}; + +// POD types. +void t3() { + int *a = new int(10); + _Complex int* b = new _Complex int(10i); + + S s; + s.a = 10; + S *sp = new S(s); +} + +// Non-POD +struct T { + T(); + int a; +}; + +void t4() { + // CHECK: call void @_ZN1TC1Ev + T *t = new T; +} + +struct T2 { + int a; + T2(int, int); +}; + +void t5() { + // CHECK: call void @_ZN2T2C1Eii + T2 *t2 = new T2(10, 10); +} + +int *t6() { + // Null check. + return new (0) int(10); +} + +void t7() { + new int(); +} + +struct U { + ~U(); +}; + +void t8(int n) { + new int[10]; + new int[n]; + + // Non-POD + new T[10]; + new T[n]; + + // Cookie required + new U[10]; + new U[n]; +} + +// noalias +// CHECK: declare noalias i8* @_Znam +void *operator new[](size_t); + +void t9() { + bool b; + + new bool(true); + new (&b) bool(true); +} + +struct A { + void* operator new(__typeof(sizeof(int)), int, float, ...); + A(); +}; + +A* t10() { + // CHECK: @_ZN1AnwEmifz + return new(1, 2, 3.45, 100) A; +} + +// CHECK: define void @_Z3t11i +struct B { int a; }; +struct Bmemptr { int Bmemptr::* memptr; int a; }; + +void t11(int n) { + // CHECK: call noalias i8* @_Znwm + // CHECK: call void @llvm.memset.p0i8.i64( + B* b = new B(); + + // CHECK: call noalias i8* @_Znam + // CHECK: {{call void.*llvm.memset.p0i8.i64.*i8 0, i64 %}} + B *b2 = new B[n](); + + // CHECK: call noalias i8* @_Znam + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 + // CHECK: br + Bmemptr *b_memptr = new Bmemptr[n](); + + // CHECK: ret void +} + +struct Empty { }; + +// We don't need to initialize an empty class. +// CHECK: define void @_Z3t12v +void t12() { + // CHECK: call noalias i8* @_Znam + // CHECK-NOT: br + (void)new Empty[10]; + + // CHECK: call noalias i8* @_Znam + // CHECK-NOT: br + (void)new Empty[10](); + + // CHECK: ret void +} + +// Zero-initialization +// CHECK: define void @_Z3t13i +void t13(int n) { + // CHECK: call noalias i8* @_Znwm + // CHECK: store i32 0, i32* + (void)new int(); + + // CHECK: call noalias i8* @_Znam + // CHECK: {{call void.*llvm.memset.p0i8.i64.*i8 0, i64 %}} + (void)new int[n](); + + // CHECK-NEXT: ret void +} + +struct Alloc{ + int x; + void* operator new[](size_t size); + void operator delete[](void* p); + ~Alloc(); +}; + +void f() { + // CHECK: call i8* @_ZN5AllocnaEm(i64 808) + // CHECK: store i64 200 + // CHECK: call void @_ZN5AllocD1Ev( + // CHECK: call void @_ZN5AllocdaEPv(i8* + delete[] new Alloc[10][20]; + // CHECK: call noalias i8* @_Znwm + // CHECK: call void @_ZdlPv(i8* + delete new bool; + // CHECK: ret void +} + +namespace test15 { + struct A { A(); ~A(); }; + + // CHECK: define void @_ZN6test155test0EPv( + // CHECK: [[P:%.*]] = load i8* + // CHECK-NEXT: icmp eq i8* [[P]], null + // CHECK-NEXT: br i1 + // CHECK: [[T0:%.*]] = bitcast i8* [[P]] to [[A:%.*]]* + // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[T0]]) + void test0(void *p) { + new (p) A(); + } + + // CHECK: define void @_ZN6test155test1EPv( + // CHECK: [[P:%.*]] = load i8** + // CHECK-NEXT: icmp eq i8* [[P]], null + // CHECK-NEXT: br i1 + // CHECK: [[BEGIN:%.*]] = bitcast i8* [[P]] to [[A:%.*]]* + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 5 + // CHECK-NEXT: br label + // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ] + // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[CUR]]) + // CHECK-NEXT: [[NEXT]] = getelementptr inbounds [[A]]* [[CUR]], i64 1 + // CHECK-NEXT: [[DONE:%.*]] = icmp eq [[A]]* [[NEXT]], [[END]] + // CHECK-NEXT: br i1 [[DONE]] + void test1(void *p) { + new (p) A[5]; + } + + // TODO: it's okay if all these size calculations get dropped. + // FIXME: maybe we should try to throw on overflow? + // CHECK: define void @_ZN6test155test2EPvi( + // CHECK: [[N:%.*]] = load i32* + // CHECK-NEXT: [[T0:%.*]] = sext i32 [[N]] to i64 + // CHECK-NEXT: [[T1:%.*]] = icmp slt i64 [[T0]], 0 + // CHECK-NEXT: [[T2:%.*]] = select i1 [[T1]], i64 -1, i64 [[T0]] + // CHECK-NEXT: [[P:%.*]] = load i8* + // CHECK-NEXT: icmp eq i8* [[P]], null + // CHECK-NEXT: br i1 + // CHECK: [[BEGIN:%.*]] = bitcast i8* [[P]] to [[A:%.*]]* + // CHECK-NEXT: [[ISEMPTY:%.*]] = icmp eq i64 [[T0]], 0 + // CHECK-NEXT: br i1 [[ISEMPTY]], + // CHECK: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 [[T0]] + // CHECK-NEXT: br label + // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], + // CHECK-NEXT: call void @_ZN6test151AC1Ev([[A]]* [[CUR]]) + void test2(void *p, int n) { + new (p) A[n]; + } +} + +namespace PR10197 { + // CHECK: define weak_odr void @_ZN7PR101971fIiEEvv() + template<typename T> + void f() { + // CHECK: [[CALL:%.*]] = call noalias i8* @_Znwm + // CHECK-NEXT: [[CASTED:%.*]] = bitcast i8* [[CALL]] to + new T; + // CHECK-NEXT: ret void + } + + template void f<int>(); +} + +namespace PR11523 { + class MyClass; + typedef int MyClass::* NewTy; + // CHECK: define i64* @_ZN7PR115231fEv + // CHECK: store i64 -1 + NewTy* f() { return new NewTy[2](); } +} + +namespace PR11757 { + // Make sure we elide the copy construction. + struct X { X(); X(const X&); }; + X* a(X* x) { return new X(X()); } + // CHECK: define {{.*}} @_ZN7PR117571aEPNS_1XE + // CHECK: [[CALL:%.*]] = call noalias i8* @_Znwm + // CHECK-NEXT: [[CASTED:%.*]] = bitcast i8* [[CALL]] to + // CHECK-NEXT: call void @_ZN7PR117571XC1Ev({{.*}}* [[CASTED]]) + // CHECK-NEXT: ret {{.*}} [[CASTED]] +} diff --git a/clang/test/CodeGenCXX/no-exceptions.cpp b/clang/test/CodeGenCXX/no-exceptions.cpp new file mode 100644 index 0000000..da672c4 --- /dev/null +++ b/clang/test/CodeGenCXX/no-exceptions.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +void g(); + +// CHECK: define void @_Z1fv() nounwind +void f() throw (int) { + + // CHECK-NOT: invoke void @_Z1gv + g(); + // CHECK: call void @_Z1gv() + // CHECK: ret void +} diff --git a/clang/test/CodeGenCXX/noinline-template.cpp b/clang/test/CodeGenCXX/noinline-template.cpp new file mode 100644 index 0000000..6ee3935 --- /dev/null +++ b/clang/test/CodeGenCXX/noinline-template.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +// This was a problem in Sema, but only shows up as noinline missing +// in CodeGen. + +// CHECK: define linkonce_odr void @_ZN6VectorIiE13growStorageByEv(%struct.Vector* %this) nounwind noinline + +template <class Ty> struct Vector { + void growStorageBy(); +}; +template <class T> __attribute__((noinline)) void Vector<T>::growStorageBy() { +} +void foo() { + Vector<int> strs; + strs.growStorageBy(); +} diff --git a/clang/test/CodeGenCXX/nonconst-init.cpp b/clang/test/CodeGenCXX/nonconst-init.cpp new file mode 100644 index 0000000..21129b9 --- /dev/null +++ b/clang/test/CodeGenCXX/nonconst-init.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s + +int a(); +// CHECK: call i32 @_Z1av() +struct x {int x, y : 10;} x = {1, a()}; diff --git a/clang/test/CodeGenCXX/nrvo-noreturn.cc b/clang/test/CodeGenCXX/nrvo-noreturn.cc new file mode 100644 index 0000000..a8259ca --- /dev/null +++ b/clang/test/CodeGenCXX/nrvo-noreturn.cc @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -emit-llvm-only %s +// PR9178 + +void abort() __attribute__((__noreturn__)); +struct CoinModelLink { + CoinModelLink(); + ~CoinModelLink(); +}; +class CoinModel { + CoinModelLink firstInQuadraticColumn(); +}; +CoinModelLink CoinModel::firstInQuadraticColumn() { + abort(); + CoinModelLink x; + return x; +} + diff --git a/clang/test/CodeGenCXX/nrvo.cpp b/clang/test/CodeGenCXX/nrvo.cpp new file mode 100644 index 0000000..2feaf68 --- /dev/null +++ b/clang/test/CodeGenCXX/nrvo.cpp @@ -0,0 +1,161 @@ +// RUN: %clang_cc1 -emit-llvm -O1 -o - %s | FileCheck %s +// RUN: %clang_cc1 -emit-llvm -O1 -fcxx-exceptions -fexceptions -o - %s | FileCheck --check-prefix=CHECK-EH %s + +// Test code generation for the named return value optimization. +class X { +public: + X(); + X(const X&); + ~X(); +}; + +// CHECK: define void @_Z5test0v +// CHECK-EH: define void @_Z5test0v +X test0() { + X x; + // CHECK: call {{.*}} @_ZN1XC1Ev + // CHECK-NEXT: ret void + + // CHECK-EH: call {{.*}} @_ZN1XC1Ev + // CHECK-EH-NEXT: ret void + return x; +} + +// CHECK: define void @_Z5test1b( +// CHECK-EH: define void @_Z5test1b( +X test1(bool B) { + // CHECK: tail call {{.*}} @_ZN1XC1Ev + // CHECK-NEXT: ret void + X x; + if (B) + return (x); + return x; + // CHECK-EH: tail call {{.*}} @_ZN1XC1Ev + // CHECK-EH-NEXT: ret void +} + +// CHECK: define void @_Z5test2b +// CHECK-EH: define void @_Z5test2b +X test2(bool B) { + // No NRVO. + + X x; + X y; + if (B) + return y; + return x; + + // CHECK: call {{.*}} @_ZN1XC1Ev + // CHECK-NEXT: call {{.*}} @_ZN1XC1Ev + // CHECK: call {{.*}} @_ZN1XC1ERKS_ + // CHECK: call {{.*}} @_ZN1XC1ERKS_ + // CHECK: call {{.*}} @_ZN1XD1Ev + // CHECK: call {{.*}} @_ZN1XD1Ev + // CHECK: ret void + + // The block ordering in the -fexceptions IR is unfortunate. + + // CHECK-EH: call {{.*}} @_ZN1XC1Ev + // CHECK-EH-NEXT: invoke {{.*}} @_ZN1XC1Ev + // -> %invoke.cont, %lpad + + // %invoke.cont: + // CHECK-EH: br i1 + // -> %if.then, %if.end + + // %if.then: returning 'x' + // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_ + // -> %cleanup, %lpad1 + + // %lpad: landing pad for ctor of 'y', dtor of 'y' + // CHECK-EH: [[CAUGHTVAL:%.*]] = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-EH-NEXT: cleanup + // CHECK-EH-NEXT: extractvalue { i8*, i32 } [[CAUGHTVAL]], 0 + // CHECK-EH-NEXT: extractvalue { i8*, i32 } [[CAUGHTVAL]], 1 + // CHECK-EH-NEXT: br label + // -> %eh.cleanup + + // %lpad1: landing pad for return copy ctors, EH cleanup for 'y' + // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev + // -> %eh.cleanup, %terminate.lpad + + // %if.end: returning 'y' + // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_ + // -> %cleanup, %lpad1 + + // %cleanup: normal cleanup for 'y' + // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev + // -> %invoke.cont11, %lpad + + // %invoke.cont11: normal cleanup for 'x' + // CHECK-EH: call {{.*}} @_ZN1XD1Ev + // CHECK-EH-NEXT: ret void + + // %eh.cleanup: EH cleanup for 'x' + // CHECK-EH: invoke {{.*}} @_ZN1XD1Ev + // -> %invoke.cont17, %terminate.lpad + + // %invoke.cont17: rethrow block for %eh.cleanup. + // This really should be elsewhere in the function. + // CHECK-EH: resume { i8*, i32 } + + // %terminate.lpad: terminate landing pad. + // CHECK-EH: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-EH-NEXT: catch i8* null + // CHECK-EH-NEXT: call void @_ZSt9terminatev() + // CHECK-EH-NEXT: unreachable + +} + +X test3(bool B) { + // FIXME: We don't manage to apply NRVO here, although we could. + { + X y; + return y; + } + X x; + return x; +} + +extern "C" void exit(int) throw(); + +// CHECK: define void @_Z5test4b +X test4(bool B) { + { + // CHECK: tail call {{.*}} @_ZN1XC1Ev + X x; + // CHECK: br i1 + if (B) + return x; + } + // CHECK: tail call {{.*}} @_ZN1XD1Ev + // CHECK: tail call void @exit(i32 1) + exit(1); +} + +#ifdef __EXCEPTIONS +// CHECK-EH: define void @_Z5test5 +void may_throw(); +X test5() { + try { + may_throw(); + } catch (X x) { + // CHECK-EH: invoke {{.*}} @_ZN1XC1ERKS_ + // CHECK-EH: call void @__cxa_end_catch() + // CHECK-EH: ret void + return x; + } +} +#endif + +// rdar://problem/10430868 +// CHECK: define void @_Z5test6v +X test6() { + X a __attribute__((aligned(8))); + return a; + // CHECK: [[A:%.*]] = alloca [[X:%.*]], align 8 + // CHECK-NEXT: call {{.*}} @_ZN1XC1Ev([[X]]* [[A]]) + // CHECK-NEXT: call {{.*}} @_ZN1XC1ERKS_([[X]]* {{%.*}}, [[X]]* [[A]]) + // CHECK-NEXT: call {{.*}} @_ZN1XD1Ev([[X]]* [[A]]) + // CHECK-NEXT: ret void +} diff --git a/clang/test/CodeGenCXX/nullptr.cpp b/clang/test/CodeGenCXX/nullptr.cpp new file mode 100644 index 0000000..e93f706 --- /dev/null +++ b/clang/test/CodeGenCXX/nullptr.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -I%S -emit-llvm -o - %s | FileCheck %s + +#include <typeinfo> + +// CHECK: @_ZTIDn = external constant i8* +int* a = nullptr; + +void f() { + int* a = nullptr; +} + +typedef decltype(nullptr) nullptr_t; + +nullptr_t get_nullptr(); + +struct X { }; +void g() { + // CHECK: call i8* @_Z11get_nullptrv() + int (X::*pmf)(int) = get_nullptr(); +} + +const std::type_info& f2() { + return typeid(nullptr_t); +} diff --git a/clang/test/CodeGenCXX/operator-new.cpp b/clang/test/CodeGenCXX/operator-new.cpp new file mode 100644 index 0000000..db56cda --- /dev/null +++ b/clang/test/CodeGenCXX/operator-new.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -triple i686-pc-linux-gnu -emit-llvm -o %t-1.ll %s +// RUN: FileCheck -check-prefix SANE --input-file=%t-1.ll %s +// RUN: %clang_cc1 -triple i686-pc-linux-gnu -emit-llvm -fno-assume-sane-operator-new -o %t-2.ll %s +// RUN: FileCheck -check-prefix SANENOT --input-file=%t-2.ll %s + + +class teste { + int A; +public: + teste() : A(2) {} +}; + +void f1() { + // SANE: declare noalias i8* @_Znwj( + // SANENOT: declare i8* @_Znwj( + new teste(); +} + + +// rdar://5739832 - operator new should check for overflow in multiply. +void *f2(long N) { + return new int[N]; + +// SANE: [[UWO:%.*]] = call {{.*}} @llvm.umul.with.overflow +// SANE-NEXT: [[OVER:%.*]] = extractvalue {{.*}} [[UWO]], 1 +// SANE-NEXT: [[SUM:%.*]] = extractvalue {{.*}} [[UWO]], 0 +// SANE-NEXT: [[RESULT:%.*]] = select i1 [[OVER]], i32 -1, i32 [[SUM]] +// SANE-NEXT: call noalias i8* @_Znaj(i32 [[RESULT]]) +} diff --git a/clang/test/CodeGenCXX/overload-binop-implicitconvert.cpp b/clang/test/CodeGenCXX/overload-binop-implicitconvert.cpp new file mode 100644 index 0000000..0eb7a06 --- /dev/null +++ b/clang/test/CodeGenCXX/overload-binop-implicitconvert.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -emit-llvm-only +class T +{}; + +void print(const char *t); + +T& operator<< (T& t,const char* c) +{ + print(c); + return t; +} + + +int main() +{ + T t; + print("foo"); + t<<"foo"; + + return 0; +} + diff --git a/clang/test/CodeGenCXX/override-layout.cpp b/clang/test/CodeGenCXX/override-layout.cpp new file mode 100644 index 0000000..d432885 --- /dev/null +++ b/clang/test/CodeGenCXX/override-layout.cpp @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -fdump-record-layouts-simple %s 2> %t.layouts +// RUN: %clang_cc1 -fdump-record-layouts-simple %s > %t.before 2>&1 +// RUN: %clang_cc1 -DPACKED= -DALIGNED16= -fdump-record-layouts-simple -foverride-record-layout=%t.layouts %s > %t.after 2>&1 +// RUN: diff %t.before %t.after +// RUN: FileCheck %s < %t.after + +// If not explicitly disabled, set PACKED to the packed attribute. +#ifndef PACKED +# define PACKED __attribute__((packed)) +#endif + +struct Empty1 { }; +struct Empty2 { }; + +// CHECK: Type: struct X0 +struct X0 : public Empty1 { + int x[6] PACKED; +}; + +// CHECK: Type: struct X1 +struct X1 : public X0, public Empty2 { + char x[13]; + struct X0 y; +} PACKED; + +// CHECK: Type: struct X2 +struct PACKED X2 : public X1, public X0, public Empty1 { + short x; + int y; +}; + +// CHECK: Type: struct X3 +struct PACKED X3 : virtual public X1, public X0 { + short x; + int y; +}; + +// CHECK: Type: struct X4 +struct PACKED X4 { + unsigned int a : 1; + unsigned int b : 1; + unsigned int c : 1; + unsigned int d : 1; + unsigned int e : 1; + unsigned int f : 1; + unsigned int g : 1; + unsigned int h : 1; + unsigned int i : 1; + unsigned int j : 1; + unsigned int k : 1; + unsigned int l : 1; + unsigned int m : 1; + unsigned int n : 1; + X4(); +}; + +void use_structs() { + X0 x0s[sizeof(X0)]; + X1 x1s[sizeof(X1)]; + X2 x2s[sizeof(X2)]; + X3 x3s[sizeof(X3)]; + X4 x4s[sizeof(X4)]; + x4s[1].a = 1; +} diff --git a/clang/test/CodeGenCXX/partial-destruction.cpp b/clang/test/CodeGenCXX/partial-destruction.cpp new file mode 100644 index 0000000..f232a15 --- /dev/null +++ b/clang/test/CodeGenCXX/partial-destruction.cpp @@ -0,0 +1,172 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s + +// Test IR generation for partial destruction of aggregates. + +void opaque(); + +// Initializer lists. +namespace test0 { + struct A { A(int); A(); ~A(); void *v; }; + void test() { + A as[10] = { 5, 7 }; + opaque(); + } + // CHECK: define void @_ZN5test04testEv() + // CHECK: [[AS:%.*]] = alloca [10 x [[A:%.*]]], align + // CHECK-NEXT: [[ENDVAR:%.*]] = alloca [[A]]* + // CHECK-NEXT: [[EXN:%.*]] = alloca i8* + // CHECK-NEXT: [[SEL:%.*]] = alloca i32 + + // Initialize. + // CHECK-NEXT: [[E_BEGIN:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i64 0, i64 0 + // CHECK-NEXT: store [[A]]* [[E_BEGIN]], [[A]]** [[ENDVAR]] + // CHECK-NEXT: invoke void @_ZN5test01AC1Ei([[A]]* [[E_BEGIN]], i32 5) + // CHECK: [[E1:%.*]] = getelementptr inbounds [[A]]* [[E_BEGIN]], i64 1 + // CHECK-NEXT: store [[A]]* [[E1]], [[A]]** [[ENDVAR]] + // CHECK-NEXT: invoke void @_ZN5test01AC1Ei([[A]]* [[E1]], i32 7) + // CHECK: [[E2:%.*]] = getelementptr inbounds [[A]]* [[E1]], i64 1 + // CHECK-NEXT: store [[A]]* [[E2]], [[A]]** [[ENDVAR]] + // CHECK-NEXT: [[E_END:%.*]] = getelementptr inbounds [[A]]* [[E_BEGIN]], i64 10 + // CHECK-NEXT: br label + // CHECK: [[E_CUR:%.*]] = phi [[A]]* [ [[E2]], {{%.*}} ], [ [[E_NEXT:%.*]], {{%.*}} ] + // CHECK-NEXT: invoke void @_ZN5test01AC1Ev([[A]]* [[E_CUR]]) + // CHECK: [[E_NEXT]] = getelementptr inbounds [[A]]* [[E_CUR]], i64 1 + // CHECK-NEXT: store [[A]]* [[E_NEXT]], [[A]]** [[ENDVAR]] + // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[E_NEXT]], [[E_END]] + // CHECK-NEXT: br i1 [[T0]], + + // Run. + // CHECK: invoke void @_Z6opaquev() + + // Normal destroy. + // CHECK: [[ED_BEGIN:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i32 0, i32 0 + // CHECK-NEXT: [[ED_END:%.*]] = getelementptr inbounds [[A]]* [[ED_BEGIN]], i64 10 + // CHECK-NEXT: br label + // CHECK: [[ED_AFTER:%.*]] = phi [[A]]* [ [[ED_END]], {{%.*}} ], [ [[ED_CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[ED_CUR]] = getelementptr inbounds [[A]]* [[ED_AFTER]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[ED_CUR]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[ED_CUR]], [[ED_BEGIN]] + // CHECK-NEXT: br i1 [[T0]], + // CHECK: ret void + + // Partial destroy for initialization. + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: cleanup + // CHECK: [[PARTIAL_END:%.*]] = load [[A]]** [[ENDVAR]] + // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[E_BEGIN]], [[PARTIAL_END]] + // CHECK-NEXT: br i1 [[T0]], + // CHECK: [[E_AFTER:%.*]] = phi [[A]]* [ [[PARTIAL_END]], {{%.*}} ], [ [[E_CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[E_CUR]] = getelementptr inbounds [[A]]* [[E_AFTER]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[E_CUR]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[E_CUR]], [[E_BEGIN]] + // CHECK-NEXT: br i1 [[T0]], + + // Primary EH destructor. + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: cleanup + // CHECK: [[E0:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i32 0, i32 0 + // CHECK-NEXT: [[E_END:%.*]] = getelementptr inbounds [[A]]* [[E0]], i64 10 + // CHECK-NEXT: br label + + // Partial destructor for primary normal destructor. + // FIXME: There's some really bad block ordering here which causes + // the partial destroy for the primary normal destructor to fall + // within the primary EH destructor. + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: cleanup + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[ED_BEGIN]], [[ED_CUR]] + // CHECK-NEXT: br i1 [[T0]] + // CHECK: [[EDD_AFTER:%.*]] = phi [[A]]* [ [[ED_CUR]], {{%.*}} ], [ [[EDD_CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[EDD_CUR]] = getelementptr inbounds [[A]]* [[EDD_AFTER]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[EDD_CUR]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[EDD_CUR]], [[ED_BEGIN]] + // CHECK-NEXT: br i1 [[T0]] + + // Back to the primary EH destructor. + // CHECK: [[E_AFTER:%.*]] = phi [[A]]* [ [[E_END]], {{%.*}} ], [ [[E_CUR:%.*]], {{%.*}} ] + // CHECK-NEXT: [[E_CUR]] = getelementptr inbounds [[A]]* [[E_AFTER]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[E_CUR]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[E_CUR]], [[E0]] + // CHECK-NEXT: br i1 [[T0]], + +} + +namespace test1 { + struct A { A(); A(int); ~A(); }; + struct B { A x, y, z; int w; }; + + void test() { + B v = { 5, 6, 7, 8 }; + } + // CHECK: define void @_ZN5test14testEv() + // CHECK: [[V:%.*]] = alloca [[B:%.*]], align 4 + // CHECK-NEXT: alloca i8* + // CHECK-NEXT: alloca i32 + // CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 0 + // CHECK-NEXT: call void @_ZN5test11AC1Ei([[A:%.*]]* [[X]], i32 5) + // CHECK-NEXT: [[Y:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 1 + // CHECK-NEXT: invoke void @_ZN5test11AC1Ei([[A]]* [[Y]], i32 6) + // CHECK: [[Z:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 2 + // CHECK-NEXT: invoke void @_ZN5test11AC1Ei([[A]]* [[Z]], i32 7) + // CHECK: [[W:%.*]] = getelementptr inbounds [[B]]* [[V]], i32 0, i32 3 + // CHECK-NEXT: store i32 8, i32* [[W]], align 4 + // CHECK-NEXT: call void @_ZN5test11BD1Ev([[B]]* [[V]]) + // CHECK-NEXT: ret void + + // FIXME: again, the block ordering is pretty bad here + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: cleanup + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: cleanup + // CHECK: invoke void @_ZN5test11AD1Ev([[A]]* [[Y]]) + // CHECK: invoke void @_ZN5test11AD1Ev([[A]]* [[X]]) +} + +namespace test2 { + struct A { A(); ~A(); }; + + void test() { + A v[4][7]; + + // CHECK: define void @_ZN5test24testEv() + // CHECK: [[V:%.*]] = alloca [4 x [7 x [[A:%.*]]]], align 1 + // CHECK-NEXT: alloca i8* + // CHECK-NEXT: alloca i32 + + // Main initialization loop. + // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [4 x [7 x [[A]]]]* [[V]], i32 0, i32 0, i32 0 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 28 + // CHECK-NEXT: br label + // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ] + // CHECK-NEXT: invoke void @_ZN5test21AC1Ev([[A]]* [[CUR]]) + // CHECK: [[NEXT:%.*]] = getelementptr inbounds [[A]]* [[CUR]], i64 1 + // CHECK-NEXT: [[DONE:%.*]] = icmp eq [[A]]* [[NEXT]], [[END]] + // CHECK-NEXT: br i1 [[DONE]], + + // Partial destruction landing pad. + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: cleanup + // CHECK: [[EMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[CUR]] + // CHECK-NEXT: br i1 [[EMPTY]], + // CHECK: [[PAST:%.*]] = phi [[A]]* [ [[CUR]], {{%.*}} ], [ [[DEL:%.*]], {{%.*}} ] + // CHECK-NEXT: [[DEL]] = getelementptr inbounds [[A]]* [[PAST]], i64 -1 + // CHECK-NEXT: invoke void @_ZN5test21AD1Ev([[A]]* [[DEL]]) + // CHECK: [[T0:%.*]] = icmp eq [[A]]* [[DEL]], [[BEGIN]] + // CHECK-NEXT: br i1 [[T0]], + } + +} + +// PR10351 +namespace test3 { + struct A { A(); ~A(); void *p; }; + struct B { + B() {} + A a; + }; + + B *test() { + return new B[10]; + // invoke void @_ZN5test31BD1Ev( + } +} diff --git a/clang/test/CodeGenCXX/pointers-to-data-members.cpp b/clang/test/CodeGenCXX/pointers-to-data-members.cpp new file mode 100644 index 0000000..90024e4 --- /dev/null +++ b/clang/test/CodeGenCXX/pointers-to-data-members.cpp @@ -0,0 +1,242 @@ +// RUN: %clang_cc1 %s -emit-llvm -o %t.ll -triple=x86_64-apple-darwin10 +// RUN: FileCheck %s < %t.ll +// RUN: FileCheck -check-prefix=CHECK-GLOBAL %s < %t.ll +// RUN: %clang_cc1 %s -emit-llvm -o %t-opt.ll -triple=x86_64-apple-darwin10 -O3 +// RUN: FileCheck --check-prefix=CHECK-O3 %s < %t-opt.ll + +struct A { int a; int b; }; +struct B { int b; }; +struct C : B, A { }; + +// Zero init. +namespace ZeroInit { + // CHECK-GLOBAL: @_ZN8ZeroInit1aE = global i64 -1 + int A::* a; + + // CHECK-GLOBAL: @_ZN8ZeroInit2aaE = global [2 x i64] [i64 -1, i64 -1] + int A::* aa[2]; + + // CHECK-GLOBAL: @_ZN8ZeroInit3aaaE = global [2 x [2 x i64]] {{\[}}[2 x i64] [i64 -1, i64 -1], [2 x i64] [i64 -1, i64 -1]] + int A::* aaa[2][2]; + + // CHECK-GLOBAL: @_ZN8ZeroInit1bE = global i64 -1, + int A::* b = 0; + + // CHECK-GLOBAL: @_ZN8ZeroInit2saE = internal global %struct.anon { i64 -1 } + struct { + int A::*a; + } sa; + void test_sa() { (void) sa; } // force emission + + // CHECK-GLOBAL: @_ZN8ZeroInit3ssaE = internal + // CHECK-GLOBAL: [2 x i64] [i64 -1, i64 -1] + struct { + int A::*aa[2]; + } ssa[2]; + void test_ssa() { (void) ssa; } + + // CHECK-GLOBAL: @_ZN8ZeroInit2ssE = internal global %struct.anon.1 { %struct.anon.2 { i64 -1 } } + struct { + struct { + int A::*pa; + } s; + } ss; + void test_ss() { (void) ss; } + + struct A { + int A::*a; + int b; + }; + + struct B { + A a[10]; + char c; + int B::*b; + }; + + struct C : A, B { int j; }; + // CHECK-GLOBAL: @_ZN8ZeroInit1cE = global {{%.*}} { %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::B" { [10 x %"struct.ZeroInit::A"] [%"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }], i8 0, i64 -1 }, i32 0 }, align 8 + C c; +} + +// PR5674 +namespace PR5674 { + // CHECK-GLOBAL: @_ZN6PR56742pbE = global i64 4 + int A::*pb = &A::b; +} + +// Casts. +namespace Casts { + +int A::*pa; +int C::*pc; + +void f() { + // CHECK: store i64 -1, i64* @_ZN5Casts2paE + pa = 0; + + // CHECK-NEXT: [[TMP:%.*]] = load i64* @_ZN5Casts2paE, align 8 + // CHECK-NEXT: [[ADJ:%.*]] = add nsw i64 [[TMP]], 4 + // CHECK-NEXT: [[ISNULL:%.*]] = icmp eq i64 [[TMP]], -1 + // CHECK-NEXT: [[RES:%.*]] = select i1 [[ISNULL]], i64 [[TMP]], i64 [[ADJ]] + // CHECK-NEXT: store i64 [[RES]], i64* @_ZN5Casts2pcE + pc = pa; + + // CHECK-NEXT: [[TMP:%.*]] = load i64* @_ZN5Casts2pcE, align 8 + // CHECK-NEXT: [[ADJ:%.*]] = sub nsw i64 [[TMP]], 4 + // CHECK-NEXT: [[ISNULL:%.*]] = icmp eq i64 [[TMP]], -1 + // CHECK-NEXT: [[RES:%.*]] = select i1 [[ISNULL]], i64 [[TMP]], i64 [[ADJ]] + // CHECK-NEXT: store i64 [[RES]], i64* @_ZN5Casts2paE + pa = static_cast<int A::*>(pc); +} + +} + +// Comparisons +namespace Comparisons { + void f() { + int A::*a; + + // CHECK: icmp ne i64 {{.*}}, -1 + if (a) { } + + // CHECK: icmp ne i64 {{.*}}, -1 + if (a != 0) { } + + // CHECK: icmp ne i64 -1, {{.*}} + if (0 != a) { } + + // CHECK: icmp eq i64 {{.*}}, -1 + if (a == 0) { } + + // CHECK: icmp eq i64 -1, {{.*}} + if (0 == a) { } + } +} + +namespace ValueInit { + +struct A { + int A::*a; + + char c; + + A(); +}; + +// CHECK: define void @_ZN9ValueInit1AC2Ev(%"struct.ValueInit::A"* %this) unnamed_addr +// CHECK: store i64 -1, i64* +// CHECK: ret void +A::A() : a() {} + +} + +namespace PR7139 { + +struct pair { + int first; + int second; +}; + +typedef int pair::*ptr_to_member_type; + +struct ptr_to_member_struct { + ptr_to_member_type data; + int i; +}; + +struct A { + ptr_to_member_struct a; + + A() : a() {} +}; + +// CHECK-O3: define zeroext i1 @_ZN6PR71395checkEv() nounwind readnone +bool check() { + // CHECK-O3: ret i1 true + return A().a.data == 0; +} + +// CHECK-O3: define zeroext i1 @_ZN6PR71396check2Ev() nounwind readnone +bool check2() { + // CHECK-O3: ret i1 true + return ptr_to_member_type() == 0; +} + +} + +namespace VirtualBases { + +struct A { + char c; + int A::*i; +}; + +// CHECK-GLOBAL: @_ZN12VirtualBases1bE = global %"struct.VirtualBases::B" { i32 (...)** null, %"struct.VirtualBases::A" { i8 0, i64 -1 } }, align 8 +struct B : virtual A { }; +B b; + +// CHECK-GLOBAL: @_ZN12VirtualBases1cE = global %"struct.VirtualBases::C" { i32 (...)** null, i64 -1, %"struct.VirtualBases::A" { i8 0, i64 -1 } }, align 8 +struct C : virtual A { int A::*i; }; +C c; + +// CHECK-GLOBAL: @_ZN12VirtualBases1dE = global %"struct.VirtualBases::D" { %"struct.VirtualBases::C.base" { i32 (...)** null, i64 -1 }, i64 -1, %"struct.VirtualBases::A" { i8 0, i64 -1 } }, align 8 +struct D : C { int A::*i; }; +D d; + +} + +namespace Test1 { + +// Don't crash when A contains a bit-field. +struct A { + int A::* a; + int b : 10; +}; +A a; + +} + +namespace BoolPtrToMember { + struct X { + bool member; + }; + + // CHECK: define i8* @_ZN15BoolPtrToMember1fERNS_1XEMS0_b + bool &f(X &x, bool X::*member) { + // CHECK: {{bitcast.* to i8\*}} + // CHECK-NEXT: getelementptr inbounds i8* + // CHECK-NEXT: ret i8* + return x.*member; + } +} + +namespace PR8507 { + +struct S; +void f(S* p, double S::*pm) { + if (0 < p->*pm) { + } +} + +} + +namespace test4 { + struct A { int A_i; }; + struct B : virtual A { int A::*B_p; }; + struct C : virtual B { int *C_p; }; + struct D : C { int *D_p; }; + + // CHECK-GLOBAL: @_ZN5test41dE = global %"struct.test4::D" { %"struct.test4::C.base" zeroinitializer, i32* null, %"struct.test4::B.base" { i32 (...)** null, i64 -1 }, %"struct.test4::A" zeroinitializer }, align 8 + D d; +} + +namespace PR11487 { + union U + { + int U::* mptr; + char x[16]; + } x; + // CHECK-GLOBAL: @_ZN7PR114871xE = global %"union.PR11487::U" { i64 -1, [8 x i8] zeroinitializer }, align 8 + +} diff --git a/clang/test/CodeGenCXX/pr11676.cpp b/clang/test/CodeGenCXX/pr11676.cpp new file mode 100644 index 0000000..896751a --- /dev/null +++ b/clang/test/CodeGenCXX/pr11676.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 %s -std=c++11 -emit-llvm-only +// CHECK that we don't crash. + +// PR11676's example is ill-formed: +/* +union _XEvent { +}; +void ProcessEvent() { + _XEvent pluginEvent = _XEvent(); +} +*/ + +// Example from PR11665: +void f() { + union U { int field; } u = U(); + (void)U().field; +} diff --git a/clang/test/CodeGenCXX/pr11797.cpp b/clang/test/CodeGenCXX/pr11797.cpp new file mode 100644 index 0000000..05221ac --- /dev/null +++ b/clang/test/CodeGenCXX/pr11797.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 %s -fvisibility hidden -emit-llvm -o - | FileCheck %s + +namespace std __attribute__ ((__visibility__ ("default"))) {} +#pragma GCC visibility push(default) +void foo() { +} +#pragma GCC visibility pop +// CHECK: define void @_Z3foov() diff --git a/clang/test/CodeGenCXX/pr12104.cpp b/clang/test/CodeGenCXX/pr12104.cpp new file mode 100644 index 0000000..a62f04b --- /dev/null +++ b/clang/test/CodeGenCXX/pr12104.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -include %S/pr12104.h %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -x c++ -emit-pch -o %t %S/pr12104.h +// RUN: %clang_cc1 -include-pch %t %s -emit-llvm -o - | FileCheck %s + +template struct Patch<1>; + +// CHECK: _ZN5PatchILi1EE11no_neighborE diff --git a/clang/test/CodeGenCXX/pr12104.h b/clang/test/CodeGenCXX/pr12104.h new file mode 100644 index 0000000..f3e9363 --- /dev/null +++ b/clang/test/CodeGenCXX/pr12104.h @@ -0,0 +1,9 @@ +template <int dimm> struct Patch { + static const unsigned int no_neighbor = 1; +}; +template <int dim> +const unsigned int Patch<dim>::no_neighbor; +void f(const unsigned int); +void g() { + f(Patch<1>::no_neighbor); +} diff --git a/clang/test/CodeGenCXX/pr12251.cpp b/clang/test/CodeGenCXX/pr12251.cpp new file mode 100644 index 0000000..a9920c0 --- /dev/null +++ b/clang/test/CodeGenCXX/pr12251.cpp @@ -0,0 +1,146 @@ +// RUN: %clang_cc1 %s -emit-llvm -O1 -relaxed-aliasing -fstrict-enums -std=c++11 -o - | FileCheck %s +// RUN: %clang_cc1 %s -emit-llvm -O1 -relaxed-aliasing -std=c++11 -o - | FileCheck --check-prefix=NO-STRICT-ENUMS %s + +bool f(bool *x) { + return *x; +} +// CHECK: define zeroext i1 @_Z1fPb +// CHECK: load i8* %{{.*}}, align 1, !range !0 + +// Only enum-tests follow. Ensure that after the bool test, no further range +// metadata shows up when strict enums are disabled. +// NO-STRICT-ENUMS: define zeroext i1 @_Z1fPb +// NO-STRICT-ENUMS: load i8* %{{.*}}, align 1, !range !0 +// NO-STRICT-ENUMS-NOT: !range + +enum e1 { }; +e1 g1(e1 *x) { + return *x; +} +// CHECK: define i32 @_Z2g1P2e1 +// CHECK: load i32* %x, align 4, !range !1 + +enum e2 { e2_a = 0 }; +e2 g2(e2 *x) { + return *x; +} +// CHECK: define i32 @_Z2g2P2e2 +// CHECK: load i32* %x, align 4, !range !1 + +enum e3 { e3_a = 16 }; +e3 g3(e3 *x) { + return *x; +} +// CHECK: define i32 @_Z2g3P2e3 +// CHECK: load i32* %x, align 4, !range !2 + +enum e4 { e4_a = -16}; +e4 g4(e4 *x) { + return *x; +} +// CHECK: define i32 @_Z2g4P2e4 +// CHECK: load i32* %x, align 4, !range !3 + +enum e5 { e5_a = -16, e5_b = 16}; +e5 g5(e5 *x) { + return *x; +} +// CHECK: define i32 @_Z2g5P2e5 +// CHECK: load i32* %x, align 4, !range !4 + +enum e6 { e6_a = -1 }; +e6 g6(e6 *x) { + return *x; +} +// CHECK: define i32 @_Z2g6P2e6 +// CHECK: load i32* %x, align 4, !range !5 + +enum e7 { e7_a = -16, e7_b = 2}; +e7 g7(e7 *x) { + return *x; +} +// CHECK: define i32 @_Z2g7P2e7 +// CHECK: load i32* %x, align 4, !range !3 + +enum e8 { e8_a = -17}; +e8 g8(e8 *x) { + return *x; +} +// CHECK: define i32 @_Z2g8P2e8 +// CHECK: load i32* %x, align 4, !range !4 + +enum e9 { e9_a = 17}; +e9 g9(e9 *x) { + return *x; +} +// CHECK: define i32 @_Z2g9P2e9 +// CHECK: load i32* %x, align 4, !range !2 + +enum e10 { e10_a = -16, e10_b = 32}; +e10 g10(e10 *x) { + return *x; +} +// CHECK: define i32 @_Z3g10P3e10 +// CHECK: load i32* %x, align 4, !range !6 + +enum e11 {e11_a = 4294967296 }; +enum e11 g11(enum e11 *x) { + return *x; +} +// CHECK: define i64 @_Z3g11P3e11 +// CHECK: load i64* %x, align {{[84]}}, !range !7 + +enum e12 {e12_a = 9223372036854775808U }; +enum e12 g12(enum e12 *x) { + return *x; +} +// CHECK: define i64 @_Z3g12P3e12 +// CHECK: load i64* %x, align {{[84]}} +// CHECK-NOT: range +// CHECK: ret + +enum e13 : char {e13_a = -1 }; +e13 g13(e13 *x) { + return *x; +} +// CHECK: define signext i8 @_Z3g13P3e13 +// CHECK: load i8* %x, align 1 +// CHECK-NOT: range +// CHECK: ret + +enum class e14 {e14_a = 1}; +e14 g14(e14 *x) { + return *x; +} +// CHECK: define i32 @_Z3g14P3e14 +// CHECK: load i32* %x, align 4 +// CHECK-NOT: range +// CHECK: ret + +enum e15 { e15_a = 2147483648 }; +e15 g15(e15 *x) { + return *x; +} +// CHECK: define i32 @_Z3g15P3e15 +// CHECK: load i32* %x, align 4 +// CHECK-NOT: range +// CHECK: ret + +enum e16 { e16_a = -2147483648 }; +e16 g16(e16 *x) { + return *x; +} +// CHECK: define i32 @_Z3g16P3e16 +// CHECK: load i32* %x, align 4 +// CHECK-NOT: range +// CHECK: ret + + +// CHECK: !0 = metadata !{i8 0, i8 2} +// CHECK: !1 = metadata !{i32 0, i32 1} +// CHECK: !2 = metadata !{i32 0, i32 32} +// CHECK: !3 = metadata !{i32 -16, i32 16} +// CHECK: !4 = metadata !{i32 -32, i32 32} +// CHECK: !5 = metadata !{i32 -1, i32 1} +// CHECK: !6 = metadata !{i32 -64, i32 64} +// CHECK: !7 = metadata !{i64 0, i64 8589934592} diff --git a/clang/test/CodeGenCXX/pr9130.cpp b/clang/test/CodeGenCXX/pr9130.cpp new file mode 100644 index 0000000..b28f394 --- /dev/null +++ b/clang/test/CodeGenCXX/pr9130.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s + +class nsOggCodecState { + virtual int StartTime() { + return -1; + } +}; +class nsVorbisState : public nsOggCodecState { + virtual ~nsVorbisState(); +}; +nsVorbisState::~nsVorbisState() { +} + +// CHECK: define linkonce_odr i32 @_ZN15nsOggCodecState9StartTimeEv diff --git a/clang/test/CodeGenCXX/pr9965.cpp b/clang/test/CodeGenCXX/pr9965.cpp new file mode 100644 index 0000000..0d267ff --- /dev/null +++ b/clang/test/CodeGenCXX/pr9965.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s | FileCheck %s +struct A { A(); }; +template<typename T> +struct X : A // default constructor is not trivial +{ + X() = default; + ~X() {} // not a literal type +}; + +X<int> x; +// CHECK: define internal void @__cxx_global_var_init() +// CHECK: call {{.*}} @_ZN1XIiEC1Ev +// CHECK: define linkonce_odr {{.*}} @_ZN1XIiEC1Ev +// CHECK: define linkonce_odr {{.*}} @_ZN1XIiEC2Ev diff --git a/clang/test/CodeGenCXX/pragma-pack-2.cpp b/clang/test/CodeGenCXX/pragma-pack-2.cpp new file mode 100644 index 0000000..9c09d5b --- /dev/null +++ b/clang/test/CodeGenCXX/pragma-pack-2.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.7.2 %s -emit-llvm -o - | FileCheck %s +// <rdar://problem/10551376> + +struct FOO { + unsigned int x; +}; + +#pragma pack(push, 2) + +// CHECK: %struct.BAR = type <{ %struct.FOO, i8, i8 }> +struct BAR : FOO { + char y; +}; + +#pragma pack(pop) + +BAR* x = 0;
\ No newline at end of file diff --git a/clang/test/CodeGenCXX/pragma-pack.cpp b/clang/test/CodeGenCXX/pragma-pack.cpp new file mode 100644 index 0000000..c0b0259 --- /dev/null +++ b/clang/test/CodeGenCXX/pragma-pack.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -triple=i686-apple-darwin10 -emit-llvm -o - | FileCheck %s + +struct Base { + virtual ~Base(); + int x; +}; + +#pragma pack(1) +struct Sub : virtual Base { + char c; +}; + +// CHECK: %struct.Sub = type <{ i32 (...)**, i8, %struct.Base }> +void f(Sub*) { } + +static int i[sizeof(Sub) == 13 ? 1 : -1]; diff --git a/clang/test/CodeGenCXX/pragma-visibility.cpp b/clang/test/CodeGenCXX/pragma-visibility.cpp new file mode 100644 index 0000000..e54626e --- /dev/null +++ b/clang/test/CodeGenCXX/pragma-visibility.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +#pragma GCC visibility push(hidden) +struct x { + static int y; +}; +#pragma GCC visibility pop +int x::y = 10; +// CHECK: @_ZN1x1yE = hidden global + +#pragma GCC visibility push(hidden) +struct __attribute((visibility("default"))) x2 { + static int y; +}; +int x2::y = 10; +// CHECK: @_ZN2x21yE = global +#pragma GCC visibility pop + +#pragma GCC visibility push(hidden) +struct x3 { + static int y; +} __attribute((visibility("default"))); +int x3::y = 10; +// CHECK: @_ZN2x31yE = global +#pragma GCC visibility pop + +#pragma GCC visibility push(hidden) +template<class T> struct x4 { + static int y; +}; +#pragma GCC visibility pop +template<> int x4<int>::y = 10; +// CHECK: @_ZN2x4IiE1yE = hidden global i32 + +#pragma GCC visibility push(hidden) +template<int x> int f() { return x; } +extern "C" int g() { return f<3>(); } +#pragma GCC visibility pop +// CHECK: define hidden i32 @g() +// CHECK: define linkonce_odr hidden i32 @_Z1fILi3EEiv() + +#pragma GCC visibility push(hidden) +template<class T> struct x5 { + void y(); +}; +#pragma GCC visibility pop +template<> void x5<int>::y() {} +// CHECK: define hidden void @_ZN2x5IiE1yEv + +#pragma GCC visibility push(hidden) +namespace n __attribute((visibility("default"))) { + void f() {} + // CHECK: define void @_ZN1n1fEv +} +#pragma GCC visibility pop + +namespace n __attribute((visibility("default"))) { +#pragma GCC visibility push(hidden) + void g() {} + // CHECK: define hidden void @_ZN1n1gEv +#pragma GCC visibility pop +} diff --git a/clang/test/CodeGenCXX/predefined-expr-sizeof.cpp b/clang/test/CodeGenCXX/predefined-expr-sizeof.cpp new file mode 100644 index 0000000..b4712ad --- /dev/null +++ b/clang/test/CodeGenCXX/predefined-expr-sizeof.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +// CHECK: store i32 59, i32* %size +// CHECK: store i32 65, i32* %size +template<typename T> +class TemplateClass { +public: + void templateClassFunction() { + int size = sizeof(__PRETTY_FUNCTION__); + } +}; + +// CHECK: store i32 35, i32* %size +// CHECK: store i32 38, i32* %size +template<typename T> +void functionTemplate(T t) { + int size = sizeof(__PRETTY_FUNCTION__); +} + +int main() { + TemplateClass<int> t1; + t1.templateClassFunction(); + TemplateClass<double> t2; + t2.templateClassFunction(); + + functionTemplate<int>(0); + functionTemplate(0.0); + + return 0; +} diff --git a/clang/test/CodeGenCXX/predefined-expr.cpp b/clang/test/CodeGenCXX/predefined-expr.cpp new file mode 100644 index 0000000..1795ec8 --- /dev/null +++ b/clang/test/CodeGenCXX/predefined-expr.cpp @@ -0,0 +1,517 @@ +// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -o - | FileCheck %s + +// CHECK: private unnamed_addr constant [15 x i8] c"externFunction\00" +// CHECK: private unnamed_addr constant [26 x i8] c"void NS::externFunction()\00" +// CHECK: private unnamed_addr constant [49 x i8] c"void functionTemplateExplicitSpecialization(int)\00" + +// CHECK: private unnamed_addr constant [95 x i8] c"void SpecializedClassTemplate<char>::memberFunctionTemplate(T, U) const [T = char, U = double]\00" +// CHECK: private unnamed_addr constant [85 x i8] c"void SpecializedClassTemplate<int>::memberFunctionTemplate(int, U) const [U = float]\00" +// CHECK: private unnamed_addr constant [57 x i8] c"void NonTypeTemplateParam<42>::size() const [Count = 42]\00" +// CHECK: private unnamed_addr constant [122 x i8] c"static void ClassWithTemplateTemplateParam<char, NS::ClassTemplate>::staticMember() [T = char, Param = NS::ClassTemplate]\00" +// CHECK: private unnamed_addr constant [106 x i8] c"void OuterClass<int *>::MiddleClass::InnerClass<float>::memberFunction(T, U) const [T = int *, U = float]\00" +// CHECK: private unnamed_addr constant [65 x i8] c"void functionTemplateWithUnnamedTemplateParameter(T) [T = float]\00" + +// CHECK: private unnamed_addr constant [60 x i8] c"void functionTemplateExplicitSpecialization(T) [T = double]\00" +// CHECK: private unnamed_addr constant [52 x i8] c"T *functionTemplateWithCompoundTypes(T *) [T = int]\00" +// CHECK: private unnamed_addr constant [54 x i8] c"T functionTemplateWithTemplateReturnType() [T = char]\00" +// CHECK: private unnamed_addr constant [57 x i8] c"void functionTemplateWithoutParameterList() [T = double]\00" +// CHECK: private unnamed_addr constant [62 x i8] c"void functionTemplateWithTwoParams(T, U) [T = int, U = float]\00" + +// CHECK: private unnamed_addr constant [22 x i8] c"classTemplateFunction\00" +// CHECK: private unnamed_addr constant [77 x i8] c"void NS::ClassTemplate<NS::Base *>::classTemplateFunction() [T = NS::Base *]\00" +// CHECK: private unnamed_addr constant [63 x i8] c"void NS::ClassTemplate<int>::classTemplateFunction() [T = int]\00" + +// CHECK: private unnamed_addr constant [18 x i8] c"functionTemplate1\00" +// CHECK: private unnamed_addr constant [53 x i8] c"void NS::Base::functionTemplate1(T) [T = NS::Base *]\00" +// CHECK: private unnamed_addr constant [46 x i8] c"void NS::Base::functionTemplate1(T) [T = int]\00" + +// CHECK: private unnamed_addr constant [23 x i8] c"anonymousUnionFunction\00" +// CHECK: private unnamed_addr constant [83 x i8] c"void NS::ContainerForAnonymousRecords::<anonymous union>::anonymousUnionFunction()\00" + +// CHECK: private unnamed_addr constant [24 x i8] c"anonymousStructFunction\00" +// CHECK: private unnamed_addr constant [85 x i8] c"void NS::ContainerForAnonymousRecords::<anonymous struct>::anonymousStructFunction()\00" + +// CHECK: private unnamed_addr constant [23 x i8] c"anonymousClassFunction\00" +// CHECK: private unnamed_addr constant [83 x i8] c"void NS::ContainerForAnonymousRecords::<anonymous class>::anonymousClassFunction()\00" + +// CHECK: private unnamed_addr constant [12 x i8] c"~Destructor\00" +// CHECK: private unnamed_addr constant [30 x i8] c"NS::Destructor::~Destructor()\00" + +// CHECK: private unnamed_addr constant [12 x i8] c"Constructor\00" +// CHECK: private unnamed_addr constant [41 x i8] c"NS::Constructor::Constructor(NS::Base *)\00" +// CHECK: private unnamed_addr constant [34 x i8] c"NS::Constructor::Constructor(int)\00" +// CHECK: private unnamed_addr constant [31 x i8] c"NS::Constructor::Constructor()\00" + +// CHECK: private unnamed_addr constant [16 x i8] c"virtualFunction\00" +// CHECK: private unnamed_addr constant [44 x i8] c"virtual void NS::Derived::virtualFunction()\00" + +// CHECK: private unnamed_addr constant [21 x i8] c"refQualifiedFunction\00" +// CHECK: private unnamed_addr constant [41 x i8] c"void NS::Base::refQualifiedFunction() &&\00" +// CHECK: private unnamed_addr constant [40 x i8] c"void NS::Base::refQualifiedFunction() &\00" + +// CHECK: private unnamed_addr constant [22 x i8] c"constVolatileFunction\00" +// CHECK: private unnamed_addr constant [54 x i8] c"void NS::Base::constVolatileFunction() const volatile\00" + +// CHECK: private unnamed_addr constant [17 x i8] c"volatileFunction\00" +// CHECK: private unnamed_addr constant [43 x i8] c"void NS::Base::volatileFunction() volatile\00" + +// CHECK: private unnamed_addr constant [14 x i8] c"constFunction\00" +// CHECK: private unnamed_addr constant [37 x i8] c"void NS::Base::constFunction() const\00" + +// CHECK: private unnamed_addr constant [26 x i8] c"functionReturingTemplate2\00" +// CHECK: private unnamed_addr constant [64 x i8] c"ClassTemplate<NS::Base *> NS::Base::functionReturingTemplate2()\00" + +// CHECK: private unnamed_addr constant [26 x i8] c"functionReturingTemplate1\00" +// CHECK: private unnamed_addr constant [57 x i8] c"ClassTemplate<int> NS::Base::functionReturingTemplate1()\00" + +// CHECK: private unnamed_addr constant [23 x i8] c"withTemplateParameter2\00" +// CHECK: private unnamed_addr constant [65 x i8] c"void NS::Base::withTemplateParameter2(ClassTemplate<NS::Base *>)\00" + +// CHECK: private unnamed_addr constant [23 x i8] c"withTemplateParameter1\00" +// CHECK: private unnamed_addr constant [58 x i8] c"void NS::Base::withTemplateParameter1(ClassTemplate<int>)\00" + +// CHECK: private unnamed_addr constant [23 x i8] c"functionReturningClass\00" +// CHECK: private unnamed_addr constant [45 x i8] c"NS::Base *NS::Base::functionReturningClass()\00" + +// CHECK: private unnamed_addr constant [23 x i8] c"functionWithParameters\00" +// CHECK: private unnamed_addr constant [64 x i8] c"void NS::Base::functionWithParameters(int, float *, NS::Base *)\00" + +// CHECK: private unnamed_addr constant [17 x i8] c"variadicFunction\00" +// CHECK: private unnamed_addr constant [42 x i8] c"void NS::Base::variadicFunction(int, ...)\00" + +// CHECK: private unnamed_addr constant [41 x i8] c"virtual void NS::Base::virtualFunction()\00" + +// CHECK: private unnamed_addr constant [15 x i8] c"inlineFunction\00" +// CHECK: private unnamed_addr constant [32 x i8] c"void NS::Base::inlineFunction()\00" + +// CHECK: private unnamed_addr constant [15 x i8] c"staticFunction\00" +// CHECK: private unnamed_addr constant [39 x i8] c"static void NS::Base::staticFunction()\00" + +// CHECK: private unnamed_addr constant [26 x i8] c"topLevelNamespaceFunction\00" +// CHECK: private unnamed_addr constant [59 x i8] c"void ClassInTopLevelNamespace::topLevelNamespaceFunction()\00" + +// CHECK: private unnamed_addr constant [27 x i8] c"anonymousNamespaceFunction\00" +// CHECK: private unnamed_addr constant [84 x i8] c"void <anonymous namespace>::ClassInAnonymousNamespace::anonymousNamespaceFunction()\00" + +// CHECK: private unnamed_addr constant [19 x i8] c"localClassFunction\00" +// CHECK: private unnamed_addr constant [59 x i8] c"void NS::localClass(int)::LocalClass::localClassFunction()\00" + + + +int printf(const char * _Format, ...); + +class ClassInTopLevelNamespace { +public: + void topLevelNamespaceFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } +}; + +namespace { + + class ClassInAnonymousNamespace { + public: + void anonymousNamespaceFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + }; + +} // end anonymous namespace + +namespace NS { + +template<typename T> +class ClassTemplate { +public: + void classTemplateFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } +}; + +class Base { +public: + static void staticFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + inline void inlineFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + virtual void virtualFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + void functionWithParameters(int, float*, Base* base) { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + Base *functionReturningClass() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + return 0; + } + + void variadicFunction(int, ...) { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + void withTemplateParameter1(ClassTemplate<int>) { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + void withTemplateParameter2(ClassTemplate<Base *>) { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + ClassTemplate<int> functionReturingTemplate1() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + return ClassTemplate<int>(); + } + + ClassTemplate<Base *> functionReturingTemplate2() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + return ClassTemplate<Base *>(); + } + + template<typename T> + void functionTemplate1(T t) { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + void constFunction() const { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + void volatileFunction() volatile { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + void constVolatileFunction() const volatile { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + void refQualifiedFunction() & { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + void refQualifiedFunction() && { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } +}; + +class Derived : public Base { +public: + // Virtual function without being explicitly written. + void virtualFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } +}; + +class Constructor { +public: + Constructor() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + Constructor(int) { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + + Constructor(Base *) { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } +}; + +class Destructor { +public: + ~Destructor() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } +}; + +class ContainerForAnonymousRecords { +public: + class { + public: + void anonymousClassFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + } anonymousClass; + + struct { + void anonymousStructFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + } anonymousStruct; + + union { + void anonymousUnionFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + } anonymousUnion; +}; + +void localClass(int) { + class LocalClass { + public: + void localClassFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + }; + LocalClass lc; + lc.localClassFunction(); +} + +extern void externFunction() { + printf("__func__ %s\n", __func__); + printf("__FUNCTION__ %s\n", __FUNCTION__); + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); +} + +} // end NS namespace + +// additional tests for __PRETTY_FUNCTION__ +template <typename T, typename U> +void functionTemplateWithTwoParams(T, U) +{ + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); +} + +template <typename T> +void functionTemplateWithoutParameterList() +{ + T t = T(); + + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); +} + +template <typename T> +T functionTemplateWithTemplateReturnType() +{ + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + + return T(); +} + +template <typename T> +T * functionTemplateWithCompoundTypes(T a[]) +{ + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + + return 0; +} + +template <typename T> +void functionTemplateExplicitSpecialization(T t) +{ + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); +} + +template <> +void functionTemplateExplicitSpecialization<int>(int i) +{ + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); +} + +template <typename, typename T> +void functionTemplateWithUnnamedTemplateParameter(T t) +{ + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); +} + +template <typename T> +class OuterClass +{ +public: + class MiddleClass + { + public: + template <typename U> + class InnerClass + { + public: + void memberFunction(T x, U y) const + { + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } + }; + }; +}; + +template <typename T, template <typename> class Param = NS::ClassTemplate> +class ClassWithTemplateTemplateParam +{ +public: + static void staticMember() + { + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } +}; + +template <int Count> +class NonTypeTemplateParam +{ +public: + void size() const + { + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } +}; + +template <typename T> +class SpecializedClassTemplate +{ +public: + template <typename U> + void memberFunctionTemplate(T t, U u) const + { + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } +}; + +template <> +class SpecializedClassTemplate<int> +{ +public: + template <typename U> + void memberFunctionTemplate(int i, U u) const + { + printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__); + } +}; + +int main() { + ClassInAnonymousNamespace anonymousNamespace; + anonymousNamespace.anonymousNamespaceFunction(); + + ClassInTopLevelNamespace topLevelNamespace; + topLevelNamespace.topLevelNamespaceFunction(); + + NS::Base::staticFunction(); + + NS::Base b; + b.inlineFunction(); + b.virtualFunction(); + b.variadicFunction(0); + b.functionWithParameters(0, 0, 0); + b.functionReturningClass(); + + b.withTemplateParameter1(NS::ClassTemplate<int>()); + b.withTemplateParameter2(NS::ClassTemplate<NS::Base *>()); + b.functionReturingTemplate1(); + b.functionReturingTemplate2(); + b.functionTemplate1<int>(0); + b.functionTemplate1<NS::Base *>(0); + b.constFunction(); + b.volatileFunction(); + b.constVolatileFunction(); + b.refQualifiedFunction(); + NS::Base().refQualifiedFunction(); + + NS::Derived d; + d.virtualFunction(); + + NS::ClassTemplate<int> t1; + t1.classTemplateFunction(); + NS::ClassTemplate<NS::Base *> t2; + t2.classTemplateFunction(); + + NS::Constructor c1; + NS::Constructor c2(0); + NS::Constructor c3((NS::Base *)0); + + { + NS::Destructor destructor; + } + + NS::ContainerForAnonymousRecords anonymous; + anonymous.anonymousClass.anonymousClassFunction(); + anonymous.anonymousStruct.anonymousStructFunction(); + anonymous.anonymousUnion.anonymousUnionFunction(); + + NS::localClass(0); + + NS::externFunction(); + + // additional tests for __PRETTY_FUNCTION__ + + functionTemplateWithTwoParams(0, 0.0f); + functionTemplateWithoutParameterList<double>(); + functionTemplateWithTemplateReturnType<char>(); + int array[] = { 1, 2, 3 }; + functionTemplateWithCompoundTypes(array); + functionTemplateExplicitSpecialization(0); + functionTemplateExplicitSpecialization(0.0); + functionTemplateWithUnnamedTemplateParameter<int, float>(0.0f); + + OuterClass<int *>::MiddleClass::InnerClass<float> omi; + omi.memberFunction(0, 0.0f); + + ClassWithTemplateTemplateParam<char>::staticMember(); + + NonTypeTemplateParam<42> ntt; + ntt.size(); + + SpecializedClassTemplate<int> sct1; + sct1.memberFunctionTemplate(0, 0.0f); + SpecializedClassTemplate<char> sct2; + sct2.memberFunctionTemplate('0', 0.0); + + return 0; +} diff --git a/clang/test/CodeGenCXX/ptr-to-datamember.cpp b/clang/test/CodeGenCXX/ptr-to-datamember.cpp new file mode 100644 index 0000000..a6f523e --- /dev/null +++ b/clang/test/CodeGenCXX/ptr-to-datamember.cpp @@ -0,0 +1,99 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s + +extern "C" int printf(...); + +struct F { + F() : iF(1), fF(2.0) {} + int iF; + float fF; +}; + +struct V { + double d; + int iV; +}; + +struct B : virtual V{ + double d; + int iB; +}; + +struct B1 : virtual V{ + double d; + int iB1; +}; + +class A : public B, public B1 { +public: + A() : f(1.0), d(2.0), Ai(3) {} + float f; + double d; + int Ai; + F Af; +}; + +template <typename T> struct TT { + int T::t::*pti; +}; + +struct I { + typedef I t; + int x; +}; + +void pr(const F& b) { + printf(" %d %f\n", b.iF, b.fF); +} + +void test_aggr_pdata(A& a1) { + F A::* af = &A::Af; + pr(a1.*af); + + (a1.*af).iF = 100; + (a1.*af).fF = 200.00; + printf(" %d %f\n", (a1.*af).iF, (a1.*af).fF); + pr(a1.*af); + + (a1.*af).iF++; + (a1.*af).fF--; + --(a1.*af).fF; + pr(a1.*af); +} + +void test_aggr_pdata_1(A* pa) { + F A::* af = &A::Af; + pr(pa->*af); + + (pa->*af).iF = 100; + (pa->*af).fF = 200.00; + printf(" %d %f\n", (pa->*af).iF, (pa->*af).fF); + pr(pa->*af); + + (pa->*af).iF++; + (pa->*af).fF--; + --(pa->*af).fF; + pr(pa->*af); +} + +int main() +{ + A a1; + TT<I> tt; + I i; + int A::* pa = &A::Ai; + float A::* pf = &A::f; + double A::* pd = &A::d; + tt.pti = &I::x; + printf("%d %d %d\n", &A::Ai, &A::f, &A::d); + printf("%d\n", &A::B::iB); + printf("%d\n", &A::B1::iB1); + printf("%d\n", &A::f); + printf("%d\n", &A::B::iV); + printf("%d\n", &A::B1::iV); + printf("%d\n", &A::B::V::iV); + printf("%d\n", &A::B1::V::iV); + printf("%d, %f, %f \n", a1.*pa, a1.*pf, a1.*pd); + printf("%d\n", i.*tt.pti); + test_aggr_pdata(a1); + test_aggr_pdata_1(&a1); +} diff --git a/clang/test/CodeGenCXX/ptr-to-member-function.cpp b/clang/test/CodeGenCXX/ptr-to-member-function.cpp new file mode 100644 index 0000000..3989c03 --- /dev/null +++ b/clang/test/CodeGenCXX/ptr-to-member-function.cpp @@ -0,0 +1,71 @@ +// REQUIRES: x86-registered-target,x86-64-registered-target +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -S %s -o %t-64.s +// RUN: FileCheck -check-prefix LP64 --input-file=%t-64.s %s +// RUN: %clang_cc1 -triple i386-apple-darwin -std=c++11 -S %s -o %t-32.s +// RUN: FileCheck -check-prefix LP32 --input-file=%t-32.s %s +// 13.3.3.2 Ranking implicit conversion sequences + +extern "C" int printf(...); + +struct A { +int Ai; +bool foo(int* arg) const; +}; + +bool A::foo(int* arg) const { + printf("A::foo(%d)\n", *arg); + return true; +} + +struct B : public A { + void bf() { printf("B::bf called\n"); } +}; + +struct C : public B { }; + +// conversion of B::* to C::* is better than conversion of A::* to C::* +typedef void (A::*pmfa)(); +typedef void (B::*pmfb)(); +typedef void (C::*pmfc)(); + +struct X { + operator pmfa(); + operator pmfb() { + return &B::bf; + } +}; + + +void g(pmfc pm) { + C c; + (c.*pm)(); +} + +void test2(X x) +{ + g(x); +} + +struct B1 { + bool (A::*pmf)(int*) const; + + B1(int i) : pmf(&A::foo), im(i) { + ((A*)this->*pmf)(&im); + } + + int im; +}; + +int main() +{ + X x; + test2(x); + B1 b = B1(1); + B1 c = B1(2); +} + +// CHECK-LP64: callq __ZN1XcvM1BFvvEEv +// CHECK-LP64: callq __Z1gM1CFvvE + +// CHECK-LP32: calll L__ZN1XcvM1BFvvEEv +// CHECK-LP32: calll __Z1gM1CFvvE diff --git a/clang/test/CodeGenCXX/reference-bind-default-argument.cpp b/clang/test/CodeGenCXX/reference-bind-default-argument.cpp new file mode 100644 index 0000000..acce962 --- /dev/null +++ b/clang/test/CodeGenCXX/reference-bind-default-argument.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 %s -emit-llvm-only -verify + +struct A {}; +struct B : A {}; +void a(const A& x = B()); +void b() { a(); } diff --git a/clang/test/CodeGenCXX/reference-cast.cpp b/clang/test/CodeGenCXX/reference-cast.cpp new file mode 100644 index 0000000..1d08b2b --- /dev/null +++ b/clang/test/CodeGenCXX/reference-cast.cpp @@ -0,0 +1,194 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10 -o - %s | FileCheck %s + +// PR6024 +extern int i; + +// CHECK: define i32* @_Z16lvalue_noop_castv() nounwind +const int &lvalue_noop_cast() { + if (i == 0) + // CHECK: store i32 17, i32* + return (const int&)17; + else if (i == 1) + // CHECK: store i32 17, i32* + return static_cast<const int&>(17); + // CHECK: store i32 17, i32* + return 17; +} + +// CHECK: define i16* @_Z20lvalue_integral_castv() +const short &lvalue_integral_cast() { + if (i == 0) + // CHECK: store i16 17, i16* + return (const short&)17; + else if (i == 1) + // CHECK: store i16 17, i16* + return static_cast<const short&>(17); + // CHECK: store i16 17, i16* + return 17; +} + +// CHECK: define i16* @_Z29lvalue_floating_integral_castv() +const short &lvalue_floating_integral_cast() { + if (i == 0) + // CHECK: store i16 17, i16* + return (const short&)17.5; + else if (i == 1) + // CHECK: store i16 17, i16* + return static_cast<const short&>(17.5); + // CHECK: store i16 17, i16* + return 17.5; +} + +// CHECK: define float* @_Z29lvalue_integral_floating_castv() +const float &lvalue_integral_floating_cast() { + if (i == 0) + // CHECK: store float 1.700000e+{{0*}}1, float* + return (const float&)17; + else if (i == 1) + // CHECK: store float 1.700000e+{{0*}}1, float* + return static_cast<const float&>(17); + // CHECK: store float 1.700000e+{{0*}}1, float* + return 17; +} + +// CHECK: define float* @_Z20lvalue_floating_castv() +const float &lvalue_floating_cast() { + if (i == 0) + // CHECK: store float 1.700000e+{{0*}}1, float* + return (const float&)17.0; + else if (i == 1) + // CHECK: store float 1.700000e+{{0*}}1, float* + return static_cast<const float&>(17.0); + // CHECK: store float 1.700000e+{{0*}}1, float* + return 17.0; +} + +int get_int(); + +// CHECK: define i8* @_Z24lvalue_integer_bool_castv() +const bool &lvalue_integer_bool_cast() { + if (i == 0) + // CHECK: call i32 @_Z7get_intv() + // CHECK: store i8 + return (const bool&)get_int(); + else if (i == 1) + // CHECK: call i32 @_Z7get_intv() + // CHECK: store i8 + return static_cast<const bool&>(get_int()); + // CHECK: call i32 @_Z7get_intv() + // CHECK: store i8 + return get_int(); +} + +float get_float(); + +// CHECK: define i8* @_Z25lvalue_floating_bool_castv() +const bool &lvalue_floating_bool_cast() { + if (i == 0) + // CHECK: call float @_Z9get_floatv() + // CHECK: fcmp une float + // CHECK: store i8 + return (const bool&)get_float(); + else if (i == 1) + // CHECK: call float @_Z9get_floatv() + // CHECK: fcmp une float + // CHECK: store i8 + return static_cast<const bool&>(get_float()); + // CHECK: call float @_Z9get_floatv() + // CHECK: fcmp une float + // CHECK: store i8 + return get_float(); +} + +struct X { }; +typedef int X::*pm; +typedef int (X::*pmf)(int); + +pm get_pointer_to_member_data(); +pmf get_pointer_to_member_function(); + +// CHECK: define i8* @_Z26lvalue_ptrmem_to_bool_castv() +const bool &lvalue_ptrmem_to_bool_cast() { + if (i == 0) + // CHECK: call i64 @_Z26get_pointer_to_member_datav() + // CHECK: store i8 + // CHECK: store i8* + return (const bool&)get_pointer_to_member_data(); + else if (i == 1) + // CHECK: call i64 @_Z26get_pointer_to_member_datav() + // CHECK: store i8 + // CHECK: store i8* + return static_cast<const bool&>(get_pointer_to_member_data()); + // CHECK: call i64 @_Z26get_pointer_to_member_datav() + // CHECK: store i8 + // CHECK: store i8* + return get_pointer_to_member_data(); +} + +// CHECK: define i8* @_Z27lvalue_ptrmem_to_bool_cast2v +const bool &lvalue_ptrmem_to_bool_cast2() { + if (i == 0) + // CHECK: {{call.*_Z30get_pointer_to_member_functionv}} + // CHECK: store i8 + // CHECK: store i8* + return (const bool&)get_pointer_to_member_function(); + else if (i == 1) + // CHECK: {{call.*_Z30get_pointer_to_member_functionv}} + // CHECK: store i8 + // CHECK: store i8* + return static_cast<const bool&>(get_pointer_to_member_function()); + // CHECK: {{call.*_Z30get_pointer_to_member_functionv}} + // CHECK: store i8 + // CHECK: store i8* + return get_pointer_to_member_function(); +} + +_Complex double get_complex_double(); + +// CHECK: {{define.*_Z2f1v}} +const _Complex float &f1() { + if (i == 0) + // CHECK: {{call.*_Z18get_complex_doublev}} + // CHECK: fptrunc + // CHECK: fptrunc + // CHECK: store float + // CHECK: store float + return (const _Complex float&)get_complex_double(); + else if (i == 1) + // CHECK: {{call.*_Z18get_complex_doublev}} + // CHECK: fptrunc + // CHECK: fptrunc + // CHECK: store float + // CHECK: store float + return static_cast<const _Complex float&>(get_complex_double()); + // CHECK: {{call.*_Z18get_complex_doublev}} + // CHECK: fptrunc + // CHECK: fptrunc + // CHECK: store float + // CHECK: store float + return get_complex_double(); +} + +// CHECK: define i32 @_Z7pr10592RKi(i32* +unsigned pr10592(const int &v) { + // CHECK: [[VADDR:%[a-zA-Z0-9.]+]] = alloca i32* + // CHECK-NEXT: [[REFTMP:%[a-zA-Z0-9.]+]] = alloca i32 + // CHECK-NEXT: store i32* [[V:%[a-zA-Z0-9.]+]], i32** [[VADDR]] + // CHECK-NEXT: [[VADDR_1:%[a-zA-Z0-9.]+]] = load i32** [[VADDR]] + // CHECK-NEXT: [[VVAL:%[a-zA-Z0-9.]+]] = load i32* [[VADDR_1]] + // CHECK-NEXT: store i32 [[VVAL]], i32* [[REFTMP]] + // CHECK-NEXT: [[VVAL_I:%[a-zA-Z0-9.]+]] = load i32* [[REFTMP]] + // CHECK-NEXT: ret i32 [[VVAL_I]] + return static_cast<const unsigned &>(v); +} + +namespace PR10650 { + struct Helper { + unsigned long long id(); + }; + unsigned long long test(Helper *obj) { + return static_cast<const unsigned long long&>(obj->id()); + } + // CHECK: define i64 @_ZN7PR106504testEPNS_6HelperE + // CHECK: store i64 +} diff --git a/clang/test/CodeGenCXX/reference-field.cpp b/clang/test/CodeGenCXX/reference-field.cpp new file mode 100644 index 0000000..0312029 --- /dev/null +++ b/clang/test/CodeGenCXX/reference-field.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s -O2 | grep "@_Z1bv" + +// Make sure the call to b() doesn't get optimized out. +extern struct x {char& x,y;}y; +int b(); +int a() { if (!&y.x) b(); } diff --git a/clang/test/CodeGenCXX/reference-in-block-args.cpp b/clang/test/CodeGenCXX/reference-in-block-args.cpp new file mode 100644 index 0000000..1ff1ae2 --- /dev/null +++ b/clang/test/CodeGenCXX/reference-in-block-args.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fblocks %s -emit-llvm -o %t +// rdar: // 8041962 + +extern "C" int printf(const char*, ...); + +struct ST { + int filler; + int referrer; +}; + +void OUTER_BLOCK(void (^fixer)(ST& ref)) { + ST ref = {2, 100}; + fixer(ref); +} + +void INNER_BLOCK(int (^largeDo) ()) { + printf("%d\n", largeDo()); +} + +void scan() { + OUTER_BLOCK(^(ST &ref) { + INNER_BLOCK(^() { return ref.referrer + ref.filler; }); + }); + +} + +int main() { + scan(); +} diff --git a/clang/test/CodeGenCXX/reference-in-blocks.cpp b/clang/test/CodeGenCXX/reference-in-blocks.cpp new file mode 100644 index 0000000..388ec7c --- /dev/null +++ b/clang/test/CodeGenCXX/reference-in-blocks.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -fblocks %s -emit-llvm -o %t + +extern "C" int printf(const char*, ...); + +template<typename T> class range { +public: +T _i; + range(T i) {_i = i;}; + T get() {return _i;}; +}; + +// rdar: // 7495203 +class A { + public: + A() : field(10), d1(3.14) {} + void F(); + void S() { + printf(" field = %d\n", field); + printf(" field = %f\n", d1); + } + int field; + double d1; +}; + +void A::F() + { + __block A &tlc = *this; + // crashed in code gen (radar 7495203) + ^{ tlc.S(); }(); + } + +int main() { + + // works + void (^bl)(range<int> ) = ^(range<int> i){printf("Hello Blocks %d\n", i.get()); }; + + //crashes in godegen? + void (^bl2)(range<int>& ) = ^(range<int>& i){printf("Hello Blocks %d\n", i.get()); }; + + A *a = new A; + a->F(); + return 0; +} diff --git a/clang/test/CodeGenCXX/reference-init.cpp b/clang/test/CodeGenCXX/reference-init.cpp new file mode 100644 index 0000000..9469c84 --- /dev/null +++ b/clang/test/CodeGenCXX/reference-init.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -emit-llvm-only -verify %s + +struct XPTParamDescriptor {}; +struct nsXPTParamInfo { + nsXPTParamInfo(const XPTParamDescriptor& desc); +}; +void a(XPTParamDescriptor *params) { + const nsXPTParamInfo& paramInfo = params[0]; +} + +// CodeGen of reference initialized const arrays. +namespace PR5911 { + template <typename T, int N> int f(const T (&a)[N]) { return N; } + int iarr[] = { 1 }; + int test() { return f(iarr); } +} + +// radar 7574896 +struct Foo { int foo; }; +Foo& ignoreSetMutex = *(new Foo); + +// Binding to a bit-field that requires a temporary. +struct { int bitfield : 3; } s = { 3 }; +const int &s2 = s.bitfield; diff --git a/clang/test/CodeGenCXX/references.cpp b/clang/test/CodeGenCXX/references.cpp new file mode 100644 index 0000000..d315f71 --- /dev/null +++ b/clang/test/CodeGenCXX/references.cpp @@ -0,0 +1,313 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin -verify -emit-llvm -o - %s | FileCheck %s +void t1() { + // CHECK: define void @_Z2t1v + // CHECK: [[REFLOAD:%.*]] = load i32** @a, align 8 + // CHECK: load i32* [[REFLOAD]], align 4 + extern int& a; + int b = a; +} + +void t2(int& a) { + // CHECK: define void @_Z2t2Ri + // CHECK: [[REFLOAD2:%.*]] = load i32** {{.*}}, align 8 + // CHECK: load i32* [[REFLOAD2]], align 4 + int b = a; +} + +int g; +int& gr = g; +int& grr = gr; +void t3() { + int b = gr; +} + +// Test reference binding. + +struct C { int a; }; +void f(const bool&); +void f(const int&); +void f(const _Complex int&); +void f(const C&); + +C aggregate_return(); + +bool& bool_reference_return(); +int& int_reference_return(); +_Complex int& complex_int_reference_return(); +C& aggregate_reference_return(); + +void test_bool() { + bool a = true; + f(a); + + f(true); + + bool_reference_return() = true; + a = bool_reference_return(); + + struct { const bool& b; } b = { true }; +} + +void test_scalar() { + int a = 10; + f(a); + + struct { int bitfield : 3; } s = { 3 }; + f(s.bitfield); + + f(10); + + __attribute((vector_size(16))) typedef int vec4; + f((vec4){1,2,3,4}[0]); + + int_reference_return() = 10; + a = int_reference_return(); + + struct { const int& a; } agg = { 10 }; +} + +void test_complex() { + _Complex int a = 10i; + f(a); + + f(10i); + + complex_int_reference_return() = 10i; + a = complex_int_reference_return(); + + struct { const _Complex int &a; } agg = { 10i }; +} + +void test_aggregate() { + C c; + f(c); + + f(aggregate_return()); + aggregate_reference_return().a = 10; + + c = aggregate_reference_return(); + + struct { const C& a; } agg = { C() }; +} + +int& reference_return() { + return g; +} + +int reference_decl() { + int& a = g; + const int& b = 1; + return a+b; +} + +struct A { + int& b(); +}; + +void f(A* a) { + int b = a->b(); +} + +// PR5122 +void *foo = 0; +void * const & kFoo = foo; + +struct D : C { D(); ~D(); }; + +void h() { + // CHECK: call void @_ZN1DD1Ev + const C& c = D(); +} + +namespace T { + struct A { + A(); + ~A(); + }; + + struct B { + B(); + ~B(); + A f(); + }; + + void f() { + // CHECK: call void @_ZN1T1BC1Ev + // CHECK: call void @_ZN1T1B1fEv + // CHECK: call void @_ZN1T1BD1Ev + const A& a = B().f(); + // CHECK: call void @_ZN1T1fEv + f(); + // CHECK: call void @_ZN1T1AD1Ev + } +} + +// PR5227. +namespace PR5227 { +void f(int &a) { + (a = 10) = 20; +} +} + +// PR5590 +struct s0; +struct s1 { struct s0 &s0; }; +void f0(s1 a) { s1 b = a; } + +// PR6024 +// CHECK: @_Z2f2v() +// CHECK: alloca i32, +// CHECK-NEXT: store +// CHECK-NEXT: ret +const int &f2() { return 0; } + +// Don't constant fold const reference parameters with default arguments to +// their default arguments. +namespace N1 { + const int foo = 1; + // CHECK: @_ZN2N14test + void test(const int& arg = foo) { + // Ensure this array is on the stack where we can set values instead of + // being a global constant. + // CHECK: %args_array = alloca + const int* const args_array[] = { &arg }; + } +} + +// Bind to subobjects while extending the life of the complete object. +namespace N2 { + class X { + public: + X(const X&); + X &operator=(const X&); + ~X(); + }; + + struct P { + X first; + }; + + P getP(); + + // CHECK: define void @_ZN2N21fEi + // CHECK: call void @_ZN2N24getPEv + // CHECK: getelementptr inbounds + // CHECK: store i32 17 + // CHECK: call void @_ZN2N21PD1Ev + void f(int i) { + const X& xr = getP().first; + i = 17; + } + + struct SpaceWaster { + int i, j; + }; + + struct ReallyHasX { + X x; + }; + + struct HasX : ReallyHasX { }; + + struct HasXContainer { + HasX has; + }; + + struct Y : SpaceWaster, HasXContainer { }; + struct Z : SpaceWaster, Y { }; + + Z getZ(); + + // CHECK: define void @_ZN2N21gEi + // CHECK: call void @_ZN2N24getZEv + // CHECK: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK: {{getelementptr inbounds.*i32 0, i32 0}} + // CHECK: store i32 19 + // CHECK: call void @_ZN2N21ZD1Ev + // CHECK: ret void + void g(int i) { + const X &xr = getZ().has.x; + i = 19; + } +} + +namespace N3 { + +// PR7326 + +struct A { + explicit A(int); + ~A(); +}; + +// CHECK: define internal void @__cxx_global_var_init +// CHECK: call void @_ZN2N31AC1Ei(%"struct.N3::A"* @_ZGRN2N35sA123E, i32 123) +// CHECK: call i32 @__cxa_atexit +// CHECK: ret void +const A &sA123 = A(123); +} + +namespace N4 { + +struct A { + A(); + ~A(); +}; + +void f() { + // CHECK: define void @_ZN2N41fEv + // CHECK: call void @_ZN2N41AC1Ev(%"struct.N4::A"* @_ZGRZN2N41fEvE2ar) + // CHECK: call i32 @__cxa_atexit + // CHECK: ret void + static const A& ar = A(); + +} +} + +// PR9494 +namespace N5 { +struct AnyS { bool b; }; +void f(const bool&); +AnyS g(); +void h() { + // CHECK: call i8 @_ZN2N51gEv() + // CHECK: call void @_ZN2N51fERKb(i8* + f(g().b); +} +} + +// PR9565 +namespace PR9565 { + struct a { int a : 10, b : 10; }; + // CHECK: define void @_ZN6PR95651fEv() + void f() { + // CHECK: call void @llvm.memcpy + a x = { 0, 0 }; + // CHECK: [[WITH_SEVENTEEN:%[a-zA-Z0-9]+]] = or i32 [[WITHOUT_SEVENTEEN:%[a-zA-Z0-9]+]], 17 + // CHECK: store i32 [[WITH_SEVENTEEN]], i32* [[XA:%[a-zA-Z0-9]+]] + x.a = 17; + // CHECK-NEXT: bitcast + // CHECK-NEXT: load + // CHECK-NEXT: and + // CHECK-NEXT: shl + // CHECK-NEXT: ashr + // CHECK-NEXT: store i32 + // CHECK-NEXT: store i32* + const int &y = x.a; + // CHECK-NEXT: bitcast + // CHECK-NEXT: load + // CHECK-NEXT: and + // CHECK-NEXT: or + // CHECK-NEXT: store i32 + x.b = 19; + // CHECK-NEXT: ret void + } +} + +namespace N6 { + extern struct x {char& x;}y; + int a() { return y.x; } + // CHECK: define i32 @_ZN2N61aEv + // CHECK: [[REFLOAD3:%.*]] = load i8** getelementptr inbounds (%"struct.N6::x"* @_ZN2N61yE, i32 0, i32 0), align 8 + // CHECK: load i8* [[REFLOAD3]], align 1 +} diff --git a/clang/test/CodeGenCXX/regparm.cpp b/clang/test/CodeGenCXX/regparm.cpp new file mode 100644 index 0000000..f0ebd2b --- /dev/null +++ b/clang/test/CodeGenCXX/regparm.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s + + +// CHECK: _Z3fooRi(i32* inreg +void __attribute__ ((regparm (1))) foo(int &a) { +} diff --git a/clang/test/CodeGenCXX/reinterpret-cast.cpp b/clang/test/CodeGenCXX/reinterpret-cast.cpp new file mode 100644 index 0000000..dafa675 --- /dev/null +++ b/clang/test/CodeGenCXX/reinterpret-cast.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s -std=c++11 +void *f1(unsigned long l) { + return reinterpret_cast<void *>(l); +} + +unsigned long f2() { + return reinterpret_cast<unsigned long>(nullptr); +} + +unsigned long f3(void *p) { + return reinterpret_cast<unsigned long>(p); +} + +void f4(int*&); +void f5(void*& u) { + f4(reinterpret_cast<int*&>(u)); +} diff --git a/clang/test/CodeGenCXX/rtti-fundamental.cpp b/clang/test/CodeGenCXX/rtti-fundamental.cpp new file mode 100644 index 0000000..2495e96 --- /dev/null +++ b/clang/test/CodeGenCXX/rtti-fundamental.cpp @@ -0,0 +1,116 @@ +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +#include <typeinfo> + +std::type_info foo() { + return typeid(void); +} + +namespace __cxxabiv1 { + struct __fundamental_type_info { + virtual ~__fundamental_type_info(); + }; + + __fundamental_type_info::~__fundamental_type_info() { } +} + +// void +// CHECK: @_ZTIv = unnamed_addr constant +// CHECK: @_ZTIPv = unnamed_addr constant +// CHECK: @_ZTIPKv = unnamed_addr constant + +// std::nullptr_t +// CHECK: @_ZTIDn = unnamed_addr constant +// CHECK: @_ZTIPDn = unnamed_addr constant +// CHECK: @_ZTIPKDn = unnamed_addr constant + +// bool +// CHECK: @_ZTIb = unnamed_addr constant +// CHECK: @_ZTIPb = unnamed_addr constant +// CHECK: @_ZTIPKb = unnamed_addr constant + +// wchar_t +// CHECK: @_ZTIw = unnamed_addr constant +// CHECK: @_ZTIPw = unnamed_addr constant +// CHECK: @_ZTIPKw = unnamed_addr constant + +// char +// CHECK: @_ZTIc = unnamed_addr constant +// CHECK: @_ZTIPc = unnamed_addr constant +// CHECK: @_ZTIPKc = unnamed_addr constant + +// unsigned char +// CHECK: @_ZTIh = unnamed_addr constant +// CHECK: @_ZTIPh = unnamed_addr constant +// CHECK: @_ZTIPKh = unnamed_addr constant + +// signed char +// CHECK: @_ZTIa = unnamed_addr constant +// CHECK: @_ZTIPa = unnamed_addr constant +// CHECK: @_ZTIPKa = unnamed_addr constant + +// short +// CHECK: @_ZTIs = unnamed_addr constant +// CHECK: @_ZTIPs = unnamed_addr constant +// CHECK: @_ZTIPKs = unnamed_addr constant + +// unsigned short +// CHECK: @_ZTIt = unnamed_addr constant +// CHECK: @_ZTIPt = unnamed_addr constant +// CHECK: @_ZTIPKt = unnamed_addr constant + +// int +// CHECK: @_ZTIi = unnamed_addr constant +// CHECK: @_ZTIPi = unnamed_addr constant +// CHECK: @_ZTIPKi = unnamed_addr constant + +// unsigned int +// CHECK: @_ZTIj = unnamed_addr constant +// CHECK: @_ZTIPj = unnamed_addr constant +// CHECK: @_ZTIPKj = unnamed_addr constant + +// long +// CHECK: @_ZTIl = unnamed_addr constant +// CHECK: @_ZTIPl = unnamed_addr constant +// CHECK: @_ZTIPKl = unnamed_addr constant + +// unsigned long +// CHECK: @_ZTIm = unnamed_addr constant +// CHECK: @_ZTIPm = unnamed_addr constant +// CHECK: @_ZTIPKm = unnamed_addr constant + +// long long +// CHECK: @_ZTIx = unnamed_addr constant +// CHECK: @_ZTIPx = unnamed_addr constant +// CHECK: @_ZTIPKx = unnamed_addr constant + +// unsigned long long +// CHECK: @_ZTIy = unnamed_addr constant +// CHECK: @_ZTIPy = unnamed_addr constant +// CHECK: @_ZTIPKy = unnamed_addr constant + +// float +// CHECK: @_ZTIf = unnamed_addr constant +// CHECK: @_ZTIPf = unnamed_addr constant +// CHECK: @_ZTIPKf = unnamed_addr constant + +// double +// CHECK: @_ZTId = unnamed_addr constant +// CHECK: @_ZTIPd = unnamed_addr constant +// CHECK: @_ZTIPKd = unnamed_addr constant + +// long double +// CHECK: @_ZTIe = unnamed_addr constant +// CHECK: @_ZTIPe = unnamed_addr constant +// CHECK: @_ZTIPKe = unnamed_addr constant + +// char16_t +// CHECK: @_ZTIDs = unnamed_addr constant +// CHECK: @_ZTIPDs = unnamed_addr constant +// CHECK: @_ZTIPKDs = unnamed_addr constant + +// char32_t +// CHECK: @_ZTIDi = unnamed_addr constant +// CHECK: @_ZTIPDi = unnamed_addr constant +// CHECK: @_ZTIPKDi = unnamed_addr constant + diff --git a/clang/test/CodeGenCXX/rtti-layout.cpp b/clang/test/CodeGenCXX/rtti-layout.cpp new file mode 100644 index 0000000..7128c4e --- /dev/null +++ b/clang/test/CodeGenCXX/rtti-layout.cpp @@ -0,0 +1,205 @@ +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s +#include <typeinfo> + +// vtables. +extern "C" { + const void *_ZTVN10__cxxabiv123__fundamental_type_infoE; + const void *_ZTVN10__cxxabiv117__class_type_infoE; + const void *_ZTVN10__cxxabiv120__si_class_type_infoE; + const void *_ZTVN10__cxxabiv121__vmi_class_type_infoE; + const void *_ZTVN10__cxxabiv119__pointer_type_infoE; + const void *_ZTVN10__cxxabiv129__pointer_to_member_type_infoE; +}; +#define fundamental_type_info_vtable _ZTVN10__cxxabiv123__fundamental_type_infoE +#define class_type_info_vtable _ZTVN10__cxxabiv117__class_type_infoE +#define si_class_type_info_vtable _ZTVN10__cxxabiv120__si_class_type_infoE +#define vmi_class_type_info_vtable _ZTVN10__cxxabiv121__vmi_class_type_infoE +#define pointer_type_info_vtable _ZTVN10__cxxabiv119__pointer_type_infoE +#define pointer_to_member_type_info_vtable _ZTVN10__cxxabiv129__pointer_to_member_type_infoE + +class __pbase_type_info : public std::type_info { +public: + unsigned int __flags; + const std::type_info *__pointee; + + enum __masks { + __const_mask = 0x1, + __volatile_mask = 0x2, + __restrict_mask = 0x4, + __incomplete_mask = 0x8, + __incomplete_class_mask = 0x10 + }; +}; + +class __class_type_info : public std::type_info { }; + +class __si_class_type_info : public __class_type_info { +public: + const __class_type_info *__base_type; +}; + +struct __base_class_type_info { +public: + const __class_type_info *__base_type; + long __offset_flags; + + enum __offset_flags_masks { + __virtual_mask = 0x1, + __public_mask = 0x2, + __offset_shift = 8 + }; +}; + +class __vmi_class_type_info : public __class_type_info { +public: + unsigned int __flags; + unsigned int __base_count; + __base_class_type_info __base_info[1]; + + enum __flags_masks { + __non_diamond_repeat_mask = 0x1, + __diamond_shaped_mask = 0x2 + }; +}; + +template<typename T> const T& to(const std::type_info &info) { +return static_cast<const T&>(info); +} +struct Incomplete; + +struct A { int a; }; +struct Empty { }; + +struct SI1 : A { }; +struct SI2 : Empty { }; +struct SI3 : Empty { virtual void f() { } }; + +struct VMI1 : private A { }; +struct VMI2 : virtual A { }; +struct VMI3 : A { virtual void f() { } }; +struct VMI4 : A, Empty { }; + +struct VMIBase1 { int a; }; +struct VMIBase2 : VMIBase1 { int a; }; +struct VMI5 : VMIBase1, VMIBase2 { int a; }; + +struct VMIBase3 : virtual VMIBase1 { int a; }; +struct VMI6 : virtual VMIBase1, VMIBase3 { int a; }; + +struct VMI7 : VMIBase1, VMI5, private VMI6 { }; + +#define CHECK(x) if (!(x)) return __LINE__ +#define CHECK_VTABLE(type, vtable) CHECK(&vtable##_type_info_vtable + 2 == (((void **)&(typeid(type)))[0])) +#define CHECK_BASE_INFO_TYPE(type, index, base) CHECK(to<__vmi_class_type_info>(typeid(type)).__base_info[(index)].__base_type == &typeid(base)) +#define CHECK_BASE_INFO_OFFSET_FLAGS(type, index, offset, flags) CHECK(to<__vmi_class_type_info>(typeid(type)).__base_info[(index)].__offset_flags == (((offset) << 8) | (flags))) + +struct B { + static int const volatile (*a)[10]; + static int (*b)[10]; + + static int const volatile (B::*c)[10]; + static int (B::*d)[10]; +}; + +// CHECK: define i32 @_Z1fv() +int f() { + // Vectors should be treated as fundamental types. + typedef short __v4hi __attribute__ ((__vector_size__ (8))); + CHECK_VTABLE(__v4hi, fundamental); + + // A does not have any bases. + CHECK_VTABLE(A, class); + + // SI1 has a single public base. + CHECK_VTABLE(SI1, si_class); + CHECK(to<__si_class_type_info>(typeid(SI1)).__base_type == &typeid(A)); + + // SI2 has a single public empty base. + CHECK_VTABLE(SI2, si_class); + CHECK(to<__si_class_type_info>(typeid(SI2)).__base_type == &typeid(Empty)); + + // SI3 has a single public empty base. SI3 is dynamic whereas Empty is not, but since Empty is + // an empty class, it will still be at offset zero. + CHECK_VTABLE(SI3, si_class); + CHECK(to<__si_class_type_info>(typeid(SI3)).__base_type == &typeid(Empty)); + + // VMI1 has a single base, but it is private. + CHECK_VTABLE(VMI1, vmi_class); + + // VMI2 has a single base, but it is virtual. + CHECK_VTABLE(VMI2, vmi_class); + + // VMI3 has a single base, but VMI3 is dynamic whereas A is not, and A is not empty. + CHECK_VTABLE(VMI3, vmi_class); + + // VMI4 has two bases. + CHECK_VTABLE(VMI4, vmi_class); + + // VMI5 has non-diamond shaped inheritance. + CHECK_VTABLE(VMI5, vmi_class); + CHECK(to<__vmi_class_type_info>(typeid(VMI5)).__flags == __vmi_class_type_info::__non_diamond_repeat_mask); + CHECK(to<__vmi_class_type_info>(typeid(VMI5)).__base_count == 2); + CHECK_BASE_INFO_TYPE(VMI5, 0, VMIBase1); + CHECK_BASE_INFO_OFFSET_FLAGS(VMI5, 0, 0, __base_class_type_info::__public_mask); + CHECK_BASE_INFO_TYPE(VMI5, 1, VMIBase2); + CHECK_BASE_INFO_OFFSET_FLAGS(VMI5, 1, 4, __base_class_type_info::__public_mask); + + // VMI6 has diamond shaped inheritance. + CHECK_VTABLE(VMI6, vmi_class); + CHECK(to<__vmi_class_type_info>(typeid(VMI6)).__flags == __vmi_class_type_info::__diamond_shaped_mask); + CHECK(to<__vmi_class_type_info>(typeid(VMI6)).__base_count == 2); + CHECK_BASE_INFO_TYPE(VMI6, 0, VMIBase1); + CHECK_BASE_INFO_OFFSET_FLAGS(VMI6, 0, -24, __base_class_type_info::__public_mask | __base_class_type_info::__virtual_mask); + CHECK_BASE_INFO_TYPE(VMI6, 1, VMIBase3); + CHECK_BASE_INFO_OFFSET_FLAGS(VMI6, 1, 0, __base_class_type_info::__public_mask); + + // VMI7 has both non-diamond and diamond shaped inheritance. + CHECK_VTABLE(VMI7, vmi_class); + CHECK(to<__vmi_class_type_info>(typeid(VMI7)).__flags == (__vmi_class_type_info::__non_diamond_repeat_mask | __vmi_class_type_info::__diamond_shaped_mask)); + CHECK(to<__vmi_class_type_info>(typeid(VMI7)).__base_count == 3); + CHECK_BASE_INFO_TYPE(VMI7, 0, VMIBase1); + CHECK_BASE_INFO_OFFSET_FLAGS(VMI7, 0, 16, __base_class_type_info::__public_mask); + CHECK_BASE_INFO_TYPE(VMI7, 1, VMI5); + CHECK_BASE_INFO_OFFSET_FLAGS(VMI7, 1, 20, __base_class_type_info::__public_mask); + CHECK_BASE_INFO_TYPE(VMI7, 2, VMI6); + CHECK_BASE_INFO_OFFSET_FLAGS(VMI7, 2, 0, 0); + + // Pointers to incomplete classes. + CHECK_VTABLE(Incomplete *, pointer); + CHECK(to<__pbase_type_info>(typeid(Incomplete *)).__flags == __pbase_type_info::__incomplete_mask); + CHECK(to<__pbase_type_info>(typeid(Incomplete **)).__flags == __pbase_type_info::__incomplete_mask); + CHECK(to<__pbase_type_info>(typeid(Incomplete ***)).__flags == __pbase_type_info::__incomplete_mask); + + // Member pointers. + CHECK_VTABLE(int Incomplete::*, pointer_to_member); + CHECK(to<__pbase_type_info>(typeid(int Incomplete::*)).__flags == __pbase_type_info::__incomplete_class_mask); + CHECK(to<__pbase_type_info>(typeid(Incomplete Incomplete::*)).__flags == (__pbase_type_info::__incomplete_class_mask | __pbase_type_info::__incomplete_mask)); + CHECK(to<__pbase_type_info>(typeid(Incomplete A::*)).__flags == (__pbase_type_info::__incomplete_mask)); + + // Check that when stripping qualifiers off the pointee type, we correctly handle arrays. + CHECK(to<__pbase_type_info>(typeid(B::a)).__flags == (__pbase_type_info::__const_mask | __pbase_type_info::__volatile_mask)); + CHECK(to<__pbase_type_info>(typeid(B::a)).__pointee == to<__pbase_type_info>(typeid(B::b)).__pointee); + CHECK(to<__pbase_type_info>(typeid(B::c)).__flags == (__pbase_type_info::__const_mask | __pbase_type_info::__volatile_mask)); + CHECK(to<__pbase_type_info>(typeid(B::c)).__pointee == to<__pbase_type_info>(typeid(B::d)).__pointee); + + // Success! + // CHECK: ret i32 0 + return 0; +} + +#ifdef HARNESS +extern "C" void printf(const char *, ...); + +int main() { + int result = f(); + + if (result == 0) + printf("success!\n"); + else + printf("test on line %d failed!\n", result); + + return result; +} +#endif + + diff --git a/clang/test/CodeGenCXX/rtti-linkage.cpp b/clang/test/CodeGenCXX/rtti-linkage.cpp new file mode 100644 index 0000000..42fe435 --- /dev/null +++ b/clang/test/CodeGenCXX/rtti-linkage.cpp @@ -0,0 +1,140 @@ +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fhidden-weak-vtables -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fvisibility hidden -fhidden-weak-vtables -emit-llvm -o - | FileCheck -check-prefix=CHECK-WITH-HIDDEN %s + +#include <typeinfo> + +// CHECK-WITH-HIDDEN: _ZTSFN12_GLOBAL__N_11DEvE = internal constant +// CHECK-WITH-HIDDEN: @_ZTSPK2T4 = linkonce_odr hidden constant +// CHECK-WITH-HIDDEN: @_ZTS2T4 = linkonce_odr hidden constant +// CHECK-WITH-HIDDEN: @_ZTI2T4 = linkonce_odr hidden unnamed_addr constant +// CHECK-WITH-HIDDEN: @_ZTIPK2T4 = linkonce_odr hidden unnamed_addr constant + +// CHECK: _ZTSP1C = internal constant +// CHECK: _ZTS1C = internal constant +// CHECK: _ZTI1C = internal unnamed_addr constant +// CHECK: _ZTIP1C = internal unnamed_addr constant +// CHECK: _ZTSPP1C = internal constant +// CHECK: _ZTIPP1C = internal unnamed_addr constant +// CHECK: _ZTSM1Ci = internal constant +// CHECK: _ZTIM1Ci = internal unnamed_addr constant +// CHECK: _ZTSPM1Ci = internal constant +// CHECK: _ZTIPM1Ci = internal unnamed_addr constant +// CHECK: _ZTSM1CS_ = internal constant +// CHECK: _ZTIM1CS_ = internal unnamed_addr constant +// CHECK: _ZTSM1CPS_ = internal constant +// CHECK: _ZTIM1CPS_ = internal unnamed_addr constant +// CHECK: _ZTSM1A1C = internal constant +// CHECK: _ZTS1A = linkonce_odr constant +// CHECK: _ZTI1A = linkonce_odr hidden unnamed_addr constant +// CHECK: _ZTIM1A1C = internal unnamed_addr constant +// CHECK: _ZTSM1AP1C = internal constant +// CHECK: _ZTIM1AP1C = internal unnamed_addr constant +// CHECK: _ZTSN12_GLOBAL__N_11DE = internal constant +// CHECK: _ZTIN12_GLOBAL__N_11DE = internal unnamed_addr constant +// CHECK: _ZTSPN12_GLOBAL__N_11DE = internal constant +// CHECK: _ZTIPN12_GLOBAL__N_11DE = internal unnamed_addr constant +// CHECK: _ZTSFN12_GLOBAL__N_11DEvE = internal constant +// CHECK: _ZTIFN12_GLOBAL__N_11DEvE = internal unnamed_addr constant +// CHECK: _ZTSFvN12_GLOBAL__N_11DEE = internal constant +// CHECK: _ZTIFvN12_GLOBAL__N_11DEE = internal unnamed_addr constant +// CHECK: _ZTSPFvvE = linkonce_odr constant +// CHECK: _ZTSFvvE = linkonce_odr constant +// CHECK: _ZTIFvvE = linkonce_odr hidden unnamed_addr constant +// CHECK: _ZTIPFvvE = linkonce_odr hidden unnamed_addr constant +// CHECK: _ZTSN12_GLOBAL__N_11EE = internal constant +// CHECK: _ZTIN12_GLOBAL__N_11EE = internal unnamed_addr constant +// CHECK: _ZTSA10_i = linkonce_odr constant +// CHECK: _ZTIA10_i = linkonce_odr hidden unnamed_addr constant +// CHECK: _ZTI1TILj0EE = linkonce_odr unnamed_addr constant +// CHECK: _ZTI1TILj1EE = weak_odr unnamed_addr constant +// CHECK: _ZTI1TILj2EE = external constant +// CHECK: _ZTS1B = constant +// CHECK: _ZTI1B = unnamed_addr constant +// CHECK: _ZTS1F = linkonce_odr constant + +// CHECK: _ZTIN12_GLOBAL__N_11DE to + +// A has no key function, so its RTTI data should be linkonce_odr. +struct A { }; + +// B has a key function defined in the translation unit, so the RTTI data should +// be emitted in this translation unit and have external linkage. +struct B : A { + virtual void f(); +}; +void B::f() { } + +// C is an incomplete class type, so any direct or indirect pointer types should have +// internal linkage, as should the type info for C itself. +struct C; + +void t1() { + (void)typeid(C*); + (void)typeid(C**); + (void)typeid(int C::*); + (void)typeid(int C::**); + (void)typeid(C C::*); + (void)typeid(C *C::*); + (void)typeid(C A::*); + (void)typeid(C* A::*); +} + +namespace { + // D is inside an anonymous namespace, so all type information related to D should have + // internal linkage. + struct D { }; + + // E is also inside an anonymous namespace. + enum E { }; + +}; + +// F has a key function defined in the translation unit, but it is inline so the RTTI +// data should be emitted with linkonce_odr linkage. +struct F { + virtual void f(); +}; + +inline void F::f() { } +const D getD(); + +const std::type_info &t2() { + (void)typeid(const D); + (void)typeid(D *); + (void)typeid(D (*)()); + (void)typeid(void (*)(D)); + (void)typeid(void (*)(D&)); + // The exception specification is not part of the RTTI descriptor, so it should not have + // internal linkage. + (void)typeid(void (*)() throw (D)); + + (void)typeid(E); + + return typeid(getD()); +} + +namespace Arrays { + struct A { + static const int a[10]; + }; + const std::type_info &f() { + return typeid(A::a); + } +} + +template <unsigned N> class T { + virtual void anchor() {} +}; +template class T<1>; +template <> class T<2> { virtual void anchor(); }; +void t3() { + (void) typeid(T<0>); + (void) typeid(T<1>); + (void) typeid(T<2>); +} + +// rdar://problem/8778973 +struct T4 {}; +void t4(const T4 *ptr) { + const void *value = &typeid(ptr); +} diff --git a/clang/test/CodeGenCXX/rtti-visibility.cpp b/clang/test/CodeGenCXX/rtti-visibility.cpp new file mode 100644 index 0000000..40cee06 --- /dev/null +++ b/clang/test/CodeGenCXX/rtti-visibility.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -o %t +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -fhidden-weak-vtables -emit-llvm -o %t.hidden +// RUN: FileCheck --check-prefix=CHECK-TEST1 %s < %t +// RUN: FileCheck --check-prefix=CHECK-TEST2 %s < %t +// RUN: FileCheck --check-prefix=CHECK-TEST2-HIDDEN %s < %t.hidden + +#include <typeinfo> + +namespace Test1 { + // A is explicitly marked hidden, so all RTTI data should also be marked hidden. + // CHECK-TEST1: @_ZTSN5Test11AE = linkonce_odr hidden constant + // CHECK-TEST1: @_ZTIN5Test11AE = linkonce_odr hidden unnamed_addr constant + // CHECK-TEST1: @_ZTSPN5Test11AE = linkonce_odr hidden constant + // CHECK-TEST1: @_ZTIPN5Test11AE = linkonce_odr hidden unnamed_addr constant + struct __attribute__((visibility("hidden"))) A { }; + + void f() { + (void)typeid(A); + (void)typeid(A *); + } +} + +namespace Test2 { + // A is weak, so its linkage should be linkoce_odr, but not marked hidden. + // CHECK-TEST2: @_ZTSN5Test21AE = linkonce_odr constant + // CHECK-TEST2: @_ZTIN5Test21AE = linkonce_odr unnamed_addr constant + struct A { }; + + // With -fhidden-weak-vtables, the typeinfo for A is marked hidden, but not its name. + // CHECK-TEST2-HIDDEN: _ZTSN5Test21AE = linkonce_odr constant + // CHECK-TEST2-HIDDEN: @_ZTIN5Test21AE = linkonce_odr hidden unnamed_addr constant + void f() { + (void)typeid(A); + } +} diff --git a/clang/test/CodeGenCXX/rvalue-references.cpp b/clang/test/CodeGenCXX/rvalue-references.cpp new file mode 100644 index 0000000..1c25543 --- /dev/null +++ b/clang/test/CodeGenCXX/rvalue-references.cpp @@ -0,0 +1,111 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + + +struct Spacer { int x; }; +struct A { double array[2]; }; +struct B : Spacer, A { }; + +B &getB(); + +// CHECK: define %struct.A* @_Z4getAv() +// CHECK: call %struct.B* @_Z4getBv() +// CHECK-NEXT: bitcast %struct.B* +// CHECK-NEXT: getelementptr i8* +// CHECK-NEXT: bitcast i8* {{.*}} to %struct.A* +// CHECK-NEXT: ret %struct.A* +A &&getA() { return static_cast<A&&>(getB()); } + +int &getIntLValue(); +int &&getIntXValue(); +int getIntPRValue(); + +// CHECK: define i32* @_Z2f0v() +// CHECK: call i32* @_Z12getIntLValuev() +// CHECK-NEXT: ret i32* +int &&f0() { return static_cast<int&&>(getIntLValue()); } + +// CHECK: define i32* @_Z2f1v() +// CHECK: call i32* @_Z12getIntXValuev() +// CHECK-NEXT: ret i32* +int &&f1() { return static_cast<int&&>(getIntXValue()); } + +// CHECK: define i32* @_Z2f2v +// CHECK: call i32 @_Z13getIntPRValuev() +// CHECK-NEXT: store i32 {{.*}}, i32* +// CHECK-NEXT: ret i32* +int &&f2() { return static_cast<int&&>(getIntPRValue()); } + +bool ok; + +class C +{ + int* state_; + + C(const C&) = delete; + C& operator=(const C&) = delete; +public: + C(int state) : state_(new int(state)) { } + + C(C&& a) { + state_ = a.state_; + a.state_ = 0; + } + + ~C() { + delete state_; + state_ = 0; + } +}; + +C test(); + +// CHECK: define void @_Z15elide_copy_initv +void elide_copy_init() { + ok = false; + // CHECK: call void @_Z4testv + C a = test(); + // CHECK-NEXT: call void @_ZN1CD1Ev + // CHECK-NEXT: ret void +} + +// CHECK: define void @_Z16test_move_returnv +C test_move_return() { + // CHECK: call void @_ZN1CC1Ei + C a1(3); + // CHECK: call void @_ZN1CC1Ei + C a2(4); + if (ok) + // CHECK: call void @_ZN1CC1EOS_ + return a1; + // CHECK: call void @_ZN1CC1EOS_ + return a2; + // CHECK: call void @_ZN1CD1Ev + // CHECK: call void @_ZN1CD1Ev + //CHECK: ret void +} + +// PR10800: don't crash +namespace test1 { + int &&move(int&); + + struct A { A(int); }; + struct B { + A a; + B(int i); + }; + + // CHECK: define void @_ZN5test11BC2Ei( + // CHECK: [[T0:%.*]] = call i32* @_ZN5test14moveERi( + // CHECK-NEXT: [[T1:%.*]] = load i32* [[T0]] + // CHECK-NEXT: call void @_ZN5test11AC1Ei({{.*}}, i32 [[T1]]) + // CHECK-NEXT: ret void + B::B(int i) : a(move(i)) {} +} + +// PR11009 +struct MoveConvertible { + operator int&& () const; +}; +void moveConstruct() { + (void)(int)MoveConvertible(); +} diff --git a/clang/test/CodeGenCXX/scoped-enums.cpp b/clang/test/CodeGenCXX/scoped-enums.cpp new file mode 100644 index 0000000..fca0509 --- /dev/null +++ b/clang/test/CodeGenCXX/scoped-enums.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -std=c++11 -emit-llvm -o - %s + +// PR9923 +enum class Color { red, blue, green }; + +void f(Color); +void g() { + f(Color::red); +} diff --git a/clang/test/CodeGenCXX/sel-address.mm b/clang/test/CodeGenCXX/sel-address.mm new file mode 100644 index 0000000..c3db9a7 --- /dev/null +++ b/clang/test/CodeGenCXX/sel-address.mm @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 %s -verify -emit-llvm -o %t +// pr7390 + +void f(const SEL& v2) {} +void g() { + f(@selector(dealloc)); + + SEL s = @selector(dealloc); + SEL* ps = &s; + + @selector(dealloc) = s; // expected-error {{expression is not assignable}} + + SEL* ps2 = &@selector(dealloc); +} diff --git a/clang/test/CodeGenCXX/sizeof-unwind-exception.cpp b/clang/test/CodeGenCXX/sizeof-unwind-exception.cpp new file mode 100644 index 0000000..5db4df7 --- /dev/null +++ b/clang/test/CodeGenCXX/sizeof-unwind-exception.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions %s -O2 -o - | FileCheck %s --check-prefix=X86-64 +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions %s -O2 -o - | FileCheck %s --check-prefix=X86-32 +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions %s -O2 -o - | FileCheck %s --check-prefix=ARM-DARWIN +// RUN: %clang_cc1 -triple arm-unknown-gnueabi -emit-llvm -fcxx-exceptions -fexceptions %s -O2 -o - | FileCheck %s --check-prefix=ARM-EABI +// RUN: %clang_cc1 -triple mipsel-unknown-unknown -emit-llvm -fcxx-exceptions -fexceptions %s -O2 -o - | FileCheck %s --check-prefix=MIPS + +void foo(); +void test() { + try { + foo(); + } catch (int *&i) { + *i = 5; + } +} + +// PR10789: different platforms have different sizes for struct UnwindException. + +// X86-64: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind +// X86-64-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i64 32 +// X86-32: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind +// X86-32-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i64 32 +// ARM-DARWIN: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind +// ARM-DARWIN-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i64 32 +// ARM-EABI: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind +// ARM-EABI-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i32 88 +// MIPS: [[T0:%.*]] = tail call i8* @__cxa_begin_catch(i8* [[EXN:%.*]]) nounwind +// MIPS-NEXT: [[T1:%.*]] = getelementptr i8* [[EXN]], i32 24 + diff --git a/clang/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp b/clang/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp new file mode 100644 index 0000000..84697be --- /dev/null +++ b/clang/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp @@ -0,0 +1,200 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// See Test9 for test description. +// CHECK: @_ZTTN5Test91BE = linkonce_odr unnamed_addr constant +namespace Test1 { + +// Check that we don't initialize the vtable pointer in A::~A(), since the destructor body is trivial. +struct A { + virtual void f(); + ~A(); +}; + +// CHECK: define void @_ZN5Test11AD2Ev +// CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test11AE, i64 0, i64 2), i8*** +A::~A() +{ +} + +} + +namespace Test2 { + +// Check that we do initialize the vtable pointer in A::~A() since the destructor body isn't trivial. +struct A { + virtual void f(); + ~A(); +}; + +// CHECK: define void @_ZN5Test21AD2Ev +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test21AE, i64 0, i64 2), i8*** +A::~A() { + f(); +} + +} + +namespace Test3 { + +// Check that we don't initialize the vtable pointer in A::~A(), since the destructor body is trivial +// and Field's destructor body is also trivial. +struct Field { + ~Field() { } +}; + +struct A { + virtual void f(); + ~A(); + + Field field; +}; + +// CHECK: define void @_ZN5Test31AD2Ev +// CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test31AE, i64 0, i64 2), i8*** +A::~A() { + +} + +} + +namespace Test4 { + +// Check that we do initialize the vtable pointer in A::~A(), since Field's destructor body +// isn't trivial. + +void f(); + +struct Field { + ~Field() { f(); } +}; + +struct A { + virtual void f(); + ~A(); + + Field field; +}; + +// CHECK: define void @_ZN5Test41AD2Ev +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test41AE, i64 0, i64 2), i8*** +A::~A() +{ +} + +} + +namespace Test5 { + +// Check that we do initialize the vtable pointer in A::~A(), since Field's destructor isn't +// available in this translation unit. + +struct Field { + ~Field(); +}; + +struct A { + virtual void f(); + ~A(); + + Field field; +}; + +// CHECK: define void @_ZN5Test51AD2Ev +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test51AE, i64 0, i64 2), i8*** +A::~A() +{ +} + +} + +namespace Test6 { + +// Check that we do initialize the vtable pointer in A::~A(), since Field has a member +// variable with a non-trivial destructor body. + +struct NonTrivialDestructorBody { + ~NonTrivialDestructorBody(); +}; + +struct Field { + NonTrivialDestructorBody nonTrivialDestructorBody; +}; + +struct A { + virtual void f(); + ~A(); + + Field field; +}; + +// CHECK: define void @_ZN5Test61AD2Ev +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test61AE, i64 0, i64 2), i8*** +A::~A() +{ +} + +} + +namespace Test7 { + +// Check that we do initialize the vtable pointer in A::~A(), since Field has a base +// class with a non-trivial destructor body. + +struct NonTrivialDestructorBody { + ~NonTrivialDestructorBody(); +}; + +struct Field : NonTrivialDestructorBody { }; + +struct A { + virtual void f(); + ~A(); + + Field field; +}; + +// CHECK: define void @_ZN5Test71AD2Ev +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test71AE, i64 0, i64 2), i8*** +A::~A() +{ +} + +} + +namespace Test8 { + +// Check that we do initialize the vtable pointer in A::~A(), since Field has a virtual base +// class with a non-trivial destructor body. + +struct NonTrivialDestructorBody { + ~NonTrivialDestructorBody(); +}; + +struct Field : virtual NonTrivialDestructorBody { }; + +struct A { + virtual void f(); + ~A(); + + Field field; +}; + +// CHECK: define void @_ZN5Test81AD2Ev +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test81AE, i64 0, i64 2), i8*** +A::~A() +{ +} + +} + +namespace Test9 { + +// Check that we emit a VTT for B, even though we don't initialize the vtable pointer in the destructor. +struct A { virtual ~A () { } }; +struct B : virtual A {}; +struct C : virtual B { + virtual ~C(); +}; +C::~C() {} + +} diff --git a/clang/test/CodeGenCXX/specialized-static-data-mem-init.cpp b/clang/test/CodeGenCXX/specialized-static-data-mem-init.cpp new file mode 100644 index 0000000..c2a2ddb --- /dev/null +++ b/clang/test/CodeGenCXX/specialized-static-data-mem-init.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// rdar: // 8562966 +// pr8409 + +// CHECK: @_ZN1CIiE11needs_guardE = weak_odr global +// CHECK: @_ZGVN1CIiE11needs_guardE = weak_odr global + +struct K +{ + K(); + K(const K &); + ~K(); + void PrintNumK(); +}; + +template<typename T> +struct C +{ + void Go() { needs_guard.PrintNumK(); } + static K needs_guard; +}; + +template<typename T> K C<T>::needs_guard; + +void F() +{ + C<int>().Go(); +} + diff --git a/clang/test/CodeGenCXX/static-assert.cpp b/clang/test/CodeGenCXX/static-assert.cpp new file mode 100644 index 0000000..53dc9a7 --- /dev/null +++ b/clang/test/CodeGenCXX/static-assert.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -std=c++11 -verify + +static_assert(true, ""); + +void f() { + static_assert(true, ""); +} diff --git a/clang/test/CodeGenCXX/static-data-member.cpp b/clang/test/CodeGenCXX/static-data-member.cpp new file mode 100644 index 0000000..4ad339d --- /dev/null +++ b/clang/test/CodeGenCXX/static-data-member.cpp @@ -0,0 +1,104 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +// 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, align 4 +// CHECK: @_ZGVN5test31AIiE1xE = weak_odr global i64 0 + +// CHECK: _ZN5test51U2k0E = global i32 0 +// CHECK: _ZN5test51U2k1E = global i32 0 +// CHECK: _ZN5test51U2k2E = constant i32 76 +// CHECK-NOT: test51U2k3E +// CHECK-NOT: test51U2k4E + +// PR5564. +namespace test1 { + struct A { + static const int a = 10; + }; + + const int A::a; + + struct S { + static int i; + }; + + void f() { + int 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: 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 +} + +// 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: define internal void @__cxx_global_var_init1() + // CHECK: [[GUARDBYTE:%.*]] = load 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: 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 +} diff --git a/clang/test/CodeGenCXX/static-init-1.cpp b/clang/test/CodeGenCXX/static-init-1.cpp new file mode 100644 index 0000000..a926c0a --- /dev/null +++ b/clang/test/CodeGenCXX/static-init-1.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple=x86_64-apple-darwin9 -emit-llvm %s -o %t +// RUN: grep "call i32 @_Z5func1i" %t | count 3 + +extern "C" int printf(...); + +static int count; + +int func2(int c) { return printf("loading the func2(%d)\n", c); }; +int func1(int c) { return printf("loading the func1(%d)\n", c); } + +static int loader_1 = func1(++count); + +int loader_2 = func2(++count); + +static int loader_3 = func1(++count); + + +int main() {} + +int loader_4 = func2(++count); +static int loader_5 = func1(++count); +int loader_6 = func2(++count); + diff --git a/clang/test/CodeGenCXX/static-init-2.cpp b/clang/test/CodeGenCXX/static-init-2.cpp new file mode 100644 index 0000000..768e6de --- /dev/null +++ b/clang/test/CodeGenCXX/static-init-2.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -emit-llvm-only -verify %s + +// Make sure we don't crash generating y; its value is constant, but the +// initializer has side effects, so EmitConstantExpr should fail. +int x(); +int y = x() & 0; diff --git a/clang/test/CodeGenCXX/static-init-3.cpp b/clang/test/CodeGenCXX/static-init-3.cpp new file mode 100644 index 0000000..dc28d5a --- /dev/null +++ b/clang/test/CodeGenCXX/static-init-3.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -emit-llvm -triple x86_64-apple-darwin10.0.0 -o - %s | FileCheck %s + +// PR7050 +template<class T> struct X0 : public T { }; + +template <class T> +struct X1 +{ + static T & instance; + // include this to provoke instantiation at pre-execution time + static void use(T const &) {} + static T & get() { + static X0<T> t; + use(instance); + return static_cast<T &>(t); + } +}; + +// CHECK: @_ZN2X1I2X2I1BEE8instanceE = weak_odr global %struct.X2* null, align 8 +// CHECJ: @_ZN2X1I2X2I1AEE8instanceE = weak_odr global %struct.X2* null, align 8 +template<class T> T & X1<T>::instance = X1<T>::get(); + +class A { }; +class B : public A { }; + +template<typename T> struct X2 {}; +X2< B > bg = X1< X2< B > >::get(); +X2< A > ag = X1< X2< A > >::get(); diff --git a/clang/test/CodeGenCXX/static-init.cpp b/clang/test/CodeGenCXX/static-init.cpp new file mode 100644 index 0000000..74278f7 --- /dev/null +++ b/clang/test/CodeGenCXX/static-init.cpp @@ -0,0 +1,154 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %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 +// CHECK: @_ZZN5test1L6getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 16 +// CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0 +// CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0 + +struct A { + A(); + ~A(); +}; + +void f() { + // CHECK: load atomic i8* bitcast (i64* @_ZGVZ1fvE1a to i8*) acquire, align 1 + // CHECK: call i32 @__cxa_guard_acquire + // CHECK: call void @_ZN1AC1Ev + // CHECK: call i32 @__cxa_atexit(void (i8*)* bitcast (void (%struct.A*)* @_ZN1AD1Ev to void (i8*)*), i8* getelementptr inbounds (%struct.A* @_ZZ1fvE1a, i32 0, i32 0), i8* @__dso_handle) + // CHECK: call void @__cxa_guard_release + static A a; +} + +void g() { + // CHECK: call noalias i8* @_Znwm(i64 1) + // CHECK: call void @_ZN1AC1Ev( + static A& a = *new A; +} + +int a(); +void h() { + static const int i = a(); +} + +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: define internal 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: define internal void @_ZZN18union_static_local4testEvEN1c4mainEv + // CHECK: call void @_ZN18union_static_local1fEPNS_1xE(%"union.union_static_local::x"* bitcast ({ [2 x i8*] }* @_ZZN18union_static_local4testEvE3foo to %"union.union_static_local::x"*)) + 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(); + } +} + +// rdar://problem/11091093 +// 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: define void @_ZN5test21BC1Ev + // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire, + // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x) + // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() + // CHECK: store i32 [[T0]], i32* @_ZZN5test21BC1EvE1x, + // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BC1EvE1x) + + // CHECK: define void @_ZN5test21BC2Ev + // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire, + // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x) + // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() + // CHECK: store i32 [[T0]], i32* @_ZZN5test21BC1EvE1x, + // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BC1EvE1x) + + // This is just for completeness, because we actually emit this + // using a delegate dtor call. + B::~B() { + static int y = foo(); + } + // CHECK: define void @_ZN5test21BD1Ev( + // CHECK: call void @_ZN5test21BD2Ev( + + // CHECK: define void @_ZN5test21BD2Ev( + // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BD1EvE1y to i8*) acquire, + // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BD1EvE1y) + // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() + // CHECK: store i32 [[T0]], i32* @_ZZN5test21BD1EvE1y, + // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BD1EvE1y) +} + +// 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: define void @_ZN5test31BC1Ev( + // CHECK: define void @_ZN5test31BC2Ev( +} diff --git a/clang/test/CodeGenCXX/static-local-in-local-class.cpp b/clang/test/CodeGenCXX/static-local-in-local-class.cpp new file mode 100644 index 0000000..ebf560a --- /dev/null +++ b/clang/test/CodeGenCXX/static-local-in-local-class.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -emit-llvm -o %t %s +// 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; +} + +// pr7101 +void foo() { + static int n = 0; + struct Helper { + static void Execute() { + n++; + } + }; + Helper::Execute(); +} + diff --git a/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp new file mode 100644 index 0000000..94fd9aa --- /dev/null +++ b/clang/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// CHECK: ; ModuleID +template<typename> struct A { static int a; }; + +// CHECK-NOT: @_ZN1AIcE1aE +template<> int A<char>::a; + +// CHECK: @_ZN1AIbE1aE = global i32 10 +template<> int A<bool>::a = 10; + + diff --git a/clang/test/CodeGenCXX/static-mutable.cpp b/clang/test/CodeGenCXX/static-mutable.cpp new file mode 100644 index 0000000..6d51f24 --- /dev/null +++ b/clang/test/CodeGenCXX/static-mutable.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 %s -triple=i686-linux-gnu -emit-llvm -o - | FileCheck %s + +struct S { + mutable int n; +}; +int f() { + // The purpose of this test is to ensure that this variable is a global + // not a constant. + // CHECK: @_ZZ1fvE1s = internal global {{.*}} { i32 12 } + static const S s = { 12 }; + return ++s.n; +} diff --git a/clang/test/CodeGenCXX/stmtexpr.cpp b/clang/test/CodeGenCXX/stmtexpr.cpp new file mode 100644 index 0000000..1f0e4ac --- /dev/null +++ b/clang/test/CodeGenCXX/stmtexpr.cpp @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -Wno-unused-value -emit-llvm -o - %s | FileCheck %s +// rdar: //8540501 +extern "C" int printf(...); +extern "C" void abort(); + +struct A +{ + int i; + A (int j) : i(j) {printf("this = %p A(%d)\n", this, j);} + A (const A &j) : i(j.i) {printf("this = %p const A&(%d)\n", this, i);} + A& operator= (const A &j) { i = j.i; abort(); return *this; } + ~A() { printf("this = %p ~A(%d)\n", this, i); } +}; + +struct B +{ + int i; + B (const A& a) { i = a.i; } + B() {printf("this = %p B()\n", this);} + B (const B &j) : i(j.i) {printf("this = %p const B&(%d)\n", this, i);} + ~B() { printf("this = %p ~B(%d)\n", this, i); } +}; + +A foo(int j) +{ + return ({ j ? A(1) : A(0); }); +} + + +void foo2() +{ + A b = ({ A a(1); A a1(2); A a2(3); a1; a2; a; }); + if (b.i != 1) + abort(); + A c = ({ A a(1); A a1(2); A a2(3); a1; a2; a; A a3(4); a2; a3; }); + if (c.i != 4) + abort(); +} + +void foo3() +{ + const A &b = ({ A a(1); a; }); + if (b.i != 1) + abort(); +} + +void foo4() +{ +// CHECK: call {{.*}} @_ZN1AC1Ei +// CHECK: call {{.*}} @_ZN1AC1ERKS_ +// CHECK: call {{.*}} @_ZN1AD1Ev +// CHECK: call {{.*}} @_ZN1BC1ERK1A +// CHECK: call {{.*}} @_ZN1AD1Ev + const B &b = ({ A a(1); a; }); + if (b.i != 1) + abort(); +} + +int main() +{ + foo2(); + foo3(); + foo4(); + return foo(1).i-1; +} + +// rdar: // 8600553 +int a[128]; +int* foo5() { +// CHECK-NOT: memcpy + // Check that array-to-pointer conversion occurs in a + // statement-expression. + return (({ a; })); +} + diff --git a/clang/test/CodeGenCXX/switch-case-folding-1.cpp b/clang/test/CodeGenCXX/switch-case-folding-1.cpp new file mode 100644 index 0000000..1daeecf --- /dev/null +++ b/clang/test/CodeGenCXX/switch-case-folding-1.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -emit-llvm-only +// CHECK that we don't crash. + +int test(int val){ + int x = 12; + // Make sure we don't crash when constant folding the case 4 + // statement due to the case 5 statement contained in the do loop + switch (val) { + case 4: do { + switch (6) { + case 6: { + case 5: x++; + }; + }; + } while (x < 100); + } + return x; +} + +int main(void) { + return test(4); +} diff --git a/clang/test/CodeGenCXX/switch-case-folding-2.cpp b/clang/test/CodeGenCXX/switch-case-folding-2.cpp new file mode 100644 index 0000000..7c0283f --- /dev/null +++ b/clang/test/CodeGenCXX/switch-case-folding-2.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s +// CHECK that we don't crash. + +extern int printf(const char*, ...); +int test(int val){ + switch (val) { + case 4: + do { + switch (6) { + case 6: do { case 5: printf("bad\n"); } while (0); + }; + } while (0); + } + return 0; +} + +int main(void) { + return test(5); +} + +// CHECK: call i32 (i8*, ...)* @_Z6printfPKcz diff --git a/clang/test/CodeGenCXX/switch-case-folding.cpp b/clang/test/CodeGenCXX/switch-case-folding.cpp new file mode 100644 index 0000000..d4444b1 --- /dev/null +++ b/clang/test/CodeGenCXX/switch-case-folding.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -emit-llvm-only +// CHECK that we don't crash. + +int main(void){ + int x = 12; + // Make sure we don't crash when constant folding the case 4 + // statement due to the case 5 statement contained in the do loop + switch (4) { + case 4: do { + switch (6) { + case 6: { + case 5: x++; + }; + }; + } while (x < 100); + } + return x; +} diff --git a/clang/test/CodeGenCXX/temp-order.cpp b/clang/test/CodeGenCXX/temp-order.cpp new file mode 100644 index 0000000..341cd0c --- /dev/null +++ b/clang/test/CodeGenCXX/temp-order.cpp @@ -0,0 +1,226 @@ +// Output file should have no calls to error() with folding. +// RUN: %clang_cc1 -triple i386-unknown-unknown -O3 -emit-llvm -o %t %s +// RUN: FileCheck %s < %t + +static unsigned pow(unsigned Base, unsigned Power) { + unsigned Val = 1; + while (Power--) + Val *= Base; + return Val; +} + +struct TempTracker { + unsigned Product, Index; + + TempTracker() : Product(1), Index(0) {} + +}; + +// FIXME: This can be used to check elision as well, if P = 0 hacks are removed. +struct A { + TempTracker &TT; + mutable unsigned P; + bool Truth; + + A(TempTracker &_TT, unsigned _P, bool _Truth = true) + : TT(_TT), P(_P), Truth(_Truth) {} + A(const A &RHS) : TT(RHS.TT), P(RHS.P), Truth(RHS.Truth) { RHS.P = 0; } + ~A() { + if (P) + TT.Product *= pow(P, ++TT.Index); + } + + A &operator=(const A &RHS) { + TT = RHS.TT; + P = RHS.P; + Truth = RHS.Truth; + RHS.P = 0; + return *this; + } + + operator bool () { return Truth; } +}; + +// 3, 7, 2 +static unsigned f0(bool val = false) { + TempTracker tt; + { + A a(tt, 2); + if ((A(tt, 3), val)) + A b(tt, 5); + A c(tt, 7); + } + return tt.Product; +} + +// 3, 5, 7, 2 +static unsigned f1(bool val = true) { + TempTracker tt; + { + A a(tt, 2); + if ((A(tt, 3), val)) + A b(tt, 5); + A c(tt, 7); + } + return tt.Product; +} + +// 5, 3, 7, 2 +static unsigned f2() { + TempTracker tt; + { + A a(tt, 2); + if (A b = A(tt, 3)) + A c(tt, 5); + A d(tt, 7); + } + return tt.Product; +} + +// 7, 3, 11, 2 +static unsigned f3() { + TempTracker tt; + { + A a(tt, 2); + if (A b = A(tt, 3, false)) + A c(tt, 5); + else + A c(tt, 7); + A d(tt, 11); + } + return tt.Product; +} + +// 3, 7, 2 +static unsigned f4() { + TempTracker tt; + { + A a(tt, 2); + while (A b = A(tt, 3, false)) + A c(tt, 5); + A c(tt, 7); + } + return tt.Product; +} + +// 5, 3, 7, 2 +static unsigned f5() { + TempTracker tt; + { + A a(tt, 2); + while (A b = A(tt, 3, true)) { + A c(tt, 5); + break; + } + A c(tt, 7); + } + return tt.Product; +} + +// 3, 7, 11, 5, 13, 2 +static unsigned f6() { + TempTracker tt; + { + A a(tt, 2); + for (A b = (A(tt, 3), A(tt, 5)), c = (A(tt, 7), A(tt, 11));;) + break; + A c(tt, 13); + } + return tt.Product; +} + +// 5, 2 +static unsigned f7() { + TempTracker tt; + { + (void)((A(tt, 2, false) && A(tt, 3, false)) || A(tt, 5, false)); + } + return tt.Product; +} + +// 5, 2 +static unsigned f8() { + TempTracker tt; + + { + (void)((A(tt, 2) || A(tt, 3)) && A(tt, 5)); + } + return tt.Product; +} + +extern "C" void error(); +extern "C" void print(const char *Name, unsigned N); + +#define ORDER2(a, b) (pow(a, 1) * pow(b, 2)) +#define ORDER3(a, b, c) (ORDER2(a, b) * pow(c, 3)) +#define ORDER4(a, b, c, d) (ORDER3(a, b, c) * pow(d, 4)) +#define ORDER5(a, b, c, d, e) (ORDER4(a, b, c, d) * pow(e, 5)) +#define ORDER6(a, b, c, d, e, f) (ORDER5(a, b, c, d, e) * pow(f, 6)) +void test() { +// CHECK: call void @print(i8* {{.*}}, i32 1176) + print("f0", f0()); + if (f0() != ORDER3(3, 7, 2)) + error(); + +// CHECK: call void @print(i8* {{.*}}, i32 411600) + print("f1", f1()); + if (f1() != ORDER4(3, 5, 7, 2)) + error(); + +// CHECK: call void @print(i8* {{.*}}, i32 246960) + print("f2", f2()); + if (f2() != ORDER4(5, 3, 7, 2)) + error(); + +// CHECK: call void @print(i8* {{.*}}, i32 1341648) + print("f3", f3()); + if (f3() != ORDER4(7, 3, 11, 2)) + error(); + +// CHECK: call void @print(i8* {{.*}}, i32 1176) + print("f4", f4()); + if (f4() != ORDER3(3, 7, 2)) + error(); + +// CHECK: call void @print(i8* {{.*}}, i32 246960) + print("f5", f5()); + if (f5() != ORDER4(5, 3, 7, 2)) + error(); + +// CHECK: call void @print(i8* {{.*}}, i32 1251552576) + print("f6", f6()); + if (f6() != ORDER6(3, 7, 11, 5, 13, 2)) + error(); + +// CHECK: call void @print(i8* {{.*}}, i32 20) + print("f7", f7()); + if (f7() != ORDER2(5, 2)) + error(); + +// CHECK: call void @print(i8* {{.*}}, i32 20) + print("f8", f8()); + if (f8() != ORDER2(5, 2)) + error(); +} + + + +#ifdef HARNESS + +#include <cstdlib> +#include <cstdio> + +extern "C" void error() { + abort(); +} + +extern "C" void print(const char *name, unsigned N) { + printf("%s: %d\n", name, N); +} + +int main() { + test(); + return 0; +} + +#endif diff --git a/clang/test/CodeGenCXX/template-anonymous-types.cpp b/clang/test/CodeGenCXX/template-anonymous-types.cpp new file mode 100644 index 0000000..72fe090 --- /dev/null +++ b/clang/test/CodeGenCXX/template-anonymous-types.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -emit-llvm -o - | FileCheck %s + +struct S { + enum { FOO = 42 }; + enum { BAR = 42 }; +}; + +template <typename T> struct X { + T value; + X(T t) : value(t) {} + int f() { return value; } +}; + +template <typename T> int f(T t) { + X<T> x(t); + return x.f(); +} + +void test() { + // Look for two instantiations, entirely internal to this TU, one for FOO's + // type and one for BAR's. + // CHECK: define internal i32 @"_Z1fIN1S3$_0EEiT_"(i32 %t) + (void)f(S::FOO); + // CHECK: define internal i32 @"_Z1fIN1S3$_1EEiT_"(i32 %t) + (void)f(S::BAR); + + // Now check for the class template instantiations. Annoyingly, they are in + // reverse order. + // + // BAR's instantiation of X: + // CHECK: define internal i32 @"_ZN1XIN1S3$_1EE1fEv"(%struct.X* %this) + // CHECK: define internal void @"_ZN1XIN1S3$_1EEC2ES1_"(%struct.X* %this, i32 %t) unnamed_addr + // + // FOO's instantiation of X: + // CHECK: define internal i32 @"_ZN1XIN1S3$_0EE1fEv"(%struct.X.0* %this) + // CHECK: define internal void @"_ZN1XIN1S3$_0EEC2ES1_"(%struct.X.0* %this, i32 %t) unnamed_addr +} diff --git a/clang/test/CodeGenCXX/template-anonymous-union-member-initializer.cpp b/clang/test/CodeGenCXX/template-anonymous-union-member-initializer.cpp new file mode 100644 index 0000000..41ae084 --- /dev/null +++ b/clang/test/CodeGenCXX/template-anonymous-union-member-initializer.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm -o %t %s +template <typename T> +class A +{ + union { void *d; }; + +public: + A() : d(0) { } +}; + +A<int> a0; diff --git a/clang/test/CodeGenCXX/template-dependent-bind-temporary.cpp b/clang/test/CodeGenCXX/template-dependent-bind-temporary.cpp new file mode 100644 index 0000000..cc1ce86 --- /dev/null +++ b/clang/test/CodeGenCXX/template-dependent-bind-temporary.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// rdar: //8620524 +// PR7851 +struct string { + string (const string& ); + string (); + ~string(); +}; + +string operator + (char ch, const string&); + +template <class T> +void IntToString(T a) +{ + string result; + T digit; + char((digit < 10 ? '0' : 'a') + digit) + result; +} + +int main() { +// CHECK: define linkonce_odr void @_Z11IntToStringIcEvT_( + IntToString('a'); +} + diff --git a/clang/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp b/clang/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp new file mode 100644 index 0000000..2c62b60 --- /dev/null +++ b/clang/test/CodeGenCXX/template-inner-struct-visibility-hidden.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -fvisibility hidden -emit-llvm -o - %s | FileCheck %s + +// Verify that symbols are hidden. +// CHECK: @_ZN1CIiE5Inner6Inner26StaticE = weak_odr hidden global +// CHECK: define weak_odr hidden void @_ZN1CIiE5Inner1fEv +// CHECK: define weak_odr hidden void @_ZN1CIiE5Inner6Inner21gEv + +template<typename T> +struct C { + struct Inner { + void f(); + struct Inner2 { + void g(); + static int Static; + }; + }; +}; + +template<typename T> void C<T>::Inner::f() { } +template<typename T> void C<T>::Inner::Inner2::g() { } +template<typename T> int C<T>::Inner::Inner2::Static; + +extern template struct C<int>; +template struct C<int>; diff --git a/clang/test/CodeGenCXX/template-instantiation.cpp b/clang/test/CodeGenCXX/template-instantiation.cpp new file mode 100644 index 0000000..09b3a4f --- /dev/null +++ b/clang/test/CodeGenCXX/template-instantiation.cpp @@ -0,0 +1,190 @@ +// RUN: %clang_cc1 %s -O1 -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// CHECK: @_ZN7PR100011xE = global +// CHECK-NOT: @_ZN7PR100014kBarE = external global i32 +// +// CHECK-NOT: @_ZTVN5test118stdio_sync_filebufIwEE = constant +// CHECK-NOT: _ZTVN5test315basic_fstreamXXIcEE +// CHECK: @_ZTVN5test018stdio_sync_filebufIwEE = unnamed_addr constant + +// CHECK: @_ZN7PR100011SIiE3arrE = weak_odr global [3 x i32] +// CHECK-NOT: @_ZN7PR100011SIiE3arr2E = weak_odr global [3 x i32]A + +// CHECK-NOT: _ZTVN5test31SIiEE +// CHECK-NOT: _ZTSN5test31SIiEE + +// CHECK: define linkonce_odr void @_ZN5test21CIiEC1Ev(%"class.test2::C"* nocapture %this) unnamed_addr +// CHECK: define linkonce_odr void @_ZN5test21CIiE6foobarIdEEvT_( +// CHECK: define available_externally void @_ZN5test21CIiE6zedbarEd( + +// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi1EEE() +// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi2EEE() +// CHECK: define linkonce_odr void @_ZN7PR106662g1ENS_1SILi3EEE() +// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi1EEE() +// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi2EEE() +// CHECK: define linkonce_odr void @_ZN7PR106662g2ENS_1SILi3EEE() +// CHECK: declare void @_ZN7PR106662h1ENS_1SILi1EEE() +// CHECK: declare void @_ZN7PR106662h1ENS_1SILi2EEE() +// CHECK: declare void @_ZN7PR106662h1ENS_1SILi3EEE() +// CHECK: declare void @_ZN7PR106662h2ENS_1SILi1EEE() +// CHECK: declare void @_ZN7PR106662h2ENS_1SILi2EEE() +// CHECK: declare void @_ZN7PR106662h2ENS_1SILi3EEE() + +namespace test0 { + struct basic_streambuf { + virtual ~basic_streambuf(); + }; + template<typename _CharT > + struct stdio_sync_filebuf : public basic_streambuf { + virtual void xsgetn(); + }; + + // This specialization should cause the vtable to be emitted, even with + // the following extern template declaration. + template<> void stdio_sync_filebuf<wchar_t>::xsgetn() { + } + extern template class stdio_sync_filebuf<wchar_t>; +} + +namespace test1 { + struct basic_streambuf { + virtual ~basic_streambuf(); + }; + template<typename _CharT > + struct stdio_sync_filebuf : public basic_streambuf { + virtual void xsgetn(); + }; + + // Just a declaration should not force the vtable to be emitted. + template<> void stdio_sync_filebuf<wchar_t>::xsgetn(); +} + +namespace test2 { + template<typename T1> + class C { + public: + virtual ~C(); + void zedbar(double) { + } + template<typename T2> + void foobar(T2 foo) { + } + }; + extern template class C<int>; + void g() { + // The extern template declaration should not prevent us from producing + // the implicit constructor (test at the top). + C<int> a; + + // or foobar(test at the top). + a.foobar(0.0); + + // But it should prevent zebbar + // (test at the top). + a.zedbar(0.0); + } +} + +namespace test3 { + template<typename T> + class basic_fstreamXX { + virtual void foo(){} + virtual void is_open() const { } + }; + + extern template class basic_fstreamXX<char>; + // This template instantiation should not cause us to produce a vtable. + // (test at the top). + template void basic_fstreamXX<char>::is_open() const; +} + +namespace test3 { + template <typename T> + struct S { + virtual void m(); + }; + + template<typename T> + void S<T>::m() { } + + // Should not cause us to produce vtable because template instantiations + // don't have key functions. + template void S<int>::m(); +} + +namespace test4 { + template <class T> struct A { static void foo(); }; + + class B { + template <class T> friend void A<T>::foo(); + B(); + }; + + template <class T> void A<T>::foo() { + B b; + } + + unsigned test() { + A<int>::foo(); + } +} + +namespace PR8505 { +// Hits an assertion due to bogus instantiation of class B. +template <int i> class A { + class B* g; +}; +class B { + void f () {} +}; +// Should not instantiate class B since it is introduced in namespace scope. +// CHECK-NOT: _ZN6PR85051AILi0EE1B1fEv +template class A<0>; +} + +// Ensure that when instantiating initializers for static data members to +// complete their type in an unevaluated context, we *do* emit initializers with +// side-effects, but *don't* emit initializers and variables which are otherwise +// unused in the program. +namespace PR10001 { + template <typename T> struct S { + static const int arr[]; + static const int arr2[]; + static const int x, y; + static int f(); + }; + + extern int foo(); + extern int kBar; + + template <typename T> const int S<T>::arr[] = { 1, 2, foo() }; // possible side effects + template <typename T> const int S<T>::arr2[] = { 1, 2, kBar }; // no side effects + template <typename T> const int S<T>::x = sizeof(arr) / sizeof(arr[0]); + template <typename T> const int S<T>::y = sizeof(arr2) / sizeof(arr2[0]); + template <typename T> int S<T>::f() { return x + y; } + + int x = S<int>::f(); +} + +// Ensure that definitions are emitted for all friend functions defined within +// class templates. Order of declaration is extremely important here. Different +// instantiations of the class happen at different points during the deferred +// method body parsing and afterward. Those different points of instantiation +// change the exact form the class template appears to have. +namespace PR10666 { + template <int N> struct S { + void f1() { S<1> s; } + friend void g1(S s) {} + friend void h1(S s); + void f2() { S<2> s; } + friend void g2(S s) {} + friend void h2(S s); + void f3() { S<3> s; } + }; + void test(S<1> s1, S<2> s2, S<3> s3) { + g1(s1); g1(s2); g1(s3); + g2(s1); g2(s2); g2(s3); + h1(s1); h1(s2); h1(s3); + h2(s1); h2(s2); h2(s3); + } +} diff --git a/clang/test/CodeGenCXX/template-linkage.cpp b/clang/test/CodeGenCXX/template-linkage.cpp new file mode 100644 index 0000000..20508c1 --- /dev/null +++ b/clang/test/CodeGenCXX/template-linkage.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +template<typename T> struct A { + virtual void f(T) { } + inline void g() { } +}; + +// Explicit instantiations have external linkage. + +// CHECK: define weak_odr void @_ZN1AIiE1gEv( +template void A<int>::g(); + +// CHECK: define weak_odr void @_ZN1AIfE1fEf( +// CHECK: define weak_odr void @_ZN1AIfE1gEv( +// FIXME: This should also emit the vtable. +template struct A<float>; + +// CHECK: define weak_odr void @_Z1fIiEvT_ +template <typename T> void f(T) { } +template void f<int>(int); + +// CHECK: define weak_odr void @_Z1gIiEvT_ +template <typename T> inline void g(T) { } +template void g<int>(int); + +template<typename T> +struct X0 { + virtual ~X0() { } +}; + +template<typename T> +struct X1 : X0<T> { + virtual void blarg(); +}; + +template<typename T> void X1<T>::blarg() { } + +extern template struct X0<char>; +extern template struct X1<char>; + +// CHECK: define linkonce_odr void @_ZN2X1IcED1Ev(%struct.X1* %this) unnamed_addr +void test_X1() { + X1<char> i1c; +} + diff --git a/clang/test/CodeGenCXX/template-static-var-defer.cpp b/clang/test/CodeGenCXX/template-static-var-defer.cpp new file mode 100644 index 0000000..fe18c21 --- /dev/null +++ b/clang/test/CodeGenCXX/template-static-var-defer.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | not grep define +// PR7415 +class X { + template <class Dummy> struct COMTypeInfo { + static const int kIID; + }; + static const int& GetIID() {return COMTypeInfo<int>::kIID;} +}; +template <class Dummy> const int X::COMTypeInfo<Dummy>::kIID = 10; + + + diff --git a/clang/test/CodeGenCXX/temporaries.cpp b/clang/test/CodeGenCXX/temporaries.cpp new file mode 100644 index 0000000..e90c947 --- /dev/null +++ b/clang/test/CodeGenCXX/temporaries.cpp @@ -0,0 +1,539 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin9 | FileCheck %s +struct A { + A(); + ~A(); + void f(); +}; + +void f1() { + // CHECK: call void @_ZN1AC1Ev + // CHECK: call void @_ZN1AD1Ev + (void)A(); + + // CHECK: call void @_ZN1AC1Ev + // CHECK: call void @_ZN1AD1Ev + A().f(); +} + +// Function calls +struct B { + B(); + ~B(); +}; + +B g(); + +void f2() { + // CHECK-NOT: call void @_ZN1BC1Ev + // CHECK: call void @_ZN1BD1Ev + (void)g(); +} + +// Member function calls +struct C { + C(); + ~C(); + + C f(); +}; + +void f3() { + // CHECK: call void @_ZN1CC1Ev + // CHECK: call void @_ZN1CD1Ev + // CHECK: call void @_ZN1CD1Ev + C().f(); +} + +// Function call operator +struct D { + D(); + ~D(); + + D operator()(); +}; + +void f4() { + // CHECK: call void @_ZN1DC1Ev + // CHECK: call void @_ZN1DD1Ev + // CHECK: call void @_ZN1DD1Ev + D()(); +} + +// Overloaded operators +struct E { + E(); + ~E(); + E operator+(const E&); + E operator!(); +}; + +void f5() { + // CHECK: call void @_ZN1EC1Ev + // CHECK: call void @_ZN1EC1Ev + // CHECK: call void @_ZN1ED1Ev + // CHECK: call void @_ZN1ED1Ev + // CHECK: call void @_ZN1ED1Ev + E() + E(); + + // CHECK: call void @_ZN1EC1Ev + // CHECK: call void @_ZN1ED1Ev + // CHECK: call void @_ZN1ED1Ev + !E(); +} + +struct F { + F(); + ~F(); + F& f(); +}; + +void f6() { + // CHECK: call void @_ZN1FC1Ev + // CHECK: call void @_ZN1FD1Ev + F().f(); +} + +struct G { + G(); + G(A); + ~G(); + operator A(); +}; + +void a(const A&); + +void f7() { + // CHECK: call void @_ZN1AC1Ev + // CHECK: call void @_Z1aRK1A + // CHECK: call void @_ZN1AD1Ev + a(A()); + + // CHECK: call void @_ZN1GC1Ev + // CHECK: call void @_ZN1Gcv1AEv + // CHECK: call void @_Z1aRK1A + // CHECK: call void @_ZN1AD1Ev + // CHECK: call void @_ZN1GD1Ev + a(G()); +} + +namespace PR5077 { + +struct A { + A(); + ~A(); + int f(); +}; + +void f(); +int g(const A&); + +struct B { + int a1; + int a2; + B(); + ~B(); +}; + +B::B() + // CHECK: call void @_ZN6PR50771AC1Ev + // CHECK: call i32 @_ZN6PR50771A1fEv + // CHECK: call void @_ZN6PR50771AD1Ev + : a1(A().f()) + // CHECK: call void @_ZN6PR50771AC1Ev + // CHECK: call i32 @_ZN6PR50771gERKNS_1AE + // CHECK: call void @_ZN6PR50771AD1Ev + , a2(g(A())) +{ + // CHECK: call void @_ZN6PR50771fEv + f(); +} + +struct C { + C(); + + const B& b; +}; + +C::C() + // CHECK: call void @_ZN6PR50771BC1Ev + : b(B()) { + // CHECK: call void @_ZN6PR50771fEv + f(); + + // CHECK: call void @_ZN6PR50771BD1Ev +} +} + +A f8() { + // CHECK: call void @_ZN1AC1Ev + // CHECK-NOT: call void @_ZN1AD1Ev + return A(); + // CHECK: ret void +} + +struct H { + H(); + ~H(); + H(const H&); +}; + +void f9(H h) { + // CHECK: call void @_ZN1HC1Ev + // CHECK: call void @_Z2f91H + // CHECK: call void @_ZN1HD1Ev + f9(H()); + + // CHECK: call void @_ZN1HC1ERKS_ + // CHECK: call void @_Z2f91H + // CHECK: call void @_ZN1HD1Ev + f9(h); +} + +void f10(const H&); + +void f11(H h) { + // CHECK: call void @_ZN1HC1Ev + // CHECK: call void @_Z3f10RK1H + // CHECK: call void @_ZN1HD1Ev + f10(H()); + + // CHECK: call void @_Z3f10RK1H + // CHECK-NOT: call void @_ZN1HD1Ev + // CHECK: ret void + f10(h); +} + +// PR5808 +struct I { + I(const char *); + ~I(); +}; + +// CHECK: _Z3f12v +I f12() { + // CHECK: call void @_ZN1IC1EPKc + // CHECK-NOT: call void @_ZN1ID1Ev + // CHECK: ret void + return "Hello"; +} + +// PR5867 +namespace PR5867 { + struct S { + S(); + S(const S &); + ~S(); + }; + + void f(S, int); + // CHECK: define void @_ZN6PR58671gEv + void g() { + // CHECK: call void @_ZN6PR58671SC1Ev + // CHECK-NEXT: call void @_ZN6PR58671fENS_1SEi + // CHECK-NEXT: call void @_ZN6PR58671SD1Ev + // CHECK-NEXT: ret void + (f)(S(), 0); + } + + // CHECK: define linkonce_odr void @_ZN6PR58672g2IiEEvT_ + template<typename T> + void g2(T) { + // CHECK: call void @_ZN6PR58671SC1Ev + // CHECK-NEXT: call void @_ZN6PR58671fENS_1SEi + // CHECK-NEXT: call void @_ZN6PR58671SD1Ev + // CHECK-NEXT: ret void + (f)(S(), 0); + } + + void h() { + g2(17); + } +} + +// PR6199 +namespace PR6199 { + struct A { ~A(); }; + + struct B { operator A(); }; + + // CHECK: define weak_odr void @_ZN6PR61992f2IiEENS_1AET_ + template<typename T> A f2(T) { + B b; + // CHECK: call void @_ZN6PR61991BcvNS_1AEEv + // CHECK-NEXT: ret void + return b; + } + + template A f2<int>(int); + +} + +namespace T12 { + +struct A { + A(); + ~A(); + int f(); +}; + +int& f(int); + +// CHECK: define void @_ZN3T121gEv +void g() { + // CHECK: call void @_ZN3T121AC1Ev + // CHECK-NEXT: call i32 @_ZN3T121A1fEv( + // CHECK-NEXT: call i32* @_ZN3T121fEi( + // CHECK-NEXT: call void @_ZN3T121AD1Ev( + int& i = f(A().f()); +} + +} + +namespace PR6648 { + struct B { + ~B(); + }; + B foo; + struct D; + D& zed(B); + void foobar() { + // CHECK: call %"struct.PR6648::D"* @_ZN6PR66483zedENS_1BE + zed(foo); + } +} + +namespace UserConvertToValue { + struct X { + X(int); + X(const X&); + ~X(); + }; + + void f(X); + + // CHECK: void @_ZN18UserConvertToValue1gEv() + void g() { + // CHECK: call void @_ZN18UserConvertToValue1XC1Ei + // CHECK: call void @_ZN18UserConvertToValue1fENS_1XE + // CHECK: call void @_ZN18UserConvertToValue1XD1Ev + // CHECK: ret void + f(1); + } +} + +namespace PR7556 { + struct A { ~A(); }; + struct B { int i; ~B(); }; + struct C { int C::*pm; ~C(); }; + // CHECK: define void @_ZN6PR75563fooEv() + void foo() { + // CHECK: call void @_ZN6PR75561AD1Ev + A(); + // CHECK: call void @llvm.memset.p0i8.i64 + // CHECK: call void @_ZN6PR75561BD1Ev + B(); + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 + // CHECK: call void @_ZN6PR75561CD1Ev + C(); + // CHECK-NEXT: ret void + } +} + +namespace Elision { + struct A { + A(); A(const A &); ~A(); + void *p; + void foo() const; + }; + + void foo(); + A fooA(); + void takeA(A a); + + // CHECK: define void @_ZN7Elision5test0Ev() + void test0() { + // CHECK: [[I:%.*]] = alloca [[A:%.*]], align 8 + // CHECK-NEXT: [[J:%.*]] = alloca [[A]], align 8 + // CHECK-NEXT: [[T0:%.*]] = alloca [[A]], align 8 + // CHECK-NEXT: [[K:%.*]] = alloca [[A]], align 8 + // CHECK-NEXT: [[T1:%.*]] = alloca [[A]], align 8 + + // CHECK-NEXT: call void @_ZN7Elision3fooEv() + // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[I]]) + A i = (foo(), A()); + + // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret [[T0]]) + // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[J]]) + // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T0]]) + A j = (fooA(), A()); + + // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[T1]]) + // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret [[K]]) + // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T1]]) + A k = (A(), fooA()); + + // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[K]]) + // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[J]]) + // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[I]]) + } + + + // CHECK: define void @_ZN7Elision5test1EbNS_1AE( + void test1(bool c, A x) { + // CHECK: [[I:%.*]] = alloca [[A]], align 8 + // CHECK-NEXT: [[J:%.*]] = alloca [[A]], align 8 + + // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[I]]) + // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[I]], [[A]]* [[X:%.*]]) + A i = (c ? A() : x); + + // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[J]], [[A]]* [[X]]) + // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[J]]) + A j = (c ? x : A()); + + // CHECK: call void @_ZN7Elision1AD1Ev([[A]]* [[J]]) + // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[I]]) + } + + // CHECK: define void @_ZN7Elision5test2Ev([[A]]* noalias sret + A test2() { + // CHECK: call void @_ZN7Elision3fooEv() + // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]]) + // CHECK-NEXT: ret void + return (foo(), A()); + } + + // CHECK: define void @_ZN7Elision5test3EiNS_1AE([[A]]* noalias sret + A test3(int v, A x) { + if (v < 5) + // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]]) + // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[RET]], [[A]]* [[X:%.*]]) + return (v < 0 ? A() : x); + else + // CHECK: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[RET]], [[A]]* [[X]]) + // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[RET]]) + return (v > 10 ? x : A()); + + // CHECK: ret void + } + + // CHECK: define void @_ZN7Elision5test4Ev() + void test4() { + // CHECK: [[X:%.*]] = alloca [[A]], align 8 + // CHECK-NEXT: [[XS:%.*]] = alloca [2 x [[A]]], align 16 + + // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[X]]) + A x; + + // CHECK-NEXT: [[XS0:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i64 0, i64 0 + // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[XS0]]) + // CHECK-NEXT: [[XS1:%.*]] = getelementptr inbounds [[A]]* [[XS0]], i64 1 + // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[XS1]], [[A]]* [[X]]) + A xs[] = { A(), x }; + + // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 0 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 2 + // CHECK-NEXT: br label + // CHECK: [[AFTER:%.*]] = phi [[A]]* + // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1 + // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[CUR]]) + // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]] + // CHECK-NEXT: br i1 [[T0]], + + // CHECK: call void @_ZN7Elision1AD1Ev([[A]]* [[X]]) + } + + // rdar://problem/8433352 + // CHECK: define void @_ZN7Elision5test5Ev([[A]]* noalias sret + struct B { A a; B(); }; + A test5() { + // CHECK: [[AT0:%.*]] = alloca [[A]], align 8 + // CHECK-NEXT: [[BT0:%.*]] = alloca [[B:%.*]], align 8 + // CHECK-NEXT: [[X:%.*]] = alloca [[A]], align 8 + // CHECK-NEXT: [[BT1:%.*]] = alloca [[B]], align 8 + // CHECK-NEXT: [[BT2:%.*]] = alloca [[B]], align 8 + + // CHECK: call void @_ZN7Elision1BC1Ev([[B]]* [[BT0]]) + // CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]]* [[BT0]], i32 0, i32 0 + // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[AT0]], [[A]]* [[AM]]) + // CHECK-NEXT: call void @_ZN7Elision5takeAENS_1AE([[A]]* [[AT0]]) + // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[AT0]]) + // CHECK-NEXT: call void @_ZN7Elision1BD1Ev([[B]]* [[BT0]]) + takeA(B().a); + + // CHECK-NEXT: call void @_ZN7Elision1BC1Ev([[B]]* [[BT1]]) + // CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]]* [[BT1]], i32 0, i32 0 + // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[X]], [[A]]* [[AM]]) + // CHECK-NEXT: call void @_ZN7Elision1BD1Ev([[B]]* [[BT1]]) + A x = B().a; + + // CHECK-NEXT: call void @_ZN7Elision1BC1Ev([[B]]* [[BT2]]) + // CHECK-NEXT: [[AM:%.*]] = getelementptr inbounds [[B]]* [[BT2]], i32 0, i32 0 + // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[RET:%.*]], [[A]]* [[AM]]) + // CHECK-NEXT: call void @_ZN7Elision1BD1Ev([[B]]* [[BT2]]) + return B().a; + + // CHECK: call void @_ZN7Elision1AD1Ev([[A]]* [[X]]) + } + + // Reduced from webkit. + // CHECK: define void @_ZN7Elision5test6EPKNS_1CE([[C:%.*]]* + struct C { operator A() const; }; + void test6(const C *x) { + // CHECK: [[T0:%.*]] = alloca [[A]], align 8 + // CHECK: [[X:%.*]] = load [[C]]** {{%.*}}, align 8 + // CHECK-NEXT: call void @_ZNK7Elision1CcvNS_1AEEv([[A]]* sret [[T0]], [[C]]* [[X]]) + // CHECK-NEXT: call void @_ZNK7Elision1A3fooEv([[A]]* [[T0]]) + // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T0]]) + // CHECK-NEXT: ret void + A(*x).foo(); + } +} + +namespace PR8623 { + struct A { A(int); ~A(); }; + + // CHECK: define void @_ZN6PR86233fooEb( + void foo(bool b) { + // CHECK: [[TMP:%.*]] = alloca [[A:%.*]], align 1 + // CHECK-NEXT: [[LCONS:%.*]] = alloca i1 + // CHECK-NEXT: [[RCONS:%.*]] = alloca i1 + // CHECK: store i1 false, i1* [[LCONS]] + // CHECK-NEXT: store i1 false, i1* [[RCONS]] + // CHECK-NEXT: br i1 + // CHECK: call void @_ZN6PR86231AC1Ei([[A]]* [[TMP]], i32 2) + // CHECK-NEXT: store i1 true, i1* [[LCONS]] + // CHECK-NEXT: br label + // CHECK: call void @_ZN6PR86231AC1Ei([[A]]* [[TMP]], i32 3) + // CHECK-NEXT: store i1 true, i1* [[RCONS]] + // CHECK-NEXT: br label + // CHECK: load i1* [[RCONS]] + // CHECK-NEXT: br i1 + // CHECK: call void @_ZN6PR86231AD1Ev([[A]]* [[TMP]]) + // CHECK-NEXT: br label + // CHECK: load i1* [[LCONS]] + // CHECK-NEXT: br i1 + // CHECK: call void @_ZN6PR86231AD1Ev([[A]]* [[TMP]]) + // CHECK-NEXT: br label + // CHECK: ret void + b ? A(2) : A(3); + } +} + +namespace PR11365 { + struct A { A(); ~A(); }; + + // CHECK: define void @_ZN7PR113653fooEv( + void foo() { + // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [3 x [[A:%.*]]]* {{.*}}, i32 0, i32 0 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 3 + // CHECK-NEXT: br label + + // CHECK: [[PHI:%.*]] = phi + // CHECK-NEXT: [[ELEM:%.*]] = getelementptr inbounds [[A]]* [[PHI]], i64 -1 + // CHECK-NEXT: call void @_ZN7PR113651AD1Ev([[A]]* [[ELEM]]) + // CHECK-NEXT: icmp eq [[A]]* [[ELEM]], [[BEGIN]] + // CHECK-NEXT: br i1 + (void) (A [3]) {}; + } +} diff --git a/clang/test/CodeGenCXX/thiscall-struct-return.cpp b/clang/test/CodeGenCXX/thiscall-struct-return.cpp new file mode 100644 index 0000000..ff53125 --- /dev/null +++ b/clang/test/CodeGenCXX/thiscall-struct-return.cpp @@ -0,0 +1,41 @@ +// For MSVC ABI compatibility, all structures returned by value using the +// thiscall calling convention must use the hidden parameter. +// +// RUN: %clang_cc1 -triple i386-PC-Win32 %s -fms-compatibility -O0 -emit-llvm -o - | FileCheck %s + +// This structure would normally be returned via EAX +struct S { + int i; +}; + +// This structure would normally be returned via EAX/EDX +struct M { + int i; + int j; +}; + +class C { +public: + C() {} + + struct S __attribute__((thiscall)) Small() const { + struct S s = { 0 }; + return s; + } + + struct M __attribute__((thiscall)) Medium() const { + struct M m = { 0 }; + return m; + } +}; + +// CHECK: define void @_Z4testv() +void test( void ) { +// CHECK: call void @_ZN1CC1Ev(%class.C* [[C:%.+]]) + C c; + +// CHECK: call x86_thiscallcc void @_ZNK1C5SmallEv(%struct.S* sret %{{.+}}, %class.C* [[C]]) + (void)c.Small(); +// CHECK: call x86_thiscallcc void @_ZNK1C6MediumEv(%struct.M* sret %{{.+}}, %class.C* [[C]]) + (void)c.Medium(); +} diff --git a/clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp b/clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp new file mode 100644 index 0000000..769d120 --- /dev/null +++ b/clang/test/CodeGenCXX/threadsafe-statics-exceptions.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -emit-llvm -o - -fcxx-exceptions -fexceptions -triple x86_64-apple-darwin10 %s | FileCheck %s + +struct X { + X(); + ~X(); +}; + +struct Y { }; + +// CHECK: define void @_Z1fv +void f() { + // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZ1fvE1x) + // CHECK: invoke void @_ZN1XC1Ev + // CHECK: call i32 @__cxa_atexit + // CHECK-NEXT: call void @__cxa_guard_release(i64* @_ZGVZ1fvE1x) + // CHECK: br + static X x; + + // CHECK: call i8* @__cxa_allocate_exception + // CHECK: call void @__cxa_throw + throw Y(); + + // Finally, the landing pad. + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK: cleanup + // CHECK: call void @__cxa_guard_abort(i64* @_ZGVZ1fvE1x) + // CHECK: resume { i8*, i32 } +} diff --git a/clang/test/CodeGenCXX/threadsafe-statics.cpp b/clang/test/CodeGenCXX/threadsafe-statics.cpp new file mode 100644 index 0000000..8afc274 --- /dev/null +++ b/clang/test/CodeGenCXX/threadsafe-statics.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -emit-llvm -triple=x86_64-apple-darwin10 -o - %s | FileCheck -check-prefix=WITH-TSS %s +// RUN: %clang_cc1 -emit-llvm -triple=x86_64-apple-darwin10 -o - %s -fno-threadsafe-statics | FileCheck -check-prefix=NO-TSS %s + +int f(); + +// WITH-TSS: @_ZZ1gvE1a = internal global i32 0, align 4 +// WITH-TSS: @_ZGVZ1gvE1a = internal global i64 0 + +// WITH-TSS: define void @_Z1gv() nounwind +// WITH-TSS: call i32 @__cxa_guard_acquire +// WITH-TSS: call void @__cxa_guard_release +// WITH-TSS: ret void +void g() { + static int a = f(); +} + +// NO-TSS: @_ZZ1gvE1a = internal global i32 0, align 4 +// NO-TSS: @_ZGVZ1gvE1a = internal global i8 0 + +// NO-TSS: define void @_Z1gv() nounwind +// NO-TSS-NOT: call i32 @__cxa_guard_acquire +// NO-TSS-NOT: call void @__cxa_guard_release +// NO-TSS: ret void diff --git a/clang/test/CodeGenCXX/throw-expression-dtor.cpp b/clang/test/CodeGenCXX/throw-expression-dtor.cpp new file mode 100644 index 0000000..0de6683 --- /dev/null +++ b/clang/test/CodeGenCXX/throw-expression-dtor.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -emit-llvm-only -verify -fcxx-exceptions -fexceptions +// PR7281 + +class A { +public: + ~A(); +}; +class B : public A { + void ice_throw(); +}; +void B::ice_throw() { + throw *this; +} diff --git a/clang/test/CodeGenCXX/throw-expressions.cpp b/clang/test/CodeGenCXX/throw-expressions.cpp new file mode 100644 index 0000000..2515acb --- /dev/null +++ b/clang/test/CodeGenCXX/throw-expressions.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -emit-llvm-only -verify %s -Wno-unreachable-code + +int val = 42; +int& test1() { + return throw val, val; +} + +int test2() { + return val ? throw val : val; +} + +// rdar://problem/8608801 +void test3() { + throw false; +} + +// PR10582 +int test4() { + return 1 ? throw val : val; +} diff --git a/clang/test/CodeGenCXX/thunk-linkonce-odr.cpp b/clang/test/CodeGenCXX/thunk-linkonce-odr.cpp new file mode 100644 index 0000000..4f4d61d --- /dev/null +++ b/clang/test/CodeGenCXX/thunk-linkonce-odr.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// <rdar://problem/7929157> & <rdar://problem/8104369> + +struct A { + virtual int f() { return 1; } +}; + +struct B { + virtual int f() { return 2; } +}; + +struct C : A, B { + virtual int f() { return 3; } +}; + +struct D : C { + virtual int f() { return 4; } +}; + +static int f(D* d) { + B* b = d; + return b->f(); +}; + +int g() { + D d; + return f(&d); +} + +// Thunks should be marked as "linkonce ODR" not "weak". +// +// CHECK: define linkonce_odr i32 @_ZThn{{[48]}}_N1D1fEv +// CHECK: define linkonce_odr i32 @_ZThn{{[48]}}_N1C1fEv diff --git a/clang/test/CodeGenCXX/thunk-use-after-free.cpp b/clang/test/CodeGenCXX/thunk-use-after-free.cpp new file mode 100644 index 0000000..d70e902 --- /dev/null +++ b/clang/test/CodeGenCXX/thunk-use-after-free.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -emit-llvm-only -O1 %s +// This used to crash under asan and valgrind. +// PR12284 + +template < typename _Tp > struct new_allocator +{ + typedef _Tp *pointer; + template < typename > struct rebind { + typedef new_allocator other; + }; +}; +template < typename _Tp > struct allocator:new_allocator < _Tp > { +}; +template < typename _Tp, typename _Alloc > struct _Vector_base { + typedef typename _Alloc::template rebind < _Tp >::other _Tp_alloc_type; + struct _Vector_impl { + typename _Tp_alloc_type::pointer _M_end_of_storage; + }; + _Vector_base () { + foo((int *) this->_M_impl._M_end_of_storage); + } + void foo(int *); + _Vector_impl _M_impl; +}; +template < typename _Tp, typename _Alloc = +allocator < _Tp > >struct vector:_Vector_base < _Tp, _Alloc > { }; + + +template < class T> struct HHH {}; +struct DDD { int x_;}; +struct Data; +struct X1; +struct CCC:DDD { virtual void xxx (HHH < X1 >); }; +template < class SSS > struct EEE:vector < HHH < SSS > > { }; +template < class SSS, class = EEE < SSS > >class FFF { }; +template < class SSS, class GGG = EEE < SSS > >class AAA:FFF <GGG> { }; +class BBB:virtual CCC { + void xxx (HHH < X1 >); + vector < HHH < X1 > >aaa; +}; +class ZZZ:AAA < Data >, BBB { virtual ZZZ *ppp () ; }; +ZZZ * ZZZ::ppp () { return new ZZZ; } diff --git a/clang/test/CodeGenCXX/thunks-available-externally.cpp b/clang/test/CodeGenCXX/thunks-available-externally.cpp new file mode 100644 index 0000000..dfdb786 --- /dev/null +++ b/clang/test/CodeGenCXX/thunks-available-externally.cpp @@ -0,0 +1,88 @@ +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s + +// Check that we don't assert on this case. +namespace Test1 { + +struct Incomplete; + +struct A { + virtual void f(); + virtual void g(Incomplete); + virtual void h(); + virtual void i(); + int a; +}; + +struct B { + virtual void f(); + virtual void g(Incomplete); + virtual void h(); + virtual void i(); + int b; +}; + +struct C : A, B { + C(); + + virtual void f(); + virtual void g(Incomplete); + virtual void h(); + virtual void i(); +}; + +void C::h() { } + +C::C() { } + +void C::i() { } + +} + +namespace Test2 { + +struct A { + virtual void f(); + int a; +}; + +struct B { + virtual void f(); + int b; +}; + +struct C : A, B { + virtual void f(); +}; + +static void f(B* b) { + b->f(); +} + +// CHECK: define void @_ZN5Test21fEv() +// CHECK: call void @_ZN5Test21C1fEv +// CHECK: ret void +// CHECK: define available_externally void @_ZThn16_N5Test21C1fEv +void f() { + C c; + f(&c); +} + +} + +// Test that we don't assert. +namespace Test3 { + +struct A { + virtual ~A(); + + int a; +}; + +struct B : A { }; +struct C : virtual B { }; + +void f() { + C c; +} + +} diff --git a/clang/test/CodeGenCXX/thunks.cpp b/clang/test/CodeGenCXX/thunks.cpp new file mode 100644 index 0000000..04d0820 --- /dev/null +++ b/clang/test/CodeGenCXX/thunks.cpp @@ -0,0 +1,308 @@ +// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-pc-linux-gnu -fhidden-weak-vtables -emit-llvm -o - | FileCheck -check-prefix=HIDDEN %s + +namespace Test1 { + +// Check that we emit a non-virtual thunk for C::f. + +struct A { + virtual void f(); +}; + +struct B { + virtual void f(); +}; + +struct C : A, B { + virtual void c(); + + virtual void f(); +}; + +// CHECK: define void @_ZThn8_N5Test11C1fEv( +void C::f() { } + +} + +namespace Test2 { + +// Check that we emit a thunk for B::f since it's overriding a virtual base. + +struct A { + virtual void f(); +}; + +struct B : virtual A { + virtual void b(); + virtual void f(); +}; + +// CHECK: define void @_ZTv0_n24_N5Test21B1fEv( +void B::f() { } + +} + +namespace Test3 { + +// Check that we emit a covariant thunk for B::f. + +struct V1 { }; +struct V2 : virtual V1 { }; + +struct A { + virtual V1 *f(); +}; + +struct B : A { + virtual void b(); + + virtual V2 *f(); +}; + +// CHECK: define %{{.*}}* @_ZTch0_v0_n24_N5Test31B1fEv( +V2 *B::f() { return 0; } + +} + +namespace Test4 { + +// Check that the thunk for 'C::f' has the same visibility as the function itself. + +struct A { + virtual void f(); +}; + +struct B { + virtual void f(); +}; + +struct __attribute__((visibility("protected"))) C : A, B { + virtual void c(); + + virtual void f(); +}; + +// CHECK: define protected void @_ZThn8_N5Test41C1fEv( +void C::f() { } + +} + +// Check that the thunk gets internal linkage. +namespace Test4B { + struct A { + virtual void f(); + }; + + struct B { + virtual void f(); + }; + + namespace { + struct C : A, B { + virtual void c(); + virtual void f(); + }; + } + void C::c() {} + void C::f() {} + + // Force C::f to be used. + void f() { + C c; + c.f(); + } +} + +namespace Test5 { + +// Check that the thunk for 'B::f' gets the same linkage as the function itself. +struct A { + virtual void f(); +}; + +struct B : virtual A { + virtual void f() { } +}; + +void f(B b) { + b.f(); +} +} + +namespace Test6 { + struct X { + X(); + X(const X&); + X &operator=(const X&); + ~X(); + }; + + struct P { + P(); + P(const P&); + ~P(); + X first; + X second; + }; + + P getP(); + + struct Base1 { + int i; + + virtual X f() { return X(); } + }; + + struct Base2 { + float real; + + virtual X f() { return X(); } + }; + + struct Thunks : Base1, Base2 { + long l; + + virtual X f(); + }; + + // CHECK: define void @_ZThn16_N5Test66Thunks1fEv + // CHECK-NOT: memcpy + // CHECK: {{call void @_ZN5Test66Thunks1fEv.*sret}} + // CHECK: ret void + X Thunks::f() { return X(); } +} + +namespace Test7 { + // PR7188 + struct X { + X(); + X(const X&); + X &operator=(const X&); + ~X(); + }; + + struct Small { short s; }; + struct Large { + char array[1024]; + }; + + class A { + protected: + virtual void foo() = 0; + }; + + class B : public A { + protected: + virtual void bar() = 0; + }; + + class C : public A { + protected: + virtual void baz(X, X&, _Complex float, Small, Small&, Large) = 0; + }; + + class D : public B, + public C { + + void foo() {} + void bar() {} + void baz(X, X&, _Complex float, Small, Small&, Large); + }; + + void D::baz(X, X&, _Complex float, Small, Small&, Large) { } + + // CHECK: define void @_ZThn8_N5Test71D3bazENS_1XERS1_CfNS_5SmallERS4_NS_5LargeE( + // CHECK-NOT: memcpy + // CHECK: ret void + void testD() { D d; } +} + +namespace Test8 { + struct NonPOD { ~NonPOD(); int x, y, z; }; + struct A { virtual void foo(); }; + struct B { virtual void bar(NonPOD); }; + struct C : A, B { virtual void bar(NonPOD); static void helper(NonPOD); }; + + // CHECK: define void @_ZN5Test81C6helperENS_6NonPODE([[NONPODTYPE:%.*]]* + void C::helper(NonPOD var) {} + + // CHECK: define void @_ZThn8_N5Test81C3barENS_6NonPODE( + // CHECK-NOT: load [[NONPODTYPE]]* + // CHECK-NOT: memcpy + // CHECK: ret void + void C::bar(NonPOD var) {} +} + +// PR7241: Emitting thunks for a method shouldn't require the vtable for +// that class to be emitted. +namespace Test9 { + struct A { virtual ~A() { } }; + struct B : A { virtual void test() const {} }; + struct C : B { C(); ~C(); }; + struct D : C { D() {} }; + void test() { + D d; + } +} + +namespace Test10 { + struct A { virtual void foo(); }; + struct B { virtual void foo(); }; + struct C : A, B { void foo() {} }; + + // CHECK-HIDDEN: define linkonce_odr void @_ZN6Test101C3fooEv + // CHECK-HIDDEN: define linkonce_odr hidden void @_ZThn8_N6Test101C3fooEv + + void test() { + C c; + } +} + +// PR7611 +namespace Test11 { + struct A { virtual A* f(); }; + struct B : virtual A { virtual A* f(); }; + struct C : B { virtual C* f(); }; + C* C::f() { return 0; } + + // C::f itself. + // CHECK: define {{.*}} @_ZN6Test111C1fEv( + + // The this-adjustment and return-adjustment thunk required when + // C::f appears in a vtable where A is at a nonzero offset from C. + // CHECK: define {{.*}} @_ZTcv0_n24_v0_n32_N6Test111C1fEv( + + // The return-adjustment thunk required when C::f appears in a vtable + // where A is at a zero offset from C. + // CHECK: define {{.*}} @_ZTch0_v0_n32_N6Test111C1fEv( +} + +// Varargs thunk test. +namespace Test12 { + struct A { + virtual A* f(int x, ...); + }; + struct B { + virtual B* f(int x, ...); + }; + struct C : A, B { + virtual void c(); + virtual C* f(int x, ...); + }; + C* C::f(int x, ...) { return this; } + + // C::f + // CHECK: define {{.*}} @_ZN6Test121C1fEiz + + // Varargs thunk; check that both the this and covariant adjustments + // are generated. + // CHECK: define {{.*}} @_ZTchn8_h8_N6Test121C1fEiz + // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK: getelementptr inbounds i8* {{.*}}, i64 8 +} + +/**** The following has to go at the end of the file ****/ + +// This is from Test5: +// CHECK: define linkonce_odr void @_ZTv0_n24_N5Test51B1fEv +// CHECK: define internal void @_ZThn8_N6Test4B12_GLOBAL__N_11C1fEv( diff --git a/clang/test/CodeGenCXX/trivial-constructor-init.cpp b/clang/test/CodeGenCXX/trivial-constructor-init.cpp new file mode 100644 index 0000000..343dc65 --- /dev/null +++ b/clang/test/CodeGenCXX/trivial-constructor-init.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -S %s -o %t-64.s +// RUN: %clang_cc1 -S %s -o %t-32.s + +extern "C" int printf(...); + +struct S { + S() { printf("S::S\n"); } +}; + +struct A { + double x; + A() : x(), y(), s() { printf("x = %f y = %x \n", x, y); } + int *y; + S s; +}; + +A a; + +int main() { +} diff --git a/clang/test/CodeGenCXX/try-catch.cpp b/clang/test/CodeGenCXX/try-catch.cpp new file mode 100644 index 0000000..89f229f --- /dev/null +++ b/clang/test/CodeGenCXX/try-catch.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s + +struct X { }; + +const X g(); + +void f() { + try { + throw g(); + // CHECK: @_ZTI1X to i8 + } catch (const X x) { + } +} diff --git a/clang/test/CodeGenCXX/typeid-cxx11.cpp b/clang/test/CodeGenCXX/typeid-cxx11.cpp new file mode 100644 index 0000000..940274e --- /dev/null +++ b/clang/test/CodeGenCXX/typeid-cxx11.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -std=c++11 -o - | FileCheck %s +#include <typeinfo> + +namespace Test1 { + +struct Item { + const std::type_info &ti; + const char *name; + void *(*make)(); +}; + +template<typename T> void *make_impl() { return new T; } +template<typename T> constexpr Item item(const char *name) { + return { typeid(T), name, make_impl<T> }; +} + +struct A { virtual ~A(); }; +struct B : virtual A {}; +struct C { int n; }; + +// FIXME: check we produce a constant array for this, once we support IRGen of +// folded structs and arrays. +constexpr Item items[] = { + item<A>("A"), item<B>("B"), item<C>("C"), item<int>("int") +}; + +// CHECK: @_ZN5Test11xE = constant %"class.std::type_info"* bitcast (i8** @_ZTIN5Test11AE to %"class.std::type_info"*), align 8 +constexpr auto &x = items[0].ti; + +} diff --git a/clang/test/CodeGenCXX/typeid.cpp b/clang/test/CodeGenCXX/typeid.cpp new file mode 100644 index 0000000..fce3795 --- /dev/null +++ b/clang/test/CodeGenCXX/typeid.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -I%S %s -triple x86_64-apple-darwin10 -emit-llvm -fcxx-exceptions -fexceptions -o - | FileCheck %s +#include <typeinfo> + +namespace Test1 { + +// PR7400 +struct A { virtual void f(); }; + +// CHECK: @_ZN5Test16int_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTIi to %"class.std::type_info"*), align 8 +const std::type_info &int_ti = typeid(int); + +// CHECK: @_ZN5Test14A_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTIN5Test11AE to %"class.std::type_info"*), align 8 +const std::type_info &A_ti = typeid(const volatile A &); + +volatile char c; + +// CHECK: @_ZN5Test14c_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTIc to %"class.std::type_info"*), align 8 +const std::type_info &c_ti = typeid(c); + +extern const double &d; + +// CHECK: @_ZN5Test14d_tiE = constant %"class.std::type_info"* bitcast (i8** @_ZTId to %"class.std::type_info"*), align 8 +const std::type_info &d_ti = typeid(d); + +extern A &a; + +// CHECK: @_ZN5Test14a_tiE = global +const std::type_info &a_ti = typeid(a); + +// CHECK: define i8* @_ZN5Test11fEv +const char *f() { + try { + // CHECK: br i1 + // CHECK: invoke void @__cxa_bad_typeid() noreturn + return typeid(*static_cast<A *>(0)).name(); + } catch (...) { + // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) + // CHECK-NEXT: catch i8* null + } + + return 0; +} + +} diff --git a/clang/test/CodeGenCXX/typeinfo b/clang/test/CodeGenCXX/typeinfo new file mode 100644 index 0000000..7af23cf --- /dev/null +++ b/clang/test/CodeGenCXX/typeinfo @@ -0,0 +1,16 @@ +namespace std { + class type_info { + public: + virtual ~type_info(); + const char* name() const { return __name; } + bool operator==(const type_info& __arg) const { + return __name == __arg.__name; + } + + bool operator!=(const type_info& __arg) const { + return !operator==(__arg); + } + protected: + const char *__name; + }; +} diff --git a/clang/test/CodeGenCXX/unary-type-trait.cpp b/clang/test/CodeGenCXX/unary-type-trait.cpp new file mode 100644 index 0000000..a11c67e --- /dev/null +++ b/clang/test/CodeGenCXX/unary-type-trait.cpp @@ -0,0 +1,3 @@ +// RUN: %clang_cc1 -emit-llvm-only -verify %s + +bool a() { return __is_pod(int); } diff --git a/clang/test/CodeGenCXX/uncode-string.cpp b/clang/test/CodeGenCXX/uncode-string.cpp new file mode 100644 index 0000000..1d83999 --- /dev/null +++ b/clang/test/CodeGenCXX/uncode-string.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +// rdar://8360841 + +wchar_t s[] = L"\u2722"; + +// CHECK: @s = global [2 x i32] [i32 10018, i32 0], align 4 diff --git a/clang/test/CodeGenCXX/union-dtor.cpp b/clang/test/CodeGenCXX/union-dtor.cpp new file mode 100644 index 0000000..a0b822a --- /dev/null +++ b/clang/test/CodeGenCXX/union-dtor.cpp @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -std=c++11 %s -S -o - -emit-llvm | FileCheck %s + +// PR10304: destructors should not call destructors for variant members. + +template<bool b = false> +struct Foo { + Foo() { static_assert(b, "Foo::Foo used"); } + ~Foo() { static_assert(b, "Foo::~Foo used"); } +}; + +struct Bar { + Bar(); + ~Bar(); +}; + +union FooBar { + FooBar() {} + ~FooBar() {} + Foo<> foo; + Bar bar; +}; + +struct Variant { + Variant() {} + ~Variant() {} + union { + Foo<> foo; + Bar bar; + }; +}; + +FooBar foobar; +Variant variant; + +// The ctor and dtor of Foo<> and Bar should not be mentioned in the resulting +// code. +// +// CHECK-NOT: 3FooILb1EEC1 +// CHECK-NOT: 3BarC1 +// +// CHECK-NOT: 3FooILb1EED1 +// CHECK-NOT: 3BarD1 diff --git a/clang/test/CodeGenCXX/unknown-anytype.cpp b/clang/test/CodeGenCXX/unknown-anytype.cpp new file mode 100644 index 0000000..902cc8d --- /dev/null +++ b/clang/test/CodeGenCXX/unknown-anytype.cpp @@ -0,0 +1,99 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -funknown-anytype -emit-llvm -o - %s | FileCheck %s + +int test0() { + extern __unknown_anytype test0_any; + // CHECK: load i32* @test0_any + return (int) test0_any; +} + +int test1() { + extern __unknown_anytype test1_any(); + // CHECK: call i32 @_Z9test1_anyv() + return (int) test1_any(); +} + +extern "C" __unknown_anytype test2_any(...); +float test2() { + // CHECK: call float (...)* @test2_any(double {{[^,]+}}) + return (float) test2_any(0.5f); +} + +extern "C" __unknown_anytype test2a_any(...); +float test2a() { + // CHECK: call float (...)* @test2a_any(float {{[^,]+}}) + return (float) test2a_any((float) 0.5f); +} + +float test3() { + extern __unknown_anytype test3_any; + // CHECK: [[FN:%.*]] = load float (i32)** @test3_any, + // CHECK: call float [[FN]](i32 5) + return ((float(*)(int)) test3_any)(5); +} + +namespace test4 { + extern __unknown_anytype test4_any1; + extern __unknown_anytype test4_any2; + + int test() { + // CHECK: load i32* @_ZN5test410test4_any1E + // CHECK: load i8* @_ZN5test410test4_any2E + return (int) test4_any1 + (char) test4_any2; + } +} + +extern "C" __unknown_anytype test5_any(); +void test5() { + // CHECK: call void @test5_any() + return (void) test5_any(); +} + +extern "C" __unknown_anytype test6_any(float *); +long test6() { + // CHECK: call i64 @test6_any(float* null) + return (long) test6_any(0); +} + +struct Test7 { + ~Test7(); +}; +extern "C" __unknown_anytype test7_any(int); +Test7 test7() { + // CHECK: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5) + return (Test7) test7_any(5); +} + +struct Test8 { + __unknown_anytype foo(); + __unknown_anytype foo(int); + + void test(); +}; +void Test8::test() { + float f; + // CHECK: call i32 @_ZN5Test83fooEv( + f = (int) foo(); + // CHECK: call i32 @_ZN5Test83fooEi( + f = (int) foo(5); + // CHECK: call i32 @_ZN5Test83fooEv( + f = (float) this->foo(); + // CHECK: call i32 @_ZN5Test83fooEi( + f = (float) this->foo(5); +} +void test8(Test8 *p) { + double d; + // CHECK: call i32 @_ZN5Test83fooEv( + d = (double) p->foo(); + // CHECK: call i32 @_ZN5Test83fooEi( + d = (double) p->foo(5); + // CHECK: call i32 @_ZN5Test83fooEv( + d = (bool) (*p).foo(); + // CHECK: call i32 @_ZN5Test83fooEi( + d = (bool) (*p).foo(5); +} + +extern "C" __unknown_anytype test9_foo; +void *test9() { + // CHECK: ret i8* bitcast (i32* @test9_foo to i8*) + return (int*) &test9_foo; +} diff --git a/clang/test/CodeGenCXX/value-init.cpp b/clang/test/CodeGenCXX/value-init.cpp new file mode 100644 index 0000000..6e60f80 --- /dev/null +++ b/clang/test/CodeGenCXX/value-init.cpp @@ -0,0 +1,262 @@ +// RUN: %clang_cc1 %s -triple x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +struct A { + virtual ~A(); +}; + +struct B : A { }; + +struct C { + int i; + B b; +}; + +// CHECK: _Z15test_value_initv +void test_value_init() { + // This value initialization requires zero initialization of the 'B' + // subobject followed by a call to its constructor. + // PR5800 + + // CHECK: store i32 17 + // CHECK: call void @llvm.memset.p0i8.i64 + // CHECK: call void @_ZN1BC1Ev + C c = { 17 } ; + // CHECK: call void @_ZN1CD1Ev +} + +enum enum_type { negative_number = -1, magic_number = 42 }; + +class enum_holder +{ + enum_type m_enum; + +public: + enum_holder() : m_enum(magic_number) { } +}; + +struct enum_holder_and_int +{ + enum_holder e; + int i; +}; + +// CHECK: _Z24test_enum_holder_and_intv() +void test_enum_holder_and_int() { + // CHECK: alloca + // CHECK-NEXT: bitcast + // CHECK-NEXT: call void @llvm.memset + // CHECK-NEXT: call void @_ZN19enum_holder_and_intC1Ev + enum_holder_and_int(); + // CHECK-NEXT: ret void +} + +// PR7834: don't crash. +namespace test1 { + struct A { + int A::*f; + A(); + A(const A&); + A &operator=(const A &); + }; + + struct B { + A base; + }; + + void foo() { + B(); + } +} + +namespace ptrmem { + struct S { + int mem1; + int S::*mem2; + }; + + // CHECK: define i32 @_ZN6ptrmem4testEPNS_1SE + int test(S *s) { + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64 + // CHECK: getelementptr + // CHECK: ret + return s->*S().mem2; + } +} + +namespace PR9801 { + +struct Test { + Test() : i(10) {} + Test(int i) : i(i) {} + int i; +private: + int j; +}; + +struct Test2 { + Test t; +}; + +struct Test3 : public Test { }; + +// CHECK: define void @_ZN6PR98011fEv +void f() { + // CHECK-NOT: call void @llvm.memset.p0i8.i64 + // CHECK: call void @_ZN6PR98014TestC1Ei + // CHECK-NOT: call void @llvm.memset.p0i8.i64 + // CHECK: call void @_ZN6PR98014TestC1Ev + Test partial[3] = { 1 }; + + // CHECK-NOT: call void @llvm.memset.p0i8.i64 + // CHECK: call void @_ZN6PR98014TestC1Ev + // CHECK-NOT: call void @_ZN6PR98014TestC1Ev + Test empty[3] = {}; + + // CHECK: call void @llvm.memset.p0i8.i64 + // CHECK-NOT: call void @llvm.memset.p0i8.i64 + // CHECK: call void @_ZN6PR98015Test2C1Ev + // CHECK-NOT: call void @_ZN6PR98015Test2C1Ev + Test2 empty2[3] = {}; + + // CHECK: call void @llvm.memset.p0i8.i64 + // CHECK-NOT: call void @llvm.memset.p0i8.i64 + // CHECK: call void @_ZN6PR98015Test3C1Ev + // CHECK-NOT: call void @llvm.memset.p0i8.i64 + // CHECK-NOT: call void @_ZN6PR98015Test3C1Ev + Test3 empty3[3] = {}; +} + +} + +namespace zeroinit { + struct S { int i; }; + + // CHECK: define i32 @_ZN8zeroinit4testEv() + int test() { + // CHECK: call void @llvm.memset.p0i8.i64 + // CHECK: ret i32 0 + return S().i; + } + + struct X0 { + X0() { } + int x; + }; + + struct X1 : X0 { + int x1; + void f(); + }; + + // CHECK: define void @_ZN8zeroinit9testX0_X1Ev + void testX0_X1() { + // CHECK: call void @llvm.memset.p0i8.i64 + // CHECK-NEXT: call void @_ZN8zeroinit2X1C1Ev + // CHECK-NEXT: call void @_ZN8zeroinit2X11fEv + X1().f(); + } + + template<typename> + struct X2 : X0 { + int x2; + void f(); + }; + + template<typename> + struct X3 : X2<int> { + X3() : X2<int>() { } + int i; + }; + + + // CHECK: define void @_ZN8zeroinit9testX0_X3Ev + void testX0_X3() { + // CHECK-NOT: call void @llvm.memset + // CHECK: call void @_ZN8zeroinit2X3IiEC1Ev + // CHECK: call void @_ZN8zeroinit2X2IiE1fEv + // CHECK-NEXT: ret void + X3<int>().f(); + } + + // More checks at EOF +} + +namespace PR8726 { +class C; +struct S { + const C &c1; + int i; + const C &c2; +}; +void f(const C& c) { + S s = {c, 42, c}; +} + +} + +// rdar://problem/9355931 +namespace test6 { + struct A { A(); A(int); }; + + void test() { + A arr[10][20] = { 5 }; + }; + // CHECK: define void @_ZN5test64testEv() + // CHECK: [[ARR:%.*]] = alloca [10 x [20 x [[A:%.*]]]], + + // CHECK-NEXT: [[INNER:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]]* [[ARR]], i64 0, i64 0 + // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 0, i64 0 + // CHECK-NEXT: call void @_ZN5test61AC1Ei([[A]]* [[T0]], i32 5) + // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [[A]]* [[T0]], i64 1 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[T0]], i64 20 + // CHECK-NEXT: br label + // CHECK: [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ] + // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[CUR]]) + // CHECK-NEXT: [[NEXT]] = getelementptr inbounds [[A]]* [[CUR]], i64 1 + // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[NEXT]], [[END]] + // CHECK-NEXT: br i1 + + // CHECK: [[BEGIN:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 1 + // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 10 + // CHECK-NEXT: br label + // CHECK: [[CUR:%.*]] = phi [20 x [[A]]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ] + + // Inner loop. + // CHECK-NEXT: [[IBEGIN:%.*]] = getelementptr inbounds [20 x [[A]]]* [[CUR]], i32 0, i32 0 + // CHECK-NEXT: [[IEND:%.*]] = getelementptr inbounds [[A]]* [[IBEGIN]], i64 20 + // CHECK-NEXT: br label + // CHECK: [[ICUR:%.*]] = phi [[A]]* [ [[IBEGIN]], {{%.*}} ], [ [[INEXT:%.*]], {{%.*}} ] + // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[ICUR]]) + // CHECK-NEXT: [[INEXT:%.*]] = getelementptr inbounds [[A]]* [[ICUR]], i64 1 + // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[INEXT]], [[IEND]] + // CHECK-NEXT: br i1 [[T0]], + + // CHECK: [[NEXT]] = getelementptr inbounds [20 x [[A]]]* [[CUR]], i64 1 + // CHECK-NEXT: [[T0:%.*]] = icmp eq [20 x [[A]]]* [[NEXT]], [[END]] + // CHECK-NEXT: br i1 [[T0]] + // CHECK: ret void +} + +namespace PR11124 { + // Make sure C::C doesn't overwrite parts of A while it is zero-initializing B + struct A { int a; A(); A(int); }; + struct B : virtual A { int b; }; + struct C : B { C(); }; + C::C() : A(3), B() {} + // CHECK: define void @_ZN7PR111241CC1Ev + // CHECK: call void @llvm.memset.p0i8.i64(i8* {{.*}}, i8 0, i64 12, i32 8, i1 false) + // CHECK-NEXT: call void @_ZN7PR111241BC2Ev + // Make sure C::C doesn't overwrite parts of A while it is zero-initializing B + + struct B2 : virtual A { int B::*b; }; + struct C2 : B2 { C2(); }; + C2::C2() : A(3), B2() {} + // CHECK: define void @_ZN7PR111242C2C1Ev + // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* {{.*}}, i64 16, i32 8, i1 false) + // CHECK-NEXT: call void @_ZN7PR111242B2C2Ev +} + +// CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr +// CHECK: call void @llvm.memset.p0i8.i64 +// CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev +// CHECK-NEXT: ret void diff --git a/clang/test/CodeGenCXX/vararg-conversion-ctor.cpp b/clang/test/CodeGenCXX/vararg-conversion-ctor.cpp new file mode 100644 index 0000000..a49b1db --- /dev/null +++ b/clang/test/CodeGenCXX/vararg-conversion-ctor.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin -std=c++11 -emit-llvm %s -o %t-64.ll +// RUN: FileCheck -check-prefix LPLL64 --input-file=%t-64.ll %s + +extern "C" int printf(...); + +struct A { + A(...) { + printf("A::A(...)\n"); + } +}; + +A a(1.34); + +A b = 2.34; + +int main() +{ + A c[3]; +} + +// CHECK-LPLL64: call void (%struct.A*, ...) +// CHECK-LPLL64: call void (%struct.A*, ...) +// CHECK-LPLL64: call void (%struct.A*, ...) diff --git a/clang/test/CodeGenCXX/vararg-non-pod.cpp b/clang/test/CodeGenCXX/vararg-non-pod.cpp new file mode 100644 index 0000000..6c6f459 --- /dev/null +++ b/clang/test/CodeGenCXX/vararg-non-pod.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -Wno-error=non-pod-varargs -emit-llvm -o - %s | FileCheck %s + +struct X { + X(); + X(const X&); + ~X(); +}; + +void vararg(...); + +// CHECK: define void @_Z4test1X +void test(X x) { + // CHECK: call void @llvm.trap() + vararg(x); + // CHECK: ret void +} diff --git a/clang/test/CodeGenCXX/varargs.cpp b/clang/test/CodeGenCXX/varargs.cpp new file mode 100644 index 0000000..af34336 --- /dev/null +++ b/clang/test/CodeGenCXX/varargs.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s + +// rdar://7309675 +// PR4678 +namespace test0 { + // test1 should be compmiled to be a varargs function in the IR even + // though there is no way to do a va_begin. Otherwise, the optimizer + // will warn about 'dropped arguments' at the call site. + + // CHECK: define i32 @_ZN5test05test1Ez(...) + int test1(...) { + return -1; + } + + // CHECK: call i32 (...)* @_ZN5test05test1Ez(i32 0) + void test() { + test1(0); + } +} + +namespace test1 { + struct A { + int x; + int y; + }; + + void foo(...); + + void test() { + A x; + foo(x); + } + // CHECK: define void @_ZN5test14testEv() + // CHECK: [[X:%.*]] = alloca [[A:%.*]], align 4 + // CHECK-NEXT: [[TMP:%.*]] = alloca [[A]], align 4 + // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[TMP]] to i8* + // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[X]] to i8* + // CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T0]], i8* [[T1]], i64 8, i32 4, i1 false) + // CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[TMP]] to i64* + // CHECK-NEXT: [[T1:%.*]] = load i64* [[T0]], align 1 + // CHECK-NEXT: call void (...)* @_ZN5test13fooEz(i64 [[T1]]) + // CHECK-NEXT: ret void +} diff --git a/clang/test/CodeGenCXX/variadic-templates.cpp b/clang/test/CodeGenCXX/variadic-templates.cpp new file mode 100644 index 0000000..c56bec3 --- /dev/null +++ b/clang/test/CodeGenCXX/variadic-templates.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -std=c++11 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +template<typename ...Types> +int get_num_types(Types...) { + return sizeof...(Types); +} + +// CHECK: define weak_odr i32 @_Z13get_num_typesIJifdEEiDpT_ +// CHECK: ret i32 3 +template int get_num_types(int, float, double); + +// PR10260 - argument packs that expand to nothing +namespace test1 { + template <class... T> void foo() { + int values[sizeof...(T)+1] = { T::value... }; + // CHECK: define linkonce_odr void @_ZN5test13fooIJEEEvv() + // CHECK: alloca [1 x i32], align 4 + } + + void test() { + foo<>(); + } +} diff --git a/clang/test/CodeGenCXX/virt-call-offsets.cpp b/clang/test/CodeGenCXX/virt-call-offsets.cpp new file mode 100644 index 0000000..5eef6fe --- /dev/null +++ b/clang/test/CodeGenCXX/virt-call-offsets.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +struct A { virtual void a(); }; +struct B : A {}; +struct C : B { virtual void a(); }; +void (C::*x)() = &C::a; + +// CHECK: @x = global { i{{[0-9]+}}, i{{[0-9]+}} } { i{{[0-9]+}} 1, i{{[0-9]+}} 0 } diff --git a/clang/test/CodeGenCXX/virt-canonical-decl.cpp b/clang/test/CodeGenCXX/virt-canonical-decl.cpp new file mode 100644 index 0000000..dfc3619 --- /dev/null +++ b/clang/test/CodeGenCXX/virt-canonical-decl.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 %s -emit-llvm-only + +class Base { +public: + virtual ~Base(); +}; + +Base::~Base() +{ +} + +class Foo : public Base { +public: + virtual ~Foo(); +}; + +Foo::~Foo() +{ +} diff --git a/clang/test/CodeGenCXX/virt-dtor-gen.cpp b/clang/test/CodeGenCXX/virt-dtor-gen.cpp new file mode 100644 index 0000000..1a6c583 --- /dev/null +++ b/clang/test/CodeGenCXX/virt-dtor-gen.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -o - -emit-llvm %s | FileCheck %s +// PR5483 + +// Make sure we generate all three forms of the destructor when it is virtual. +class Foo { + virtual ~Foo(); +}; +Foo::~Foo() {} + +// CHECK: define void @_ZN3FooD0Ev(%class.Foo* %this) unnamed_addr diff --git a/clang/test/CodeGenCXX/virt-dtor-key.cpp b/clang/test/CodeGenCXX/virt-dtor-key.cpp new file mode 100644 index 0000000..a8fa371 --- /dev/null +++ b/clang/test/CodeGenCXX/virt-dtor-key.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s +// CHECK: @_ZTI3foo = unnamed_addr constant +class foo { + foo(); + virtual ~foo(); +}; + +foo::~foo() { +} diff --git a/clang/test/CodeGenCXX/virt-template-vtable.cpp b/clang/test/CodeGenCXX/virt-template-vtable.cpp new file mode 100644 index 0000000..25736fd --- /dev/null +++ b/clang/test/CodeGenCXX/virt-template-vtable.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +template<class T> class A { +public: + A() {} + virtual void a() {} +}; +class B : A<int> { + B(); +}; +B::B() {} + +template class A<long>; + +extern template class A<short>; +template class A<short>; + + +// CHECK: @_ZTV1B = linkonce_odr unnamed_addr constant +// CHECK: @_ZTV1AIlE = weak_odr unnamed_addr constant +// CHECK: @_ZTV1AIsE = weak_odr unnamed_addr constant +// CHECK: @_ZTV1AIiE = linkonce_odr unnamed_addr constant diff --git a/clang/test/CodeGenCXX/virt-thunk-reference.cpp b/clang/test/CodeGenCXX/virt-thunk-reference.cpp new file mode 100644 index 0000000..0cd958b --- /dev/null +++ b/clang/test/CodeGenCXX/virt-thunk-reference.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -emit-llvm-only %s + +struct A { int a; virtual void aa(int&); }; +struct B { int b; virtual void bb(int&); }; +struct C : A,B { virtual void aa(int&), bb(int&); }; +void C::aa(int&) {} +void C::bb(int&) {} diff --git a/clang/test/CodeGenCXX/virtual-base-cast.cpp b/clang/test/CodeGenCXX/virtual-base-cast.cpp new file mode 100644 index 0000000..73b7c1c --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-base-cast.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple i686-pc-linux-gnu | FileCheck %s + +struct A { int a; virtual int aa(); }; +struct B { int b; virtual int bb(); }; +struct C : virtual A, virtual B { int c; virtual int aa(); virtual int bb(); }; +struct AA { int a; virtual int aa(); }; +struct BB { int b; virtual int bb(); }; +struct CC : AA, BB { virtual int aa(); virtual int bb(); virtual int cc(); }; +struct D : virtual C, virtual CC { int e; }; + +D* x; + +A* a() { return x; } +// CHECK: @_Z1av() nounwind +// CHECK: [[VBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -16 +// CHECK: [[CASTVBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = bitcast i8* [[VBASEOFFSETPTRA]] to i32* +// CHECK: load i32* [[CASTVBASEOFFSETPTRA]] +// CHECK: } + +B* b() { return x; } +// CHECK: @_Z1bv() nounwind +// CHECK: [[VBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -20 +// CHECK: [[CASTVBASEOFFSETPTRA:%[a-zA-Z0-9\.]+]] = bitcast i8* [[VBASEOFFSETPTRA]] to i32* +// CHECK: load i32* [[CASTVBASEOFFSETPTRA]] +// CHECK: } + +BB* c() { return x; } +// CHECK: @_Z1cv() nounwind +// CHECK: [[VBASEOFFSETPTRC:%[a-zA-Z0-9\.]+]] = getelementptr i8* {{.*}}, i64 -24 +// CHECK: [[CASTVBASEOFFSETPTRC:%[a-zA-Z0-9\.]+]] = bitcast i8* [[VBASEOFFSETPTRC]] to i32* +// CHECK: [[VBASEOFFSETC:%[a-zA-Z0-9\.]+]] = load i32* [[CASTVBASEOFFSETPTRC]] +// CHECK: add i32 [[VBASEOFFSETC]], 8 +// CHECK: } diff --git a/clang/test/CodeGenCXX/virtual-base-ctor.cpp b/clang/test/CodeGenCXX/virtual-base-ctor.cpp new file mode 100644 index 0000000..2d81ebd --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-base-ctor.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - -O2 | FileCheck %s + +struct B; +extern B x; +char y; +typedef __typeof(sizeof(int)) size_t; +struct A { int a; A() { y = ((size_t)this - (size_t)&x) / sizeof(void*); } }; +struct B : virtual A { void* x; }; +B x; + +// CHECK: @y = global i8 2 diff --git a/clang/test/CodeGenCXX/virtual-base-destructor-call.cpp b/clang/test/CodeGenCXX/virtual-base-destructor-call.cpp new file mode 100644 index 0000000..2424d21 --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-base-destructor-call.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +struct basic_ios{~basic_ios(); }; + +template<typename _CharT> struct basic_istream : virtual public basic_ios { + virtual ~basic_istream(){} +}; + +template<typename _CharT> struct basic_iostream : public basic_istream<_CharT> +{ + virtual ~basic_iostream(){} +}; + +basic_iostream<char> res; + +int main() { +} + +// basic_iostream's complete dtor calls its base dtor, then its +// virtual base's dtor. +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED1Ev(%struct.basic_iostream* %this) unnamed_addr +// CHECK: call {{.*}} @_ZN14basic_iostreamIcED2Ev +// CHECK: call {{.*}} @_ZN9basic_iosD2Ev + +// basic_iostream's base dtor calls its non-virtual base dtor. +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED2Ev(%struct.basic_iostream* %this, i8** %vtt) unnamed_addr +// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev +// CHECK: } + +// basic_iostream's deleting dtor calls its complete dtor, then +// operator delete(). +// CHECK: define linkonce_odr {{.*}} @_ZN14basic_iostreamIcED0Ev(%struct.basic_iostream* %this) unnamed_addr +// CHECK: call {{.*}} @_ZN14basic_iostreamIcED1Ev +// CHECK: call {{.*}} @_ZdlPv + +// basic_istream's complete dtor calls the base dtor, +// then its virtual base's base dtor. +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED1Ev(%struct.basic_istream* %this) unnamed_addr +// CHECK: call {{.*}} @_ZN13basic_istreamIcED2Ev +// CHECK: call {{.*}} @_ZN9basic_iosD2Ev + +// basic_istream's deleting dtor calls the complete dtor, then +// operator delete(). +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED0Ev(%struct.basic_istream* %this) unnamed_addr +// CHECK: call {{.*}} @_ZN13basic_istreamIcED1Ev +// CHECK: call {{.*}} @_ZdlPv + +// basic_istream's base dtor is a no-op. +// CHECK: define linkonce_odr {{.*}} @_ZN13basic_istreamIcED2Ev(%struct.basic_istream* %this, i8** %vtt) unnamed_addr +// CHECK-NOT: call +// CHECK: } diff --git a/clang/test/CodeGenCXX/virtual-bases.cpp b/clang/test/CodeGenCXX/virtual-bases.cpp new file mode 100644 index 0000000..c9f13f8 --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-bases.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s + +struct A { + A(); +}; + +// CHECK: @_ZN1AC1Ev = alias {{.*}} @_ZN1AC2Ev +// CHECK: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr +A::A() { } + +struct B : virtual A { + B(); +}; + +// CHECK: define void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr +// CHECK: define void @_ZN1BC2Ev(%struct.B* %this, i8** %vtt) unnamed_addr +B::B() { } + +struct C : virtual A { + C(bool); +}; + +// CHECK: define void @_ZN1CC1Eb(%struct.C* %this, i1 zeroext) unnamed_addr +// CHECK: define void @_ZN1CC2Eb(%struct.C* %this, i8** %vtt, i1 zeroext) unnamed_addr +C::C(bool) { } + +// PR6251 +namespace PR6251 { + +// Test that we don't call the A<char> constructor twice. + +template<typename T> +struct A { A(); }; + +struct B : virtual A<char> { }; +struct C : virtual A<char> { }; + +struct D : B, C { + D(); +}; + +// CHECK: define void @_ZN6PR62511DC1Ev(%"struct.PR6251::D"* %this) unnamed_addr +// CHECK: call void @_ZN6PR62511AIcEC2Ev +// CHECK-NOT: call void @_ZN6PR62511AIcEC2Ev +// CHECK: ret void +D::D() { } + +} diff --git a/clang/test/CodeGenCXX/virtual-destructor-calls.cpp b/clang/test/CodeGenCXX/virtual-destructor-calls.cpp new file mode 100644 index 0000000..1cc8bcc --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-destructor-calls.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-apple-darwin10 -mconstructor-aliases | FileCheck %s + +struct Member { + ~Member(); +}; + +struct A { + virtual ~A(); +}; + +struct B : A { + Member m; + virtual ~B(); +}; + +// Complete dtor: just an alias because there are no virtual bases. +// CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev + +// (aliases from C) +// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1CD2Ev +// CHECK: @_ZN1CD2Ev = alias bitcast {{.*}} @_ZN1BD2Ev + +// Deleting dtor: defers to the complete dtor. +// CHECK: define void @_ZN1BD0Ev(%struct.B* %this) unnamed_addr +// CHECK: call void @_ZN1BD1Ev +// CHECK: call void @_ZdlPv + +// Base dtor: actually calls A's base dtor. +// CHECK: define void @_ZN1BD2Ev(%struct.B* %this) unnamed_addr +// CHECK: call void @_ZN6MemberD1Ev +// CHECK: call void @_ZN1AD2Ev + +B::~B() { } + +struct C : B { + ~C(); +}; + +C::~C() { } + +// Complete dtor: just an alias (checked above). + +// Deleting dtor: defers to the complete dtor. +// CHECK: define void @_ZN1CD0Ev(%struct.C* %this) unnamed_addr +// CHECK: call void @_ZN1CD1Ev +// CHECK: call void @_ZdlPv + +// Base dtor: just an alias to B's base dtor. diff --git a/clang/test/CodeGenCXX/virtual-destructor-synthesis.cpp b/clang/test/CodeGenCXX/virtual-destructor-synthesis.cpp new file mode 100644 index 0000000..90f66a8 --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-destructor-synthesis.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +struct box { + virtual ~box(); +}; + +struct pile_box : public box { + pile_box(box *); +}; + +pile_box::pile_box(box *pp) +{ +} + +// CHECK: call void @_ZdlPv + diff --git a/clang/test/CodeGenCXX/virtual-function-calls.cpp b/clang/test/CodeGenCXX/virtual-function-calls.cpp new file mode 100644 index 0000000..46e7b2d --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-function-calls.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +// PR5021 +namespace PR5021 { + +struct A { + virtual void f(char); +}; + +void f(A *a) { + // CHECK: call void % + a->f('c'); +} + +struct B : virtual A { + virtual void f(); +}; + +void f(B * b) { + b->f(); +} + +} + +namespace Test1 { + struct A { + virtual ~A(); + }; + + struct B : A { + virtual ~B(); + virtual void f(); + }; + + void f(B *b) { + b->f(); + } +} diff --git a/clang/test/CodeGenCXX/virtual-functions-incomplete-types.cpp b/clang/test/CodeGenCXX/virtual-functions-incomplete-types.cpp new file mode 100644 index 0000000..afa658f --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-functions-incomplete-types.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +struct A; + +struct B { + virtual void f(); + virtual A g(); +}; + +void B::f() { } + +// CHECK: define i32 @_ZN1D1gEv(%struct.D* %this) +// CHECK: declare void @_ZN1B1gEv() + +struct C; + +struct D { + virtual void f(); + virtual C g(); +}; + +void D::f() { } + +struct C { + int a; +}; + +C D::g() { + return C(); +} diff --git a/clang/test/CodeGenCXX/virtual-implicit-copy-assignment.cpp b/clang/test/CodeGenCXX/virtual-implicit-copy-assignment.cpp new file mode 100644 index 0000000..70bc6fc --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-implicit-copy-assignment.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -emit-llvm -o - %s | FileCheck %s + +struct D; +struct B { + virtual D& operator = (const D&); +}; +struct D : B { D(); virtual void a(); }; +void D::a() {} + +// CHECK: @_ZTV1D = {{.*}} @_ZN1DaSERKS_ +// CHECK: define linkonce_odr {{.*}} @_ZN1DaSERKS_ diff --git a/clang/test/CodeGenCXX/virtual-implicit-move-assignment.cpp b/clang/test/CodeGenCXX/virtual-implicit-move-assignment.cpp new file mode 100644 index 0000000..d8ac1ed --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-implicit-move-assignment.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm -std=c++11 -o - %s | FileCheck %s + +struct D; +struct B { + virtual D &operator=(D&&) = 0; +}; +struct D : B { D(); virtual void a(); }; +void D::a() {} +D d; + +// CHECK: @_ZTV1D = {{.*}} @_ZN1DaSEOS_ +// CHECK: define linkonce_odr {{.*}} @_ZN1DaSEOS_ diff --git a/clang/test/CodeGenCXX/virtual-inherited-destructor.cpp b/clang/test/CodeGenCXX/virtual-inherited-destructor.cpp new file mode 100644 index 0000000..509d40a --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-inherited-destructor.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 %s -emit-llvm-only + +struct A { virtual ~A(); }; +struct B : A { + ~B() { } +}; +B x; + diff --git a/clang/test/CodeGenCXX/virtual-operator-call.cpp b/clang/test/CodeGenCXX/virtual-operator-call.cpp new file mode 100644 index 0000000..42d38e5 --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-operator-call.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +struct A { + virtual int operator-() = 0; +}; + +void f(A *a) { + // CHECK: call i32 % + -*a; +} diff --git a/clang/test/CodeGenCXX/virtual-pseudo-destructor-call.cpp b/clang/test/CodeGenCXX/virtual-pseudo-destructor-call.cpp new file mode 100644 index 0000000..0d3574e --- /dev/null +++ b/clang/test/CodeGenCXX/virtual-pseudo-destructor-call.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s + +struct A { + virtual ~A(); +}; + +void f(A *a) { + // CHECK: define {{.*}} @_Z1fP1A + // CHECK: load + // CHECK: load + // CHECK: [[CALLEE:%[a-zA-Z0-9.]*]] = load + // CHECK: call {{.*}} [[CALLEE]]( + a->~A(); +} diff --git a/clang/test/CodeGenCXX/visibility-hidden-extern-templates.cpp b/clang/test/CodeGenCXX/visibility-hidden-extern-templates.cpp new file mode 100644 index 0000000..7629b77 --- /dev/null +++ b/clang/test/CodeGenCXX/visibility-hidden-extern-templates.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -O1 -emit-llvm -o - -fvisibility hidden %s | FileCheck %s + +template<typename T> +struct X { + void f(); + void g() { } +}; + +template<typename T> void X<T>::f() { } + +extern template struct X<int>; +template struct X<int>; +extern template struct X<char>; + +// <rdar://problem/8109763> +void test_X(X<int> xi, X<char> xc) { + // CHECK: define weak_odr hidden void @_ZN1XIiE1fEv + xi.f(); + // CHECK: define weak_odr hidden void @_ZN1XIiE1gEv + xi.g(); + // CHECK: declare void @_ZN1XIcE1fEv + xc.f(); + // CHECK: define available_externally void @_ZN1XIcE1gEv + xc.g(); +} + diff --git a/clang/test/CodeGenCXX/visibility-inlines-hidden.cpp b/clang/test/CodeGenCXX/visibility-inlines-hidden.cpp new file mode 100644 index 0000000..d660b1b --- /dev/null +++ b/clang/test/CodeGenCXX/visibility-inlines-hidden.cpp @@ -0,0 +1,110 @@ +// RUN: %clang_cc1 -fvisibility-inlines-hidden -emit-llvm -o - %s -O2 -disable-llvm-optzns | FileCheck %s + +// The trickery with optimization in the run line is to get IR +// generation to emit available_externally function bodies, but not +// actually inline them (and thus remove the emitted bodies). + +struct X0 { + void __attribute__((visibility("default"))) f1() { } + void f2() { } + void f3(); + static void f5() { } + virtual void f6() { } +}; + +inline void X0::f3() { } + +template<typename T> +struct X1 { + void __attribute__((visibility("default"))) f1() { } + void f2() { } + void f3(); + void f4(); + static void f5() { } + virtual void f6() { } +}; + +template<typename T> +inline void X1<T>::f3() { } + +template<> +inline void X1<int>::f4() { } + +struct __attribute__((visibility("default"))) X2 { + void f2() { } +}; + +extern template struct X1<float>; + +void use(X0 *x0, X1<int> *x1, X2 *x2, X1<float> *x3) { + // CHECK: define linkonce_odr void @_ZN2X02f1Ev + x0->f1(); + // CHECK: define linkonce_odr hidden void @_ZN2X02f2Ev + x0->f2(); + // CHECK: define linkonce_odr hidden void @_ZN2X02f3Ev + x0->f3(); + // CHECK: define linkonce_odr hidden void @_ZN2X02f5Ev + X0::f5(); + // CHECK: define linkonce_odr hidden void @_ZN2X02f6Ev + x0->X0::f6(); + // CHECK: define linkonce_odr void @_ZN2X1IiE2f1Ev + x1->f1(); + // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f2Ev + x1->f2(); + // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f3Ev + x1->f3(); + // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f4Ev + x1->f4(); + // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f5Ev + X1<int>::f5(); + // CHECK: define linkonce_odr hidden void @_ZN2X1IiE2f6Ev + x1->X1::f6(); + // CHECK: define linkonce_odr hidden void @_ZN2X22f2Ev + x2->f2(); + // CHECK: define available_externally void @_ZN2X1IfE2f2Ev + x3->f2(); +} + +// rdar://problem/8614470 +namespace test1 { + struct __attribute__((visibility("default"))) A { + inline void foo(); + ~A(); + }; + + void test() { + A a; + a.foo(); + } +// CHECK: declare void @_ZN5test11A3fooEv +// CHECK: declare {{.*}} @_ZN5test11AD1Ev +} + +// PR8713 +namespace test2 { + struct A {}; + template <class T> class B {}; + typedef B<A> arg; + + namespace ns __attribute__((visibility("default"))) { + template <class T> inline void foo() {} + extern template void foo<arg>(); + } + + void test() { + ns::foo<arg>(); + } + + // CHECK: define available_externally void @_ZN5test22ns3fooINS_1BINS_1AEEEEEvv() +} + +namespace PR11642 { + template <typename T> + class Foo { + public: + T foo(T x) { return x; } + }; + extern template class Foo<int>; + template class Foo<int>; + // CHECK: define weak_odr i32 @_ZN7PR116423FooIiE3fooEi +} diff --git a/clang/test/CodeGenCXX/visibility.cpp b/clang/test/CodeGenCXX/visibility.cpp new file mode 100644 index 0000000..59fd7c2 --- /dev/null +++ b/clang/test/CodeGenCXX/visibility.cpp @@ -0,0 +1,607 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fvisibility hidden -emit-llvm -o - | FileCheck %s -check-prefix=CHECK-HIDDEN + +#define HIDDEN __attribute__((visibility("hidden"))) +#define PROTECTED __attribute__((visibility("protected"))) +#define DEFAULT __attribute__((visibility("default"))) + +namespace test25 { + template<typename T> + struct X { + template<typename U> + struct definition { + }; + }; + + class DEFAULT A { }; + + X<int>::definition<A> a; + // CHECK: @_ZN6test251aE = global + // CHECK-HIDDEN: @_ZN6test251aE = hidden global +} + +namespace test28 { + class DEFAULT foo { + }; + foo myvec; + // CHECK: @_ZN6test285myvecE = global + // CHECK-HIDDEN: @_ZN6test285myvecE = hidden global +} + +// CHECK: @_ZN5Test425VariableInHiddenNamespaceE = hidden global i32 10 +// CHECK: @_ZN5Test71aE = hidden global +// CHECK: @_ZN5Test71bE = global +// CHECK: @test9_var = global +// CHECK-HIDDEN: @test9_var = global +// CHECK: @_ZN6Test121A6hiddenE = external hidden global +// CHECK: @_ZN6Test121A7visibleE = external global +// CHECK-HIDDEN: @_ZN6Test121A6hiddenE = external hidden global +// CHECK-HIDDEN: @_ZN6Test121A7visibleE = external global +// CHECK: @_ZN6Test131B1aE = hidden global +// CHECK: @_ZN6Test131C1aE = global +// CHECK-HIDDEN: @_ZN6Test131B1aE = hidden global +// CHECK-HIDDEN: @_ZN6Test131C1aE = global +// CHECK: @_ZN6Test143varE = external global +// CHECK-HIDDEN: @_ZN6Test143varE = external global +// CHECK: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8] +// CHECK-HIDDEN: @_ZN6Test154TempINS_1AEE5Inner6bufferE = external global [0 x i8] + +namespace test27 { + template<typename T> + class C { + class __attribute__((visibility("default"))) D { + void f(); + }; + }; + + template<> + class C<int>::D { + virtual void g(); + }; + + void C<int>::D::g() { + } + // CHECK: _ZTVN6test271CIiE1DE = unnamed_addr constant + // CHECK-HIDDEN: _ZTVN6test271CIiE1DE = unnamed_addr constant +} + +// CHECK: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr global +// CHECK: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr global i64 +// CHECK-HIDDEN: @_ZZN6Test193fooIiEEvvE1a = linkonce_odr hidden global +// CHECK-HIDDEN: @_ZGVZN6Test193fooIiEEvvE1a = linkonce_odr hidden global i64 +// CHECK-HIDDEN: @_ZTVN6Test161AIcEE = external unnamed_addr constant +// CHECK-HIDDEN: @_ZTTN6Test161AIcEE = external unnamed_addr constant +// CHECK: @_ZTVN5Test63fooE = linkonce_odr hidden unnamed_addr constant + +namespace Test1 { + // CHECK: define hidden void @_ZN5Test11fEv + void HIDDEN f() { } + +} + +namespace Test2 { + struct HIDDEN A { + void f(); + }; + + // A::f is a member function of a hidden class. + // CHECK: define hidden void @_ZN5Test21A1fEv + void A::f() { } +} + +namespace Test3 { + struct HIDDEN A { + struct B { + void f(); + }; + }; + + // B is a nested class where its parent class is hidden. + // CHECK: define hidden void @_ZN5Test31A1B1fEv + void A::B::f() { } +} + +namespace Test4 HIDDEN { + int VariableInHiddenNamespace = 10; + + // Test4::g is in a hidden namespace. + // CHECK: define hidden void @_ZN5Test41gEv + void g() { } + + struct DEFAULT A { + void f(); + }; + + // A has default visibility. + // CHECK: define void @_ZN5Test41A1fEv + void A::f() { } +} + +namespace Test5 { + + namespace NS HIDDEN { + // f is in NS which is hidden. + // CHECK: define hidden void @_ZN5Test52NS1fEv() + void f() { } + } + + namespace NS { + // g is in NS, but this NS decl is not hidden. + // CHECK: define void @_ZN5Test52NS1gEv + void g() { } + } +} + +// <rdar://problem/8091955> +namespace Test6 { + struct HIDDEN foo { + foo() { } + void bonk(); + virtual void bar() = 0; + + virtual void zonk() {} + }; + + struct barc : public foo { + barc(); + virtual void bar(); + }; + + barc::barc() {} +} + +namespace Test7 { + class HIDDEN A {}; + A a; // top of file + + template <A&> struct Aref { + static void foo() {} + }; + + class B : public A {}; + B b; // top of file + + // CHECK: define linkonce_odr hidden void @_ZN5Test74ArefILZNS_1aEEE3fooEv() + void test() { + Aref<a>::foo(); + } +} + +namespace Test8 { + void foo(); + void bar() {} + // CHECK-HIDDEN: define hidden void @_ZN5Test83barEv() + // CHECK-HIDDEN: declare void @_ZN5Test83fooEv() + + void test() { + foo(); + bar(); + } +} + +// PR8457 +namespace Test9 { + extern "C" { + struct A { int field; }; + void DEFAULT test9_fun(struct A *a) { } + struct A DEFAULT test9_var; // above + } + // CHECK: define void @test9_fun( + // CHECK-HIDDEN: define void @test9_fun( + + void test() { + A a = test9_var; + test9_fun(&a); + } +} + +// PR8478 +namespace Test10 { + struct A; + + class DEFAULT B { + void foo(A*); + }; + + // CHECK: define void @_ZN6Test101B3fooEPNS_1AE( + // CHECK-HIDDEN: define void @_ZN6Test101B3fooEPNS_1AE( + void B::foo(A*) {} +} + +// PR8492 +namespace Test11 { + struct A { + void foo() {} + void DEFAULT bar() {} + }; + + void test() { + A a; + a.foo(); + a.bar(); + } + + // CHECK: define linkonce_odr void @_ZN6Test111A3fooEv( + // CHECK: define linkonce_odr void @_ZN6Test111A3barEv( + // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6Test111A3fooEv( + // CHECK-HIDDEN: define linkonce_odr void @_ZN6Test111A3barEv( +} + +// Tested at top of file. +namespace Test12 { + struct A { + // This is hidden in all cases: the explicit attribute takes + // priority over -fvisibility on the parent. + static int hidden HIDDEN; + + // This is default in all cases because it's only a declaration. + static int visible; + }; + + void test() { + A::hidden = 0; + A::visible = 0; + } +} + +// Tested at top of file. +namespace Test13 { + struct HIDDEN A {}; + + // Should be hidden in all cases. + struct B { + static A a; + }; + A B::a; + + // Should be default in all cases. + struct DEFAULT C { + static A a; + }; + A C::a; +}; + +// Tested at top of file. +namespace Test14 { + // Neither the visibility of the type nor -fvisibility=hidden should + // apply to declarations. + extern struct A *var; + + struct A *test() { return var; } +} + +// rdar://problem/8613093 +namespace Test15 { + struct A {}; + template <class T> struct Temp { + struct Inner { + static char buffer[0]; + }; + }; + + char *test() { + return Temp<A>::Inner::buffer; + } +} + +namespace Test16 { + struct Base1 { virtual void foo(); }; + struct Base2 : virtual Base1 { virtual void foo(); }; + template <class T> struct A : virtual Base1, Base2 { + virtual void foo(); + }; + extern template struct A<char>; + + void test() { + A<char> a; + a.foo(); + } +} + +namespace Test17 { + struct HIDDEN A { + static void foo(); + static void DEFAULT bar(); + static void HIDDEN baz(); + + struct DEFAULT B { + static void foo(); + static void DEFAULT bar(); + static void HIDDEN baz(); + }; + }; + + void test() { + A::foo(); + A::bar(); + A::baz(); + A::B::foo(); + A::B::bar(); + A::B::baz(); + } + // CHECK: declare hidden void @_ZN6Test171A3fooEv() + // CHECK: declare void @_ZN6Test171A3barEv() + // CHECK: declare hidden void @_ZN6Test171A3bazEv() + // CHECK: declare void @_ZN6Test171A1B3fooEv() + // CHECK: declare void @_ZN6Test171A1B3barEv() + // CHECK: declare hidden void @_ZN6Test171A1B3bazEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test171A3fooEv() + // CHECK-HIDDEN: declare void @_ZN6Test171A3barEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test171A3bazEv() + // CHECK-HIDDEN: declare void @_ZN6Test171A1B3fooEv() + // CHECK-HIDDEN: declare void @_ZN6Test171A1B3barEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test171A1B3bazEv() +} + +namespace Test18 { + template <class T> struct HIDDEN A { + static void foo(); + static void DEFAULT bar(); + static void HIDDEN baz(); + + struct DEFAULT B { + static void foo(); + static void DEFAULT bar(); + static void HIDDEN baz(); + }; + }; + struct HIDDEN H; + + void test() { + A<int>::foo(); + A<int>::bar(); + A<int>::baz(); + A<int>::B::foo(); + A<int>::B::bar(); + A<int>::B::baz(); + A<H>::foo(); + A<H>::bar(); + A<H>::baz(); + A<H>::B::foo(); + A<H>::B::bar(); + A<H>::B::baz(); + } + // CHECK: declare hidden void @_ZN6Test181AIiE3fooEv() + // CHECK: declare void @_ZN6Test181AIiE3barEv() + // CHECK: declare hidden void @_ZN6Test181AIiE3bazEv() + // CHECK: declare void @_ZN6Test181AIiE1B3fooEv() + // CHECK: declare void @_ZN6Test181AIiE1B3barEv() + // CHECK: declare hidden void @_ZN6Test181AIiE1B3bazEv() + // CHECK: declare hidden void @_ZN6Test181AINS_1HEE3fooEv() + // CHECK: declare hidden void @_ZN6Test181AINS_1HEE3barEv() + // CHECK: declare hidden void @_ZN6Test181AINS_1HEE3bazEv() + // CHECK: declare hidden void @_ZN6Test181AINS_1HEE1B3fooEv() + // CHECK: declare hidden void @_ZN6Test181AINS_1HEE1B3barEv() + // CHECK: declare hidden void @_ZN6Test181AINS_1HEE1B3bazEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test181AIiE3fooEv() + // CHECK-HIDDEN: declare void @_ZN6Test181AIiE3barEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test181AIiE3bazEv() + // CHECK-HIDDEN: declare void @_ZN6Test181AIiE1B3fooEv() + // CHECK-HIDDEN: declare void @_ZN6Test181AIiE1B3barEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test181AIiE1B3bazEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE3fooEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE3barEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE3bazEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE1B3fooEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE1B3barEv() + // CHECK-HIDDEN: declare hidden void @_ZN6Test181AINS_1HEE1B3bazEv() +} + +namespace Test19 { + struct A { A(); ~A(); }; + + // Tested at top of file. + template <class T> void foo() { + static A a; + } + + void test() { + foo<int>(); + } +} + +// Various things with class template specializations. +namespace Test20 { + template <unsigned> struct HIDDEN A {}; + + // An explicit specialization inherits the explicit visibility of + // the template. + template <> struct A<0> { + static void test0(); + static void test1(); + }; + + // CHECK: define hidden void @_ZN6Test201AILj0EE5test0Ev() + void A<0>::test0() {} + + // CHECK: declare hidden void @_ZN6Test201AILj0EE5test1Ev() + void test1() { + A<0>::test1(); + } + + // ...unless that's explicitly overridden. + template <> struct DEFAULT A<1> { + static void test2(); + static void test3(); + }; + + // CHECK: define void @_ZN6Test201AILj1EE5test2Ev() + void A<1>::test2() {} + + // CHECK: declare void @_ZN6Test201AILj1EE5test3Ev() + void test3() { + A<1>::test3(); + } + + // <rdar://problem/8778497> + // But we should assume that an unknown specialization has the + // explicit visibility settings of the template. + template <class T> struct B { + static void test4() {} + static void test5(); + }; + + // CHECK: define linkonce_odr hidden void @_ZN6Test201BINS_1AILj2EEEE5test4Ev() + void test4() { + B<A<2> >::test4(); + } + + // CHECK: declare hidden void @_ZN6Test201BINS_1AILj2EEEE5test5Ev() + void test5() { + B<A<2> >::test5(); + } +} + +// PR9371 +namespace test21 { + enum En { en }; + template<En> struct A { + __attribute__((visibility("default"))) void foo() {} + }; + + // CHECK: define weak_odr void @_ZN6test211AILNS_2EnE0EE3fooEv( + template void A<en>::foo(); +} + +// rdar://problem/9616154 +// Visibility on explicit specializations should take precedence. +namespace test22 { + class A1 {}; + class A2 {}; + + template <class T> struct B {}; + template <> struct DEFAULT B<A1> { + static void foo(); + static void bar() {} + }; + template <> struct B<A2> { + static void foo(); + static void bar() {} + }; + + void test() { + B<A1>::foo(); + B<A1>::bar(); + B<A2>::foo(); + B<A2>::bar(); + } + // CHECK: declare void @_ZN6test221BINS_2A1EE3fooEv() + // CHECK: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv() + // CHECK: declare void @_ZN6test221BINS_2A2EE3fooEv() + // CHECK: define linkonce_odr void @_ZN6test221BINS_2A2EE3barEv() + // CHECK-HIDDEN: declare void @_ZN6test221BINS_2A1EE3fooEv() + // CHECK-HIDDEN: define linkonce_odr void @_ZN6test221BINS_2A1EE3barEv() + // CHECK-HIDDEN: declare void @_ZN6test221BINS_2A2EE3fooEv() + // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test221BINS_2A2EE3barEv() +} + +namespace PR10113 { + namespace foo DEFAULT { + template<typename T> + class bar { + void zed() {} + }; + } + template class foo::bar<char>; + // CHECK: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv + // CHECK-HIDDEN: define weak_odr void @_ZN7PR101133foo3barIcE3zedEv + + struct zed { + }; + template class foo::bar<zed>; + // CHECK: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv + // CHECK-HIDDEN: define weak_odr void @_ZN7PR101133foo3barINS_3zedEE3zedEv +} + +namespace PR11690 { + template<class T> struct Class { + void size() const { + } + }; + template class DEFAULT Class<char>; + // CHECK: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv + // CHECK-HIDDEN: define weak_odr void @_ZNK7PR116905ClassIcE4sizeEv + + template<class T> void Method() {} + template DEFAULT void Method<char>(); + // CHECK: define weak_odr void @_ZN7PR116906MethodIcEEvv + // CHECK-HIDDEN: define weak_odr void @_ZN7PR116906MethodIcEEvv +} + +namespace PR11690_2 { + namespace foo DEFAULT { + class bar; + template<typename T1, typename T2 = bar> + class zed { + void bar() { + } + }; + } + struct baz { + }; + template class foo::zed<baz>; + // CHECK: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv + // CHECK-HIDDEN: define weak_odr void @_ZN9PR11690_23foo3zedINS_3bazENS0_3barEE3barEv +} + +namespace test23 { + // Having a template argument that is explicitly visible should not make + // the template instantiation visible. + template <typename T> + struct X { + static void f() { + } + }; + + class DEFAULT A; + + void g() { + X<A> y; + y.f(); + } + // CHECK: define linkonce_odr void @_ZN6test231XINS_1AEE1fEv + // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test231XINS_1AEE1fEv +} + +namespace PR12001 { + template <typename P1> + void Bind(const P1& p1) { + } + + class DEFAULT Version { }; + + void f() { + Bind(Version()); + } + // CHECK: define linkonce_odr void @_ZN7PR120014BindINS_7VersionEEEvRKT_ + // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN7PR120014BindINS_7VersionEEEvRKT_ +} + +namespace test24 { + class DEFAULT A { }; + + struct S { + template <typename T> + void mem() {} + }; + + void test() { + S s; + s.mem<A>(); + } + // CHECK: define linkonce_odr void @_ZN6test241S3memINS_1AEEEvv + // CHECK-HIDDEN: define linkonce_odr hidden void @_ZN6test241S3memINS_1AEEEvv +} + +namespace test26 { + template<typename T> + class C { + __attribute__((visibility("default"))) void f(); + }; + + template<> + void C<int>::f() { } + + // CHECK: define void @_ZN6test261CIiE1fEv + // CHECK-HIDDEN: define void @_ZN6test261CIiE1fEv +} diff --git a/clang/test/CodeGenCXX/vla.cpp b/clang/test/CodeGenCXX/vla.cpp new file mode 100644 index 0000000..b523c76 --- /dev/null +++ b/clang/test/CodeGenCXX/vla.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin %s -emit-llvm -o - | FileCheck %s + +template<typename T> +struct S { + static int n; +}; +template<typename T> int S<T>::n = 5; + +int f() { + // Make sure that the reference here is enough to trigger the instantiation of + // the static data member. + // CHECK: @_ZN1SIiE1nE = weak_odr global i32 5 + int a[S<int>::n]; + return sizeof a; +} + +// rdar://problem/9506377 +void test0(void *array, int n) { + // CHECK: define void @_Z5test0Pvi( + // CHECK: [[ARRAY:%.*]] = alloca i8*, align 8 + // CHECK-NEXT: [[N:%.*]] = alloca i32, align 4 + // CHECK-NEXT: [[REF:%.*]] = alloca i16*, align 8 + // CHECK-NEXT: [[S:%.*]] = alloca i16, align 2 + // CHECK-NEXT: store i8* + // CHECK-NEXT: store i32 + + // Capture the bounds. + // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4 + // CHECK-NEXT: [[DIM0:%.*]] = zext i32 [[T0]] to i64 + // CHECK-NEXT: [[T0:%.*]] = load i32* [[N]], align 4 + // CHECK-NEXT: [[T1:%.*]] = add nsw i32 [[T0]], 1 + // CHECK-NEXT: [[DIM1:%.*]] = zext i32 [[T1]] to i64 + typedef short array_t[n][n+1]; + + // CHECK-NEXT: [[T0:%.*]] = load i8** [[ARRAY]], align 8 + // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i16* + // CHECK-NEXT: store i16* [[T1]], i16** [[REF]], align 8 + array_t &ref = *(array_t*) array; + + // CHECK-NEXT: [[T0:%.*]] = load i16** [[REF]] + // CHECK-NEXT: [[T1:%.*]] = mul nsw i64 1, [[DIM1]] + // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i16* [[T0]], i64 [[T1]] + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i16* [[T2]], i64 2 + // CHECK-NEXT: store i16 3, i16* [[T3]] + ref[1][2] = 3; + + // CHECK-NEXT: [[T0:%.*]] = load i16** [[REF]] + // CHECK-NEXT: [[T1:%.*]] = mul nsw i64 4, [[DIM1]] + // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i16* [[T0]], i64 [[T1]] + // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i16* [[T2]], i64 5 + // CHECK-NEXT: [[T4:%.*]] = load i16* [[T3]] + // CHECK-NEXT: store i16 [[T4]], i16* [[S]], align 2 + short s = ref[4][5]; + + // CHECK-NEXT: ret void +} diff --git a/clang/test/CodeGenCXX/volatile-1.cpp b/clang/test/CodeGenCXX/volatile-1.cpp new file mode 100644 index 0000000..71ff1ed --- /dev/null +++ b/clang/test/CodeGenCXX/volatile-1.cpp @@ -0,0 +1,352 @@ +// RUN: %clang_cc1 -Wno-unused-value -emit-llvm %s -o - | FileCheck %s + +// CHECK: @i = global [[INT:i[0-9]+]] 0 +volatile int i, j, k; +volatile int ar[5]; +volatile char c; +// CHECK: @ci = global [[CINT:.*]] zeroinitializer +volatile _Complex int ci; +volatile struct S { +#ifdef __cplusplus + void operator =(volatile struct S&o) volatile; +#endif + int i; +} a, b; + +//void operator =(volatile struct S&o1, volatile struct S&o2) volatile; +int printf(const char *, ...); + + +// CHECK: define void @{{.*}}test +void test() { + + asm("nop"); // CHECK: call void asm + + // should not load + i; + + (float)(ci); + // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) + // CHECK-NEXT: load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // CHECK-NEXT: sitofp [[INT]] + + // These are not uses in C++: + // [expr.static.cast]p6: + // The lvalue-to-rvalue . . . conversions are not applied to the expression. + (void)ci; + (void)a; + + (void)(ci=ci); + // CHECK-NEXT: [[R:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) + // CHECK-NEXT: [[I:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) + // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + + (void)(i=j); + // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]]* @j + // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* @i + + ci+=ci; + // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) + // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) + // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // Not sure why they're ordered this way. + // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]] + // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]] + // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) + // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + + // Note that C++ requires an extra load volatile over C from the LHS of the '+'. + (ci += ci) + ci; + // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) + // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) + // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // CHECK-NEXT: [[R:%.*]] = add [[INT]] [[R2]], [[R1]] + // CHECK-NEXT: [[I:%.*]] = add [[INT]] [[I2]], [[I1]] + // CHECK-NEXT: store volatile [[INT]] [[R]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) + // CHECK-NEXT: store volatile [[INT]] [[I]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // CHECK-NEXT: [[R1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) + // CHECK-NEXT: [[I1:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // CHECK-NEXT: [[R2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 0) + // CHECK-NEXT: [[I2:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // These additions can be elided. + // CHECK-NEXT: add [[INT]] [[R1]], [[R2]] + // CHECK-NEXT: add [[INT]] [[I1]], [[I2]] + + asm("nop"); // CHECK-NEXT: call void asm + + // Extra load volatile in C++. + (i += j) + k; + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: add nsw [[INT]] + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: add nsw [[INT]] + + asm("nop"); // CHECK-NEXT: call void asm + + // Extra load volatile in C++. + (i += j) + 1; + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: add nsw [[INT]] + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: add nsw [[INT]] + + asm("nop"); // CHECK-NEXT: call void asm + + ci+ci; + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: add [[INT]] + // CHECK-NEXT: add [[INT]] + + __real i; + + +ci; + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + + asm("nop"); // CHECK-NEXT: call void asm + + (void)(i=i); + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + + (float)(i=i); + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: sitofp + + (void)i; + + i=i; + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + + // Extra load volatile in C++. + i=i=i; + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + + (void)__builtin_choose_expr(0, i=i, j=j); + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + + k ? (i=i) : (j=j); + // CHECK-NEXT: load volatile + // CHECK-NEXT: icmp + // CHECK-NEXT: br i1 + // CHECK: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: br label + // CHECK: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: br label + // CHECK: phi + + (void)(i,(i=i)); + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + + i=i,k; + // CHECK-NEXT: load volatile [[INT]]* @i + // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @i + + (i=j,k=j); + // CHECK-NEXT: load volatile [[INT]]* @j + // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @i + // CHECK-NEXT: load volatile [[INT]]* @j + // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @k + + (i=j,k); + // CHECK-NEXT: load volatile [[INT]]* @j + // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @i + + (i,j); + + // Extra load in C++. + i=c=k; + // CHECK-NEXT: load volatile + // CHECK-NEXT: trunc + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: sext + // CHECK-NEXT: store volatile + + i+=k; + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: add nsw [[INT]] + // CHECK-NEXT: store volatile + + ci; + + asm("nop"); // CHECK-NEXT: call void asm + + (int)ci; + // CHECK-NEXT: load volatile {{.*}} @ci, i32 0, i32 0 + // CHECK-NEXT: load volatile {{.*}} @ci, i32 0, i32 1 + + (bool)ci; + // CHECK-NEXT: load volatile {{.*}} @ci, i32 0, i32 0 + // CHECK-NEXT: load volatile {{.*}} @ci, i32 0, i32 1 + // CHECK-NEXT: icmp ne + // CHECK-NEXT: icmp ne + // CHECK-NEXT: or i1 + + ci=ci; + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: store volatile + + asm("nop"); // CHECK-NEXT: call void asm + + // Extra load in C++. + ci=ci=ci; + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: store volatile + + __imag ci = __imag ci = __imag ci; + // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // CHECK-NEXT: [[T:%.*]] = load volatile [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + // CHECK-NEXT: store volatile [[INT]] [[T]], [[INT]]* getelementptr inbounds ([[CINT]]* @ci, i32 0, i32 1) + + __real (i = j); + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + + __imag i; + + // ============================================================ + // FIXME: Test cases we get wrong. + + // A use. We load all of a into a copy of a, then load i. gcc forgets to do + // the assignment. + // (a = a).i; + + // ============================================================ + // Test cases where we intentionally differ from gcc, due to suspected bugs in + // gcc. + + // Not a use. gcc forgets to do the assignment. + // CHECK-NEXT: call + ((a=a),a); + + // Not a use. gcc gets this wrong, it doesn't emit the copy! + // CHECK-NEXT: call + (void)(a=a); + + // Not a use. gcc got this wrong in 4.2 and omitted the side effects + // entirely, but it is fixed in 4.4.0. + __imag (i = j); + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + + // C++ does an extra load here. Note that we have to do full loads. + (float)(ci=ci); + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: sitofp + + // Not a use, bug? gcc treats this as not a use, that's probably a + // bug due to tree folding ignoring volatile. + (int)(ci=ci); + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + + // A use. + (float)(i=i); + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: sitofp + + // A use. gcc treats this as not a use, that's probably a bug due to tree + // folding ignoring volatile. + (int)(i=i); + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + + // A use. + -(i=j); + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: sub + + // A use. gcc treats this a not a use, that's probably a bug due to tree + // folding ignoring volatile. + +(i=k); + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + + // A use. gcc treats this a not a use, that's probably a bug due to tree + // folding ignoring volatile. + __real (ci=ci); + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: store volatile + + // A use. + i + 0; + // CHECK-NEXT: load volatile + // CHECK-NEXT: add + + // A use. + (i=j) + i; + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: add + + // A use. gcc treats this as not a use, that's probably a bug due to tree + // folding ignoring volatile. + (i=j) + 0; + // CHECK-NEXT: load volatile + // CHECK-NEXT: store volatile + // CHECK-NEXT: load volatile + // CHECK-NEXT: add + + (i,j)=k; + // CHECK-NEXT: load volatile [[INT]]* @k + // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @j + + (j=k,i)=i; + // CHECK-NEXT: load volatile [[INT]]* @i + // CHECK-NEXT: load volatile [[INT]]* @k + // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @j + // CHECK-NEXT: store volatile {{.*}}, [[INT]]* @i + + // CHECK-NEXT: ret void +} diff --git a/clang/test/CodeGenCXX/volatile.cpp b/clang/test/CodeGenCXX/volatile.cpp new file mode 100644 index 0000000..6ebb2f1 --- /dev/null +++ b/clang/test/CodeGenCXX/volatile.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// Check that IR gen doesn't try to do an lvalue-to-rvalue conversion +// on a volatile reference result. rdar://problem/8338198 +namespace test0 { + struct A { + A(const A& t); + A& operator=(const A& t); + volatile A& operator=(const volatile A& t) volatile; + }; + + volatile A *array; + + // CHECK: define void @_ZN5test04testENS_1AE( + void test(A t) { + // CHECK: [[ARR:%.*]] = load [[A:%.*]]** @_ZN5test05arrayE, align 8 + // CHECK-NEXT: [[IDX:%.*]] = getelementptr inbounds [[A]]* [[ARR]], i64 0 + // CHECK-NEXT: [[TMP:%.*]] = call [[A]]* @_ZNV5test01AaSERVKS0_([[A]]* [[IDX]], [[A]]* [[T:%.*]]) + // CHECK-NEXT: ret void + array[0] = t; + } +} + +namespace test1 { + volatile int *x; + + // CHECK: define void @_ZN5test14testEv() + void test() { + // CHECK: [[TMP:%.*]] = load i32** @_ZN5test11xE, align 8 + // CHECK-NEXT: ret void + *x; + } +} diff --git a/clang/test/CodeGenCXX/vtable-available-externally.cpp b/clang/test/CodeGenCXX/vtable-available-externally.cpp new file mode 100644 index 0000000..23baac9 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-available-externally.cpp @@ -0,0 +1,171 @@ +// RUN: %clang_cc1 %s -I%S -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o %t +// RUN: FileCheck --check-prefix=CHECK-TEST1 %s < %t +// RUN: FileCheck --check-prefix=CHECK-TEST2 %s < %t +// RUN: FileCheck --check-prefix=CHECK-TEST5 %s < %t +// RUN: FileCheck --check-prefix=CHECK-TEST7 %s < %t + +#include <typeinfo> + +// Test1::A's key function (f) is not defined in this translation unit, but in +// order to devirtualize calls, we emit the class related data with +// available_externally linkage. + +// CHECK-TEST1: @_ZTVN5Test11AE = available_externally +// CHECK-TEST1: @_ZTSN5Test11AE = available_externally +// CHECK-TEST1: @_ZTIN5Test11AE = available_externally +namespace Test1 { + +struct A { + A(); + virtual void f(); + virtual ~A() { } +}; + +A::A() { } + +void f(A* a) { + a->f(); +}; + +// CHECK: define void @_ZN5Test11gEv +// CHECK: call void @_ZN5Test11A1fEv +void g() { + A a; + f(&a); +} + +} + +// Test2::A's key function (f) is defined in this translation unit, but when +// we're doing codegen for the typeid(A) call, we don't know that yet. +// This tests mainly that the typeinfo and typename constants have their linkage +// updated correctly. + +// CHECK-TEST2: @_ZTSN5Test21AE = constant +// CHECK-TEST2: @_ZTIN5Test21AE = unnamed_addr constant +// CHECK-TEST2: @_ZTVN5Test21AE = unnamed_addr constant +namespace Test2 { + struct A { + virtual void f(); + }; + + const std::type_info &g() { + return typeid(A); + }; + + void A::f() { } +} + +// Test that we don't assert on this test. +namespace Test3 { + +struct A { + virtual void f(); + virtual ~A() { } +}; + +struct B : A { + B(); + virtual void f(); +}; + +B::B() { } + +void g(A* a) { + a->f(); +}; + +} + +// PR9114, test that we don't try to instantiate RefPtr<Node>. +namespace Test4 { + +template <class T> struct RefPtr { + T* p; + ~RefPtr() { + p->deref(); + } +}; + +struct A { + virtual ~A(); +}; + +struct Node; + +struct B : A { + virtual void deref(); + RefPtr<Node> m; +}; + +void f() { + RefPtr<B> b; +} + +} + +// PR9130, test that we emit a definition of A::f. +// CHECK-TEST5: define linkonce_odr void @_ZN5Test51A1fEv +namespace Test5 { + +struct A { + virtual void f() { } +}; + +struct B : A { + virtual ~B(); +}; + +B::~B() { } + +} + +// Check that we don't assert on this test. +namespace Test6 { + +struct A { + virtual ~A(); + int a; +}; + +struct B { + virtual ~B(); + int b; +}; + +struct C : A, B { + C(); +}; + +struct D : C { + virtual void f(); + D(); +}; + +D::D() { } + +} + +namespace Test7 { + +struct c1 {}; +struct c10 : c1{ + virtual void foo (); +}; +struct c11 : c10, c1{ + virtual void f6 (); +}; +struct c28 : virtual c11{ + void f6 (); +}; + +// CHECK-TEST7: define void @_ZN5Test79check_c28Ev +// CHECK-TEST7: call void @_ZN5Test73c282f6Ev +// CHECK-TEST7: ret void +void check_c28 () { + c28 obj; + c11 *ptr = &obj; + ptr->f6 (); +} + +} diff --git a/clang/test/CodeGenCXX/vtable-cast-crash.cpp b/clang/test/CodeGenCXX/vtable-cast-crash.cpp new file mode 100644 index 0000000..cc419fd --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-cast-crash.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -emit-llvm-only %s +struct A +{ +A(); +virtual ~A(); +}; + +struct B: A +{ + B(); + ~B(); +}; + +B::B() +{ +} + +B::~B() +{ +} + diff --git a/clang/test/CodeGenCXX/vtable-debug-info.cpp b/clang/test/CodeGenCXX/vtable-debug-info.cpp new file mode 100644 index 0000000..9294d20 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-debug-info.cpp @@ -0,0 +1,319 @@ +// RUN: %clang -c -g %s -o /dev/null +// Radar 8730409 +// XFAIL: win32 + +// FIXME: This test crashes on *-pc-win32 +// for lack of debugging support on -integrated-as (MCCOFF). +#ifdef _MSC_VER + +#error this test must xfail + +#else +class foo { +public: +#define x(a) virtual void v ## a (void) +x(1); +x(2); +x(3); +x(4); +x(5); +x(6); +x(7); +x(8); +x(9); +x(10); +x(11); +x(12); +x(13); +x(14); +x(15); +x(16); +x(17); +x(18); +x(19); +x(20); +x(21); +x(22); +x(23); +x(24); +x(25); +x(26); +x(27); +x(28); +x(29); +x(30); +x(31); +x(32); +x(33); +x(34); +x(35); +x(36); +x(37); +x(38); +x(39); +x(40); +x(41); +x(42); +x(43); +x(44); +x(45); +x(46); +x(47); +x(48); +x(49); +x(50); +x(51); +x(52); +x(53); +x(54); +x(55); +x(56); +x(57); +x(58); +x(59); +x(60); +x(61); +x(62); +x(63); +x(64); +x(65); +x(66); +x(67); +x(68); +x(69); +x(70); +x(71); +x(72); +x(73); +x(74); +x(75); +x(76); +x(77); +x(78); +x(79); +x(80); +x(81); +x(82); +x(83); +x(84); +x(85); +x(86); +x(87); +x(88); +x(89); +x(90); +x(91); +x(92); +x(93); +x(94); +x(95); +x(96); +x(97); +x(98); +x(99); +x(100); +x(101); +x(102); +x(103); +x(104); +x(105); +x(106); +x(107); +x(108); +x(109); +x(110); +x(111); +x(112); +x(113); +x(114); +x(115); +x(116); +x(117); +x(118); +x(119); +x(120); +x(121); +x(122); +x(123); +x(124); +x(125); +x(126); +x(127); +x(128); +x(129); +x(130); +x(131); +x(132); +x(133); +x(134); +x(135); +x(136); +x(137); +x(138); +x(139); +x(140); +x(141); +x(142); +x(143); +x(144); +x(145); +x(146); +x(147); +x(148); +x(149); +x(150); +x(151); +x(152); +x(153); +x(154); +x(155); +x(156); +x(157); +x(158); +x(159); +x(160); +x(161); +x(162); +x(163); +x(164); +x(165); +x(166); +x(167); +x(168); +x(169); +x(170); +x(171); +x(172); +x(173); +x(174); +x(175); +x(176); +x(177); +x(178); +x(179); +x(180); +x(181); +x(182); +x(183); +x(184); +x(185); +x(186); +x(187); +x(188); +x(189); +x(190); +x(191); +x(192); +x(193); +x(194); +x(195); +x(196); +x(197); +x(198); +x(199); +x(200); +x(201); +x(202); +x(203); +x(204); +x(205); +x(206); +x(207); +x(208); +x(209); +x(210); +x(211); +x(212); +x(213); +x(214); +x(215); +x(216); +x(217); +x(218); +x(219); +x(220); +x(221); +x(222); +x(223); +x(224); +x(225); +x(226); +x(227); +x(228); +x(229); +x(230); +x(231); +x(232); +x(233); +x(234); +x(235); +x(236); +x(237); +x(238); +x(239); +x(240); +x(241); +x(242); +x(243); +x(244); +x(245); +x(246); +x(247); +x(248); +x(249); +x(250); +x(251); +x(252); +x(253); +x(254); +x(255); +x(256); +x(257); +x(258); +x(259); +x(260); +x(261); +x(262); +x(263); +x(264); +x(265); +x(266); +x(267); +x(268); +x(269); +x(270); +x(271); +x(272); +x(273); +x(274); +x(275); +x(276); +x(277); +x(278); +x(279); +x(280); +x(281); +x(282); +x(283); +x(284); +x(285); +x(286); +x(287); +x(288); +x(289); +x(290); +x(291); +x(292); +x(293); +x(294); +x(295); +x(296); +x(297); +x(298); +x(299); +x(300); +}; + +foo b; + +#endif diff --git a/clang/test/CodeGenCXX/vtable-key-function.cpp b/clang/test/CodeGenCXX/vtable-key-function.cpp new file mode 100644 index 0000000..bf2e679 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-key-function.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s +// PR5697 +namespace PR5697 { +struct A { + virtual void f() { } + A(); + A(int); +}; + +// A does not have a key function, so the first constructor we emit should +// cause the vtable to be defined (without assertions.) +// CHECK: @_ZTVN6PR56971AE = linkonce_odr unnamed_addr constant +A::A() { } +A::A(int) { } +} + +// Make sure that we don't assert when building the vtable for a class +// template specialization or explicit instantiation with a key +// function. +template<typename T> +struct Base { + virtual ~Base(); +}; + +template<typename T> +struct Derived : public Base<T> { }; + +template<> +struct Derived<char> : public Base<char> { + virtual void anchor(); +}; + +void Derived<char>::anchor() { } diff --git a/clang/test/CodeGenCXX/vtable-layout-abi-examples.cpp b/clang/test/CodeGenCXX/vtable-layout-abi-examples.cpp new file mode 100644 index 0000000..8f084a9 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-layout-abi-examples.cpp @@ -0,0 +1,322 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts > %t 2>&1 +// RUN: FileCheck --check-prefix=CHECK-1 %s < %t +// RUN: FileCheck --check-prefix=CHECK-2 %s < %t +// RUN: FileCheck --check-prefix=CHECK-3 %s < %t +// RUN: FileCheck --check-prefix=CHECK-4 %s < %t +// RUN: FileCheck --check-prefix=CHECK-5 %s < %t +// RUN: FileCheck --check-prefix=CHECK-6 %s < %t +// RUN: FileCheck --check-prefix=CHECK-7 %s < %t +// RUN: FileCheck --check-prefix=CHECK-8 %s < %t +// RUN: FileCheck --check-prefix=CHECK-9 %s < %t +// RUN: FileCheck --check-prefix=CHECK-10 %s < %t +// RUN: FileCheck --check-prefix=CHECK-11 %s < %t + +/// Examples from the Itanium C++ ABI specification. +/// http://www.codesourcery.com/public/cxx-abi/ + +namespace Test1 { + +// This is from http://www.codesourcery.com/public/cxx-abi/cxx-vtable-ex.html + +// CHECK-1: Vtable for 'Test1::A' (5 entries). +// CHECK-1-NEXT: 0 | offset_to_top (0) +// CHECK-1-NEXT: 1 | Test1::A RTTI +// CHECK-1-NEXT: -- (Test1::A, 0) vtable address -- +// CHECK-1-NEXT: 2 | void Test1::A::f() +// CHECK-1-NEXT: 3 | void Test1::A::g() +// CHECK-1-NEXT: 4 | void Test1::A::h() +struct A { + virtual void f (); + virtual void g (); + virtual void h (); + int ia; +}; +void A::f() {} + +// CHECK-2: Vtable for 'Test1::B' (13 entries). +// CHECK-2-NEXT: 0 | vbase_offset (16) +// CHECK-2-NEXT: 1 | offset_to_top (0) +// CHECK-2-NEXT: 2 | Test1::B RTTI +// CHECK-2-NEXT: -- (Test1::B, 0) vtable address -- +// CHECK-2-NEXT: 3 | void Test1::B::f() +// CHECK-2-NEXT: 4 | void Test1::B::h() +// CHECK-2-NEXT: 5 | vcall_offset (-16) +// CHECK-2-NEXT: 6 | vcall_offset (0) +// CHECK-2-NEXT: 7 | vcall_offset (-16) +// CHECK-2-NEXT: 8 | offset_to_top (-16) +// CHECK-2-NEXT: 9 | Test1::B RTTI +// CHECK-2-NEXT: -- (Test1::A, 16) vtable address -- +// CHECK-2-NEXT: 10 | void Test1::B::f() +// CHECK-2-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-2-NEXT: 11 | void Test1::A::g() +// CHECK-2-NEXT: 12 | void Test1::B::h() +// CHECK-2-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset] +struct B: public virtual A { + void f (); + void h (); + int ib; +}; +void B::f() {} + +// CHECK-3: Vtable for 'Test1::C' (13 entries). +// CHECK-3-NEXT: 0 | vbase_offset (16) +// CHECK-3-NEXT: 1 | offset_to_top (0) +// CHECK-3-NEXT: 2 | Test1::C RTTI +// CHECK-3-NEXT: -- (Test1::C, 0) vtable address -- +// CHECK-3-NEXT: 3 | void Test1::C::g() +// CHECK-3-NEXT: 4 | void Test1::C::h() +// CHECK-3-NEXT: 5 | vcall_offset (-16) +// CHECK-3-NEXT: 6 | vcall_offset (-16) +// CHECK-3-NEXT: 7 | vcall_offset (0) +// CHECK-3-NEXT: 8 | offset_to_top (-16) +// CHECK-3-NEXT: 9 | Test1::C RTTI +// CHECK-3-NEXT: -- (Test1::A, 16) vtable address -- +// CHECK-3-NEXT: 10 | void Test1::A::f() +// CHECK-3-NEXT: 11 | void Test1::C::g() +// CHECK-3-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-3-NEXT: 12 | void Test1::C::h() +// CHECK-3-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset] +struct C: public virtual A { + void g (); + void h (); + int ic; +}; +void C::g() {} + +// CHECK-4: Vtable for 'Test1::D' (18 entries). +// CHECK-4-NEXT: 0 | vbase_offset (32) +// CHECK-4-NEXT: 1 | offset_to_top (0) +// CHECK-4-NEXT: 2 | Test1::D RTTI +// CHECK-4-NEXT: -- (Test1::B, 0) vtable address -- +// CHECK-4-NEXT: -- (Test1::D, 0) vtable address -- +// CHECK-4-NEXT: 3 | void Test1::B::f() +// CHECK-4-NEXT: 4 | void Test1::D::h() +// CHECK-4-NEXT: 5 | vbase_offset (16) +// CHECK-4-NEXT: 6 | offset_to_top (-16) +// CHECK-4-NEXT: 7 | Test1::D RTTI +// CHECK-4-NEXT: -- (Test1::C, 16) vtable address -- +// CHECK-4-NEXT: 8 | void Test1::C::g() +// CHECK-4-NEXT: 9 | void Test1::D::h() +// CHECK-4-NEXT: [this adjustment: -16 non-virtual] +// CHECK-4-NEXT: 10 | vcall_offset (-32) +// CHECK-4-NEXT: 11 | vcall_offset (-16) +// CHECK-4-NEXT: 12 | vcall_offset (-32) +// CHECK-4-NEXT: 13 | offset_to_top (-32) +// CHECK-4-NEXT: 14 | Test1::D RTTI +// CHECK-4-NEXT: -- (Test1::A, 32) vtable address -- +// CHECK-4-NEXT: 15 | void Test1::B::f() +// CHECK-4-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-4-NEXT: 16 | void Test1::C::g() +// CHECK-4-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-4-NEXT: 17 | void Test1::D::h() +// CHECK-4-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset] +struct D: public B, public C { + void h (); + int id; +}; +void D::h() { } + +struct X { + int ix; + virtual void x(); +}; + +// CHECK-5: Vtable for 'Test1::E' (24 entries). +// CHECK-5-NEXT: 0 | vbase_offset (56) +// CHECK-5-NEXT: 1 | offset_to_top (0) +// CHECK-5-NEXT: 2 | Test1::E RTTI +// CHECK-5-NEXT: -- (Test1::E, 0) vtable address -- +// CHECK-5-NEXT: -- (Test1::X, 0) vtable address -- +// CHECK-5-NEXT: 3 | void Test1::X::x() +// CHECK-5-NEXT: 4 | void Test1::E::f() +// CHECK-5-NEXT: 5 | void Test1::E::h() +// CHECK-5-NEXT: 6 | vbase_offset (40) +// CHECK-5-NEXT: 7 | offset_to_top (-16) +// CHECK-5-NEXT: 8 | Test1::E RTTI +// CHECK-5-NEXT: -- (Test1::B, 16) vtable address -- +// CHECK-5-NEXT: -- (Test1::D, 16) vtable address -- +// CHECK-5-NEXT: 9 | void Test1::E::f() +// CHECK-5-NEXT: [this adjustment: -16 non-virtual] +// CHECK-5-NEXT: 10 | void Test1::E::h() +// CHECK-5-NEXT: [this adjustment: -16 non-virtual] +// CHECK-5-NEXT: 11 | vbase_offset (24) +// CHECK-5-NEXT: 12 | offset_to_top (-32) +// CHECK-5-NEXT: 13 | Test1::E RTTI +// CHECK-5-NEXT: -- (Test1::C, 32) vtable address -- +// CHECK-5-NEXT: 14 | void Test1::C::g() +// CHECK-5-NEXT: 15 | void Test1::E::h() +// CHECK-5-NEXT: [this adjustment: -32 non-virtual] +// CHECK-5-NEXT: 16 | vcall_offset (-56) +// CHECK-5-NEXT: 17 | vcall_offset (-24) +// CHECK-5-NEXT: 18 | vcall_offset (-56) +// CHECK-5-NEXT: 19 | offset_to_top (-56) +// CHECK-5-NEXT: 20 | Test1::E RTTI +// CHECK-5-NEXT: -- (Test1::A, 56) vtable address -- +// CHECK-5-NEXT: 21 | void Test1::E::f() +// CHECK-5-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-5-NEXT: 22 | void Test1::C::g() +// CHECK-5-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-5-NEXT: 23 | void Test1::E::h() +// CHECK-5-NEXT: [this adjustment: 0 non-virtual, -40 vcall offset offset] +struct E : X, D { + int ie; + void f(); + void h (); +}; +void E::f() { } + +} + +namespace Test2 { + +// From http://www.codesourcery.com/public/cxx-abi/abi.html#class-types. + +struct A { virtual void f(); }; +struct B : virtual public A { int i; }; +struct C : virtual public A { int j; }; + +// CHECK-6: Vtable for 'Test2::D' (11 entries). +// CHECK-6-NEXT: 0 | vbase_offset (0) +// CHECK-6-NEXT: 1 | vcall_offset (0) +// CHECK-6-NEXT: 2 | offset_to_top (0) +// CHECK-6-NEXT: 3 | Test2::D RTTI +// CHECK-6-NEXT: -- (Test2::A, 0) vtable address -- +// CHECK-6-NEXT: -- (Test2::B, 0) vtable address -- +// CHECK-6-NEXT: -- (Test2::D, 0) vtable address -- +// CHECK-6-NEXT: 4 | void Test2::A::f() +// CHECK-6-NEXT: 5 | void Test2::D::d() +// CHECK-6-NEXT: 6 | vbase_offset (-16) +// CHECK-6-NEXT: 7 | vcall_offset (-16) +// CHECK-6-NEXT: 8 | offset_to_top (-16) +// CHECK-6-NEXT: 9 | Test2::D RTTI +// CHECK-6-NEXT: -- (Test2::C, 16) vtable address -- +// CHECK-6-NEXT: 10 | [unused] void Test2::A::f() +struct D : public B, public C { + virtual void d(); +}; +void D::d() { } + +} + +namespace Test3 { + +// From http://www.codesourcery.com/public/cxx-abi/abi-examples.html#vtable-ctor + +struct V1 { + int v1; + virtual void f(); +}; + +struct V2 : virtual V1 { + int v2; + virtual void f(); +}; + +// CHECK-7: Vtable for 'Test3::C' (14 entries). +// CHECK-7-NEXT: 0 | vbase_offset (32) +// CHECK-7-NEXT: 1 | vbase_offset (16) +// CHECK-7-NEXT: 2 | offset_to_top (0) +// CHECK-7-NEXT: 3 | Test3::C RTTI +// CHECK-7-NEXT: -- (Test3::C, 0) vtable address -- +// CHECK-7-NEXT: 4 | void Test3::C::f() +// CHECK-7-NEXT: 5 | vcall_offset (-16) +// CHECK-7-NEXT: 6 | offset_to_top (-16) +// CHECK-7-NEXT: 7 | Test3::C RTTI +// CHECK-7-NEXT: -- (Test3::V1, 16) vtable address -- +// CHECK-7-NEXT: 8 | void Test3::C::f() +// CHECK-7-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-7-NEXT: 9 | vcall_offset (-32) +// CHECK-7-NEXT: 10 | vbase_offset (-16) +// CHECK-7-NEXT: 11 | offset_to_top (-32) +// CHECK-7-NEXT: 12 | Test3::C RTTI +// CHECK-7-NEXT: -- (Test3::V2, 32) vtable address -- +// CHECK-7-NEXT: 13 | void Test3::C::f() +// CHECK-7-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] + +// CHECK-8: Construction vtable for ('Test3::V2', 32) in 'Test3::C' (9 entries). +// CHECK-8-NEXT: 0 | vcall_offset (0) +// CHECK-8-NEXT: 1 | vbase_offset (-16) +// CHECK-8-NEXT: 2 | offset_to_top (0) +// CHECK-8-NEXT: 3 | Test3::V2 RTTI +// CHECK-8-NEXT: -- (Test3::V2, 32) vtable address -- +// CHECK-8-NEXT: 4 | void Test3::V2::f() +// CHECK-8-NEXT: 5 | vcall_offset (16) +// CHECK-8-NEXT: 6 | offset_to_top (16) +// CHECK-8-NEXT: 7 | Test3::V2 RTTI +// CHECK-8-NEXT: -- (Test3::V1, 16) vtable address -- +// CHECK-8-NEXT: 8 | void Test3::V2::f() +// CHECK-8-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +struct C : virtual V1, virtual V2 { + int c; + virtual void f(); +}; +void C::f() { } + +struct B { + int b; +}; + +// CHECK-9: Vtable for 'Test3::D' (15 entries). +// CHECK-9-NEXT: 0 | vbase_offset (40) +// CHECK-9-NEXT: 1 | vbase_offset (24) +// CHECK-9-NEXT: 2 | offset_to_top (0) +// CHECK-9-NEXT: 3 | Test3::D RTTI +// CHECK-9-NEXT: -- (Test3::C, 0) vtable address -- +// CHECK-9-NEXT: -- (Test3::D, 0) vtable address -- +// CHECK-9-NEXT: 4 | void Test3::C::f() +// CHECK-9-NEXT: 5 | void Test3::D::g() +// CHECK-9-NEXT: 6 | vcall_offset (-24) +// CHECK-9-NEXT: 7 | offset_to_top (-24) +// CHECK-9-NEXT: 8 | Test3::D RTTI +// CHECK-9-NEXT: -- (Test3::V1, 24) vtable address -- +// CHECK-9-NEXT: 9 | void Test3::C::f() +// CHECK-9-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-9-NEXT: 10 | vcall_offset (-40) +// CHECK-9-NEXT: 11 | vbase_offset (-16) +// CHECK-9-NEXT: 12 | offset_to_top (-40) +// CHECK-9-NEXT: 13 | Test3::D RTTI +// CHECK-9-NEXT: -- (Test3::V2, 40) vtable address -- +// CHECK-9-NEXT: 14 | void Test3::C::f() +// CHECK-9-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] + +// CHECK-10: Construction vtable for ('Test3::C', 0) in 'Test3::D' (14 entries). +// CHECK-10-NEXT: 0 | vbase_offset (40) +// CHECK-10-NEXT: 1 | vbase_offset (24) +// CHECK-10-NEXT: 2 | offset_to_top (0) +// CHECK-10-NEXT: 3 | Test3::C RTTI +// CHECK-10-NEXT: -- (Test3::C, 0) vtable address -- +// CHECK-10-NEXT: 4 | void Test3::C::f() +// CHECK-10-NEXT: 5 | vcall_offset (-24) +// CHECK-10-NEXT: 6 | offset_to_top (-24) +// CHECK-10-NEXT: 7 | Test3::C RTTI +// CHECK-10-NEXT: -- (Test3::V1, 24) vtable address -- +// CHECK-10-NEXT: 8 | void Test3::C::f() +// CHECK-10-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-10-NEXT: 9 | vcall_offset (-40) +// CHECK-10-NEXT: 10 | vbase_offset (-16) +// CHECK-10-NEXT: 11 | offset_to_top (-40) +// CHECK-10-NEXT: 12 | Test3::C RTTI +// CHECK-10-NEXT: -- (Test3::V2, 40) vtable address -- +// CHECK-10-NEXT: 13 | void Test3::C::f() +// CHECK-10-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] + +// CHECK-11: Construction vtable for ('Test3::V2', 40) in 'Test3::D' (9 entries). +// CHECK-11-NEXT: 0 | vcall_offset (0) +// CHECK-11-NEXT: 1 | vbase_offset (-16) +// CHECK-11-NEXT: 2 | offset_to_top (0) +// CHECK-11-NEXT: 3 | Test3::V2 RTTI +// CHECK-11-NEXT: -- (Test3::V2, 40) vtable address -- +// CHECK-11-NEXT: 4 | void Test3::V2::f() +// CHECK-11-NEXT: 5 | vcall_offset (16) +// CHECK-11-NEXT: 6 | offset_to_top (16) +// CHECK-11-NEXT: 7 | Test3::V2 RTTI +// CHECK-11-NEXT: -- (Test3::V1, 24) vtable address -- +// CHECK-11-NEXT: 8 | void Test3::V2::f() +// CHECK-11-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +struct D : B, C { + int d; + virtual void g(); +}; +void D::g() { } + +} diff --git a/clang/test/CodeGenCXX/vtable-layout-extreme.cpp b/clang/test/CodeGenCXX/vtable-layout-extreme.cpp new file mode 100644 index 0000000..14e7879 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-layout-extreme.cpp @@ -0,0 +1,210 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts 2>&1 | FileCheck %s + +// A collection of big class hierarchies and their vtables. + +namespace Test1 { + +class C0 +{ +}; +class C1 + : virtual public C0 +{ + int k0; +}; +class C2 + : public C0 + , virtual public C1 +{ + int k0; +}; +class C3 + : virtual public C0 + , virtual public C1 + , public C2 +{ + int k0; + int k1; + int k2; + int k3; +}; +class C4 + : public C2 + , virtual public C3 + , public C0 +{ + int k0; +}; +class C5 + : public C0 + , virtual public C4 + , public C2 + , public C1 + , virtual public C3 +{ + int k0; +}; +class C6 + : virtual public C3 + , public C0 + , public C5 + , public C4 + , public C1 +{ + int k0; +}; +class C7 + : virtual public C5 + , virtual public C6 + , virtual public C3 + , public C4 + , virtual public C2 +{ + int k0; + int k1; +}; +class C8 + : public C7 + , public C5 + , public C3 + , virtual public C4 + , public C1 + , public C2 +{ + int k0; + int k1; +}; + +// CHECK: Vtable for 'Test1::C9' (87 entries). +// CHECK-NEXT: 0 | vbase_offset (344) +// CHECK-NEXT: 1 | vbase_offset (312) +// CHECK-NEXT: 2 | vbase_offset (184) +// CHECK-NEXT: 3 | vbase_offset (168) +// CHECK-NEXT: 4 | vbase_offset (120) +// CHECK-NEXT: 5 | vbase_offset (48) +// CHECK-NEXT: 6 | vbase_offset (148) +// CHECK-NEXT: 7 | vbase_offset (152) +// CHECK-NEXT: 8 | offset_to_top (0) +// CHECK-NEXT: 9 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 0) vtable address -- +// CHECK-NEXT: -- (Test1::C9, 0) vtable address -- +// CHECK-NEXT: 10 | void Test1::C9::f() +// CHECK-NEXT: 11 | vbase_offset (104) +// CHECK-NEXT: 12 | vbase_offset (132) +// CHECK-NEXT: 13 | vbase_offset (136) +// CHECK-NEXT: 14 | offset_to_top (-16) +// CHECK-NEXT: 15 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 16) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 16) vtable address -- +// CHECK-NEXT: 16 | vbase_offset (72) +// CHECK-NEXT: 17 | vbase_offset (120) +// CHECK-NEXT: 18 | vbase_offset (100) +// CHECK-NEXT: 19 | vbase_offset (104) +// CHECK-NEXT: 20 | offset_to_top (-48) +// CHECK-NEXT: 21 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 48) vtable address -- +// CHECK-NEXT: -- (Test1::C5, 48) vtable address -- +// CHECK-NEXT: -- (Test1::C6, 48) vtable address -- +// CHECK-NEXT: 22 | vbase_offset (84) +// CHECK-NEXT: 23 | offset_to_top (-64) +// CHECK-NEXT: 24 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 64) vtable address -- +// CHECK-NEXT: 25 | vbase_offset (32) +// CHECK-NEXT: 26 | vbase_offset (60) +// CHECK-NEXT: 27 | vbase_offset (64) +// CHECK-NEXT: 28 | offset_to_top (-88) +// CHECK-NEXT: 29 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 88) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 88) vtable address -- +// CHECK-NEXT: 30 | vbase_offset (44) +// CHECK-NEXT: 31 | offset_to_top (-104) +// CHECK-NEXT: 32 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 104) vtable address -- +// CHECK-NEXT: 33 | vbase_offset (28) +// CHECK-NEXT: 34 | vbase_offset (32) +// CHECK-NEXT: 35 | offset_to_top (-120) +// CHECK-NEXT: 36 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 120) vtable address -- +// CHECK-NEXT: -- (Test1::C3, 120) vtable address -- +// CHECK-NEXT: 37 | vbase_offset (-4) +// CHECK-NEXT: 38 | offset_to_top (-152) +// CHECK-NEXT: 39 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 152) vtable address -- +// CHECK-NEXT: 40 | vbase_offset (-48) +// CHECK-NEXT: 41 | vbase_offset (-20) +// CHECK-NEXT: 42 | vbase_offset (-16) +// CHECK-NEXT: 43 | offset_to_top (-168) +// CHECK-NEXT: 44 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 168) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 168) vtable address -- +// CHECK-NEXT: 45 | vbase_offset (160) +// CHECK-NEXT: 46 | vbase_offset (-136) +// CHECK-NEXT: 47 | vbase_offset (-16) +// CHECK-NEXT: 48 | vbase_offset (128) +// CHECK-NEXT: 49 | vbase_offset (-64) +// CHECK-NEXT: 50 | vbase_offset (-36) +// CHECK-NEXT: 51 | vbase_offset (-32) +// CHECK-NEXT: 52 | offset_to_top (-184) +// CHECK-NEXT: 53 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 184) vtable address -- +// CHECK-NEXT: -- (Test1::C4, 184) vtable address -- +// CHECK-NEXT: -- (Test1::C7, 184) vtable address -- +// CHECK-NEXT: -- (Test1::C8, 184) vtable address -- +// CHECK-NEXT: 54 | vbase_offset (-88) +// CHECK-NEXT: 55 | vbase_offset (-40) +// CHECK-NEXT: 56 | vbase_offset (-60) +// CHECK-NEXT: 57 | vbase_offset (-56) +// CHECK-NEXT: 58 | offset_to_top (-208) +// CHECK-NEXT: 59 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 208) vtable address -- +// CHECK-NEXT: -- (Test1::C5, 208) vtable address -- +// CHECK-NEXT: 60 | vbase_offset (-76) +// CHECK-NEXT: 61 | offset_to_top (-224) +// CHECK-NEXT: 62 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 224) vtable address -- +// CHECK-NEXT: 63 | vbase_offset (-92) +// CHECK-NEXT: 64 | vbase_offset (-88) +// CHECK-NEXT: 65 | offset_to_top (-240) +// CHECK-NEXT: 66 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 240) vtable address -- +// CHECK-NEXT: -- (Test1::C3, 240) vtable address -- +// CHECK-NEXT: 67 | vbase_offset (-124) +// CHECK-NEXT: 68 | offset_to_top (-272) +// CHECK-NEXT: 69 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 272) vtable address -- +// CHECK-NEXT: 70 | vbase_offset (-140) +// CHECK-NEXT: 71 | vbase_offset (-136) +// CHECK-NEXT: 72 | offset_to_top (-288) +// CHECK-NEXT: 73 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 288) vtable address -- +// CHECK-NEXT: 74 | vbase_offset (-192) +// CHECK-NEXT: 75 | vbase_offset (-144) +// CHECK-NEXT: 76 | vbase_offset (-164) +// CHECK-NEXT: 77 | vbase_offset (-160) +// CHECK-NEXT: 78 | offset_to_top (-312) +// CHECK-NEXT: 79 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C2, 312) vtable address -- +// CHECK-NEXT: -- (Test1::C5, 312) vtable address -- +// CHECK-NEXT: 80 | vbase_offset (-180) +// CHECK-NEXT: 81 | offset_to_top (-328) +// CHECK-NEXT: 82 | Test1::C9 RTTI +// CHECK-NEXT: -- (Test1::C1, 328) vtable address -- +// CHECK-NEXT: 83 | vbase_offset (-196) +// CHECK-NEXT: 84 | vbase_offset (-192) +// CHECK-NEXT: 85 | offset_to_top (-344) +// CHECK-NEXT: 86 | Test1::C9 RTTI +class C9 + : virtual public C6 + , public C2 + , public C4 + , virtual public C8 +{ + int k0; + int k1; + int k2; + int k3; + virtual void f(); +}; +void C9::f() { } + +} diff --git a/clang/test/CodeGenCXX/vtable-layout.cpp b/clang/test/CodeGenCXX/vtable-layout.cpp new file mode 100644 index 0000000..d7644b9 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-layout.cpp @@ -0,0 +1,1729 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts > %t 2>&1 +// RUN: FileCheck --check-prefix=CHECK-1 %s < %t +// RUN: FileCheck --check-prefix=CHECK-2 %s < %t +// RUN: FileCheck --check-prefix=CHECK-3 %s < %t +// RUN: FileCheck --check-prefix=CHECK-4 %s < %t +// RUN: FileCheck --check-prefix=CHECK-5 %s < %t +// RUN: FileCheck --check-prefix=CHECK-6 %s < %t +// RUN: FileCheck --check-prefix=CHECK-7 %s < %t +// RUN: FileCheck --check-prefix=CHECK-8 %s < %t +// RUN: FileCheck --check-prefix=CHECK-9 %s < %t +// RUN: FileCheck --check-prefix=CHECK-10 %s < %t +// RUN: FileCheck --check-prefix=CHECK-11 %s < %t +// RUN: FileCheck --check-prefix=CHECK-12 %s < %t +// RUN: FileCheck --check-prefix=CHECK-13 %s < %t +// RUN: FileCheck --check-prefix=CHECK-14 %s < %t +// RUN: FileCheck --check-prefix=CHECK-15 %s < %t +// RUN: FileCheck --check-prefix=CHECK-16 %s < %t +// RUN: FileCheck --check-prefix=CHECK-17 %s < %t +// RUN: FileCheck --check-prefix=CHECK-18 %s < %t +// RUN: FileCheck --check-prefix=CHECK-19 %s < %t +// RUN: FileCheck --check-prefix=CHECK-20 %s < %t +// RUN: FileCheck --check-prefix=CHECK-21 %s < %t +// RUN: FileCheck --check-prefix=CHECK-22 %s < %t +// RUN: FileCheck --check-prefix=CHECK-23 %s < %t +// RUN: FileCheck --check-prefix=CHECK-24 %s < %t +// RUN: FileCheck --check-prefix=CHECK-25 %s < %t +// RUN: FileCheck --check-prefix=CHECK-26 %s < %t +// RUN: FileCheck --check-prefix=CHECK-27 %s < %t +// RUN: FileCheck --check-prefix=CHECK-28 %s < %t +// RUN: FileCheck --check-prefix=CHECK-29 %s < %t +// RUN: FileCheck --check-prefix=CHECK-30 %s < %t +// RUN: FileCheck --check-prefix=CHECK-31 %s < %t +// RUN: FileCheck --check-prefix=CHECK-32 %s < %t +// RUN: FileCheck --check-prefix=CHECK-33 %s < %t +// RUN: FileCheck --check-prefix=CHECK-34 %s < %t +// RUN: FileCheck --check-prefix=CHECK-35 %s < %t +// RUN: FileCheck --check-prefix=CHECK-36 %s < %t +// RUN: FileCheck --check-prefix=CHECK-37 %s < %t +// RUN: FileCheck --check-prefix=CHECK-38 %s < %t +// RUN: FileCheck --check-prefix=CHECK-39 %s < %t +// RUN: FileCheck --check-prefix=CHECK-40 %s < %t +// RUN: FileCheck --check-prefix=CHECK-41 %s < %t +// RUN: FileCheck --check-prefix=CHECK-42 %s < %t +// RUN: FileCheck --check-prefix=CHECK-43 %s < %t +// RUN: FileCheck --check-prefix=CHECK-44 %s < %t + +// For now, just verify this doesn't crash. +namespace test0 { + struct Obj {}; + + struct Base { virtual const Obj *foo() = 0; }; + struct Derived : Base { virtual Obj *foo() { return new Obj(); } }; + + void test(Derived *D) { D->foo(); } +} + +namespace Test1 { +// CHECK-1: Vtable for 'Test1::A' (3 entries). +// CHECK-1-NEXT: 0 | offset_to_top (0) +// CHECK-1-NEXT: 1 | Test1::A RTTI +// CHECK-1-NEXT: -- (Test1::A, 0) vtable address -- +// CHECK-1-NEXT: 2 | void Test1::A::f() +struct A { + virtual void f(); +}; +void A::f() { } + +} + +namespace Test2 { + +// This is a smoke test of the vtable dumper. +// CHECK-2: Vtable for 'Test2::A' (9 entries). +// CHECK-2-NEXT: 0 | offset_to_top (0) +// CHECK-2-NEXT: 1 | Test2::A RTTI +// CHECK-2-NEXT: -- (Test2::A, 0) vtable address -- +// CHECK-2-NEXT: 2 | void Test2::A::f() +// CHECK-2-NEXT: 3 | void Test2::A::f() const +// CHECK-2-NEXT: 4 | Test2::A *Test2::A::g(int) +// CHECK-2-NEXT: 5 | Test2::A::~A() [complete] +// CHECK-2-NEXT: 6 | Test2::A::~A() [deleting] +// CHECK-2-NEXT: 7 | void Test2::A::h() +// CHECK-2-NEXT: 8 | Test2::A &Test2::A::operator=(const Test2::A &) +struct A { + virtual void f(); + virtual void f() const; + + virtual A* g(int a); + virtual ~A(); + virtual void h(); + virtual A& operator=(const A&); +}; +void A::f() { } + +// Another simple vtable dumper test. + +// CHECK-3: Vtable for 'Test2::B' (6 entries). +// CHECK-3-NEXT: 0 | offset_to_top (0) +// CHECK-3-NEXT: 1 | Test2::B RTTI +// CHECK-3-NEXT: -- (Test2::B, 0) vtable address -- +// CHECK-3-NEXT: 2 | void Test2::B::f() +// CHECK-3-NEXT: 3 | void Test2::B::g() [pure] +// CHECK-3-NEXT: 4 | Test2::B::~B() [complete] [pure] +// CHECK-3-NEXT: 5 | Test2::B::~B() [deleting] [pure] +struct B { + virtual void f(); + virtual void g() = 0; + virtual ~B() = 0; +}; +void B::f() { } + +} + +namespace Test3 { + +// If a function in a derived class overrides a function in a primary base, +// then the function should not have an entry in the derived class (unless the return +// value requires adjusting). + +// CHECK-4: Vtable for 'Test3::A' (3 entries). +// CHECK-4-NEXT: 0 | offset_to_top (0) +// CHECK-4-NEXT: 1 | Test3::A RTTI +// CHECK-4-NEXT: -- (Test3::A, 0) vtable address -- +// CHECK-4-NEXT: 2 | void Test3::A::f() +struct A { + virtual void f(); +}; +void A::f() { } + +// CHECK-5: Vtable for 'Test3::B' (4 entries). +// CHECK-5-NEXT: 0 | offset_to_top (0) +// CHECK-5-NEXT: 1 | Test3::B RTTI +// CHECK-5-NEXT: -- (Test3::A, 0) vtable address -- +// CHECK-5-NEXT: -- (Test3::B, 0) vtable address -- +// CHECK-5-NEXT: 2 | void Test3::B::f() +// CHECK-5-NEXT: 3 | void Test3::B::g() +struct B : A { + virtual void f(); + virtual void g(); +}; +void B::f() { } + +// CHECK-6: Vtable for 'Test3::C' (5 entries). +// CHECK-6-NEXT: 0 | offset_to_top (0) +// CHECK-6-NEXT: 1 | Test3::C RTTI +// CHECK-6-NEXT: -- (Test3::A, 0) vtable address -- +// CHECK-6-NEXT: -- (Test3::C, 0) vtable address -- +// CHECK-6-NEXT: 2 | void Test3::A::f() +// CHECK-6-NEXT: 3 | void Test3::C::g() +// CHECK-6-NEXT: 4 | void Test3::C::h() +struct C : A { + virtual void g(); + virtual void h(); +}; +void C::g() { } + +// CHECK-7: Vtable for 'Test3::D' (5 entries). +// CHECK-7-NEXT: 0 | offset_to_top (0) +// CHECK-7-NEXT: 1 | Test3::D RTTI +// CHECK-7-NEXT: -- (Test3::A, 0) vtable address -- +// CHECK-7-NEXT: -- (Test3::B, 0) vtable address -- +// CHECK-7-NEXT: -- (Test3::D, 0) vtable address -- +// CHECK-7-NEXT: 2 | void Test3::D::f() +// CHECK-7-NEXT: 3 | void Test3::D::g() +// CHECK-7-NEXT: 4 | void Test3::D::h() +struct D : B { + virtual void f(); + virtual void g(); + virtual void h(); +}; + +void D::f() { } +} + +namespace Test4 { + +// Test non-virtual result adjustments. + +struct R1 { int r1; }; +struct R2 { int r2; }; +struct R3 : R1, R2 { int r3; }; + +struct A { + virtual R2 *f(); +}; + +// CHECK-8: Vtable for 'Test4::B' (4 entries). +// CHECK-8-NEXT: 0 | offset_to_top (0) +// CHECK-8-NEXT: 1 | Test4::B RTTI +// CHECK-8-NEXT: -- (Test4::A, 0) vtable address -- +// CHECK-8-NEXT: -- (Test4::B, 0) vtable address -- +// CHECK-8-NEXT: 2 | Test4::R3 *Test4::B::f() +// CHECK-8-NEXT: [return adjustment: 4 non-virtual] +// CHECK-8-NEXT: 3 | Test4::R3 *Test4::B::f() + +struct B : A { + virtual R3 *f(); +}; +R3 *B::f() { return 0; } + +// Test virtual result adjustments. +struct V1 { int v1; }; +struct V2 : virtual V1 { int v1; }; + +struct C { + virtual V1 *f(); +}; + +// CHECK-9: Vtable for 'Test4::D' (4 entries). +// CHECK-9-NEXT: 0 | offset_to_top (0) +// CHECK-9-NEXT: 1 | Test4::D RTTI +// CHECK-9-NEXT: -- (Test4::C, 0) vtable address -- +// CHECK-9-NEXT: -- (Test4::D, 0) vtable address -- +// CHECK-9-NEXT: 2 | Test4::V2 *Test4::D::f() +// CHECK-9-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset] +// CHECK-9-NEXT: 3 | Test4::V2 *Test4::D::f() +struct D : C { + virtual V2 *f(); +}; +V2 *D::f() { return 0; }; + +// Virtual result adjustments with an additional non-virtual adjustment. +struct V3 : virtual R3 { int r3; }; + +// CHECK-10: Vtable for 'Test4::E' (4 entries). +// CHECK-10-NEXT: 0 | offset_to_top (0) +// CHECK-10-NEXT: 1 | Test4::E RTTI +// CHECK-10-NEXT: -- (Test4::A, 0) vtable address -- +// CHECK-10-NEXT: -- (Test4::E, 0) vtable address -- +// CHECK-10-NEXT: 2 | Test4::V3 *Test4::E::f() +// CHECK-10-NEXT: [return adjustment: 4 non-virtual, -24 vbase offset offset] +// CHECK-10-NEXT: 3 | Test4::V3 *Test4::E::f() + +struct E : A { + virtual V3 *f(); +}; +V3 *E::f() { return 0;} + +// Test that a pure virtual member doesn't get a thunk. + +// CHECK-11: Vtable for 'Test4::F' (5 entries). +// CHECK-11-NEXT: 0 | offset_to_top (0) +// CHECK-11-NEXT: 1 | Test4::F RTTI +// CHECK-11-NEXT: -- (Test4::A, 0) vtable address -- +// CHECK-11-NEXT: -- (Test4::F, 0) vtable address -- +// CHECK-11-NEXT: 2 | Test4::R3 *Test4::F::f() [pure] +// CHECK-11-NEXT: 3 | void Test4::F::g() +// CHECK-11-NEXT: 4 | Test4::R3 *Test4::F::f() [pure] +struct F : A { + virtual void g(); + virtual R3 *f() = 0; +}; +void F::g() { } + +} + +namespace Test5 { + +// Simple secondary vtables without 'this' pointer adjustments. +struct A { + virtual void f(); + virtual void g(); + int a; +}; + +struct B1 : A { + virtual void f(); + int b1; +}; + +struct B2 : A { + virtual void g(); + int b2; +}; + +// CHECK-12: Vtable for 'Test5::C' (9 entries). +// CHECK-12-NEXT: 0 | offset_to_top (0) +// CHECK-12-NEXT: 1 | Test5::C RTTI +// CHECK-12-NEXT: -- (Test5::A, 0) vtable address -- +// CHECK-12-NEXT: -- (Test5::B1, 0) vtable address -- +// CHECK-12-NEXT: -- (Test5::C, 0) vtable address -- +// CHECK-12-NEXT: 2 | void Test5::B1::f() +// CHECK-12-NEXT: 3 | void Test5::A::g() +// CHECK-12-NEXT: 4 | void Test5::C::h() +// CHECK-12-NEXT: 5 | offset_to_top (-16) +// CHECK-12-NEXT: 6 | Test5::C RTTI +// CHECK-12-NEXT: -- (Test5::A, 16) vtable address -- +// CHECK-12-NEXT: -- (Test5::B2, 16) vtable address -- +// CHECK-12-NEXT: 7 | void Test5::A::f() +// CHECK-12-NEXT: 8 | void Test5::B2::g() +struct C : B1, B2 { + virtual void h(); +}; +void C::h() { } +} + +namespace Test6 { + +// Simple non-virtual 'this' pointer adjustments. +struct A1 { + virtual void f(); + int a; +}; + +struct A2 { + virtual void f(); + int a; +}; + +// CHECK-13: Vtable for 'Test6::C' (6 entries). +// CHECK-13-NEXT: 0 | offset_to_top (0) +// CHECK-13-NEXT: 1 | Test6::C RTTI +// CHECK-13-NEXT: -- (Test6::A1, 0) vtable address -- +// CHECK-13-NEXT: -- (Test6::C, 0) vtable address -- +// CHECK-13-NEXT: 2 | void Test6::C::f() +// CHECK-13-NEXT: 3 | offset_to_top (-16) +// CHECK-13-NEXT: 4 | Test6::C RTTI +// CHECK-13-NEXT: -- (Test6::A2, 16) vtable address -- +// CHECK-13-NEXT: 5 | void Test6::C::f() +// CHECK-13-NEXT: [this adjustment: -16 non-virtual] +struct C : A1, A2 { + virtual void f(); +}; +void C::f() { } + +} + +namespace Test7 { + +// Test that the D::f overrider for A::f have different 'this' pointer +// adjustments in the two A base subobjects. + +struct A { + virtual void f(); + int a; +}; + +struct B1 : A { }; +struct B2 : A { }; + +struct C { virtual void c(); }; + +// CHECK-14: Vtable for 'Test7::D' (10 entries). +// CHECK-14-NEXT: 0 | offset_to_top (0) +// CHECK-14-NEXT: 1 | Test7::D RTTI +// CHECK-14-NEXT: -- (Test7::C, 0) vtable address -- +// CHECK-14-NEXT: -- (Test7::D, 0) vtable address -- +// CHECK-14-NEXT: 2 | void Test7::C::c() +// CHECK-14-NEXT: 3 | void Test7::D::f() +// CHECK-14-NEXT: 4 | offset_to_top (-8) +// CHECK-14-NEXT: 5 | Test7::D RTTI +// CHECK-14-NEXT: -- (Test7::A, 8) vtable address -- +// CHECK-14-NEXT: -- (Test7::B1, 8) vtable address -- +// CHECK-14-NEXT: 6 | void Test7::D::f() +// CHECK-14-NEXT: [this adjustment: -8 non-virtual] +// CHECK-14-NEXT: 7 | offset_to_top (-24) +// CHECK-14-NEXT: 8 | Test7::D RTTI +// CHECK-14-NEXT: -- (Test7::A, 24) vtable address -- +// CHECK-14-NEXT: -- (Test7::B2, 24) vtable address -- +// CHECK-14-NEXT: 9 | void Test7::D::f() +// CHECK-14-NEXT: [this adjustment: -24 non-virtual] +struct D : C, B1, B2 { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test8 { + +// Test that we don't try to layout vtables for classes that don't have +// virtual bases or virtual member functions. + +struct A { }; + +// CHECK-15: Vtable for 'Test8::B' (3 entries). +// CHECK-15-NEXT: 0 | offset_to_top (0) +// CHECK-15-NEXT: 1 | Test8::B RTTI +// CHECK-15-NEXT: -- (Test8::B, 0) vtable address -- +// CHECK-15-NEXT: 2 | void Test8::B::f() +struct B : A { + virtual void f(); +}; +void B::f() { } + +} + +namespace Test9 { + +// Simple test of vbase offsets. + +struct A1 { int a1; }; +struct A2 { int a2; }; + +// CHECK-16: Vtable for 'Test9::B' (5 entries). +// CHECK-16-NEXT: 0 | vbase_offset (16) +// CHECK-16-NEXT: 1 | vbase_offset (12) +// CHECK-16-NEXT: 2 | offset_to_top (0) +// CHECK-16-NEXT: 3 | Test9::B RTTI +// CHECK-16-NEXT: -- (Test9::B, 0) vtable address -- +// CHECK-16-NEXT: 4 | void Test9::B::f() +struct B : virtual A1, virtual A2 { + int b; + + virtual void f(); +}; + + +void B::f() { } + +} + +namespace Test10 { + +// Test for a bug where we would not emit secondary vtables for bases +// of a primary base. +struct A1 { virtual void a1(); }; +struct A2 { virtual void a2(); }; + +// CHECK-17: Vtable for 'Test10::C' (7 entries). +// CHECK-17-NEXT: 0 | offset_to_top (0) +// CHECK-17-NEXT: 1 | Test10::C RTTI +// CHECK-17-NEXT: -- (Test10::A1, 0) vtable address -- +// CHECK-17-NEXT: -- (Test10::B, 0) vtable address -- +// CHECK-17-NEXT: -- (Test10::C, 0) vtable address -- +// CHECK-17-NEXT: 2 | void Test10::A1::a1() +// CHECK-17-NEXT: 3 | void Test10::C::f() +// CHECK-17-NEXT: 4 | offset_to_top (-8) +// CHECK-17-NEXT: 5 | Test10::C RTTI +// CHECK-17-NEXT: -- (Test10::A2, 8) vtable address -- +// CHECK-17-NEXT: 6 | void Test10::A2::a2() +struct B : A1, A2 { + int b; +}; + +struct C : B { + virtual void f(); +}; +void C::f() { } + +} + +namespace Test11 { + +// Very simple test of vtables for virtual bases. +struct A1 { int a; }; +struct A2 { int b; }; + +struct B : A1, virtual A2 { + int b; +}; + +// CHECK-18: Vtable for 'Test11::C' (8 entries). +// CHECK-18-NEXT: 0 | vbase_offset (24) +// CHECK-18-NEXT: 1 | vbase_offset (8) +// CHECK-18-NEXT: 2 | offset_to_top (0) +// CHECK-18-NEXT: 3 | Test11::C RTTI +// CHECK-18-NEXT: -- (Test11::C, 0) vtable address -- +// CHECK-18-NEXT: 4 | void Test11::C::f() +// CHECK-18-NEXT: 5 | vbase_offset (16) +// CHECK-18-NEXT: 6 | offset_to_top (-8) +// CHECK-18-NEXT: 7 | Test11::C RTTI +struct C : virtual B { + virtual void f(); +}; +void C::f() { } + +} + +namespace Test12 { + +// Test that the right vcall offsets are generated in the right order. + +// CHECK-19: Vtable for 'Test12::B' (19 entries). +// CHECK-19-NEXT: 0 | vbase_offset (8) +// CHECK-19-NEXT: 1 | offset_to_top (0) +// CHECK-19-NEXT: 2 | Test12::B RTTI +// CHECK-19-NEXT: -- (Test12::B, 0) vtable address -- +// CHECK-19-NEXT: 3 | void Test12::B::f() +// CHECK-19-NEXT: 4 | void Test12::B::a() +// CHECK-19-NEXT: 5 | vcall_offset (32) +// CHECK-19-NEXT: 6 | vcall_offset (16) +// CHECK-19-NEXT: 7 | vcall_offset (-8) +// CHECK-19-NEXT: 8 | vcall_offset (0) +// CHECK-19-NEXT: 9 | offset_to_top (-8) +// CHECK-19-NEXT: 10 | Test12::B RTTI +// CHECK-19-NEXT: -- (Test12::A, 8) vtable address -- +// CHECK-19-NEXT: -- (Test12::A1, 8) vtable address -- +// CHECK-19-NEXT: 11 | void Test12::A1::a1() +// CHECK-19-NEXT: 12 | void Test12::B::a() +// CHECK-19-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-19-NEXT: 13 | offset_to_top (-24) +// CHECK-19-NEXT: 14 | Test12::B RTTI +// CHECK-19-NEXT: -- (Test12::A2, 24) vtable address -- +// CHECK-19-NEXT: 15 | void Test12::A2::a2() +// CHECK-19-NEXT: 16 | offset_to_top (-40) +// CHECK-19-NEXT: 17 | Test12::B RTTI +// CHECK-19-NEXT: -- (Test12::A3, 40) vtable address -- +// CHECK-19-NEXT: 18 | void Test12::A3::a3() +struct A1 { + virtual void a1(); + int a; +}; + +struct A2 { + virtual void a2(); + int a; +}; + +struct A3 { + virtual void a3(); + int a; +}; + +struct A : A1, A2, A3 { + virtual void a(); + int i; +}; + +struct B : virtual A { + virtual void f(); + + virtual void a(); +}; +void B::f() { } + +} + +namespace Test13 { + +// Test that we don't try to emit a vtable for 'A' twice. +struct A { + virtual void f(); +}; + +struct B : virtual A { + virtual void f(); +}; + +// CHECK-20: Vtable for 'Test13::C' (6 entries). +// CHECK-20-NEXT: 0 | vbase_offset (0) +// CHECK-20-NEXT: 1 | vbase_offset (0) +// CHECK-20-NEXT: 2 | vcall_offset (0) +// CHECK-20-NEXT: 3 | offset_to_top (0) +// CHECK-20-NEXT: 4 | Test13::C RTTI +// CHECK-20-NEXT: -- (Test13::A, 0) vtable address -- +// CHECK-20-NEXT: -- (Test13::B, 0) vtable address -- +// CHECK-20-NEXT: -- (Test13::C, 0) vtable address -- +// CHECK-20-NEXT: 5 | void Test13::C::f() +struct C : virtual B, virtual A { + virtual void f(); +}; +void C::f() { } + +} + +namespace Test14 { + +// Verify that we handle A being a non-virtual base of B, which is a virtual base. + +struct A { + virtual void f(); +}; + +struct B : A { }; + +struct C : virtual B { }; + +// CHECK-21: Vtable for 'Test14::D' (5 entries). +// CHECK-21-NEXT: 0 | vbase_offset (0) +// CHECK-21-NEXT: 1 | vcall_offset (0) +// CHECK-21-NEXT: 2 | offset_to_top (0) +// CHECK-21-NEXT: 3 | Test14::D RTTI +// CHECK-21-NEXT: -- (Test14::A, 0) vtable address -- +// CHECK-21-NEXT: -- (Test14::B, 0) vtable address -- +// CHECK-21-NEXT: -- (Test14::C, 0) vtable address -- +// CHECK-21-NEXT: -- (Test14::D, 0) vtable address -- +// CHECK-21-NEXT: 4 | void Test14::D::f() +struct D : C, virtual B { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test15 { + +// Test that we don't emit an extra vtable for B since it's a primary base of C. +struct A { virtual void a(); }; +struct B { virtual void b(); }; + +struct C : virtual B { }; + +// CHECK-22: Vtable for 'Test15::D' (11 entries). +// CHECK-22-NEXT: 0 | vbase_offset (8) +// CHECK-22-NEXT: 1 | vbase_offset (8) +// CHECK-22-NEXT: 2 | offset_to_top (0) +// CHECK-22-NEXT: 3 | Test15::D RTTI +// CHECK-22-NEXT: -- (Test15::A, 0) vtable address -- +// CHECK-22-NEXT: -- (Test15::D, 0) vtable address -- +// CHECK-22-NEXT: 4 | void Test15::A::a() +// CHECK-22-NEXT: 5 | void Test15::D::f() +// CHECK-22-NEXT: 6 | vbase_offset (0) +// CHECK-22-NEXT: 7 | vcall_offset (0) +// CHECK-22-NEXT: 8 | offset_to_top (-8) +// CHECK-22-NEXT: 9 | Test15::D RTTI +// CHECK-22-NEXT: -- (Test15::B, 8) vtable address -- +// CHECK-22-NEXT: -- (Test15::C, 8) vtable address -- +// CHECK-22-NEXT: 10 | void Test15::B::b() +struct D : A, virtual B, virtual C { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test16 { + +// Test that destructors share vcall offsets. + +struct A { virtual ~A(); }; +struct B { virtual ~B(); }; + +struct C : A, B { virtual ~C(); }; + +// CHECK-23: Vtable for 'Test16::D' (15 entries). +// CHECK-23-NEXT: 0 | vbase_offset (8) +// CHECK-23-NEXT: 1 | offset_to_top (0) +// CHECK-23-NEXT: 2 | Test16::D RTTI +// CHECK-23-NEXT: -- (Test16::D, 0) vtable address -- +// CHECK-23-NEXT: 3 | void Test16::D::f() +// CHECK-23-NEXT: 4 | Test16::D::~D() [complete] +// CHECK-23-NEXT: 5 | Test16::D::~D() [deleting] +// CHECK-23-NEXT: 6 | vcall_offset (-8) +// CHECK-23-NEXT: 7 | offset_to_top (-8) +// CHECK-23-NEXT: 8 | Test16::D RTTI +// CHECK-23-NEXT: -- (Test16::A, 8) vtable address -- +// CHECK-23-NEXT: -- (Test16::C, 8) vtable address -- +// CHECK-23-NEXT: 9 | Test16::D::~D() [complete] +// CHECK-23-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-23-NEXT: 10 | Test16::D::~D() [deleting] +// CHECK-23-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-23-NEXT: 11 | offset_to_top (-16) +// CHECK-23-NEXT: 12 | Test16::D RTTI +// CHECK-23-NEXT: -- (Test16::B, 16) vtable address -- +// CHECK-23-NEXT: 13 | Test16::D::~D() [complete] +// CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset] +// CHECK-23-NEXT: 14 | Test16::D::~D() [deleting] +// CHECK-23-NEXT: [this adjustment: -8 non-virtual, -24 vcall offset offset] +struct D : virtual C { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test17 { + +// Test that we don't mark E::f in the C-in-E vtable as unused. +struct A { virtual void f(); }; +struct B : virtual A { virtual void f(); }; +struct C : virtual A { virtual void f(); }; +struct D : virtual B, virtual C { virtual void f(); }; + +// CHECK-24: Vtable for 'Test17::E' (13 entries). +// CHECK-24-NEXT: 0 | vbase_offset (0) +// CHECK-24-NEXT: 1 | vbase_offset (8) +// CHECK-24-NEXT: 2 | vbase_offset (0) +// CHECK-24-NEXT: 3 | vbase_offset (0) +// CHECK-24-NEXT: 4 | vcall_offset (0) +// CHECK-24-NEXT: 5 | offset_to_top (0) +// CHECK-24-NEXT: 6 | Test17::E RTTI +// CHECK-24-NEXT: -- (Test17::A, 0) vtable address -- +// CHECK-24-NEXT: -- (Test17::B, 0) vtable address -- +// CHECK-24-NEXT: -- (Test17::D, 0) vtable address -- +// CHECK-24-NEXT: -- (Test17::E, 0) vtable address -- +// CHECK-24-NEXT: 7 | void Test17::E::f() +// CHECK-24-NEXT: 8 | vbase_offset (-8) +// CHECK-24-NEXT: 9 | vcall_offset (-8) +// CHECK-24-NEXT: 10 | offset_to_top (-8) +// CHECK-24-NEXT: 11 | Test17::E RTTI +// CHECK-24-NEXT: -- (Test17::C, 8) vtable address -- +// CHECK-24-NEXT: 12 | void Test17::E::f() +// CHECK-24-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +class E : virtual D { + virtual void f(); +}; +void E::f() {} + +} + +namespace Test18 { + +// Test that we compute the right 'this' adjustment offsets. + +struct A { + virtual void f(); + virtual void g(); +}; + +struct B : virtual A { + virtual void f(); +}; + +struct C : A, B { + virtual void g(); +}; + +// CHECK-25: Vtable for 'Test18::D' (24 entries). +// CHECK-25-NEXT: 0 | vbase_offset (8) +// CHECK-25-NEXT: 1 | vbase_offset (0) +// CHECK-25-NEXT: 2 | vbase_offset (0) +// CHECK-25-NEXT: 3 | vcall_offset (8) +// CHECK-25-NEXT: 4 | vcall_offset (0) +// CHECK-25-NEXT: 5 | offset_to_top (0) +// CHECK-25-NEXT: 6 | Test18::D RTTI +// CHECK-25-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-25-NEXT: -- (Test18::B, 0) vtable address -- +// CHECK-25-NEXT: -- (Test18::D, 0) vtable address -- +// CHECK-25-NEXT: 7 | void Test18::D::f() +// CHECK-25-NEXT: 8 | void Test18::C::g() +// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-25-NEXT: 9 | void Test18::D::h() +// CHECK-25-NEXT: 10 | vcall_offset (0) +// CHECK-25-NEXT: 11 | vcall_offset (-8) +// CHECK-25-NEXT: 12 | vbase_offset (-8) +// CHECK-25-NEXT: 13 | offset_to_top (-8) +// CHECK-25-NEXT: 14 | Test18::D RTTI +// CHECK-25-NEXT: -- (Test18::A, 8) vtable address -- +// CHECK-25-NEXT: -- (Test18::C, 8) vtable address -- +// CHECK-25-NEXT: 15 | void Test18::D::f() +// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] +// CHECK-25-NEXT: 16 | void Test18::C::g() +// CHECK-25-NEXT: 17 | vbase_offset (-16) +// CHECK-25-NEXT: 18 | vcall_offset (-8) +// CHECK-25-NEXT: 19 | vcall_offset (-16) +// CHECK-25-NEXT: 20 | offset_to_top (-16) +// CHECK-25-NEXT: 21 | Test18::D RTTI +// CHECK-25-NEXT: -- (Test18::B, 16) vtable address -- +// CHECK-25-NEXT: 22 | void Test18::D::f() +// CHECK-25-NEXT: [this adjustment: -8 non-virtual, -32 vcall offset offset] +// CHECK-25-NEXT: 23 | [unused] void Test18::C::g() + +// CHECK-25: Construction vtable for ('Test18::B', 0) in 'Test18::D' (7 entries). +// CHECK-25-NEXT: 0 | vbase_offset (0) +// CHECK-25-NEXT: 1 | vcall_offset (0) +// CHECK-25-NEXT: 2 | vcall_offset (0) +// CHECK-25-NEXT: 3 | offset_to_top (0) +// CHECK-25-NEXT: 4 | Test18::B RTTI +// CHECK-25-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-25-NEXT: -- (Test18::B, 0) vtable address -- +// CHECK-25-NEXT: 5 | void Test18::B::f() +// CHECK-25-NEXT: 6 | void Test18::A::g() + +// CHECK-25: Construction vtable for ('Test18::C', 8) in 'Test18::D' (20 entries). +// CHECK-25-NEXT: 0 | vcall_offset (0) +// CHECK-25-NEXT: 1 | vcall_offset (0) +// CHECK-25-NEXT: 2 | vbase_offset (-8) +// CHECK-25-NEXT: 3 | offset_to_top (0) +// CHECK-25-NEXT: 4 | Test18::C RTTI +// CHECK-25-NEXT: -- (Test18::A, 8) vtable address -- +// CHECK-25-NEXT: -- (Test18::C, 8) vtable address -- +// CHECK-25-NEXT: 5 | void Test18::A::f() +// CHECK-25-NEXT: 6 | void Test18::C::g() +// CHECK-25-NEXT: 7 | vbase_offset (-16) +// CHECK-25-NEXT: 8 | vcall_offset (-8) +// CHECK-25-NEXT: 9 | vcall_offset (0) +// CHECK-25-NEXT: 10 | offset_to_top (-8) +// CHECK-25-NEXT: 11 | Test18::C RTTI +// CHECK-25-NEXT: -- (Test18::B, 16) vtable address -- +// CHECK-25-NEXT: 12 | void Test18::B::f() +// CHECK-25-NEXT: 13 | [unused] void Test18::C::g() +// CHECK-25-NEXT: 14 | vcall_offset (8) +// CHECK-25-NEXT: 15 | vcall_offset (16) +// CHECK-25-NEXT: 16 | offset_to_top (8) +// CHECK-25-NEXT: 17 | Test18::C RTTI +// CHECK-25-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-25-NEXT: 18 | void Test18::B::f() +// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-25-NEXT: 19 | void Test18::C::g() +// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -32 vcall offset offset] + +// CHECK-25: Construction vtable for ('Test18::B', 16) in 'Test18::D' (13 entries). +// CHECK-25-NEXT: 0 | vbase_offset (-16) +// CHECK-25-NEXT: 1 | vcall_offset (-16) +// CHECK-25-NEXT: 2 | vcall_offset (0) +// CHECK-25-NEXT: 3 | offset_to_top (0) +// CHECK-25-NEXT: 4 | Test18::B RTTI +// CHECK-25-NEXT: -- (Test18::B, 16) vtable address -- +// CHECK-25-NEXT: 5 | void Test18::B::f() +// CHECK-25-NEXT: 6 | [unused] void Test18::A::g() +// CHECK-25-NEXT: 7 | vcall_offset (0) +// CHECK-25-NEXT: 8 | vcall_offset (16) +// CHECK-25-NEXT: 9 | offset_to_top (16) +// CHECK-25-NEXT: 10 | Test18::B RTTI +// CHECK-25-NEXT: -- (Test18::A, 0) vtable address -- +// CHECK-25-NEXT: 11 | void Test18::B::f() +// CHECK-25-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-25-NEXT: 12 | void Test18::A::g() +struct D : virtual B, virtual C, virtual A +{ + virtual void f(); + virtual void h(); +}; +void D::f() {} + +} + +namespace Test19 { + +// Another 'this' adjustment test. + +struct A { + int a; + + virtual void f(); +}; + +struct B : A { + int b; + + virtual void g(); +}; + +struct C { + virtual void c(); +}; + +// CHECK-26: Vtable for 'Test19::D' (13 entries). +// CHECK-26-NEXT: 0 | vbase_offset (24) +// CHECK-26-NEXT: 1 | offset_to_top (0) +// CHECK-26-NEXT: 2 | Test19::D RTTI +// CHECK-26-NEXT: -- (Test19::C, 0) vtable address -- +// CHECK-26-NEXT: -- (Test19::D, 0) vtable address -- +// CHECK-26-NEXT: 3 | void Test19::C::c() +// CHECK-26-NEXT: 4 | void Test19::D::f() +// CHECK-26-NEXT: 5 | offset_to_top (-8) +// CHECK-26-NEXT: 6 | Test19::D RTTI +// CHECK-26-NEXT: -- (Test19::A, 8) vtable address -- +// CHECK-26-NEXT: -- (Test19::B, 8) vtable address -- +// CHECK-26-NEXT: 7 | void Test19::D::f() +// CHECK-26-NEXT: [this adjustment: -8 non-virtual] +// CHECK-26-NEXT: 8 | void Test19::B::g() +// CHECK-26-NEXT: 9 | vcall_offset (-24) +// CHECK-26-NEXT: 10 | offset_to_top (-24) +// CHECK-26-NEXT: 11 | Test19::D RTTI +// CHECK-26-NEXT: -- (Test19::A, 24) vtable address -- +// CHECK-26-NEXT: 12 | void Test19::D::f() +// CHECK-26-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +struct D : C, B, virtual A { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test20 { + +// pure virtual member functions should never have 'this' adjustments. + +struct A { + virtual void f() = 0; + virtual void g(); +}; + +struct B : A { }; + +// CHECK-27: Vtable for 'Test20::C' (9 entries). +// CHECK-27-NEXT: 0 | offset_to_top (0) +// CHECK-27-NEXT: 1 | Test20::C RTTI +// CHECK-27-NEXT: -- (Test20::A, 0) vtable address -- +// CHECK-27-NEXT: -- (Test20::C, 0) vtable address -- +// CHECK-27-NEXT: 2 | void Test20::C::f() [pure] +// CHECK-27-NEXT: 3 | void Test20::A::g() +// CHECK-27-NEXT: 4 | void Test20::C::h() +// CHECK-27-NEXT: 5 | offset_to_top (-8) +// CHECK-27-NEXT: 6 | Test20::C RTTI +// CHECK-27-NEXT: -- (Test20::A, 8) vtable address -- +// CHECK-27-NEXT: -- (Test20::B, 8) vtable address -- +// CHECK-27-NEXT: 7 | void Test20::C::f() [pure] +// CHECK-27-NEXT: 8 | void Test20::A::g() +struct C : A, B { + virtual void f() = 0; + virtual void h(); +}; +void C::h() { } + +} + +namespace Test21 { + +// Test that we get vbase offsets right in secondary vtables. +struct A { + virtual void f(); +}; + +struct B : virtual A { }; +class C : virtual B { }; +class D : virtual C { }; + +class E : virtual C { }; + +// CHECK-28: Vtable for 'Test21::F' (16 entries). +// CHECK-28-NEXT: 0 | vbase_offset (8) +// CHECK-28-NEXT: 1 | vbase_offset (0) +// CHECK-28-NEXT: 2 | vbase_offset (0) +// CHECK-28-NEXT: 3 | vbase_offset (0) +// CHECK-28-NEXT: 4 | vbase_offset (0) +// CHECK-28-NEXT: 5 | vcall_offset (0) +// CHECK-28-NEXT: 6 | offset_to_top (0) +// CHECK-28-NEXT: 7 | Test21::F RTTI +// CHECK-28-NEXT: -- (Test21::A, 0) vtable address -- +// CHECK-28-NEXT: -- (Test21::B, 0) vtable address -- +// CHECK-28-NEXT: -- (Test21::C, 0) vtable address -- +// CHECK-28-NEXT: -- (Test21::D, 0) vtable address -- +// CHECK-28-NEXT: -- (Test21::F, 0) vtable address -- +// CHECK-28-NEXT: 8 | void Test21::F::f() +// CHECK-28-NEXT: 9 | vbase_offset (-8) +// CHECK-28-NEXT: 10 | vbase_offset (-8) +// CHECK-28-NEXT: 11 | vbase_offset (-8) +// CHECK-28-NEXT: 12 | vcall_offset (-8) +// CHECK-28-NEXT: 13 | offset_to_top (-8) +// CHECK-28-NEXT: 14 | Test21::F RTTI +// CHECK-28-NEXT: -- (Test21::E, 8) vtable address -- +// CHECK-28-NEXT: 15 | [unused] void Test21::F::f() +// +// CHECK-28: Virtual base offset offsets for 'Test21::F' (5 entries). +// CHECK-28-NEXT: Test21::A | -32 +// CHECK-28-NEXT: Test21::B | -40 +// CHECK-28-NEXT: Test21::C | -48 +// CHECK-28-NEXT: Test21::D | -56 +// CHECK-28-NEXT: Test21::E | -64 +class F : virtual D, virtual E { + virtual void f(); +}; +void F::f() { } + +} + +namespace Test22 { + +// Very simple construction vtable test. +struct V1 { + int v1; +}; + +struct V2 : virtual V1 { + int v2; +}; + +// CHECK-29: Vtable for 'Test22::C' (8 entries). +// CHECK-29-NEXT: 0 | vbase_offset (16) +// CHECK-29-NEXT: 1 | vbase_offset (12) +// CHECK-29-NEXT: 2 | offset_to_top (0) +// CHECK-29-NEXT: 3 | Test22::C RTTI +// CHECK-29-NEXT: -- (Test22::C, 0) vtable address -- +// CHECK-29-NEXT: 4 | void Test22::C::f() +// CHECK-29-NEXT: 5 | vbase_offset (-4) +// CHECK-29-NEXT: 6 | offset_to_top (-16) +// CHECK-29-NEXT: 7 | Test22::C RTTI +// CHECK-29-NEXT: -- (Test22::V2, 16) vtable address -- + +// CHECK-29: Construction vtable for ('Test22::V2', 16) in 'Test22::C' (3 entries). +// CHECK-29-NEXT: 0 | vbase_offset (-4) +// CHECK-29-NEXT: 1 | offset_to_top (0) +// CHECK-29-NEXT: 2 | Test22::V2 RTTI + +struct C : virtual V1, virtual V2 { + int c; + virtual void f(); +}; +void C::f() { } + +} + +namespace Test23 { + +struct A { + int a; +}; + +struct B : virtual A { + int b; +}; + +struct C : A, virtual B { + int c; +}; + +// CHECK-30: Vtable for 'Test23::D' (7 entries). +// CHECK-30-NEXT: 0 | vbase_offset (20) +// CHECK-30-NEXT: 1 | vbase_offset (24) +// CHECK-30-NEXT: 2 | offset_to_top (0) +// CHECK-30-NEXT: 3 | Test23::D RTTI +// CHECK-30-NEXT: -- (Test23::C, 0) vtable address -- +// CHECK-30-NEXT: -- (Test23::D, 0) vtable address -- +// CHECK-30-NEXT: 4 | vbase_offset (-4) +// CHECK-30-NEXT: 5 | offset_to_top (-24) +// CHECK-30-NEXT: 6 | Test23::D RTTI +// CHECK-30-NEXT: -- (Test23::B, 24) vtable address -- + +// CHECK-30: Construction vtable for ('Test23::C', 0) in 'Test23::D' (7 entries). +// CHECK-30-NEXT: 0 | vbase_offset (20) +// CHECK-30-NEXT: 1 | vbase_offset (24) +// CHECK-30-NEXT: 2 | offset_to_top (0) +// CHECK-30-NEXT: 3 | Test23::C RTTI +// CHECK-30-NEXT: -- (Test23::C, 0) vtable address -- +// CHECK-30-NEXT: 4 | vbase_offset (-4) +// CHECK-30-NEXT: 5 | offset_to_top (-24) +// CHECK-30-NEXT: 6 | Test23::C RTTI +// CHECK-30-NEXT: -- (Test23::B, 24) vtable address -- + +// CHECK-30: Construction vtable for ('Test23::B', 24) in 'Test23::D' (3 entries). +// CHECK-30-NEXT: 0 | vbase_offset (-4) +// CHECK-30-NEXT: 1 | offset_to_top (0) +// CHECK-30-NEXT: 2 | Test23::B RTTI +// CHECK-30-NEXT: -- (Test23::B, 24) vtable address -- + +struct D : virtual A, virtual B, C { + int d; + + void f(); +}; +void D::f() { } + D d; +} + +namespace Test24 { + +// Another construction vtable test. + +struct A { + virtual void f(); +}; + +struct B : virtual A { }; +struct C : virtual A { }; + +// CHECK-31: Vtable for 'Test24::D' (10 entries). +// CHECK-31-NEXT: 0 | vbase_offset (0) +// CHECK-31-NEXT: 1 | vcall_offset (0) +// CHECK-31-NEXT: 2 | offset_to_top (0) +// CHECK-31-NEXT: 3 | Test24::D RTTI +// CHECK-31-NEXT: -- (Test24::A, 0) vtable address -- +// CHECK-31-NEXT: -- (Test24::B, 0) vtable address -- +// CHECK-31-NEXT: -- (Test24::D, 0) vtable address -- +// CHECK-31-NEXT: 4 | void Test24::D::f() +// CHECK-31-NEXT: 5 | vbase_offset (-8) +// CHECK-31-NEXT: 6 | vcall_offset (-8) +// CHECK-31-NEXT: 7 | offset_to_top (-8) +// CHECK-31-NEXT: 8 | Test24::D RTTI +// CHECK-31-NEXT: -- (Test24::C, 8) vtable address -- +// CHECK-31-NEXT: 9 | [unused] void Test24::D::f() + +// CHECK-31: Construction vtable for ('Test24::B', 0) in 'Test24::D' (5 entries). +// CHECK-31-NEXT: 0 | vbase_offset (0) +// CHECK-31-NEXT: 1 | vcall_offset (0) +// CHECK-31-NEXT: 2 | offset_to_top (0) +// CHECK-31-NEXT: 3 | Test24::B RTTI +// CHECK-31-NEXT: -- (Test24::A, 0) vtable address -- +// CHECK-31-NEXT: -- (Test24::B, 0) vtable address -- +// CHECK-31-NEXT: 4 | void Test24::A::f() + +// CHECK-31: Construction vtable for ('Test24::C', 8) in 'Test24::D' (9 entries). +// CHECK-31-NEXT: 0 | vbase_offset (-8) +// CHECK-31-NEXT: 1 | vcall_offset (-8) +// CHECK-31-NEXT: 2 | offset_to_top (0) +// CHECK-31-NEXT: 3 | Test24::C RTTI +// CHECK-31-NEXT: -- (Test24::C, 8) vtable address -- +// CHECK-31-NEXT: 4 | [unused] void Test24::A::f() +// CHECK-31-NEXT: 5 | vcall_offset (0) +// CHECK-31-NEXT: 6 | offset_to_top (8) +// CHECK-31-NEXT: 7 | Test24::C RTTI +// CHECK-31-NEXT: -- (Test24::A, 0) vtable address -- +// CHECK-31-NEXT: 8 | void Test24::A::f() +struct D : B, C { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test25 { + +// This mainly tests that we don't assert on this class hierarchy. + +struct V { + virtual void f(); +}; + +struct A : virtual V { }; +struct B : virtual V { }; + +// CHECK-32: Vtable for 'Test25::C' (11 entries). +// CHECK-32-NEXT: 0 | vbase_offset (0) +// CHECK-32-NEXT: 1 | vcall_offset (0) +// CHECK-32-NEXT: 2 | offset_to_top (0) +// CHECK-32-NEXT: 3 | Test25::C RTTI +// CHECK-32-NEXT: -- (Test25::A, 0) vtable address -- +// CHECK-32-NEXT: -- (Test25::C, 0) vtable address -- +// CHECK-32-NEXT: -- (Test25::V, 0) vtable address -- +// CHECK-32-NEXT: 4 | void Test25::V::f() +// CHECK-32-NEXT: 5 | void Test25::C::g() +// CHECK-32-NEXT: 6 | vbase_offset (-8) +// CHECK-32-NEXT: 7 | vcall_offset (-8) +// CHECK-32-NEXT: 8 | offset_to_top (-8) +// CHECK-32-NEXT: 9 | Test25::C RTTI +// CHECK-32-NEXT: -- (Test25::B, 8) vtable address -- +// CHECK-32-NEXT: 10 | [unused] void Test25::V::f() + +// CHECK-32: Construction vtable for ('Test25::A', 0) in 'Test25::C' (5 entries). +// CHECK-32-NEXT: 0 | vbase_offset (0) +// CHECK-32-NEXT: 1 | vcall_offset (0) +// CHECK-32-NEXT: 2 | offset_to_top (0) +// CHECK-32-NEXT: 3 | Test25::A RTTI +// CHECK-32-NEXT: -- (Test25::A, 0) vtable address -- +// CHECK-32-NEXT: -- (Test25::V, 0) vtable address -- +// CHECK-32-NEXT: 4 | void Test25::V::f() + +// CHECK-32: Construction vtable for ('Test25::B', 8) in 'Test25::C' (9 entries). +// CHECK-32-NEXT: 0 | vbase_offset (-8) +// CHECK-32-NEXT: 1 | vcall_offset (-8) +// CHECK-32-NEXT: 2 | offset_to_top (0) +// CHECK-32-NEXT: 3 | Test25::B RTTI +// CHECK-32-NEXT: -- (Test25::B, 8) vtable address -- +// CHECK-32-NEXT: 4 | [unused] void Test25::V::f() +// CHECK-32-NEXT: 5 | vcall_offset (0) +// CHECK-32-NEXT: 6 | offset_to_top (8) +// CHECK-32-NEXT: 7 | Test25::B RTTI +// CHECK-32-NEXT: -- (Test25::V, 0) vtable address -- +// CHECK-32-NEXT: 8 | void Test25::V::f() +struct C : A, virtual V, B { + virtual void g(); +}; +void C::g() { } + +} + +namespace Test26 { + +// Test that we generate the right number of entries in the C-in-D construction vtable, and that +// we don't mark A::a as unused. + +struct A { + virtual void a(); +}; + +struct B { + virtual void c(); +}; + +struct C : virtual A { + virtual void b(); +}; + +// CHECK-33: Vtable for 'Test26::D' (15 entries). +// CHECK-33-NEXT: 0 | vbase_offset (8) +// CHECK-33-NEXT: 1 | vbase_offset (8) +// CHECK-33-NEXT: 2 | vbase_offset (0) +// CHECK-33-NEXT: 3 | vcall_offset (0) +// CHECK-33-NEXT: 4 | offset_to_top (0) +// CHECK-33-NEXT: 5 | Test26::D RTTI +// CHECK-33-NEXT: -- (Test26::B, 0) vtable address -- +// CHECK-33-NEXT: -- (Test26::D, 0) vtable address -- +// CHECK-33-NEXT: 6 | void Test26::B::c() +// CHECK-33-NEXT: 7 | void Test26::D::d() +// CHECK-33-NEXT: 8 | vcall_offset (0) +// CHECK-33-NEXT: 9 | vbase_offset (0) +// CHECK-33-NEXT: 10 | vcall_offset (0) +// CHECK-33-NEXT: 11 | offset_to_top (-8) +// CHECK-33-NEXT: 12 | Test26::D RTTI +// CHECK-33-NEXT: -- (Test26::A, 8) vtable address -- +// CHECK-33-NEXT: -- (Test26::C, 8) vtable address -- +// CHECK-33-NEXT: 13 | void Test26::A::a() +// CHECK-33-NEXT: 14 | void Test26::C::b() + +// CHECK-33: Construction vtable for ('Test26::C', 8) in 'Test26::D' (7 entries). +// CHECK-33-NEXT: 0 | vcall_offset (0) +// CHECK-33-NEXT: 1 | vbase_offset (0) +// CHECK-33-NEXT: 2 | vcall_offset (0) +// CHECK-33-NEXT: 3 | offset_to_top (0) +// CHECK-33-NEXT: 4 | Test26::C RTTI +// CHECK-33-NEXT: -- (Test26::A, 8) vtable address -- +// CHECK-33-NEXT: -- (Test26::C, 8) vtable address -- +// CHECK-33-NEXT: 5 | void Test26::A::a() +// CHECK-33-NEXT: 6 | void Test26::C::b() +class D : virtual B, virtual C { + virtual void d(); +}; +void D::d() { } + +} + +namespace Test27 { + +// Test that we don't generate a secondary vtable for C in the D-in-E vtable, since +// C doesn't have any virtual bases. + +struct A { + virtual void a(); +}; + +struct B { + virtual void b(); +}; + +struct C { + virtual void c(); +}; + +struct D : A, virtual B, C { + virtual void d(); +}; + +// CHECK-34: Vtable for 'Test27::E' (13 entries). +// CHECK-34-NEXT: 0 | vbase_offset (16) +// CHECK-34-NEXT: 1 | offset_to_top (0) +// CHECK-34-NEXT: 2 | Test27::E RTTI +// CHECK-34-NEXT: -- (Test27::A, 0) vtable address -- +// CHECK-34-NEXT: -- (Test27::D, 0) vtable address -- +// CHECK-34-NEXT: -- (Test27::E, 0) vtable address -- +// CHECK-34-NEXT: 3 | void Test27::A::a() +// CHECK-34-NEXT: 4 | void Test27::D::d() +// CHECK-34-NEXT: 5 | void Test27::E::e() +// CHECK-34-NEXT: 6 | offset_to_top (-8) +// CHECK-34-NEXT: 7 | Test27::E RTTI +// CHECK-34-NEXT: -- (Test27::C, 8) vtable address -- +// CHECK-34-NEXT: 8 | void Test27::C::c() +// CHECK-34-NEXT: 9 | vcall_offset (0) +// CHECK-34-NEXT: 10 | offset_to_top (-16) +// CHECK-34-NEXT: 11 | Test27::E RTTI +// CHECK-34-NEXT: -- (Test27::B, 16) vtable address -- +// CHECK-34-NEXT: 12 | void Test27::B::b() + +// CHECK-34: Construction vtable for ('Test27::D', 0) in 'Test27::E' (9 entries). +// CHECK-34-NEXT: 0 | vbase_offset (16) +// CHECK-34-NEXT: 1 | offset_to_top (0) +// CHECK-34-NEXT: 2 | Test27::D RTTI +// CHECK-34-NEXT: -- (Test27::A, 0) vtable address -- +// CHECK-34-NEXT: -- (Test27::D, 0) vtable address -- +// CHECK-34-NEXT: 3 | void Test27::A::a() +// CHECK-34-NEXT: 4 | void Test27::D::d() +// CHECK-34-NEXT: 5 | vcall_offset (0) +// CHECK-34-NEXT: 6 | offset_to_top (-16) +// CHECK-34-NEXT: 7 | Test27::D RTTI +// CHECK-34-NEXT: -- (Test27::B, 16) vtable address -- +// CHECK-34-NEXT: 8 | void Test27::B::b() +struct E : D { + virtual void e(); +}; +void E::e() { } + +} + +namespace Test28 { + +// Check that we do include the vtable for B in the D-in-E construction vtable, since +// B is a base class of a virtual base (C). + +struct A { + virtual void a(); +}; + +struct B { + virtual void b(); +}; + +struct C : A, B { + virtual void c(); +}; + +struct D : virtual C { +}; + +// CHECK-35: Vtable for 'Test28::E' (14 entries). +// CHECK-35-NEXT: 0 | vbase_offset (8) +// CHECK-35-NEXT: 1 | offset_to_top (0) +// CHECK-35-NEXT: 2 | Test28::E RTTI +// CHECK-35-NEXT: -- (Test28::D, 0) vtable address -- +// CHECK-35-NEXT: -- (Test28::E, 0) vtable address -- +// CHECK-35-NEXT: 3 | void Test28::E::e() +// CHECK-35-NEXT: 4 | vcall_offset (8) +// CHECK-35-NEXT: 5 | vcall_offset (0) +// CHECK-35-NEXT: 6 | vcall_offset (0) +// CHECK-35-NEXT: 7 | offset_to_top (-8) +// CHECK-35-NEXT: 8 | Test28::E RTTI +// CHECK-35-NEXT: -- (Test28::A, 8) vtable address -- +// CHECK-35-NEXT: -- (Test28::C, 8) vtable address -- +// CHECK-35-NEXT: 9 | void Test28::A::a() +// CHECK-35-NEXT: 10 | void Test28::C::c() +// CHECK-35-NEXT: 11 | offset_to_top (-16) +// CHECK-35-NEXT: 12 | Test28::E RTTI +// CHECK-35-NEXT: -- (Test28::B, 16) vtable address -- +// CHECK-35-NEXT: 13 | void Test28::B::b() + +// CHECK-35: Construction vtable for ('Test28::D', 0) in 'Test28::E' (13 entries). +// CHECK-35-NEXT: 0 | vbase_offset (8) +// CHECK-35-NEXT: 1 | offset_to_top (0) +// CHECK-35-NEXT: 2 | Test28::D RTTI +// CHECK-35-NEXT: -- (Test28::D, 0) vtable address -- +// CHECK-35-NEXT: 3 | vcall_offset (8) +// CHECK-35-NEXT: 4 | vcall_offset (0) +// CHECK-35-NEXT: 5 | vcall_offset (0) +// CHECK-35-NEXT: 6 | offset_to_top (-8) +// CHECK-35-NEXT: 7 | Test28::D RTTI +// CHECK-35-NEXT: -- (Test28::A, 8) vtable address -- +// CHECK-35-NEXT: -- (Test28::C, 8) vtable address -- +// CHECK-35-NEXT: 8 | void Test28::A::a() +// CHECK-35-NEXT: 9 | void Test28::C::c() +// CHECK-35-NEXT: 10 | offset_to_top (-16) +// CHECK-35-NEXT: 11 | Test28::D RTTI +// CHECK-35-NEXT: -- (Test28::B, 16) vtable address -- +// CHECK-35-NEXT: 12 | void Test28::B::b() +struct E : D { + virtual void e(); +}; +void E::e() { } + +} + +namespace Test29 { + +// Test that the covariant return thunk for B::f will have a virtual 'this' adjustment, +// matching gcc. + +struct V1 { }; +struct V2 : virtual V1 { }; + +struct A { + virtual V1 *f(); +}; + +// CHECK-36: Vtable for 'Test29::B' (6 entries). +// CHECK-36-NEXT: 0 | vbase_offset (0) +// CHECK-36-NEXT: 1 | vcall_offset (0) +// CHECK-36-NEXT: 2 | offset_to_top (0) +// CHECK-36-NEXT: 3 | Test29::B RTTI +// CHECK-36-NEXT: -- (Test29::A, 0) vtable address -- +// CHECK-36-NEXT: -- (Test29::B, 0) vtable address -- +// CHECK-36-NEXT: 4 | Test29::V2 *Test29::B::f() +// CHECK-36-NEXT: [return adjustment: 0 non-virtual, -24 vbase offset offset] +// CHECK-36-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +// CHECK-36-NEXT: 5 | Test29::V2 *Test29::B::f() +struct B : virtual A { + virtual V2 *f(); +}; +V2 *B::f() { return 0; } + +} + +namespace Test30 { + +// Test that we don't assert when generating a vtable for F. +struct A { }; + +struct B : virtual A { + int i; +}; + +struct C { + virtual void f(); +}; + +struct D : virtual C, B { }; +struct E : virtual D { }; + +struct F : E { + virtual void f(); +}; +void F::f() { } + +} + +namespace Test31 { + +// Test that we don't add D::f twice to the primary vtable. +struct A { + int a; +}; + +struct B { + virtual void f(); +}; + +struct C : A, virtual B { + virtual void f(); +}; + +// CHECK-37: Vtable for 'Test31::D' (11 entries). +// CHECK-37-NEXT: 0 | vbase_offset (0) +// CHECK-37-NEXT: 1 | vbase_offset (8) +// CHECK-37-NEXT: 2 | vcall_offset (0) +// CHECK-37-NEXT: 3 | offset_to_top (0) +// CHECK-37-NEXT: 4 | Test31::D RTTI +// CHECK-37-NEXT: -- (Test31::B, 0) vtable address -- +// CHECK-37-NEXT: -- (Test31::D, 0) vtable address -- +// CHECK-37-NEXT: 5 | void Test31::D::f() +// CHECK-37-NEXT: 6 | vbase_offset (-8) +// CHECK-37-NEXT: 7 | vcall_offset (-8) +// CHECK-37-NEXT: 8 | offset_to_top (-8) +// CHECK-37-NEXT: 9 | Test31::D RTTI +// CHECK-37-NEXT: -- (Test31::C, 8) vtable address -- +// CHECK-37-NEXT: 10 | void Test31::D::f() +// CHECK-37-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +struct D : virtual C { + virtual void f(); +}; +void D::f() { } + +} + +namespace Test32 { + +// Check that we correctly lay out the virtual bases of 'Test32::D'. + +struct A { + virtual void f(); +}; + +struct B : virtual A { }; +struct C : A, virtual B { }; +struct D : virtual B { }; + +// CHECK-38: Virtual base offset offsets for 'Test32::E' (3 entries). +// CHECK-38-NEXT: Test32::A | -32 +// CHECK-38-NEXT: Test32::B | -24 +// CHECK-38-NEXT: Test32::D | -40 +struct E : C, virtual D { + virtual void f(); +}; +void E::f() { } + +} + +namespace Test33 { + +// Test that we don't emit too many vcall offsets in 'Test32::F'. + +struct A { + virtual void a(); +}; + +struct B { + virtual void b(); +}; + +struct C : virtual A, virtual B { + virtual void c(); +}; + +struct D : virtual C { }; + +struct E : A, D { + virtual void e(); +}; + +// CHECK-39: Vtable for 'Test33::F' (30 entries). +// CHECK-39-NEXT: 0 | vbase_offset (24) +// CHECK-39-NEXT: 1 | vbase_offset (16) +// CHECK-39-NEXT: 2 | vbase_offset (16) +// CHECK-39-NEXT: 3 | vbase_offset (8) +// CHECK-39-NEXT: 4 | offset_to_top (0) +// CHECK-39-NEXT: 5 | Test33::F RTTI +// CHECK-39-NEXT: -- (Test33::A, 0) vtable address -- +// CHECK-39-NEXT: -- (Test33::F, 0) vtable address -- +// CHECK-39-NEXT: 6 | void Test33::A::a() +// CHECK-39-NEXT: 7 | void Test33::F::f() +// CHECK-39-NEXT: 8 | vcall_offset (0) +// CHECK-39-NEXT: 9 | vcall_offset (0) +// CHECK-39-NEXT: 10 | vbase_offset (16) +// CHECK-39-NEXT: 11 | vbase_offset (8) +// CHECK-39-NEXT: 12 | vbase_offset (8) +// CHECK-39-NEXT: 13 | offset_to_top (-8) +// CHECK-39-NEXT: 14 | Test33::F RTTI +// CHECK-39-NEXT: -- (Test33::A, 8) vtable address -- +// CHECK-39-NEXT: -- (Test33::E, 8) vtable address -- +// CHECK-39-NEXT: 15 | void Test33::A::a() +// CHECK-39-NEXT: 16 | void Test33::E::e() +// CHECK-39-NEXT: 17 | vbase_offset (0) +// CHECK-39-NEXT: 18 | vcall_offset (0) +// CHECK-39-NEXT: 19 | vbase_offset (8) +// CHECK-39-NEXT: 20 | vbase_offset (0) +// CHECK-39-NEXT: 21 | vcall_offset (0) +// CHECK-39-NEXT: 22 | offset_to_top (-16) +// CHECK-39-NEXT: 23 | Test33::F RTTI +// CHECK-39-NEXT: -- (Test33::A, 16) vtable address -- +// CHECK-39-NEXT: -- (Test33::C, 16) vtable address -- +// CHECK-39-NEXT: -- (Test33::D, 16) vtable address -- +// CHECK-39-NEXT: 24 | void Test33::A::a() +// CHECK-39-NEXT: 25 | void Test33::C::c() +// CHECK-39-NEXT: 26 | vcall_offset (0) +// CHECK-39-NEXT: 27 | offset_to_top (-24) +// CHECK-39-NEXT: 28 | Test33::F RTTI +// CHECK-39-NEXT: -- (Test33::B, 24) vtable address -- +// CHECK-39-NEXT: 29 | void Test33::B::b() +struct F : virtual E, A { + virtual void f(); +}; +void F::f() { } + +} + +namespace Test34 { + +// Test that we lay out the construction vtable for 'Test34::E' in 'Test34::F' correctly. + +struct A { + virtual void a(); +}; +struct B : virtual A { }; + +struct C : B, A { + virtual void c(); +}; + +struct D : A, C { }; + +struct E : virtual D { + virtual void e(); +}; + +// CHECK-40: Construction vtable for ('Test34::E', 0) in 'Test34::F' (22 entries). +// CHECK-40-NEXT: 0 | vbase_offset (0) +// CHECK-40-NEXT: 1 | vbase_offset (8) +// CHECK-40-NEXT: 2 | vcall_offset (0) +// CHECK-40-NEXT: 3 | offset_to_top (0) +// CHECK-40-NEXT: 4 | Test34::E RTTI +// CHECK-40-NEXT: -- (Test34::A, 0) vtable address -- +// CHECK-40-NEXT: -- (Test34::E, 0) vtable address -- +// CHECK-40-NEXT: 5 | void Test34::A::a() +// CHECK-40-NEXT: 6 | void Test34::E::e() +// CHECK-40-NEXT: 7 | vcall_offset (8) +// CHECK-40-NEXT: 8 | vcall_offset (0) +// CHECK-40-NEXT: 9 | vbase_offset (-8) +// CHECK-40-NEXT: 10 | offset_to_top (-8) +// CHECK-40-NEXT: 11 | Test34::E RTTI +// CHECK-40-NEXT: -- (Test34::A, 8) vtable address -- +// CHECK-40-NEXT: -- (Test34::D, 8) vtable address -- +// CHECK-40-NEXT: 12 | void Test34::A::a() +// CHECK-40-NEXT: 13 | vbase_offset (-16) +// CHECK-40-NEXT: 14 | vcall_offset (-16) +// CHECK-40-NEXT: 15 | offset_to_top (-16) +// CHECK-40-NEXT: 16 | Test34::E RTTI +// CHECK-40-NEXT: -- (Test34::B, 16) vtable address -- +// CHECK-40-NEXT: -- (Test34::C, 16) vtable address -- +// CHECK-40-NEXT: 17 | [unused] void Test34::A::a() +// CHECK-40-NEXT: 18 | void Test34::C::c() +// CHECK-40-NEXT: 19 | offset_to_top (-24) +// CHECK-40-NEXT: 20 | Test34::E RTTI +// CHECK-40-NEXT: -- (Test34::A, 24) vtable address -- +// CHECK-40-NEXT: 21 | void Test34::A::a() +struct F : E { + virtual void f(); +}; +void F::f() { } + +} + +namespace Test35 { + +// Test that we lay out the virtual bases of 'Test35::H' in the correct order. + +struct A { + virtual void a(); + + int i; +}; + +struct B : virtual A { + virtual void b(); +}; + +struct C { + virtual void c(); +}; + +struct D : C, virtual B { + virtual void d(); +}; + +struct E : D { + virtual void e(); + + bool b; +}; + +struct F : virtual D { }; +struct G : virtual E { }; + +// CHECK-41: Vtable for 'Test35::H' (32 entries). +// CHECK-41-NEXT: 0 | vbase_offset (32) +// CHECK-41-NEXT: 1 | vbase_offset (0) +// CHECK-41-NEXT: 2 | vcall_offset (0) +// CHECK-41-NEXT: 3 | vcall_offset (0) +// CHECK-41-NEXT: 4 | vbase_offset (16) +// CHECK-41-NEXT: 5 | vbase_offset (8) +// CHECK-41-NEXT: 6 | offset_to_top (0) +// CHECK-41-NEXT: 7 | Test35::H RTTI +// CHECK-41-NEXT: -- (Test35::C, 0) vtable address -- +// CHECK-41-NEXT: -- (Test35::D, 0) vtable address -- +// CHECK-41-NEXT: -- (Test35::F, 0) vtable address -- +// CHECK-41-NEXT: -- (Test35::H, 0) vtable address -- +// CHECK-41-NEXT: 8 | void Test35::C::c() +// CHECK-41-NEXT: 9 | void Test35::D::d() +// CHECK-41-NEXT: 10 | void Test35::H::h() +// CHECK-41-NEXT: 11 | vbase_offset (0) +// CHECK-41-NEXT: 12 | vbase_offset (24) +// CHECK-41-NEXT: 13 | vcall_offset (0) +// CHECK-41-NEXT: 14 | vbase_offset (8) +// CHECK-41-NEXT: 15 | offset_to_top (-8) +// CHECK-41-NEXT: 16 | Test35::H RTTI +// CHECK-41-NEXT: -- (Test35::B, 8) vtable address -- +// CHECK-41-NEXT: -- (Test35::G, 8) vtable address -- +// CHECK-41-NEXT: 17 | void Test35::B::b() +// CHECK-41-NEXT: 18 | vcall_offset (0) +// CHECK-41-NEXT: 19 | offset_to_top (-16) +// CHECK-41-NEXT: 20 | Test35::H RTTI +// CHECK-41-NEXT: -- (Test35::A, 16) vtable address -- +// CHECK-41-NEXT: 21 | void Test35::A::a() +// CHECK-41-NEXT: 22 | vcall_offset (0) +// CHECK-41-NEXT: 23 | vcall_offset (0) +// CHECK-41-NEXT: 24 | vcall_offset (0) +// CHECK-41-NEXT: 25 | vbase_offset (-16) +// CHECK-41-NEXT: 26 | vbase_offset (-24) +// CHECK-41-NEXT: 27 | offset_to_top (-32) +// CHECK-41-NEXT: 28 | Test35::H RTTI +// CHECK-41-NEXT: -- (Test35::C, 32) vtable address -- +// CHECK-41-NEXT: -- (Test35::D, 32) vtable address -- +// CHECK-41-NEXT: -- (Test35::E, 32) vtable address -- +// CHECK-41-NEXT: 29 | void Test35::C::c() +// CHECK-41-NEXT: 30 | void Test35::D::d() +// CHECK-41-NEXT: 31 | void Test35::E::e() + +// CHECK-41: Virtual base offset offsets for 'Test35::H' (4 entries). +// CHECK-41-NEXT: Test35::A | -32 +// CHECK-41-NEXT: Test35::B | -24 +// CHECK-41-NEXT: Test35::D | -56 +// CHECK-41-NEXT: Test35::E | -64 +struct H : F, G { + virtual void h(); +}; +void H::h() { } + +} + +namespace Test36 { + +// Test that we don't mark B::f as unused in the vtable for D. + +struct A { + virtual void f(); +}; + +struct B : virtual A { }; + +struct C : virtual A { + virtual void f(); +}; + +// CHECK-42: Vtable for 'Test36::D' (12 entries). +// CHECK-42-NEXT: 0 | vbase_offset (8) +// CHECK-42-NEXT: 1 | vbase_offset (8) +// CHECK-42-NEXT: 2 | vcall_offset (0) +// CHECK-42-NEXT: 3 | offset_to_top (0) +// CHECK-42-NEXT: 4 | Test36::D RTTI +// CHECK-42-NEXT: -- (Test36::C, 0) vtable address -- +// CHECK-42-NEXT: -- (Test36::D, 0) vtable address -- +// CHECK-42-NEXT: 5 | void Test36::C::f() +// CHECK-42-NEXT: 6 | void Test36::D::g() +// CHECK-42-NEXT: 7 | vbase_offset (0) +// CHECK-42-NEXT: 8 | vcall_offset (-8) +// CHECK-42-NEXT: 9 | offset_to_top (-8) +// CHECK-42-NEXT: 10 | Test36::D RTTI +// CHECK-42-NEXT: -- (Test36::A, 8) vtable address -- +// CHECK-42-NEXT: -- (Test36::B, 8) vtable address -- +// CHECK-42-NEXT: 11 | void Test36::C::f() +// CHECK-42-NEXT: [this adjustment: 0 non-virtual, -24 vcall offset offset] +struct D : virtual B, C { + virtual void g(); +}; +void D::g() { } + +} + +namespace Test37 { + +// Test that we give C::f the right vtable index. (PR9660). +struct A { + virtual A* f() = 0; +}; + +struct B : virtual A { + virtual B* f(); +}; + +// CHECK-43: VTable indices for 'Test37::C' (1 entries). +// CHECK-43-NEXT: 1 | Test37::C *Test37::C::f() +struct C : B { + virtual C* f(); +}; + +C* C::f() { return 0; } + +} + +// rdar://problem/10959710 +namespace Test38 { + struct A { + virtual void *foo(); + virtual const void *foo() const; + }; + + // CHECK-44: Vtable for 'Test38::B' (7 entries). + // CHECK-44-NEXT: 0 | vbase_offset (0) + // CHECK-44-NEXT: 1 | vcall_offset (0) + // CHECK-44-NEXT: 2 | vcall_offset (0) + // CHECK-44-NEXT: 3 | offset_to_top (0) + // CHECK-44-NEXT: 4 | Test38::B RTTI + // CHECK-44-NEXT: -- (Test38::A, 0) vtable address -- + // CHECK-44-NEXT: -- (Test38::B, 0) vtable address -- + // CHECK-44-NEXT: 5 | void *Test38::B::foo() + // CHECK-44-NEXT: 6 | const void *Test38::B::foo() const + class B : virtual public A { + void *foo(); + const void *foo() const; + }; + + void *B::foo() { return 0; } +} diff --git a/clang/test/CodeGenCXX/vtable-linkage.cpp b/clang/test/CodeGenCXX/vtable-linkage.cpp new file mode 100644 index 0000000..4633a3f --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-linkage.cpp @@ -0,0 +1,216 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o %t +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -fhidden-weak-vtables -emit-llvm -o %t.hidden +// RUN: FileCheck --check-prefix=CHECK-1 %s < %t +// RUN: FileCheck --check-prefix=CHECK-2 %s < %t +// RUN: FileCheck --check-prefix=CHECK-2-HIDDEN %s < %t.hidden +// RUN: FileCheck --check-prefix=CHECK-3 %s < %t +// RUN: FileCheck --check-prefix=CHECK-4 %s < %t +// RUN: FileCheck --check-prefix=CHECK-5 %s < %t +// RUN: FileCheck --check-prefix=CHECK-5-HIDDEN %s < %t.hidden +// RUN: FileCheck --check-prefix=CHECK-6 %s < %t +// RUN: FileCheck --check-prefix=CHECK-6-HIDDEN %s < %t.hidden +// RUN: FileCheck --check-prefix=CHECK-7 %s < %t +// RUN: FileCheck --check-prefix=CHECK-8 %s < %t +// RUN: FileCheck --check-prefix=CHECK-9 %s < %t +// RUN: FileCheck --check-prefix=CHECK-10 %s < %t +// RUN: FileCheck --check-prefix=CHECK-11 %s < %t +// RUN: FileCheck --check-prefix=CHECK-12 %s < %t +// RUN: FileCheck --check-prefix=CHECK-13 %s < %t + +namespace { + struct A { + virtual void f() { } + }; +} + +void f() { A b; } + +struct B { + B(); + virtual void f(); +}; + +B::B() { } + +struct C : virtual B { + C(); + virtual void f() { } +}; + +C::C() { } + +struct D { + virtual void f(); +}; + +void D::f() { } + +static struct : D { } e; + +// The destructor is the key function. +template<typename T> +struct E { + virtual ~E(); +}; + +template<typename T> E<T>::~E() { } + +// Anchor is the key function +template<> +struct E<char> { + virtual void anchor(); +}; + +void E<char>::anchor() { } + +template struct E<short>; +extern template struct E<int>; + +void use_E() { + E<int> ei; + (void)ei; + E<long> el; + (void)el; +} + +// No key function +template<typename T> +struct F { + virtual void foo() { } +}; + +// No key function +template<> +struct F<char> { + virtual void foo() { } +}; + +template struct F<short>; +extern template struct F<int>; + +void use_F() { + F<char> fc; + fc.foo(); + F<int> fi; + fi.foo(); + F<long> fl; + (void)fl; +} + +// B has a key function that is not defined in this translation unit so its vtable +// has external linkage. +// CHECK-1: @_ZTV1B = external unnamed_addr constant + +// C has no key function, so its vtable should have weak_odr linkage +// and hidden visibility (rdar://problem/7523229). +// CHECK-2: @_ZTV1C = linkonce_odr unnamed_addr constant +// CHECK-2: @_ZTS1C = linkonce_odr constant +// CHECK-2: @_ZTI1C = linkonce_odr unnamed_addr constant +// CHECK-2: @_ZTT1C = linkonce_odr unnamed_addr constant +// CHECK-2-HIDDEN: @_ZTV1C = linkonce_odr hidden unnamed_addr constant +// CHECK-2-HIDDEN: @_ZTS1C = linkonce_odr constant +// CHECK-2-HIDDEN: @_ZTI1C = linkonce_odr hidden unnamed_addr constant +// CHECK-2-HIDDEN: @_ZTT1C = linkonce_odr hidden unnamed_addr constant + +// D has a key function that is defined in this translation unit so its vtable is +// defined in the translation unit. +// CHECK-3: @_ZTV1D = unnamed_addr constant +// CHECK-3: @_ZTS1D = constant +// CHECK-3: @_ZTI1D = unnamed_addr constant + +// E<char> is an explicit specialization with a key function defined +// in this translation unit, so its vtable should have external +// linkage. +// CHECK-4: @_ZTV1EIcE = unnamed_addr constant +// CHECK-4: @_ZTS1EIcE = constant +// CHECK-4: @_ZTI1EIcE = unnamed_addr constant + +// E<short> is an explicit template instantiation with a key function +// defined in this translation unit, so its vtable should have +// weak_odr linkage. +// CHECK-5: @_ZTV1EIsE = weak_odr unnamed_addr constant +// CHECK-5: @_ZTS1EIsE = weak_odr constant +// CHECK-5: @_ZTI1EIsE = weak_odr unnamed_addr constant +// CHECK-5-HIDDEN: @_ZTV1EIsE = weak_odr unnamed_addr constant +// CHECK-5-HIDDEN: @_ZTS1EIsE = weak_odr constant +// CHECK-5-HIDDEN: @_ZTI1EIsE = weak_odr unnamed_addr constant + +// F<short> is an explicit template instantiation without a key +// function, so its vtable should have weak_odr linkage +// CHECK-6: @_ZTV1FIsE = weak_odr unnamed_addr constant +// CHECK-6: @_ZTS1FIsE = weak_odr constant +// CHECK-6: @_ZTI1FIsE = weak_odr unnamed_addr constant +// CHECK-6-HIDDEN: @_ZTV1FIsE = weak_odr unnamed_addr constant +// CHECK-6-HIDDEN: @_ZTS1FIsE = weak_odr constant +// CHECK-6-HIDDEN: @_ZTI1FIsE = weak_odr unnamed_addr constant + +// E<long> is an implicit template instantiation with a key function +// defined in this translation unit, so its vtable should have +// linkonce_odr linkage. +// CHECK-7: @_ZTV1EIlE = linkonce_odr unnamed_addr constant +// CHECK-7: @_ZTS1EIlE = linkonce_odr constant +// CHECK-7: @_ZTI1EIlE = linkonce_odr unnamed_addr constant + +// F<long> is an implicit template instantiation with no key function, +// so its vtable should have linkonce_odr linkage. +// CHECK-8: @_ZTV1FIlE = linkonce_odr unnamed_addr constant +// CHECK-8: @_ZTS1FIlE = linkonce_odr constant +// CHECK-8: @_ZTI1FIlE = linkonce_odr unnamed_addr constant + +// F<int> is an explicit template instantiation declaration without a +// key function, so its vtable should have external linkage. +// CHECK-9: @_ZTV1FIiE = external unnamed_addr constant + +// E<int> is an explicit template instantiation declaration. It has a +// key function that is not instantiated, so we should only reference +// its vtable, not define it. +// CHECK-10: @_ZTV1EIiE = external unnamed_addr constant + +// The anonymous struct for e has no linkage, so the vtable should have +// internal linkage. +// CHECK-11: @"_ZTV3$_0" = internal unnamed_addr constant +// CHECK-11: @"_ZTS3$_0" = internal constant +// CHECK-11: @"_ZTI3$_0" = internal unnamed_addr constant + +// The A vtable should have internal linkage since it is inside an anonymous +// namespace. +// CHECK-12: @_ZTVN12_GLOBAL__N_11AE = internal unnamed_addr constant +// CHECK-12: @_ZTSN12_GLOBAL__N_11AE = internal constant +// CHECK-12: @_ZTIN12_GLOBAL__N_11AE = internal unnamed_addr constant + +// F<char> is an explicit specialization without a key function, so +// its vtable should have linkonce_odr linkage. +// CHECK-13: @_ZTV1FIcE = linkonce_odr unnamed_addr constant +// CHECK-13: @_ZTS1FIcE = linkonce_odr constant +// CHECK-13: @_ZTI1FIcE = linkonce_odr unnamed_addr constant + +// RUN: FileCheck --check-prefix=CHECK-G %s < %t +// +// CHECK-G: @_ZTV1GIiE = linkonce_odr unnamed_addr constant +template <typename T> +class G { +public: + G() {} + virtual void f0(); + virtual void f1(); +}; +template <> +void G<int>::f1() {} +template <typename T> +void G<T>::f0() {} +void G_f0() { new G<int>(); } + +// RUN: FileCheck --check-prefix=CHECK-H %s < %t + +// H<int> has a key function without a body but it's a template instantiation +// so its VTable must be emitted. +// CHECK-H: @_ZTV1HIiE = linkonce_odr unnamed_addr constant +template <typename T> +class H { +public: + virtual ~H(); +}; + +void use_H() { + H<int> h; +} diff --git a/clang/test/CodeGenCXX/vtable-pointer-initialization.cpp b/clang/test/CodeGenCXX/vtable-pointer-initialization.cpp new file mode 100644 index 0000000..9b1eaa5 --- /dev/null +++ b/clang/test/CodeGenCXX/vtable-pointer-initialization.cpp @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +struct Field { + Field(); + ~Field(); +}; + +struct Base { + Base(); + ~Base(); +}; + +struct A : Base { + A(); + ~A(); + + virtual void f(); + + Field field; +}; + +// CHECK: define void @_ZN1AC2Ev(%struct.A* %this) unnamed_addr +// CHECK: call void @_ZN4BaseC2Ev( +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) +// CHECK: call void @_ZN5FieldC1Ev( +// CHECK: ret void +A::A() { } + +// CHECK: define void @_ZN1AD2Ev(%struct.A* %this) unnamed_addr +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1A, i64 0, i64 2) +// CHECK: call void @_ZN5FieldD1Ev( +// CHECK: call void @_ZN4BaseD2Ev( +// CHECK: ret void +A::~A() { } + +struct B : Base { + virtual void f(); + + Field field; +}; + +void f() { B b; } + +// CHECK: define linkonce_odr void @_ZN1BC1Ev(%struct.B* %this) unnamed_addr +// CHECK: call void @_ZN1BC2Ev( + +// CHECK: define linkonce_odr void @_ZN1BD1Ev(%struct.B* %this) unnamed_addr +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) +// CHECK: call void @_ZN5FieldD1Ev( +// CHECK: call void @_ZN4BaseD2Ev( +// CHECK: ret void + +// CHECK: define linkonce_odr void @_ZN1BC2Ev(%struct.B* %this) unnamed_addr +// CHECK: call void @_ZN4BaseC2Ev( +// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTV1B, i64 0, i64 2) +// CHECK: call void @_ZN5FieldC1Ev +// CHECK: ret void diff --git a/clang/test/CodeGenCXX/vtt-layout.cpp b/clang/test/CodeGenCXX/vtt-layout.cpp new file mode 100644 index 0000000..ace7b74 --- /dev/null +++ b/clang/test/CodeGenCXX/vtt-layout.cpp @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s + +// Test1::B should just have a single entry in its VTT, which points to the vtable. +namespace Test1 { +struct A { }; + +struct B : virtual A { + virtual void f(); +}; + +void B::f() { } +} + +// Check that we don't add a secondary virtual pointer for Test2::A, since Test2::A doesn't have any virtual member functions or bases. +namespace Test2 { + struct A { }; + + struct B : A { virtual void f(); }; + struct C : virtual B { }; + + C c; +} + +// This is the sample from the C++ Itanium ABI, p2.6.2. +namespace Test3 { + class A1 { int i; }; + class A2 { int i; virtual void f(); }; + class V1 : public A1, public A2 { int i; }; + class B1 { int i; }; + class B2 { int i; }; + class V2 : public B1, public B2, public virtual V1 { int i; }; + class V3 {virtual void g(); }; + class C1 : public virtual V1 { int i; }; + class C2 : public virtual V3, virtual V2 { int i; }; + class X1 { int i; }; + class C3 : public X1 { int i; }; + class D : public C1, public C2, public C3 { int i; }; + + D d; +} + +// This is the sample from the C++ Itanium ABI, p2.6.2, with the change suggested +// (making A2 a virtual base of V1) +namespace Test4 { + class A1 { int i; }; + class A2 { int i; virtual void f(); }; + class V1 : public A1, public virtual A2 { int i; }; + class B1 { int i; }; + class B2 { int i; }; + class V2 : public B1, public B2, public virtual V1 { int i; }; + class V3 {virtual void g(); }; + class C1 : public virtual V1 { int i; }; + class C2 : public virtual V3, virtual V2 { int i; }; + class X1 { int i; }; + class C3 : public X1 { int i; }; + class D : public C1, public C2, public C3 { int i; }; + + D d; +} + +// CHECK: @_ZTTN5Test11BE = unnamed_addr constant [1 x i8*] [i8* bitcast (i8** getelementptr inbounds ([4 x i8*]* @_ZTVN5Test11BE, i64 0, i64 3) to i8*)] +// CHECK: @_ZTTN5Test41DE = linkonce_odr unnamed_addr constant [19 x i8*] [i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE0_NS_2C1E, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE0_NS_2C1E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE0_NS_2C1E, i64 0, i64 10) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 12) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 15) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTCN5Test41DE16_NS_2C2E, i64 0, i64 18) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 17) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 20) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 13) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 0, i64 13) to i8*), i8* bitcast (i8** getelementptr inbounds ([25 x i8*]* @_ZTVN5Test41DE, i64 1, i64 0) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test41DE40_NS_2V1E, i64 0, i64 3) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test41DE40_NS_2V1E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE72_NS_2V2E, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE72_NS_2V2E, i64 0, i64 7) to i8*), i8* bitcast (i8** getelementptr inbounds ([11 x i8*]* @_ZTCN5Test41DE72_NS_2V2E, i64 0, i64 10) to i8*)] +// CHECK: @_ZTTN5Test31DE = linkonce_odr unnamed_addr constant [13 x i8*] [i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 5) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE0_NS_2C1E, i64 0, i64 3) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE0_NS_2C1E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 6) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 10) to i8*), i8* bitcast (i8** getelementptr inbounds ([14 x i8*]* @_ZTCN5Test31DE16_NS_2C2E, i64 0, i64 13) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 15) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 11) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 0, i64 11) to i8*), i8* bitcast (i8** getelementptr inbounds ([19 x i8*]* @_ZTVN5Test31DE, i64 1, i64 0) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE64_NS_2V2E, i64 0, i64 3) to i8*), i8* bitcast (i8** getelementptr inbounds ([7 x i8*]* @_ZTCN5Test31DE64_NS_2V2E, i64 0, i64 6) to i8*)] +// CHECK: @_ZTTN5Test21CE = linkonce_odr unnamed_addr constant [2 x i8*] [i8* bitcast (i8** getelementptr inbounds ([5 x i8*]* @_ZTVN5Test21CE, i64 0, i64 4) to i8*), i8* bitcast (i8** getelementptr inbounds ([5 x i8*]* @_ZTVN5Test21CE, i64 0, i64 4) to i8*)] diff --git a/clang/test/CodeGenCXX/warn-padded-packed.cpp b/clang/test/CodeGenCXX/warn-padded-packed.cpp new file mode 100644 index 0000000..4203bb3 --- /dev/null +++ b/clang/test/CodeGenCXX/warn-padded-packed.cpp @@ -0,0 +1,76 @@ +// RUN: %clang_cc1 -triple=x86_64-none-none -Wpadded -Wpacked -verify %s -emit-llvm-only + +struct S1 { + char c; + short s; // expected-warning {{padding struct 'S1' with 1 byte to align 's'}} + long l; // expected-warning {{padding struct 'S1' with 4 bytes to align 'l'}} +}; + +struct S2 { // expected-warning {{padding size of 'S2' with 3 bytes to alignment boundary}} + int i; + char c; +}; + +struct S3 { + char c; + int i; +} __attribute__((packed)); + +struct S4 { + int i; // expected-warning {{packed attribute is unnecessary for 'i'}} + char c; +} __attribute__((packed)); + +struct S5 { + char c; + union { + char c; + int i; + } u; // expected-warning {{padding struct 'S5' with 3 bytes to align 'u'}} +}; + +struct S6 { // expected-warning {{padding size of 'S6' with 30 bits to alignment boundary}} + int i : 2; +}; + +struct S7 { // expected-warning {{padding size of 'S7' with 7 bytes to alignment boundary}} + char c; + virtual void m(); +}; + +struct B { + char c; +}; + +struct S8 : B { + int i; // expected-warning {{padding struct 'S8' with 3 bytes to align 'i'}} +}; + +struct S9 { // expected-warning {{packed attribute is unnecessary for 'S9'}} + int x; // expected-warning {{packed attribute is unnecessary for 'x'}} + int y; // expected-warning {{packed attribute is unnecessary for 'y'}} +} __attribute__((packed)); + +struct S10 { // expected-warning {{packed attribute is unnecessary for 'S10'}} + int x; // expected-warning {{packed attribute is unnecessary for 'x'}} + char a,b,c,d; +} __attribute__((packed)); + + +struct S11 { + bool x; + char a,b,c,d; +} __attribute__((packed)); + +struct S12 { + bool b : 1; + char c; // expected-warning {{padding struct 'S12' with 7 bits to align 'c'}} +}; + +struct S13 { // expected-warning {{padding size of 'S13' with 6 bits to alignment boundary}} + char c; + bool b : 10; // expected-warning {{size of bit-field 'b' (10 bits) exceeds the size of its type}} +}; + +// The warnings are emitted when the layout of the structs is computed, so we have to use them. +void f(S1*, S2*, S3*, S4*, S5*, S6*, S7*, S8*, S9*, S10*, S11*, S12*, S13*) { } diff --git a/clang/test/CodeGenCXX/weak-extern-typeinfo.cpp b/clang/test/CodeGenCXX/weak-extern-typeinfo.cpp new file mode 100644 index 0000000..3c3406e --- /dev/null +++ b/clang/test/CodeGenCXX/weak-extern-typeinfo.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s +// rdar://10246395 + +#define WEAK __attribute__ ((weak)) + +class WEAK A { + virtual void foo(); +}; + +class B : public A { + virtual void foo(); +}; +void A::foo() { } +void B::foo() { } + +class T {}; +class T1 {}; + +class C : public T1, public B, public T { + virtual void foo(); +}; +void C::foo() { } + +class V1 : public virtual A { + virtual void foo(); +}; + +class V2 : public virtual V1 { + virtual void foo(); +}; +void V1::foo() { } +void V2::foo() { } + +// CHECK: @_ZTS1A = weak_odr constant +// CHECK: @_ZTI1A = weak_odr unnamed_addr constant +// CHECK: @_ZTS1B = weak_odr constant +// CHECK: @_ZTI1B = weak_odr unnamed_addr constant +// CHECK: @_ZTS1C = weak_odr constant +// CHECK: @_ZTS2T1 = linkonce_odr constant +// CHECK: @_ZTI2T1 = linkonce_odr unnamed_addr constant +// CHECK: @_ZTS1T = linkonce_odr constant +// CHECK: @_ZTI1T = linkonce_odr unnamed_addr constant +// CHECK: @_ZTI1C = weak_odr unnamed_addr constant +// CHECK: @_ZTS2V1 = weak_odr constant +// CHECK: @_ZTI2V1 = weak_odr unnamed_addr constant +// CHECK: @_ZTS2V2 = weak_odr constant +// CHECK: @_ZTI2V2 = weak_odr unnamed_addr constant diff --git a/clang/test/CodeGenCXX/weak-external.cpp b/clang/test/CodeGenCXX/weak-external.cpp new file mode 100644 index 0000000..dad54f6 --- /dev/null +++ b/clang/test/CodeGenCXX/weak-external.cpp @@ -0,0 +1,66 @@ +// RUN: %clang -fexceptions %s -S -emit-llvm -o - | FileCheck %s +// PR4262 + +// CHECK-NOT: _ZNSs12_S_constructIPKcEEPcT_S3_RKSaIcESt20forward_iterator_tag + +// The "basic_string" extern template instantiation declaration is supposed to +// suppress the implicit instantiation of non-inline member functions. Make sure +// that we suppress the implicit instantiation of non-inline member functions +// defined out-of-line. That we aren't instantiating the basic_string +// constructor when we shouldn't be. Such an instantiation forces the implicit +// instantiation of _S_construct<const char*>. Since _S_construct is a member +// template, it's instantiation is *not* suppressed (despite being in +// basic_string<char>), so we would emit it as a weak definition. + +#define _LIBCPP_EXCEPTION_ABI __attribute__ ((__visibility__("default"))) +#define _LIBCPP_INLINE_VISIBILITY __attribute__ ((__visibility__("hidden"), __always_inline__)) +#define _LIBCPP_VISIBLE __attribute__ ((__visibility__("default"))) +#if (__has_feature(cxx_noexcept)) +# define _NOEXCEPT noexcept +# define _NOEXCEPT_(x) noexcept(x) +#else +# define _NOEXCEPT throw() +# define _NOEXCEPT_(x) +#endif + +namespace std // purposefully not using versioning namespace +{ + +template<class charT> struct char_traits; +template<class T> class allocator; +template <class _CharT, + class _Traits = char_traits<_CharT>, + class _Allocator = allocator<_CharT> > + class _LIBCPP_VISIBLE basic_string; +typedef basic_string<char, char_traits<char>, allocator<char> > string; + +class _LIBCPP_EXCEPTION_ABI exception +{ +public: + _LIBCPP_INLINE_VISIBILITY exception() _NOEXCEPT {} + virtual ~exception() _NOEXCEPT; + virtual const char* what() const _NOEXCEPT; +}; + +class _LIBCPP_EXCEPTION_ABI runtime_error + : public exception +{ +private: + void* __imp_; +public: + explicit runtime_error(const string&); + explicit runtime_error(const char*); + + runtime_error(const runtime_error&) _NOEXCEPT; + runtime_error& operator=(const runtime_error&) _NOEXCEPT; + + virtual ~runtime_error() _NOEXCEPT; + + virtual const char* what() const _NOEXCEPT; +}; + +} + +void dummysymbol() { + throw(std::runtime_error("string")); +} diff --git a/clang/test/CodeGenCXX/x86_32-arguments.cpp b/clang/test/CodeGenCXX/x86_32-arguments.cpp new file mode 100644 index 0000000..4404de0 --- /dev/null +++ b/clang/test/CodeGenCXX/x86_32-arguments.cpp @@ -0,0 +1,116 @@ +// RUN: %clang_cc1 -triple i386-apple-darwin9 -emit-llvm -o - %s | FileCheck %s + +// Non-trivial dtors, should both be passed indirectly. +struct S { + ~S(); + short s; +}; + +// CHECK: define void @_Z1fv(%struct.S* noalias sret % +S f() { return S(); } +// CHECK: define void @_Z1f1S(%struct.S*) +void f(S) { } + +// Non-trivial dtors, should both be passed indirectly. +class C { +public: + ~C(); + double c; +}; + +// CHECK: define void @_Z1gv(%class.C* noalias sret % +C g() { return C(); } + +// CHECK: define void @_Z1f1C(%class.C*) +void f(C) { } + + + + +// PR7058 - Missing byval on MI thunk definition. + +// CHECK: define void @_ZThn4_N18BasicAliasAnalysis13getModRefInfoE8CallSite +// ... +// CHECK: %struct.CallSite* byval align 4 %CS) +struct CallSite { + unsigned Ptr; + CallSite(unsigned XX) : Ptr(XX) {} +}; + +struct AliasAnalysis { + virtual void xyz(); + virtual void getModRefInfo(CallSite CS) = 0; +}; + +struct ModulePass { + virtual void xx(); +}; + +struct BasicAliasAnalysis : public ModulePass, public AliasAnalysis { + void getModRefInfo(CallSite CS); +}; + +void BasicAliasAnalysis::getModRefInfo(CallSite CS) { +} + +// Check various single element struct type conditions. +// +// PR7098. + +// CHECK: define i64 @_Z2f0v() +struct s0_0 { int x; }; +struct s0_1 : s0_0 { int* y; }; +s0_1 f0() { return s0_1(); } + +// CHECK: define i32 @_Z2f1v() +struct s1_0 { int x; }; +struct s1_1 : s1_0 { }; +s1_1 f1() { return s1_1(); } + +// CHECK: define double @_Z2f2v() +struct s2_0 { double x; }; +struct s2_1 : s2_0 { }; +s2_1 f2() { return s2_1(); } + +// CHECK: define double @_Z2f3v() +struct s3_0 { }; +struct s3_1 { double x; }; +struct s3_2 : s3_0, s3_1 { }; +s3_2 f3() { return s3_2(); } + +// CHECK: define i64 @_Z2f4v() +struct s4_0 { float x; }; +struct s4_1 { float x; }; +struct s4_2 : s4_0, s4_1 { }; +s4_2 f4() { return s4_2(); } + +// CHECK: define i32* @_Z2f5v() +struct s5 { s5(); int &x; }; +s5 f5() { return s5(); } + +// CHECK: define i32 @_Z4f6_0M2s6i(i32 %a) +// CHECK: define i64 @_Z4f6_1M2s6FivE({ i32, i32 }* byval align 4) +// FIXME: It would be nice to avoid byval on the previous case. +struct s6 {}; +typedef int s6::* s6_mdp; +typedef int (s6::*s6_mfp)(); +s6_mdp f6_0(s6_mdp a) { return a; } +s6_mfp f6_1(s6_mfp a) { return a; } + +// CHECK: define double @_Z2f7v() +struct s7_0 { unsigned : 0; }; +struct s7_1 { double x; }; +struct s7 : s7_0, s7_1 { }; +s7 f7() { return s7(); } + +// CHECK: define void @_Z2f8v(%struct.s8* noalias sret %agg.result) +struct s8_0 { }; +struct s8_1 { double x; }; +struct s8 { s8_0 a; s8_1 b; }; +s8 f8() { return s8(); } + +// CHECK: define void @_Z2f9v(%struct.s9* noalias sret %agg.result) +struct s9_0 { unsigned : 0; }; +struct s9_1 { double x; }; +struct s9 { s9_0 a; s9_1 b; }; +s9 f9() { return s9(); } diff --git a/clang/test/CodeGenCXX/x86_64-arguments.cpp b/clang/test/CodeGenCXX/x86_64-arguments.cpp new file mode 100644 index 0000000..6721803 --- /dev/null +++ b/clang/test/CodeGenCXX/x86_64-arguments.cpp @@ -0,0 +1,183 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s + +// Basic base class test. +struct f0_s0 { unsigned a; }; +struct f0_s1 : public f0_s0 { void *b; }; +// CHECK: define void @_Z2f05f0_s1(i32 %a0.coerce0, i8* %a0.coerce1) +void f0(f0_s1 a0) { } + +// Check with two eight-bytes in base class. +struct f1_s0 { unsigned a; unsigned b; float c; }; +struct f1_s1 : public f1_s0 { float d;}; +// CHECK: define void @_Z2f15f1_s1(i64 %a0.coerce0, <2 x float> %a0.coerce1) +void f1(f1_s1 a0) { } + +// Check with two eight-bytes in base class and merge. +struct f2_s0 { unsigned a; unsigned b; float c; }; +struct f2_s1 : public f2_s0 { char d;}; +// CHECK: define void @_Z2f25f2_s1(i64 %a0.coerce0, i64 %a0.coerce1) +void f2(f2_s1 a0) { } + +// PR5831 +// CHECK: define void @_Z2f34s3_1(i64 %x.coerce) +struct s3_0 {}; +struct s3_1 { struct s3_0 a; long b; }; +void f3(struct s3_1 x) {} + +// CHECK: define i64 @_Z4f4_0M2s4i(i64 %a) +// CHECK: define {{.*}} @_Z4f4_1M2s4FivE(i64 %a.coerce0, i64 %a.coerce1) +struct s4 {}; +typedef int s4::* s4_mdp; +typedef int (s4::*s4_mfp)(); +s4_mdp f4_0(s4_mdp a) { return a; } +s4_mfp f4_1(s4_mfp a) { return a; } + + +namespace PR7523 { +struct StringRef { + char *a; +}; + +void AddKeyword(StringRef, int x); + +void foo() { + // CHECK: define void @_ZN6PR75233fooEv() + // CHECK: call void @_ZN6PR752310AddKeywordENS_9StringRefEi(i8* {{.*}}, i32 4) + AddKeyword(StringRef(), 4); +} +} + +namespace PR7742 { // Also rdar://8250764 + struct s2 { + float a[2]; + }; + + struct c2 : public s2 {}; + + // CHECK: define <2 x float> @_ZN6PR77423fooEPNS_2c2E(%"struct.PR7742::c2"* %P) + c2 foo(c2 *P) { + return c2(); + } + +} + +namespace PR5179 { + struct B {}; + + struct B1 : B { + int* pa; + }; + + struct B2 : B { + B1 b1; + }; + + // CHECK: define i8* @_ZN6PR51793barENS_2B2E(i32* %b2.coerce) + const void *bar(B2 b2) { + return b2.b1.pa; + } +} + +namespace test5 { + struct Xbase { }; + struct Empty { }; + struct Y; + struct X : public Xbase { + Empty empty; + Y f(); + }; + struct Y : public X { + Empty empty; + }; + X getX(); + int takeY(const Y&, int y); + void g() { + // rdar://8340348 - The temporary for the X object needs to have a defined + // address when passed into X::f as 'this'. + takeY(getX().f(), 42); + } + // CHECK: void @_ZN5test51gEv() + // CHECK: alloca %"struct.test5::Y" + // CHECK: alloca %"struct.test5::X" + // CHECK: alloca %"struct.test5::Y" +} + + +// rdar://8360877 +namespace test6 { + struct outer { + int x; + struct epsilon_matcher {} e; + int f; + }; + + int test(outer x) { + return x.x + x.f; + } + // CHECK: define i32 @_ZN5test64testENS_5outerE(i64 %x.coerce0, i32 %x.coerce1) +} + +namespace test7 { + struct StringRef {char* ptr; long len; }; + class A { public: ~A(); }; + A x(A, A, long, long, StringRef) { return A(); } + // Check that the StringRef is passed byval instead of expanded + // (which would split it between registers and memory). + // rdar://problem/9686430 + // CHECK: define void @_ZN5test71xENS_1AES0_llNS_9StringRefE({{.*}} byval align 8) + + // And a couple extra related tests: + A y(A, long double, long, long, StringRef) { return A(); } + // CHECK: define void @_ZN5test71yENS_1AEellNS_9StringRefE({{.*}} i8* + struct StringDouble {char * ptr; double d;}; + A z(A, A, A, A, A, StringDouble) { return A(); } + A zz(A, A, A, A, StringDouble) { return A(); } + // CHECK: define void @_ZN5test71zENS_1AES0_S0_S0_S0_NS_12StringDoubleE({{.*}} byval align 8) + // CHECK: define void @_ZN5test72zzENS_1AES0_S0_S0_NS_12StringDoubleE({{.*}} i8* +} + +namespace test8 { + // CHECK: declare void @_ZN5test83fooENS_1BE(%"class.test8::B"* byval align 8) + class A { + char big[17]; + }; + + class B : public A {}; + + void foo(B b); + void bar() { + B b; + foo(b); + } +} + +// PR4242 +namespace test9 { + // Large enough to be passed indirectly. + struct S { void *data[3]; }; + + struct T { void *data[2]; }; + + // CHECK: define void @_ZN5test93fooEPNS_1SEPNS_1TE([[S:%.*]]*, [[T:%.*]]*) + void foo(S*, T*) {} + + // CHECK: define void @_ZN5test91aEiiiiNS_1TEPv([[S]]* noalias sret {{%.*}}, i32, i32, i32, i32, [[T]]* byval align 8, i8*) + S a(int, int, int, int, T, void*) { + return S(); + } + + // CHECK: define [[S]]* @_ZN5test91bEPNS_1SEiiiiNS_1TEPv([[S]]* {{%.*}}, i32, i32, i32, i32, [[T:%.*]]* byval align 8, i8*) + S* b(S* sret, int, int, int, int, T, void*) { + return sret; + } + + // CHECK: define void @_ZN5test91cEiiiNS_1TEPv([[S]]* noalias sret {{%.*}}, i32, i32, i32, i8* {{%.*}}, i8* {{%.*}}, i8*) + S c(int, int, int, T, void*) { + return S(); + } + + // CHECK: define [[S]]* @_ZN5test91dEPNS_1SEiiiNS_1TEPv([[S]]* {{%.*}}, i32, i32, i32, i8* {{%.*}}, i8* {{%.*}}, i8*) + S* d(S* sret, int, int, int, T, void*) { + return sret; + } +} |