From: Richard Trieu Date: Mon, 19 Sep 2011 19:01:00 +0000 (+0000) Subject: Changes to the name lookup have caused a regression in the digraph fix-it hint. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=950be71c745409e373ae8a834490f9026c8ac222;p=clang Changes to the name lookup have caused a regression in the digraph fix-it hint. For instance: template void E() {}; class F {}; void test() { ::E<::F>(); E<::F>(); } Gives the following error messages: error: found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'? ::E<::F>(); ^~~ < :: error: expected expression E<::F>(); ^ error: expected ']' note: to match this '[' E<::F>(); This patch adds the digraph fix-it check right before the name lookup, moves the shared checking code to a new function, and adds new tests to catch future regressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140039 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index d32c36efbd..ee2dbd5519 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1237,6 +1237,10 @@ private: // C++ Expressions ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false); + void CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectTypePtr, + bool EnteringContext, IdentifierInfo &II, + CXXScopeSpec &SS); + bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext, diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 4086da84ab..88abce9c5e 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -70,6 +70,31 @@ static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken, PP.EnterToken(DigraphToken); } +// Check for '<::' which should be '< ::' instead of '[:' when following +// a template name. +void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, + bool EnteringContext, + IdentifierInfo &II, CXXScopeSpec &SS) { + if (!Next.is(tok::l_square) || !Next.getLength() == 2) + return; + + Token SecondToken = GetLookAheadToken(2); + if (!SecondToken.is(tok::colon) || !AreTokensAdjacent(PP, Next, SecondToken)) + return; + + TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&II, Tok.getLocation()); + bool MemberOfUnknownSpecialization; + if (!Actions.isTemplateName(getCurScope(), SS, /*hasTemplateKeyword=*/false, + TemplateName, ObjectType, EnteringContext, + Template, MemberOfUnknownSpecialization)) + return; + + FixDigraph(*this, PP, Next, SecondToken, tok::kw_template, + /*AtDigraph*/false); +} + /// \brief Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which @@ -341,28 +366,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, continue; } - // Check for '<::' which should be '< ::' instead of '[:' when following - // a template name. - if (Next.is(tok::l_square) && Next.getLength() == 2) { - Token SecondToken = GetLookAheadToken(2); - if (SecondToken.is(tok::colon) && - AreTokensAdjacent(PP, Next, SecondToken)) { - TemplateTy Template; - UnqualifiedId TemplateName; - TemplateName.setIdentifier(&II, Tok.getLocation()); - bool MemberOfUnknownSpecialization; - if (Actions.isTemplateName(getCurScope(), SS, - /*hasTemplateKeyword=*/false, - TemplateName, - ObjectType, - EnteringContext, - Template, - MemberOfUnknownSpecialization)) { - FixDigraph(*this, PP, Next, SecondToken, tok::kw_template, - /*AtDigraph*/false); - } - } - } + CheckForTemplateAndDigraph(Next, ObjectType, EnteringContext, II, SS); // nested-name-specifier: // type-name '<' diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index c1ead6bdef..58514b0467 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -114,6 +114,11 @@ Retry: CXXScopeSpec SS; IdentifierInfo *Name = Tok.getIdentifierInfo(); SourceLocation NameLoc = Tok.getLocation(); + + if (getLang().CPlusPlus) + CheckForTemplateAndDigraph(Next, ParsedType(), + /*EnteringContext=*/false, *Name, SS); + Sema::NameClassification Classification = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next); switch (Classification.getKind()) { diff --git a/test/Parser/cxx-casting.cpp b/test/Parser/cxx-casting.cpp index 4a0bb4d1e4..cb82c8efda 100644 --- a/test/Parser/cxx-casting.cpp +++ b/test/Parser/cxx-casting.cpp @@ -67,3 +67,19 @@ void test2(char x, struct B * b) { test1::A LCC B> e; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}} (void)static_cast LCC c>(&x); // expected-error{{found '<::' after a static_cast which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}} } + +template class D {}; +template void E() {}; +class F {}; + +void test3() { + ::D<::F> A1; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}} + D<::F> A2; // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}} + ::E<::F>(); // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}} + E<::F>(); // expected-error{{found '<::' after a template name which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?}} + + ::D< ::F> A3; + D< ::F> A4; + ::E< ::F>(); + E< ::F>(); +}