From: Richard Smith Date: Sun, 20 Mar 2016 10:33:40 +0000 (+0000) Subject: P0184R0: Allow types of 'begin' and 'end' expressions in range-based for loops to... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6fa284fdc5fee59aa1739d500e279897263ad9ca;p=clang P0184R0: Allow types of 'begin' and 'end' expressions in range-based for loops to differ. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@263895 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/StmtCXX.h b/include/clang/AST/StmtCXX.h index 1ca73e207e..1d29c228a4 100644 --- a/include/clang/AST/StmtCXX.h +++ b/include/clang/AST/StmtCXX.h @@ -127,7 +127,7 @@ public: /// 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]; @@ -137,7 +137,7 @@ class CXXForRangeStmt : public Stmt { 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); @@ -152,9 +152,10 @@ public: DeclStmt *getRangeStmt() { return cast(SubExprs[RANGE]); } - DeclStmt *getBeginEndStmt() { - return cast_or_null(SubExprs[BEGINEND]); + DeclStmt *getBeginStmt() { + return cast_or_null(SubExprs[BEGINSTMT]); } + DeclStmt *getEndStmt() { return cast_or_null(SubExprs[ENDSTMT]); } Expr *getCond() { return cast_or_null(SubExprs[COND]); } Expr *getInc() { return cast_or_null(SubExprs[INC]); } DeclStmt *getLoopVarStmt() { return cast(SubExprs[LOOPVAR]); } @@ -163,8 +164,11 @@ public: const DeclStmt *getRangeStmt() const { return cast(SubExprs[RANGE]); } - const DeclStmt *getBeginEndStmt() const { - return cast_or_null(SubExprs[BEGINEND]); + const DeclStmt *getBeginStmt() const { + return cast_or_null(SubExprs[BEGINSTMT]); + } + const DeclStmt *getEndStmt() const { + return cast_or_null(SubExprs[ENDSTMT]); } const Expr *getCond() const { return cast_or_null(SubExprs[COND]); @@ -179,7 +183,8 @@ public: void setRangeInit(Expr *E) { SubExprs[RANGE] = reinterpret_cast(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(E); } void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast(E); } void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 8aeb290135..e8038b63b6 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -30,23 +30,6 @@ def warn_redundant_loop_iteration : Warning< InGroup, 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, 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, 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, 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>, DefaultIgnore; @@ -1920,8 +1903,12 @@ def err_for_range_iter_deduction_failure : Error< "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; +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, DefaultIgnore; def note_in_for_range: Note< "when looking up '%select{begin|end}0' function for range expression " "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">; 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, 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, 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, DefaultIgnore; +def note_use_reference_type : Note<"use reference type %0 to prevent copying">; // C++11 constexpr def warn_cxx98_compat_constexpr : Warning< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index d16293d78e..a0d2b6f73f 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3376,7 +3376,7 @@ public: 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, diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index c3d39b9b75..7d241bbbfb 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -4940,9 +4940,13 @@ Stmt *ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { dyn_cast_or_null(Importer.Import(S->getRangeStmt())); if (!ToRange && S->getRangeStmt()) return nullptr; - DeclStmt *ToBeginEnd = - dyn_cast_or_null(Importer.Import(S->getBeginEndStmt())); - if (!ToBeginEnd && S->getBeginEndStmt()) + DeclStmt *ToBegin = + dyn_cast_or_null(Importer.Import(S->getBeginStmt())); + if (!ToBegin && S->getBeginStmt()) + return nullptr; + DeclStmt *ToEnd = + dyn_cast_or_null(Importer.Import(S->getEndStmt())); + if (!ToEnd && S->getEndStmt()) return nullptr; Expr *ToCond = Importer.Import(S->getCond()); if (!ToCond && S->getCond()) @@ -4961,7 +4965,7 @@ Stmt *ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { 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, diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 4d5a772fc8..262c97a74b 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -3647,7 +3647,10 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, 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; diff --git a/lib/AST/StmtCXX.cpp b/lib/AST/StmtCXX.cpp index e39a01daf9..4692db84b5 100644 --- a/lib/AST/StmtCXX.cpp +++ b/lib/AST/StmtCXX.cpp @@ -49,7 +49,8 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, 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, @@ -57,7 +58,8 @@ CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt, : 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; diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index dc58b92090..855017c7c1 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -3397,8 +3397,10 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) { // 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; @@ -3489,7 +3491,8 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) { // Add the initialization statements. Block = createBlock(); - addStmt(S->getBeginEndStmt()); + addStmt(S->getBeginStmt()); + addStmt(S->getEndStmt()); return addStmt(S->getRangeStmt()); } diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 5b5afba04d..741c13a934 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -870,7 +870,8 @@ CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S, // 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 diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp index 2d46adfce1..5b8e342713 100644 --- a/lib/CodeGen/CodeGenPGO.cpp +++ b/lib/CodeGen/CodeGenPGO.cpp @@ -409,7 +409,8 @@ struct ComputeRegionCounts : public ConstStmtVisitor { 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()); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 1975fcb110..3f63854ec0 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -2033,8 +2033,9 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, } 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 @@ -2184,8 +2185,8 @@ struct InvalidateOnErrorScope { /// 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 @@ -2211,7 +2212,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, InvalidateOnErrorScope Invalidate(*this, LoopVar, LoopVar->getType()->isUndeducedType()); - StmtResult BeginEndDecl = BeginEnd; + StmtResult BeginDeclStmt = Begin; + StmtResult EndDeclStmt = End; ExprResult NotEqExpr = Cond, IncrExpr = Inc; if (RangeVarType->isDependentType()) { @@ -2222,7 +2224,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, // 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(); @@ -2347,20 +2349,21 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, "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(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, @@ -2435,7 +2438,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, return StmtResult(); return new (Context) CXXForRangeStmt( - RangeDS, cast_or_null(BeginEndDecl.get()), NotEqExpr.get(), + RangeDS, cast_or_null(BeginDeclStmt.get()), + cast_or_null(EndDeclStmt.get()), NotEqExpr.get(), IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc, ColonLoc, RParenLoc); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 6f09c0f535..fc20129214 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1840,7 +1840,7 @@ public: 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) { @@ -1862,7 +1862,7 @@ public: } return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, - Range, BeginEnd, + Range, Begin, End, Cond, Inc, LoopVar, RParenLoc, Sema::BFRK_Rebuild); } @@ -6889,8 +6889,11 @@ TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) { 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()); @@ -6916,14 +6919,16 @@ TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) { 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()) @@ -6940,7 +6945,8 @@ TreeTransform::TransformCXXForRangeStmt(CXXForRangeStmt *S) { 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()) diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index ab44c96545..c2256ebbc0 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -1207,7 +1207,8 @@ void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) { 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()); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index ea3b80458a..38cd89254f 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -1161,7 +1161,8 @@ void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { 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()); diff --git a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp index 7d689ae0b1..8c4f36c0ff 100644 --- a/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp +++ b/test/CXX/stmt.stmt/stmt.iter/stmt.ranged/p1.cpp @@ -1,4 +1,6 @@ // 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; @@ -118,10 +120,15 @@ void g() { ; 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}} @@ -129,7 +136,7 @@ void g() { 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}} diff --git a/www/cxx_status.html b/www/cxx_status.html index fc354b2b89..04ca78bcff 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -654,7 +654,7 @@ as the draft C++1z standard evolves.

Differing begin and end types in range-based for P0184R0 - No + SVN Lambda capture of *this