forked from OSchip/llvm-project
P0184R0: Allow types of 'begin' and 'end' expressions in range-based for loops to differ.
llvm-svn: 263895
This commit is contained in:
parent
25a63b1bcc
commit
01694c340d
|
@ -127,7 +127,7 @@ public:
|
||||||
/// can be extracted using getLoopVariable and getRangeInit.
|
/// can be extracted using getLoopVariable and getRangeInit.
|
||||||
class CXXForRangeStmt : public Stmt {
|
class CXXForRangeStmt : public Stmt {
|
||||||
SourceLocation ForLoc;
|
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[RANGE] is an expression or declstmt.
|
||||||
// SubExprs[COND] and SubExprs[INC] are expressions.
|
// SubExprs[COND] and SubExprs[INC] are expressions.
|
||||||
Stmt *SubExprs[END];
|
Stmt *SubExprs[END];
|
||||||
|
@ -137,7 +137,7 @@ class CXXForRangeStmt : public Stmt {
|
||||||
|
|
||||||
friend class ASTStmtReader;
|
friend class ASTStmtReader;
|
||||||
public:
|
public:
|
||||||
CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEnd,
|
CXXForRangeStmt(DeclStmt *Range, DeclStmt *Begin, DeclStmt *End,
|
||||||
Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body,
|
Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body,
|
||||||
SourceLocation FL, SourceLocation CAL, SourceLocation CL,
|
SourceLocation FL, SourceLocation CAL, SourceLocation CL,
|
||||||
SourceLocation RPL);
|
SourceLocation RPL);
|
||||||
|
@ -152,9 +152,10 @@ public:
|
||||||
|
|
||||||
|
|
||||||
DeclStmt *getRangeStmt() { return cast<DeclStmt>(SubExprs[RANGE]); }
|
DeclStmt *getRangeStmt() { return cast<DeclStmt>(SubExprs[RANGE]); }
|
||||||
DeclStmt *getBeginEndStmt() {
|
DeclStmt *getBeginStmt() {
|
||||||
return cast_or_null<DeclStmt>(SubExprs[BEGINEND]);
|
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 *getCond() { return cast_or_null<Expr>(SubExprs[COND]); }
|
||||||
Expr *getInc() { return cast_or_null<Expr>(SubExprs[INC]); }
|
Expr *getInc() { return cast_or_null<Expr>(SubExprs[INC]); }
|
||||||
DeclStmt *getLoopVarStmt() { return cast<DeclStmt>(SubExprs[LOOPVAR]); }
|
DeclStmt *getLoopVarStmt() { return cast<DeclStmt>(SubExprs[LOOPVAR]); }
|
||||||
|
@ -163,8 +164,11 @@ public:
|
||||||
const DeclStmt *getRangeStmt() const {
|
const DeclStmt *getRangeStmt() const {
|
||||||
return cast<DeclStmt>(SubExprs[RANGE]);
|
return cast<DeclStmt>(SubExprs[RANGE]);
|
||||||
}
|
}
|
||||||
const DeclStmt *getBeginEndStmt() const {
|
const DeclStmt *getBeginStmt() const {
|
||||||
return cast_or_null<DeclStmt>(SubExprs[BEGINEND]);
|
return cast_or_null<DeclStmt>(SubExprs[BEGINSTMT]);
|
||||||
|
}
|
||||||
|
const DeclStmt *getEndStmt() const {
|
||||||
|
return cast_or_null<DeclStmt>(SubExprs[ENDSTMT]);
|
||||||
}
|
}
|
||||||
const Expr *getCond() const {
|
const Expr *getCond() const {
|
||||||
return cast_or_null<Expr>(SubExprs[COND]);
|
return cast_or_null<Expr>(SubExprs[COND]);
|
||||||
|
@ -179,7 +183,8 @@ public:
|
||||||
|
|
||||||
void setRangeInit(Expr *E) { SubExprs[RANGE] = reinterpret_cast<Stmt*>(E); }
|
void setRangeInit(Expr *E) { SubExprs[RANGE] = reinterpret_cast<Stmt*>(E); }
|
||||||
void setRangeStmt(Stmt *S) { SubExprs[RANGE] = S; }
|
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 setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); }
|
||||||
void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); }
|
void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); }
|
||||||
void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; }
|
void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; }
|
||||||
|
|
|
@ -30,23 +30,6 @@ def warn_redundant_loop_iteration : Warning<
|
||||||
InGroup<ForLoopAnalysis>, DefaultIgnore;
|
InGroup<ForLoopAnalysis>, DefaultIgnore;
|
||||||
def note_loop_iteration_here : Note<"%select{decremented|incremented}0 here">;
|
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<
|
def warn_duplicate_enum_values : Warning<
|
||||||
"element %0 has been implicitly assigned %1 which another element has "
|
"element %0 has been implicitly assigned %1 which another element has "
|
||||||
"been assigned">, InGroup<DiagGroup<"duplicate-enum">>, DefaultIgnore;
|
"been assigned">, InGroup<DiagGroup<"duplicate-enum">>, DefaultIgnore;
|
||||||
|
@ -1920,8 +1903,12 @@ def err_for_range_iter_deduction_failure : Error<
|
||||||
"cannot use type %0 as an iterator">;
|
"cannot use type %0 as an iterator">;
|
||||||
def err_for_range_member_begin_end_mismatch : Error<
|
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">;
|
"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<
|
def ext_for_range_begin_end_types_differ : ExtWarn<
|
||||||
"'begin' and 'end' must return the same type (got %0 and %1)">;
|
"'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<
|
def note_in_for_range: Note<
|
||||||
"when looking up '%select{begin|end}0' function for range expression "
|
"when looking up '%select{begin|end}0' function for range expression "
|
||||||
"of type %1">;
|
"of type %1">;
|
||||||
|
@ -1938,6 +1925,22 @@ def note_for_range_invalid_iterator : Note <
|
||||||
"in implicit call to 'operator%select{!=|*|++}0' for iterator of type %1">;
|
"in implicit call to 'operator%select{!=|*|++}0' for iterator of type %1">;
|
||||||
def note_for_range_begin_end : Note<
|
def note_for_range_begin_end : Note<
|
||||||
"selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">;
|
"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
|
// C++11 constexpr
|
||||||
def warn_cxx98_compat_constexpr : Warning<
|
def warn_cxx98_compat_constexpr : Warning<
|
||||||
|
|
|
@ -3376,7 +3376,7 @@ public:
|
||||||
StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc,
|
StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc,
|
||||||
SourceLocation CoawaitLoc,
|
SourceLocation CoawaitLoc,
|
||||||
SourceLocation ColonLoc,
|
SourceLocation ColonLoc,
|
||||||
Stmt *RangeDecl, Stmt *BeginEndDecl,
|
Stmt *RangeDecl, Stmt *Begin, Stmt *End,
|
||||||
Expr *Cond, Expr *Inc,
|
Expr *Cond, Expr *Inc,
|
||||||
Stmt *LoopVarDecl,
|
Stmt *LoopVarDecl,
|
||||||
SourceLocation RParenLoc,
|
SourceLocation RParenLoc,
|
||||||
|
|
|
@ -4940,9 +4940,13 @@ Stmt *ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||||
dyn_cast_or_null<DeclStmt>(Importer.Import(S->getRangeStmt()));
|
dyn_cast_or_null<DeclStmt>(Importer.Import(S->getRangeStmt()));
|
||||||
if (!ToRange && S->getRangeStmt())
|
if (!ToRange && S->getRangeStmt())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
DeclStmt *ToBeginEnd =
|
DeclStmt *ToBegin =
|
||||||
dyn_cast_or_null<DeclStmt>(Importer.Import(S->getBeginEndStmt()));
|
dyn_cast_or_null<DeclStmt>(Importer.Import(S->getBeginStmt()));
|
||||||
if (!ToBeginEnd && S->getBeginEndStmt())
|
if (!ToBegin && S->getBeginStmt())
|
||||||
|
return nullptr;
|
||||||
|
DeclStmt *ToEnd =
|
||||||
|
dyn_cast_or_null<DeclStmt>(Importer.Import(S->getEndStmt()));
|
||||||
|
if (!ToEnd && S->getEndStmt())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
Expr *ToCond = Importer.Import(S->getCond());
|
Expr *ToCond = Importer.Import(S->getCond());
|
||||||
if (!ToCond && S->getCond())
|
if (!ToCond && S->getCond())
|
||||||
|
@ -4961,7 +4965,7 @@ Stmt *ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||||
SourceLocation ToCoawaitLoc = Importer.Import(S->getCoawaitLoc());
|
SourceLocation ToCoawaitLoc = Importer.Import(S->getCoawaitLoc());
|
||||||
SourceLocation ToColonLoc = Importer.Import(S->getColonLoc());
|
SourceLocation ToColonLoc = Importer.Import(S->getColonLoc());
|
||||||
SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc());
|
SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc());
|
||||||
return new (Importer.getToContext()) CXXForRangeStmt(ToRange, ToBeginEnd,
|
return new (Importer.getToContext()) CXXForRangeStmt(ToRange, ToBegin, ToEnd,
|
||||||
ToCond, ToInc,
|
ToCond, ToInc,
|
||||||
ToLoopVar, ToBody,
|
ToLoopVar, ToBody,
|
||||||
ToForLoc, ToCoawaitLoc,
|
ToForLoc, ToCoawaitLoc,
|
||||||
|
|
|
@ -3647,7 +3647,10 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
|
||||||
return ESR;
|
return ESR;
|
||||||
|
|
||||||
// Create the __begin and __end iterators.
|
// 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)
|
if (ESR != ESR_Succeeded)
|
||||||
return ESR;
|
return ESR;
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,8 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
|
||||||
std::copy(handlers.begin(), handlers.end(), Stmts + 1);
|
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,
|
Expr *Cond, Expr *Inc, DeclStmt *LoopVar,
|
||||||
Stmt *Body, SourceLocation FL,
|
Stmt *Body, SourceLocation FL,
|
||||||
SourceLocation CAL, SourceLocation CL,
|
SourceLocation CAL, SourceLocation CL,
|
||||||
|
@ -57,7 +58,8 @@ CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
|
||||||
: Stmt(CXXForRangeStmtClass), ForLoc(FL), CoawaitLoc(CAL), ColonLoc(CL),
|
: Stmt(CXXForRangeStmtClass), ForLoc(FL), CoawaitLoc(CAL), ColonLoc(CL),
|
||||||
RParenLoc(RPL) {
|
RParenLoc(RPL) {
|
||||||
SubExprs[RANGE] = Range;
|
SubExprs[RANGE] = Range;
|
||||||
SubExprs[BEGINEND] = BeginEndStmt;
|
SubExprs[BEGINSTMT] = BeginStmt;
|
||||||
|
SubExprs[ENDSTMT] = EndStmt;
|
||||||
SubExprs[COND] = Cond;
|
SubExprs[COND] = Cond;
|
||||||
SubExprs[INC] = Inc;
|
SubExprs[INC] = Inc;
|
||||||
SubExprs[LOOPVAR] = LoopVar;
|
SubExprs[LOOPVAR] = LoopVar;
|
||||||
|
|
|
@ -3397,8 +3397,10 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||||
// Create local scopes and destructors for range, begin and end variables.
|
// Create local scopes and destructors for range, begin and end variables.
|
||||||
if (Stmt *Range = S->getRangeStmt())
|
if (Stmt *Range = S->getRangeStmt())
|
||||||
addLocalScopeForStmt(Range);
|
addLocalScopeForStmt(Range);
|
||||||
if (Stmt *BeginEnd = S->getBeginEndStmt())
|
if (Stmt *Begin = S->getBeginStmt())
|
||||||
addLocalScopeForStmt(BeginEnd);
|
addLocalScopeForStmt(Begin);
|
||||||
|
if (Stmt *End = S->getEndStmt())
|
||||||
|
addLocalScopeForStmt(End);
|
||||||
addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S);
|
addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S);
|
||||||
|
|
||||||
LocalScope::const_iterator ContinueScopePos = ScopePos;
|
LocalScope::const_iterator ContinueScopePos = ScopePos;
|
||||||
|
@ -3489,7 +3491,8 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||||
|
|
||||||
// Add the initialization statements.
|
// Add the initialization statements.
|
||||||
Block = createBlock();
|
Block = createBlock();
|
||||||
addStmt(S->getBeginEndStmt());
|
addStmt(S->getBeginStmt());
|
||||||
|
addStmt(S->getEndStmt());
|
||||||
return addStmt(S->getRangeStmt());
|
return addStmt(S->getRangeStmt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -870,7 +870,8 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S,
|
||||||
|
|
||||||
// Evaluate the first pieces before the loop.
|
// Evaluate the first pieces before the loop.
|
||||||
EmitStmt(S.getRangeStmt());
|
EmitStmt(S.getRangeStmt());
|
||||||
EmitStmt(S.getBeginEndStmt());
|
EmitStmt(S.getBeginStmt());
|
||||||
|
EmitStmt(S.getEndStmt());
|
||||||
|
|
||||||
// Start the loop with a block that tests the condition.
|
// Start the loop with a block that tests the condition.
|
||||||
// If there's an increment, the continue scope will be overwritten
|
// If there's an increment, the continue scope will be overwritten
|
||||||
|
|
|
@ -409,7 +409,8 @@ struct ComputeRegionCounts : public ConstStmtVisitor<ComputeRegionCounts> {
|
||||||
RecordStmtCount(S);
|
RecordStmtCount(S);
|
||||||
Visit(S->getLoopVarStmt());
|
Visit(S->getLoopVarStmt());
|
||||||
Visit(S->getRangeStmt());
|
Visit(S->getRangeStmt());
|
||||||
Visit(S->getBeginEndStmt());
|
Visit(S->getBeginStmt());
|
||||||
|
Visit(S->getEndStmt());
|
||||||
|
|
||||||
uint64_t ParentCount = CurrentCount;
|
uint64_t ParentCount = CurrentCount;
|
||||||
BreakContinueStack.push_back(BreakContinue());
|
BreakContinueStack.push_back(BreakContinue());
|
||||||
|
|
|
@ -2033,8 +2033,9 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
|
||||||
}
|
}
|
||||||
|
|
||||||
return BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, RangeDecl.get(),
|
return BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, RangeDecl.get(),
|
||||||
/*BeginEndDecl=*/nullptr, /*Cond=*/nullptr,
|
/*BeginStmt=*/nullptr, /*EndStmt=*/nullptr,
|
||||||
/*Inc=*/nullptr, DS, RParenLoc, Kind);
|
/*Cond=*/nullptr, /*Inc=*/nullptr,
|
||||||
|
DS, RParenLoc, Kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Create the initialization, compare, and increment steps for
|
/// \brief Create the initialization, compare, and increment steps for
|
||||||
|
@ -2184,8 +2185,8 @@ struct InvalidateOnErrorScope {
|
||||||
/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
|
/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
|
||||||
StmtResult
|
StmtResult
|
||||||
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
||||||
SourceLocation ColonLoc,
|
SourceLocation ColonLoc, Stmt *RangeDecl,
|
||||||
Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond,
|
Stmt *Begin, Stmt *End, Expr *Cond,
|
||||||
Expr *Inc, Stmt *LoopVarDecl,
|
Expr *Inc, Stmt *LoopVarDecl,
|
||||||
SourceLocation RParenLoc, BuildForRangeKind Kind) {
|
SourceLocation RParenLoc, BuildForRangeKind Kind) {
|
||||||
// FIXME: This should not be used during template instantiation. We should
|
// FIXME: This should not be used during template instantiation. We should
|
||||||
|
@ -2211,7 +2212,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
||||||
InvalidateOnErrorScope Invalidate(*this, LoopVar,
|
InvalidateOnErrorScope Invalidate(*this, LoopVar,
|
||||||
LoopVar->getType()->isUndeducedType());
|
LoopVar->getType()->isUndeducedType());
|
||||||
|
|
||||||
StmtResult BeginEndDecl = BeginEnd;
|
StmtResult BeginDeclStmt = Begin;
|
||||||
|
StmtResult EndDeclStmt = End;
|
||||||
ExprResult NotEqExpr = Cond, IncrExpr = Inc;
|
ExprResult NotEqExpr = Cond, IncrExpr = Inc;
|
||||||
|
|
||||||
if (RangeVarType->isDependentType()) {
|
if (RangeVarType->isDependentType()) {
|
||||||
|
@ -2222,7 +2224,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
||||||
// them in properly when we instantiate the loop.
|
// them in properly when we instantiate the loop.
|
||||||
if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check)
|
if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check)
|
||||||
LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
|
LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
|
||||||
} else if (!BeginEndDecl.get()) {
|
} else if (!BeginDeclStmt.get()) {
|
||||||
SourceLocation RangeLoc = RangeVar->getLocation();
|
SourceLocation RangeLoc = RangeVar->getLocation();
|
||||||
|
|
||||||
const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
|
const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
|
||||||
|
@ -2347,20 +2349,21 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
||||||
"invalid range expression in for loop");
|
"invalid range expression in for loop");
|
||||||
|
|
||||||
// C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same.
|
// 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();
|
QualType BeginType = BeginVar->getType(), EndType = EndVar->getType();
|
||||||
if (!Context.hasSameType(BeginType, EndType)) {
|
if (!Context.hasSameType(BeginType, EndType)) {
|
||||||
Diag(RangeLoc, diag::err_for_range_begin_end_types_differ)
|
Diag(RangeLoc, getLangOpts().CPlusPlus1z
|
||||||
<< BeginType << EndType;
|
? 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, BeginExpr.get(), BEF_begin);
|
||||||
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
|
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
Decl *BeginEndDecls[] = { BeginVar, EndVar };
|
BeginDeclStmt =
|
||||||
// Claim the type doesn't contain auto: we've already done the checking.
|
ActOnDeclStmt(ConvertDeclToDeclGroup(BeginVar), ColonLoc, ColonLoc);
|
||||||
DeclGroupPtrTy BeginEndGroup =
|
EndDeclStmt =
|
||||||
BuildDeclaratorGroup(MutableArrayRef<Decl *>(BeginEndDecls, 2),
|
ActOnDeclStmt(ConvertDeclToDeclGroup(EndVar), ColonLoc, ColonLoc);
|
||||||
/*TypeMayContainAuto=*/ false);
|
|
||||||
BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc);
|
|
||||||
|
|
||||||
const QualType BeginRefNonRefType = BeginType.getNonReferenceType();
|
const QualType BeginRefNonRefType = BeginType.getNonReferenceType();
|
||||||
ExprResult BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType,
|
ExprResult BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType,
|
||||||
|
@ -2435,7 +2438,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
|
||||||
return StmtResult();
|
return StmtResult();
|
||||||
|
|
||||||
return new (Context) CXXForRangeStmt(
|
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,
|
IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc,
|
||||||
ColonLoc, RParenLoc);
|
ColonLoc, RParenLoc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1840,7 +1840,7 @@ public:
|
||||||
StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc,
|
StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc,
|
||||||
SourceLocation CoawaitLoc,
|
SourceLocation CoawaitLoc,
|
||||||
SourceLocation ColonLoc,
|
SourceLocation ColonLoc,
|
||||||
Stmt *Range, Stmt *BeginEnd,
|
Stmt *Range, Stmt *Begin, Stmt *End,
|
||||||
Expr *Cond, Expr *Inc,
|
Expr *Cond, Expr *Inc,
|
||||||
Stmt *LoopVar,
|
Stmt *LoopVar,
|
||||||
SourceLocation RParenLoc) {
|
SourceLocation RParenLoc) {
|
||||||
|
@ -1862,7 +1862,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc,
|
return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc,
|
||||||
Range, BeginEnd,
|
Range, Begin, End,
|
||||||
Cond, Inc, LoopVar, RParenLoc,
|
Cond, Inc, LoopVar, RParenLoc,
|
||||||
Sema::BFRK_Rebuild);
|
Sema::BFRK_Rebuild);
|
||||||
}
|
}
|
||||||
|
@ -6889,8 +6889,11 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||||
if (Range.isInvalid())
|
if (Range.isInvalid())
|
||||||
return StmtError();
|
return StmtError();
|
||||||
|
|
||||||
StmtResult BeginEnd = getDerived().TransformStmt(S->getBeginEndStmt());
|
StmtResult Begin = getDerived().TransformStmt(S->getBeginStmt());
|
||||||
if (BeginEnd.isInvalid())
|
if (Begin.isInvalid())
|
||||||
|
return StmtError();
|
||||||
|
StmtResult End = getDerived().TransformStmt(S->getEndStmt());
|
||||||
|
if (End.isInvalid())
|
||||||
return StmtError();
|
return StmtError();
|
||||||
|
|
||||||
ExprResult Cond = getDerived().TransformExpr(S->getCond());
|
ExprResult Cond = getDerived().TransformExpr(S->getCond());
|
||||||
|
@ -6916,14 +6919,16 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||||
StmtResult NewStmt = S;
|
StmtResult NewStmt = S;
|
||||||
if (getDerived().AlwaysRebuild() ||
|
if (getDerived().AlwaysRebuild() ||
|
||||||
Range.get() != S->getRangeStmt() ||
|
Range.get() != S->getRangeStmt() ||
|
||||||
BeginEnd.get() != S->getBeginEndStmt() ||
|
Begin.get() != S->getBeginStmt() ||
|
||||||
|
End.get() != S->getEndStmt() ||
|
||||||
Cond.get() != S->getCond() ||
|
Cond.get() != S->getCond() ||
|
||||||
Inc.get() != S->getInc() ||
|
Inc.get() != S->getInc() ||
|
||||||
LoopVar.get() != S->getLoopVarStmt()) {
|
LoopVar.get() != S->getLoopVarStmt()) {
|
||||||
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
|
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
|
||||||
S->getCoawaitLoc(),
|
S->getCoawaitLoc(),
|
||||||
S->getColonLoc(), Range.get(),
|
S->getColonLoc(), Range.get(),
|
||||||
BeginEnd.get(), Cond.get(),
|
Begin.get(), End.get(),
|
||||||
|
Cond.get(),
|
||||||
Inc.get(), LoopVar.get(),
|
Inc.get(), LoopVar.get(),
|
||||||
S->getRParenLoc());
|
S->getRParenLoc());
|
||||||
if (NewStmt.isInvalid())
|
if (NewStmt.isInvalid())
|
||||||
|
@ -6940,7 +6945,8 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||||
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
|
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
|
||||||
S->getCoawaitLoc(),
|
S->getCoawaitLoc(),
|
||||||
S->getColonLoc(), Range.get(),
|
S->getColonLoc(), Range.get(),
|
||||||
BeginEnd.get(), Cond.get(),
|
Begin.get(), End.get(),
|
||||||
|
Cond.get(),
|
||||||
Inc.get(), LoopVar.get(),
|
Inc.get(), LoopVar.get(),
|
||||||
S->getRParenLoc());
|
S->getRParenLoc());
|
||||||
if (NewStmt.isInvalid())
|
if (NewStmt.isInvalid())
|
||||||
|
|
|
@ -1207,7 +1207,8 @@ void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||||
S->ColonLoc = ReadSourceLocation(Record, Idx);
|
S->ColonLoc = ReadSourceLocation(Record, Idx);
|
||||||
S->RParenLoc = ReadSourceLocation(Record, Idx);
|
S->RParenLoc = ReadSourceLocation(Record, Idx);
|
||||||
S->setRangeStmt(Reader.ReadSubStmt());
|
S->setRangeStmt(Reader.ReadSubStmt());
|
||||||
S->setBeginEndStmt(Reader.ReadSubStmt());
|
S->setBeginStmt(Reader.ReadSubStmt());
|
||||||
|
S->setEndStmt(Reader.ReadSubStmt());
|
||||||
S->setCond(Reader.ReadSubExpr());
|
S->setCond(Reader.ReadSubExpr());
|
||||||
S->setInc(Reader.ReadSubExpr());
|
S->setInc(Reader.ReadSubExpr());
|
||||||
S->setLoopVarStmt(Reader.ReadSubStmt());
|
S->setLoopVarStmt(Reader.ReadSubStmt());
|
||||||
|
|
|
@ -1161,7 +1161,8 @@ void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) {
|
||||||
Writer.AddSourceLocation(S->getColonLoc(), Record);
|
Writer.AddSourceLocation(S->getColonLoc(), Record);
|
||||||
Writer.AddSourceLocation(S->getRParenLoc(), Record);
|
Writer.AddSourceLocation(S->getRParenLoc(), Record);
|
||||||
Writer.AddStmt(S->getRangeStmt());
|
Writer.AddStmt(S->getRangeStmt());
|
||||||
Writer.AddStmt(S->getBeginEndStmt());
|
Writer.AddStmt(S->getBeginStmt());
|
||||||
|
Writer.AddStmt(S->getEndStmt());
|
||||||
Writer.AddStmt(S->getCond());
|
Writer.AddStmt(S->getCond());
|
||||||
Writer.AddStmt(S->getInc());
|
Writer.AddStmt(S->getInc());
|
||||||
Writer.AddStmt(S->getLoopVarStmt());
|
Writer.AddStmt(S->getLoopVarStmt());
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
|
// 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 {
|
struct pr12960 {
|
||||||
int begin;
|
int begin;
|
||||||
|
@ -118,10 +120,15 @@ void g() {
|
||||||
;
|
;
|
||||||
|
|
||||||
struct Differ {
|
struct Differ {
|
||||||
int *begin(); // expected-note {{selected 'begin' function with iterator type 'int *'}}
|
int *begin();
|
||||||
null_t end(); // expected-note {{selected 'end' function with iterator type 'null_t'}}
|
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 (void f() : "error") // expected-error {{for range declaration must declare a variable}}
|
||||||
|
@ -129,7 +136,7 @@ void g() {
|
||||||
|
|
||||||
for (extern int a : A()) {} // expected-error {{loop variable 'a' may not be declared 'extern'}}
|
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 (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 (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}}
|
for (auto u : X::NoBeginADL()) { // expected-error {{invalid range expression of type 'X::NoBeginADL'; no viable 'begin' function available}}
|
||||||
|
|
|
@ -654,7 +654,7 @@ as the draft C++1z standard evolves.</p>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Differing <tt>begin</tt> and <tt>end</tt> types in range-based <tt>for</tt></td>
|
<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><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>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Lambda capture of <tt>*this</tt></td>
|
<td>Lambda capture of <tt>*this</tt></td>
|
||||||
|
|
Loading…
Reference in New Issue