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. llvm-svn: 162248
This commit is contained in:
parent
74e6f9fc65
commit
0f38443616
|
@ -1415,7 +1415,15 @@ def err_for_range_member_begin_end_mismatch : Error<
|
|||
"range type %0 has '%select{begin|end}1' member but no '%select{end|begin}1' member">;
|
||||
def err_for_range_begin_end_types_differ : Error<
|
||||
"'begin' and 'end' must return the same type (got %0 and %1)">;
|
||||
def note_for_range_type : Note<"range has type %0">;
|
||||
def note_in_for_range: Note<
|
||||
"when looking up '%select{begin|end}0' function for range expression "
|
||||
"of type %1">;
|
||||
def err_for_range_invalid: Error<
|
||||
"invalid range expression of type %0; no viable '%select{begin|end}1' "
|
||||
"function available">;
|
||||
def err_for_range_dereference : Error<
|
||||
"invalid range expression of type %0; did you mean to dereference it "
|
||||
"with '*'?">;
|
||||
def note_for_range_begin_end : Note<
|
||||
"selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">;
|
||||
|
||||
|
|
|
@ -1924,6 +1924,30 @@ public:
|
|||
OverloadCandidateSet &CandidateSet,
|
||||
bool PartialOverloading = false);
|
||||
|
||||
// An enum used to represent the different possible results of building a
|
||||
// range-based for loop.
|
||||
enum ForRangeStatus {
|
||||
FRS_Success,
|
||||
FRS_NoViableFunction,
|
||||
FRS_DiagnosticIssued
|
||||
};
|
||||
|
||||
// An enum to represent whether something is dealing with a call to begin()
|
||||
// or a call to end() in a range-based for loop.
|
||||
enum BeginEndFunction {
|
||||
BEF_begin,
|
||||
BEF_end
|
||||
};
|
||||
|
||||
ForRangeStatus BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc,
|
||||
SourceLocation RangeLoc,
|
||||
VarDecl *Decl,
|
||||
BeginEndFunction BEF,
|
||||
const DeclarationNameInfo &NameInfo,
|
||||
LookupResult &MemberLookup,
|
||||
OverloadCandidateSet *CandidateSet,
|
||||
Expr *Range, ExprResult *CallExpr);
|
||||
|
||||
ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn,
|
||||
UnresolvedLookupExpr *ULE,
|
||||
SourceLocation LParenLoc,
|
||||
|
@ -1932,6 +1956,12 @@ public:
|
|||
Expr *ExecConfig,
|
||||
bool AllowTypoCorrection=true);
|
||||
|
||||
bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation RParenLoc,
|
||||
OverloadCandidateSet *CandidateSet,
|
||||
ExprResult *Result);
|
||||
|
||||
ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc,
|
||||
unsigned Opc,
|
||||
const UnresolvedSetImpl &Fns,
|
||||
|
@ -2512,13 +2542,15 @@ public:
|
|||
|
||||
StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc, Stmt *LoopVar,
|
||||
SourceLocation ColonLoc, Expr *Collection,
|
||||
SourceLocation RParenLoc);
|
||||
SourceLocation RParenLoc,
|
||||
bool ShouldTryDeref);
|
||||
StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc,
|
||||
SourceLocation ColonLoc,
|
||||
Stmt *RangeDecl, Stmt *BeginEndDecl,
|
||||
Expr *Cond, Expr *Inc,
|
||||
Stmt *LoopVarDecl,
|
||||
SourceLocation RParenLoc);
|
||||
SourceLocation RParenLoc,
|
||||
bool ShouldTryDeref);
|
||||
StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body);
|
||||
|
||||
StmtResult ActOnGotoStmt(SourceLocation GotoLoc,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
OverloadCandidateSet CandidateSet(RangeLoc);
|
||||
Sema::BeginEndFunction BEFFailure;
|
||||
ForRangeStatus RangeStatus =
|
||||
BuildNonArrayForRange(*this, S, BeginRangeRef.get(),
|
||||
EndRangeRef.get(), RangeType,
|
||||
BeginVar, EndVar, ColonLoc, &CandidateSet,
|
||||
&BeginExpr, &EndExpr, &BEFFailure);
|
||||
|
||||
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();
|
||||
// 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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
struct pr12960 {
|
||||
int begin;
|
||||
void foo(int x) {
|
||||
for (int& it : x) { // expected-error {{use of undeclared identifier 'begin'}} expected-note {{range has type 'int'}}
|
||||
for (int& it : x) { // expected-error {{invalid range expression of type 'int'; no viable 'begin' function available}}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -116,9 +116,9 @@ void g() {
|
|||
struct NoEndADL {
|
||||
null_t alt_begin();
|
||||
};
|
||||
for (auto u : NoBeginADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type 'NoBeginADL'}}
|
||||
for (auto u : NoBeginADL()) { // expected-error {{invalid range expression of type 'NoBeginADL'; no viable 'begin' function available}}
|
||||
}
|
||||
for (auto u : NoEndADL()) { // expected-error {{no matching function for call to 'end'}} expected-note {{range has type 'NoEndADL'}}
|
||||
for (auto u : NoEndADL()) { // expected-error {{invalid range expression of type 'NoEndADL'; no viable 'end' function available}}
|
||||
}
|
||||
|
||||
struct NoBegin {
|
||||
|
@ -156,8 +156,7 @@ void g() {
|
|||
for (int n : NoCopy()) { // ok
|
||||
}
|
||||
|
||||
for (int n : 42) { // expected-error {{no matching function for call to 'begin'}} \
|
||||
expected-note {{range has type 'int'}}
|
||||
for (int n : 42) { // expected-error {{invalid range expression of type 'int'; no viable 'begin' function available}}
|
||||
}
|
||||
|
||||
for (auto a : *also_incomplete) { // expected-error {{cannot use incomplete type 'struct Incomplete' as a range}}
|
||||
|
@ -179,9 +178,10 @@ template void h<A(&)[13], int>(A(&)[13]); // expected-note {{requested here}}
|
|||
|
||||
template<typename T>
|
||||
void i(T t) {
|
||||
for (auto u : t) { // expected-error {{no matching function for call to 'begin'}} \
|
||||
for (auto u : t) { // expected-error {{invalid range expression of type 'A *'; no viable 'begin' function available}} \
|
||||
expected-error {{member function 'begin' not viable}} \
|
||||
expected-note {{range has type}}
|
||||
expected-note {{when looking up 'begin' function}}
|
||||
|
||||
}
|
||||
}
|
||||
template void i<A[13]>(A*); // expected-note {{requested here}}
|
||||
|
@ -204,9 +204,10 @@ void end(VoidBeginADL);
|
|||
void j() {
|
||||
for (auto u : NS::ADL()) {
|
||||
}
|
||||
for (auto u : NS::NoADL()) { // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
|
||||
for (auto u : NS::NoADL()) { // expected-error {{invalid range expression of type 'NS::NoADL'; no viable 'begin' function available}}
|
||||
}
|
||||
for (auto a : VoidBeginADL()) { // expected-error {{cannot use type 'void' as an iterator}}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,4 +216,3 @@ void example() {
|
|||
for (int &x : array)
|
||||
x *= 2;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
|
||||
struct Data { };
|
||||
struct T {
|
||||
Data *begin();
|
||||
Data *end();
|
||||
};
|
||||
|
||||
struct NoBegin {
|
||||
Data *end();
|
||||
};
|
||||
|
||||
struct DeletedEnd : public T {
|
||||
Data *begin();
|
||||
Data *end() = delete; //expected-note {{function has been explicitly marked deleted here}}
|
||||
};
|
||||
|
||||
struct DeletedADLBegin { };
|
||||
|
||||
int* begin(DeletedADLBegin) = delete; //expected-note {{candidate function has been explicitly deleted}} \
|
||||
expected-note 6 {{candidate function not viable: no known conversion}}
|
||||
|
||||
struct PrivateEnd {
|
||||
Data *begin();
|
||||
|
||||
private:
|
||||
Data *end(); // expected-note 1 {{declared private here}}
|
||||
};
|
||||
|
||||
struct ADLNoEnd { };
|
||||
Data * begin(ADLNoEnd); // expected-note 7 {{candidate function not viable: no known conversion}}
|
||||
|
||||
struct OverloadedStar {
|
||||
T operator*();
|
||||
};
|
||||
|
||||
void f() {
|
||||
T t;
|
||||
for (auto i : t) { }
|
||||
T *pt;
|
||||
for (auto i : pt) { } // expected-error{{invalid range expression of type 'T *'; did you mean to dereference it with '*'?}}
|
||||
|
||||
int arr[10];
|
||||
for (auto i : arr) { }
|
||||
int (*parr)[10];
|
||||
for (auto i : parr) { }// expected-error{{invalid range expression of type 'int (*)[10]'; did you mean to dereference it with '*'?}}
|
||||
|
||||
NoBegin NB;
|
||||
for (auto i : NB) { }// expected-error{{range type 'NoBegin' has 'end' member but no 'begin' member}}
|
||||
NoBegin *pNB;
|
||||
for (auto i : pNB) { }// expected-error{{invalid range expression of type 'NoBegin *'; no viable 'begin' function available}}
|
||||
NoBegin **ppNB;
|
||||
for (auto i : ppNB) { }// expected-error{{invalid range expression of type 'NoBegin **'; no viable 'begin' function available}}
|
||||
NoBegin *****pppppNB;
|
||||
for (auto i : pppppNB) { }// expected-error{{invalid range expression of type 'NoBegin *****'; no viable 'begin' function available}}
|
||||
|
||||
ADLNoEnd ANE;
|
||||
for (auto i : ANE) { } // expected-error{{invalid range expression of type 'ADLNoEnd'; no viable 'end' function available}}
|
||||
ADLNoEnd *pANE;
|
||||
for (auto i : pANE) { } // expected-error{{invalid range expression of type 'ADLNoEnd *'; no viable 'begin' function available}}
|
||||
|
||||
DeletedEnd DE;
|
||||
for (auto i : DE) { } // expected-error{{attempt to use a deleted function}} \
|
||||
expected-note {{when looking up 'end' function for range expression of type 'DeletedEnd'}}
|
||||
DeletedEnd *pDE;
|
||||
|
||||
for (auto i : pDE) { } // expected-error {{invalid range expression of type 'DeletedEnd *'; no viable 'begin' function available}}
|
||||
|
||||
PrivateEnd PE;
|
||||
// FIXME: This diagnostic should be improved, as it does not specify that
|
||||
// the range is invalid.
|
||||
for (auto i : PE) { } // expected-error{{'end' is a private member of 'PrivateEnd'}}
|
||||
|
||||
// FIXME: This diagnostic should be improved as well. It should not mention a
|
||||
// deleted function, and we should not issue a FixIt suggesting a dereference.
|
||||
PrivateEnd *pPE;
|
||||
for (auto i : pPE) { }// expected-error {{invalid range expression of type 'PrivateEnd *'}}
|
||||
|
||||
DeletedADLBegin DAB;
|
||||
for (auto i : DAB) { } // expected-error {{call to deleted function 'begin'}}\
|
||||
expected-note {{when looking up 'begin' function for range expression of type 'DeletedADLBegin'}}
|
||||
|
||||
OverloadedStar OS;
|
||||
for (auto i : *OS) { }
|
||||
|
||||
for (auto i : OS) { } // expected-error {{invalid range expression of type 'OverloadedStar'; did you mean to dereference it with '*'?}}
|
||||
}
|
|
@ -31,10 +31,10 @@ NS::iter end(NS::NoADL);
|
|||
void f() {
|
||||
int a[] = {1, 2, 3};
|
||||
for (auto b : S()) {} // ok
|
||||
for (auto b : T()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
|
||||
for (auto b : T()) {} // expected-error {{invalid range expression of type 'T'}}
|
||||
for (auto b : a) {} // ok
|
||||
for (int b : NS::ADL()) {} // ok
|
||||
for (int b : NS::NoADL()) {} // expected-error {{no matching function for call to 'begin'}} expected-note {{range has type}}
|
||||
for (int b : NS::NoADL()) {} // expected-error {{invalid range expression of type 'NS::NoADL'}}
|
||||
}
|
||||
|
||||
void PR11601() {
|
||||
|
|
|
@ -155,7 +155,7 @@ void Test3() {
|
|||
struct R {};
|
||||
bool begun(R);
|
||||
void RangeTest() {
|
||||
for (auto b : R()) {} // expected-error {{use of undeclared identifier 'begin'}} expected-note {{range has type}}
|
||||
for (auto b : R()) {} // expected-error {{invalid range expression of type 'R'}}
|
||||
}
|
||||
|
||||
// PR 12019 - Avoid infinite mutual recursion in DiagnoseInvalidRedeclaration
|
||||
|
|
Loading…
Reference in New Issue