diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-09-20 21:52:32 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-09-20 21:52:32 +0000 |
commit | 8b533d97e0683a0c87096b95927a2e9ce02243d4 (patch) | |
tree | 7d5410b9c89d4fde235fe52eb592867cc579262c /lib/Sema/SemaStmt.cpp | |
parent | cb5336fa5985a02298aeccf473257c0fcd6b89b4 (diff) |
If the range in a for range statement doesn't have a viable begin/end function,
but can be dereferenced to form an expression which does have viable begin/end
functions, then typo-correct the range, even if something else goes wrong with
the statement (such as inaccessible begin/end or the wrong type of loop
variable).
In order to ensure we recover correctly and produce any followup diagnostics in
this case, redo semantic analysis on the for-range statement outside of the
diagnostic trap, after issuing the typo-correction.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164323 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaStmt.cpp')
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 72 |
1 files changed, 45 insertions, 27 deletions
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 17d1de81e7..70ece511d1 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1656,7 +1656,7 @@ static bool ObjCEnumerationCollection(Expr *Collection) { StmtResult Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, Stmt *First, SourceLocation ColonLoc, Expr *Range, - SourceLocation RParenLoc, bool ShouldTryDeref) { + SourceLocation RParenLoc, BuildForRangeKind Kind) { if (!First || !Range) return StmtError(); @@ -1694,7 +1694,7 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(), /*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS, - RParenLoc, ShouldTryDeref); + RParenLoc, Kind); } /// \brief Create the initialization, compare, and increment steps for @@ -1782,8 +1782,8 @@ static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, } /// Speculatively attempt to dereference an invalid range expression. -/// This function will not emit diagnostics, but returns StmtError if -/// an error occurs. +/// If the attempt fails, this function will return a valid, null StmtResult +/// and emit no diagnostics. static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, SourceLocation ForLoc, Stmt *LoopVarDecl, @@ -1791,22 +1791,40 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, Expr *Range, SourceLocation RangeLoc, SourceLocation RParenLoc) { - Sema::SFINAETrap Trap(SemaRef); - ExprResult AdjustedRange = SemaRef.BuildUnaryOp(S, RangeLoc, UO_Deref, Range); - StmtResult SR = - SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc, - AdjustedRange.get(), RParenLoc, false); - if (Trap.hasErrorOccurred()) - return StmtError(); - return SR; -} - -/// BuildCXXForRangeStmt - Build or instantiate a C++0x for-range statement. + // Determine whether we can rebuild the for-range statement with a + // dereferenced range expression. + ExprResult AdjustedRange; + { + Sema::SFINAETrap Trap(SemaRef); + + AdjustedRange = SemaRef.BuildUnaryOp(S, RangeLoc, UO_Deref, Range); + if (AdjustedRange.isInvalid()) + return StmtResult(); + + StmtResult SR = + SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc, + AdjustedRange.get(), RParenLoc, + Sema::BFRK_Check); + if (SR.isInvalid()) + return StmtResult(); + } + + // The attempt to dereference worked well enough that it could produce a valid + // loop. Produce a fixit, and rebuild the loop with diagnostics enabled, in + // case there are any other (non-fatal) problems with it. + SemaRef.Diag(RangeLoc, diag::err_for_range_dereference) + << Range->getType() << FixItHint::CreateInsertion(RangeLoc, "*"); + return SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc, + AdjustedRange.get(), RParenLoc, + Sema::BFRK_Rebuild); +} + +/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement. StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, - SourceLocation RParenLoc, bool ShouldTryDeref) { + SourceLocation RParenLoc, BuildForRangeKind Kind) { Scope *S = getCurScope(); DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl); @@ -1902,25 +1920,19 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, // If building the range failed, try dereferencing the range expression // unless a diagnostic was issued or the end function is problematic. - if (ShouldTryDeref && RangeStatus == FRS_NoViableFunction && + if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction && BEFFailure == BEF_begin) { StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc, LoopVarDecl, ColonLoc, Range, RangeLoc, RParenLoc); - if (!SR.isInvalid()) { - // The attempt to dereference would succeed; return the result of - // recovery. - Diag(RangeLoc, diag::err_for_range_dereference) - << RangeLoc << RangeType - << FixItHint::CreateInsertion(RangeLoc, "*"); + if (SR.isInvalid() || SR.isUsable()) return SR; - } } // Otherwise, emit diagnostics if we haven't already. if (RangeStatus == FRS_NoViableFunction) { - Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get(); + Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get(); Diag(Range->getLocStart(), diag::err_for_range_invalid) << RangeLoc << Range->getType() << BEFFailure; CandidateSet.NoteCandidates(*this, OCD_AllCandidates, @@ -2003,8 +2015,9 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, return StmtError(); } - // Attach *__begin as initializer for VD. - if (!LoopVar->isInvalidDecl()) { + // Attach *__begin as initializer for VD. Don't touch it if we're just + // trying to determine whether this would be a valid range. + if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) { AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false, /*TypeMayContainAuto=*/true); if (LoopVar->isInvalidDecl()) @@ -2015,6 +2028,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, RangeVar->setUsed(); } + // Don't bother to actually allocate the result if we're just trying to + // determine whether it would be valid. + if (Kind == BFRK_Check) + return StmtResult(); + return Owned(new (Context) CXXForRangeStmt(RangeDS, cast_or_null<DeclStmt>(BeginEndDecl.get()), NotEqExpr.take(), IncrExpr.take(), |