diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11996,7 +11996,12 @@ /*TreatUnavailableAsInvalid=*/false); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { - VDecl->setInvalidDecl(); + // If the provied initializer fails to initialize the var decl, + // we attach a recovery expr for better recovery. + auto RecoveryExpr = + CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), Args); + if (RecoveryExpr.get()) + VDecl->setInit(RecoveryExpr.get()); return; } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2669,7 +2669,8 @@ // trying to determine whether this would be a valid range. if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) { AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false); - if (LoopVar->isInvalidDecl()) + if (LoopVar->isInvalidDecl() || + (LoopVar->getInit() && LoopVar->getInit()->containsErrors())) NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); } } diff --git a/clang/test/AST/ast-dump-invalid-initialized.cpp b/clang/test/AST/ast-dump-invalid-initialized.cpp --- a/clang/test/AST/ast-dump-invalid-initialized.cpp +++ b/clang/test/AST/ast-dump-invalid-initialized.cpp @@ -4,6 +4,8 @@ class ForwardDecl; void test() { + // Verify the valid-bit of the VarDecl. + // CHECK: `-VarDecl {{.*}} a1 'A' A a1; // CHECK: `-VarDecl {{.*}} a2 'const A' @@ -16,4 +18,10 @@ const A& b1; // CHECK: `-VarDecl {{.*}} invalid b2 'ForwardDecl' ForwardDecl b2; + // CHECK: `-VarDecl {{.*}} invalid b3 'auto' + auto b3 = garbage(); + // CHECK: `-VarDecl {{.*}} invalid b4 'auto' + auto b4 = A(1); + // CHECK: `-VarDecl {{.*}} invalid b5 'auto' + auto b5 = A{1}; } \ No newline at end of file diff --git a/clang/test/AST/ast-dump-recovery.cpp b/clang/test/AST/ast-dump-recovery.cpp --- a/clang/test/AST/ast-dump-recovery.cpp +++ b/clang/test/AST/ast-dump-recovery.cpp @@ -103,3 +103,56 @@ // CHECK-NEXT:| `-RecoveryExpr {{.*}} contains-errors // CHECK-NEXT:| `-UnresolvedLookupExpr {{.*}} 'invalid' struct alignas(invalid()) Aligned {}; + +void InvalidInitalizer(int x) { + struct Bar { Bar(); }; + // CHECK: `-VarDecl {{.*}} a1 'Bar' + // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors + // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 + Bar a1(1); + // CHECK: `-VarDecl {{.*}} a2 'Bar' + // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors + // CHECK-NEXT: `-DeclRefExpr {{.*}} 'x' + Bar a2(x); + // CHECK: `-VarDecl {{.*}} a3 'Bar' + // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors + // CHECK-NEXT: `-InitListExpr + // CHECK-NEDT: `-DeclRefExpr {{.*}} 'x' + Bar a3{x}; + // CHECK: `-VarDecl {{.*}} a4 'Bar' + // CHECK-NEXT: `-ParenListExpr {{.*}} 'NULL TYPE' contains-errors + // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors + // CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid' + Bar a4(invalid()); + // CHECK: `-VarDecl {{.*}} a5 'Bar' + // CHECK-NEXT: `-InitListExpr {{.*}} contains-errors + // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors + // CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid' + Bar a5{invalid()}; + + // CHECK: `-VarDecl {{.*}} b1 'Bar' + // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors + // CHECK-NEXT: `-IntegerLiteral {{.*}} 'int' 1 + Bar b1 = 1; + // CHECK: `-VarDecl {{.*}} b2 'Bar' + // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors + // CHECK-NEXT: `-InitListExpr + Bar b2 = {1}; + // FIXME: preserve the invalid initializer. + // CHECK: `-VarDecl {{.*}} b3 'Bar' + Bar b3 = Bar(x); + // FIXME: preserve the invalid initializer. + // CHECK: `-VarDecl {{.*}} b4 'Bar' + Bar b4 = Bar{x}; + // CHECK: `-VarDecl {{.*}} b5 'Bar' + // CHECK-NEXT: `-CXXUnresolvedConstructExpr {{.*}} 'Bar' contains-errors 'Bar' + // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors + // CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid' + Bar b5 = Bar(invalid()); + // CHECK: `-VarDecl {{.*}} b6 'Bar' + // CHECK-NEXT: `-CXXUnresolvedConstructExpr {{.*}} 'Bar' contains-errors 'Bar' + // CHECK-NEXT: `-InitListExpr {{.*}} contains-errors + // CHECK-NEXT: `-RecoveryExpr {{.*}} contains-errors + // CHECK-NEXT: `-UnresolvedLookupExpr {{.*}} 'invalid' + Bar b6 = Bar{invalid()}; +} diff --git a/clang/test/CXX/special/class.copy/p11.0x.move.cpp b/clang/test/CXX/special/class.copy/p11.0x.move.cpp --- a/clang/test/CXX/special/class.copy/p11.0x.move.cpp +++ b/clang/test/CXX/special/class.copy/p11.0x.move.cpp @@ -32,7 +32,7 @@ }; }; extern DeletedNTVariant3 dntv3a(0); // expected-error {{no matching}} -extern DeletedNTVariant3 dntv3a(0); // expected-error {{no matching}} +extern DeletedNTVariant3 dntv3b(0); // expected-error {{no matching}} // -- a non-static data member of class type M (or array thereof) that cannot be // copied because overload resolution results in an ambiguity or a function diff --git a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp --- a/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp +++ b/clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp @@ -21,8 +21,7 @@ auto end(T &&t) -> decltype(t.end()) { return t.end(); } // expected-note {{candidate template ignored: substitution failure [with T = }} template - auto begin(T &&t) -> decltype(t.alt_begin()) { return t.alt_begin(); } // expected-note {{selected 'begin' template [with T = }} \ - expected-note 2{{candidate template ignored: substitution failure [with T = }} + auto begin(T &&t) -> decltype(t.alt_begin()) { return t.alt_begin(); } // expected-note 2{{candidate template ignored: substitution failure [with T = }} template auto end(T &&t) -> decltype(t.alt_end()) { return t.alt_end(); } // expected-note {{candidate template ignored: substitution failure [with T = }} @@ -36,7 +35,7 @@ struct A { // expected-note 2 {{candidate constructor}} A(); - int *begin(); // expected-note 3{{selected 'begin' function with iterator type 'int *'}} expected-note {{'begin' declared here}} + int *begin(); // expected-note {{selected 'begin' function with iterator type 'int *'}} expected-note {{'begin' declared here}} int *end(); }; diff --git a/clang/test/OpenMP/task_messages.cpp b/clang/test/OpenMP/task_messages.cpp --- a/clang/test/OpenMP/task_messages.cpp +++ b/clang/test/OpenMP/task_messages.cpp @@ -48,7 +48,6 @@ S1 s1; // expected-error@+1 2 {{call to deleted constructor of 'S1'}} #pragma omp task -// expected-note@+1 2 {{predetermined as a firstprivate in a task construct here}} ++s1; #pragma omp task default(none) // expected-note 2 {{explicit data sharing attribute requested here}} #pragma omp task default(shared) diff --git a/clang/test/SemaCXX/block-call.cpp b/clang/test/SemaCXX/block-call.cpp --- a/clang/test/SemaCXX/block-call.cpp +++ b/clang/test/SemaCXX/block-call.cpp @@ -10,8 +10,6 @@ int (^PFR) (int) = IFP; // expected-error {{cannot initialize a variable of type 'int (^)(int)' with an lvalue of type 'int (^)()'}} PFR = II; // OK - int (^IFP) () = PFR; // OK - const int (^CIC) () = IFP; // OK - initializing 'const int (^)()' with an expression of type 'int (^)()'}} @@ -32,8 +30,8 @@ int (^IPCC6) (int, char (^CArg) (float)) = IPCC4; // expected-error {{cannot initialize a variable of type 'int (^)(int, char (^)(float))' with an lvalue of type}} - IPCC2 = 0; - IPCC2 = 1; + IPCC2 = 0; // OK - assign a nullptr to a pointer. + IPCC2 = 1; // expected-error {{invalid block pointer conversion assigning to 'int *(^)()' from 'int'}} int (^x)() = 0; int (^y)() = 3; // expected-error {{cannot initialize a variable of type 'int (^)()' with an rvalue of type 'int'}} int a = 1; diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -877,9 +877,9 @@ // null pointer in C++11. Just check for an integer literal with value 0. constexpr Base *nullB = 42 - 6 * 7; // expected-error {{cannot initialize a variable of type 'Class::Base *const' with an rvalue of type 'int'}} constexpr Base *nullB1 = 0; -static_assert((Bottom*)nullB == 0, ""); -static_assert((Derived*)nullB == 0, ""); -static_assert((void*)(Bottom*)nullB == (void*)(Derived*)nullB, ""); +static_assert((Bottom*)nullB == 0, ""); // expected-error {{static_assert expression is not an integral constant expression}} +static_assert((Derived*)nullB1 == 0, ""); +static_assert((void*)(Bottom*)nullB1 == (void*)(Derived*)nullB1, ""); Base *nullB2 = '\0'; // expected-error {{cannot initialize a variable of type 'Class::Base *' with an rvalue of type 'char'}} Base *nullB3 = (0); Base *nullB4 = false; // expected-error {{cannot initialize a variable of type 'Class::Base *' with an rvalue of type 'bool'}} diff --git a/clang/test/SemaCXX/cxx11-crashes.cpp b/clang/test/SemaCXX/cxx11-crashes.cpp --- a/clang/test/SemaCXX/cxx11-crashes.cpp +++ b/clang/test/SemaCXX/cxx11-crashes.cpp @@ -67,7 +67,7 @@ struct S {}; // expected-note 3{{candidate}} void f() { S s(1, 2, 3); // expected-error {{no matching}} - for (auto x : s) { + for (auto x : s) { // expected-error {{invalid range expression of}} // We used to attempt to evaluate the initializer of this variable, // and crash because it has an undeduced type. const int &n(x); diff --git a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp --- a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp +++ b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp @@ -124,7 +124,7 @@ A && a6{ 0}; A a7 = { 0}; // expected-error {{chosen constructor is explicit in copy-initialization}} -a0 = 0; +a0 = 0; // expected-error {{no viable overloaded '='}} a1 = { 0}; // expected-error {{no viable overloaded '='}} a2 = A( 0); a3 = A{ 0}; diff --git a/clang/test/SemaCXX/for-range-dereference.cpp b/clang/test/SemaCXX/for-range-dereference.cpp --- a/clang/test/SemaCXX/for-range-dereference.cpp +++ b/clang/test/SemaCXX/for-range-dereference.cpp @@ -85,5 +85,4 @@ for (Data *p : pt) { } // expected-error {{invalid range expression of type 'T *'; did you mean to dereference it with '*'?}} // expected-error@-1 {{no viable conversion from 'Data' to 'Data *'}} - // expected-note@4 {{selected 'begin' function with iterator type 'Data *'}} } diff --git a/clang/test/SemaCXX/member-init.cpp b/clang/test/SemaCXX/member-init.cpp --- a/clang/test/SemaCXX/member-init.cpp +++ b/clang/test/SemaCXX/member-init.cpp @@ -64,7 +64,7 @@ template struct X { X() { - T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} + T* x = 1; // expected-error{{cannot initialize a variable of type 'int *' with an rvalue of type 'int'}} expected-warning {{unused variable}} } }; diff --git a/clang/test/SemaCXX/recovery-initializer.cpp b/clang/test/SemaCXX/recovery-initializer.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/recovery-initializer.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -frecovery-ast -verify %s + +// NOTE: these tests can be merged to existing tests after -frecovery-ast is +// turned on by default. +void test1() { + struct Data {}; + struct T { + Data *begin(); + Data *end(); + }; + T *pt; + for (Data *p : T()) {} // expected-error {{no viable conversion from 'Data' to 'Data *'}} + // expected-note@-5 {{selected 'begin' function with iterator type}} +} + +void test2() { + struct Bottom { + constexpr Bottom() {} + }; + struct Base : Bottom { + constexpr Base(int a = 42, const char *b = "test") : a(a), b(b) {} + int a; + const char *b; + }; + constexpr Base *nullB = 12; // expected-error {{cannot initialize a variable of type}} + // verify that the "static_assert expression is not an integral constant expr" + // diagnostic is suppressed. + static_assert((Bottom*)nullB == 0, ""); +} diff --git a/clang/test/SemaObjCXX/parameterized_classes_arc.mm b/clang/test/SemaObjCXX/parameterized_classes_arc.mm --- a/clang/test/SemaObjCXX/parameterized_classes_arc.mm +++ b/clang/test/SemaObjCXX/parameterized_classes_arc.mm @@ -13,7 +13,7 @@ @interface PC1 : NSObject - (T) get; -- (void) set: (T) v; +- (void) set: (T) v; // expected-note 4{{passing argument to}} @end void test1a(PC1<__weak id> *obj) { // expected-error {{type argument '__weak id' cannot be qualified with '__weak'}} @@ -34,17 +34,17 @@ // Test that this doesn't completely kill downstream type-checking. void test1d(PC1<__weak Forward*> *obj) { // expected-error {{type argument 'Forward *__weak' cannot be qualified with '__weak'}} Forward2 *x = [obj get]; // expected-error {{cannot initialize}} - [obj set: x]; + [obj set: x]; // expected-error {{cannot initialize a parameter of type 'Forward *' with an lvalue of type 'Forward2 *__strong'}} } void test1e(PC1<__strong Forward*> *obj) { // expected-error {{type argument 'Forward *__strong' cannot be qualified with '__strong'}} Forward2 *x = [obj get]; // expected-error {{cannot initialize}} - [obj set: x]; + [obj set: x]; // expected-error {{cannot initialize a parameter of type 'Forward *'}} } void test1f(PC1 *obj) { Forward2 *x = [obj get]; // expected-error {{cannot initialize}} - [obj set: x]; + [obj set: x]; // expected-error {{cannot initialize a parameter of type 'Forward *'}} } // Typedefs are fine, just silently ignore them. @@ -57,7 +57,7 @@ typedef __strong Forward *StrongForward; void test1h(PC1 *obj) { Forward2 *x = [obj get]; // expected-error {{cannot initialize}} - [obj set: x]; + [obj set: x]; // expected-error {{cannot initialize a parameter of type 'Forward *'}} } // These aren't really ARC-specific, but they're the same basic idea.