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