Implement support for C++ nested-name-specifiers ('foo::bar::x') in the Parser side.
No Sema functionality change, just the signatures of the Action/Sema methods.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58913 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 2fec359..58e391e 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -55,8 +55,11 @@
 /// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to
 /// determine whether the name is a type name (objc class name or typedef) or
 /// not in this scope.
+///
+/// FIXME: Use the passed CXXScopeSpec for accurate C++ type checking.
 Action::TypeTy *
-MinimalAction::isTypeName(const IdentifierInfo &II, Scope *S) {
+MinimalAction::isTypeName(const IdentifierInfo &II, Scope *S,
+                          const CXXScopeSpec *SS) {
   if (TypeNameInfo *TI = II.getFETokenInfo<TypeNameInfo>())
     if (TI->isTypeName)
       return TI;
@@ -65,7 +68,8 @@
 
 /// isCurrentClassName - Always returns false, because MinimalAction
 /// does not support C++ classes with constructors.
-bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *) {
+bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,
+                                       const CXXScopeSpec *) {
   return false;
 }
 
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 2b18be0..e3094ad 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -13,7 +13,6 @@
 
 #include "clang/Parse/Parser.h"
 #include "clang/Basic/Diagnostic.h"
-#include "clang/Parse/DeclSpec.h"
 #include "clang/Parse/Scope.h"
 #include "ExtensionRAIIObject.h"
 #include "llvm/ADT/SmallSet.h"
@@ -419,6 +418,10 @@
     const char *PrevSpec = 0;
     SourceLocation Loc = Tok.getLocation();
 
+    // Only annotate C++ scope. Allow class-name as an identifier in case
+    // it's a constructor.
+    TryAnnotateScopeToken();
+    
     switch (Tok.getKind()) {
     default: 
       // Try to parse a type-specifier; if we found one, continue.
@@ -430,7 +433,45 @@
       // specifiers.  First verify that DeclSpec's are consistent.
       DS.Finish(Diags, PP.getSourceManager(), getLang());
       return;
-        
+
+    case tok::annot_cxxscope: {
+      if (DS.hasTypeSpecifier())
+        goto DoneWithDeclSpec;
+
+      // We are looking for a qualified typename.
+      if (NextToken().isNot(tok::identifier))
+        goto DoneWithDeclSpec;
+
+      CXXScopeSpec SS;
+      SS.setScopeRep(Tok.getAnnotationValue());
+      SS.setRange(Tok.getAnnotationRange());
+
+      // If the next token is the name of the class type that the C++ scope
+      // denotes, followed by a '(', then this is a constructor declaration.
+      // We're done with the decl-specifiers.
+      if (Actions.isCurrentClassName(*NextToken().getIdentifierInfo(),
+                                     CurScope, &SS) &&
+          GetLookAheadToken(2).is(tok::l_paren))
+        goto DoneWithDeclSpec;
+
+      TypeTy *TypeRep = Actions.isTypeName(*NextToken().getIdentifierInfo(),
+                                           CurScope, &SS);
+      if (TypeRep == 0)
+        goto DoneWithDeclSpec;
+
+      ConsumeToken(); // The C++ scope.
+
+      isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec,
+                                     TypeRep);
+      if (isInvalid)
+        break;
+      
+      DS.SetRangeEnd(Tok.getLocation());
+      ConsumeToken(); // The typename.
+
+      continue;
+    }
+
       // typedef-name
     case tok::identifier: {
       // This identifier can only be a typedef name if we haven't already seen
@@ -605,19 +646,18 @@
 /// [OBJC]  typedef-name objc-protocol-refs[opt]  [TODO]
 bool Parser::MaybeParseTypeSpecifier(DeclSpec &DS, int& isInvalid,
                                      const char *&PrevSpec) {
+  // Annotate typenames and C++ scope specifiers.
+  TryAnnotateTypeOrScopeToken();
+
   SourceLocation Loc = Tok.getLocation();
 
   switch (Tok.getKind()) {
   // simple-type-specifier:
-  case tok::identifier: {
-    TypeTy *TypeRep = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope);
-    if (!TypeRep)
-      return false;
-
+  case tok::annot_qualtypename: {
     isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec,
-                                   TypeRep);
-    DS.SetRangeEnd(Loc);
-    ConsumeToken(); // The identifier
+                                   Tok.getAnnotationValue());
+    DS.SetRangeEnd(Tok.getAnnotationEndLoc());
+    ConsumeToken(); // The typename
     
     // Objective-C supports syntax of the form 'id<proto1,proto2>' where 'id'
     // is a specific typedef and 'itf<proto1,proto2>' where 'itf' is an
@@ -914,11 +954,15 @@
 /// ParseEnumSpecifier
 ///       enum-specifier: [C99 6.7.2.2]
 ///         'enum' identifier[opt] '{' enumerator-list '}'
-/// [C99]   'enum' identifier[opt] '{' enumerator-list ',' '}'
+///[C99/C++]'enum' identifier[opt] '{' enumerator-list ',' '}'
 /// [GNU]   'enum' attributes[opt] identifier[opt] '{' enumerator-list ',' [opt]
 ///                                                 '}' attributes[opt]
 ///         'enum' identifier
 /// [GNU]   'enum' attributes[opt] identifier
+///
+/// [C++] elaborated-type-specifier:
+/// [C++]   'enum' '::'[opt] nested-name-specifier[opt] identifier
+///
 void Parser::ParseEnumSpecifier(DeclSpec &DS) {
   assert(Tok.is(tok::kw_enum) && "Not an enum specifier");
   SourceLocation StartLoc = ConsumeToken();
@@ -929,6 +973,20 @@
   // If attributes exist after tag, parse them.
   if (Tok.is(tok::kw___attribute))
     Attr = ParseAttributes();
+
+  CXXScopeSpec SS;
+  if (isTokenCXXScopeSpecifier()) {
+    ParseCXXScopeSpecifier(SS);
+    if (Tok.isNot(tok::identifier)) {
+      Diag(Tok, diag::err_expected_ident);
+      if (Tok.isNot(tok::l_brace)) {
+        // Has no name and is not a definition.
+        // Skip the rest of this declarator, up until the comma or semicolon.
+        SkipUntil(tok::comma, true);
+        return;
+      }
+    }
+  }
   
   // Must have either 'enum name' or 'enum {...}'.
   if (Tok.isNot(tok::identifier) && Tok.isNot(tok::l_brace)) {
@@ -963,7 +1021,7 @@
   else
     TK = Action::TK_Reference;
   DeclTy *TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TK, StartLoc,
-                                     Name, NameLoc, Attr);
+                                     SS, Name, NameLoc, Attr);
   
   if (Tok.is(tok::l_brace))
     ParseEnumBody(StartLoc, TagDecl);
@@ -1054,7 +1112,10 @@
 
 /// isTypeSpecifierQualifier - Return true if the current token could be the
 /// start of a specifier-qualifier-list.
-bool Parser::isTypeSpecifierQualifier() const {
+bool Parser::isTypeSpecifierQualifier() {
+  // Annotate typenames and C++ scope specifiers.
+  TryAnnotateTypeOrScopeToken();
+
   switch (Tok.getKind()) {
   default: return false;
     // GNU attributes support.
@@ -1092,21 +1153,23 @@
   case tok::kw_const:
   case tok::kw_volatile:
   case tok::kw_restrict:
+
+    // typedef-name
+  case tok::annot_qualtypename:
     return true;
       
     // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
   case tok::less:
     return getLang().ObjC1;
-    
-    // typedef-name
-  case tok::identifier:
-    return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope) != 0;
   }
 }
 
 /// isDeclarationSpecifier() - Return true if the current token is part of a
 /// declaration specifier.
-bool Parser::isDeclarationSpecifier() const {
+bool Parser::isDeclarationSpecifier() {
+  // Annotate typenames and C++ scope specifiers.
+  TryAnnotateTypeOrScopeToken();
+
   switch (Tok.getKind()) {
   default: return false;
     // storage-class-specifier
@@ -1154,6 +1217,9 @@
   case tok::kw_virtual:
   case tok::kw_explicit:
 
+    // typedef-name
+  case tok::annot_qualtypename:
+
     // GNU typeof support.
   case tok::kw_typeof:
     
@@ -1164,10 +1230,6 @@
     // GNU ObjC bizarre protocol extension: <proto1,proto2> with implicit 'id'.
   case tok::less:
     return getLang().ObjC1;
-    
-    // typedef-name
-  case tok::identifier:
-    return Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope) != 0;
   }
 }
 
@@ -1351,12 +1413,22 @@
 ///
 ///       unqualified-id: [C++ 5.1]
 ///         identifier 
-///         operator-function-id    [TODO]
+///         operator-function-id
 ///         conversion-function-id  [TODO]
 ///          '~' class-name         
 ///         template-id             [TODO]
 ///
 void Parser::ParseDirectDeclarator(Declarator &D) {
+  CXXScopeSpec &SS = D.getCXXScopeSpec();
+  DeclaratorScopeObj DeclScopeObj(*this, SS);
+
+  if (D.mayHaveIdentifier() && isTokenCXXScopeSpecifier()) {
+    ParseCXXScopeSpecifier(SS);
+    // Change the declaration context for name lookup, until this function is
+    // exited (and the declarator has been parsed).
+    DeclScopeObj.EnterDeclaratorScope();
+  }
+
   // Parse the first direct-declarator seen.
   if (Tok.is(tok::identifier) && D.mayHaveIdentifier()) {
     assert(Tok.getIdentifierInfo() && "Not an identifier?");
@@ -1407,18 +1479,20 @@
         D.SetConversionFunction(ConvType, II, OperatorLoc);
       }
     }
-  } else if (Tok.is(tok::l_paren)) {
+  } else if (Tok.is(tok::l_paren) && SS.isEmpty()) {
     // direct-declarator: '(' declarator ')'
     // direct-declarator: '(' attributes declarator ')'
     // Example: 'char (*X)'   or 'int (*XX)(void)'
     ParseParenDeclarator(D);
-  } else if (D.mayOmitIdentifier()) {
+  } else if (D.mayOmitIdentifier() && SS.isEmpty()) {
     // This could be something simple like "int" (in which case the declarator
     // portion is empty), if an abstract-declarator is allowed.
     D.SetIdentifier(0, Tok.getLocation());
   } else {
-    // Expected identifier or '('.
-    Diag(Tok, diag::err_expected_ident_lparen);
+    if (getLang().CPlusPlus)
+      Diag(Tok, diag::err_expected_unqualified_id);
+    else
+      Diag(Tok, diag::err_expected_ident_lparen); // Expected identifier or '('.
     D.SetIdentifier(0, Tok.getLocation());
   }
   
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index f90469a..752d552 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -138,7 +138,7 @@
 ///         identifier
 ///         template-id   [TODO]
 /// 
-Parser::TypeTy *Parser::ParseClassName() {
+Parser::TypeTy *Parser::ParseClassName(const CXXScopeSpec *SS) {
   // Parse the class-name.
   // FIXME: Alternatively, parse a simple-template-id.
   if (Tok.isNot(tok::identifier)) {
@@ -147,7 +147,7 @@
   }
 
   // We have an identifier; check whether it is actually a type.
-  TypeTy *Type = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope);
+  TypeTy *Type = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope, SS);
   if (!Type) {
     Diag(Tok.getLocation(), diag::err_expected_class_name);
     return 0;
@@ -216,7 +216,13 @@
   if (Tok.is(tok::kw___attribute))
     Attr = ParseAttributes();
 
-  // FIXME: Parse the (optional) nested-name-specifier.
+  // Parse the (optional) nested-name-specifier.
+  CXXScopeSpec SS;
+  if (isTokenCXXScopeSpecifier()) {
+    ParseCXXScopeSpecifier(SS);
+    if (Tok.isNot(tok::identifier))
+      Diag(Tok, diag::err_expected_ident);
+  }
 
   // Parse the (optional) class name.
   // FIXME: Alternatively, parse a simple-template-id.
@@ -250,7 +256,7 @@
   }
 
   // Parse the tag portion of this.
-  DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, Name, 
+  DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, Name, 
                                      NameLoc, Attr);
 
   // Parse the optional base clause (C++ only).
@@ -354,13 +360,16 @@
     IsVirtual = true;
   }
 
-  // FIXME: Parse optional '::' and optional nested-name-specifier.
+  // Parse optional '::' and optional nested-name-specifier.
+  CXXScopeSpec SS;
+  if (isTokenCXXScopeSpecifier())
+    ParseCXXScopeSpecifier(SS);
 
   // The location of the base class itself.
   SourceLocation BaseLoc = Tok.getLocation();
 
   // Parse the class-name.
-  TypeTy *BaseType = ParseClassName();
+  TypeTy *BaseType = ParseClassName(&SS);
   if (!BaseType)
     return true;
   
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 4515e4b..e8758e1 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -401,7 +401,14 @@
 ///                   conversion-function-id [TODO]
 ///                   '~' class-name         [TODO]
 ///                   template-id            [TODO]
+///
 Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
+  if (getLang().CPlusPlus) {
+    // Annotate typenames and C++ scope specifiers.
+    // Used only in C++; in C let the typedef name be handled as an identifier.
+    TryAnnotateTypeOrScopeToken();
+  }
+
   ExprResult Res;
   tok::TokenKind SavedKind = Tok.getKind();
   
@@ -463,17 +470,9 @@
   case tok::kw_false:
     return ParseCXXBoolLiteral();
 
-  case tok::identifier: {
-    if (getLang().CPlusPlus &&
-        Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope)) {
-      // Handle C++ function-style cast, e.g. "T(4.5)" where T is a typedef for
-      // double.
-      goto HandleType;
-    }
-    
-    // primary-expression: identifier
-    // unqualified-id: identifier
-    // constant: enumeration-constant
+  case tok::identifier: {      // primary-expression: identifier
+                               // unqualified-id: identifier
+                               // constant: enumeration-constant
 
     // Consume the identifier so that we can see if it is followed by a '('.
     // Function designators are allowed to be undeclared (C99 6.5.1p2), so we
@@ -587,7 +586,8 @@
   case tok::kw_typeof: {
     if (!getLang().CPlusPlus)
       goto UnhandledToken;
-  HandleType:
+  case tok::annot_qualtypename:
+    assert(getLang().CPlusPlus && "Expected C++");
     // postfix-expression: simple-type-specifier '(' expression-list[opt] ')'
     //
     DeclSpec DS;
@@ -601,16 +601,11 @@
     return ParsePostfixExpressionSuffix(Res);
   }
 
-  case tok::kw_operator: {
-    SourceLocation OperatorLoc = Tok.getLocation();
-    if (IdentifierInfo *II = MaybeParseOperatorFunctionId()) {
-      Res = Actions.ActOnIdentifierExpr(CurScope, OperatorLoc, *II, 
-                                        Tok.is(tok::l_paren));
-      // These can be followed by postfix-expr pieces.
-      return ParsePostfixExpressionSuffix(Res);
-    }
-    break;
-  }
+  case tok::annot_cxxscope: // [C++] id-expression: qualified-id
+  case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
+                         //                      template-id
+    Res = ParseCXXIdExpression();
+    return ParsePostfixExpressionSuffix(Res);
 
   case tok::at: {
     SourceLocation AtLoc = ConsumeToken();
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 7ce136c..2fe3bcf 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -16,6 +16,154 @@
 #include "clang/Parse/DeclSpec.h"
 using namespace clang;
 
+/// ParseCXXScopeSpecifier - Parse global scope or nested-name-specifier.
+///
+///       '::'[opt] nested-name-specifier
+///       '::'
+///
+///       nested-name-specifier:
+///         type-name '::'
+///         namespace-name '::'
+///         nested-name-specifier identifier '::'
+///         nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
+///
+void Parser::ParseCXXScopeSpecifier(CXXScopeSpec &SS) {
+  assert(isTokenCXXScopeSpecifier() && "Not scope specifier!");
+
+  if (Tok.is(tok::annot_cxxscope)) {
+    SS.setScopeRep(Tok.getAnnotationValue());
+    SS.setRange(Tok.getAnnotationRange());
+    ConsumeToken();
+    return;
+  }
+
+  SS.setBeginLoc(Tok.getLocation());
+
+  // '::'
+
+  if (Tok.is(tok::coloncolon)) {
+    // Global scope.
+    SourceLocation CCLoc = ConsumeToken();
+    SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
+    SS.setEndLoc(CCLoc);
+  }
+
+  // nested-name-specifier:
+  //   type-name '::'
+  //   namespace-name '::'
+  //   nested-name-specifier identifier '::'
+  //   nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
+
+  while (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
+    IdentifierInfo *II = Tok.getIdentifierInfo();
+    SourceLocation IdLoc = ConsumeToken();
+    assert(Tok.is(tok::coloncolon) &&
+           "NextToken() not working properly!");
+    SourceLocation CCLoc = ConsumeToken();
+    if (SS.isInvalid())
+      continue;
+
+    SS.setScopeRep(
+         Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II) );
+    SS.setEndLoc(CCLoc);
+  }
+}
+
+/// ParseCXXIdExpression - Handle id-expression.
+///
+///       id-expression:
+///         unqualified-id
+///         qualified-id
+///
+///       unqualified-id:
+///         identifier
+///         operator-function-id
+///         conversion-function-id                [TODO]
+///         '~' class-name                        [TODO]
+///         template-id                           [TODO]
+///
+///       qualified-id:
+///         '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
+///         '::' identifier
+///         '::' operator-function-id
+///         '::' template-id                      [TODO]
+///
+///       nested-name-specifier:
+///         type-name '::'
+///         namespace-name '::'
+///         nested-name-specifier identifier '::'
+///         nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
+///
+/// NOTE: The standard specifies that, for qualified-id, the parser does not
+/// expect:
+///
+///   '::' conversion-function-id
+///   '::' '~' class-name
+///
+/// This may cause a slight inconsistency on diagnostics:
+///
+/// class C {};
+/// namespace A {}
+/// void f() {
+///   :: A :: ~ C(); // Some Sema error about using destructor with a
+///                  // namespace.
+///   :: ~ C(); // Some Parser error like 'unexpected ~'.
+/// }
+///
+/// We simplify the parser a bit and make it work like:
+///
+///       qualified-id:
+///         '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
+///         '::' unqualified-id
+///
+/// That way Sema can handle and report similar errors for namespaces and the
+/// global scope.
+///
+Parser::ExprResult Parser::ParseCXXIdExpression() {
+  // qualified-id:
+  //   '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
+  //   '::' unqualified-id
+  //
+  CXXScopeSpec SS;
+  if (isTokenCXXScopeSpecifier())
+    ParseCXXScopeSpecifier(SS);
+
+  // unqualified-id:
+  //   identifier
+  //   operator-function-id
+  //   conversion-function-id                [TODO]
+  //   '~' class-name                        [TODO]
+  //   template-id                           [TODO]
+  //
+  switch (Tok.getKind()) {
+  default:
+    return Diag(Tok, diag::err_expected_unqualified_id);
+
+  case tok::identifier: {
+    // Consume the identifier so that we can see if it is followed by a '('.
+    IdentifierInfo &II = *Tok.getIdentifierInfo();
+    SourceLocation L = ConsumeToken();
+    return Actions.ActOnIdentifierExpr(CurScope, L, II,
+                                       Tok.is(tok::l_paren), &SS);
+  }
+
+  case tok::kw_operator: {
+    SourceLocation OperatorLoc = Tok.getLocation();
+    if (IdentifierInfo *II = MaybeParseOperatorFunctionId()) {
+      return Actions.ActOnIdentifierExpr(CurScope, OperatorLoc, *II, 
+                                         Tok.is(tok::l_paren), &SS);
+    }
+    // FIXME: Handle conversion-function-id.
+    unsigned DiagID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error,
+                                    "expected operator-function-id");
+    return Diag(Tok, DiagID);
+  }
+
+  } // switch.
+
+  assert(0 && "The switch was supposed to take care everything.");
+}
+
 /// ParseCXXCasts - This handles the various ways to cast expressions to another
 /// type.
 ///
@@ -207,7 +355,7 @@
 /// simple-type-specifier.
 ///
 ///       simple-type-specifier:
-///         '::'[opt] nested-name-specifier[opt] type-name                [TODO]
+///         '::'[opt] nested-name-specifier[opt] type-name
 ///         '::'[opt] nested-name-specifier 'template' simple-template-id [TODO]
 ///         char
 ///         wchar_t
@@ -229,6 +377,9 @@
 ///         typedef-name
 ///
 void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
+  // Annotate typenames and C++ scope specifiers.
+  TryAnnotateTypeOrScopeToken();
+
   DS.SetRangeStart(Tok.getLocation());
   const char *PrevSpec;
   SourceLocation Loc = Tok.getLocation();
@@ -239,10 +390,9 @@
     abort();
       
   // type-name
-  case tok::identifier: {
-    TypeTy *TypeRep = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope);
-    assert(TypeRep && "Identifier wasn't a type-name!");
-    DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec, TypeRep);
+  case tok::annot_qualtypename: {
+    DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec,
+                       Tok.getAnnotationValue());
     break;
   }
     
@@ -287,7 +437,10 @@
     DS.Finish(Diags, PP.getSourceManager(), getLang());
     return;
   }
-  DS.SetRangeEnd(Tok.getLocation());
+  if (Tok.is(tok::annot_qualtypename))
+    DS.SetRangeEnd(Tok.getAnnotationEndLoc());
+  else
+    DS.SetRangeEnd(Tok.getLocation());
   ConsumeToken();
   DS.Finish(Diags, PP.getSourceManager(), getLang());
 }
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 3e7aeb8..4f6f117 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -569,6 +569,9 @@
 /// [GNU]     restrict
 ///
 Parser::TPResult Parser::isCXXDeclarationSpecifier() {
+  // Annotate typenames and C++ scope specifiers.
+  TryAnnotateTypeOrScopeToken();
+
   switch (Tok.getKind()) {
     // decl-specifier:
     //   storage-class-specifier
@@ -634,11 +637,6 @@
 
     // simple-type-specifier:
 
-  case tok::identifier:
-    if (!Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope))
-      return TPResult::False();
-    // FALL THROUGH.
-
   case tok::kw_char:
   case tok::kw_wchar_t:
   case tok::kw_bool:
@@ -650,6 +648,7 @@
   case tok::kw_float:
   case tok::kw_double:
   case tok::kw_void:
+  case tok::annot_qualtypename:
     if (NextToken().is(tok::l_paren))
       return TPResult::Ambiguous();
 
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 625da6c..ee4cd7b 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -706,3 +706,74 @@
   return Result;
 }
 
+/// TryAnnotateTypeOrScopeToken - If the current token position is on a
+/// typename (possibly qualified in C++) or a C++ scope specifier not followed
+/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
+/// with a single annotation token representing the typename or C++ scope
+/// respectively.
+/// This simplifies handling of C++ scope specifiers and allows efficient
+/// backtracking without the need to re-parse and resolve nested-names and
+/// typenames.
+void Parser::TryAnnotateTypeOrScopeToken() {
+  if (Tok.is(tok::annot_qualtypename) || Tok.is(tok::annot_cxxscope))
+    return;
+
+  CXXScopeSpec SS;
+  if (isTokenCXXScopeSpecifier())
+    ParseCXXScopeSpecifier(SS);
+
+  if (Tok.is(tok::identifier)) {
+    TypeTy *Ty = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope, &SS);
+    if (Ty) {
+      // This is a typename. Replace the current token in-place with an
+      // annotation type token.
+      Tok.setKind(tok::annot_qualtypename);
+      Tok.setAnnotationValue(Ty);
+      Tok.setAnnotationEndLoc(Tok.getLocation());
+      if (SS.isNotEmpty()) // it was a C++ qualified type name.
+        Tok.setLocation(SS.getBeginLoc());
+
+      // In case the tokens were cached, have Preprocessor replace them with the
+      // annotation token.
+      PP.AnnotateCachedTokens(Tok);
+      return;
+    }
+  }
+
+  if (SS.isNotEmpty()) {
+    // A C++ scope specifier that isn't followed by a typename.
+    // Push the current token back into the token stream and use an annotation
+    // scope token for current token.
+    PP.EnterToken(Tok);
+    Tok.setKind(tok::annot_cxxscope);
+    Tok.setAnnotationValue(SS.getScopeRep());
+    Tok.setAnnotationRange(SS.getRange());
+
+    // In case the tokens were cached, have Preprocessor replace them with the
+    // annotation token.
+    PP.AnnotateCachedTokens(Tok);
+  }
+}
+
+/// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only
+/// annotates C++ scope specifiers.
+void Parser::TryAnnotateScopeToken() {
+  if (Tok.is(tok::annot_cxxscope))
+    return;
+
+  if (isTokenCXXScopeSpecifier()) {
+    CXXScopeSpec SS;
+    ParseCXXScopeSpecifier(SS);
+
+    // Push the current token back into the token stream and use an annotation
+    // scope token for current token.
+    PP.EnterToken(Tok);
+    Tok.setKind(tok::annot_cxxscope);
+    Tok.setAnnotationValue(SS.getScopeRep());
+    Tok.setAnnotationRange(SS.getRange());
+
+    // In case the tokens were cached, have Preprocessor replace them with the
+    // annotation token.
+    PP.AnnotateCachedTokens(Tok);
+  }
+}