mirror of
https://github.com/intel/llvm.git
synced 2026-01-23 16:06:39 +08:00
Extend the error recovery for a template-argument-list terminated by '>>' to
also deal with '>>>' (in CUDA), '>=', and '>>='. Fix the FixItHints logic to deal with cases where the token is followed by an adjacent '=', '==', '>=', '>>=', or '>>>' token, where a naive fix-it would result in a differing token stream on a re-lex. llvm-svn: 158652
This commit is contained in:
@@ -498,6 +498,9 @@ def err_id_after_template_in_nested_name_spec : Error<
|
||||
"expected template name after 'template' keyword in nested name specifier">;
|
||||
def err_two_right_angle_brackets_need_space : Error<
|
||||
"a space is required between consecutive right angle brackets (use '> >')">;
|
||||
def err_right_angle_bracket_equal_needs_space : Error<
|
||||
"a space is required between a right angle bracket and an equals sign "
|
||||
"(use '> =')">;
|
||||
def warn_cxx0x_right_shift_in_template_arg : Warning<
|
||||
"use of right-shift operator ('>>') in template argument will require "
|
||||
"parentheses in C++11">, InGroup<CXX11Compat>;
|
||||
|
||||
@@ -1215,6 +1215,8 @@ private:
|
||||
// C++ Expressions
|
||||
ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
|
||||
|
||||
bool areTokensAdjacent(const Token &A, const Token &B);
|
||||
|
||||
void CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectTypePtr,
|
||||
bool EnteringContext, IdentifierInfo &II,
|
||||
CXXScopeSpec &SS);
|
||||
|
||||
@@ -36,7 +36,7 @@ static int SelectDigraphErrorMessage(tok::TokenKind Kind) {
|
||||
}
|
||||
|
||||
// Are the two tokens adjacent in the same source file?
|
||||
static bool AreTokensAdjacent(Preprocessor &PP, Token &First, Token &Second) {
|
||||
bool Parser::areTokensAdjacent(const Token &First, const Token &Second) {
|
||||
SourceManager &SM = PP.getSourceManager();
|
||||
SourceLocation FirstLoc = SM.getSpellingLoc(First.getLocation());
|
||||
SourceLocation FirstEnd = FirstLoc.getLocWithOffset(First.getLength());
|
||||
@@ -80,7 +80,7 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType,
|
||||
return;
|
||||
|
||||
Token SecondToken = GetLookAheadToken(2);
|
||||
if (!SecondToken.is(tok::colon) || !AreTokensAdjacent(PP, Next, SecondToken))
|
||||
if (!SecondToken.is(tok::colon) || !areTokensAdjacent(Next, SecondToken))
|
||||
return;
|
||||
|
||||
TemplateTy Template;
|
||||
@@ -921,7 +921,7 @@ ExprResult Parser::ParseCXXCasts() {
|
||||
// diagnose error, suggest fix, and recover parsing.
|
||||
Token Next = NextToken();
|
||||
if (Tok.is(tok::l_square) && Tok.getLength() == 2 && Next.is(tok::colon) &&
|
||||
AreTokensAdjacent(PP, Tok, Next))
|
||||
areTokensAdjacent(Tok, Next))
|
||||
FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true);
|
||||
|
||||
if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
|
||||
|
||||
@@ -316,6 +316,11 @@ bool Parser::ParseTemplateParameters(unsigned Depth,
|
||||
Failed = ParseTemplateParameterList(Depth, TemplateParams);
|
||||
|
||||
if (Tok.is(tok::greatergreater)) {
|
||||
// No diagnostic required here: a template-parameter-list can only be
|
||||
// followed by a declaration or, for a template template parameter, the
|
||||
// 'class' keyword. Therefore, the second '>' will be diagnosed later.
|
||||
// This matters for elegant diagnosis of:
|
||||
// template<template<typename>> struct S;
|
||||
Tok.setKind(tok::greater);
|
||||
RAngleLoc = Tok.getLocation();
|
||||
Tok.setLocation(Tok.getLocation().getLocWithOffset(1));
|
||||
@@ -713,34 +718,104 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template,
|
||||
}
|
||||
}
|
||||
|
||||
if (Tok.isNot(tok::greater) && Tok.isNot(tok::greatergreater)) {
|
||||
// What will be left once we've consumed the '>'.
|
||||
tok::TokenKind RemainingToken;
|
||||
const char *ReplacementStr = "> >";
|
||||
|
||||
switch (Tok.getKind()) {
|
||||
default:
|
||||
Diag(Tok.getLocation(), diag::err_expected_greater);
|
||||
return true;
|
||||
|
||||
case tok::greater:
|
||||
// Determine the location of the '>' token. Only consume this token
|
||||
// if the caller asked us to.
|
||||
RAngleLoc = Tok.getLocation();
|
||||
if (ConsumeLastToken)
|
||||
ConsumeToken();
|
||||
return false;
|
||||
|
||||
case tok::greatergreater:
|
||||
RemainingToken = tok::greater;
|
||||
break;
|
||||
|
||||
case tok::greatergreatergreater:
|
||||
RemainingToken = tok::greatergreater;
|
||||
break;
|
||||
|
||||
case tok::greaterequal:
|
||||
RemainingToken = tok::equal;
|
||||
ReplacementStr = "> =";
|
||||
break;
|
||||
|
||||
case tok::greatergreaterequal:
|
||||
RemainingToken = tok::greaterequal;
|
||||
break;
|
||||
}
|
||||
|
||||
// Determine the location of the '>' or '>>'. Only consume this
|
||||
// token if the caller asked us to.
|
||||
// This template-id is terminated by a token which starts with a '>'. Outside
|
||||
// C++11, this is now error recovery, and in C++11, this is error recovery if
|
||||
// the token isn't '>>'.
|
||||
|
||||
RAngleLoc = Tok.getLocation();
|
||||
|
||||
if (Tok.is(tok::greatergreater)) {
|
||||
const char *ReplaceStr = "> >";
|
||||
if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater))
|
||||
ReplaceStr = "> > ";
|
||||
// The source range of the '>>' or '>=' at the start of the token.
|
||||
CharSourceRange ReplacementRange =
|
||||
CharSourceRange::getCharRange(RAngleLoc,
|
||||
Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(),
|
||||
getLangOpts()));
|
||||
|
||||
Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ?
|
||||
diag::warn_cxx98_compat_two_right_angle_brackets :
|
||||
diag::err_two_right_angle_brackets_need_space)
|
||||
<< FixItHint::CreateReplacement(SourceRange(Tok.getLocation()),
|
||||
ReplaceStr);
|
||||
// A hint to put a space between the '>>'s. In order to make the hint as
|
||||
// clear as possible, we include the characters either side of the space in
|
||||
// the replacement, rather than just inserting a space at SecondCharLoc.
|
||||
FixItHint Hint1 = FixItHint::CreateReplacement(ReplacementRange,
|
||||
ReplacementStr);
|
||||
|
||||
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)
|
||||
// A hint to put another space after the token, if it would otherwise be
|
||||
// lexed differently.
|
||||
FixItHint Hint2;
|
||||
Token Next = NextToken();
|
||||
if ((RemainingToken == tok::greater ||
|
||||
RemainingToken == tok::greatergreater) &&
|
||||
(Next.is(tok::greater) || Next.is(tok::greatergreater) ||
|
||||
Next.is(tok::greatergreatergreater) || Next.is(tok::equal) ||
|
||||
Next.is(tok::greaterequal) || Next.is(tok::greatergreaterequal) ||
|
||||
Next.is(tok::equalequal)) &&
|
||||
areTokensAdjacent(Tok, Next))
|
||||
Hint2 = FixItHint::CreateInsertion(Next.getLocation(), " ");
|
||||
|
||||
unsigned DiagId = diag::err_two_right_angle_brackets_need_space;
|
||||
if (getLangOpts().CPlusPlus0x && Tok.is(tok::greatergreater))
|
||||
DiagId = diag::warn_cxx98_compat_two_right_angle_brackets;
|
||||
else if (Tok.is(tok::greaterequal))
|
||||
DiagId = diag::err_right_angle_bracket_equal_needs_space;
|
||||
Diag(Tok.getLocation(), DiagId) << Hint1 << Hint2;
|
||||
|
||||
// Strip the initial '>' from the token.
|
||||
if (RemainingToken == tok::equal && Next.is(tok::equal) &&
|
||||
areTokensAdjacent(Tok, Next)) {
|
||||
// Join two adjacent '=' tokens into one, for cases like:
|
||||
// void (*p)() = f<int>;
|
||||
// return f<int>==p;
|
||||
ConsumeToken();
|
||||
Tok.setKind(tok::equalequal);
|
||||
Tok.setLength(Tok.getLength() + 1);
|
||||
} else {
|
||||
Tok.setKind(RemainingToken);
|
||||
Tok.setLength(Tok.getLength() - 1);
|
||||
}
|
||||
Tok.setLocation(Lexer::AdvanceToTokenCharacter(RAngleLoc, 1,
|
||||
PP.getSourceManager(),
|
||||
getLangOpts()));
|
||||
|
||||
if (!ConsumeLastToken) {
|
||||
// Since we're not supposed to consume the '>' token, we need to push
|
||||
// this token and revert the current token back to the '>'.
|
||||
PP.EnterToken(Tok);
|
||||
Tok.setKind(tok::greater);
|
||||
Tok.setLength(1);
|
||||
Tok.setLocation(RAngleLoc);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -260,3 +260,34 @@ bool Foo::isGood() { // expected-error {{out-of-line definition of 'isGood' does
|
||||
}
|
||||
void Foo::beEvil() {} // expected-error {{out-of-line definition of 'beEvil' does not match any declaration in namespace 'redecl_typo::Foo'; did you mean 'BeEvil'?}}
|
||||
}
|
||||
|
||||
// Test behavior when a template-id is ended by a token which starts with '>'.
|
||||
namespace greatergreater {
|
||||
template<typename T> struct S { S(); S(T); };
|
||||
void f(S<int>=0); // expected-error {{a space is required between a right angle bracket and an equals sign (use '> =')}}
|
||||
|
||||
// FIXME: The fix-its here overlap so -fixit mode can't apply the second one.
|
||||
//void f(S<S<int>>=S<int>());
|
||||
|
||||
struct Shr {
|
||||
template<typename T> Shr(T);
|
||||
template<typename T> void operator >>=(T);
|
||||
};
|
||||
|
||||
template<template<typename>> struct TemplateTemplateParam; // expected-error {{requires 'class'}}
|
||||
|
||||
template<typename T> void t();
|
||||
void g() {
|
||||
void (*p)() = &t<int>;
|
||||
(void)(&t<int>==p); // expected-error {{use '> ='}}
|
||||
(void)(&t<int>>=p); // expected-error {{use '> >'}}
|
||||
(void)(&t<S<int>>>=p); // expected-error {{use '> >'}}
|
||||
(Shr)&t<S<int>>>>=p; // expected-error {{use '> >'}}
|
||||
|
||||
// FIXME: We correct this to '&t<int> > >= p;' not '&t<int> >>= p;'
|
||||
//(Shr)&t<int>>>=p;
|
||||
|
||||
// FIXME: The fix-its here overlap.
|
||||
//(void)(&t<S<int>>==p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
template<typename> struct S {};
|
||||
template<typename> void f();
|
||||
|
||||
void foo(void) {
|
||||
foo<<<1; // expected-error {{expected '>>>'}} expected-note {{to match this '<<<'}}
|
||||
|
||||
foo<<<1,1>>>; // expected-error {{expected '('}}
|
||||
|
||||
foo<<<>>>(); // expected-error {{expected expression}}
|
||||
|
||||
S<S<S<int>>> s; // expected-error 2{{use '> >'}}
|
||||
|
||||
(void)(&f<S<S<int>>>==0); // expected-error 2{{use '> >'}}
|
||||
}
|
||||
|
||||
@@ -10,3 +10,18 @@ A<int x; // expected-error {{expected '>'}}
|
||||
// PR8912
|
||||
template <bool> struct S {};
|
||||
S<bool(2 > 1)> s;
|
||||
|
||||
// Test behavior when a template-id is ended by a token which starts with '>'.
|
||||
namespace greatergreater {
|
||||
template<typename T> struct S { S(); S(T); };
|
||||
void f(S<int>=0); // expected-error {{a space is required between a right angle bracket and an equals sign (use '> =')}}
|
||||
void f(S<S<int>>=S<int>()); // expected-error {{use '> >'}} expected-error {{use '> ='}}
|
||||
template<typename T> void t();
|
||||
void g() {
|
||||
void (*p)() = &t<int>;
|
||||
(void)(&t<int>==p); // expected-error {{use '> ='}}
|
||||
(void)(&t<int>>=p); // expected-error {{use '> >'}}
|
||||
(void)(&t<S<int>>>=p); // expected-error {{use '> >'}}
|
||||
(void)(&t<S<int>>==p); // expected-error {{use '> >'}} expected-error {{use '> ='}}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user