1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
|
// Check that delete exprs call aligned (de)allocation functions if
// -faligned-allocation is passed in both C++11 and C++14.
// RUN: %clang_cc1 -no-opaque-pointers -std=c++11 -fexceptions -fsized-deallocation -faligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
// RUN: %clang_cc1 -no-opaque-pointers -std=c++14 -fexceptions -fsized-deallocation -faligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
// RUN: %clang_cc1 -no-opaque-pointers -std=c++1z -fexceptions -fsized-deallocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
// RUN: %clang_cc1 -no-opaque-pointers -std=c++1z -fexceptions -fsized-deallocation %s -emit-llvm -triple x86_64-windows-msvc -o - | FileCheck %s --check-prefix=CHECK-MS
// Check that we don't used aligned (de)allocation without -faligned-allocation or C++1z.
// RUN: %clang_cc1 -no-opaque-pointers -std=c++14 -DUNALIGNED -fexceptions %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNALIGNED
// RUN: %clang_cc1 -no-opaque-pointers -std=c++1z -DUNALIGNED -fexceptions -fno-aligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNALIGNED
// CHECK-UNALIGNED-NOT: _Znwm_St11align_val_t
// CHECK-UNALIGNED-NOT: _Znam_St11align_val_t
// CHECK-UNALIGNED-NOT: _ZdlPv_St11align_val_t
// CHECK-UNALIGNED-NOT: _ZdaPv_St11align_val_t
// CHECK-UNALIGNED-NOT: _ZdlPvm_St11align_val_t
// CHECK-UNALIGNED-NOT: _ZdaPvm_St11align_val_t
typedef decltype(sizeof(0)) size_t;
namespace std { enum class align_val_t : size_t {}; }
#define OVERALIGNED alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2)
// Global new and delete.
// ======================
struct OVERALIGNED A { A(); int n[128]; };
// CHECK-LABEL: define {{.*}} @_Z2a0v()
// CHECK: %[[ALLOC:.*]] = call noalias noundef nonnull align 32 i8* @_ZnwmSt11align_val_t(i64 noundef 512, i64 noundef 32)
// CHECK: call void @_ZdlPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 32)
// CHECK-MS-LABEL: define {{.*}} @"?a0@@YAPEAXXZ"()
// CHECK-MS: %[[ALLOC:.*]] = call noalias noundef nonnull align 32 i8* @"??2@YAPEAX_KW4align_val_t@std@@@Z"(i64 noundef 512, i64 noundef 32)
// CHECK-MS: cleanuppad
// CHECK-MS: call void @"??3@YAXPEAXW4align_val_t@std@@@Z"(i8* noundef %[[ALLOC]], i64 noundef 32)
void *a0() { return new A; }
// FIXME: Why don't we call the sized array deallocation overload in this case?
// The size is known.
//
// CHECK-LABEL: define {{.*}} @_Z2a1l(
// CHECK: %[[ALLOC:.*]] = call noalias noundef nonnull align 32 i8* @_ZnamSt11align_val_t(i64 noundef %{{.*}}, i64 noundef 32)
// No array cookie.
// CHECK-NOT: store
// CHECK: invoke void @_ZN1AC1Ev(
// CHECK: call void @_ZdaPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 32)
// CHECK-MS-LABEL: define {{.*}} @"?a1@@YAPEAXJ@Z"(
// CHECK-MS: %[[ALLOC:.*]] = call noalias noundef nonnull align 32 i8* @"??_U@YAPEAX_KW4align_val_t@std@@@Z"(i64 noundef %{{.*}}, i64 noundef 32)
// No array cookie.
// CHECK-MS-NOT: store
// CHECK-MS: invoke noundef %struct.A* @"??0A@@QEAA@XZ"(
// CHECK-MS: cleanuppad
// CHECK-MS: call void @"??_V@YAXPEAXW4align_val_t@std@@@Z"(i8* noundef %[[ALLOC]], i64 noundef 32)
void *a1(long n) { return new A[n]; }
// CHECK-LABEL: define {{.*}} @_Z2a2P1A(
// CHECK: call void @_ZdlPvmSt11align_val_t(i8* noundef %{{.*}}, i64 noundef 512, i64 noundef 32) #9
void a2(A *p) { delete p; }
// CHECK-LABEL: define {{.*}} @_Z2a3P1A(
// CHECK: call void @_ZdaPvSt11align_val_t(i8* noundef %{{.*}}, i64 noundef 32) #9
void a3(A *p) { delete[] p; }
// Class-specific usual new and delete.
// ====================================
struct OVERALIGNED B {
B();
// These are just a distraction. We should ignore them.
void *operator new(size_t);
void operator delete(void*, size_t);
void operator delete[](void*, size_t);
void *operator new(size_t, std::align_val_t);
void operator delete(void*, std::align_val_t);
void operator delete[](void*, std::align_val_t);
int n[128];
};
// CHECK-LABEL: define {{.*}} @_Z2b0v()
// CHECK: %[[ALLOC:.*]] = call noundef i8* @_ZN1BnwEmSt11align_val_t(i64 noundef 512, i64 noundef 32)
// CHECK: call void @_ZN1BdlEPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 32)
void *b0() { return new B; }
// CHECK-LABEL: define {{.*}} @_Z2b1l(
// CHECK: %[[ALLOC:.*]] = call noalias noundef nonnull align 32 i8* @_ZnamSt11align_val_t(i64 noundef %{{.*}}, i64 noundef 32)
// No array cookie.
// CHECK-NOT: store
// CHECK: invoke void @_ZN1BC1Ev(
// CHECK: call void @_ZN1BdaEPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 32)
void *b1(long n) { return new B[n]; }
// CHECK-LABEL: define {{.*}} @_Z2b2P1B(
// CHECK: call void @_ZN1BdlEPvSt11align_val_t(i8* noundef %{{.*}}, i64 noundef 32)
void b2(B *p) { delete p; }
// CHECK-LABEL: define {{.*}} @_Z2b3P1B(
// CHECK: call void @_ZN1BdaEPvSt11align_val_t(i8* noundef %{{.*}}, i64 noundef 32)
void b3(B *p) { delete[] p; }
struct OVERALIGNED C {
C();
void *operator new[](size_t, std::align_val_t);
void operator delete[](void*, size_t, std::align_val_t);
// It doesn't matter that we have an unaligned operator delete[] that doesn't
// want the size. What matters is that the aligned one does.
void operator delete[](void*);
};
// This one has an array cookie.
// CHECK-LABEL: define {{.*}} @_Z2b4l(
// CHECK: call {{.*}} @llvm.umul.with.overflow{{.*}}i64 32
// CHECK: call {{.*}} @llvm.uadd.with.overflow{{.*}}i64 32
// CHECK: %[[ALLOC:.*]] = call noundef i8* @_ZN1CnaEmSt11align_val_t(i64 noundef %{{.*}}, i64 noundef 32)
// CHECK: store
// CHECK: call void @_ZN1CC1Ev(
//
// Note, we're still calling a placement allocation function, and there is no
// matching placement operator delete. =(
// FIXME: This seems broken.
// CHECK-NOT: call void @_ZN1CdaEPvmSt11align_val_t(
#ifndef UNALIGNED
void *b4(long n) { return new C[n]; }
#endif
// CHECK-LABEL: define {{.*}} @_Z2b5P1C(
// CHECK: mul i64{{.*}} 32
// CHECK: add i64{{.*}} 32
// CHECK: call void @_ZN1CdaEPvmSt11align_val_t(
void b5(C *p) { delete[] p; }
// Global placement new.
// =====================
struct Q { int n; } q;
void *operator new(size_t, Q);
void *operator new(size_t, std::align_val_t, Q);
void operator delete(void*, Q);
void operator delete(void*, std::align_val_t, Q);
// CHECK-LABEL: define {{.*}} @_Z2c0v(
// CHECK: %[[ALLOC:.*]] = call noundef i8* @_ZnwmSt11align_val_t1Q(i64 noundef 512, i64 noundef 32, i32 %
// CHECK: call void @_ZdlPvSt11align_val_t1Q(i8* noundef %[[ALLOC]], i64 noundef 32, i32 %
void *c0() { return new (q) A; }
// Class-specific placement new.
// =============================
struct OVERALIGNED D {
D();
void *operator new(size_t, Q);
void *operator new(size_t, std::align_val_t, Q);
void operator delete(void*, Q);
void operator delete(void*, std::align_val_t, Q);
};
// CHECK-LABEL: define {{.*}} @_Z2d0v(
// CHECK: %[[ALLOC:.*]] = call noundef i8* @_ZN1DnwEmSt11align_val_t1Q(i64 noundef 32, i64 noundef 32, i32 %
// CHECK: call void @_ZN1DdlEPvSt11align_val_t1Q(i8* noundef %[[ALLOC]], i64 noundef 32, i32 %
void *d0() { return new (q) D; }
// Calling aligned new with placement syntax.
// ==========================================
#ifndef UNALIGNED
// CHECK-LABEL: define {{.*}} @_Z2e0v(
// CHECK: %[[ALLOC:.*]] = call noalias noundef nonnull align 4 i8* @_ZnwmSt11align_val_t(i64 noundef 512, i64 noundef 4)
// CHECK: call void @_ZdlPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 4)
void *e0() { return new (std::align_val_t(4)) A; }
// CHECK-LABEL: define {{.*}} @_Z2e1v(
// CHECK: %[[ALLOC:.*]] = call noundef i8* @_ZN1BnwEmSt11align_val_t(i64 noundef 512, i64 noundef 4)
// CHECK: call void @_ZN1BdlEPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 4)
void *e1() { return new (std::align_val_t(4)) B; }
#endif
// Variadic placement/non-placement allocation functions.
// ======================================================
struct OVERALIGNED F {
F();
void *operator new(size_t, ...);
void operator delete(void*, ...);
int n[128];
};
// CHECK-LABEL: define {{.*}} @_Z2f0v(
// CHECK: %[[ALLOC:.*]] = call noundef i8* (i64, ...) @_ZN1FnwEmz(i64 noundef 512, i64 noundef 32)
// Non-placement allocation function, uses normal deallocation lookup which
// cares about whether a parameter has type std::align_val_t.
// CHECK: call void (i8*, ...) @_ZN1FdlEPvz(i8* noundef %[[ALLOC]])
void *f0() { return new F; }
// CHECK-LABEL: define {{.*}} @_Z2f1v(
// CHECK: %[[ALLOC:.*]] = call noundef i8* (i64, ...) @_ZN1FnwEmz(i64 noundef 512, i64 noundef 32, i32 %
// Placement allocation function, uses placement deallocation matching, which
// passes same arguments and therefore includes alignment.
// CHECK: call void (i8*, ...) @_ZN1FdlEPvz(i8* noundef %[[ALLOC]], i64 noundef 32, i32 %
void *f1() { return new (q) F; }
struct OVERALIGNED G {
G();
void *operator new(size_t, std::align_val_t, ...);
void operator delete(void*, std::align_val_t, ...);
int n[128];
};
#ifndef UNALIGNED
// CHECK-LABEL: define {{.*}} @_Z2g0v
// CHECK: %[[ALLOC:.*]] = call noundef i8* (i64, i64, ...) @_ZN1GnwEmSt11align_val_tz(i64 noundef 512, i64 noundef 32)
// CHECK: call void (i8*, i64, ...) @_ZN1GdlEPvSt11align_val_tz(i8* noundef %[[ALLOC]], i64 noundef 32)
void *g0() { return new G; }
// CHECK-LABEL: define {{.*}} @_Z2g1v
// CHECK: %[[ALLOC:.*]] = call noundef i8* (i64, i64, ...) @_ZN1GnwEmSt11align_val_tz(i64 noundef 512, i64 noundef 32, i32 %
// CHECK: call void (i8*, i64, ...) @_ZN1GdlEPvSt11align_val_tz(i8* noundef %[[ALLOC]], i64 noundef 32, i32 %
void *g1() { return new (q) G; }
#endif
|