1 | // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -O0 %s -o - 2>&1 -std=c++11 | FileCheck %s |
2 | |
3 | namespace templates { |
4 | void *my_malloc(int N) __attribute__((alloc_size(1))); |
5 | void *my_calloc(int N, int M) __attribute__((alloc_size(1, 2))); |
6 | |
7 | struct MyType { |
8 | int arr[4]; |
9 | }; |
10 | |
11 | template <typename T> int callMalloc(); |
12 | |
13 | template <typename T, int N> int callCalloc(); |
14 | |
15 | // CHECK-LABEL: define i32 @_ZN9templates6testItEv() |
16 | int testIt() { |
17 | // CHECK: call i32 @_ZN9templates10callMallocINS_6MyTypeEEEiv |
18 | // CHECK: call i32 @_ZN9templates10callCallocINS_6MyTypeELi4EEEiv |
19 | return callMalloc<MyType>() + callCalloc<MyType, 4>(); |
20 | } |
21 | |
22 | // CHECK-LABEL: define linkonce_odr i32 |
23 | // @_ZN9templates10callMallocINS_6MyTypeEEEiv |
24 | template <typename T> int callMalloc() { |
25 | static_assert(sizeof(T) == 16, ""); |
26 | // CHECK: ret i32 16 |
27 | return __builtin_object_size(my_malloc(sizeof(T)), 0); |
28 | } |
29 | |
30 | // CHECK-LABEL: define linkonce_odr i32 |
31 | // @_ZN9templates10callCallocINS_6MyTypeELi4EEEiv |
32 | template <typename T, int N> int callCalloc() { |
33 | static_assert(sizeof(T) * N == 64, ""); |
34 | // CHECK: ret i32 64 |
35 | return __builtin_object_size(my_malloc(sizeof(T) * N), 0); |
36 | } |
37 | } |
38 | |
39 | namespace templated_alloc_size { |
40 | using size_t = unsigned long; |
41 | |
42 | // We don't need bodies for any of these, because they're only used in |
43 | // __builtin_object_size, and that shouldn't need anything but a function |
44 | // decl with alloc_size on it. |
45 | template <typename T> |
46 | T *my_malloc(size_t N = sizeof(T)) __attribute__((alloc_size(1))); |
47 | |
48 | template <typename T> |
49 | T *my_calloc(size_t M, size_t N = sizeof(T)) __attribute__((alloc_size(2, 1))); |
50 | |
51 | template <size_t N> |
52 | void *dependent_malloc(size_t NT = N) __attribute__((alloc_size(1))); |
53 | |
54 | template <size_t N, size_t M> |
55 | void *dependent_calloc(size_t NT = N, size_t MT = M) |
56 | __attribute__((alloc_size(1, 2))); |
57 | |
58 | template <typename T, size_t M> |
59 | void *dependent_calloc2(size_t NT = sizeof(T), size_t MT = M) |
60 | __attribute__((alloc_size(1, 2))); |
61 | |
62 | // CHECK-LABEL: define i32 @_ZN20templated_alloc_size6testItEv |
63 | int testIt() { |
64 | // 122 = 4 + 5*4 + 6 + 7*8 + 4*9 |
65 | // CHECK: ret i32 122 |
66 | return __builtin_object_size(my_malloc<int>(), 0) + |
67 | __builtin_object_size(my_calloc<int>(5), 0) + |
68 | __builtin_object_size(dependent_malloc<6>(), 0) + |
69 | __builtin_object_size(dependent_calloc<7, 8>(), 0) + |
70 | __builtin_object_size(dependent_calloc2<int, 9>(), 0); |
71 | } |
72 | } // namespace templated_alloc_size |
73 | |
74 | // Be sure that an ExprWithCleanups doesn't deter us. |
75 | namespace alloc_size_with_cleanups { |
76 | struct Foo { |
77 | ~Foo(); |
78 | }; |
79 | |
80 | void *my_malloc(const Foo &, int N) __attribute__((alloc_size(2))); |
81 | |
82 | // CHECK-LABEL: define i32 @_ZN24alloc_size_with_cleanups6testItEv |
83 | int testIt() { |
84 | int *const p = (int *)my_malloc(Foo{}, 3); |
85 | // CHECK: ret i32 3 |
86 | return __builtin_object_size(p, 0); |
87 | } |
88 | } // namespace alloc_size_with_cleanups |
89 | |
90 | class C { |
91 | public: |
92 | void *my_malloc(int N) __attribute__((alloc_size(2))); |
93 | void *my_calloc(int N, int M) __attribute__((alloc_size(2, 3))); |
94 | }; |
95 | |
96 | // CHECK-LABEL: define i32 @_Z16callMemberMallocv |
97 | int callMemberMalloc() { |
98 | // CHECK: ret i32 16 |
99 | return __builtin_object_size(C().my_malloc(16), 0); |
100 | } |
101 | |
102 | // CHECK-LABEL: define i32 @_Z16callMemberCallocv |
103 | int callMemberCalloc() { |
104 | // CHECK: ret i32 32 |
105 | return __builtin_object_size(C().my_calloc(16, 2), 0); |
106 | } |
107 | |