Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -2134,7 +2134,8 @@ TPResult TryParsePtrOperatorSeq(); TPResult TryParseOperatorId(); TPResult TryParseInitDeclaratorList(); - TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true); + TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier = true, + bool mayHaveTrailingStrayEllipsis = true); TPResult TryParseParameterDeclarationClause(bool *InvalidAsDeclaration = nullptr, bool VersusTemplateArg = false); Index: lib/Parse/ParseTentative.cpp =================================================================== --- lib/Parse/ParseTentative.cpp +++ lib/Parse/ParseTentative.cpp @@ -481,10 +481,10 @@ /// the corresponding ')'. If the context is /// TypeIdAsTemplateArgument, we've already parsed the '<' or ',' /// before this template argument, and will cease lookahead when we - /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id - /// and false for an expression. If during the disambiguation - /// process a parsing error is encountered, the function returns - /// true to let the declaration parsing code handle it. + /// hit a '>', '>>' (in C++0x), or ','; or, in C++0x, an ellipsis immediately + /// preceding such. Returns true for a type-id and false for an expression. + /// If during the disambiguation process a parsing error is encountered, + /// the function returns true to let the declaration parsing code handle it. /// /// type-id: /// type-specifier-seq abstract-declarator[opt] @@ -533,10 +533,15 @@ // We are supposed to be inside a template argument, so if after // the abstract declarator we encounter a '>', '>>' (in C++0x), or - // ',', this is a type-id. Otherwise, it's an expression. + // ','; or, in C++0x, an ellipsis immediately preceding such, this + // is a type-id. Otherwise, it's an expression. } else if (Context == TypeIdAsTemplateArgument && (Tok.isOneOf(tok::greater, tok::comma) || - (getLangOpts().CPlusPlus11 && Tok.is(tok::greatergreater)))) { + (getLangOpts().CPlusPlus11 && + (Tok.is(tok::greatergreater) || + (Tok.is(tok::ellipsis) && + NextToken().isOneOf(tok::greater, tok::greatergreater, + tok::comma)))))) { TPR = TPResult::True; isAmbiguous = true; @@ -829,14 +834,14 @@ /// abstract-declarator: /// ptr-operator abstract-declarator[opt] /// direct-abstract-declarator -/// ... /// /// direct-abstract-declarator: /// direct-abstract-declarator[opt] -/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] +/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt] /// exception-specification[opt] /// direct-abstract-declarator[opt] '[' constant-expression[opt] ']' /// '(' abstract-declarator ')' +/// [C++0x] ... /// /// ptr-operator: /// '*' cv-qualifier-seq[opt] @@ -868,7 +873,8 @@ /// template-id [TODO] /// Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, - bool mayHaveIdentifier) { + bool mayHaveIdentifier, + bool mayHaveTrailingStrayEllipsis) { // declarator: // direct-declarator // ptr-operator declarator @@ -914,7 +920,11 @@ tok::kw___stdcall, tok::kw___fastcall, tok::kw___thiscall, tok::kw___regcall, tok::kw___vectorcall)) return TPResult::True; // attributes indicate declaration - TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier); + + // Disallow trailing stray ellipses since they can parse successfully in + // an initializer-list. + TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier, + /*mayHaveTrailingStrayEllipsis*/ false); if (TPR != TPResult::Ambiguous) return TPR; if (Tok.isNot(tok::r_paren)) @@ -928,8 +938,10 @@ while (1) { TPResult TPR(TPResult::Ambiguous); - // abstract-declarator: ... - if (Tok.is(tok::ellipsis)) + // Allow stray ellipses as attempts to declare parameter packs. + if (Tok.is(tok::ellipsis) && + (mayHaveTrailingStrayEllipsis || + !(NextToken().is(tok::r_paren) || NextToken().is(tok::comma)))) ConsumeToken(); if (Tok.is(tok::l_paren)) { @@ -1790,7 +1802,11 @@ // declarator // abstract-declarator[opt] - TPR = TryParseDeclarator(true/*mayBeAbstract*/); + + // Disallow trailing stray ellipses since they can parse successfully in an + // initializer-list. + TPR = TryParseDeclarator(/*mayBeAbstract*/ true, /*mayHaveIdentifier*/ true, + /*mayHaveTrailingStrayEllipsis*/ false); if (TPR != TPResult::Ambiguous) return TPR; Index: test/Parser/cxx0x-ambig.cpp =================================================================== --- test/Parser/cxx0x-ambig.cpp +++ test/Parser/cxx0x-ambig.cpp @@ -132,6 +132,32 @@ void l(int(*...)(T)); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}} void l(int(S::*...)(T)); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}} }; + + struct CtorSink { + template constexpr CtorSink(T &&...t) { } + constexpr operator int() const { return 42; } + }; + + template struct UnsignedTmplArgSink; + + template + void foo(int x, T ...t) { + // Have a variety of cases where the syntax is technically unambiguous, but hinges on careful treatment of ellipses. + CtorSink(t ...), x; // ok, expression; expected-warning 2{{expression result unused}} + + int x0(CtorSink(t ...)); // ok, declares object x0 + int *p0 = &x0; + (void)p0; + + CtorSink x1(int(t) ..., int(x)); // ok, declares object x1 + CtorSink *p1 = &x1; + (void)p1; + + UnsignedTmplArgSink *t0; // ok + UnsignedTmplArgSink<((T *)0, 42u) ...> **t0p = &t0; + } + + template void foo(int, int, int); // expected-note {{in instantiation of function template specialization 'ellipsis::foo' requested here}} } namespace braced_init_list {