From: Douglas Gregor Date: Wed, 25 Feb 2009 23:02:36 +0000 (+0000) Subject: Cope with use of the token '>>' inside a template argument list, e.g., X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3965b7be250de002d8744331631b9901941666a0;p=clang Cope with use of the token '>>' inside a template argument list, e.g., vector> Matrix; In C++98/03, this token always means "right shift". However, if we're in a context where we know that it can't mean "right shift", provide a friendly reminder to put a space between the two >'s and then treat it as two >'s as part of recovery. In C++0x, this token is always broken into two '>' tokens. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65484 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticParseKinds.def b/include/clang/Basic/DiagnosticParseKinds.def index e8485c69bf..03868cda49 100644 --- a/include/clang/Basic/DiagnosticParseKinds.def +++ b/include/clang/Basic/DiagnosticParseKinds.def @@ -278,6 +278,8 @@ DIAG(err_id_after_template_in_nested_name_spec, ERROR, "expected template name after 'template' keyword in nested name specifier") DIAG(err_less_after_template_name_in_nested_name_spec, ERROR, "expected '<' after 'template %0' in nested name specifier") +DIAG(err_two_right_angle_brackets_need_space, ERROR, + "a space is required between consecutive right angle brackets (use '> >')") // Language specific pragmas diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index b6c2a71e08..d0808a5f97 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -56,16 +56,29 @@ namespace prec { /// token. This returns: /// static prec::Level getBinOpPrecedence(tok::TokenKind Kind, - bool GreaterThanIsOperator) { + bool GreaterThanIsOperator, + bool CPlusPlus0x) { switch (Kind) { case tok::greater: - // The '>' token can act as either an operator or as the ending - // token for a template argument list. - // FIXME: '>>' is similar, for error recovery and C++0x. + // C++ [temp.names]p3: + // [...] When parsing a template-argument-list, the first + // non-nested > is taken as the ending delimiter rather than a + // greater-than operator. [...] if (GreaterThanIsOperator) return prec::Relational; return prec::Unknown; + case tok::greatergreater: + // C++0x [temp.names]p3: + // + // [...] Similarly, the first non-nested >> is treated as two + // consecutive but distinct > tokens, the first of which is + // taken as the end of the template-argument-list and completes + // the template-id. [...] + if (GreaterThanIsOperator || !CPlusPlus0x) + return prec::Shift; + return prec::Unknown; + default: return prec::Unknown; case tok::comma: return prec::Comma; case tok::equal: @@ -90,8 +103,7 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, case tok::lessequal: case tok::less: case tok::greaterequal: return prec::Relational; - case tok::lessless: - case tok::greatergreater: return prec::Shift; + case tok::lessless: return prec::Shift; case tok::plus: case tok::minus: return prec::Additive; case tok::percent: @@ -274,7 +286,9 @@ Parser::OwningExprResult Parser::ParseConstantExpression() { /// LHS and has a precedence of at least MinPrec. Parser::OwningExprResult Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { - unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator); + unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(), + GreaterThanIsOperator, + getLang().CPlusPlus0x); SourceLocation ColonLoc; while (1) { @@ -324,7 +338,8 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { // Remember the precedence of this operator and get the precedence of the // operator immediately to the right of the RHS. unsigned ThisPrec = NextTokPrec; - NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator); + NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, + getLang().CPlusPlus0x); // Assignment and conditional expressions are right-associative. bool isRightAssoc = ThisPrec == prec::Conditional || @@ -343,7 +358,8 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { if (RHS.isInvalid()) return move(RHS); - NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator); + NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, + getLang().CPlusPlus0x); } assert(NextTokPrec <= ThisPrec && "Recursion didn't work!"); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 64fc8fdf47..65705e8d32 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -431,14 +431,24 @@ Parser::ParseTemplateIdAfterTemplateName(DeclTy *Template, } } - if (Tok.isNot(tok::greater)) + if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) return true; - // Determine the location of the '>'. Only consume this token if the - // caller asked us to. + // Determine the location of the '>' or '>>'. Only consume this + // token if the caller asked us to. RAngleLoc = Tok.getLocation(); - if (ConsumeLastToken) + if (Tok.is(tok::greatergreater)) { + if (!getLang().CPlusPlus0x) + Diag(Tok.getLocation(), diag::err_two_right_angle_brackets_need_space); + + Tok.setKind(tok::greater); + if (!ConsumeLastToken) { + // Since we're not supposed to consume the '>>' token, we need + // to insert a second '>' token after the first. + PP.EnterToken(Tok); + } + } else if (ConsumeLastToken) ConsumeToken(); return false; @@ -670,6 +680,6 @@ Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs, ConsumeToken(); } - return Tok.isNot(tok::greater); + return Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater); } diff --git a/test/SemaTemplate/right-angle-brackets-0x.cpp b/test/SemaTemplate/right-angle-brackets-0x.cpp new file mode 100644 index 0000000000..e11dfe9f75 --- /dev/null +++ b/test/SemaTemplate/right-angle-brackets-0x.cpp @@ -0,0 +1,22 @@ +// RUN: clang -fsyntax-only -std=c++0x -verify %s +template struct X; +template struct Y; + +X> *x1; + +Y<(1 >> 2)> *y1; +Y<1 >> 2> *y2; // FIXME: expected-error{{expected unqualified-id}} + +X>>>> *x2; + +template<> struct X { }; +typedef X X_int; +struct Z : X_int { }; + +void f(const X x) { + (void)reinterpret_cast>(x); // expected-error{{reinterpret_cast from}} + (void)reinterpret_cast>>>(x); // expected-error{{reinterpret_cast from}} + + X> *x1; +} + diff --git a/test/SemaTemplate/right-angle-brackets-98.cpp b/test/SemaTemplate/right-angle-brackets-98.cpp new file mode 100644 index 0000000000..709e8b05e5 --- /dev/null +++ b/test/SemaTemplate/right-angle-brackets-98.cpp @@ -0,0 +1,13 @@ +// RUN: clang -fsyntax-only -std=c++98 -verify %s +template struct X; +template struct Y; + +X > *x1; +X> *x2; // expected-error{{a space is required between consecutive right angle brackets (use '> >')}} + +X> // expected-error{{a space is required between consecutive right angle brackets (use '> >')}} + >> *x3; // expected-error{{a space is required between consecutive right angle brackets (use '> >')}} + +Y<(1 >> 2)> *y1; +Y<1 >> 2> *y2; +// FIXME: when we get a -Wc++0x mode, warn about the use above