<div dir="ltr">This broke the self-host on llvm/lib/Option/ArgList.cpp, so I reverted it in r212965.</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Jul 14, 2014 at 9:42 AM, Serge Pavlov <span dir="ltr"><<a href="mailto:sepavloff@gmail.com" target="_blank">sepavloff@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: sepavloff<br>
Date: Mon Jul 14 11:42:20 2014<br>
New Revision: 212957<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=212957&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=212957&view=rev</a><br>
Log:<br>
Improve error recovery around colon.<br>
<br>
Recognize additional cases, when '::' is mistyped as ':'.<br>
This is a fix to RP18587 - colons have too much protection in member-declarations.<br>
<br>
Differential Revision: <a href="http://reviews.llvm.org/D3653" target="_blank">http://reviews.llvm.org/D3653</a><br>
<br>
Modified:<br>
    cfe/trunk/lib/Parse/ParseDecl.cpp<br>
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
    cfe/trunk/test/SemaCXX/enum-bitfield.cpp<br>
    cfe/trunk/test/SemaCXX/nested-name-spec.cpp<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=212957&r1=212956&r2=212957&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=212957&r1=212956&r2=212957&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jul 14 11:42:20 2014<br>
@@ -2715,24 +2715,23 @@ void Parser::ParseDeclarationSpecifiers(<br>
       // typedef-name<br>
     case tok::kw_decltype:<br>
     case tok::identifier: {<br>
+      // This identifier can only be a typedef name if we haven't already seen<br>
+      // a type-specifier.  Without this check we misparse:<br>
+      //  typedef int X; struct Y { short X; };  as 'short int'.<br>
+      if (DS.hasTypeSpecifier())<br>
+        goto DoneWithDeclSpec;<br>
+<br>
       // In C++, check to see if this is a scope specifier like foo::bar::, if<br>
       // so handle it as such.  This is important for ctor parsing.<br>
       if (getLangOpts().CPlusPlus) {<br>
         if (TryAnnotateCXXScopeToken(EnteringContext)) {<br>
-          if (!DS.hasTypeSpecifier())<br>
-            DS.SetTypeSpecError();<br>
+          DS.SetTypeSpecError();<br>
           goto DoneWithDeclSpec;<br>
         }<br>
         if (!Tok.is(tok::identifier))<br>
           continue;<br>
       }<br>
<br>
-      // This identifier can only be a typedef name if we haven't already seen<br>
-      // a type-specifier.  Without this check we misparse:<br>
-      //  typedef int X; struct Y { short X; };  as 'short int'.<br>
-      if (DS.hasTypeSpecifier())<br>
-        goto DoneWithDeclSpec;<br>
-<br>
       // Check for need to substitute AltiVec keyword tokens.<br>
       if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))<br>
         break;<br>
@@ -4529,7 +4528,9 @@ void Parser::ParseDeclaratorInternal(Dec<br>
   // Member pointers get special handling, since there's no place for the<br>
   // scope spec in the generic path below.<br>
   if (getLangOpts().CPlusPlus &&<br>
-      (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||<br>
+      (Tok.is(tok::coloncolon) ||<br>
+       (Tok.is(tok::identifier) &&<br>
+        (NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) ||<br>
        Tok.is(tok::annot_cxxscope))) {<br>
     bool EnteringContext = D.getContext() == Declarator::FileContext ||<br>
                            D.getContext() == Declarator::MemberContext;<br>
@@ -4722,6 +4723,11 @@ void Parser::ParseDirectDeclarator(Decla<br>
   DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec());<br>
<br>
   if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) {<br>
+    // Don't parse FOO:BAR as if it were a typo for FOO::BAR inside a class, in<br>
+    // this context it is a bitfield.<br>
+    ColonProtectionRAIIObject X(*this,<br>
+                                D.getContext() == Declarator::MemberContext);<br>
+<br>
     // ParseDeclaratorInternal might already have parsed the scope.<br>
     if (D.getCXXScopeSpec().isEmpty()) {<br>
       bool EnteringContext = D.getContext() == Declarator::FileContext ||<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=212957&r1=212956&r2=212957&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=212957&r1=212956&r2=212957&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Jul 14 11:42:20 2014<br>
@@ -1239,7 +1239,8 @@ void Parser::ParseClassSpecifier(tok::To<br>
   // Parse the (optional) nested-name-specifier.<br>
   CXXScopeSpec &SS = DS.getTypeSpecScope();<br>
   if (getLangOpts().CPlusPlus) {<br>
-    // "FOO : BAR" is not a potential typo for "FOO::BAR".<br>
+    // "FOO : BAR" is not a potential typo for "FOO::BAR".  In this context it<br>
+    // is a base-specifier-list.<br>
     ColonProtectionRAIIObject X(*this);<br>
<br>
     if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))<br>
@@ -1926,14 +1927,8 @@ void Parser::ParseCXXMemberDeclaratorBef<br>
   //   declarator pure-specifier[opt]<br>
   //   declarator brace-or-equal-initializer[opt]<br>
   //   identifier[opt] ':' constant-expression<br>
-  if (Tok.isNot(tok::colon)) {<br>
-    // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it<br>
-    // is a bitfield.<br>
-    // FIXME: This should only apply when parsing the id-expression (see<br>
-    // PR18587).<br>
-    ColonProtectionRAIIObject X(*this);<br>
+  if (Tok.isNot(tok::colon))<br>
     ParseDeclarator(DeclaratorInfo);<br>
-  }<br>
<br>
   if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) {<br>
     BitfieldSize = ParseConstantExpression();<br>
@@ -2015,6 +2010,14 @@ void Parser::ParseCXXClassMemberDeclarat<br>
     return;<br>
   }<br>
<br>
+  // Turn on colon protection early, while parsing declspec, although there is<br>
+  // nothing to protect there. It prevents from false errors if error recovery<br>
+  // incorrectly determines where the declspec ends, as in the example:<br>
+  //   struct A { enum class B { C }; };<br>
+  //   const int C = 4;<br>
+  //   struct D { A::B : C; };<br>
+  ColonProtectionRAIIObject X(*this);<br>
+<br>
   // Access declarations.<br>
   bool MalformedTypeSpec = false;<br>
   if (!TemplateInfo.Kind &&<br>
@@ -2128,13 +2131,11 @@ void Parser::ParseCXXClassMemberDeclarat<br>
   if (MalformedTypeSpec)<br>
     DS.SetTypeSpecError();<br>
<br>
-  {<br>
-    // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it<br>
-    // is a bitfield.<br>
-    ColonProtectionRAIIObject X(*this);<br>
-    ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,<br>
-                               &CommonLateParsedAttrs);<br>
-  }<br>
+  ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,<br>
+                             &CommonLateParsedAttrs);<br>
+<br>
+  // Turn off colon protection that was set for declspec.<br>
+  X.restore();<br>
<br>
   // If we had a free-standing type definition with a missing semicolon, we<br>
   // may get this far before the problem becomes obvious.<br>
<br>
Modified: cfe/trunk/test/SemaCXX/enum-bitfield.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/enum-bitfield.cpp?rev=212957&r1=212956&r2=212957&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/enum-bitfield.cpp?rev=212957&r1=212956&r2=212957&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/SemaCXX/enum-bitfield.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/enum-bitfield.cpp Mon Jul 14 11:42:20 2014<br>
@@ -16,3 +16,15 @@ struct Y {<br>
   enum E : int(2);<br>
   enum E : Z(); // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'Z'}}<br>
 };<br>
+<br>
+namespace pr18587 {<br>
+struct A {<br>
+  enum class B {<br>
+    C<br>
+  };<br>
+};<br>
+const int C = 4;<br>
+struct D {<br>
+  A::B : C;<br>
+};<br>
+}<br>
<br>
Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=212957&r1=212956&r2=212957&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=212957&r1=212956&r2=212957&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Mon Jul 14 11:42:20 2014<br>
@@ -311,3 +311,102 @@ namespace N {<br>
<br>
 namespace TypedefNamespace { typedef int F; };<br>
 TypedefNamespace::F::NonexistentName BadNNSWithCXXScopeSpec; // expected-error {{'F' (aka 'int') is not a class, namespace, or scoped enumeration}}<br>
+<br>
+namespace PR18587 {<br>
+<br>
+struct C1 {<br>
+  int a, b, c;<br>
+  typedef int C2;<br>
+  struct B1 {<br>
+    struct B2 {<br>
+      int a, b, c;<br>
+    };<br>
+  };<br>
+};<br>
+struct C2 { static const unsigned N1 = 1; };<br>
+struct B1 {<br>
+  enum E1 { B2 = 2 };<br>
+  static const int B3 = 3;<br>
+};<br>
+const int N1 = 2;<br>
+<br>
+// Function declarators<br>
+struct S1a { int f(C1::C2); };<br>
+struct S1b { int f(C1:C2); };  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+<br>
+struct S2a {<br>
+  C1::C2 f(C1::C2);<br>
+};<br>
+struct S2c {<br>
+  C1::C2 f(C1:C2);  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+};<br>
+<br>
+struct S3a {<br>
+  int f(C1::C2), C2 : N1;<br>
+  int g : B1::B2;<br>
+};<br>
+struct S3b {<br>
+  int g : B1:B2;  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+};<br>
+<br>
+// Inside square brackets<br>
+struct S4a {<br>
+  int f[C2::N1];<br>
+};<br>
+struct S4b {<br>
+  int f[C2:N1];  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+};<br>
+<br>
+struct S5a {<br>
+  int f(int xx[B1::B3 ? C2::N1 : B1::B2]);<br>
+};<br>
+struct S5b {<br>
+  int f(int xx[B1::B3 ? C2::N1 : B1:B2]);  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+};<br>
+struct S5c {<br>
+  int f(int xx[B1:B3 ? C2::N1 : B1::B2]);  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+};<br>
+<br>
+// Bit fields<br>
+struct S6a {<br>
+  C1::C2 m1 : B1::B2;<br>
+};<br>
+struct S6c {<br>
+  C1::C2 m1 : B1:B2;  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+};<br>
+struct S6d {<br>
+  int C2:N1;<br>
+};<br>
+struct S6e {<br>
+  static const int N = 3;<br>
+  B1::E1 : N;<br>
+};<br>
+struct S6g {<br>
+  C1::C2 : B1:B2;  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+  B1::E1 : B1:B2;  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+};<br>
+<br>
+// Template parameters<br>
+template <int N> struct T1 {<br>
+  int a,b,c;<br>
+  static const unsigned N1 = N;<br>
+  typedef unsigned C1;<br>
+};<br>
+T1<C2::N1> var_1a;<br>
+T1<C2:N1> var_1b;  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+template<int N> int F() {}<br>
+int (*X1)() = (B1::B2 ? F<1> : F<2>);<br>
+int (*X2)() = (B1:B2 ? F<1> : F<2>);  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+<br>
+// Bit fields + templates<br>
+struct S7a {<br>
+  T1<B1::B2>::C1 m1 : T1<B1::B2>::N1;<br>
+};<br>
+struct S7b {<br>
+  T1<B1:B2>::C1 m1 : T1<B1::B2>::N1;  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+};<br>
+struct S7c {<br>
+  T1<B1::B2>::C1 m1 : T1<B1:B2>::N1;  // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}<br>
+};<br>
+<br>
+}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>