r211267 - [c++1z] Implement N3994: a range-based for loop can declare a variable with super-terse notation
Richard Smith
richard-llvm at metafoo.co.uk
Thu Jun 19 04:42:00 PDT 2014
Author: rsmith
Date: Thu Jun 19 06:42:00 2014
New Revision: 211267
URL: http://llvm.org/viewvc/llvm-project?rev=211267&view=rev
Log:
[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) { ... }
Modified:
cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Parse/ParseStmt.cpp
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/SemaCXX/for-range-examples.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=211267&r1=211266&r2=211267&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Thu Jun 19 06:42:00 2014
@@ -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<
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=211267&r1=211266&r2=211267&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Thu Jun 19 06:42:00 2014
@@ -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();
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=211267&r1=211266&r2=211267&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Jun 19 06:42:00 2014
@@ -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);
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=211267&r1=211266&r2=211267&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu Jun 19 06:42:00 2014
@@ -3390,13 +3390,23 @@ void Parser::ParseCXX11Attributes(Parsed
}
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::DiagnoseAndSkipCXX11Attribu
}
} 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]
Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=211267&r1=211266&r2=211267&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Thu Jun 19 06:42:00 2014
@@ -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(Sou
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?
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=211267&r1=211266&r2=211267&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jun 19 06:42:00 2014
@@ -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;
Modified: cfe/trunk/test/SemaCXX/for-range-examples.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/for-range-examples.cpp?rev=211267&r1=211266&r2=211267&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/for-range-examples.cpp (original)
+++ cfe/trunk/test/SemaCXX/for-range-examples.cpp Thu Jun 19 06:42:00 2014
@@ -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 at -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}}
+ }
+}
More information about the cfe-commits
mailing list