Support C++11 attributes at the start of a parameter-declaration.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154476 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index d2ec7aa..0851941 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -4038,7 +4038,8 @@
   } else if (Tok.is(tok::r_paren) ||           // 'int()' is a function.
              (getLangOpts().CPlusPlus && Tok.is(tok::ellipsis) &&
               NextToken().is(tok::r_paren)) || // C++ int(...)
-             isDeclarationSpecifier()) {       // 'int(int)' is a function.
+             isDeclarationSpecifier() ||       // 'int(int)' is a function.
+             isCXX11AttributeSpecifier()) {    // 'int([[]]int)' is a function.
     // This handles C99 6.7.5.3p11: in "typedef int X; void foo(X)", X is
     // considered to be a type, not a K&R identifier-list.
     isGrouping = false;
@@ -4318,9 +4319,9 @@
 /// after the opening parenthesis. This function will not parse a K&R-style
 /// identifier list.
 ///
-/// D is the declarator being parsed.  If attrs is non-null, then the caller
-/// parsed those arguments immediately after the open paren - they should be
-/// considered to be the first argument of a parameter.
+/// D is the declarator being parsed.  If FirstArgAttrs is non-null, then the
+/// caller parsed those arguments immediately after the open paren - they should
+/// be considered to be part of the first parameter.
 ///
 /// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will
 /// be the location of the ellipsis, if any was parsed.
@@ -4343,15 +4344,18 @@
 /// [C++]   declaration-specifiers abstract-declarator[opt]
 ///           '=' assignment-expression
 /// [GNU]   declaration-specifiers abstract-declarator[opt] attributes
+/// [C++11] attribute-specifier-seq parameter-declaration
 ///
 void Parser::ParseParameterDeclarationClause(
        Declarator &D,
-       ParsedAttributes &attrs,
+       ParsedAttributes &FirstArgAttrs,
        SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo,
        SourceLocation &EllipsisLoc) {
 
   while (1) {
     if (Tok.is(tok::ellipsis)) {
+      // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq
+      // before deciding this was a parameter-declaration-clause.
       EllipsisLoc = ConsumeToken();     // Consume the ellipsis.
       break;
     }
@@ -4360,6 +4364,9 @@
     // Just use the ParsingDeclaration "scope" of the declarator.
     DeclSpec DS(AttrFactory);
 
+    // Parse any C++11 attributes.
+    MaybeParseCXX0XAttributes(DS.getAttributes());
+
     // Skip any Microsoft attributes before a param.
     if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square))
       ParseMicrosoftAttributes(DS.getAttributes());
@@ -4368,12 +4375,10 @@
 
     // If the caller parsed attributes for the first argument, add them now.
     // Take them so that we only apply the attributes to the first parameter.
-    // FIXME: If we saw an ellipsis first, this code is not reached. Are the
-    // attributes lost? Should they even be allowed?
     // FIXME: If we can leave the attributes in the token stream somehow, we can
-    // get rid of a parameter (attrs) and this statement. It might be too much
-    // hassle.
-    DS.takeAttributesFrom(attrs);
+    // get rid of a parameter (FirstArgAttrs) and this statement. It might be
+    // too much hassle.
+    DS.takeAttributesFrom(FirstArgAttrs);
 
     ParseDeclarationSpecifiers(DS);
 
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 5ce6b2b..28c5e8b 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -1322,6 +1322,11 @@
         return TPResult::False();
     }
 
+    // An attribute-specifier-seq here is a sign of a function declarator.
+    if (isCXX11AttributeSpecifier(/*Disambiguate*/false,
+                                  /*OuterMightBeMessageSend*/true))
+      return TPResult::True();
+
     ParsedAttributes attrs(AttrFactory);
     MaybeParseMicrosoftAttributes(attrs);
 
diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp
index bf73e08..f97995e 100644
--- a/test/Parser/cxx0x-attributes.cpp
+++ b/test/Parser/cxx0x-attributes.cpp
@@ -71,6 +71,10 @@
   (void)s.arr[ [] { return 0; }() ]; // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}}
   int n = __builtin_offsetof(S, arr[ [] { return 0; }() ]); // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}}
 
+  void bar [[noreturn]] ([[]] int i, [[]] int j);
+  using FuncType = void ([[]] int);
+  void baz([[]]...); // expected-error {{expected parameter declarator}}
+
   [[]] return;
 }
 
diff --git a/test/Parser/objcxx11-attributes.mm b/test/Parser/objcxx11-attributes.mm
index fead1d1..0875b66 100644
--- a/test/Parser/objcxx11-attributes.mm
+++ b/test/Parser/objcxx11-attributes.mm
@@ -34,6 +34,18 @@
   [[int(), noreturn]];
   [[class, test(foo 'x' bar),,,]];
   [[bitand, noreturn]];
+
+  [[noreturn]]int(e)();
+
+  // A function taking a noreturn function.
+  int(f)([[noreturn]] int());
+  f(e);
+
+  // Variables initialized by a message send.
+  int(g)([[noreturn getSelf] getSize]);
+  int(h)([[noreturn]{return noreturn;}() getSize]);
+
+  int i = g + h;
 }
 
 template<typename...Ts> void f(Ts ...x) {