diff options
Diffstat (limited to 'lib/Parse/ParseTemplate.cpp')
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 135 |
1 files changed, 108 insertions, 27 deletions
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 5c3e2ba..ade918f 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -90,7 +90,8 @@ Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context, // Tell the action that names should be checked in the context of // the declaration to come. - ParsingDeclRAIIObject ParsingTemplateParams(*this); + ParsingDeclRAIIObject + ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); // Parse multiple levels of template headers within this template // parameter scope, e.g., @@ -213,11 +214,15 @@ Parser::ParseSingleDeclarationAfterTemplate( return ParseUsingDirectiveOrDeclaration(Context, TemplateInfo, DeclEnd, prefixAttrs); - // Parse the declaration specifiers, stealing the accumulated - // diagnostics from the template parameters. + // Parse the declaration specifiers, stealing any diagnostics from + // the template parameters. ParsingDeclSpec DS(*this, &DiagsFromTParams); - DS.takeAttributesFrom(prefixAttrs); + // Move the attributes from the prefix into the DS. + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + ProhibitAttributes(prefixAttrs); + else + DS.takeAttributesFrom(prefixAttrs); ParseDeclarationSpecifiers(DS, TemplateInfo, AS, getDeclSpecContextFromDeclaratorContext(Context)); @@ -259,7 +264,7 @@ Parser::ParseSingleDeclarationAfterTemplate( } // Eat the semi colon after the declaration. - ExpectAndConsume(tok::semi, diag::err_expected_semi_declaration); + ExpectAndConsumeSemi(diag::err_expected_semi_declaration); if (LateParsedAttrs.size() > 0) ParseLexedAttributeList(LateParsedAttrs, ThisDecl, true, false); DeclaratorInfo.complete(ThisDecl); @@ -314,6 +319,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)); @@ -711,34 +721,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; - } - // Determine the location of the '>' or '>>'. Only consume this - // token if the caller asked us to. - RAngleLoc = Tok.getLocation(); + 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; - if (Tok.is(tok::greatergreater)) { - const char *ReplaceStr = "> >"; - if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater)) - ReplaceStr = "> > "; + case tok::greatergreater: + RemainingToken = tok::greater; + break; - 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); + case tok::greatergreatergreater: + RemainingToken = tok::greatergreater; + break; - 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) + case tok::greaterequal: + RemainingToken = tok::equal; + ReplacementStr = "> ="; + break; + + case tok::greatergreaterequal: + RemainingToken = tok::greaterequal; + break; + } + + // 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(); + + // The source range of the '>>' or '>=' at the start of the token. + CharSourceRange ReplacementRange = + CharSourceRange::getCharRange(RAngleLoc, + Lexer::AdvanceToTokenCharacter(RAngleLoc, 2, PP.getSourceManager(), + getLangOpts())); + + // 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); + + // 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; } @@ -1132,7 +1212,8 @@ Decl *Parser::ParseExplicitInstantiation(unsigned Context, SourceLocation &DeclEnd, AccessSpecifier AS) { // This isn't really required here. - ParsingDeclRAIIObject ParsingTemplateParams(*this); + ParsingDeclRAIIObject + ParsingTemplateParams(*this, ParsingDeclRAIIObject::NoParent); return ParseSingleDeclarationAfterTemplate(Context, ParsedTemplateInfo(ExternLoc, |