[cfe-commits] r154369 - in /cfe/trunk: include/clang/Basic/DiagnosticParseKinds.td include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseInit.cpp lib/Parse/ParseStmt.cpp lib/Parse/ParseTentative.cpp test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp test/Parser/cxx0x-attributes.cpp test/Parser/objcxx11-attributes.mm test/SemaCXX/new-delete-0x.cpp test/SemaCXX/new-delete.cpp

Richard Smith richard-llvm at metafoo.co.uk
Mon Apr 9 18:32:12 PDT 2012


Author: rsmith
Date: Mon Apr  9 20:32:12 2012
New Revision: 154369

URL: http://llvm.org/viewvc/llvm-project?rev=154369&view=rev
Log:
Disambiguation of '[[':
 * In C++11, '[[' is ill-formed unless it starts an attribute-specifier. Reject
   array sizes and array indexes which begin with a lambda-expression. Recover by
   parsing the lambda as a lambda.
 * In Objective-C++11, either '[' could be the start of a message-send.
   Fully disambiguate this case: it turns out that the grammars of message-sends,
   lambdas and attributes do not actually overlap. Accept any occurrence of '[['
   where either '[' starts a message send, but reject a lambda in an array index
   just like in C++11 mode.

Implement a couple of changes to the attribute wording which occurred after our
attributes implementation landed:
 * In a function-declaration, the attributes go after the exception specification,
   not after the right paren.
 * A reference type can have attributes applied.
 * An 'identifier' in an attribute can also be a keyword. Support for alternative
   tokens (iso646 keywords) in attributes to follow.

And some bug fixes:
 * Parse attributes after declarator-ids, even if they are not simple identifiers.
 * Do not accept attributes after a parenthesized declarator.
 * Accept attributes after an array size in a new-type-id.
 * Partially disamiguate 'delete' followed by a lambda. More work is required
   here for the case where the lambda-introducer is '[]'.

Added:
    cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp
    cfe/trunk/test/Parser/objcxx11-attributes.mm
    cfe/trunk/test/SemaCXX/new-delete-0x.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/ParseInit.cpp
    cfe/trunk/lib/Parse/ParseStmt.cpp
    cfe/trunk/lib/Parse/ParseTentative.cpp
    cfe/trunk/test/Parser/cxx0x-attributes.cpp
    cfe/trunk/test/SemaCXX/new-delete.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=154369&r1=154368&r2=154369&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Apr  9 20:32:12 2012
@@ -469,6 +469,9 @@
 def err_cxx0x_attribute_requires_arguments : Error<
   "C++11 attribute '%0' must have an argument list">;
 def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
+def err_l_square_l_square_not_attribute : Error<
+  "C++11 only allows consecutive left square brackets when "
+  "introducing an attribute">;
 def err_alignas_pack_exp_unsupported : Error<
   "pack expansions in alignment specifiers are not supported yet">;
 

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=154369&r1=154368&r2=154369&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Mon Apr  9 20:32:12 2012
@@ -1864,6 +1864,16 @@
                            Decl **OwnedType = 0);
   void ParseBlockId();
 
+  // Check for the start of a C++11 attribute-specifier-seq in a context where
+  // an attribute is not allowed.
+  bool CheckProhibitedCXX11Attribute() {
+    assert(Tok.is(tok::l_square));
+    if (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))
+      return false;
+    return DiagnoseProhibitedCXX11Attribute();
+  }
+  bool DiagnoseProhibitedCXX11Attribute();
+
   void ProhibitAttributes(ParsedAttributesWithRange &attrs) {
     if (!attrs.Range.isValid()) return;
     DiagnoseProhibitedAttributes(attrs);
@@ -1894,7 +1904,7 @@
                              SourceLocation *EndLoc);
 
   void MaybeParseCXX0XAttributes(Declarator &D) {
-    if (getLangOpts().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+    if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) {
       ParsedAttributesWithRange attrs(AttrFactory);
       SourceLocation endLoc;
       ParseCXX0XAttributes(attrs, &endLoc);
@@ -1903,15 +1913,17 @@
   }
   void MaybeParseCXX0XAttributes(ParsedAttributes &attrs,
                                  SourceLocation *endLoc = 0) {
-    if (getLangOpts().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
+    if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) {
       ParsedAttributesWithRange attrsWithRange(AttrFactory);
       ParseCXX0XAttributes(attrsWithRange, endLoc);
       attrs.takeAllFrom(attrsWithRange);
     }
   }
   void MaybeParseCXX0XAttributes(ParsedAttributesWithRange &attrs,
-                                 SourceLocation *endLoc = 0) {
-    if (getLangOpts().CPlusPlus0x && isCXX0XAttributeSpecifier())
+                                 SourceLocation *endLoc = 0,
+                                 bool OuterMightBeMessageSend = false) {
+    if (getLangOpts().CPlusPlus0x &&
+        isCXX11AttributeSpecifier(false, OuterMightBeMessageSend))
       ParseCXX0XAttributes(attrs, endLoc);
   }
 
@@ -2029,8 +2041,19 @@
   //===--------------------------------------------------------------------===//
   // C++ 7: Declarations [dcl.dcl]
 
-  bool isCXX0XAttributeSpecifier(bool FullLookahead = false,
-                                 tok::TokenKind *After = 0);
+  /// The kind of attribute specifier we have found.
+  enum CXX11AttributeKind {
+    /// This is not an attribute specifier.
+    CAK_NotAttributeSpecifier,
+    /// This should be treated as an attribute-specifier.
+    CAK_AttributeSpecifier,
+    /// The next tokens are '[[', but this is not an attribute-specifier. This
+    /// is ill-formed by C++11 [dcl.attr.grammar]p6.
+    CAK_InvalidAttributeSpecifier
+  };
+  CXX11AttributeKind
+  isCXX11AttributeSpecifier(bool Disambiguate = false,
+                            bool OuterMightBeMessageSend = false);
 
   Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd,
                        SourceLocation InlineLoc = SourceLocation());

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=154369&r1=154368&r2=154369&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Apr  9 20:32:12 2012
@@ -906,6 +906,39 @@
     *EndLoc = T.getCloseLocation();
 }
 
+/// DiagnoseProhibitedCXX11Attribute - We have found the opening square brackets
+/// of a C++11 attribute-specifier in a location where an attribute is not
+/// permitted. By C++11 [dcl.attr.grammar]p6, this is ill-formed. Diagnose this
+/// situation.
+///
+/// \return \c true if we skipped an attribute-like chunk of tokens, \c false if
+/// this doesn't appear to actually be an attribute-specifier, and the caller
+/// should try to parse it.
+bool Parser::DiagnoseProhibitedCXX11Attribute() {
+  assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square));
+
+  switch (isCXX11AttributeSpecifier(/*Disambiguate*/true)) {
+  case CAK_NotAttributeSpecifier:
+    // No diagnostic: we're in Obj-C++11 and this is not actually an attribute.
+    return false;
+
+  case CAK_InvalidAttributeSpecifier:
+    Diag(Tok.getLocation(), diag::err_l_square_l_square_not_attribute);
+    return false;
+
+  case CAK_AttributeSpecifier:
+    // Parse and discard the attributes.
+    SourceLocation BeginLoc = ConsumeBracket();
+    ConsumeBracket();
+    SkipUntil(tok::r_square, /*StopAtSemi*/ false);
+    assert(Tok.is(tok::r_square) && "isCXX11AttributeSpecifier lied");
+    SourceLocation EndLoc = ConsumeBracket();
+    Diag(BeginLoc, diag::err_attributes_not_allowed)
+      << SourceRange(BeginLoc, EndLoc);
+    return true;
+  }
+}
+
 void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) {
   Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed)
     << attrs.Range;
@@ -3454,14 +3487,11 @@
 void Parser::ParseTypeQualifierListOpt(DeclSpec &DS,
                                        bool VendorAttributesAllowed,
                                        bool CXX0XAttributesAllowed) {
-  if (getLangOpts().CPlusPlus0x && isCXX0XAttributeSpecifier()) {
-    SourceLocation Loc = Tok.getLocation();
+  if (getLangOpts().CPlusPlus0x && CXX0XAttributesAllowed &&
+      isCXX11AttributeSpecifier()) {
     ParsedAttributesWithRange attrs(AttrFactory);
     ParseCXX0XAttributes(attrs);
-    if (CXX0XAttributesAllowed)
-      DS.takeAttributesFrom(attrs);
-    else
-      Diag(Loc, diag::err_attributes_not_allowed);
+    DS.takeAttributesFrom(attrs);
   }
 
   SourceLocation EndLoc;
@@ -3654,6 +3684,7 @@
     // Is a pointer.
     DeclSpec DS(AttrFactory);
 
+    // FIXME: GNU attributes are not allowed here in a new-type-id.
     ParseTypeQualifierListOpt(DS);
     D.ExtendWithDeclSpec(DS);
 
@@ -3684,16 +3715,13 @@
            diag::warn_cxx98_compat_rvalue_reference :
            diag::ext_rvalue_reference);
 
+    // GNU-style and C++11 attributes are allowed here, as is restrict.
+    ParseTypeQualifierListOpt(DS);
+    D.ExtendWithDeclSpec(DS);
+
     // C++ 8.3.2p1: cv-qualified references are ill-formed except when the
     // cv-qualifiers are introduced through the use of a typedef or of a
     // template type argument, in which case the cv-qualifiers are ignored.
-    //
-    // [GNU] Retricted references are allowed.
-    // [GNU] Attributes on references are allowed.
-    // [C++0x] Attributes on references are not allowed.
-    ParseTypeQualifierListOpt(DS, true, false);
-    D.ExtendWithDeclSpec(DS);
-
     if (DS.getTypeQualifiers() != DeclSpec::TQ_unspecified) {
       if (DS.getTypeQualifiers() & DeclSpec::TQ_const)
         Diag(DS.getConstSpecLoc(),
@@ -3754,13 +3782,19 @@
 /// [C99]   direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
 /// [C99]   direct-declarator '[' type-qual-list 'static' assignment-expr ']'
 /// [C99]   direct-declarator '[' type-qual-list[opt] '*' ']'
+/// [C++11] direct-declarator '[' constant-expression[opt] ']'
+///                    attribute-specifier-seq[opt]
 ///         direct-declarator '(' parameter-type-list ')'
 ///         direct-declarator '(' identifier-list[opt] ')'
 /// [GNU]   direct-declarator '(' parameter-forward-declarations
 ///                    parameter-type-list[opt] ')'
 /// [C++]   direct-declarator '(' parameter-declaration-clause ')'
 ///                    cv-qualifier-seq[opt] exception-specification[opt]
+/// [C++11] direct-declarator '(' parameter-declaration-clause ')'
+///                    attribute-specifier-seq[opt] cv-qualifier-seq[opt]
+///                    ref-qualifier[opt] exception-specification[opt]
 /// [C++]   declarator-id
+/// [C++11] declarator-id attribute-specifier-seq[opt]
 ///
 ///       declarator-id: [C++ 8]
 ///         '...'[opt] id-expression
@@ -3908,8 +3942,8 @@
   assert(D.isPastIdentifier() &&
          "Haven't past the location of the identifier yet?");
 
-  // Don't parse attributes unless we have an identifier.
-  if (D.getIdentifier())
+  // Don't parse attributes unless we have parsed an unparenthesized name.
+  if (D.hasName() && !D.getNumTypeObjects())
     MaybeParseCXX0XAttributes(D);
 
   while (1) {
@@ -4055,22 +4089,23 @@
 /// declarator D up to a paren, which indicates that we are parsing function
 /// arguments.
 ///
-/// 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.  If RequiresArg is true, then the first argument of the
-/// function is required to be present and required to not be an identifier
-/// list.
-///
-/// For C++, after the parameter-list, it also parses cv-qualifier-seq[opt],
-/// (C++0x) ref-qualifier[opt], exception-specification[opt], and
-/// (C++0x) trailing-return-type[opt].
+/// If FirstArgAttrs 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.
+///
+/// If RequiresArg is true, then the first argument of the function is required
+/// to be present and required to not be an identifier list.
+///
+/// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt],
+/// (C++11) ref-qualifier[opt], exception-specification[opt],
+/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt].
 ///
-/// [C++0x] exception-specification:
+/// [C++11] exception-specification:
 ///           dynamic-exception-specification
 ///           noexcept-specification
 ///
 void Parser::ParseFunctionDeclarator(Declarator &D,
-                                     ParsedAttributes &attrs,
+                                     ParsedAttributes &FirstArgAttrs,
                                      BalancedDelimiterTracker &Tracker,
                                      bool RequiresArg) {
   assert(getCurScope()->isFunctionPrototypeScope() && 
@@ -4096,8 +4131,9 @@
   SmallVector<ParsedType, 2> DynamicExceptions;
   SmallVector<SourceRange, 2> DynamicExceptionRanges;
   ExprResult NoexceptExpr;
+  ParsedAttributes FnAttrs(AttrFactory);
   ParsedType TrailingReturnType;
-  
+
   Actions.ActOnStartFunctionDeclarator();
 
   SourceLocation EndLoc;
@@ -4111,7 +4147,7 @@
     EndLoc = Tracker.getCloseLocation();
   } else {
     if (Tok.isNot(tok::r_paren))
-      ParseParameterDeclarationClause(D, attrs, ParamInfo, EllipsisLoc);
+      ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc);
     else if (RequiresArg)
       Diag(Tok, diag::err_argument_required_after_attribute);
 
@@ -4122,22 +4158,24 @@
     EndLoc = Tracker.getCloseLocation();
 
     if (getLangOpts().CPlusPlus) {
-      MaybeParseCXX0XAttributes(attrs);
+      // FIXME: Accept these components in any order, and produce fixits to
+      // correct the order if the user gets it wrong. Ideally we should deal
+      // with the virt-specifier-seq and pure-specifier in the same way.
 
       // Parse cv-qualifier-seq[opt].
-      ParseTypeQualifierListOpt(DS, false /*no attributes*/);
-        if (!DS.getSourceRange().getEnd().isInvalid()) {
-          EndLoc = DS.getSourceRange().getEnd();
-          ConstQualifierLoc = DS.getConstSpecLoc();
-          VolatileQualifierLoc = DS.getVolatileSpecLoc();
-        }
+      ParseTypeQualifierListOpt(DS, false /*no attributes*/, false);
+      if (!DS.getSourceRange().getEnd().isInvalid()) {
+        EndLoc = DS.getSourceRange().getEnd();
+        ConstQualifierLoc = DS.getConstSpecLoc();
+        VolatileQualifierLoc = DS.getVolatileSpecLoc();
+      }
 
       // Parse ref-qualifier[opt].
       if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) {
         Diag(Tok, getLangOpts().CPlusPlus0x ?
              diag::warn_cxx98_compat_ref_qualifier :
              diag::ext_ref_qualifier);
-        
+
         RefQualifierIsLValueRef = Tok.is(tok::amp);
         RefQualifierLoc = ConsumeToken();
         EndLoc = RefQualifierLoc;
@@ -4151,6 +4189,10 @@
       if (ESpecType != EST_None)
         EndLoc = ESpecRange.getEnd();
 
+      // Parse attribute-specifier-seq[opt]. Per DR 979 and DR 1297, this goes
+      // after the exception-specification.
+      MaybeParseCXX0XAttributes(FnAttrs);
+
       // Parse trailing-return-type[opt].
       if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) {
         Diag(Tok, diag::warn_cxx98_compat_trailing_return_type);
@@ -4181,7 +4223,7 @@
                                              Tracker.getOpenLocation(), 
                                              EndLoc, D,
                                              TrailingReturnType),
-                attrs, EndLoc);
+                FnAttrs, EndLoc);
 
   Actions.ActOnEndFunctionDeclarator();
 }
@@ -4455,7 +4497,12 @@
 /// [C99]   direct-declarator '[' 'static' type-qual-list[opt] assign-expr ']'
 /// [C99]   direct-declarator '[' type-qual-list 'static' assignment-expr ']'
 /// [C99]   direct-declarator '[' type-qual-list[opt] '*' ']'
+/// [C++11] direct-declarator '[' constant-expression[opt] ']'
+///                           attribute-specifier-seq[opt]
 void Parser::ParseBracketDeclarator(Declarator &D) {
+  if (CheckProhibitedCXX11Attribute())
+    return;
+
   BalancedDelimiterTracker T(*this, tok::l_square);
   T.consumeOpen();
 

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=154369&r1=154368&r2=154369&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Apr  9 20:32:12 2012
@@ -2736,38 +2736,38 @@
   Victim->TemplateScope = getCurScope()->getParent()->isTemplateParamScope();
 }
 
-/// ParseCXX0XAttributeSpecifier - Parse a C++0x attribute-specifier. Currently
+/// ParseCXX0XAttributeSpecifier - Parse a C++11 attribute-specifier. Currently
 /// only parses standard attributes.
 ///
-/// [C++0x] attribute-specifier:
+/// [C++11] attribute-specifier:
 ///         '[' '[' attribute-list ']' ']'
 ///         alignment-specifier
 ///
-/// [C++0x] attribute-list:
+/// [C++11] attribute-list:
 ///         attribute[opt]
 ///         attribute-list ',' attribute[opt]
 ///
-/// [C++0x] attribute:
+/// [C++11] attribute:
 ///         attribute-token attribute-argument-clause[opt]
 ///
-/// [C++0x] attribute-token:
+/// [C++11] attribute-token:
 ///         identifier
 ///         attribute-scoped-token
 ///
-/// [C++0x] attribute-scoped-token:
+/// [C++11] attribute-scoped-token:
 ///         attribute-namespace '::' identifier
 ///
-/// [C++0x] attribute-namespace:
+/// [C++11] attribute-namespace:
 ///         identifier
 ///
-/// [C++0x] attribute-argument-clause:
+/// [C++11] attribute-argument-clause:
 ///         '(' balanced-token-seq ')'
 ///
-/// [C++0x] balanced-token-seq:
+/// [C++11] balanced-token-seq:
 ///         balanced-token
 ///         balanced-token-seq balanced-token
 ///
-/// [C++0x] balanced-token:
+/// [C++11] balanced-token:
 ///         '(' balanced-token-seq ')'
 ///         '[' balanced-token-seq ']'
 ///         '{' balanced-token-seq '}'
@@ -2781,7 +2781,7 @@
   }
 
   assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square)
-      && "Not a C++0x attribute list");
+      && "Not a C++11 attribute list");
 
   Diag(Tok.getLocation(), diag::warn_cxx98_compat_attribute);
 
@@ -2793,7 +2793,11 @@
     ConsumeToken();
   }
 
-  while (Tok.is(tok::identifier) || Tok.is(tok::comma)) {
+  // C++11 [dcl.attr.grammar]p3: If a keyword or an alternative token that
+  // satisfies the syntactic requirements of an identifier is contained in an
+  // attribute-token, it is considered an identifier.
+  // FIXME: Support alternative tokens here.
+  while (Tok.getIdentifierInfo() || Tok.is(tok::comma)) {
     // attribute not present
     if (Tok.is(tok::comma)) {
       ConsumeToken();
@@ -2807,7 +2811,7 @@
     if (Tok.is(tok::coloncolon)) {
       ConsumeToken();
 
-      if (!Tok.is(tok::identifier)) {
+      if (!Tok.getIdentifierInfo()) {
         Diag(Tok.getLocation(), diag::err_expected_ident);
         SkipUntil(tok::r_square, tok::comma, true, true);
         continue;
@@ -2824,8 +2828,7 @@
     // No scoped names are supported; ideally we could put all non-standard
     // attributes into namespaces.
     if (!ScopeName) {
-      switch(AttributeList::getKind(AttrName))
-      {
+      switch (AttributeList::getKind(AttrName)) {
       // No arguments
       case AttributeList::AT_carries_dependency:
       case AttributeList::AT_noreturn: {
@@ -2852,6 +2855,9 @@
       // SkipUntil maintains the balancedness of tokens.
       SkipUntil(tok::r_paren, false);
     }
+
+    if (Tok.is(tok::ellipsis))
+      ConsumeToken();
   }
 
   if (ExpectAndConsume(tok::r_square, diag::err_expected_rsquare))
@@ -2874,7 +2880,7 @@
 
   do {
     ParseCXX0XAttributeSpecifier(attrs, endLoc);
-  } while (isCXX0XAttributeSpecifier());
+  } while (isCXX11AttributeSpecifier());
 
   attrs.Range = SourceRange(StartLoc, *endLoc);
 }
@@ -2892,6 +2898,7 @@
   assert(Tok.is(tok::l_square) && "Not a Microsoft attribute list");
 
   while (Tok.is(tok::l_square)) {
+    // FIXME: If this is actually a C++11 attribute, parse it as one.
     ConsumeBracket();
     SkipUntil(tok::r_square, true, true);
     if (endLoc) *endLoc = Tok.getLocation();

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=154369&r1=154368&r2=154369&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Mon Apr  9 20:32:12 2012
@@ -1287,7 +1287,12 @@
       if (getLangOpts().ObjC1 && Tok.isAtStartOfLine() &&
           isSimpleObjCMessageExpression())
         return move(LHS);
-       
+
+      // Reject array indices starting with a lambda-expression. '[[' is
+      // reserved for attributes.
+      if (CheckProhibitedCXX11Attribute())
+        return ExprError();
+
       BalancedDelimiterTracker T(*this, tok::l_square);
       T.consumeOpen();
       Loc = T.getOpenLocation();
@@ -1756,6 +1761,9 @@
         Comps.back().LocEnd = ConsumeToken();
 
       } else if (Tok.is(tok::l_square)) {
+        if (CheckProhibitedCXX11Attribute())
+          return ExprError();
+
         // offsetof-member-designator: offsetof-member-design '[' expression ']'
         Comps.push_back(Sema::OffsetOfComponent());
         Comps.back().isBrackets = true;

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=154369&r1=154368&r2=154369&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Mon Apr  9 20:32:12 2012
@@ -1817,7 +1817,9 @@
       bool isNew = Tok.getKind() == tok::kw_new;
       // Consume the 'new' or 'delete'.
       SymbolLocations[SymbolIdx++] = ConsumeToken();
-      if (Tok.is(tok::l_square)) {
+      // Check for array new/delete.
+      if (Tok.is(tok::l_square) &&
+          (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square))) {
         // Consume the '[' and ']'.
         BalancedDelimiterTracker T(*this, tok::l_square);
         T.consumeOpen();
@@ -2346,6 +2348,10 @@
   // Parse the array dimensions.
   bool first = true;
   while (Tok.is(tok::l_square)) {
+    // An array-size expression can't start with a lambda.
+    if (CheckProhibitedCXX11Attribute())
+      continue;
+
     BalancedDelimiterTracker T(*this, tok::l_square);
     T.consumeOpen();
 
@@ -2360,13 +2366,16 @@
 
     T.consumeClose();
 
-    ParsedAttributes attrs(AttrFactory);
+    // Attributes here appertain to the array type. C++11 [expr.new]p5.
+    ParsedAttributes Attrs(AttrFactory);
+    MaybeParseCXX0XAttributes(Attrs);
+
     D.AddTypeInfo(DeclaratorChunk::getArray(0,
                                             /*static=*/false, /*star=*/false,
                                             Size.release(),
                                             T.getOpenLocation(),
                                             T.getCloseLocation()),
-                  attrs, T.getCloseLocation());
+                  Attrs, T.getCloseLocation());
 
     if (T.getCloseLocation().isInvalid())
       return;
@@ -2418,7 +2427,11 @@
 
   // Array delete?
   bool ArrayDelete = false;
-  if (Tok.is(tok::l_square)) {
+  if (Tok.is(tok::l_square) && NextToken().is(tok::r_square)) {
+    // FIXME: This could be the start of a lambda-expression. We should
+    // disambiguate this, but that will require arbitrary lookahead if
+    // the next token is '(':
+    //   delete [](int*){ /* ... */
     ArrayDelete = true;
     BalancedDelimiterTracker T(*this, tok::l_square);
 

Modified: cfe/trunk/lib/Parse/ParseInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseInit.cpp?rev=154369&r1=154368&r2=154369&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseInit.cpp (original)
+++ cfe/trunk/lib/Parse/ParseInit.cpp Mon Apr  9 20:32:12 2012
@@ -211,6 +211,11 @@
     //   [foo ... bar]     -> array designator
     //   [4][foo bar]      -> obsolete GNU designation with objc message send.
     //
+    // We do not need to check for an expression starting with [[ here. If it
+    // contains an Objective-C message send, then it is not an ill-formed
+    // attribute. If it is a lambda-expression within an array-designator, then
+    // it will be rejected because a constant-expression cannot begin with a
+    // lambda-expression.
     InMessageExpressionRAIIObject InMessage(*this, true);
     
     BalancedDelimiterTracker T(*this, tok::l_square);

Modified: cfe/trunk/lib/Parse/ParseStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseStmt.cpp?rev=154369&r1=154368&r2=154369&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseStmt.cpp (original)
+++ cfe/trunk/lib/Parse/ParseStmt.cpp Mon Apr  9 20:32:12 2012
@@ -84,7 +84,7 @@
   ParenBraceBracketBalancer BalancerRAIIObj(*this);
 
   ParsedAttributesWithRange attrs(AttrFactory);
-  MaybeParseCXX0XAttributes(attrs);
+  MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true);
 
   // Cases in this switch statement should fall through if the parser expects
   // the token to end in a semicolon (in which case SemiError should be set),
@@ -789,7 +789,7 @@
         ConsumeToken();
 
       ParsedAttributesWithRange attrs(AttrFactory);
-      MaybeParseCXX0XAttributes(attrs);
+      MaybeParseCXX0XAttributes(attrs, 0, /*MightBeObjCMessageSend*/ true);
 
       // If this is the start of a declaration, parse it as such.
       if (isDeclarationStatement()) {

Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=154369&r1=154368&r2=154369&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Mon Apr  9 20:32:12 2012
@@ -374,91 +374,167 @@
   return TPR == TPResult::True();
 }
 
-/// isCXX0XAttributeSpecifier - returns true if this is a C++0x
-/// attribute-specifier. By default, unless in Obj-C++, only a cursory check is
-/// performed that will simply return true if a [[ is seen. Currently C++ has no
-/// syntactical ambiguities from this check, but it may inhibit error recovery.
-/// If CheckClosing is true, a check is made for closing ]] brackets.
-///
-/// If given, After is set to the token after the attribute-specifier so that
-/// appropriate parsing decisions can be made; it is left untouched if false is
-/// returned.
-///
-/// FIXME: If an error is in the closing ]] brackets, the program assumes
-/// the absence of an attribute-specifier, which can cause very yucky errors
-/// to occur.
+/// \brief Returns true if this is a C++11 attribute-specifier. Per
+/// C++11 [dcl.attr.grammar]p6, two consecutive left square bracket tokens
+/// always introduce an attribute. In Objective-C++11, this rule does not
+/// apply if either '[' begins a message-send.
 ///
-/// [C++0x] attribute-specifier:
+/// If Disambiguate is true, we try harder to determine whether a '[[' starts
+/// an attribute-specifier, and return CAK_InvalidAttributeSpecifier if not.
+///
+/// If OuterMightBeMessageSend is true, we assume the outer '[' is either an
+/// Obj-C message send or the start of an attribute. Otherwise, we assume it
+/// is not an Obj-C message send.
+///
+/// C++11 [dcl.attr.grammar]:
+///
+///     attribute-specifier:
 ///         '[' '[' attribute-list ']' ']'
 ///         alignment-specifier
 ///
-/// [C++0x] attribute-list:
+///     attribute-list:
 ///         attribute[opt]
 ///         attribute-list ',' attribute[opt]
+///         attribute '...'
+///         attribute-list ',' attribute '...'
 ///
-/// [C++0x] attribute:
+///     attribute:
 ///         attribute-token attribute-argument-clause[opt]
 ///
-/// [C++0x] attribute-token:
-///         identifier
-///         attribute-scoped-token
-///
-/// [C++0x] attribute-scoped-token:
-///         attribute-namespace '::' identifier
-///
-/// [C++0x] attribute-namespace:
+///     attribute-token:
 ///         identifier
+///         identifier '::' identifier
 ///
-/// [C++0x] attribute-argument-clause:
-///         '(' balanced-token-seq ')'
-///
-/// [C++0x] balanced-token-seq:
-///         balanced-token
-///         balanced-token-seq balanced-token
-///
-/// [C++0x] balanced-token:
+///     attribute-argument-clause:
 ///         '(' balanced-token-seq ')'
-///         '[' balanced-token-seq ']'
-///         '{' balanced-token-seq '}'
-///         any token but '(', ')', '[', ']', '{', or '}'
-bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing,
-                                        tok::TokenKind *After) {
+Parser::CXX11AttributeKind
+Parser::isCXX11AttributeSpecifier(bool Disambiguate,
+                                  bool OuterMightBeMessageSend) {
   if (Tok.is(tok::kw_alignas))
-    return true;
+    return CAK_AttributeSpecifier;
 
   if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
-    return false;
-  
-  // No tentative parsing if we don't need to look for ]]
-  if (!CheckClosing && !getLangOpts().ObjC1)
-    return true;
-  
-  struct TentativeReverter {
-    TentativeParsingAction PA;
+    return CAK_NotAttributeSpecifier;
 
-    TentativeReverter (Parser& P)
-      : PA(P)
-    {}
-    ~TentativeReverter () {
-      PA.Revert();
-    }
-  } R(*this);
+  // No tentative parsing if we don't need to look for ']]' or a lambda.
+  if (!Disambiguate && !getLangOpts().ObjC1)
+    return CAK_AttributeSpecifier;
+
+  TentativeParsingAction PA(*this);
 
   // Opening brackets were checked for above.
   ConsumeBracket();
-  ConsumeBracket();
 
-  // SkipUntil will handle balanced tokens, which are guaranteed in attributes.
-  SkipUntil(tok::r_square, false);
+  // Outside Obj-C++11, treat anything with a matching ']]' as an attribute.
+  if (!getLangOpts().ObjC1) {
+    ConsumeBracket();
+
+    bool IsAttribute = SkipUntil(tok::r_square, false);
+    IsAttribute &= Tok.is(tok::r_square);
+
+    PA.Revert();
+
+    return IsAttribute ? CAK_AttributeSpecifier : CAK_InvalidAttributeSpecifier;
+  }
+
+  // In Obj-C++11, we need to distinguish four situations:
+  //  1a) int x[[attr]];                     C++11 attribute.
+  //  1b) [[attr]];                          C++11 statement attribute.
+  //   2) int x[[obj](){ return 1; }()];     Lambda in array size/index.
+  //  3a) int x[[obj get]];                  Message send in array size/index.
+  //  3b) [[Class alloc] init];              Message send in message send.
+  //   4) [[obj]{ return self; }() doStuff]; Lambda in message send.
+  // (1) is an attribute, (2) is ill-formed, and (3) and (4) are accepted.
+
+  // If we have a lambda-introducer, then this is definitely not a message send.
+  // FIXME: If this disambiguation is too slow, fold the tentative lambda parse
+  // into the tentative attribute parse below.
+  LambdaIntroducer Intro;
+  if (!TryParseLambdaIntroducer(Intro)) {
+    // A lambda cannot end with ']]', and an attribute must.
+    bool IsAttribute = Tok.is(tok::r_square);
+
+    PA.Revert();
+
+    if (IsAttribute)
+      // Case 1: C++11 attribute.
+      return CAK_AttributeSpecifier;
+
+    if (OuterMightBeMessageSend)
+      // Case 4: Lambda in message send.
+      return CAK_NotAttributeSpecifier;
+
+    // Case 2: Lambda in array size / index.
+    return CAK_InvalidAttributeSpecifier;
+  }
 
-  if (Tok.isNot(tok::r_square))
-    return false;
   ConsumeBracket();
 
-  if (After)
-    *After = Tok.getKind();
+  // If we don't have a lambda-introducer, then we have an attribute or a
+  // message-send.
+  bool IsAttribute = true;
+  while (Tok.isNot(tok::r_square)) {
+    if (Tok.is(tok::comma)) {
+      // Case 1: Stray commas can only occur in attributes.
+      PA.Revert();
+      return CAK_AttributeSpecifier;
+    }
+
+    // Parse the attribute-token, if present.
+    // C++11 [dcl.attr.grammar]:
+    //   If a keyword or an alternative token that satisfies the syntactic
+    //   requirements of an identifier is contained in an attribute-token,
+    //   it is considered an identifier.
+    if (!Tok.getIdentifierInfo()) {
+      IsAttribute = false;
+      break;
+    }
+    ConsumeToken();
+    if (Tok.is(tok::coloncolon)) {
+      ConsumeToken();
+      if (!Tok.getIdentifierInfo()) {
+        IsAttribute = false;
+        break;
+      }
+      ConsumeToken();
+    }
+
+    // Parse the attribute-argument-clause, if present.
+    if (Tok.is(tok::l_paren)) {
+      ConsumeParen();
+      if (!SkipUntil(tok::r_paren, false)) {
+        IsAttribute = false;
+        break;
+      }
+    }
+
+    if (Tok.is(tok::ellipsis))
+      ConsumeToken();
+
+    if (Tok.isNot(tok::comma))
+      break;
+
+    ConsumeToken();
+  }
+
+  // An attribute must end ']]'.
+  if (IsAttribute) {
+    if (Tok.is(tok::r_square)) {
+      ConsumeBracket();
+      IsAttribute = Tok.is(tok::r_square);
+    } else {
+      IsAttribute = false;
+    }
+  }
+
+  PA.Revert();
+
+  if (IsAttribute)
+    // Case 1: C++11 statement attribute.
+    return CAK_AttributeSpecifier;
 
-  return true;
+  // Case 3: Message send.
+  return CAK_NotAttributeSpecifier;
 }
 
 ///         declarator:
@@ -1217,11 +1293,13 @@
 ///   parameter-declaration-list ',' parameter-declaration
 ///
 /// parameter-declaration:
-///   decl-specifier-seq declarator attributes[opt]
-///   decl-specifier-seq declarator attributes[opt] '=' assignment-expression
-///   decl-specifier-seq abstract-declarator[opt] attributes[opt]
-///   decl-specifier-seq abstract-declarator[opt] attributes[opt]
+///   attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt]
+///   attribute-specifier-seq[opt] decl-specifier-seq declarator attributes[opt]
 ///     '=' assignment-expression
+///   attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
+///     attributes[opt]
+///   attribute-specifier-seq[opt] decl-specifier-seq abstract-declarator[opt]
+///     attributes[opt] '=' assignment-expression
 ///
 Parser::TPResult Parser::TryParseParameterDeclarationClause() {
 

Added: cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp?rev=154369&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp (added)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.attr/dcl.attr.grammar/p6.cpp Mon Apr  9 20:32:12 2012
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+namespace std_example {
+
+int p[10];
+void f() {
+  int x = 42, y[5];
+  // FIXME: Produce a better diagnostic for this case.
+  int(p[[x] { return x; }()]); // expected-error {{expected ']'}}
+  y[[] { return 2; }()] = 2; // expected-error {{consecutive left square brackets}}
+}
+
+}

Modified: cfe/trunk/test/Parser/cxx0x-attributes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-attributes.cpp?rev=154369&r1=154368&r2=154369&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx0x-attributes.cpp (original)
+++ cfe/trunk/test/Parser/cxx0x-attributes.cpp Mon Apr  9 20:32:12 2012
@@ -5,11 +5,17 @@
 int [[]] between_attr;
 int after_attr [[]];
 int * [[]] ptr_attr;
+int & [[]] ref_attr = after_attr;
+int && [[]] rref_attr = 0;
 int array_attr [1] [[]];
 alignas(8) int aligned_attr;
 [[test::valid(for 42 [very] **** '+' symbols went on a trip; the end.)]]
   int garbage_attr;
 void fn_attr () [[]];
+void noexcept_fn_attr () noexcept [[]];
+struct MemberFnOrder {
+  virtual void f() const volatile && noexcept [[]] final = 0;
+};
 class [[]] class_attr {};
 extern "C++" [[]] int extern_attr;
 template <typename T> [[]] void template_attr ();
@@ -17,10 +23,10 @@
 
 int comma_attr [[,]]; // expected-error {{expected identifier}}
 int scope_attr [[foo::]]; // expected-error {{expected identifier}}
+int (paren_attr) [[]]; // expected-error {{an attribute list cannot appear here}}
 unsigned [[]] int attr_in_decl_spec; // expected-error {{expected unqualified-id}}
-int & [[]] ref_attr = after_attr; // expected-error {{an attribute list cannot appear here}}
 class foo {
-  void after_const_attr () const [[]]; // expected-error {{expected body of lambda expression}}
+  void const_after_attr () [[]] const; // expected-error {{expected ';'}}
 };
 extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}}
 [[]] template <typename T> void before_template_attr (); // expected-error {{an attribute list cannot appear here}}
@@ -58,6 +64,9 @@
   [[]] try {
   } [[]] catch (...) { // expected-error {{an attribute list cannot appear here}}
   }
-  
+  struct S { int arr[2]; } s;
+  (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}}
+
   [[]] return;
 }

Added: cfe/trunk/test/Parser/objcxx11-attributes.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/objcxx11-attributes.mm?rev=154369&view=auto
==============================================================================
--- cfe/trunk/test/Parser/objcxx11-attributes.mm (added)
+++ cfe/trunk/test/Parser/objcxx11-attributes.mm Mon Apr  9 20:32:12 2012
@@ -0,0 +1,42 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+ at interface X {}
++ (X*) alloc;
+- (X*) init;
+- (int) getSize;
+- (void) setSize: (int) size;
+- (X*) getSelf;
+ at end
+
+void f(X *noreturn) {
+  // An array size which is computed by a message send is OK.
+  int a[ [noreturn getSize] ];
+
+  // ... but is interpreted as an attribute where possible.
+  int b[ [noreturn] ]; // expected-warning {{'noreturn' only applies to function types}}
+
+  int c[ [noreturn getSize] + 1 ];
+
+  // An array size which is computed by a lambda is not OK.
+  int d[ [noreturn] { return 3; } () ]; // expected-error {{expected ']'}} expected-warning {{'noreturn' only applies}}
+
+  // A message send which contains a message send is OK.
+  [ [ X alloc ] init ];
+  [ [ int(), noreturn getSelf ] getSize ]; // expected-warning {{unused}}
+
+  // A message send which contains a lambda is OK.
+  [ [noreturn] { return noreturn; } () setSize: 4 ];
+  [ [bitand] { return noreturn; } () setSize: 5 ];
+  [[[[] { return [ X alloc ]; } () init] getSelf] getSize];
+
+  // An attribute is OK.
+  [[]];
+  [[int(), noreturn]];
+  [[class, test(foo 'x' bar),,,]];
+}
+
+template<typename...Ts> void f(Ts ...x) {
+  [[test::foo(bar, baz)...]];
+  [[used(x)...]];
+  [[x...] { return [ X alloc ]; }() init];
+}

Added: cfe/trunk/test/SemaCXX/new-delete-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/new-delete-0x.cpp?rev=154369&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/new-delete-0x.cpp (added)
+++ cfe/trunk/test/SemaCXX/new-delete-0x.cpp Mon Apr  9 20:32:12 2012
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -std=c++11
+
+using size_t = decltype(sizeof(0));
+struct noreturn_t {} constexpr noreturn = {};
+
+void *operator new [[noreturn]] (size_t, noreturn_t);
+void operator delete [[noreturn]] (void*, noreturn_t);
+
+void good_news()
+{
+  auto p = new int[2][[]];
+  auto q = new int[[]][2];
+  auto r = new int*[[]][2][[]];
+  auto s = new (int(*[[]])[2][[]]);
+}
+
+void bad_news(int *ip)
+{
+  // attribute-specifiers can go almost anywhere in a new-type-id...
+  auto r = new int[[]{return 1;}()][2]; // expected-error {{expected ']'}}
+  auto s = new int*[[]{return 1;}()][2]; // expected-error {{expected ']'}}
+  // ... but not here:
+  auto t = new (int(*)[[]]); // expected-error {{an attribute list cannot appear here}}
+  auto u = new (int(*)[[]{return 1;}()][2]); // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}} expected-error {{variably modified type}}
+}
+
+void good_deletes()
+{
+  delete [&]{ return (int*)0; }();
+  // FIXME: This appears to be legal.
+  delete []{ return (int*)0; }(); // unexpected-error {{expected expression}}
+}

Modified: cfe/trunk/test/SemaCXX/new-delete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/new-delete.cpp?rev=154369&r1=154368&r2=154369&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/new-delete.cpp (original)
+++ cfe/trunk/test/SemaCXX/new-delete.cpp Mon Apr  9 20:32:12 2012
@@ -102,8 +102,7 @@
 void bad_deletes()
 {
   delete 0; // expected-error {{cannot delete expression of type 'int'}}
-  delete [0] (int*)0; // expected-error {{expected ']'}} \
-                      // expected-note {{to match this '['}}
+  delete [0] (int*)0; // expected-error {{expected expression}}
   delete (void*)0; // expected-warning {{cannot delete expression with pointer-to-'void' type 'void *'}}
   delete (T*)0; // expected-warning {{deleting pointer to incomplete type}}
   ::S::delete (int*)0; // expected-error {{expected unqualified-id}}





More information about the cfe-commits mailing list