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