From c8e27cc402043ec86c1698c09e4ee9e415b16207 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Fri, 26 Jun 2009 04:27:47 +0000 Subject: [PATCH] fix PR4452, a crash on invalid. The error recovery is still terrible in this case but at least we don't crash :) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74264 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 2 +- lib/Parse/ParseExprCXX.cpp | 10 +++++++--- lib/Parse/ParseTemplate.cpp | 27 +++++++++++++++++++++------ lib/Parse/Parser.cpp | 13 ++++++++++--- test/SemaCXX/nested-name-spec.cpp | 24 ++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 13 deletions(-) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 7a1c90a259..e5f62ec683 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1193,7 +1193,7 @@ private: TemplateArgLocationList &TemplateArgLocations, SourceLocation &RAngleLoc); - void AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, + bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, const CXXScopeSpec *SS, SourceLocation TemplateKWLoc = SourceLocation(), bool AllowTypeAnnotation = true); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 68964e91ee..d89f1e172f 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -85,8 +85,10 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { = Actions.ActOnDependentTemplateName(TemplateKWLoc, *Tok.getIdentifierInfo(), Tok.getLocation(), SS); - AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, - &SS, TemplateKWLoc, false); + if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name, + &SS, TemplateKWLoc, false)) + break; + continue; } @@ -179,7 +181,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { // because some clients (e.g., the parsing of class template // specializations) still want to see the original template-id // token. - AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), false); + if (AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(), + false)) + break; continue; } } diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index ab359f4c5e..57a09fbc73 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -621,7 +621,11 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, /// replaced with a type annotation token. Otherwise, the /// simple-template-id is always replaced with a template-id /// annotation token. -void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, +/// +/// If an unrecoverable parse error occurs and no annotation token can be +/// formed, this function returns true. +/// +bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, const CXXScopeSpec *SS, SourceLocation TemplateKWLoc, bool AllowTypeAnnotation) { @@ -644,14 +648,19 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateArgIsType, TemplateArgLocations, RAngleLoc); + + if (Invalid) { + // If we failed to parse the template ID but skipped ahead to a >, we're not + // going to be able to form a token annotation. Eat the '>' if present. + if (Tok.is(tok::greater)) + ConsumeToken(); + return true; + } ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), TemplateArgIsType.data(), TemplateArgs.size()); - if (Invalid) // FIXME: How to recover from a broken template-id? - return; - // Build the annotation token. if (TNK == TNK_Type_template && AllowTypeAnnotation) { Action::TypeResult Type @@ -659,8 +668,13 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, LAngleLoc, TemplateArgsPtr, &TemplateArgLocations[0], RAngleLoc); - if (Type.isInvalid()) // FIXME: better recovery? - return; + if (Type.isInvalid()) { + // If we failed to parse the template ID but skipped ahead to a >, we're not + // going to be able to form a token annotation. Eat the '>' if present. + if (Tok.is(tok::greater)) + ConsumeToken(); + return true; + } Tok.setKind(tok::annot_typename); Tok.setAnnotationValue(Type.get()); @@ -705,6 +719,7 @@ void Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // In case the tokens were cached, have Preprocessor replace them with the // annotation token. PP.AnnotateCachedTokens(Tok); + return false; } /// \brief Replaces a template-id annotation token with a type diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 1804844322..f582448ee9 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -839,7 +839,8 @@ Parser::OwningExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { /// specifier, and another one to get the actual type inside /// ParseDeclarationSpecifiers). /// -/// This returns true if the token was annotated. +/// This returns true if the token was annotated or an unrecoverable error +/// occurs. /// /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. @@ -934,7 +935,12 @@ bool Parser::TryAnnotateTypeOrScopeToken() { if (TemplateNameKind TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope, Template, &SS)) - AnnotateTemplateIdToken(Template, TNK, &SS); + if (AnnotateTemplateIdToken(Template, TNK, &SS)) { + // If an unrecoverable error occurred, we need to return true here, + // because the token stream is in a damaged state. We may not return + // a valid identifier. + return Tok.isNot(tok::identifier); + } } // The current token, which is either an identifier or a @@ -978,7 +984,8 @@ bool Parser::TryAnnotateTypeOrScopeToken() { /// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only /// annotates C++ scope specifiers and template-ids. This returns -/// true if the token was annotated. +/// true if the token was annotated or there was an error that could not be +/// recovered from. /// /// Note that this routine emits an error if you call it with ::new or ::delete /// as the current tokens, so only call it in contexts where these are invalid. diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index 4c3ecee090..c3e4eb18e2 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -171,3 +171,27 @@ Y::foo y; // expected-error{{incomplete type 'struct Y' named in nested name spe X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}} \ // expected-error{{C++ requires a type specifier for all declarations}} \ // expected-error{{only constructors take base initializers}} + + + + +namespace somens { + struct a { }; +} + +template +class foo { +}; + + +// PR4452 +// FIXME: This error recovery sucks. +foo a2; // expected-error {{unexpected namespace name 'somens': expected expression}} \ +expected-error {{C++ requires a type specifier for all declarations}} + +// FIXME: This is bogus, there is no int here! +somens::a a3 = a2; // expected-error {{cannot initialize 'a3' with an lvalue of type 'int'}} + + + +