forked from OSchip/llvm-project
Cope with use of the token '>>' inside a template argument list, e.g.,
vector<vector<double>> 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. llvm-svn: 65484
This commit is contained in:
parent
16f3d8dcfb
commit
cbb45d0c65
|
@ -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
|
||||
|
||||
|
|
|
@ -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!");
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// RUN: clang -fsyntax-only -std=c++0x -verify %s
|
||||
template<typename T> struct X;
|
||||
template<int I> struct Y;
|
||||
|
||||
X<X<int>> *x1;
|
||||
|
||||
Y<(1 >> 2)> *y1;
|
||||
Y<1 >> 2> *y2; // FIXME: expected-error{{expected unqualified-id}}
|
||||
|
||||
X<X<X<X<X<int>>>>> *x2;
|
||||
|
||||
template<> struct X<int> { };
|
||||
typedef X<int> X_int;
|
||||
struct Z : X_int { };
|
||||
|
||||
void f(const X<int> x) {
|
||||
(void)reinterpret_cast<X<int>>(x); // expected-error{{reinterpret_cast from}}
|
||||
(void)reinterpret_cast<X<X<X<int>>>>(x); // expected-error{{reinterpret_cast from}}
|
||||
|
||||
X<X<int>> *x1;
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// RUN: clang -fsyntax-only -std=c++98 -verify %s
|
||||
template<typename T> struct X;
|
||||
template<int I> struct Y;
|
||||
|
||||
X<X<int> > *x1;
|
||||
X<X<int>> *x2; // expected-error{{a space is required between consecutive right angle brackets (use '> >')}}
|
||||
|
||||
X<X<X<X<int>> // 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
|
Loading…
Reference in New Issue