]> granicus.if.org Git - clang/commitdiff
Don't crash on `struct ::, struct ::` (and the same for enums).
authorNico Weber <nicolasweber@gmx.de>
Sun, 15 Feb 2015 07:26:13 +0000 (07:26 +0000)
committerNico Weber <nicolasweber@gmx.de>
Sun, 15 Feb 2015 07:26:13 +0000 (07:26 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@229288 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
test/Parser/recovery.cpp

index 8fcfcb34be2a569a1005f4619faa4f11c669e0f8..a17fd6dbee898fcac0e673ff94886073bb856a65 100644 (file)
@@ -3648,11 +3648,12 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
     // 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(SourceLocation StartLoc, DeclSpec &DS,
         return;
       }
     }
+
+    SS = Spec;
   }
 
   // Must have either 'enum name' or 'enum {...}'.
index 63baaefc2fc5634690c16c0c42675749e625c316..0a88d202b8beb9579f35edbe3c78933b0d8009ce 100644 (file)
@@ -1310,11 +1310,19 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
     // 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;
index e53a361dca801ab55d83567837d8fd090e98a956..bca9ace89e21fcb1dbb312eeb237e856c7abdc7c 100644 (file)
@@ -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}}
+}