From a7bc7c880f86bc180684ef032d06df51bcae7a23 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 4 Jan 2009 23:23:14 +0000 Subject: [PATCH] my previous patch caused sema to drop the global qualifier, make sure to pass it down. This makes the code a bit gross, I will clean it up in subsequent commits. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61650 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 10 ++++++++-- lib/Parse/ParseExpr.cpp | 35 ++++++++++++++++++----------------- lib/Parse/ParseExprCXX.cpp | 34 +++++++++++++++++++++++----------- lib/Parse/Parser.cpp | 13 ++++++++----- 4 files changed, 57 insertions(+), 35 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index cccd971073..8d57cd60ce 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -267,7 +267,9 @@ private: /// (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. - void TryAnnotateTypeOrScopeToken(); + /// + /// This returns true if the token was annotated. + bool TryAnnotateTypeOrScopeToken(const Token *GlobalQualifier = 0); /// TryAnnotateCXXScopeToken - Like TryAnnotateTypeOrScopeToken but only /// annotates C++ scope specifiers. @@ -607,7 +609,11 @@ private: /// MaybeParseCXXScopeSpecifier - Parse global scope or nested-name-specifier. /// Returns true if a nested-name-specifier was parsed from the token stream. - bool MaybeParseCXXScopeSpecifier(CXXScopeSpec &SS); + /// + /// If GlobalQualifier is non-null, then it is a :: token we should use as the + /// global qualifier. + bool MaybeParseCXXScopeSpecifier(CXXScopeSpec &SS, + const Token *GlobalQualifier = 0); //===--------------------------------------------------------------------===// // C++ 5.2p1: C++ Casts diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index c1f6946529..c5ed745d82 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -478,12 +478,14 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression) { // constant: enumeration-constant // Turn a potentially qualified name into a annot_qualtypename or // annot_cxxscope if it would be valid. This handles things like x::y, etc. - TryAnnotateTypeOrScopeToken(); + if (getLang().CPlusPlus) { + TryAnnotateTypeOrScopeToken(); - // If TryAnnotateTypeOrScopeToken modified the current token, then tail - // recurse. - if (Tok.getKind() != tok::identifier) - return ParseCastExpression(isUnaryExpression); + // If TryAnnotateTypeOrScopeToken modified the current token, then tail + // recurse. + if (Tok.getKind() != tok::identifier) + return ParseCastExpression(isUnaryExpression); + } // 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 @@ -630,23 +632,22 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression) { // ::new -> [C++] new-expression // ::delete -> [C++] delete-expression // ::foo::bar -> global qualified name etc. - SourceLocation ScopeLoc = ConsumeToken(); + Token ColonColonTok = Tok; + ConsumeToken(); if (Tok.is(tok::kw_new)) - return ParseCXXNewExpression(true, ScopeLoc); + return ParseCXXNewExpression(true, ColonColonTok.getLocation()); if (Tok.is(tok::kw_delete)) - return ParseCXXDeleteExpression(true, ScopeLoc); + return ParseCXXDeleteExpression(true, ColonColonTok.getLocation()); // Turn the qualified name into a annot_qualtypename or annot_cxxscope if // it would be valid. - TryAnnotateTypeOrScopeToken(); - - // If we still have a :: as our current token, then this is not a type - // name or scope specifier. - if (Tok.getKind() == tok::coloncolon) { - Diag(Tok, diag::err_expected_expression); - return ExprError(); + if (TryAnnotateTypeOrScopeToken(&ColonColonTok)) { + // If so, retry (tail recurse). + return ParseCastExpression(isUnaryExpression); } - // Otherwise, retry (tail recurse). - return ParseCastExpression(isUnaryExpression); + + // This is not a type name or scope specifier, it is an invalid expression. + Diag(ColonColonTok, diag::err_expected_expression); + return ExprError(); } case tok::kw_new: // [C++] new-expression diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 75e4e1fe7c..195b52e988 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -29,37 +29,49 @@ using namespace clang; /// nested-name-specifier identifier '::' /// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] /// -bool Parser::MaybeParseCXXScopeSpecifier(CXXScopeSpec &SS) { +bool Parser::MaybeParseCXXScopeSpecifier(CXXScopeSpec &SS, + const Token *GlobalQualifier) { assert(getLang().CPlusPlus && "Call sites of this function should be guarded by checking for C++."); if (Tok.is(tok::annot_cxxscope)) { + assert(GlobalQualifier == 0 && + "Cannot have :: followed by a resolve annotation scope"); SS.setScopeRep(Tok.getAnnotationValue()); SS.setRange(Tok.getAnnotationRange()); ConsumeToken(); return true; } - if (Tok.isNot(tok::coloncolon) && + if (GlobalQualifier == 0 && + Tok.isNot(tok::coloncolon) && (Tok.isNot(tok::identifier) || NextToken().isNot(tok::coloncolon))) return false; // ::new and ::delete aren't nested-name-specifiers, so parsing the :: as // a scope specifier only makes things more complicated. - if (Tok.is(tok::coloncolon)) { + if (GlobalQualifier == 0 && Tok.is(tok::coloncolon)) { Token Next = NextToken(); if (Next.is(tok::kw_new) || Next.is(tok::kw_delete)) return false; } - SS.setBeginLoc(Tok.getLocation()); - - // '::' - if (Tok.is(tok::coloncolon)) { - // Global scope. - SourceLocation CCLoc = ConsumeToken(); - SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc)); - SS.setEndLoc(CCLoc); + if (GlobalQualifier) { + // Pre-parsed '::'. + SS.setBeginLoc(GlobalQualifier->getLocation()); + SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, + GlobalQualifier->getLocation())); + SS.setEndLoc(GlobalQualifier->getLocation()); + } else { + 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: diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 381c84e317..29843b1668 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -741,14 +741,16 @@ Parser::OwningExprResult Parser::ParseSimpleAsm() { /// will not be called twice, once to check whether we have a declaration /// specifier, and another one to get the actual type inside /// ParseDeclarationSpecifiers). -void Parser::TryAnnotateTypeOrScopeToken() { +/// +/// This returns true if the token was annotated. +bool Parser::TryAnnotateTypeOrScopeToken(const Token *GlobalQualifier) { // FIXME: what about template-ids? if (Tok.is(tok::annot_qualtypename) || Tok.is(tok::annot_cxxscope)) - return; + return false; CXXScopeSpec SS; if (getLang().CPlusPlus) - MaybeParseCXXScopeSpecifier(SS); + MaybeParseCXXScopeSpecifier(SS, GlobalQualifier); if (Tok.is(tok::identifier)) { DeclTy *Template = 0; @@ -772,7 +774,7 @@ void Parser::TryAnnotateTypeOrScopeToken() { // In case the tokens were cached, have Preprocessor replace // them with the annotation token. PP.AnnotateCachedTokens(Tok); - return; + return true; } } @@ -785,7 +787,7 @@ void Parser::TryAnnotateTypeOrScopeToken() { // names a type. if (SS.isEmpty()) - return; + return false; // 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 @@ -801,6 +803,7 @@ void Parser::TryAnnotateTypeOrScopeToken() { // In case the tokens were cached, have Preprocessor replace them with the // annotation token. PP.AnnotateCachedTokens(Tok); + return true; } /// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only -- 2.40.0