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 | |
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')
-rw-r--r-- | clang/include/clang/Basic/DiagnosticParseKinds.td | 7 | ||||
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 7 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 4 | ||||
-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 | ||||
-rw-r--r-- | clang/test/SemaCXX/for-range-examples.cpp | 22 |
7 files changed, 125 insertions, 10 deletions
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index b2da81e17dc..874e0e2049b 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -277,6 +277,13 @@ def ext_for_range : ExtWarn< def warn_cxx98_compat_for_range : Warning< "range-based for loop is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def ext_for_range_identifier : ExtWarn< + "range-based for loop with implicit deduced type is a C++1z extension">, + InGroup<CXX1z>; +def warn_cxx1y_compat_for_range_identifier : Warning< + "range-based for loop with implicit deduced type is incompatible with " + "C++ standards before C++1z">, + InGroup<CXXPre1zCompat>, DefaultIgnore; def err_for_range_expected_decl : Error< "for range declaration must declare a variable">; def err_argument_required_after_attribute : Error< diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 019660e184d..2c76dce7619 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1827,6 +1827,9 @@ private: return isDeclarationSpecifier(true); } + /// \brief Determine whether this is a C++1z for-range-identifier. + bool isForRangeIdentifier(); + /// \brief Determine whether we are currently at the start of an Objective-C /// class message that appears to be missing the open bracket '['. bool isStartOfObjCClassMessageMissingOpenBracket(); @@ -2006,6 +2009,10 @@ private: // for example, attributes appertain to decl specifiers. void ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs); + /// \brief Skip C++11 attributes and return the end location of the last one. + /// \returns SourceLocation() if there are no attributes. + SourceLocation SkipCXX11Attributes(); + /// \brief Diagnose and skip C++11 attributes that appear in syntactic /// locations where attributes are not allowed. void DiagnoseAndSkipCXX11Attributes(); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 86ab905dbba..872dbffb80e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1622,6 +1622,10 @@ public: void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto); void ActOnInitializerError(Decl *Dcl); void ActOnCXXForRangeDecl(Decl *D); + StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, + IdentifierInfo *Ident, + ParsedAttributes &Attrs, + SourceLocation AttrEnd); void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc); void FinalizeDeclaration(Decl *D); 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; diff --git a/clang/test/SemaCXX/for-range-examples.cpp b/clang/test/SemaCXX/for-range-examples.cpp index b3cf9c32642..329be6362dd 100644 --- a/clang/test/SemaCXX/for-range-examples.cpp +++ b/clang/test/SemaCXX/for-range-examples.cpp @@ -176,8 +176,9 @@ namespace test4 { // Make sure these don't crash. Better diagnostics would be nice. for (: {1, 2, 3}) {} // expected-error {{expected expression}} expected-error {{expected ';'}} - for (x : {1, 2, 3}) {} // expected-error {{undeclared identifier}} expected-error {{expected ';'}} - for (y : {1, 2, 3}) {} // expected-error {{must declare a variable}} expected-warning {{result unused}} + for (1 : {1, 2, 3}) {} // expected-error {{must declare a variable}} expected-warning {{result unused}} + for (+x : {1, 2, 3}) {} // expected-error {{undeclared identifier}} expected-error {{expected ';'}} + for (+y : {1, 2, 3}) {} // expected-error {{must declare a variable}} expected-warning {{result unused}} } } @@ -209,3 +210,20 @@ namespace test6 { // expected-error@-1 {{cannot build range expression with array function parameter 'arr' since parameter with array type 'test6::vector []' is treated as pointer type 'test6::vector *'}} } } + +namespace test7 { + void f() { + int arr[5], b; + for (a : arr) {} // expected-warning {{extension}} + // FIXME: Give a -Wshadow for this by default? + for (b : arr) {} // expected-warning {{extension}} + for (arr : arr) {} // expected-warning {{extension}} + for (c alignas(8) : arr) { // expected-warning {{extension}} + static_assert(alignof(c) == 8, ""); // expected-warning {{extension}} + } + // FIXME: We should reject this, but don't, because we only check the + // attribute before we deduce the 'auto' type. + for (d alignas(1) : arr) {} // expected-warning {{extension}} + for (e [[deprecated]] : arr) { e = 0; } // expected-warning {{deprecated}} expected-note {{here}} expected-warning {{extension}} + } +} |