Exemplo n.º 1
0
bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
                                        UnexpandedParameterPackContext UPPC) {
  // C++0x [temp.variadic]p5:
  //   An appearance of a name of a parameter pack that is not expanded is
  //   ill-formed.
  if (!SS.getScopeRep() ||
      !SS.getScopeRep()->containsUnexpandedParameterPack())
    return false;

  SmallVector<UnexpandedParameterPack, 2> Unexpanded;
  CollectUnexpandedParameterPacksVisitor(Unexpanded)
    .TraverseNestedNameSpecifier(SS.getScopeRep());
  assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
  return DiagnoseUnexpandedParameterPacks(SS.getRange().getBegin(),
                                          UPPC, Unexpanded);
}
Exemplo n.º 2
0
/// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only
/// annotates C++ scope specifiers and template-ids.  This returns
/// true if the token was annotated or there was an error that could not be
/// recovered from.
/// 
/// Note that this routine emits an error if you call it with ::new or ::delete
/// as the current tokens, so only call it in contexts where these are invalid.
bool Parser::TryAnnotateCXXScopeToken() {
  assert(getLang().CPlusPlus &&
         "Call sites of this function should be guarded by checking for C++");
  assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) &&
         "Cannot be a type or scope token!");

  CXXScopeSpec SS;
  if (!ParseOptionalCXXScopeSpecifier(SS))
    return Tok.is(tok::annot_template_id);

  // Push the current token back into the token stream (or revert it if it is
  // cached) and use an annotation scope token for current token.
  if (PP.isBacktrackEnabled())
    PP.RevertCachedTokens(1);
  else
    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);
  return true;
}
// \brief Determine whether this C++ scope specifier refers to an
// unknown specialization, i.e., a dependent type that is not the
// current instantiation.
bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
  if (!isDependentScopeSpecifier(SS))
    return false;

  NestedNameSpecifier *NNS
    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
  return getCurrentInstantiationOf(NNS) == 0;
}
bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
  if (!SS.isSet() || SS.isInvalid())
    return false;

  NestedNameSpecifier *NNS
    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
  return NNS->isDependent();
}
Exemplo n.º 5
0
/// \brief Retrieve a version of the type 'T' that is qualified by the
/// nested-name-specifier contained in SS.
QualType Sema::getQualifiedNameType(const CXXScopeSpec &SS, QualType T) {
  if (!SS.isSet() || SS.isInvalid() || T.isNull())
    return T;
  
  NestedNameSpecifier *NNS
    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
  return Context.getQualifiedNameType(NNS, T);
}
Exemplo n.º 6
0
static ExprResult
BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
                        const CXXScopeSpec &SS, FieldDecl *Field,
                        DeclAccessPair FoundDecl,
                        const DeclarationNameInfo &MemberNameInfo) {
  // x.a is an l-value if 'a' has a reference type. Otherwise:
  // x.a is an l-value/x-value/pr-value if the base is (and note
  //   that *x is always an l-value), except that if the base isn't
  //   an ordinary object then we must have an rvalue.
  ExprValueKind VK = VK_LValue;
  ExprObjectKind OK = OK_Ordinary;
  if (!IsArrow) {
    if (BaseExpr->getObjectKind() == OK_Ordinary)
      VK = BaseExpr->getValueKind();
    else
      VK = VK_RValue;
  }
  if (VK != VK_RValue && Field->isBitField())
    OK = OK_BitField;
  
  // Figure out the type of the member; see C99 6.5.2.3p3, C++ [expr.ref]
  QualType MemberType = Field->getType();
  if (const ReferenceType *Ref = MemberType->getAs<ReferenceType>()) {
    MemberType = Ref->getPointeeType();
    VK = VK_LValue;
  } else {
    QualType BaseType = BaseExpr->getType();
    if (IsArrow) BaseType = BaseType->getAs<PointerType>()->getPointeeType();

    Qualifiers BaseQuals = BaseType.getQualifiers();

    // CVR attributes from the base are picked up by members,
    // except that 'mutable' members don't pick up 'const'.
    if (Field->isMutable()) BaseQuals.removeConst();

    Qualifiers MemberQuals
    = S.Context.getCanonicalType(MemberType).getQualifiers();

    assert(!MemberQuals.hasAddressSpace());


    Qualifiers Combined = BaseQuals + MemberQuals;
    if (Combined != MemberQuals)
      MemberType = S.Context.getQualifiedType(MemberType, Combined);
  }

  S.UnusedPrivateFields.remove(Field);

  ExprResult Base =
  S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(),
                                  FoundDecl, Field);
  if (Base.isInvalid())
    return ExprError();
  return S.Owned(BuildMemberExpr(S, S.Context, Base.take(), IsArrow,
                                 Field, FoundDecl, MemberNameInfo,
                                 MemberType, VK, OK));
}
Exemplo n.º 7
0
void Sema::collectUnexpandedParameterPacks(CXXScopeSpec &SS,
                                           SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
  NestedNameSpecifier *Qualifier = SS.getScopeRep();
  if (!Qualifier)
    return;

  NestedNameSpecifierLoc QualifierLoc(Qualifier, SS.location_data());
  CollectUnexpandedParameterPacksVisitor(Unexpanded)
    .TraverseNestedNameSpecifierLoc(QualifierLoc);
}
Exemplo n.º 8
0
bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) {
  assert(SS.isSet() && "Parser passed invalid CXXScopeSpec.");

  // Don't enter a declarator context when the current context is an Objective-C
  // declaration.
  if (isa<ObjCContainerDecl>(CurContext) || isa<ObjCMethodDecl>(CurContext))
    return false;

  NestedNameSpecifier *Qualifier = SS.getScopeRep();

  // There are only two places a well-formed program may qualify a
  // declarator: first, when defining a namespace or class member
  // out-of-line, and second, when naming an explicitly-qualified
  // friend function.  The latter case is governed by
  // C++03 [basic.lookup.unqual]p10:
  //   In a friend declaration naming a member function, a name used
  //   in the function declarator and not part of a template-argument
  //   in a template-id is first looked up in the scope of the member
  //   function's class. If it is not found, or if the name is part of
  //   a template-argument in a template-id, the look up is as
  //   described for unqualified names in the definition of the class
  //   granting friendship.
  // i.e. we don't push a scope unless it's a class member.

  switch (Qualifier->getKind()) {
  case NestedNameSpecifier::Global:
  case NestedNameSpecifier::Namespace:
  case NestedNameSpecifier::NamespaceAlias:
    // These are always namespace scopes.  We never want to enter a
    // namespace scope from anything but a file context.
    return CurContext->getRedeclContext()->isFileContext();

  case NestedNameSpecifier::Identifier:
  case NestedNameSpecifier::TypeSpec:
  case NestedNameSpecifier::TypeSpecWithTemplate:
  case NestedNameSpecifier::Super:
    // These are never namespace scopes.
    return true;
  }

  llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
Exemplo n.º 9
0
/// 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()
/// if a parsing error was found and reported.
///
/// If HasMissingTypename is provided, a name with a dependent scope specifier
/// will be treated as ambiguous if the 'typename' keyword is missing. If this
/// happens, *HasMissingTypename will be set to 'true'.
///
///         decl-specifier:
///           storage-class-specifier
///           type-specifier
///           function-specifier
///           'friend'
///           'typedef'
/// [C++0x]   'constexpr'
/// [GNU]     attributes declaration-specifiers[opt]
///
///         storage-class-specifier:
///           'register'
///           'static'
///           'extern'
///           'mutable'
///           'auto'
/// [GNU]     '__thread'
///
///         function-specifier:
///           'inline'
///           'virtual'
///           'explicit'
///
///         typedef-name:
///           identifier
///
///         type-specifier:
///           simple-type-specifier
///           class-specifier
///           enum-specifier
///           elaborated-type-specifier
///           typename-specifier
///           cv-qualifier
///
///         simple-type-specifier:
///           '::'[opt] nested-name-specifier[opt] type-name
///           '::'[opt] nested-name-specifier 'template'
///                 simple-template-id                              [TODO]
///           'char'
///           'wchar_t'
///           'bool'
///           'short'
///           'int'
///           'long'
///           'signed'
///           'unsigned'
///           'float'
///           'double'
///           'void'
/// [GNU]     typeof-specifier
/// [GNU]     '_Complex'
/// [C++0x]   'auto'                                                [TODO]
/// [C++0x]   'decltype' ( expression )
///
///         type-name:
///           class-name
///           enum-name
///           typedef-name
///
///         elaborated-type-specifier:
///           class-key '::'[opt] nested-name-specifier[opt] identifier
///           class-key '::'[opt] nested-name-specifier[opt] 'template'[opt]
///               simple-template-id
///           'enum' '::'[opt] nested-name-specifier[opt] identifier
///
///         enum-name:
///           identifier
///
///         enum-specifier:
///           'enum' identifier[opt] '{' enumerator-list[opt] '}'
///           'enum' identifier[opt] '{' enumerator-list ',' '}'
///
///         class-specifier:
///           class-head '{' member-specification[opt] '}'
///
///         class-head:
///           class-key identifier[opt] base-clause[opt]
///           class-key nested-name-specifier identifier base-clause[opt]
///           class-key nested-name-specifier[opt] simple-template-id
///               base-clause[opt]
///
///         class-key:
///           'class'
///           'struct'
///           'union'
///
///         cv-qualifier:
///           'const'
///           'volatile'
/// [GNU]     restrict
///
Parser::TPResult
Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult,
                                  bool *HasMissingTypename) {
  switch (Tok.getKind()) {
  case tok::identifier:   // foo::bar
    // Check for need to substitute AltiVec __vector keyword
    // for "vector" identifier.
    if (TryAltiVecVectorToken())
      return TPResult::True();
    // Fall through.
  case tok::kw_typename:  // typename T::type
    // Annotate typenames and C++ scope specifiers.  If we get one, just
    // recurse to handle whatever we get.
    if (TryAnnotateTypeOrScopeToken())
      return TPResult::Error();
    if (Tok.is(tok::identifier)) {
      const Token &Next = NextToken();
      return (!getLangOpts().ObjC1 && Next.is(tok::identifier)) ?
          TPResult::True() : TPResult::False();
    }
    return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);

  case tok::coloncolon: {    // ::foo::bar
    const Token &Next = NextToken();
    if (Next.is(tok::kw_new) ||    // ::new
        Next.is(tok::kw_delete))   // ::delete
      return TPResult::False();
  }
    // Fall through.
  case tok::kw_decltype:
    // Annotate typenames and C++ scope specifiers.  If we get one, just
    // recurse to handle whatever we get.
    if (TryAnnotateTypeOrScopeToken())
      return TPResult::Error();
    return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename);

    // decl-specifier:
    //   storage-class-specifier
    //   type-specifier
    //   function-specifier
    //   'friend'
    //   'typedef'
    //   'constexpr'
  case tok::kw_friend:
  case tok::kw_typedef:
  case tok::kw_constexpr:
    // storage-class-specifier
  case tok::kw_register:
  case tok::kw_static:
  case tok::kw_extern:
  case tok::kw_mutable:
  case tok::kw_auto:
  case tok::kw___thread:
    // function-specifier
  case tok::kw_inline:
  case tok::kw_virtual:
  case tok::kw_explicit:

    // Modules
  case tok::kw___module_private__:
      
    // type-specifier:
    //   simple-type-specifier
    //   class-specifier
    //   enum-specifier
    //   elaborated-type-specifier
    //   typename-specifier
    //   cv-qualifier

    // class-specifier
    // elaborated-type-specifier
  case tok::kw_class:
  case tok::kw_struct:
  case tok::kw_union:
    // enum-specifier
  case tok::kw_enum:
    // cv-qualifier
  case tok::kw_const:
  case tok::kw_volatile:

    // GNU
  case tok::kw_restrict:
  case tok::kw__Complex:
  case tok::kw___attribute:
    return TPResult::True();

    // Microsoft
  case tok::kw___declspec:
  case tok::kw___cdecl:
  case tok::kw___stdcall:
  case tok::kw___fastcall:
  case tok::kw___thiscall:
  case tok::kw___w64:
  case tok::kw___ptr64:
  case tok::kw___ptr32:
  case tok::kw___forceinline:
  case tok::kw___unaligned:
    return TPResult::True();

    // Borland
  case tok::kw___pascal:
    return TPResult::True();
  
    // AltiVec
  case tok::kw___vector:
    return TPResult::True();

  case tok::annot_template_id: {
    TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
    if (TemplateId->Kind != TNK_Type_template)
      return TPResult::False();
    CXXScopeSpec SS;
    AnnotateTemplateIdTokenAsType();
    assert(Tok.is(tok::annot_typename));
    goto case_typename;
  }

  case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
    // We've already annotated a scope; try to annotate a type.
    if (TryAnnotateTypeOrScopeToken())
      return TPResult::Error();
    if (!Tok.is(tok::annot_typename)) {
      // If the next token is an identifier or a type qualifier, then this
      // can't possibly be a valid expression either.
      if (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier)) {
        CXXScopeSpec SS;
        Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
                                                     Tok.getAnnotationRange(),
                                                     SS);
        if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) {
          TentativeParsingAction PA(*this);
          ConsumeToken();
          ConsumeToken();
          bool isIdentifier = Tok.is(tok::identifier);
          TPResult TPR = TPResult::False();
          if (!isIdentifier)
            TPR = isCXXDeclarationSpecifier(BracedCastResult,
                                            HasMissingTypename);
          PA.Revert();

          if (isIdentifier ||
              TPR == TPResult::True() || TPR == TPResult::Error())
            return TPResult::Error();

          if (HasMissingTypename) {
            // We can't tell whether this is a missing 'typename' or a valid
            // expression.
            *HasMissingTypename = true;
            return TPResult::Ambiguous();
          }
        }
      }
      return TPResult::False();
    }
    // If that succeeded, fallthrough into the generic simple-type-id case.

    // The ambiguity resides in a simple-type-specifier/typename-specifier
    // followed by a '('. The '(' could either be the start of:
    //
    //   direct-declarator:
    //     '(' declarator ')'
    //
    //   direct-abstract-declarator:
    //     '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
    //              exception-specification[opt]
    //     '(' abstract-declarator ')'
    //
    // or part of a function-style cast expression:
    //
    //     simple-type-specifier '(' expression-list[opt] ')'
    //

    // simple-type-specifier:

  case tok::annot_typename:
  case_typename:
    // In Objective-C, we might have a protocol-qualified type.
    if (getLangOpts().ObjC1 && NextToken().is(tok::less)) {
      // Tentatively parse the 
      TentativeParsingAction PA(*this);
      ConsumeToken(); // The type token
      
      TPResult TPR = TryParseProtocolQualifiers();
      bool isFollowedByParen = Tok.is(tok::l_paren);
      bool isFollowedByBrace = Tok.is(tok::l_brace);
      
      PA.Revert();
      
      if (TPR == TPResult::Error())
        return TPResult::Error();
      
      if (isFollowedByParen)
        return TPResult::Ambiguous();

      if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
        return BracedCastResult;
      
      return TPResult::True();
    }
      
  case tok::kw_char:
  case tok::kw_wchar_t:
  case tok::kw_char16_t:
  case tok::kw_char32_t:
  case tok::kw_bool:
  case tok::kw_short:
  case tok::kw_int:
  case tok::kw_long:
  case tok::kw___int64:
  case tok::kw___int128:
  case tok::kw_signed:
  case tok::kw_unsigned:
  case tok::kw_half:
  case tok::kw_float:
  case tok::kw_double:
  case tok::kw_void:
  case tok::annot_decltype:
    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 (getLangOpts().CPlusPlus0x && NextToken().is(tok::l_brace))
      return BracedCastResult;

    if (isStartOfObjCClassMessageMissingOpenBracket())
      return TPResult::False();
      
    return TPResult::True();

  // GNU typeof support.
  case tok::kw_typeof: {
    if (NextToken().isNot(tok::l_paren))
      return TPResult::True();

    TentativeParsingAction PA(*this);

    TPResult TPR = TryParseTypeofSpecifier();
    bool isFollowedByParen = Tok.is(tok::l_paren);
    bool isFollowedByBrace = Tok.is(tok::l_brace);

    PA.Revert();

    if (TPR == TPResult::Error())
      return TPResult::Error();

    if (isFollowedByParen)
      return TPResult::Ambiguous();

    if (getLangOpts().CPlusPlus0x && isFollowedByBrace)
      return BracedCastResult;

    return TPResult::True();
  }

  // C++0x type traits support
  case tok::kw___underlying_type:
    return TPResult::True();

  // C11 _Atomic
  case tok::kw__Atomic:
    return TPResult::True();

  default:
    return TPResult::False();
  }
}
bool Sema::ActOnCXXNestedNameSpecifier(Scope *S,
                                       SourceLocation TemplateLoc, 
                                       CXXScopeSpec &SS, 
                                       TemplateTy Template,
                                       SourceLocation TemplateNameLoc,
                                       SourceLocation LAngleLoc,
                                       ASTTemplateArgsPtr TemplateArgsIn,
                                       SourceLocation RAngleLoc,
                                       SourceLocation CCLoc,
                                       bool EnteringContext) {
  if (SS.isInvalid())
    return true;
  
  // Translate the parser's template argument list in our AST format.
  TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
  translateTemplateArguments(TemplateArgsIn, TemplateArgs);

  if (DependentTemplateName *DTN = Template.get().getAsDependentTemplateName()){
    // Handle a dependent template specialization for which we cannot resolve
    // the template name.
    assert(DTN->getQualifier()
             == static_cast<NestedNameSpecifier*>(SS.getScopeRep()));
    QualType T = Context.getDependentTemplateSpecializationType(ETK_None,
                                                          DTN->getQualifier(),
                                                          DTN->getIdentifier(),
                                                                TemplateArgs);
    
    // Create source-location information for this type.
    TypeLocBuilder Builder;
    DependentTemplateSpecializationTypeLoc SpecTL 
      = Builder.push<DependentTemplateSpecializationTypeLoc>(T);
    SpecTL.setLAngleLoc(LAngleLoc);
    SpecTL.setRAngleLoc(RAngleLoc);
    SpecTL.setKeywordLoc(SourceLocation());
    SpecTL.setNameLoc(TemplateNameLoc);
    SpecTL.setQualifierLoc(SS.getWithLocInContext(Context));
    for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
      SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());
    
    SS.Extend(Context, TemplateLoc, Builder.getTypeLocInContext(Context, T), 
              CCLoc);
    return false;
  }
  
  
  if (Template.get().getAsOverloadedTemplate() ||
      isa<FunctionTemplateDecl>(Template.get().getAsTemplateDecl())) {
    SourceRange R(TemplateNameLoc, RAngleLoc);
    if (SS.getRange().isValid())
      R.setBegin(SS.getRange().getBegin());
      
    Diag(CCLoc, diag::err_non_type_template_in_nested_name_specifier)
      << Template.get() << R;
    NoteAllFoundTemplates(Template.get());
    return true;
  }
                                
  // We were able to resolve the template name to an actual template. 
  // Build an appropriate nested-name-specifier.
  QualType T = CheckTemplateIdType(Template.get(), TemplateNameLoc, 
                                   TemplateArgs);
  if (T.isNull())
    return true;

  // Alias template specializations can produce types which are not valid
  // nested name specifiers.
  if (!T->isDependentType() && !T->getAs<TagType>()) {
    Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T;
    NoteAllFoundTemplates(Template.get());
    return true;
  }

  // Provide source-location information for the template specialization 
  // type.
  TypeLocBuilder Builder;
  TemplateSpecializationTypeLoc SpecTL 
    = Builder.push<TemplateSpecializationTypeLoc>(T);
  
  SpecTL.setLAngleLoc(LAngleLoc);
  SpecTL.setRAngleLoc(RAngleLoc);
  SpecTL.setTemplateNameLoc(TemplateNameLoc);
  for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
    SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo());


  SS.Extend(Context, TemplateLoc, Builder.getTypeLocInContext(Context, T), 
            CCLoc);
  return false;
}
Exemplo n.º 11
0
bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) {
  if (!SS.isSet() || SS.isInvalid())
    return false;

  return SS.getScopeRep()->isDependent();
}
Exemplo n.º 12
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.
/// It will mainly be called when we expect to treat identifiers as typenames
/// (if they are typenames). For example, in C we do not expect identifiers
/// inside expressions to be treated as typenames so it will not be called
/// for expressions in C.
/// The benefit for C/ObjC is that a typename will be annotated and
/// Actions.getTypeName will not be needed to be called again (e.g. getTypeName
/// will not be called twice, once to check whether we have a declaration
/// specifier, and another one to get the actual type inside
/// ParseDeclarationSpecifiers).
///
/// This returns true if the token was annotated or an unrecoverable error
/// occurs.
/// 
/// Note that this routine emits an error if you call it with ::new or ::delete
/// as the current tokens, so only call it in contexts where these are invalid.
bool Parser::TryAnnotateTypeOrScopeToken() {
  assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) 
          || Tok.is(tok::kw_typename)) &&
         "Cannot be a type or scope token!");
  
  if (Tok.is(tok::kw_typename)) {
    // Parse a C++ typename-specifier, e.g., "typename T::type".
    //
    //   typename-specifier:
    //     'typename' '::' [opt] nested-name-specifier identifier
    //     'typename' '::' [opt] nested-name-specifier template [opt] 
    //            simple-template-id
    SourceLocation TypenameLoc = ConsumeToken();
    CXXScopeSpec SS;
    bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS);
    if (!HadNestedNameSpecifier) {
      Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename);
      return false;
    }

    TypeResult Ty;
    if (Tok.is(tok::identifier)) {
      // FIXME: check whether the next token is '<', first!
      Ty = Actions.ActOnTypenameType(TypenameLoc, SS, *Tok.getIdentifierInfo(), 
                                     Tok.getLocation());
    } else if (Tok.is(tok::annot_template_id)) {
      TemplateIdAnnotation *TemplateId 
        = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
      if (TemplateId->Kind == TNK_Function_template) {
        Diag(Tok, diag::err_typename_refers_to_non_type_template)
          << Tok.getAnnotationRange();
        return false;
      }

      AnnotateTemplateIdTokenAsType(0);
      assert(Tok.is(tok::annot_typename) && 
             "AnnotateTemplateIdTokenAsType isn't working properly");
      if (Tok.getAnnotationValue())
        Ty = Actions.ActOnTypenameType(TypenameLoc, SS, SourceLocation(),
                                       Tok.getAnnotationValue());
      else
        Ty = true;
    } else {
      Diag(Tok, diag::err_expected_type_name_after_typename)
        << SS.getRange();
      return false;
    }

    Tok.setKind(tok::annot_typename);
    Tok.setAnnotationValue(Ty.isInvalid()? 0 : Ty.get());
    Tok.setAnnotationEndLoc(Tok.getLocation());
    Tok.setLocation(TypenameLoc);
    PP.AnnotateCachedTokens(Tok);
    return true;
  }

  CXXScopeSpec SS;
  if (getLang().CPlusPlus)
    ParseOptionalCXXScopeSpecifier(SS);

  if (Tok.is(tok::identifier)) {
    // Determine whether the identifier is a type name.
    if (TypeTy *Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), 
                                         Tok.getLocation(), CurScope, &SS)) {
      // This is a typename. Replace the current token in-place with an
      // annotation type token.
      Tok.setKind(tok::annot_typename);
      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 true;
    } 

    if (!getLang().CPlusPlus) {
      // If we're in C, we can't have :: tokens at all (the lexer won't return
      // them).  If the identifier is not a type, then it can't be scope either,
      // just early exit. 
      return false;
    }
    
    // If this is a template-id, annotate with a template-id or type token.
    if (NextToken().is(tok::less)) {
      TemplateTy Template;
      if (TemplateNameKind TNK 
            = Actions.isTemplateName(*Tok.getIdentifierInfo(),
                                     CurScope, Template, &SS))
        if (AnnotateTemplateIdToken(Template, TNK, &SS)) {
          // If an unrecoverable error occurred, we need to return true here,
          // because the token stream is in a damaged state.  We may not return
          // a valid identifier.
          return Tok.isNot(tok::identifier);
        }
    }

    // The current token, which is either an identifier or a
    // template-id, is not part of the annotation. Fall through to
    // push that token back into the stream and complete the C++ scope
    // specifier annotation.
  } 

  if (Tok.is(tok::annot_template_id)) {
    TemplateIdAnnotation *TemplateId 
      = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
    if (TemplateId->Kind == TNK_Type_template) {
      // A template-id that refers to a type was parsed into a
      // template-id annotation in a context where we weren't allowed
      // to produce a type annotation token. Update the template-id
      // annotation token to a type annotation token now.
      AnnotateTemplateIdTokenAsType(&SS);
      return true;
    }
  }

  if (SS.isEmpty())
    return Tok.isNot(tok::identifier) && Tok.isNot(tok::coloncolon);
  
  // A C++ scope specifier that isn't followed by a typename.
  // Push the current token back into the token stream (or revert it if it is
  // cached) and use an annotation scope token for current token.
  if (PP.isBacktrackEnabled())
    PP.RevertCachedTokens(1);
  else
    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);
  return true;
}