r188853 - If we find an error in the range expression in a range-based for loop, and the

Richard Smith richard-llvm at metafoo.co.uk
Tue Aug 20 18:40:36 PDT 2013


Author: rsmith
Date: Tue Aug 20 20:40:36 2013
New Revision: 188853

URL: http://llvm.org/viewvc/llvm-project?rev=188853&view=rev
Log:
If we find an error in the range expression in a range-based for loop, and the
loop variable has a type containing 'auto', set the declaration to be invalid
(because we couldn't deduce its type) to prevent follow-on errors.

Modified:
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/test/SemaCXX/cxx11-crashes.cpp
    cfe/trunk/test/SemaCXX/for-range-examples.cpp

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=188853&r1=188852&r2=188853&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Aug 20 20:40:36 2013
@@ -1831,10 +1831,10 @@ StmtResult
 Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc,
                            Stmt *First, SourceLocation ColonLoc, Expr *Range,
                            SourceLocation RParenLoc, BuildForRangeKind Kind) {
-  if (!First || !Range)
+  if (!First)
     return StmtError();
 
-  if (ObjCEnumerationCollection(Range))
+  if (Range && ObjCEnumerationCollection(Range))
     return ActOnObjCForCollectionStmt(ForLoc, First, Range, RParenLoc);
 
   DeclStmt *DS = dyn_cast<DeclStmt>(First);
@@ -1844,11 +1844,13 @@ Sema::ActOnCXXForRangeStmt(SourceLocatio
     Diag(DS->getStartLoc(), diag::err_type_defined_in_for_range);
     return StmtError();
   }
-  if (DS->getSingleDecl()->isInvalidDecl())
-    return StmtError();
 
-  if (DiagnoseUnexpandedParameterPack(Range, UPPC_Expression))
+  Decl *LoopVar = DS->getSingleDecl();
+  if (LoopVar->isInvalidDecl() || !Range ||
+      DiagnoseUnexpandedParameterPack(Range, UPPC_Expression)) {
+    LoopVar->setInvalidDecl();
     return StmtError();
+  }
 
   // Build  auto && __range = range-init
   SourceLocation RangeLoc = Range->getLocStart();
@@ -1856,16 +1858,20 @@ Sema::ActOnCXXForRangeStmt(SourceLocatio
                                            Context.getAutoRRefDeductType(),
                                            "__range");
   if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc,
-                            diag::err_for_range_deduction_failure))
+                            diag::err_for_range_deduction_failure)) {
+    LoopVar->setInvalidDecl();
     return StmtError();
+  }
 
   // Claim the type doesn't contain auto: we've already done the checking.
   DeclGroupPtrTy RangeGroup =
       BuildDeclaratorGroup(llvm::MutableArrayRef<Decl *>((Decl **)&RangeVar, 1),
                            /*TypeMayContainAuto=*/ false);
   StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc);
-  if (RangeDecl.isInvalid())
+  if (RangeDecl.isInvalid()) {
+    LoopVar->setInvalidDecl();
     return StmtError();
+  }
 
   return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(),
                               /*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS,
@@ -1994,6 +2000,22 @@ static StmtResult RebuildForRangeWithDer
                                       Sema::BFRK_Rebuild);
 }
 
+namespace {
+/// RAII object to automatically invalidate a declaration if an error occurs.
+struct InvalidateOnErrorScope {
+  InvalidateOnErrorScope(Sema &SemaRef, Decl *D, bool Enabled)
+      : Trap(SemaRef.Diags), D(D), Enabled(Enabled) {}
+  ~InvalidateOnErrorScope() {
+    if (Enabled && Trap.hasErrorOccurred())
+      D->setInvalidDecl();
+  }
+
+  DiagnosticErrorTrap Trap;
+  Decl *D;
+  bool Enabled;
+};
+}
+
 /// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
 StmtResult
 Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc,
@@ -2009,6 +2031,11 @@ Sema::BuildCXXForRangeStmt(SourceLocatio
   DeclStmt *LoopVarDS = cast<DeclStmt>(LoopVarDecl);
   VarDecl *LoopVar = cast<VarDecl>(LoopVarDS->getSingleDecl());
 
+  // If we hit any errors, mark the loop variable as invalid if its type
+  // contains 'auto'.
+  InvalidateOnErrorScope Invalidate(*this, LoopVar,
+                                    LoopVar->getType()->isUndeducedType());
+
   StmtResult BeginEndDecl = BeginEnd;
   ExprResult NotEqExpr = Cond, IncrExpr = Inc;
 

Modified: cfe/trunk/test/SemaCXX/cxx11-crashes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx11-crashes.cpp?rev=188853&r1=188852&r2=188853&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx11-crashes.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx11-crashes.cpp Tue Aug 20 20:40:36 2013
@@ -70,9 +70,7 @@ namespace b6981007 {
     for (auto x : s) {
       // We used to attempt to evaluate the initializer of this variable,
       // and crash because it has an undeduced type.
-      // FIXME: We should set the loop variable to be invalid if we can't build
-      // the loop, to suppress this follow-on error.
-      const int &n(x); // expected-error {{could not bind to an lvalue of type 'auto'}}
+      const int &n(x);
     }
   }
 }

Modified: cfe/trunk/test/SemaCXX/for-range-examples.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/for-range-examples.cpp?rev=188853&r1=188852&r2=188853&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/for-range-examples.cpp (original)
+++ cfe/trunk/test/SemaCXX/for-range-examples.cpp Tue Aug 20 20:40:36 2013
@@ -180,3 +180,14 @@ namespace test4 {
     for (y : {1, 2, 3}) {} // expected-error {{must declare a variable}} expected-warning {{result unused}}
   }
 }
+
+namespace test5 {
+  // Test error-recovery.
+  void f() {
+    for (auto x : undeclared_identifier) // expected-error {{undeclared identifier}}
+      for (auto y : x->foo)
+        y->bar();
+    for (auto x : 123) // expected-error {{no viable 'begin'}}
+      x->foo();
+  }
+}





More information about the cfe-commits mailing list