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/Driver/PrintParserCallbacks.cpp b/Driver/PrintParserCallbacks.cpp
index 996051a..adf3bed 100644
--- a/Driver/PrintParserCallbacks.cpp
+++ b/Driver/PrintParserCallbacks.cpp
@@ -174,8 +174,9 @@
     }
   
     virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK,
-                             SourceLocation KWLoc, IdentifierInfo *Name,
-                             SourceLocation NameLoc, AttributeList *Attr) {
+                             SourceLocation KWLoc, const CXXScopeSpec &SS,
+                             IdentifierInfo *Name, SourceLocation NameLoc,
+                             AttributeList *Attr) {
       // TagType is an instance of DeclSpec::TST, indicating what kind of tag this
       // is (struct/union/enum/class).
       llvm::cout << __FUNCTION__ << "\n";
@@ -399,7 +400,8 @@
     /// token immediately after it.
     virtual ExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
                                            IdentifierInfo &II,
-                                           bool HasTrailingLParen) {
+                                           bool HasTrailingLParen,
+                                           const CXXScopeSpec *SS) {
       llvm::cout << __FUNCTION__ << "\n";
       return 0;
     }
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 0067061..fa39182 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -550,6 +550,8 @@
      "property type '%0' does not match property type inherited from '%1'")
 
 /// C++ parser diagnostics
+DIAG(err_expected_unqualified_id, ERROR,
+     "expected unqualified-id")
 DIAG(err_no_declarators, ERROR,
      "declaration does not declare anything")
 DIAG(err_func_def_no_params, ERROR,
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 698feff..038c858 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -22,6 +22,7 @@
   // Semantic.
   class DeclSpec;
   class ObjCDeclSpec;
+  class CXXScopeSpec;
   class Declarator;
   class AttributeList;
   struct FieldDeclarator;
@@ -60,6 +61,7 @@
   typedef void AttrTy;
   typedef void BaseTy;
   typedef void MemInitTy;
+  typedef void CXXScopeTy;
 
   /// ActionResult - This structure is used while parsing/acting on expressions,
   /// stmts, etc.  It encapsulates both the object returned by the action, plus
@@ -103,11 +105,54 @@
   
   /// isTypeName - Return non-null if the specified identifier is a typedef name
   /// in the current scope.
-  virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S) = 0;
+  /// An optional CXXScopeSpec can be passed to indicate the C++ scope (class or
+  /// namespace) that the identifier must be a member of.
+  /// i.e. for "foo::bar", 'II' will be "bar" and 'SS' will be "foo::".
+  virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S,
+                             const CXXScopeSpec *SS = 0) = 0;
 
   /// isCurrentClassName - Return true if the specified name is the
   /// name of the innermost C++ class type currently being defined.
-  virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S) = 0;
+  virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
+                                  const CXXScopeSpec *SS = 0) = 0;
+
+  /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
+  /// global scope ('::').
+  virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
+                                                   SourceLocation CCLoc) {
+    return 0;
+  }
+
+  /// ActOnCXXNestedNameSpecifier - Called during parsing of a
+  /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
+  /// we want to resolve "bar::". 'SS' is empty or the previously parsed
+  /// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
+  /// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
+  /// Returns a CXXScopeTy* object representing the C++ scope.
+  virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
+                                                  const CXXScopeSpec &SS,
+                                                  SourceLocation IdLoc,
+                                                  SourceLocation CCLoc,
+                                                  const IdentifierInfo &II) {
+    return 0;
+  }
+
+  /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global
+  /// scope or nested-name-specifier) is parsed, part of a declarator-id.
+  /// After this method is called, according to [C++ 3.4.3p3], names should be
+  /// looked up in the declarator-id's scope, until the declarator is parsed and
+  /// ActOnCXXExitDeclaratorScope is called.
+  /// The 'SS' should be a non-empty valid CXXScopeSpec.
+  virtual void ActOnCXXEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
+  }
+
+  /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously
+  /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same
+  /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well.
+  /// Used to indicate that names should revert to being looked up in the
+  /// defining scope.
+  virtual void ActOnCXXExitDeclaratorScope(const CXXScopeSpec &SS) {
+  }
 
   /// getTypeAsString - Returns a string that describes the given
   /// type. This callback is used in C++ to form identifiers for
@@ -227,8 +272,9 @@
     TK_Definition   // Definition of a tag: 'struct foo { int X; } Y;'
   };
   virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK,
-                           SourceLocation KWLoc, IdentifierInfo *Name,
-                           SourceLocation NameLoc, AttributeList *Attr) {
+                           SourceLocation KWLoc, const CXXScopeSpec &SS,
+                           IdentifierInfo *Name, SourceLocation NameLoc,
+                           AttributeList *Attr) {
     // TagType is an instance of DeclSpec::TST, indicating what kind of tag this
     // is (struct/union/enum/class).
     return 0;
@@ -413,9 +459,13 @@
   /// ActOnIdentifierExpr - Parse an identifier in expression context.
   /// 'HasTrailingLParen' indicates whether or not the identifier has a '('
   /// token immediately after it.
+  /// An optional CXXScopeSpec can be passed to indicate the C++ scope (class or
+  /// namespace) that the identifier must be a member of.
+  /// i.e. for "foo::bar", 'II' will be "bar" and 'SS' will be "foo::".
   virtual ExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
                                          IdentifierInfo &II,
-                                         bool HasTrailingLParen) {
+                                         bool HasTrailingLParen,
+                                         const CXXScopeSpec *SS = 0) {
     return 0;
   }
   
@@ -968,11 +1018,13 @@
   
   /// isTypeName - This looks at the IdentifierInfo::FETokenInfo field to
   /// determine whether the name is a typedef or not in this scope.
-  virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S);
+  virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S,
+                             const CXXScopeSpec *SS);
 
   /// isCurrentClassName - Always returns false, because MinimalAction
   /// does not support C++ classes with constructors.
-  virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S);
+  virtual bool isCurrentClassName(const IdentifierInfo& II, Scope *S,
+                                  const CXXScopeSpec *SS);
 
   /// ActOnDeclarator - If this is a typedef declarator, we modify the
   /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is
diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h
index 76e3e7b..94bd839 100644
--- a/include/clang/Parse/DeclSpec.h
+++ b/include/clang/Parse/DeclSpec.h
@@ -385,6 +385,40 @@
   IdentifierInfo *GetterName;    // getter name of NULL if no getter
   IdentifierInfo *SetterName;    // setter name of NULL if no setter
 };
+
+/// CXXScopeSpec - Represents a C++ nested-name-specifier or a global scope
+/// specifier.
+class CXXScopeSpec {
+  SourceRange Range;
+  Action::CXXScopeTy *ScopeRep;
+
+public:
+  CXXScopeSpec() : ScopeRep(0) {}
+
+  const SourceRange &getRange() const { return Range; }
+  void setRange(const SourceRange &R) { Range = R; }
+  void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); }
+  void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); }
+  SourceLocation getBeginLoc() const { return Range.getBegin(); }
+  SourceLocation getEndLoc() const { return Range.getEnd(); }
+
+  Action::CXXScopeTy *getScopeRep() const { return ScopeRep; }
+  void setScopeRep(Action::CXXScopeTy *S) { ScopeRep = S; }
+
+  bool isEmpty() const { return !Range.isValid(); }
+  bool isNotEmpty() const { return !isEmpty(); }
+
+  /// isInvalid - An error occured during parsing of the scope specifier.
+  bool isInvalid() const { return isNotEmpty() && ScopeRep == 0; }
+
+  /// isSet - A scope specifier was resolved to a valid C++ scope.
+  bool isSet() const { return getScopeRep() != 0; }
+
+  void clear() {
+    Range = SourceRange();
+    ScopeRep = 0;
+  }
+};
   
 /// DeclaratorChunk - One instance of this struct is used for each type in a
 /// declarator that is parsed.
@@ -590,6 +624,7 @@
 /// stack, not objects that are allocated in large quantities on the heap.
 class Declarator {
   const DeclSpec &DS;
+  CXXScopeSpec SS;
   IdentifierInfo *Identifier;
   SourceLocation IdentifierLoc;
   
@@ -667,6 +702,11 @@
   /// be shared or when in error recovery etc.
   DeclSpec &getMutableDeclSpec() { return const_cast<DeclSpec &>(DS); }
 
+  /// getCXXScopeSpec - Return the C++ scope specifier (global scope or
+  /// nested-name-specifier) that is part of the declarator-id.
+  const CXXScopeSpec &getCXXScopeSpec() const { return SS; }
+  CXXScopeSpec &getCXXScopeSpec() { return SS; }
+
   TheContext getContext() const { return Context; }
   DeclaratorKind getKind() const { return Kind; }
 
@@ -675,6 +715,7 @@
   
   /// clear - Reset the contents of this Declarator.
   void clear() {
+    SS.clear();
     Identifier = 0;
     IdentifierLoc = SourceLocation();
     Kind = DK_Abstract;
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index f9b233c..c7558db 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -16,6 +16,7 @@
 
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Parse/Action.h"
+#include "clang/Parse/DeclSpec.h"
 #include <stack>
 
 namespace clang {
@@ -75,6 +76,7 @@
   typedef Action::TypeTy TypeTy;
   typedef Action::BaseTy BaseTy;
   typedef Action::MemInitTy MemInitTy;
+  typedef Action::CXXScopeTy CXXScopeTy;
 
   // Parsing methods.
   
@@ -114,7 +116,35 @@
     return Tok.getKind() == tok::string_literal ||
            Tok.getKind() == tok::wide_string_literal;
   }
+
+  /// isTokenCXXScopeSpecifier - True if this token is '::', or identifier with
+  /// '::' as next token, or a 'C++ scope annotation' token.
+  /// When not in C++, always returns false.
+  ///
+  bool isTokenCXXScopeSpecifier() {
+    return getLang().CPlusPlus &&
+           (Tok.is(tok::coloncolon)     ||
+            Tok.is(tok::annot_cxxscope) ||
+            (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)));
+  }
   
+  /// isTokenUnqualifiedId - True if token is the start of C++ unqualified-id
+  /// or an identifier in C.
+  ///
+  ///       unqualified-id:
+  ///         identifier
+  /// [C++]   operator-function-id
+  /// [C++]   conversion-function-id
+  /// [C++]   '~' class-name
+  /// [C++]   template-id      [TODO]
+  ///
+  bool isTokenUnqualifiedId() const {
+    return Tok.is(tok::identifier)  ||   // identifier or template-id 
+           Tok.is(tok::kw_operator) ||   // operator/conversion-function-id or
+                                         // template-id
+           (Tok.is(tok::tilde) && getLang().CPlusPlus); // '~' class-name
+  }
+
   /// ConsumeToken - Consume the current 'peek token' and lex the next one.
   /// This does not work with all kinds of tokens: strings and specific other
   /// tokens must be consumed with custom methods below.  This returns the
@@ -215,6 +245,20 @@
     return PP.LookAhead(0);
   }
 
+  /// 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 TryAnnotateTypeOrScopeToken();
+
+  /// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only
+  /// annotates C++ scope specifiers.
+  void TryAnnotateScopeToken();
+
   /// TentativeParsingAction - An object that is used as a kind of "tentative
   /// parsing transaction". It gets instantiated to mark the token position and
   /// after the token consumption is done, Commit() or Revert() is called to
@@ -449,6 +493,11 @@
     return ParseParenExpression(Op, CastTy, RParenLoc);
   }
   ExprResult ParseStringLiteralExpression();
+
+  //===--------------------------------------------------------------------===//
+  // C++ Expressions
+  ExprResult ParseCXXIdExpression();
+  void ParseCXXScopeSpecifier(CXXScopeSpec &SS);
   
   //===--------------------------------------------------------------------===//
   // C++ 5.2p1: C++ Casts
@@ -583,8 +632,8 @@
   void ParseStructDeclaration(DeclSpec &DS,
                               llvm::SmallVectorImpl<FieldDeclarator> &Fields);
                               
-  bool isDeclarationSpecifier() const;
-  bool isTypeSpecifierQualifier() const;
+  bool isDeclarationSpecifier();
+  bool isTypeSpecifierQualifier();
   bool isTypeQualifier() const;
 
   /// isDeclarationStatement - Disambiguates between a declaration or an
@@ -700,6 +749,26 @@
   TypeTy *ParseTypeName();
   AttributeList *ParseAttributes();
   void ParseTypeofSpecifier(DeclSpec &DS);
+
+  /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to
+  /// enter a new C++ declarator scope and exit it when the function is
+  /// finished.
+  class DeclaratorScopeObj {
+    CXXScopeSpec &SS;
+    Parser &P;
+  public:
+    DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss) : P(p), SS(ss) {}
+
+    void EnterDeclaratorScope() {
+      if (SS.isSet())
+        P.Actions.ActOnCXXEnterDeclaratorScope(P.CurScope, SS);
+    }
+
+    ~DeclaratorScopeObj() {
+      if (SS.isSet())
+        P.Actions.ActOnCXXExitDeclaratorScope(SS);
+    }
+  };
   
   /// ParseDeclarator - Parse and verify a newly-initialized declarator.
   void ParseDeclarator(Declarator &D);
@@ -722,7 +791,7 @@
 
   //===--------------------------------------------------------------------===//
   // C++ 9: classes [class] and C structs/unions.
-  TypeTy *ParseClassName();
+  TypeTy *ParseClassName(const CXXScopeSpec *SS = 0);
   void ParseClassSpecifier(DeclSpec &DS);
   void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
                                    DeclTy *TagDecl);
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);
+  }
+}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 38f7540..c04f80d 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -270,7 +270,8 @@
   //===--------------------------------------------------------------------===//
   // Symbol table / Decl tracking callbacks: SemaDecl.cpp.
   //
-  virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S);
+  virtual TypeTy *isTypeName(const IdentifierInfo &II, Scope *S,
+                             const CXXScopeSpec *SS);
   virtual std::string getTypeAsString(TypeTy *Type);
   virtual DeclTy *ActOnDeclarator(Scope *S, Declarator &D, DeclTy *LastInGroup);
   virtual DeclTy *ActOnParamDeclarator(Scope *S, Declarator &D);
@@ -300,8 +301,9 @@
   virtual DeclTy *ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS);  
   
   virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK,
-                           SourceLocation KWLoc, IdentifierInfo *Name,
-                           SourceLocation NameLoc, AttributeList *Attr);
+                           SourceLocation KWLoc, const CXXScopeSpec &SS,
+                           IdentifierInfo *Name, SourceLocation NameLoc,
+                           AttributeList *Attr);
   
   DeclTy* ActOnTagStruct(Scope *S, TagDecl::TagKind Kind, TagKind TK,
                          SourceLocation KWLoc, IdentifierInfo *Name,
@@ -585,7 +587,8 @@
   // Primary Expressions.
   virtual ExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
                                          IdentifierInfo &II,
-                                         bool HasTrailingLParen);
+                                         bool HasTrailingLParen,
+                                         const CXXScopeSpec *SS = 0);
   virtual ExprResult ActOnPredefinedExpr(SourceLocation Loc,
                                          tok::TokenKind Kind);
   virtual ExprResult ActOnNumericConstant(const Token &);
@@ -797,7 +800,8 @@
   //===--------------------------------------------------------------------===//
   // C++ Classes
   //
-  virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S);
+  virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
+                                  const CXXScopeSpec *SS);
   
   virtual void ActOnStartCXXClassDef(Scope *S, DeclTy *TagDecl,
                                      SourceLocation LBrace);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 18d77c4..57a5aa8 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -28,7 +28,8 @@
 #include "llvm/ADT/StringExtras.h"
 using namespace clang;
 
-Sema::TypeTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S) {
+Sema::TypeTy *Sema::isTypeName(const IdentifierInfo &II, Scope *S,
+                               const CXXScopeSpec *SS) {
   Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, false);
 
   if (IIDecl && (isa<TypedefDecl>(IIDecl) || 
@@ -2067,8 +2068,9 @@
 /// TagType indicates what kind of tag this is. TK indicates whether this is a
 /// reference/declaration/definition of a tag.
 Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
-                             SourceLocation KWLoc, IdentifierInfo *Name,
-                             SourceLocation NameLoc, AttributeList *Attr) {
+                             SourceLocation KWLoc, const CXXScopeSpec &SS,
+                             IdentifierInfo *Name, SourceLocation NameLoc,
+                             AttributeList *Attr) {
   // If this is a use of an existing tag, it must have a name.
   assert((Name != 0 || TK == TK_Definition) &&
          "Nameless record must be a definition!");
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index fe7efba..2ac5804 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -262,7 +262,8 @@
 /// name of the class type currently being defined. In the case of
 /// nested classes, this will only return true if II is the name of
 /// the innermost class.
-bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *) {
+bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
+                              const CXXScopeSpec *SS) {
   if (CXXRecordDecl *CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext))
     return &II == CurDecl->getIdentifier();
   else
@@ -614,7 +615,7 @@
   }
 
   // It didn't name a member, so see if it names a class.
-  TypeTy *BaseTy = isTypeName(*MemberOrBase, S);
+  TypeTy *BaseTy = isTypeName(*MemberOrBase, S, 0/*SS*/);
   if (!BaseTy)
     return Diag(IdLoc, diag::err_mem_init_not_member_or_class,
                 MemberOrBase->getName(), SourceRange(IdLoc, RParenLoc));
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index d3650c8..d638b8d 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -337,7 +337,8 @@
 /// identifier is used in a function call context.
 Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
                                            IdentifierInfo &II,
-                                           bool HasTrailingLParen) {
+                                           bool HasTrailingLParen,
+                                           const CXXScopeSpec *SS) {
   // Could be enum-constant, value decl, instance variable, etc.
   Decl *D = LookupDecl(&II, Decl::IDNS_Ordinary, S);
   
diff --git a/test/Lexer/cxx0x_keyword.cpp b/test/Lexer/cxx0x_keyword.cpp
index d55649c..a54d263 100644
--- a/test/Lexer/cxx0x_keyword.cpp
+++ b/test/Lexer/cxx0x_keyword.cpp
@@ -1,2 +1,2 @@
 // RUN: clang -fsyntax-only -verify -std=c++0x %s 2>&1
-int static_assert; /* expected-error {{expected identifier or '('}} */
+int static_assert; /* expected-error {{expected unqualified-id}} */