diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-29 01:16:42 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-03-29 01:16:42 +0000 |
commit | 9988f28fe7a6c19239a7426fea1ab23f9a8aac9c (patch) | |
tree | 32bd3325d1d69326b1e893d571b931c47da7d2ed | |
parent | 0fd4a6869e9a12999af24b8df7a0275a0e6c18be (diff) |
Reject 'template<typename...Ts> void f(Ts ...(x));'. Add a special-case
diagnostic and a fix-it to explain to the user where the ellipsis is
supposed to go.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153622 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 3 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 63 | ||||
-rw-r--r-- | test/FixIt/fixit-cxx0x.cpp | 23 |
3 files changed, 78 insertions, 11 deletions
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index c585f87c73..35acec5544 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -428,6 +428,9 @@ def err_default_arg_unparsed : Error< "unexpected end of default argument expression">; def err_parser_impl_limit_overflow : Error< "parser recursion limit reached, program too complex">, DefaultFatal; +def err_misplaced_ellipsis_in_declaration : Error< + "'...' must %select{immediately precede declared identifier|" + "be innermost component of anonymous pack declaration}0">; // C++ derived classes def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 9aa5eaba00..03f41a0980 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -3540,6 +3540,17 @@ void Parser::ParseDeclarator(Declarator &D) { ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); } +static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang) { + if (Kind == tok::star || Kind == tok::caret) + return true; + + // We parse rvalue refs in C++03, because otherwise the errors are scary. + if (!Lang.CPlusPlus) + return false; + + return Kind == tok::amp || Kind == tok::ampamp; +} + /// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator /// is parsed by the function passed to it. Pass null, and the direct-declarator /// isn't parsed at all, making this function effectively parse the C++ @@ -3611,10 +3622,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, tok::TokenKind Kind = Tok.getKind(); // Not a pointer, C++ reference, or block. - if (Kind != tok::star && Kind != tok::caret && - (Kind != tok::amp || !getLangOpts().CPlusPlus) && - // We parse rvalue refs in C++03, because otherwise the errors are scary. - (Kind != tok::ampamp || !getLangOpts().CPlusPlus)) { + if (!isPtrOperatorToken(Kind, getLangOpts())) { if (DirectDeclParser) (this->*DirectDeclParser)(D); return; @@ -3706,6 +3714,19 @@ 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 @@ -3767,13 +3788,26 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // abstract-declarator if the type of the parameter names a template // parameter pack that has not been expanded; otherwise, it is parsed // as part of the parameter-declaration-clause. - if (Tok.is(tok::ellipsis) && + if (Tok.is(tok::ellipsis) && D.getCXXScopeSpec().isEmpty() && !((D.getContext() == Declarator::PrototypeContext || D.getContext() == Declarator::BlockLiteralContext) && NextToken().is(tok::r_paren) && - !Actions.containsUnexpandedParameterPacks(D))) - D.setEllipsisLoc(ConsumeToken()); - + !Actions.containsUnexpandedParameterPacks(D))) { + SourceLocation EllipsisLoc = ConsumeToken(); + if (isPtrOperatorToken(Tok.getKind(), getLangOpts())) { + // 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); + return; + } else + D.setEllipsisLoc(EllipsisLoc); + + // The ellipsis can't be followed by a parenthesized declarator. We + // check for that in ParseParenDeclarator, after we have disambiguated + // the l_paren token. + } + if (Tok.is(tok::identifier) || Tok.is(tok::kw_operator) || Tok.is(tok::annot_template_id) || Tok.is(tok::tilde)) { // We found something that indicates the start of an unqualified-id. @@ -3818,7 +3852,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { ConsumeToken(); goto PastIdentifier; } - + if (Tok.is(tok::l_paren)) { // direct-declarator: '(' declarator ')' // direct-declarator: '(' attributes declarator ')' @@ -3830,7 +3864,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // the scope already. Re-enter the scope, if we need to. if (D.getCXXScopeSpec().isSet()) { // If there was an error parsing parenthesized declarator, declarator - // scope may have been enterred before. Don't do it again. + // scope may have been entered before. Don't do it again. if (!D.isInvalidType() && Actions.ShouldEnterDeclaratorScope(getCurScope(), D.getCXXScopeSpec())) // Change the declaration context for name lookup, until this function @@ -3965,9 +3999,11 @@ void Parser::ParseParenDeclarator(Declarator &D) { // direct-declarator: '(' declarator ')' // direct-declarator: '(' attributes declarator ')' if (isGrouping) { + SourceLocation EllipsisLoc = D.getEllipsisLoc(); + D.setEllipsisLoc(SourceLocation()); + bool hadGroupingParens = D.hasGroupingParens(); D.setGroupingParens(true); - ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); // Match the ')'. T.consumeClose(); @@ -3976,6 +4012,11 @@ void Parser::ParseParenDeclarator(Declarator &D) { attrs, T.getCloseLocation()); D.setGroupingParens(hadGroupingParens); + + // An ellipsis cannot be placed outside parentheses. + if (EllipsisLoc.isValid()) + diagnoseMisplacedEllipsis(*this, D, EllipsisLoc); + return; } diff --git a/test/FixIt/fixit-cxx0x.cpp b/test/FixIt/fixit-cxx0x.cpp index dcd9f74a10..dfc5c8c561 100644 --- a/test/FixIt/fixit-cxx0x.cpp +++ b/test/FixIt/fixit-cxx0x.cpp @@ -77,3 +77,26 @@ void f() { 'c'_z; 'd'_whoops; } + +template<typename ...Ts> struct MisplacedEllipsis { + int a(Ts ...(x)); // expected-error {{'...' must immediately precede declared identifier}} + int b(Ts ...&x); // expected-error {{'...' must immediately precede declared identifier}} + int c(Ts ...&); // expected-error {{'...' must be innermost component of anonymous pack declaration}} + int d(Ts ...(...&...)); // expected-error 2{{'...' must be innermost component of anonymous pack declaration}} + int e(Ts ...*[]); // expected-error {{'...' must be innermost component of anonymous pack declaration}} + int f(Ts ...(...*)()); // expected-error 2{{'...' must be innermost component of anonymous pack declaration}} + int g(Ts ...()); // ok +}; +namespace TestMisplacedEllipsisRecovery { + MisplacedEllipsis<int, char> me; + int i; char k; + int *ip; char *kp; + int ifn(); char kfn(); + int a = me.a(i, k); + int b = me.b(i, k); + int c = me.c(i, k); + int d = me.d(i, k); + int e = me.e(&ip, &kp); + int f = me.f(ifn, kfn); + int g = me.g(ifn, kfn); +} |