diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-06-19 11:42:00 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-06-19 11:42:00 +0000 |
| commit | 955bf016ee1b01884c15de92b631b709a1015707 (patch) | |
| tree | a8c50a90499edf23a9f1c5fe718b3ba4a840c4df /clang/lib | |
| parent | 562fd7534c1c82b105565e6f01429ebfdd0fa8eb (diff) | |
| download | bcm5719-llvm-955bf016ee1b01884c15de92b631b709a1015707.tar.gz bcm5719-llvm-955bf016ee1b01884c15de92b631b709a1015707.zip | |
[c++1z] Implement N3994: a range-based for loop can declare a variable with super-terse notation
for (x : range) { ... }
which is equivalent to
for (auto &&x : range) { ... }
llvm-svn: 211267
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 22 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseStmt.cpp | 42 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 31 |
3 files changed, 87 insertions, 8 deletions
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 5ec899f5898..33e3cab8671 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -3390,13 +3390,23 @@ void Parser::ParseCXX11Attributes(ParsedAttributesWithRange &attrs, } void Parser::DiagnoseAndSkipCXX11Attributes() { - if (!isCXX11AttributeSpecifier()) - return; - // Start and end location of an attribute or an attribute list. SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc = SkipCXX11Attributes(); + + if (EndLoc.isValid()) { + SourceRange Range(StartLoc, EndLoc); + Diag(StartLoc, diag::err_attributes_not_allowed) + << Range; + } +} + +SourceLocation Parser::SkipCXX11Attributes() { SourceLocation EndLoc; + if (!isCXX11AttributeSpecifier()) + return EndLoc; + do { if (Tok.is(tok::l_square)) { BalancedDelimiterTracker T(*this, tok::l_square); @@ -3413,11 +3423,7 @@ void Parser::DiagnoseAndSkipCXX11Attributes() { } } while (isCXX11AttributeSpecifier()); - if (EndLoc.isValid()) { - SourceRange Range(StartLoc, EndLoc); - Diag(StartLoc, diag::err_attributes_not_allowed) - << Range; - } + return EndLoc; } /// ParseMicrosoftAttributes - Parse a Microsoft attribute [Attr] diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 059c2b6a3f8..536e92c0cc6 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1388,6 +1388,25 @@ StmtResult Parser::ParseDoStatement() { Cond.get(), T.getCloseLocation()); } +bool Parser::isForRangeIdentifier() { + assert(Tok.is(tok::identifier)); + + const Token &Next = NextToken(); + if (Next.is(tok::colon)) + return true; + + if (Next.is(tok::l_square) || Next.is(tok::kw_alignas)) { + TentativeParsingAction PA(*this); + ConsumeToken(); + SkipCXX11Attributes(); + bool Result = Tok.is(tok::colon); + PA.Revert(); + return Result; + } + + return false; +} + /// ParseForStatement /// for-statement: [C99 6.8.5.3] /// 'for' '(' expr[opt] ';' expr[opt] ';' expr[opt] ')' statement @@ -1471,6 +1490,29 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { ProhibitAttributes(attrs); // no first part, eat the ';'. ConsumeToken(); + } else if (getLangOpts().CPlusPlus && Tok.is(tok::identifier) && + isForRangeIdentifier()) { + ProhibitAttributes(attrs); + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation Loc = ConsumeToken(); + MaybeParseCXX11Attributes(attrs); + + ForRangeInit.ColonLoc = ConsumeToken(); + if (Tok.is(tok::l_brace)) + ForRangeInit.RangeExpr = ParseBraceInitializer(); + else + ForRangeInit.RangeExpr = ParseExpression(); + + Diag(Loc, getLangOpts().CPlusPlus1z + ? diag::warn_cxx1y_compat_for_range_identifier + : diag::ext_for_range_identifier) + << ((getLangOpts().CPlusPlus11 && !getLangOpts().CPlusPlus1z) + ? FixItHint::CreateInsertion(Loc, "auto &&") + : FixItHint()); + + FirstPart = Actions.ActOnCXXForRangeIdentifier(getCurScope(), Loc, Name, + attrs, attrs.Range.getEnd()); + ForRange = true; } else if (isForInitDeclaration()) { // for (int X = 4; // Parse declaration, which eats the ';'. if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode? diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index e4b2096bec7..bdc8609116f 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -8941,6 +8941,37 @@ void Sema::ActOnCXXForRangeDecl(Decl *D) { } } +StmtResult +Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, + IdentifierInfo *Ident, + ParsedAttributes &Attrs, + SourceLocation AttrEnd) { + // C++1y [stmt.iter]p1: + // A range-based for statement of the form + // for ( for-range-identifier : for-range-initializer ) statement + // is equivalent to + // for ( auto&& for-range-identifier : for-range-initializer ) statement + DeclSpec DS(Attrs.getPool().getFactory()); + + const char *PrevSpec; + unsigned DiagID; + DS.SetTypeSpecType(DeclSpec::TST_auto, IdentLoc, PrevSpec, DiagID, + getPrintingPolicy()); + + Declarator D(DS, Declarator::ForContext); + D.SetIdentifier(Ident, IdentLoc); + D.takeAttributes(Attrs, AttrEnd); + + ParsedAttributes EmptyAttrs(Attrs.getPool().getFactory()); + D.AddTypeInfo(DeclaratorChunk::getReference(0, IdentLoc, /*lvalue*/false), + EmptyAttrs, IdentLoc); + Decl *Var = ActOnDeclarator(S, D); + cast<VarDecl>(Var)->setCXXForRangeDecl(true); + FinalizeDeclaration(Var); + return ActOnDeclStmt(FinalizeDeclaratorGroup(S, DS, Var), IdentLoc, + AttrEnd.isValid() ? AttrEnd : IdentLoc); +} + void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isInvalidDecl()) return; |

