diff options
author | Sam Panzer <espanz@gmail.com> | 2012-08-21 00:52:01 +0000 |
---|---|---|
committer | Sam Panzer <espanz@gmail.com> | 2012-08-21 00:52:01 +0000 |
commit | e1715b66a878bcab315513351e5df68bfc010d2e (patch) | |
tree | bd09db1864a394c68f16dfa348c04f7399d0b562 /lib | |
parent | a34d4f47321324187ed57948628f5938357ae034 (diff) |
Better diagnostics for range-based for loops with bad range types.
The old error message stating that 'begin' was an undeclared identifier
is replaced with a new message explaining that the error is in the range
expression, along with which of the begin() and end() functions was
problematic if relevant.
Additionally, if the range was a pointer type or defines operator*,
attempt to dereference the range, and offer a FixIt if the modified range
works.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162248 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 233 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 270 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 2 |
4 files changed, 336 insertions, 171 deletions
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 0716f6f901..091d4aaaf2 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1441,7 +1441,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, FirstPart.take(), ForRangeInit.ColonLoc, ForRangeInit.RangeExpr.get(), - T.getCloseLocation()); + T.getCloseLocation(), true); // Similarly, we need to do the semantic analysis for a for-range diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 9382f7dddc..efc5b6eb0d 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -9695,20 +9695,15 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, RParenLoc); } -/// ResolveOverloadedCallFn - Given the call expression that calls Fn -/// (which eventually refers to the declaration Func) and the call -/// arguments Args/NumArgs, attempt to resolve the function call down -/// to a specific function. If overload resolution succeeds, returns -/// the function declaration produced by overload -/// resolution. Otherwise, emits diagnostics, deletes all of the -/// arguments and Fn, and returns NULL. -ExprResult -Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, - SourceLocation LParenLoc, - Expr **Args, unsigned NumArgs, - SourceLocation RParenLoc, - Expr *ExecConfig, - bool AllowTypoCorrection) { +/// \brief Constructs and populates an OverloadedCandidateSet from +/// the given function. +/// \returns true when an the ExprResult output parameter has been set. +bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, + UnresolvedLookupExpr *ULE, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc, + OverloadCandidateSet *CandidateSet, + ExprResult *Result) { #ifndef NDEBUG if (ULE->requiresADL()) { // To do ADL, we must have found an unqualified name. @@ -9730,20 +9725,20 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, #endif UnbridgedCastsSet UnbridgedCasts; - if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts)) - return ExprError(); - - OverloadCandidateSet CandidateSet(Fn->getExprLoc()); + if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts)) { + *Result = ExprError(); + return true; + } // Add the functions denoted by the callee to the set of candidate // functions, including those from argument-dependent lookup. AddOverloadedCallCandidates(ULE, llvm::makeArrayRef(Args, NumArgs), - CandidateSet); + *CandidateSet); // If we found nothing, try to recover. // BuildRecoveryCallExpr diagnoses the error itself, so we just bail // out if it fails. - if (CandidateSet.empty()) { + if (CandidateSet->empty()) { // In Microsoft mode, if we are inside a template class member function then // create a type dependent CallExpr. The goal is to postpone name lookup // to instantiation time to be able to search into type dependent base @@ -9754,32 +9749,50 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, Context.DependentTy, VK_RValue, RParenLoc); CE->setTypeDependent(true); - return Owned(CE); + *Result = Owned(CE); + return true; } - return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, - llvm::MutableArrayRef<Expr *>(Args, NumArgs), - RParenLoc, /*EmptyLookup=*/true, - AllowTypoCorrection); + return false; } UnbridgedCasts.restore(); + return false; +} - OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) { +/// FinishOverloadedCallExpr - given an OverloadCandidateSet, builds and returns +/// the completed call expression. If overload resolution fails, emits +/// diagnostics and returns ExprError() +static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, + UnresolvedLookupExpr *ULE, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc, + Expr *ExecConfig, + OverloadCandidateSet *CandidateSet, + OverloadCandidateSet::iterator *Best, + OverloadingResult OverloadResult, + bool AllowTypoCorrection) { + if (CandidateSet->empty()) + return BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc, + llvm::MutableArrayRef<Expr *>(Args, NumArgs), + RParenLoc, /*EmptyLookup=*/true, + AllowTypoCorrection); + + switch (OverloadResult) { case OR_Success: { - FunctionDecl *FDecl = Best->Function; - MarkFunctionReferenced(Fn->getExprLoc(), FDecl); - CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); - DiagnoseUseOfDecl(FDecl, ULE->getNameLoc()); - Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); - return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc, - ExecConfig); + FunctionDecl *FDecl = (*Best)->Function; + SemaRef.MarkFunctionReferenced(Fn->getExprLoc(), FDecl); + SemaRef.CheckUnresolvedLookupAccess(ULE, (*Best)->FoundDecl); + SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc()); + Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); + return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, + RParenLoc, ExecConfig); } case OR_No_Viable_Function: { // Try to recover by looking for viable functions which the user might // have meant to call. - ExprResult Recovery = BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, + ExprResult Recovery = BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc, llvm::MutableArrayRef<Expr *>(Args, NumArgs), RParenLoc, /*EmptyLookup=*/false, @@ -9787,44 +9800,73 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, if (!Recovery.isInvalid()) return Recovery; - Diag(Fn->getLocStart(), + SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_no_viable_function_in_call) << ULE->getName() << Fn->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, - llvm::makeArrayRef(Args, NumArgs)); + CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, + llvm::makeArrayRef(Args, NumArgs)); break; } case OR_Ambiguous: - Diag(Fn->getLocStart(), diag::err_ovl_ambiguous_call) + SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_ambiguous_call) << ULE->getName() << Fn->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, - llvm::makeArrayRef(Args, NumArgs)); + CandidateSet->NoteCandidates(SemaRef, OCD_ViableCandidates, + llvm::makeArrayRef(Args, NumArgs)); break; - case OR_Deleted: - { - Diag(Fn->getLocStart(), diag::err_ovl_deleted_call) - << Best->Function->isDeleted() - << ULE->getName() - << getDeletedOrUnavailableSuffix(Best->Function) - << Fn->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, - llvm::makeArrayRef(Args, NumArgs)); + case OR_Deleted: { + SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_deleted_call) + << (*Best)->Function->isDeleted() + << ULE->getName() + << SemaRef.getDeletedOrUnavailableSuffix((*Best)->Function) + << Fn->getSourceRange(); + CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, + llvm::makeArrayRef(Args, NumArgs)); - // We emitted an error for the unvailable/deleted function call but keep - // the call in the AST. - FunctionDecl *FDecl = Best->Function; - Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); - return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, - RParenLoc, ExecConfig); - } + // We emitted an error for the unvailable/deleted function call but keep + // the call in the AST. + FunctionDecl *FDecl = (*Best)->Function; + Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); + return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, + RParenLoc, ExecConfig); + } } // Overload resolution failed. return ExprError(); } +/// BuildOverloadedCallExpr - Given the call expression that calls Fn +/// (which eventually refers to the declaration Func) and the call +/// arguments Args/NumArgs, attempt to resolve the function call down +/// to a specific function. If overload resolution succeeds, returns +/// the call expression produced by overload resolution. +/// Otherwise, emits diagnostics and returns ExprError. +ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, + UnresolvedLookupExpr *ULE, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc, + Expr *ExecConfig, + bool AllowTypoCorrection) { + OverloadCandidateSet CandidateSet(Fn->getExprLoc()); + ExprResult result; + + if (buildOverloadedCallSet(S, Fn, ULE, Args, NumArgs, LParenLoc, + &CandidateSet, &result)) + return result; + + OverloadCandidateSet::iterator Best; + OverloadingResult OverloadResult = + CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best); + + return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs, + RParenLoc, ExecConfig, &CandidateSet, + &Best, OverloadResult, + AllowTypoCorrection); +} + static bool IsOverloaded(const UnresolvedSetImpl &Functions) { return Functions.size() > 1 || (Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin())); @@ -11199,6 +11241,83 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, return MaybeBindToTemporary(UDL); } +/// Build a call to 'begin' or 'end' for a C++11 for-range statement. If the +/// given LookupResult is non-empty, it is assumed to describe a member which +/// will be invoked. Otherwise, the function will be found via argument +/// dependent lookup. +/// CallExpr is set to a valid expression and FRS_Success returned on success, +/// otherwise CallExpr is set to ExprError() and some non-success value +/// is returned. +Sema::ForRangeStatus +Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, + SourceLocation RangeLoc, VarDecl *Decl, + BeginEndFunction BEF, + const DeclarationNameInfo &NameInfo, + LookupResult &MemberLookup, + OverloadCandidateSet *CandidateSet, + Expr *Range, ExprResult *CallExpr) { + CandidateSet->clear(); + if (!MemberLookup.empty()) { + ExprResult MemberRef = + BuildMemberReferenceExpr(Range, Range->getType(), Loc, + /*IsPtr=*/false, CXXScopeSpec(), + /*TemplateKWLoc=*/SourceLocation(), + /*FirstQualifierInScope=*/0, + MemberLookup, + /*TemplateArgs=*/0); + if (MemberRef.isInvalid()) { + *CallExpr = ExprError(); + Diag(Range->getLocStart(), diag::note_in_for_range) + << RangeLoc << BEF << Range->getType(); + return FRS_DiagnosticIssued; + } + *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(), Loc, 0); + if (CallExpr->isInvalid()) { + *CallExpr = ExprError(); + Diag(Range->getLocStart(), diag::note_in_for_range) + << RangeLoc << BEF << Range->getType(); + return FRS_DiagnosticIssued; + } + } else { + UnresolvedSet<0> FoundNames; + // C++11 [stmt.ranged]p1: For the purposes of this name lookup, namespace + // std is an associated namespace. + UnresolvedLookupExpr *Fn = + UnresolvedLookupExpr::Create(Context, /*NamingClass=*/0, + NestedNameSpecifierLoc(), NameInfo, + /*NeedsADL=*/true, /*Overloaded=*/false, + FoundNames.begin(), FoundNames.end(), + /*LookInStdNamespace=*/true); + + bool CandidateSetError = buildOverloadedCallSet(S, Fn, Fn, &Range, 1, Loc, + CandidateSet, CallExpr); + if (CandidateSet->empty() || CandidateSetError) { + *CallExpr = ExprError(); + return FRS_NoViableFunction; + } + OverloadCandidateSet::iterator Best; + OverloadingResult OverloadResult = + CandidateSet->BestViableFunction(*this, Fn->getLocStart(), Best); + + if (OverloadResult == OR_No_Viable_Function) { + *CallExpr = ExprError(); + return FRS_NoViableFunction; + } + *CallExpr = FinishOverloadedCallExpr(*this, S, Fn, Fn, Loc, &Range, 1, + Loc, 0, CandidateSet, &Best, + OverloadResult, + /*AllowTypoCorrection=*/false); + if (CallExpr->isInvalid() || OverloadResult != OR_Success) { + *CallExpr = ExprError(); + Diag(Range->getLocStart(), diag::note_in_for_range) + << RangeLoc << BEF << Range->getType(); + return FRS_DiagnosticIssued; + } + } + return FRS_Success; +} + + /// FixOverloadedFunctionReference - E is an expression that refers to /// a C++ overloaded function (possibly with some parentheses and /// perhaps a '&' around it). We have resolved the overloaded function diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index bb025a4fb3..8367c1a220 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1549,25 +1549,6 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, ForLoc, RParenLoc)); } -namespace { - -enum BeginEndFunction { - BEF_begin, - BEF_end -}; - -/// Build a variable declaration for a for-range statement. -static VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, - QualType Type, const char *Name) { - DeclContext *DC = SemaRef.CurContext; - IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); - TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); - VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, - TInfo, SC_Auto, SC_None); - Decl->setImplicit(); - return Decl; -} - /// Finish building a variable declaration for a for-range statement. /// \return true if an error occurs. static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, @@ -1600,12 +1581,14 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, return false; } +namespace { + /// Produce a note indicating which begin/end function was implicitly called -/// by a C++0x for-range statement. This is often not obvious from the code, +/// by a C++11 for-range statement. This is often not obvious from the code, /// nor from the diagnostics produced when analysing the implicit expressions /// required in a for-range statement. void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E, - BeginEndFunction BEF) { + Sema::BeginEndFunction BEF) { CallExpr *CE = dyn_cast<CallExpr>(E); if (!CE) return; @@ -1626,56 +1609,16 @@ void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E, << BEF << IsTemplate << Description << E->getType(); } -/// Build a call to 'begin' or 'end' for a C++0x for-range statement. If the -/// given LookupResult is non-empty, it is assumed to describe a member which -/// will be invoked. Otherwise, the function will be found via argument -/// dependent lookup. -static ExprResult BuildForRangeBeginEndCall(Sema &SemaRef, Scope *S, - SourceLocation Loc, - VarDecl *Decl, - BeginEndFunction BEF, - const DeclarationNameInfo &NameInfo, - LookupResult &MemberLookup, - Expr *Range) { - ExprResult CallExpr; - if (!MemberLookup.empty()) { - ExprResult MemberRef = - SemaRef.BuildMemberReferenceExpr(Range, Range->getType(), Loc, - /*IsPtr=*/false, CXXScopeSpec(), - /*TemplateKWLoc=*/SourceLocation(), - /*FirstQualifierInScope=*/0, - MemberLookup, - /*TemplateArgs=*/0); - if (MemberRef.isInvalid()) - return ExprError(); - CallExpr = SemaRef.ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(), - Loc, 0); - if (CallExpr.isInvalid()) - return ExprError(); - } else { - UnresolvedSet<0> FoundNames; - // C++0x [stmt.ranged]p1: For the purposes of this name lookup, namespace - // std is an associated namespace. - UnresolvedLookupExpr *Fn = - UnresolvedLookupExpr::Create(SemaRef.Context, /*NamingClass=*/0, - NestedNameSpecifierLoc(), NameInfo, - /*NeedsADL=*/true, /*Overloaded=*/false, - FoundNames.begin(), FoundNames.end(), - /*LookInStdNamespace=*/true); - CallExpr = SemaRef.BuildOverloadedCallExpr(S, Fn, Fn, Loc, &Range, 1, Loc, - 0, /*AllowTypoCorrection=*/false); - if (CallExpr.isInvalid()) { - SemaRef.Diag(Range->getLocStart(), diag::note_for_range_type) - << Range->getType(); - return ExprError(); - } - } - if (FinishForRangeVarDecl(SemaRef, Decl, CallExpr.get(), Loc, - diag::err_for_range_iter_deduction_failure)) { - NoteForRangeBeginEndFunction(SemaRef, CallExpr.get(), BEF); - return ExprError(); - } - return CallExpr; +/// Build a variable declaration for a for-range statement. +VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, + QualType Type, const char *Name) { + DeclContext *DC = SemaRef.CurContext; + IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); + TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); + VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, + TInfo, SC_Auto, SC_None); + Decl->setImplicit(); + return Decl; } } @@ -1706,7 +1649,7 @@ static bool ObjCEnumerationCollection(Expr *Collection) { StmtResult Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, Stmt *First, SourceLocation ColonLoc, Expr *Range, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, bool ShouldTryDeref) { if (!First || !Range) return StmtError(); @@ -1744,7 +1687,111 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(), /*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS, - RParenLoc); + RParenLoc, ShouldTryDeref); +} + +/// \brief Create the initialization, compare, and increment steps for +/// the range-based for loop expression. +/// This function does not handle array-based for loops, +/// which are created in Sema::BuildCXXForRangeStmt. +/// +/// \returns a ForRangeStatus indicating success or what kind of error occurred. +/// BeginExpr and EndExpr are set and FRS_Success is returned on success; +/// CandidateSet and BEF are set and some non-success value is returned on +/// failure. +static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, + Expr *BeginRange, Expr *EndRange, + QualType RangeType, + VarDecl *BeginVar, + VarDecl *EndVar, + SourceLocation ColonLoc, + OverloadCandidateSet *CandidateSet, + ExprResult *BeginExpr, + ExprResult *EndExpr, + Sema::BeginEndFunction *BEF) { + DeclarationNameInfo BeginNameInfo( + &SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc); + DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"), + ColonLoc); + + LookupResult BeginMemberLookup(SemaRef, BeginNameInfo, + Sema::LookupMemberName); + LookupResult EndMemberLookup(SemaRef, EndNameInfo, Sema::LookupMemberName); + + if (CXXRecordDecl *D = RangeType->getAsCXXRecordDecl()) { + // - if _RangeT is a class type, the unqualified-ids begin and end are + // looked up in the scope of class _RangeT as if by class member access + // lookup (3.4.5), and if either (or both) finds at least one + // declaration, begin-expr and end-expr are __range.begin() and + // __range.end(), respectively; + SemaRef.LookupQualifiedName(BeginMemberLookup, D); + SemaRef.LookupQualifiedName(EndMemberLookup, D); + + if (BeginMemberLookup.empty() != EndMemberLookup.empty()) { + SourceLocation RangeLoc = BeginVar->getLocation(); + *BEF = BeginMemberLookup.empty() ? Sema::BEF_end : Sema::BEF_begin; + + SemaRef.Diag(RangeLoc, diag::err_for_range_member_begin_end_mismatch) + << RangeLoc << BeginRange->getType() << *BEF; + return Sema::FRS_DiagnosticIssued; + } + } else { + // - otherwise, begin-expr and end-expr are begin(__range) and + // end(__range), respectively, where begin and end are looked up with + // argument-dependent lookup (3.4.2). For the purposes of this name + // lookup, namespace std is an associated namespace. + + } + + *BEF = Sema::BEF_begin; + Sema::ForRangeStatus RangeStatus = + SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, BeginVar, + Sema::BEF_begin, BeginNameInfo, + BeginMemberLookup, CandidateSet, + BeginRange, BeginExpr); + + if (RangeStatus != Sema::FRS_Success) + return RangeStatus; + if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc, + diag::err_for_range_iter_deduction_failure)) { + NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF); + return Sema::FRS_DiagnosticIssued; + } + + *BEF = Sema::BEF_end; + RangeStatus = + SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, EndVar, + Sema::BEF_end, EndNameInfo, + EndMemberLookup, CandidateSet, + EndRange, EndExpr); + if (RangeStatus != Sema::FRS_Success) + return RangeStatus; + if (FinishForRangeVarDecl(SemaRef, EndVar, EndExpr->get(), ColonLoc, + diag::err_for_range_iter_deduction_failure)) { + NoteForRangeBeginEndFunction(SemaRef, EndExpr->get(), *BEF); + return Sema::FRS_DiagnosticIssued; + } + return Sema::FRS_Success; +} + +/// Speculatively attempt to dereference an invalid range expression. +/// This function will not emit diagnostics, but returns StmtError if +/// an error occurs. +static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, + SourceLocation ForLoc, + Stmt *LoopVarDecl, + SourceLocation ColonLoc, + 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. @@ -1752,7 +1799,7 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, bool ShouldTryDeref) { Scope *S = getCurScope(); DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl); @@ -1838,50 +1885,49 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, return StmtError(); } } else { - DeclarationNameInfo BeginNameInfo(&PP.getIdentifierTable().get("begin"), - ColonLoc); - DeclarationNameInfo EndNameInfo(&PP.getIdentifierTable().get("end"), - ColonLoc); - - LookupResult BeginMemberLookup(*this, BeginNameInfo, LookupMemberName); - LookupResult EndMemberLookup(*this, EndNameInfo, LookupMemberName); - - if (CXXRecordDecl *D = RangeType->getAsCXXRecordDecl()) { - // - if _RangeT is a class type, the unqualified-ids begin and end are - // looked up in the scope of class _RangeT as if by class member access - // lookup (3.4.5), and if either (or both) finds at least one - // declaration, begin-expr and end-expr are __range.begin() and - // __range.end(), respectively; - LookupQualifiedName(BeginMemberLookup, D); - LookupQualifiedName(EndMemberLookup, D); - - if (BeginMemberLookup.empty() != EndMemberLookup.empty()) { - Diag(ColonLoc, diag::err_for_range_member_begin_end_mismatch) - << RangeType << BeginMemberLookup.empty(); - return StmtError(); + OverloadCandidateSet CandidateSet(RangeLoc); + Sema::BeginEndFunction BEFFailure; + ForRangeStatus RangeStatus = + BuildNonArrayForRange(*this, S, BeginRangeRef.get(), + EndRangeRef.get(), RangeType, + BeginVar, EndVar, ColonLoc, &CandidateSet, + &BeginExpr, &EndExpr, &BEFFailure); + + // 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 && + 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, "*"); + return SR; } - } else { - // - otherwise, begin-expr and end-expr are begin(__range) and - // end(__range), respectively, where begin and end are looked up with - // argument-dependent lookup (3.4.2). For the purposes of this name - // lookup, namespace std is an associated namespace. } - BeginExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, BeginVar, - BEF_begin, BeginNameInfo, - BeginMemberLookup, - BeginRangeRef.get()); - if (BeginExpr.isInvalid()) - return StmtError(); - - EndExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, EndVar, - BEF_end, EndNameInfo, - EndMemberLookup, EndRangeRef.get()); - if (EndExpr.isInvalid()) + // Otherwise, emit diagnostics if we haven't already. + if (RangeStatus == FRS_NoViableFunction) { + Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get(); + Diag(Range->getLocStart(), diag::err_for_range_invalid) + << RangeLoc << Range->getType() << BEFFailure; + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, + llvm::makeArrayRef(&Range, /*NumArgs=*/1)); + } + // Return an error if no fix was discovered. + if (RangeStatus != FRS_Success) return StmtError(); } - // C++0x [decl.spec.auto]p6: BeginType and EndType must be the same. + assert(!BeginExpr.isInvalid() && !EndExpr.isInvalid() && + "invalid range expression in for loop"); + + // C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same. QualType BeginType = BeginVar->getType(), EndType = EndVar->getType(); if (!Context.hasSameType(BeginType, EndType)) { Diag(RangeLoc, diag::err_for_range_begin_end_types_differ) diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 05a3c611e9..391c0b3f3b 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1338,7 +1338,7 @@ public: Stmt *LoopVar, SourceLocation RParenLoc) { return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd, - Cond, Inc, LoopVar, RParenLoc); + Cond, Inc, LoopVar, RParenLoc, false); } /// \brief Build a new C++0x range-based for statement. |