[cfe-commits] r120582 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/ParseTentative.cpp test/SemaCXX/enum-bitfield.cpp

Douglas Gregor dgregor at apple.com
Wed Dec 1 09:42:47 PST 2010


Author: dgregor
Date: Wed Dec  1 11:42:47 2010
New Revision: 120582

URL: http://llvm.org/viewvc/llvm-project?rev=120582&view=rev
Log:
After parsing a ':' in an enum-specifier within class context,
disambiguate between an expression (for a bit-field width) and a type
(for a fixed underlying type). Since the disambiguation can be
expensive (due to tentative parsing), we perform a simplistic
disambiguation based on one-token lookahead before going into the
full-blown tentative parsing. Based on a patch by Daniel Wallin.

Added:
    cfe/trunk/test/SemaCXX/enum-bitfield.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseTentative.cpp

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=120582&r1=120581&r2=120582&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Dec  1 11:42:47 2010
@@ -1409,6 +1409,18 @@
     bool operator!=(const TPResult &RHS) const { return Res != RHS.Res; }
   };
 
+  /// \brief Based only on the given token kind, determine whether we know that
+  /// we're at the start of an expression or a type-specifier-seq (which may
+  /// be an expression, in C++).
+  ///
+  /// This routine does not attempt to resolve any of the trick cases, e.g.,
+  /// those involving lookup of identifiers.
+  ///
+  /// \returns \c TPR_true if this token starts an expression, \c TPR_false if
+  /// this token starts a type-specifier-seq, or \c TPR_ambiguous if it cannot
+  /// tell.
+  TPResult isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind);
+
   /// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a
   /// declaration specifier, TPResult::False() if it is not,
   /// TPResult::Ambiguous() if it could be either a decl-specifier or a
@@ -1416,7 +1428,7 @@
   /// encountered.
   /// Doesn't consume tokens.
   TPResult isCXXDeclarationSpecifier();
-
+  
   // "Tentative parsing" functions, used for disambiguation. If a parsing error
   // is encountered they will return TPResult::Error().
   // Returning TPResult::True()/False() indicates that the ambiguity was

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=120582&r1=120581&r2=120582&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed Dec  1 11:42:47 2010
@@ -1921,7 +1921,6 @@
   Actions.ActOnTagFinishDefinition(getCurScope(), TagDecl, RBraceLoc);
 }
 
-
 /// ParseEnumSpecifier
 ///       enum-specifier: [C99 6.7.2.2]
 ///         'enum' identifier[opt] '{' enumerator-list '}'
@@ -2014,10 +2013,57 @@
 
   TypeResult BaseType;
 
+  // Parse the fixed underlying type.
   if (getLang().CPlusPlus0x && Tok.is(tok::colon)) {
-    ConsumeToken();
-    SourceRange Range;
-    BaseType = ParseTypeName(&Range);
+    bool PossibleBitfield = false;
+    if (getCurScope()->getFlags() & Scope::ClassScope) {
+      // If we're in class scope, this can either be an enum declaration with
+      // an underlying type, or a declaration of a bitfield member. We try to
+      // use a simple disambiguation scheme first to catch the common cases
+      // (integer literal, sizeof); if it's still ambiguous, we then consider 
+      // anything that's a simple-type-specifier followed by '(' as an 
+      // expression. This suffices because function types are not valid 
+      // underlying types anyway.
+      TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind());
+      // If the next token starts an expression, we know we're parsing a 
+      // bit-field. This is the common case.
+      if (TPR == TPResult::True())
+        PossibleBitfield = true;
+      // If the next token starts a type-specifier-seq, it may be either a
+      // a fixed underlying type or the start of a function-style cast in C++;
+      // lookahead one more token to see if it's obvious that we have a 
+      // fixed underlying type.
+      else if (TPR == TPResult::False() && 
+               GetLookAheadToken(2).getKind() == tok::semi) {
+        // Consume the ':'.
+        ConsumeToken();
+      } else {
+        // We have the start of a type-specifier-seq, so we have to perform
+        // tentative parsing to determine whether we have an expression or a
+        // type.
+        TentativeParsingAction TPA(*this);
+
+        // Consume the ':'.
+        ConsumeToken();
+      
+        if (isCXXDeclarationSpecifier() != TPResult::True()) {
+          // We'll parse this as a bitfield later.
+          PossibleBitfield = true;
+          TPA.Revert();
+        } else {
+          // We have a type-specifier-seq.
+          TPA.Commit();
+        }
+      }
+    } else {
+      // Consume the ':'.
+      ConsumeToken();
+    }
+
+    if (!PossibleBitfield) {
+      SourceRange Range;
+      BaseType = ParseTypeName(&Range);
+    }
   }
 
   // There are three options here.  If we have 'enum foo;', then this is a

Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=120582&r1=120581&r2=120582&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Wed Dec  1 11:42:47 2010
@@ -593,6 +593,116 @@
   return TPResult::Ambiguous();
 }
 
+Parser::TPResult 
+Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
+  switch (Kind) {
+  // Obviously starts an expression.
+  case tok::numeric_constant:
+  case tok::char_constant:
+  case tok::string_literal:
+  case tok::wide_string_literal:
+  case tok::l_square:
+  case tok::l_paren:
+  case tok::amp:
+  case tok::star:
+  case tok::plus:
+  case tok::plusplus:
+  case tok::minus:
+  case tok::minusminus:
+  case tok::tilde:
+  case tok::exclaim:
+  case tok::kw_sizeof:
+  case tok::kw___func__:
+  case tok::kw_const_cast:
+  case tok::kw_delete:
+  case tok::kw_dynamic_cast:
+  case tok::kw_false:
+  case tok::kw_new:
+  case tok::kw_operator:
+  case tok::kw_reinterpret_cast:
+  case tok::kw_static_cast:
+  case tok::kw_this:
+  case tok::kw_throw:
+  case tok::kw_true:
+  case tok::kw_typeid:
+  case tok::kw_alignof:
+  case tok::kw_noexcept:
+  case tok::kw_nullptr:
+  case tok::kw___null:
+  case tok::kw___alignof:
+  case tok::kw___builtin_choose_expr:
+  case tok::kw___builtin_offsetof:
+  case tok::kw___builtin_types_compatible_p:
+  case tok::kw___builtin_va_arg:
+  case tok::kw___imag:
+  case tok::kw___real:
+  case tok::kw___FUNCTION__:
+  case tok::kw___PRETTY_FUNCTION__:
+  case tok::kw___has_nothrow_assign:
+  case tok::kw___has_nothrow_copy:
+  case tok::kw___has_nothrow_constructor:
+  case tok::kw___has_trivial_assign:
+  case tok::kw___has_trivial_copy:
+  case tok::kw___has_trivial_constructor:
+  case tok::kw___has_trivial_destructor:
+  case tok::kw___has_virtual_destructor:
+  case tok::kw___is_abstract:
+  case tok::kw___is_base_of:
+  case tok::kw___is_class:
+  case tok::kw___is_empty:
+  case tok::kw___is_enum:
+  case tok::kw___is_pod:
+  case tok::kw___is_polymorphic:
+  case tok::kw___is_union:
+  case tok::kw___is_literal:
+  case tok::kw___uuidof:
+    return TPResult::True();
+      
+  // Obviously starts a type-specifier-seq:
+  case tok::kw_char:
+  case tok::kw_const:
+  case tok::kw_double:
+  case tok::kw_enum:
+  case tok::kw_float:
+  case tok::kw_int:
+  case tok::kw_long:
+  case tok::kw_restrict:
+  case tok::kw_short:
+  case tok::kw_signed:
+  case tok::kw_struct:
+  case tok::kw_union:
+  case tok::kw_unsigned:
+  case tok::kw_void:
+  case tok::kw_volatile:
+  case tok::kw__Bool:
+  case tok::kw__Complex:
+  case tok::kw_class:
+  case tok::kw_typename:
+  case tok::kw_wchar_t:
+  case tok::kw_char16_t:
+  case tok::kw_char32_t:
+  case tok::kw_decltype:
+  case tok::kw_thread_local:
+  case tok::kw__Decimal32:
+  case tok::kw__Decimal64:
+  case tok::kw__Decimal128:
+  case tok::kw___thread:
+  case tok::kw_typeof:
+  case tok::kw___cdecl:
+  case tok::kw___stdcall:
+  case tok::kw___fastcall:
+  case tok::kw___thiscall:
+  case tok::kw___vector:
+  case tok::kw___pixel:
+    return TPResult::False();
+
+  default:
+    break;
+  }
+  
+  return TPResult::Ambiguous();
+}
+
 /// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a 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()

Added: cfe/trunk/test/SemaCXX/enum-bitfield.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/enum-bitfield.cpp?rev=120582&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/enum-bitfield.cpp (added)
+++ cfe/trunk/test/SemaCXX/enum-bitfield.cpp Wed Dec  1 11:42:47 2010
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fsyntax-only -pedantic -std=c++0x -verify -triple x86_64-apple-darwin %s
+
+enum E {};
+
+struct Z {};
+typedef int Integer;
+
+struct X {
+  enum E : 1;
+  enum E : Z; // expected-error{{invalid underlying type}}
+  enum E2 : int;
+  enum E3 : Integer;
+};
+
+struct Y {
+  enum E : int(2);
+  enum E : Z(); // expected-error{{not an integer constant}}
+};

Propchange: cfe/trunk/test/SemaCXX/enum-bitfield.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/SemaCXX/enum-bitfield.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/SemaCXX/enum-bitfield.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list