From 69fdc9ff89813e679b578e3953131515ddfcac32 Mon Sep 17 00:00:00 2001 From: Nikola Smiljanic Date: Fri, 6 Jun 2014 02:58:59 +0000 Subject: [PATCH] PR11306 - Variadic template fix-it suggestion. Recover from misplaced or redundant ellipsis in parameter pack. llvm-svn: 210304 --- clang/include/clang/Parse/Parser.h | 6 ++++++ clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Parse/ParseDecl.cpp | 18 +++------------- clang/lib/Parse/ParseTemplate.cpp | 43 +++++++++++++++++++++++++++++++++++--- clang/lib/Sema/SemaTemplate.cpp | 7 ++++--- clang/test/FixIt/fixit-cxx0x.cpp | 20 ++++++++++++++++++ 6 files changed, 74 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 83fa1a5..c2aa1e6 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2371,6 +2371,12 @@ private: Decl *ParseTypeParameter(unsigned Depth, unsigned Position); Decl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); Decl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); + void DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc, + SourceLocation CorrectLoc, + bool AlreadyHasEllipsis, + bool IdentifierHasName); + void DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc, + Declarator &D); // C++ 14.3: Template arguments [temp.arg] typedef SmallVector TemplateArgList; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 2b69fc7..1702c78 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -5174,7 +5174,7 @@ public: void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl); - Decl *ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, + Decl *ActOnTypeParameter(Scope *S, bool Typename, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 53851929..65ec44c5 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -4661,19 +4661,6 @@ void Parser::ParseDeclaratorInternal(Declarator &D, } } -static void diagnoseMisplacedEllipsis(Parser &P, Declarator &D, - SourceLocation EllipsisLoc) { - if (EllipsisLoc.isValid()) { - FixItHint Insertion; - if (!D.getEllipsisLoc().isValid()) { - Insertion = FixItHint::CreateInsertion(D.getIdentifierLoc(), "..."); - D.setEllipsisLoc(EllipsisLoc); - } - P.Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration) - << FixItHint::CreateRemoval(EllipsisLoc) << Insertion << !D.hasName(); - } -} - /// ParseDirectDeclarator /// direct-declarator: [C99 6.7.5] /// [C99] identifier @@ -4753,7 +4740,8 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // The ellipsis was put in the wrong place. Recover, and explain to // the user what they should have done. ParseDeclarator(D); - diagnoseMisplacedEllipsis(*this, D, EllipsisLoc); + if (EllipsisLoc.isValid()) + DiagnoseMisplacedEllipsisInDeclarator(EllipsisLoc, D); return; } else D.setEllipsisLoc(EllipsisLoc); @@ -5004,7 +4992,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { // An ellipsis cannot be placed outside parentheses. if (EllipsisLoc.isValid()) - diagnoseMisplacedEllipsis(*this, D, EllipsisLoc); + DiagnoseMisplacedEllipsisInDeclarator(EllipsisLoc, D); return; } diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index a4a7abc..4d0ec8f 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -498,6 +498,11 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { return nullptr; } + // Recover from misplaced ellipsis. + bool AlreadyHasEllipsis = EllipsisLoc.isValid(); + if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) + DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true); + // Grab a default argument (if available). // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before // we introduce the type parameter into the local scope. @@ -507,9 +512,9 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { DefaultArg = ParseTypeName(/*Range=*/nullptr, Declarator::TemplateTypeArgContext).get(); - return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, Ellipsis, - EllipsisLoc, KeyLoc, ParamName, NameLoc, - Depth, Position, EqualLoc, DefaultArg); + return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, EllipsisLoc, + KeyLoc, ParamName, NameLoc, Depth, Position, + EqualLoc, DefaultArg); } /// ParseTemplateTemplateParameter - Handle the parsing of template @@ -579,6 +584,11 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { return nullptr; } + // Recover from misplaced ellipsis. + bool AlreadyHasEllipsis = EllipsisLoc.isValid(); + if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) + DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true); + TemplateParameterList *ParamList = Actions.ActOnTemplateParameterList(Depth, SourceLocation(), TemplateLoc, LAngleLoc, @@ -629,6 +639,11 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { return nullptr; } + // Recover from misplaced ellipsis. + SourceLocation EllipsisLoc; + if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) + DiagnoseMisplacedEllipsisInDeclarator(EllipsisLoc, ParamDecl); + // If there is a default value, parse it. // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before // we introduce the template parameter into the local scope. @@ -654,6 +669,28 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { DefaultArg.get()); } +void Parser::DiagnoseMisplacedEllipsis(SourceLocation EllipsisLoc, + SourceLocation CorrectLoc, + bool AlreadyHasEllipsis, + bool IdentifierHasName) { + FixItHint Insertion; + if (!AlreadyHasEllipsis) + Insertion = FixItHint::CreateInsertion(CorrectLoc, "..."); + Diag(EllipsisLoc, diag::err_misplaced_ellipsis_in_declaration) + << FixItHint::CreateRemoval(EllipsisLoc) << Insertion + << !IdentifierHasName; +} + +void Parser::DiagnoseMisplacedEllipsisInDeclarator(SourceLocation EllipsisLoc, + Declarator &D) { + assert(EllipsisLoc.isValid()); + bool AlreadyHasEllipsis = D.getEllipsisLoc().isValid(); + if (!AlreadyHasEllipsis) + D.setEllipsisLoc(EllipsisLoc); + DiagnoseMisplacedEllipsis(EllipsisLoc, D.getIdentifierLoc(), + AlreadyHasEllipsis, D.hasName()); +} + /// \brief Parses a '>' at the end of a template list. /// /// If this function encounters '>>', '>>>', '>=', or '>>=', it tries diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 92197e4..d893c88 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -544,7 +544,7 @@ static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S, /// ParamNameLoc is the location of the parameter name (if any). /// If the type parameter has a default argument, it will be added /// later via ActOnTypeParameterDefault. -Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, +Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, @@ -560,10 +560,11 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, if (!ParamName) Loc = KeyLoc; + bool IsParameterPack = EllipsisLoc.isValid(); TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), KeyLoc, Loc, Depth, Position, ParamName, - Typename, Ellipsis); + Typename, IsParameterPack); Param->setAccess(AS_public); if (Invalid) Param->setInvalidDecl(); @@ -579,7 +580,7 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, // C++0x [temp.param]p9: // A default template-argument may be specified for any kind of // template-parameter that is not a template parameter pack. - if (DefaultArg && Ellipsis) { + if (DefaultArg && IsParameterPack) { Diag(EqualLoc, diag::err_template_param_pack_default_arg); DefaultArg = ParsedType(); } diff --git a/clang/test/FixIt/fixit-cxx0x.cpp b/clang/test/FixIt/fixit-cxx0x.cpp index 5fe7ca4..49a05ff 100644 --- a/clang/test/FixIt/fixit-cxx0x.cpp +++ b/clang/test/FixIt/fixit-cxx0x.cpp @@ -138,3 +138,23 @@ int RegisterVariable() { register int n; // expected-warning {{'register' storage class specifier is deprecated}} return n; } + +namespace MisplacedParameterPack { + template // expected-error {{'...' must immediately precede declared identifier}} + void misplacedEllipsisInTypeParameter(Args...); + + template // expected-error {{'...' must immediately precede declared identifier}} + void redundantEllipsisInTypeParameter(Args...); + + template