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] @@ -928,10 +933,6 @@ while (1) { TPResult TPR(TPResult::Ambiguous); - // abstract-declarator: ... - if (Tok.is(tok::ellipsis)) - ConsumeToken(); - if (Tok.is(tok::l_paren)) { // Check whether we have a function declarator or a possible ctor-style // initializer that follows the declarator. Note that ctor-style 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 {