/// can be extracted using getLoopVariable and getRangeInit.
class CXXForRangeStmt : public Stmt {
SourceLocation ForLoc;
- enum { RANGE, BEGINEND, COND, INC, LOOPVAR, BODY, END };
+ enum { RANGE, BEGINSTMT, ENDSTMT, COND, INC, LOOPVAR, BODY, END };
// SubExprs[RANGE] is an expression or declstmt.
// SubExprs[COND] and SubExprs[INC] are expressions.
Stmt *SubExprs[END];
friend class ASTStmtReader;
public:
- CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEnd,
+ CXXForRangeStmt(DeclStmt *Range, DeclStmt *Begin, DeclStmt *End,
Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body,
SourceLocation FL, SourceLocation CAL, SourceLocation CL,
SourceLocation RPL);
DeclStmt *getRangeStmt() { return cast<DeclStmt>(SubExprs[RANGE]); }
- DeclStmt *getBeginEndStmt() {
- return cast_or_null<DeclStmt>(SubExprs[BEGINEND]);
+ DeclStmt *getBeginStmt() {
+ return cast_or_null<DeclStmt>(SubExprs[BEGINSTMT]);
}
+ DeclStmt *getEndStmt() { return cast_or_null<DeclStmt>(SubExprs[ENDSTMT]); }
Expr *getCond() { return cast_or_null<Expr>(SubExprs[COND]); }
Expr *getInc() { return cast_or_null<Expr>(SubExprs[INC]); }
DeclStmt *getLoopVarStmt() { return cast<DeclStmt>(SubExprs[LOOPVAR]); }
const DeclStmt *getRangeStmt() const {
return cast<DeclStmt>(SubExprs[RANGE]);
}
- const DeclStmt *getBeginEndStmt() const {
- return cast_or_null<DeclStmt>(SubExprs[BEGINEND]);
+ const DeclStmt *getBeginStmt() const {
+ return cast_or_null<DeclStmt>(SubExprs[BEGINSTMT]);
+ }
+ const DeclStmt *getEndStmt() const {
+ return cast_or_null<DeclStmt>(SubExprs[ENDSTMT]);
}
const Expr *getCond() const {
return cast_or_null<Expr>(SubExprs[COND]);
void setRangeInit(Expr *E) { SubExprs[RANGE] = reinterpret_cast<Stmt*>(E); }
void setRangeStmt(Stmt *S) { SubExprs[RANGE] = S; }
- void setBeginEndStmt(Stmt *S) { SubExprs[BEGINEND] = S; }
+ void setBeginStmt(Stmt *S) { SubExprs[BEGINSTMT] = S; }
+ void setEndStmt(Stmt *S) { SubExprs[ENDSTMT] = S; }
void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); }
void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; }
InGroup<ForLoopAnalysis>, DefaultIgnore;
def note_loop_iteration_here : Note<"%select{decremented|incremented}0 here">;
-def warn_for_range_const_reference_copy : Warning<
- "loop variable %0 "
- "%diff{has type $ but is initialized with type $"
- "| is initialized with a value of a different type}1,2 resulting in a copy">,
- InGroup<RangeLoopAnalysis>, DefaultIgnore;
-def note_use_type_or_non_reference : Note<
- "use non-reference type %0 to keep the copy or type %1 to prevent copying">;
-def warn_for_range_variable_always_copy : Warning<
- "loop variable %0 is always a copy because the range of type %1 does not "
- "return a reference">,
- InGroup<RangeLoopAnalysis>, DefaultIgnore;
-def note_use_non_reference_type : Note<"use non-reference type %0">;
-def warn_for_range_copy : Warning<
- "loop variable %0 of type %1 creates a copy from type %2">,
- InGroup<RangeLoopAnalysis>, DefaultIgnore;
-def note_use_reference_type : Note<"use reference type %0 to prevent copying">;
-
def warn_duplicate_enum_values : Warning<
"element %0 has been implicitly assigned %1 which another element has "
"been assigned">, InGroup<DiagGroup<"duplicate-enum">>, DefaultIgnore;
"cannot use type %0 as an iterator">;
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 ext_for_range_begin_end_types_differ : ExtWarn<
+ "'begin' and 'end' returning different types (%0 and %1) is a C++1z extension">,
+ InGroup<CXX1z>;
+def warn_for_range_begin_end_types_differ : Warning<
+ "'begin' and 'end' returning different types (%0 and %1) is incompatible "
+ "with C++ standards before C++1z">, InGroup<CXXPre1zCompat>, DefaultIgnore;
def note_in_for_range: Note<
"when looking up '%select{begin|end}0' function for range expression "
"of type %1">;
"in implicit call to 'operator%select{!=|*|++}0' for iterator of type %1">;
def note_for_range_begin_end : Note<
"selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">;
+def warn_for_range_const_reference_copy : Warning<
+ "loop variable %0 "
+ "%diff{has type $ but is initialized with type $"
+ "| is initialized with a value of a different type}1,2 resulting in a copy">,
+ InGroup<RangeLoopAnalysis>, DefaultIgnore;
+def note_use_type_or_non_reference : Note<
+ "use non-reference type %0 to keep the copy or type %1 to prevent copying">;
+def warn_for_range_variable_always_copy : Warning<
+ "loop variable %0 is always a copy because the range of type %1 does not "
+ "return a reference">,
+ InGroup<RangeLoopAnalysis>, DefaultIgnore;
+def note_use_non_reference_type : Note<"use non-reference type %0">;
+def warn_for_range_copy : Warning<
+ "loop variable %0 of type %1 creates a copy from type %2">,
+ InGroup<RangeLoopAnalysis>, DefaultIgnore;
+def note_use_reference_type : Note<"use reference type %0 to prevent copying">;
// C++11 constexpr
def warn_cxx98_compat_constexpr : Warning<
StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc,
SourceLocation CoawaitLoc,
SourceLocation ColonLoc,
- Stmt *RangeDecl, Stmt *BeginEndDecl,
+ Stmt *RangeDecl, Stmt *Begin, Stmt *End,
Expr *Cond, Expr *Inc,
Stmt *LoopVarDecl,
SourceLocation RParenLoc,
dyn_cast_or_null<DeclStmt>(Importer.Import(S->getRangeStmt()));
if (!ToRange && S->getRangeStmt())
return nullptr;
- DeclStmt *ToBeginEnd =
- dyn_cast_or_null<DeclStmt>(Importer.Import(S->getBeginEndStmt()));
- if (!ToBeginEnd && S->getBeginEndStmt())
+ DeclStmt *ToBegin =
+ dyn_cast_or_null<DeclStmt>(Importer.Import(S->getBeginStmt()));
+ if (!ToBegin && S->getBeginStmt())
+ return nullptr;
+ DeclStmt *ToEnd =
+ dyn_cast_or_null<DeclStmt>(Importer.Import(S->getEndStmt()));
+ if (!ToEnd && S->getEndStmt())
return nullptr;
Expr *ToCond = Importer.Import(S->getCond());
if (!ToCond && S->getCond())
SourceLocation ToCoawaitLoc = Importer.Import(S->getCoawaitLoc());
SourceLocation ToColonLoc = Importer.Import(S->getColonLoc());
SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc());
- return new (Importer.getToContext()) CXXForRangeStmt(ToRange, ToBeginEnd,
+ return new (Importer.getToContext()) CXXForRangeStmt(ToRange, ToBegin, ToEnd,
ToCond, ToInc,
ToLoopVar, ToBody,
ToForLoc, ToCoawaitLoc,
return ESR;
// Create the __begin and __end iterators.
- ESR = EvaluateStmt(Result, Info, FS->getBeginEndStmt());
+ ESR = EvaluateStmt(Result, Info, FS->getBeginStmt());
+ if (ESR != ESR_Succeeded)
+ return ESR;
+ ESR = EvaluateStmt(Result, Info, FS->getEndStmt());
if (ESR != ESR_Succeeded)
return ESR;
std::copy(handlers.begin(), handlers.end(), Stmts + 1);
}
-CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
+CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range,
+ DeclStmt *BeginStmt, DeclStmt *EndStmt,
Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
Stmt *Body, SourceLocation FL,
SourceLocation CAL, SourceLocation CL,
: Stmt(CXXForRangeStmtClass), ForLoc(FL), CoawaitLoc(CAL), ColonLoc(CL),
RParenLoc(RPL) {
SubExprs[RANGE] = Range;
- SubExprs[BEGINEND] = BeginEndStmt;
+ SubExprs[BEGINSTMT] = BeginStmt;
+ SubExprs[ENDSTMT] = EndStmt;
SubExprs[COND] = Cond;
SubExprs[INC] = Inc;
SubExprs[LOOPVAR] = LoopVar;
// Create local scopes and destructors for range, begin and end variables.
if (Stmt *Range = S->getRangeStmt())
addLocalScopeForStmt(Range);
- if (Stmt *BeginEnd = S->getBeginEndStmt())
- addLocalScopeForStmt(BeginEnd);
+ if (Stmt *Begin = S->getBeginStmt())
+ addLocalScopeForStmt(Begin);
+ if (Stmt *End = S->getEndStmt())
+ addLocalScopeForStmt(End);
addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S);
LocalScope::const_iterator ContinueScopePos = ScopePos;
// Add the initialization statements.
Block = createBlock();
- addStmt(S->getBeginEndStmt());
+ addStmt(S->getBeginStmt());
+ addStmt(S->getEndStmt());
return addStmt(S->getRangeStmt());
}
// Evaluate the first pieces before the loop.
EmitStmt(S.getRangeStmt());
- EmitStmt(S.getBeginEndStmt());
+ EmitStmt(S.getBeginStmt());
+ EmitStmt(S.getEndStmt());
// Start the loop with a block that tests the condition.
// If there's an increment, the continue scope will be overwritten
RecordStmtCount(S);
Visit(S->getLoopVarStmt());
Visit(S->getRangeStmt());
- Visit(S->getBeginEndStmt());
+ Visit(S->getBeginStmt());
+ Visit(S->getEndStmt());
uint64_t ParentCount = CurrentCount;
BreakContinueStack.push_back(BreakContinue());
}
return BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, RangeDecl.get(),
- /*BeginEndDecl=*/nullptr, /*Cond=*/nullptr,
- /*Inc=*/nullptr, DS, RParenLoc, Kind);
+ /*BeginStmt=*/nullptr, /*EndStmt=*/nullptr,
+ /*Cond=*/nullptr, /*Inc=*/nullptr,
+ DS, RParenLoc, Kind);
}
/// \brief Create the initialization, compare, and increment steps for
/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
StmtResult
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
- SourceLocation ColonLoc,
- Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond,
+ SourceLocation ColonLoc, Stmt *RangeDecl,
+ Stmt *Begin, Stmt *End, Expr *Cond,
Expr *Inc, Stmt *LoopVarDecl,
SourceLocation RParenLoc, BuildForRangeKind Kind) {
// FIXME: This should not be used during template instantiation. We should
InvalidateOnErrorScope Invalidate(*this, LoopVar,
LoopVar->getType()->isUndeducedType());
- StmtResult BeginEndDecl = BeginEnd;
+ StmtResult BeginDeclStmt = Begin;
+ StmtResult EndDeclStmt = End;
ExprResult NotEqExpr = Cond, IncrExpr = Inc;
if (RangeVarType->isDependentType()) {
// them in properly when we instantiate the loop.
if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check)
LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
- } else if (!BeginEndDecl.get()) {
+ } else if (!BeginDeclStmt.get()) {
SourceLocation RangeLoc = RangeVar->getLocation();
const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
"invalid range expression in for loop");
// C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same.
+ // C++1z removes this restriction.
QualType BeginType = BeginVar->getType(), EndType = EndVar->getType();
if (!Context.hasSameType(BeginType, EndType)) {
- Diag(RangeLoc, diag::err_for_range_begin_end_types_differ)
- << BeginType << EndType;
+ Diag(RangeLoc, getLangOpts().CPlusPlus1z
+ ? diag::warn_for_range_begin_end_types_differ
+ : diag::ext_for_range_begin_end_types_differ)
+ << BeginType << EndType;
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
}
- Decl *BeginEndDecls[] = { BeginVar, EndVar };
- // Claim the type doesn't contain auto: we've already done the checking.
- DeclGroupPtrTy BeginEndGroup =
- BuildDeclaratorGroup(MutableArrayRef<Decl *>(BeginEndDecls, 2),
- /*TypeMayContainAuto=*/ false);
- BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc);
+ BeginDeclStmt =
+ ActOnDeclStmt(ConvertDeclToDeclGroup(BeginVar), ColonLoc, ColonLoc);
+ EndDeclStmt =
+ ActOnDeclStmt(ConvertDeclToDeclGroup(EndVar), ColonLoc, ColonLoc);
const QualType BeginRefNonRefType = BeginType.getNonReferenceType();
ExprResult BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType,
return StmtResult();
return new (Context) CXXForRangeStmt(
- RangeDS, cast_or_null<DeclStmt>(BeginEndDecl.get()), NotEqExpr.get(),
+ RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()),
+ cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(),
IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc,
ColonLoc, RParenLoc);
}
StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc,
SourceLocation CoawaitLoc,
SourceLocation ColonLoc,
- Stmt *Range, Stmt *BeginEnd,
+ Stmt *Range, Stmt *Begin, Stmt *End,
Expr *Cond, Expr *Inc,
Stmt *LoopVar,
SourceLocation RParenLoc) {
}
return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc,
- Range, BeginEnd,
+ Range, Begin, End,
Cond, Inc, LoopVar, RParenLoc,
Sema::BFRK_Rebuild);
}
if (Range.isInvalid())
return StmtError();
- StmtResult BeginEnd = getDerived().TransformStmt(S->getBeginEndStmt());
- if (BeginEnd.isInvalid())
+ StmtResult Begin = getDerived().TransformStmt(S->getBeginStmt());
+ if (Begin.isInvalid())
+ return StmtError();
+ StmtResult End = getDerived().TransformStmt(S->getEndStmt());
+ if (End.isInvalid())
return StmtError();
ExprResult Cond = getDerived().TransformExpr(S->getCond());
StmtResult NewStmt = S;
if (getDerived().AlwaysRebuild() ||
Range.get() != S->getRangeStmt() ||
- BeginEnd.get() != S->getBeginEndStmt() ||
+ Begin.get() != S->getBeginStmt() ||
+ End.get() != S->getEndStmt() ||
Cond.get() != S->getCond() ||
Inc.get() != S->getInc() ||
LoopVar.get() != S->getLoopVarStmt()) {
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
S->getCoawaitLoc(),
S->getColonLoc(), Range.get(),
- BeginEnd.get(), Cond.get(),
+ Begin.get(), End.get(),
+ Cond.get(),
Inc.get(), LoopVar.get(),
S->getRParenLoc());
if (NewStmt.isInvalid())
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
S->getCoawaitLoc(),
S->getColonLoc(), Range.get(),
- BeginEnd.get(), Cond.get(),
+ Begin.get(), End.get(),
+ Cond.get(),
Inc.get(), LoopVar.get(),
S->getRParenLoc());
if (NewStmt.isInvalid())
S->ColonLoc = ReadSourceLocation(Record, Idx);
S->RParenLoc = ReadSourceLocation(Record, Idx);
S->setRangeStmt(Reader.ReadSubStmt());
- S->setBeginEndStmt(Reader.ReadSubStmt());
+ S->setBeginStmt(Reader.ReadSubStmt());
+ S->setEndStmt(Reader.ReadSubStmt());
S->setCond(Reader.ReadSubExpr());
S->setInc(Reader.ReadSubExpr());
S->setLoopVarStmt(Reader.ReadSubStmt());
Writer.AddSourceLocation(S->getColonLoc(), Record);
Writer.AddSourceLocation(S->getRParenLoc(), Record);
Writer.AddStmt(S->getRangeStmt());
- Writer.AddStmt(S->getBeginEndStmt());
+ Writer.AddStmt(S->getBeginStmt());
+ Writer.AddStmt(S->getEndStmt());
Writer.AddStmt(S->getCond());
Writer.AddStmt(S->getInc());
Writer.AddStmt(S->getLoopVarStmt());
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++14 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s
struct pr12960 {
int begin;
;
struct Differ {
- int *begin(); // expected-note {{selected 'begin' function with iterator type 'int *'}}
- null_t end(); // expected-note {{selected 'end' function with iterator type 'null_t'}}
+ int *begin();
+ null_t end();
};
- for (auto a : Differ()) // expected-error {{'begin' and 'end' must return the same type (got 'int *' and 'null_t')}}
+ for (auto a : Differ())
+#if __cplusplus <= 201402L
+ // expected-warning@-2 {{'begin' and 'end' returning different types ('int *' and 'null_t') is a C++1z extension}}
+ // expected-note@-6 {{selected 'begin' function with iterator type 'int *'}}
+ // expected-note@-6 {{selected 'end' function with iterator type 'null_t'}}
+#endif
;
for (void f() : "error") // expected-error {{for range declaration must declare a variable}}
for (extern int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'extern'}}
for (static int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'static'}}
- for (register int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'register'}} expected-warning {{deprecated}}
+ for (register int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'register'}} expected-warning 0-1{{register}} expected-error 0-1{{register}}
for (constexpr int a : X::C()) {} // OK per CWG issue #1204.
for (auto u : X::NoBeginADL()) { // expected-error {{invalid range expression of type 'X::NoBeginADL'; no viable 'begin' function available}}
<tr>
<td>Differing <tt>begin</tt> and <tt>end</tt> types in range-based <tt>for</tt></td>
<td><a href="http://wg21.link/p0184r0">P0184R0</a></td>
- <td class="none" align="center">No</td>
+ <td class="svn" align="center">SVN</td>
</tr>
<tr>
<td>Lambda capture of <tt>*this</tt></td>