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
|
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx14 -std=c++14 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2b %s
typedef __SIZE_TYPE__ size_t;
namespace basic {
// Ensuring that __bos can be used in constexpr functions without anything
// sketchy going on...
constexpr int bos0() {
int k = 5;
char cs[10] = {};
return __builtin_object_size(&cs[k], 0);
}
constexpr int bos1() {
int k = 5;
char cs[10] = {};
return __builtin_object_size(&cs[k], 1);
}
constexpr int bos2() {
int k = 5;
char cs[10] = {};
return __builtin_object_size(&cs[k], 2);
}
constexpr int bos3() {
int k = 5;
char cs[10] = {};
return __builtin_object_size(&cs[k], 3);
}
static_assert(bos0() == sizeof(char) * 5, "");
static_assert(bos1() == sizeof(char) * 5, "");
static_assert(bos2() == sizeof(char) * 5, "");
static_assert(bos3() == sizeof(char) * 5, "");
}
namespace in_enable_if {
// The code that prompted these changes was __bos in enable_if
void copy5CharsInto(char *buf) // expected-note{{candidate}}
__attribute__((enable_if(__builtin_object_size(buf, 0) != -1 &&
__builtin_object_size(buf, 0) > 5,
"")));
// We use different EvalModes for __bos with type 0 versus 1. Ensure 1 works,
// too...
void copy5CharsIntoStrict(char *buf) // expected-note{{candidate}}
__attribute__((enable_if(__builtin_object_size(buf, 1) != -1 &&
__builtin_object_size(buf, 1) > 5,
"")));
struct LargeStruct {
int pad;
char buf[6];
int pad2;
};
struct SmallStruct {
int pad;
char buf[5];
int pad2;
};
void noWriteToBuf() {
char buf[6];
copy5CharsInto(buf);
LargeStruct large;
copy5CharsIntoStrict(large.buf);
}
void initTheBuf() {
char buf[6] = {};
copy5CharsInto(buf);
LargeStruct large = {0, {}, 0};
copy5CharsIntoStrict(large.buf);
}
int getI();
void initTheBufWithALoop() {
char buf[6] = {};
for (unsigned I = getI(); I != sizeof(buf); ++I)
buf[I] = I;
copy5CharsInto(buf);
LargeStruct large;
for (unsigned I = getI(); I != sizeof(buf); ++I)
large.buf[I] = I;
copy5CharsIntoStrict(large.buf);
}
void tooSmallBuf() {
char buf[5];
copy5CharsInto(buf); // expected-error{{no matching function for call}}
SmallStruct small;
copy5CharsIntoStrict(small.buf); // expected-error{{no matching function for call}}
}
}
namespace InvalidBase {
// Ensure this doesn't crash.
struct S { const char *name; };
S invalid_base();
constexpr size_t bos_name = __builtin_object_size(invalid_base().name, 1);
static_assert(bos_name == -1, "");
struct T { ~T(); };
T invalid_base_2();
constexpr size_t bos_dtor = __builtin_object_size(&(T&)(T&&)invalid_base_2(), 0);
static_assert(bos_dtor == -1, "");
}
// PR44268
constexpr int bos_new() { // cxx14-error {{constant expression}}
void *p = new int; // cxx14-note {{until C++20}}
return __builtin_object_size(p, 0);
}
namespace GH129397 {
struct incomplete;
void test(incomplete &ref) {
__builtin_object_size(&ref, 1);
}
}
|