hubert.reinterpretcast created this revision. The trial parse for declarative syntax accepts an invalid pack declaration syntax, which is ambiguous with valid pack expansions of expressions. This commit restricts the invalid pack declaration syntax to avoid mistaking valid pack expansions as invalid declarator components.
Additionally, have the trial parse of a //template-argument-list// handle the optional ellipsis that is part of that grammar, as opposed to relying on the trial parse for declarators accepting stray ellipses. https://reviews.llvm.org/D33339 Files: include/clang/Parse/Parser.h lib/Parse/ParseTentative.cpp test/Parser/cxx0x-ambig.cpp
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<int>::*...)(T)); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}} }; + + struct CtorSink { + template <typename ...T> constexpr CtorSink(T &&...t) { } + constexpr operator int() const { return 42; } + }; + + template <unsigned ...N> struct UnsignedTmplArgSink; + + template <typename ...T> + 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<T(CtorSink(t ...)) ...> *t0; // ok + UnsignedTmplArgSink<((T *)0, 42u) ...> **t0p = &t0; + } + + template void foo(int, int, int); // expected-note {{in instantiation of function template specialization 'ellipsis::foo<int, int>' requested here}} } namespace braced_init_list { 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: 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);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits