hokein created this revision.
hokein added a reviewer: sammccall.
Herald added a project: clang.

This might be splitted into 2 separate patchs:

1. the initializer of a variable should play no part in decl "invalid" bit;
2. preserve the exprs in an error initializer via recovery exprs;

if we do 1) only, we will regress the diagnostics (one big regression is that
we loose the "selected 'begin' function with iterator type" diagnostic in 
for-range stmt;
with 2) together, we don't have regressions (the new diagnostics seems to be
improved).


Repository:
  rG LLVM Github Monorepo

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/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/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
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -frecovery-ast -verify %s
 struct Data { };
 struct T {
   Data *begin();
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
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fsyntax-only -fcxx-exceptions -verify -std=c++11 -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
+// RUN: %clang_cc1 -triple x86_64-linux -Wno-string-plus-int -Wno-pointer-arith -Wno-zero-length-array -Wno-c99-designator -fsyntax-only -fcxx-exceptions -verify -frecovery-ast -std=c++11 -pedantic %s -Wno-comment -Wno-tautological-pointer-compare -Wno-bool-conversion
 
 namespace StaticAssertFoldTest {
 
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
@@ -1,6 +1,6 @@
-// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -frecovery-ast -verify %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -frecovery-ast -verify %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -frecovery-ast -verify %s
 
 struct pr12960 {
   int begin;
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
@@ -94,7 +94,28 @@
 // CHECK-NEXT:  | `-DeclRefExpr {{.*}} 'foo'
 // CHECK-NEXT:  `-DeclRefExpr {{.*}} 'x'
 struct Foo {} foo;
-void test(int x) {
+void test1(int x) {
   foo.abc;
   foo->func(x);
-}
\ No newline at end of file
+}
+
+struct Bar { Bar(); };
+Bar createBar(int arg);
+void test2() {
+  // CHECK:      `-VarDecl {{.*}} bar1 'Bar'
+  // CHECK-NEXT:  `-RecoveryExpr {{.*}} contains-errors
+  // CHECK-NEXT:   `-UnresolvedLookupExpr {{.*}} 'createBar'
+  Bar bar1 = createBar();
+  // CHECK:      `-VarDecl {{.*}} bar2 'Bar'
+  // CHECK-NEXT:  `-RecoveryExpr {{.*}} contains-errors
+  // CHECK-NEXT:   `-InitListExpr
+  Bar bar2 = {1};
+  // CHECK:      `-VarDecl {{.*}} bar3 'Bar'
+  // CHECK-NEXT:  `-RecoveryExpr {{.*}} contains-errors
+  // CHECK-NEXT:   `-IntegerLiteral
+  Bar bar3 = 1;
+
+  // FIXME: would be nice to have recovery-expr for the failed ctor candidates
+  Bar foo1 = Bar(1);
+  Bar foo2 = Bar{1};
+}
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
@@ -11,9 +11,35 @@
   // CHECK: `-VarDecl {{.*}} a3 'A'
   A a3 = garbage();
 
+  // CHECK: `-VarDecl {{.*}} a4 'A'
+  A a4(1);
+  // CHECK: `-VarDecl {{.*}} a5 'A'
+  A a5{1};
+  // CHECK: `-VarDecl {{.*}} a6 'A'
+  A a6(invalid());
+  // CHECK: `-VarDecl {{.*}} a7 'A'
+  A a7{invalid()};
+
+  // CHECK: `-VarDecl {{.*}} a8 'A'
+  A a8 = 1;
+  // CHECK: `-VarDecl {{.*}} a9 'A'
+  A a9 = A(1);
+  // CHECK: `-VarDecl {{.*}} a10 'A'
+  A a10 = A(var);
+  // CHECK: `-VarDecl {{.*}} a11 'A'
+  A a11 = A{1};
+  // CHECK: `-VarDecl {{.*}} a12 'A'
+  A a12 = {1};
+
 
   // CHECK: `-VarDecl {{.*}} invalid b1 'const A &'
   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,10 @@
                                    /*TreatUnavailableAsInvalid=*/false);
     ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
     if (Result.isInvalid()) {
-      VDecl->setInvalidDecl();
+      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