blob: 9e88eab0c69640a52efdd0d7922590ba4c264330 [file] [log] [blame]
mistergc2e75482017-09-19 16:54:40 -04001// Copyright 2017 The Abseil Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "absl/container/fixed_array.h"
16
17#include <stdio.h>
18#include <list>
19#include <memory>
20#include <numeric>
21#include <stdexcept>
22#include <string>
23#include <vector>
24
25#include "gmock/gmock.h"
26#include "gtest/gtest.h"
27#include "absl/base/internal/exception_testing.h"
28#include "absl/memory/memory.h"
29
30namespace {
31
32// Helper routine to determine if a absl::FixedArray used stack allocation.
33template <typename ArrayType>
34static bool IsOnStack(const ArrayType& a) {
35 return a.size() <= ArrayType::inline_elements;
36}
37
38class ConstructionTester {
39 public:
40 ConstructionTester()
41 : self_ptr_(this),
42 value_(0) {
43 constructions++;
44 }
45 ~ConstructionTester() {
46 assert(self_ptr_ == this);
47 self_ptr_ = nullptr;
48 destructions++;
49 }
50
51 // These are incremented as elements are constructed and destructed so we can
52 // be sure all elements are properly cleaned up.
53 static int constructions;
54 static int destructions;
55
56 void CheckConstructed() {
57 assert(self_ptr_ == this);
58 }
59
60 void set(int value) { value_ = value; }
61 int get() { return value_; }
62
63 private:
64 // self_ptr_ should always point to 'this' -- that's how we can be sure the
65 // constructor has been called.
66 ConstructionTester* self_ptr_;
67 int value_;
68};
69
70int ConstructionTester::constructions = 0;
71int ConstructionTester::destructions = 0;
72
73// ThreeInts will initialize its three ints to the value stored in
74// ThreeInts::counter. The constructor increments counter so that each object
75// in an array of ThreeInts will have different values.
76class ThreeInts {
77 public:
78 ThreeInts() {
79 x_ = counter;
80 y_ = counter;
81 z_ = counter;
82 ++counter;
83 }
84
85 static int counter;
86
87 int x_, y_, z_;
88};
89
90int ThreeInts::counter = 0;
91
92TEST(FixedArrayTest, SmallObjects) {
93 // Small object arrays
94 {
95 // Short arrays should be on the stack
96 absl::FixedArray<int> array(4);
97 EXPECT_TRUE(IsOnStack(array));
98 }
99
100 {
101 // Large arrays should be on the heap
102 absl::FixedArray<int> array(1048576);
103 EXPECT_FALSE(IsOnStack(array));
104 }
105
106 {
107 // Arrays of <= default size should be on the stack
108 absl::FixedArray<int, 100> array(100);
109 EXPECT_TRUE(IsOnStack(array));
110 }
111
112 {
113 // Arrays of > default size should be on the stack
114 absl::FixedArray<int, 100> array(101);
115 EXPECT_FALSE(IsOnStack(array));
116 }
117
118 {
119 // Arrays with different size elements should use approximately
120 // same amount of stack space
121 absl::FixedArray<int> array1(0);
122 absl::FixedArray<char> array2(0);
123 EXPECT_LE(sizeof(array1), sizeof(array2)+100);
124 EXPECT_LE(sizeof(array2), sizeof(array1)+100);
125 }
126
127 {
128 // Ensure that vectors are properly constructed inside a fixed array.
129 absl::FixedArray<std::vector<int> > array(2);
130 EXPECT_EQ(0, array[0].size());
131 EXPECT_EQ(0, array[1].size());
132 }
133
134 {
135 // Regardless of absl::FixedArray implementation, check that a type with a
136 // low alignment requirement and a non power-of-two size is initialized
137 // correctly.
138 ThreeInts::counter = 1;
139 absl::FixedArray<ThreeInts> array(2);
140 EXPECT_EQ(1, array[0].x_);
141 EXPECT_EQ(1, array[0].y_);
142 EXPECT_EQ(1, array[0].z_);
143 EXPECT_EQ(2, array[1].x_);
144 EXPECT_EQ(2, array[1].y_);
145 EXPECT_EQ(2, array[1].z_);
146 }
147}
148
149TEST(FixedArrayTest, AtThrows) {
150 absl::FixedArray<int> a = {1, 2, 3};
151 EXPECT_EQ(a.at(2), 3);
152 ABSL_BASE_INTERNAL_EXPECT_FAIL(a.at(3), std::out_of_range,
153 "failed bounds check");
154}
155
156TEST(FixedArrayRelationalsTest, EqualArrays) {
157 for (int i = 0; i < 10; ++i) {
158 absl::FixedArray<int, 5> a1(i);
159 std::iota(a1.begin(), a1.end(), 0);
160 absl::FixedArray<int, 5> a2(a1.begin(), a1.end());
161
162 EXPECT_TRUE(a1 == a2);
163 EXPECT_FALSE(a1 != a2);
164 EXPECT_TRUE(a2 == a1);
165 EXPECT_FALSE(a2 != a1);
166 EXPECT_FALSE(a1 < a2);
167 EXPECT_FALSE(a1 > a2);
168 EXPECT_FALSE(a2 < a1);
169 EXPECT_FALSE(a2 > a1);
170 EXPECT_TRUE(a1 <= a2);
171 EXPECT_TRUE(a1 >= a2);
172 EXPECT_TRUE(a2 <= a1);
173 EXPECT_TRUE(a2 >= a1);
174 }
175}
176
177TEST(FixedArrayRelationalsTest, UnequalArrays) {
178 for (int i = 1; i < 10; ++i) {
179 absl::FixedArray<int, 5> a1(i);
180 std::iota(a1.begin(), a1.end(), 0);
181 absl::FixedArray<int, 5> a2(a1.begin(), a1.end());
182 --a2[i / 2];
183
184 EXPECT_FALSE(a1 == a2);
185 EXPECT_TRUE(a1 != a2);
186 EXPECT_FALSE(a2 == a1);
187 EXPECT_TRUE(a2 != a1);
188 EXPECT_FALSE(a1 < a2);
189 EXPECT_TRUE(a1 > a2);
190 EXPECT_TRUE(a2 < a1);
191 EXPECT_FALSE(a2 > a1);
192 EXPECT_FALSE(a1 <= a2);
193 EXPECT_TRUE(a1 >= a2);
194 EXPECT_TRUE(a2 <= a1);
195 EXPECT_FALSE(a2 >= a1);
196 }
197}
198
199template <int stack_elements>
200static void TestArray(int n) {
201 SCOPED_TRACE(n);
202 SCOPED_TRACE(stack_elements);
203 ConstructionTester::constructions = 0;
204 ConstructionTester::destructions = 0;
205 {
206 absl::FixedArray<ConstructionTester, stack_elements> array(n);
207
208 EXPECT_THAT(array.size(), n);
209 EXPECT_THAT(array.memsize(), sizeof(ConstructionTester) * n);
210 EXPECT_THAT(array.begin() + n, array.end());
211
212 // Check that all elements were constructed
213 for (int i = 0; i < n; i++) {
214 array[i].CheckConstructed();
215 }
216 // Check that no other elements were constructed
217 EXPECT_THAT(ConstructionTester::constructions, n);
218
219 // Test operator[]
220 for (int i = 0; i < n; i++) {
221 array[i].set(i);
222 }
223 for (int i = 0; i < n; i++) {
224 EXPECT_THAT(array[i].get(), i);
225 EXPECT_THAT(array.data()[i].get(), i);
226 }
227
228 // Test data()
229 for (int i = 0; i < n; i++) {
230 array.data()[i].set(i + 1);
231 }
232 for (int i = 0; i < n; i++) {
233 EXPECT_THAT(array[i].get(), i+1);
234 EXPECT_THAT(array.data()[i].get(), i+1);
235 }
236 } // Close scope containing 'array'.
237
238 // Check that all constructed elements were destructed.
239 EXPECT_EQ(ConstructionTester::constructions,
240 ConstructionTester::destructions);
241}
242
243template <int elements_per_inner_array, int inline_elements>
244static void TestArrayOfArrays(int n) {
245 SCOPED_TRACE(n);
246 SCOPED_TRACE(inline_elements);
247 SCOPED_TRACE(elements_per_inner_array);
248 ConstructionTester::constructions = 0;
249 ConstructionTester::destructions = 0;
250 {
251 using InnerArray = ConstructionTester[elements_per_inner_array];
252 // Heap-allocate the FixedArray to avoid blowing the stack frame.
253 auto array_ptr =
254 absl::make_unique<absl::FixedArray<InnerArray, inline_elements>>(n);
255 auto& array = *array_ptr;
256
257 ASSERT_EQ(array.size(), n);
258 ASSERT_EQ(array.memsize(),
259 sizeof(ConstructionTester) * elements_per_inner_array * n);
260 ASSERT_EQ(array.begin() + n, array.end());
261
262 // Check that all elements were constructed
263 for (int i = 0; i < n; i++) {
264 for (int j = 0; j < elements_per_inner_array; j++) {
265 (array[i])[j].CheckConstructed();
266 }
267 }
268 // Check that no other elements were constructed
269 ASSERT_EQ(ConstructionTester::constructions, n * elements_per_inner_array);
270
271 // Test operator[]
272 for (int i = 0; i < n; i++) {
273 for (int j = 0; j < elements_per_inner_array; j++) {
274 (array[i])[j].set(i * elements_per_inner_array + j);
275 }
276 }
277 for (int i = 0; i < n; i++) {
278 for (int j = 0; j < elements_per_inner_array; j++) {
279 ASSERT_EQ((array[i])[j].get(), i * elements_per_inner_array + j);
280 ASSERT_EQ((array.data()[i])[j].get(), i * elements_per_inner_array + j);
281 }
282 }
283
284 // Test data()
285 for (int i = 0; i < n; i++) {
286 for (int j = 0; j < elements_per_inner_array; j++) {
287 (array.data()[i])[j].set((i + 1) * elements_per_inner_array + j);
288 }
289 }
290 for (int i = 0; i < n; i++) {
291 for (int j = 0; j < elements_per_inner_array; j++) {
292 ASSERT_EQ((array[i])[j].get(),
293 (i + 1) * elements_per_inner_array + j);
294 ASSERT_EQ((array.data()[i])[j].get(),
295 (i + 1) * elements_per_inner_array + j);
296 }
297 }
298 } // Close scope containing 'array'.
299
300 // Check that all constructed elements were destructed.
301 EXPECT_EQ(ConstructionTester::constructions,
302 ConstructionTester::destructions);
303}
304
305TEST(IteratorConstructorTest, NonInline) {
306 int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
307 absl::FixedArray<int, ABSL_ARRAYSIZE(kInput) - 1> const fixed(
308 kInput, kInput + ABSL_ARRAYSIZE(kInput));
309 ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
310 for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
311 ASSERT_EQ(kInput[i], fixed[i]);
312 }
313}
314
315TEST(IteratorConstructorTest, Inline) {
316 int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
317 absl::FixedArray<int, ABSL_ARRAYSIZE(kInput)> const fixed(
318 kInput, kInput + ABSL_ARRAYSIZE(kInput));
319 ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
320 for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
321 ASSERT_EQ(kInput[i], fixed[i]);
322 }
323}
324
325TEST(IteratorConstructorTest, NonPod) {
326 char const* kInput[] =
327 { "red", "orange", "yellow", "green", "blue", "indigo", "violet" };
328 absl::FixedArray<std::string> const fixed(kInput, kInput + ABSL_ARRAYSIZE(kInput));
329 ASSERT_EQ(ABSL_ARRAYSIZE(kInput), fixed.size());
330 for (size_t i = 0; i < ABSL_ARRAYSIZE(kInput); ++i) {
331 ASSERT_EQ(kInput[i], fixed[i]);
332 }
333}
334
335TEST(IteratorConstructorTest, FromEmptyVector) {
336 std::vector<int> const empty;
337 absl::FixedArray<int> const fixed(empty.begin(), empty.end());
338 EXPECT_EQ(0, fixed.size());
339 EXPECT_EQ(empty.size(), fixed.size());
340}
341
342TEST(IteratorConstructorTest, FromNonEmptyVector) {
343 int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
344 std::vector<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput));
345 absl::FixedArray<int> const fixed(items.begin(), items.end());
346 ASSERT_EQ(items.size(), fixed.size());
347 for (size_t i = 0; i < items.size(); ++i) {
348 ASSERT_EQ(items[i], fixed[i]);
349 }
350}
351
352TEST(IteratorConstructorTest, FromBidirectionalIteratorRange) {
353 int const kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
354 std::list<int> const items(kInput, kInput + ABSL_ARRAYSIZE(kInput));
355 absl::FixedArray<int> const fixed(items.begin(), items.end());
356 EXPECT_THAT(fixed, testing::ElementsAreArray(kInput));
357}
358
359TEST(InitListConstructorTest, InitListConstruction) {
360 absl::FixedArray<int> fixed = {1, 2, 3};
361 EXPECT_THAT(fixed, testing::ElementsAreArray({1, 2, 3}));
362}
363
364TEST(FillConstructorTest, NonEmptyArrays) {
365 absl::FixedArray<int> stack_array(4, 1);
366 EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
367
368 absl::FixedArray<int, 0> heap_array(4, 1);
369 EXPECT_THAT(stack_array, testing::ElementsAreArray({1, 1, 1, 1}));
370}
371
372TEST(FillConstructorTest, EmptyArray) {
373 absl::FixedArray<int> empty_fill(0, 1);
374 absl::FixedArray<int> empty_size(0);
375 EXPECT_EQ(empty_fill, empty_size);
376}
377
378TEST(FillConstructorTest, NotTriviallyCopyable) {
379 std::string str = "abcd";
380 absl::FixedArray<std::string> strings = {str, str, str, str};
381
382 absl::FixedArray<std::string> array(4, str);
383 EXPECT_EQ(array, strings);
384}
385
386TEST(FillConstructorTest, Disambiguation) {
387 absl::FixedArray<size_t> a(1, 2);
388 EXPECT_THAT(a, testing::ElementsAre(2));
389}
390
391TEST(FixedArrayTest, ManySizedArrays) {
392 std::vector<int> sizes;
393 for (int i = 1; i < 100; i++) sizes.push_back(i);
394 for (int i = 100; i <= 1000; i += 100) sizes.push_back(i);
395 for (int n : sizes) {
396 TestArray<0>(n);
397 TestArray<1>(n);
398 TestArray<64>(n);
399 TestArray<1000>(n);
400 }
401}
402
403TEST(FixedArrayTest, ManySizedArraysOfArraysOf1) {
404 for (int n = 1; n < 1000; n++) {
405 ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 0>(n)));
406 ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1>(n)));
407 ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 64>(n)));
408 ASSERT_NO_FATAL_FAILURE((TestArrayOfArrays<1, 1000>(n)));
409 }
410}
411
412TEST(FixedArrayTest, ManySizedArraysOfArraysOf2) {
413 for (int n = 1; n < 1000; n++) {
414 TestArrayOfArrays<2, 0>(n);
415 TestArrayOfArrays<2, 1>(n);
416 TestArrayOfArrays<2, 64>(n);
417 TestArrayOfArrays<2, 1000>(n);
418 }
419}
420
421// If value_type is put inside of a struct container,
422// we might evoke this error in a hardened build unless data() is carefully
423// written, so check on that.
424// error: call to int __builtin___sprintf_chk(etc...)
425// will always overflow destination buffer [-Werror]
426TEST(FixedArrayTest, AvoidParanoidDiagnostics) {
427 absl::FixedArray<char, 32> buf(32);
428 sprintf(buf.data(), "foo"); // NOLINT(runtime/printf)
429}
430
431TEST(FixedArrayTest, TooBigInlinedSpace) {
432 struct TooBig {
433 char c[1 << 20];
434 }; // too big for even one on the stack
435
436 // Simulate the data members of absl::FixedArray, a pointer and a size_t.
437 struct Data {
438 TooBig* p;
439 size_t size;
440 };
441
442 // Make sure TooBig objects are not inlined for 0 or default size.
443 static_assert(sizeof(absl::FixedArray<TooBig, 0>) == sizeof(Data),
444 "0-sized absl::FixedArray should have same size as Data.");
445 static_assert(alignof(absl::FixedArray<TooBig, 0>) == alignof(Data),
446 "0-sized absl::FixedArray should have same alignment as Data.");
447 static_assert(sizeof(absl::FixedArray<TooBig>) == sizeof(Data),
448 "default-sized absl::FixedArray should have same size as Data");
449 static_assert(
450 alignof(absl::FixedArray<TooBig>) == alignof(Data),
451 "default-sized absl::FixedArray should have same alignment as Data.");
452}
453
454// PickyDelete EXPECTs its class-scope deallocation funcs are unused.
455struct PickyDelete {
456 PickyDelete() {}
457 ~PickyDelete() {}
458 void operator delete(void* p) {
459 EXPECT_TRUE(false) << __FUNCTION__;
460 ::operator delete(p);
461 }
462 void operator delete[](void* p) {
463 EXPECT_TRUE(false) << __FUNCTION__;
464 ::operator delete[](p);
465 }
466};
467
468TEST(FixedArrayTest, UsesGlobalAlloc) { absl::FixedArray<PickyDelete, 0> a(5); }
469
470TEST(FixedArrayTest, Data) {
471 static const int kInput[] = { 2, 3, 5, 7, 11, 13, 17 };
472 absl::FixedArray<int> fa(std::begin(kInput), std::end(kInput));
473 EXPECT_EQ(fa.data(), &*fa.begin());
474 EXPECT_EQ(fa.data(), &fa[0]);
475
476 const absl::FixedArray<int>& cfa = fa;
477 EXPECT_EQ(cfa.data(), &*cfa.begin());
478 EXPECT_EQ(cfa.data(), &cfa[0]);
479}
480
481TEST(FixedArrayTest, Empty) {
482 absl::FixedArray<int> empty(0);
483 absl::FixedArray<int> inline_filled(1);
484 absl::FixedArray<int, 0> heap_filled(1);
485 EXPECT_TRUE(empty.empty());
486 EXPECT_FALSE(inline_filled.empty());
487 EXPECT_FALSE(heap_filled.empty());
488}
489
490TEST(FixedArrayTest, FrontAndBack) {
491 absl::FixedArray<int, 3 * sizeof(int)> inlined = {1, 2, 3};
492 EXPECT_EQ(inlined.front(), 1);
493 EXPECT_EQ(inlined.back(), 3);
494
495 absl::FixedArray<int, 0> allocated = {1, 2, 3};
496 EXPECT_EQ(allocated.front(), 1);
497 EXPECT_EQ(allocated.back(), 3);
498
499 absl::FixedArray<int> one_element = {1};
500 EXPECT_EQ(one_element.front(), one_element.back());
501}
502
503TEST(FixedArrayTest, ReverseIteratorInlined) {
504 absl::FixedArray<int, 5 * sizeof(int)> a = {0, 1, 2, 3, 4};
505
506 int counter = 5;
507 for (absl::FixedArray<int>::reverse_iterator iter = a.rbegin();
508 iter != a.rend(); ++iter) {
509 counter--;
510 EXPECT_EQ(counter, *iter);
511 }
512 EXPECT_EQ(counter, 0);
513
514 counter = 5;
515 for (absl::FixedArray<int>::const_reverse_iterator iter = a.rbegin();
516 iter != a.rend(); ++iter) {
517 counter--;
518 EXPECT_EQ(counter, *iter);
519 }
520 EXPECT_EQ(counter, 0);
521
522 counter = 5;
523 for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
524 counter--;
525 EXPECT_EQ(counter, *iter);
526 }
527 EXPECT_EQ(counter, 0);
528}
529
530TEST(FixedArrayTest, ReverseIteratorAllocated) {
531 absl::FixedArray<int, 0> a = {0, 1, 2, 3, 4};
532
533 int counter = 5;
534 for (absl::FixedArray<int>::reverse_iterator iter = a.rbegin();
535 iter != a.rend(); ++iter) {
536 counter--;
537 EXPECT_EQ(counter, *iter);
538 }
539 EXPECT_EQ(counter, 0);
540
541 counter = 5;
542 for (absl::FixedArray<int>::const_reverse_iterator iter = a.rbegin();
543 iter != a.rend(); ++iter) {
544 counter--;
545 EXPECT_EQ(counter, *iter);
546 }
547 EXPECT_EQ(counter, 0);
548
549 counter = 5;
550 for (auto iter = a.crbegin(); iter != a.crend(); ++iter) {
551 counter--;
552 EXPECT_EQ(counter, *iter);
553 }
554 EXPECT_EQ(counter, 0);
555}
556
557TEST(FixedArrayTest, Fill) {
558 absl::FixedArray<int, 5 * sizeof(int)> inlined(5);
559 int fill_val = 42;
560 inlined.fill(fill_val);
561 for (int i : inlined) EXPECT_EQ(i, fill_val);
562
563 absl::FixedArray<int, 0> allocated(5);
564 allocated.fill(fill_val);
565 for (int i : allocated) EXPECT_EQ(i, fill_val);
566
567 // It doesn't do anything, just make sure this compiles.
568 absl::FixedArray<int> empty(0);
569 empty.fill(fill_val);
570}
571
572#ifdef ADDRESS_SANITIZER
573TEST(FixedArrayTest, AddressSanitizerAnnotations1) {
574 absl::FixedArray<int, 32> a(10);
575 int *raw = a.data();
576 raw[0] = 0;
577 raw[9] = 0;
578 EXPECT_DEATH(raw[-2] = 0, "container-overflow");
579 EXPECT_DEATH(raw[-1] = 0, "container-overflow");
580 EXPECT_DEATH(raw[10] = 0, "container-overflow");
581 EXPECT_DEATH(raw[31] = 0, "container-overflow");
582}
583
584TEST(FixedArrayTest, AddressSanitizerAnnotations2) {
585 absl::FixedArray<char, 17> a(12);
586 char *raw = a.data();
587 raw[0] = 0;
588 raw[11] = 0;
589 EXPECT_DEATH(raw[-7] = 0, "container-overflow");
590 EXPECT_DEATH(raw[-1] = 0, "container-overflow");
591 EXPECT_DEATH(raw[12] = 0, "container-overflow");
592 EXPECT_DEATH(raw[17] = 0, "container-overflow");
593}
594
595TEST(FixedArrayTest, AddressSanitizerAnnotations3) {
596 absl::FixedArray<uint64_t, 20> a(20);
597 uint64_t *raw = a.data();
598 raw[0] = 0;
599 raw[19] = 0;
600 EXPECT_DEATH(raw[-1] = 0, "container-overflow");
601 EXPECT_DEATH(raw[20] = 0, "container-overflow");
602}
603
604TEST(FixedArrayTest, AddressSanitizerAnnotations4) {
605 absl::FixedArray<ThreeInts> a(10);
606 ThreeInts *raw = a.data();
607 raw[0] = ThreeInts();
608 raw[9] = ThreeInts();
609 // Note: raw[-1] is pointing to 12 bytes before the container range. However,
610 // there is only a 8-byte red zone before the container range, so we only
611 // access the last 4 bytes of the struct to make sure it stays within the red
612 // zone.
613 EXPECT_DEATH(raw[-1].z_ = 0, "container-overflow");
614 EXPECT_DEATH(raw[10] = ThreeInts(), "container-overflow");
615 // The actual size of storage is kDefaultBytes=256, 21*12 = 252,
616 // so reading raw[21] should still trigger the correct warning.
617 EXPECT_DEATH(raw[21] = ThreeInts(), "container-overflow");
618}
619#endif // ADDRESS_SANITIZER
620
621} // namespace