From: Richard Smith Date: Wed, 21 Aug 2013 01:40:36 +0000 (+0000) Subject: If we find an error in the range expression in a range-based for loop, and the X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=37aa0f7ca567128fb00f88ceb4a7c229833f257e;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188853 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 5b21c93426..0570a60a0a 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -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(First); @@ -1844,11 +1844,13 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, 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(SourceLocation ForLoc, 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 **)&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 RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, 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(SourceLocation ForLoc, SourceLocation ColonLoc, DeclStmt *LoopVarDS = cast(LoopVarDecl); VarDecl *LoopVar = cast(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; diff --git a/test/SemaCXX/cxx11-crashes.cpp b/test/SemaCXX/cxx11-crashes.cpp index a4d4829f3f..bd51af1da2 100644 --- a/test/SemaCXX/cxx11-crashes.cpp +++ b/test/SemaCXX/cxx11-crashes.cpp @@ -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); } } } diff --git a/test/SemaCXX/for-range-examples.cpp b/test/SemaCXX/for-range-examples.cpp index ca505e0245..08c6936816 100644 --- a/test/SemaCXX/for-range-examples.cpp +++ b/test/SemaCXX/for-range-examples.cpp @@ -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(); + } +}