From aad6cdd1bc865e81c0187a43e56cfe8cb555e7a5 Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Sun, 15 Feb 2015 07:26:13 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@229288 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Parse/ParseDecl.cpp | 7 +++++-- lib/Parse/ParseDeclCXX.cpp | 14 +++++++++++--- test/Parser/recovery.cpp | 10 +++++++++- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 8fcfcb34be..a17fd6dbee 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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 {...}'. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 63baaefc2f..0a88d202b8 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -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; diff --git a/test/Parser/recovery.cpp b/test/Parser/recovery.cpp index e53a361dca..bca9ace89e 100644 --- a/test/Parser/recovery.cpp +++ b/test/Parser/recovery.cpp @@ -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}} +} -- 2.40.0