r303472 - Fix valid-for-expr ellipses eaten as invalid decl

Hubert Tong via cfe-commits cfe-commits at lists.llvm.org
Fri May 19 17:21:55 PDT 2017


Author: hubert.reinterpretcast
Date: Fri May 19 19:21:55 2017
New Revision: 303472

URL: http://llvm.org/viewvc/llvm-project?rev=303472&view=rev
Log:
Fix valid-for-expr ellipses eaten as invalid decl

Summary:
The trial parse for declarative syntax accepts an invalid pack
declaration syntax, which is ambiguous with valid pack expansions of
expressions. This commit removes the invalid pack declaration syntax to
avoid mistaking valid pack expansions as invalid declarator components.

Additionally, the trial parse of a //template-argument-list// then needs
to handle the optional ellipsis that is part of that grammar, as opposed
to relying on the trial parse for declarators accepting stray ellipses.

Reviewers: rsmith, rcraik, aaron.ballman

Reviewed By: rsmith

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D33339

Modified:
    cfe/trunk/lib/Parse/ParseTentative.cpp
    cfe/trunk/test/Parser/cxx0x-ambig.cpp

Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=303472&r1=303471&r2=303472&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Fri May 19 19:21:55 2017
@@ -481,10 +481,10 @@ Parser::isCXXConditionDeclarationOrInitS
   /// 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 @@ bool Parser::isCXXTypeId(TentativeCXXTyp
 
     // 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 @@ Parser::TPResult Parser::TryParseOperato
 ///         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 @@ Parser::TPResult Parser::TryParseDeclara
   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

Modified: cfe/trunk/test/Parser/cxx0x-ambig.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-ambig.cpp?rev=303472&r1=303471&r2=303472&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx0x-ambig.cpp (original)
+++ cfe/trunk/test/Parser/cxx0x-ambig.cpp Fri May 19 19:21:55 2017
@@ -132,6 +132,32 @@ namespace ellipsis {
     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 {




More information about the cfe-commits mailing list