From 98440b4ac17dc5f85ea3db683c1c1785449c17e1 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 21 Nov 2009 02:07:55 +0000 Subject: [PATCH] Implement C++ [temp.param]p2 correctly, looking ahead when we see a "typename" parameter to distinguish between non-type and type template parameters. Fixes the actual bug in PR5559. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89532 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 1 + lib/Parse/ParseTemplate.cpp | 40 ++++++++++++++++++++++++++++----- test/CXX/temp/temp.param/p2.cpp | 3 ++- 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index f7ccccac09..814064a79e 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1353,6 +1353,7 @@ private: SourceLocation &RAngleLoc); bool ParseTemplateParameterList(unsigned Depth, TemplateParameterList &TemplateParams); + bool isStartOfTemplateTypeParameter(); DeclPtrTy ParseTemplateParameter(unsigned Depth, unsigned Position); DeclPtrTy ParseTypeParameter(unsigned Depth, unsigned Position); DeclPtrTy ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 5be4ca82f7..e655dedab4 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -333,6 +333,40 @@ Parser::ParseTemplateParameterList(unsigned Depth, return true; } +/// \brief Determine whether the parser is at the start of a template +/// type parameter. +bool Parser::isStartOfTemplateTypeParameter() { + if (Tok.is(tok::kw_class)) + return true; + + if (Tok.isNot(tok::kw_typename)) + return false; + + // C++ [temp.param]p2: + // There is no semantic difference between class and typename in a + // template-parameter. typename followed by an unqualified-id + // names a template type parameter. typename followed by a + // qualified-id denotes the type in a non-type + // parameter-declaration. + Token Next = NextToken(); + + // If we have an identifier, skip over it. + if (Next.getKind() == tok::identifier) + Next = GetLookAheadToken(2); + + switch (Next.getKind()) { + case tok::equal: + case tok::comma: + case tok::greater: + case tok::greatergreater: + case tok::ellipsis: + return true; + + default: + return false; + } +} + /// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]). /// /// template-parameter: [C++ temp.param] @@ -348,12 +382,8 @@ Parser::ParseTemplateParameterList(unsigned Depth, /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression Parser::DeclPtrTy Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { - if (Tok.is(tok::kw_class) || - (Tok.is(tok::kw_typename) && - // FIXME: Next token has not been annotated! - NextToken().isNot(tok::annot_typename))) { + if (isStartOfTemplateTypeParameter()) return ParseTypeParameter(Depth, Position); - } if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); diff --git a/test/CXX/temp/temp.param/p2.cpp b/test/CXX/temp/temp.param/p2.cpp index a402cf6f88..d40f99b58a 100644 --- a/test/CXX/temp/temp.param/p2.cpp +++ b/test/CXX/temp/temp.param/p2.cpp @@ -8,7 +8,8 @@ template struct X; // typename followed by aqualified-id denotes the type in a non-type // parameter-declaration. -// FIXME: template struct Y; +template struct Y0; +template::type Value> struct Y1; // A storage class shall not be specified in a template-parameter declaration. template struct Z; // FIXME: expect an error -- 2.40.0