This revision was automatically updated to reflect the committed changes.
hokein marked an inline comment as done.
Closed by commit rG89d9912cbf45: [AST] dont invaliate VarDecl when the 
initializer contains errors. (authored by hokein).

Changed prior to commit:
  https://reviews.llvm.org/D78116?vs=258169&id=258933#toc

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D78116/new/

https://reviews.llvm.org/D78116

Files:
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaStmt.cpp
  clang/test/AST/ast-dump-invalid-initialized.cpp
  clang/test/AST/ast-dump-recovery.cpp
  clang/test/CXX/special/class.copy/p11.0x.move.cpp
  clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
  clang/test/OpenMP/task_messages.cpp
  clang/test/SemaCXX/block-call.cpp
  clang/test/SemaCXX/constant-expression-cxx11.cpp
  clang/test/SemaCXX/cxx11-crashes.cpp
  clang/test/SemaCXX/cxx2a-explicit-bool.cpp
  clang/test/SemaCXX/for-range-dereference.cpp
  clang/test/SemaCXX/member-init.cpp
  clang/test/SemaCXX/recovery-initializer.cpp
  clang/test/SemaObjCXX/parameterized_classes_arc.mm

Index: clang/test/SemaObjCXX/parameterized_classes_arc.mm
===================================================================
--- clang/test/SemaObjCXX/parameterized_classes_arc.mm
+++ clang/test/SemaObjCXX/parameterized_classes_arc.mm
@@ -13,7 +13,7 @@
 
 @interface PC1<T> : 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<Forward*> *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<StrongForward> *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.
Index: clang/test/SemaCXX/recovery-initializer.cpp
===================================================================
--- /dev/null
+++ 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, "");
+}
Index: clang/test/SemaCXX/member-init.cpp
===================================================================
--- clang/test/SemaCXX/member-init.cpp
+++ clang/test/SemaCXX/member-init.cpp
@@ -64,7 +64,7 @@
   template<typename T>
   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}}
     }
   };
 
Index: clang/test/SemaCXX/for-range-dereference.cpp
===================================================================
--- clang/test/SemaCXX/for-range-dereference.cpp
+++ 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 *'}}
 }
Index: clang/test/SemaCXX/cxx2a-explicit-bool.cpp
===================================================================
--- clang/test/SemaCXX/cxx2a-explicit-bool.cpp
+++ clang/test/SemaCXX/cxx2a-explicit-bool.cpp
@@ -124,7 +124,7 @@
 A<true> && a6{ 0};
 A<true> 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<true>( 0);
 a3 = A<true>{ 0};
Index: clang/test/SemaCXX/cxx11-crashes.cpp
===================================================================
--- clang/test/SemaCXX/cxx11-crashes.cpp
+++ 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);
Index: clang/test/SemaCXX/constant-expression-cxx11.cpp
===================================================================
--- clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ 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'}}
Index: clang/test/SemaCXX/block-call.cpp
===================================================================
--- clang/test/SemaCXX/block-call.cpp
+++ 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;
Index: clang/test/OpenMP/task_messages.cpp
===================================================================
--- clang/test/OpenMP/task_messages.cpp
+++ 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)
Index: clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
===================================================================
--- clang/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp
+++ 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<typename T>
-    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<typename T>
     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();
   };
 
Index: clang/test/CXX/special/class.copy/p11.0x.move.cpp
===================================================================
--- clang/test/CXX/special/class.copy/p11.0x.move.cpp
+++ clang/test/CXX/special/class.copy/p11.0x.move.cpp
@@ -32,7 +32,7 @@
   };
 };
 extern DeletedNTVariant3<NonTrivial> dntv3a(0); // expected-error {{no matching}}
-extern DeletedNTVariant3<DeletedCopy> dntv3a(0); // expected-error {{no matching}}
+extern DeletedNTVariant3<DeletedCopy> 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
Index: clang/test/AST/ast-dump-recovery.cpp
===================================================================
--- clang/test/AST/ast-dump-recovery.cpp
+++ 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()};
+}
Index: clang/test/AST/ast-dump-invalid-initialized.cpp
===================================================================
--- clang/test/AST/ast-dump-invalid-initialized.cpp
+++ 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
Index: clang/lib/Sema/SemaStmt.cpp
===================================================================
--- clang/lib/Sema/SemaStmt.cpp
+++ 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);
     }
   }
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ 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;
     }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to