[cfe-commits] r151227 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/ParseTentative.cpp test/Parser/cxx0x-ambig.cpp test/Parser/cxx0x-condition.cpp

Richard Smith richard-llvm at metafoo.co.uk
Wed Feb 22 17:36:13 PST 2012


Author: rsmith
Date: Wed Feb 22 19:36:12 2012
New Revision: 151227

URL: http://llvm.org/viewvc/llvm-project?rev=151227&view=rev
Log:
Update parser's disambiguation to cope with braced function-style casts in
C++11, and with braced-init-list initializers in conditions. This exposed an
ambiguity with enum underlying types versus bitfields, which we resolve by
treating 'enum E : T {' as always defining an enumeration (even if it would
only successfully parse as a bitfield). This appears to be g++ compatible.

Added:
    cfe/trunk/test/Parser/cxx0x-ambig.cpp
Modified:
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseTentative.cpp
    cfe/trunk/test/Parser/cxx0x-condition.cpp

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=151227&r1=151226&r2=151227&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Feb 22 19:36:12 2012
@@ -1828,9 +1828,11 @@
   /// declaration specifier, TPResult::False() if it is not,
   /// TPResult::Ambiguous() if it could be either a decl-specifier or a
   /// function-style cast, and TPResult::Error() if a parsing error was
-  /// encountered.
+  /// encountered. If it could be a braced C++11 function-style cast, returns
+  /// BracedCastResult.
   /// Doesn't consume tokens.
-  TPResult isCXXDeclarationSpecifier();
+  TPResult
+  isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False());
 
   // "Tentative parsing" functions, used for disambiguation. If a parsing error
   // is encountered they will return TPResult::Error().

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=151227&r1=151226&r2=151227&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed Feb 22 19:36:12 2012
@@ -3000,9 +3000,15 @@
 
         // Consume the ':'.
         ConsumeToken();
-      
-        if ((getLang().CPlusPlus && 
-             isCXXDeclarationSpecifier() != TPResult::True()) ||
+
+        // If we see a type specifier followed by an open-brace, we have an
+        // ambiguity between an underlying type and a C++11 braced
+        // function-style cast. Resolve this by always treating it as an
+        // underlying type.
+        // FIXME: The standard is not entirely clear on how to disambiguate in
+        // this case.
+        if ((getLang().CPlusPlus &&
+             isCXXDeclarationSpecifier(TPResult::True()) != TPResult::True()) ||
             (!getLang().CPlusPlus && !isDeclarationSpecifier(true))) {
           // We'll parse this as a bitfield later.
           PossibleBitfield = true;

Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=151227&r1=151226&r2=151227&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Wed Feb 22 19:36:12 2012
@@ -233,6 +233,8 @@
 ///       condition:
 ///         expression
 ///         type-specifier-seq declarator '=' assignment-expression
+/// [C++11] type-specifier-seq declarator '=' initializer-clause
+/// [C++11] type-specifier-seq declarator braced-init-list
 /// [GNU]   type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
 ///             '=' assignment-expression
 ///
@@ -274,6 +276,8 @@
     if (Tok.is(tok::equal)  ||
         Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
       TPR = TPResult::True();
+    else if (getLang().CPlusPlus0x && Tok.is(tok::l_brace))
+      TPR = TPResult::True();
     else
       TPR = TPResult::False();
   }
@@ -834,7 +838,8 @@
 ///           'volatile'
 /// [GNU]     restrict
 ///
-Parser::TPResult Parser::isCXXDeclarationSpecifier() {
+Parser::TPResult
+Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) {
   switch (Tok.getKind()) {
   case tok::identifier:   // foo::bar
     // Check for need to substitute AltiVec __vector keyword
@@ -849,7 +854,7 @@
       return TPResult::Error();
     if (Tok.is(tok::identifier))
       return TPResult::False();
-    return isCXXDeclarationSpecifier();
+    return isCXXDeclarationSpecifier(BracedCastResult);
 
   case tok::coloncolon: {    // ::foo::bar
     const Token &Next = NextToken();
@@ -863,7 +868,7 @@
     // recurse to handle whatever we get.
     if (TryAnnotateTypeOrScopeToken())
       return TPResult::Error();
-    return isCXXDeclarationSpecifier();
+    return isCXXDeclarationSpecifier(BracedCastResult);
 
     // decl-specifier:
     //   storage-class-specifier
@@ -965,7 +970,7 @@
           bool isIdentifier = Tok.is(tok::identifier);
           TPResult TPR = TPResult::False();
           if (!isIdentifier)
-            TPR = isCXXDeclarationSpecifier();
+            TPR = isCXXDeclarationSpecifier(BracedCastResult);
           PA.Revert();
 
           if (isIdentifier ||
@@ -1005,6 +1010,7 @@
       
       TPResult TPR = TryParseProtocolQualifiers();
       bool isFollowedByParen = Tok.is(tok::l_paren);
+      bool isFollowedByBrace = Tok.is(tok::l_brace);
       
       PA.Revert();
       
@@ -1013,6 +1019,9 @@
       
       if (isFollowedByParen)
         return TPResult::Ambiguous();
+
+      if (getLang().CPlusPlus0x && isFollowedByBrace)
+        return BracedCastResult;
       
       return TPResult::True();
     }
@@ -1036,6 +1045,15 @@
     if (NextToken().is(tok::l_paren))
       return TPResult::Ambiguous();
 
+    // This is a function-style cast in all cases we disambiguate other than
+    // one:
+    //   struct S {
+    //     enum E : int { a = 4 }; // enum
+    //     enum E : int { 4 };     // bit-field
+    //   };
+    if (getLang().CPlusPlus0x && NextToken().is(tok::l_brace))
+      return BracedCastResult;
+
     if (isStartOfObjCClassMessageMissingOpenBracket())
       return TPResult::False();
       
@@ -1050,6 +1068,7 @@
 
     TPResult TPR = TryParseTypeofSpecifier();
     bool isFollowedByParen = Tok.is(tok::l_paren);
+    bool isFollowedByBrace = Tok.is(tok::l_brace);
 
     PA.Revert();
 
@@ -1059,6 +1078,9 @@
     if (isFollowedByParen)
       return TPResult::Ambiguous();
 
+    if (getLang().CPlusPlus0x && isFollowedByBrace)
+      return BracedCastResult;
+
     return TPResult::True();
   }
 
@@ -1219,6 +1241,8 @@
     MaybeParseMicrosoftAttributes(attrs);
 
     // decl-specifier-seq
+    // A parameter-declaration's initializer must be preceded by an '=', so
+    // decl-specifier-seq '{' is not a parameter in C++11.
     TPResult TPR = TryParseDeclarationSpecifier();
     if (TPR != TPResult::Ambiguous())
       return TPR;

Added: cfe/trunk/test/Parser/cxx0x-ambig.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-ambig.cpp?rev=151227&view=auto
==============================================================================
--- cfe/trunk/test/Parser/cxx0x-ambig.cpp (added)
+++ cfe/trunk/test/Parser/cxx0x-ambig.cpp Wed Feb 22 19:36:12 2012
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// New exciting ambiguities in C++11
+
+// final 'context sensitive' mess.
+namespace final {
+  struct S { int n; };
+  namespace N {
+    int n;
+    // This defines a class, not a variable, even though it would successfully
+    // parse as a variable but not as a class. DR1318's wording suggests that
+    // this disambiguation is only performed on an ambiguity, but that was not
+    // the intent.
+    struct S final {
+      int(n) // expected-error {{expected ';'}}
+    };
+  }
+}
+
+// enum versus bitfield mess.
+namespace bitfield {
+  enum E {};
+
+  struct T {
+    constexpr T() {}
+    constexpr T(int) {}
+    constexpr T(T, T, T, T) {}
+    constexpr T operator=(T) { return *this; }
+    constexpr operator int() { return 4; }
+  };
+  constexpr T a, b, c, d;
+
+  struct S1 {
+    enum E : T ( a = 1, b = 2, c = 3, 4 ); // ok, declares a bitfield
+  };
+  // This could be a bit-field.
+  struct S2 {
+    enum E : T { a = 1, b = 2, c = 3, 4 }; // expected-error {{non-integral type}} expected-error {{expected '}'}} expected-note {{to match}}
+  };
+  struct S3 {
+    enum E : int { a = 1, b = 2, c = 3, d }; // ok, defines an enum
+  };
+  // Ambiguous.
+  struct S4 {
+    enum E : int { a = 1 }; // ok, defines an enum
+  };
+  // This could be a bit-field, but would be ill-formed due to the anonymous
+  // member being initialized.
+  struct S5 {
+    enum E : int { a = 1 } { b = 2 }; // expected-error {{expected member name}}
+  };
+  // This could be a bit-field.
+  struct S6 {
+    enum E : int { 1 }; // expected-error {{expected '}'}} expected-note {{to match}}
+  };
+
+  struct U {
+    constexpr operator T() { return T(); } // expected-note 2{{candidate}}
+  };
+  // This could be a bit-field.
+  struct S7 {
+    enum E : int { a = U() }; // expected-error {{no viable conversion}}
+  };
+  // This could be a bit-field, and does not conform to the grammar of an
+  // enum definition, because 'id(U())' is not a constant-expression.
+  constexpr const U &id(const U &u) { return u; }
+  struct S8 {
+    enum E : int { a = id(U()) }; // expected-error {{no viable conversion}}
+  };
+}
+
+namespace trailing_return {
+  typedef int n;
+  int a;
+
+  struct S {
+    S(int);
+    S *operator()() const;
+    int n;
+  };
+
+  namespace N {
+    void f() {
+      // This parses as a function declaration, but DR1223 makes the presence of
+      // 'auto' be used for disambiguation.
+      S(a)()->n; // ok, expression; expected-warning{{expression result unused}}
+      auto(a)()->n; // ok, function declaration
+      using T = decltype(a);
+      using T = auto() -> n;
+    }
+  }
+}

Modified: cfe/trunk/test/Parser/cxx0x-condition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-condition.cpp?rev=151227&r1=151226&r2=151227&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx0x-condition.cpp (original)
+++ cfe/trunk/test/Parser/cxx0x-condition.cpp Wed Feb 22 19:36:12 2012
@@ -27,11 +27,11 @@
   if (S b(n) = 0) {} // expected-error {{a function type is not allowed here}}
   if (S b(n) == 0) {} // expected-error {{a function type is not allowed here}} expected-error {{did you mean '='?}}
 
-  // FIXME: this is legal, and incorrectly rejected, because tentative parsing
-  // does not yet know about braced function-style casts.
-  if (S{a}) {} // unexpected-error{{unqualified-id}}
-
+  if (S{a}) {} // ok
   if (S a{a}) {} // ok
   if (S a = {a}) {} // ok
   if (S a == {a}) {} // expected-error {{did you mean '='?}}
+
+  if (S(b){a}) {} // ok
+  if (S(b) = {a}) {} // ok
 }





More information about the cfe-commits mailing list