aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-02-25 23:02:36 +0000
committerDouglas Gregor <dgregor@apple.com>2009-02-25 23:02:36 +0000
commit3965b7be250de002d8744331631b9901941666a0 (patch)
treebb44455ae531d916159cbd3bc5f40d513cdaa589
parentce87b929703cac0b3f236b0b0d1c7b78d8af38f2 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65484 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.def2
-rw-r--r--lib/Parse/ParseExpr.cpp34
-rw-r--r--lib/Parse/ParseTemplate.cpp20
-rw-r--r--test/SemaTemplate/right-angle-brackets-0x.cpp22
-rw-r--r--test/SemaTemplate/right-angle-brackets-98.cpp13
5 files changed, 77 insertions, 14 deletions
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<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;
+}
+
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<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