r229288 - Don't crash on `struct ::, struct ::` (and the same for enums).

Nico Weber nicolasweber at gmx.de
Sat Feb 14 23:26:13 PST 2015


Author: nico
Date: Sun Feb 15 01:26:13 2015
New Revision: 229288

URL: http://llvm.org/viewvc/llvm-project?rev=229288&view=rev
Log:
Don't crash on `struct ::, struct ::` (and the same for enums).

The first part of that line doesn't parse correctly and ParseClassSpecifier() for
some reason skips to tok::comma to recover, and then
ParseDeclarationSpecifiers() sees the next struct and calls
ParseClassSpecifier() again with the same DeclSpec object.

However, the first call already called ActOnCXXGlobalScopeSpecifier() on the
DeclSpec's CXXScopeSpec, and sema gets confused when this gets called again.

As a fix, let ParseClassSpecifier() (and ParseEnumSpecifier()) call
ParseOptionalCXXScopeSpec() with a temporary CXXScopeSpec object, and only
copy it into the DeclSpec if things work out.  (This is also how all the other
functions that set the DeclSpec's TypeSpecScope set it.)

Found by SLi's bot.

Modified:
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/test/Parser/recovery.cpp

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=229288&r1=229287&r2=229288&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Sun Feb 15 01:26:13 2015
@@ -3648,11 +3648,12 @@ void Parser::ParseEnumSpecifier(SourceLo
     // if a fixed underlying type is allowed.
     ColonProtectionRAIIObject X(*this, AllowFixedUnderlyingType);
 
-    if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
+    CXXScopeSpec Spec;
+    if (ParseOptionalCXXScopeSpecifier(Spec, ParsedType(),
                                        /*EnteringContext=*/true))
       return;
 
-    if (SS.isSet() && Tok.isNot(tok::identifier)) {
+    if (Spec.isSet() && Tok.isNot(tok::identifier)) {
       Diag(Tok, diag::err_expected) << tok::identifier;
       if (Tok.isNot(tok::l_brace)) {
         // Has no name and is not a definition.
@@ -3661,6 +3662,8 @@ void Parser::ParseEnumSpecifier(SourceLo
         return;
       }
     }
+
+    SS = Spec;
   }
 
   // Must have either 'enum name' or 'enum {...}'.

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=229288&r1=229287&r2=229288&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Sun Feb 15 01:26:13 2015
@@ -1310,11 +1310,19 @@ void Parser::ParseClassSpecifier(tok::To
     // is a base-specifier-list.
     ColonProtectionRAIIObject X(*this);
 
-    if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
+    CXXScopeSpec Spec;
+    bool HasValidSpec = true;
+    if (ParseOptionalCXXScopeSpecifier(Spec, ParsedType(), EnteringContext)) {
       DS.SetTypeSpecError();
-    if (SS.isSet())
-      if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id))
+      HasValidSpec = false;
+    }
+    if (Spec.isSet())
+      if (Tok.isNot(tok::identifier) && Tok.isNot(tok::annot_template_id)) {
         Diag(Tok, diag::err_expected) << tok::identifier;
+        HasValidSpec = false;
+      }
+    if (HasValidSpec)
+      SS = Spec;
   }
 
   TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams;

Modified: cfe/trunk/test/Parser/recovery.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/recovery.cpp?rev=229288&r1=229287&r2=229288&view=diff
==============================================================================
--- cfe/trunk/test/Parser/recovery.cpp (original)
+++ cfe/trunk/test/Parser/recovery.cpp Sun Feb 15 01:26:13 2015
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -verify -std=c++11 %s
+// RUN: %clang_cc1 -verify -std=c++11 -fms-extensions %s
 
 8gi///===--- recovery.cpp ---===// // expected-error {{unqualified-id}}
 namespace Std { // expected-note {{here}}
@@ -202,3 +202,11 @@ namespace pr15133 {
   struct S2 :: S3 :: public S2 {  // expected-error{{'public' cannot be a part of nested name specifier; did you mean ':'?}}
   };
 }
+
+namespace InvalidEmptyNames {
+// These shouldn't crash, the diagnostics aren't important.
+struct ::, struct ::; // expected-error 2 {{expected identifier}} expected-error 2 {{declaration of anonymous struct must be a definition}} expected-warning {{declaration does not declare anything}}
+enum ::, enum ::; // expected-error 2 {{expected identifier}} expected-warning {{declaration does not declare anything}}
+struct ::__super, struct ::__super; // expected-error 2 {{expected identifier}} expected-error 2 {{expected '::' after '__super'}}
+struct ::template foo, struct ::template bar; // expected-error 2 {{expected identifier}} expected-error 2 {{declaration of anonymous struct must be a definition}} expected-warning {{declaration does not declare anything}}
+}





More information about the cfe-commits mailing list