summaryrefslogtreecommitdiffstats
path: root/clang/test
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2019-08-29 22:49:34 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2019-08-29 22:49:34 +0000
commitcd839ccf9985884c25e87cc34f658c02c5e1cd93 (patch)
treeee2c1bcc407711493f1e60c6760f6ba4fdde56d7 /clang/test
parent33e9be6c8b5aad9c164e082c7e78cc08dd13cac1 (diff)
downloadbcm5719-llvm-cd839ccf9985884c25e87cc34f658c02c5e1cd93.tar.gz
bcm5719-llvm-cd839ccf9985884c25e87cc34f658c02c5e1cd93.zip
Fix silent wrong-code bugs and crashes with designated initialization.
We failed to correctly handle the 'holes' left behind by designated initializers in VerifyOnly mode. This would result in us thinking that a designated initialization would be valid, only to find that it is not actually valid when we come to build it. In a +Asserts build, that would assert, and in a -Asserts build, that would silently lose some part of the initialization or crash. With this change, when an InitListExpr contains any designators, we now always build a structured list so that we can track the locations of the 'holes' that we need to go back and fill in. We could in principle do better: we only need the structured form if there is a designator that jumps backwards (and can otherwise check for the holes as we progress through the initializer list), but dealing with that turns out to be rather complicated, so it's not done as part of this patch. llvm-svn: 370419
Diffstat (limited to 'clang/test')
-rw-r--r--clang/test/SemaCXX/designated-initializers.cpp147
1 files changed, 147 insertions, 0 deletions
diff --git a/clang/test/SemaCXX/designated-initializers.cpp b/clang/test/SemaCXX/designated-initializers.cpp
index 04002c0b6c1..739817372eb 100644
--- a/clang/test/SemaCXX/designated-initializers.cpp
+++ b/clang/test/SemaCXX/designated-initializers.cpp
@@ -30,3 +30,150 @@ void bar() {
Bar<int>::Test(); // expected-note {{in instantiation of member function 'Bar<int>::Test' requested here}}
Bar<bool>::Test(); // expected-note {{in instantiation of member function 'Bar<bool>::Test' requested here}}
}
+
+namespace Reorder {
+ struct X {
+ X(int n);
+ private:
+ int i;
+ };
+
+ struct foo {
+ X x;
+ X y;
+ };
+
+ foo n = {.y = 4, .x = 5};
+ X arr[2] = {[1] = 1, [0] = 2};
+}
+
+namespace Reorder2 {
+ struct S {
+ S();
+ S(const S &);
+ ~S();
+ };
+
+ struct EF {
+ S s;
+ };
+
+ struct PN {
+ PN(const PN &);
+ };
+ extern PN pn;
+
+ struct FLN {
+ EF ef;
+ int it;
+ PN pn;
+ };
+
+ void f() {
+ FLN new_elem = {
+ .ef = EF(),
+ .pn = pn,
+ .it = 0,
+ };
+ }
+}
+
+namespace Reorder3 {
+ struct S {
+ int a, &b, &c; // expected-note 2{{here}}
+ };
+ S s1 = {
+ .a = 1, .c = s1.a, .b = s1.a
+ };
+ S s2 = {
+ .a = 1, .c = s2.a
+ }; // expected-error {{uninitialized}}
+ S s3 = {
+ .b = s3.a, .a = 1,
+ }; // expected-error {{uninitialized}}
+}
+
+// Check that we don't even think about whether holes in a designated
+// initializer are zero-initializable if the holes are filled later.
+namespace NoCheckingFilledHoles {
+ template<typename T> struct Error { using type = typename T::type; }; // expected-error 3{{'::'}}
+
+ template<int N>
+ struct DefaultInitIsError {
+ DefaultInitIsError(Error<int[N]> = {}); // expected-note 3{{instantiation}} expected-note 3{{passing}}
+ DefaultInitIsError(int, int);
+ };
+
+ template<int N>
+ struct X {
+ int a;
+ DefaultInitIsError<N> e;
+ int b;
+ };
+ X<1> x1 = {
+ .b = 2,
+ .a = 1,
+ {4, 4}
+ };
+ X<2> x2 = {
+ .e = {4, 4},
+ .b = 2,
+ .a = 1
+ };
+ X<3> x3 = {
+ .b = 2,
+ .a = 1
+ }; // expected-note {{default function argument}}
+ X<4> x4 = {
+ .a = 1,
+ .b = 2
+ }; // expected-note {{default function argument}}
+ X<5> x5 = {
+ .e = {4, 4},
+ .a = 1,
+ .b = 2
+ };
+ X<6> x6 = {
+ .a = 1,
+ .b = 2,
+ .e = {4, 4}
+ };
+
+ template<int N> struct Y { X<N> x; };
+ Y<7> y7 = {
+ .x = {.a = 1, .b = 2}, // expected-note {{default function argument}}
+ .x.e = {3, 4}
+ };
+ Y<8> y8 = {
+ .x = {.e = {3, 4}},
+ .x.a = 1,
+ .x.b = 2
+ };
+}
+
+namespace LargeArrayDesignator {
+ struct X {
+ int arr[1000000000];
+ };
+ struct Y {
+ int arr[3];
+ };
+ void f(X x);
+ void f(Y y) = delete;
+ void g() {
+ f({.arr[4] = 1});
+ }
+}
+
+namespace ADL {
+ struct A {};
+ void f(A, int);
+
+ namespace X {
+ void f(A, int);
+ // OK. Would fail if checking {} against type A set the type of the
+ // initializer list to A, because ADL would find ADL::f, resulting in
+ // ambiguity.
+ void g() { f({}, {}); }
+ }
+}
OpenPOWER on IntegriCloud