From: Richard Trieu Date: Mon, 22 Oct 2012 20:28:48 +0000 (+0000) Subject: Fix for PR13334. This prevents crashes that result from badly formed X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=97bc3d54a95153945d14b1ee812837160d45ed90;p=clang Fix for PR13334. This prevents crashes that result from badly formed expressions involving __has_include git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166438 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 3959671fda..06b39d3fa7 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -925,22 +925,30 @@ static bool HasAttribute(const IdentifierInfo *II) { static bool EvaluateHasIncludeCommon(Token &Tok, IdentifierInfo *II, Preprocessor &PP, const DirectoryLookup *LookupFrom) { - SourceLocation LParenLoc; + // Save the location of the current token. If a '(' is later found, use + // that location. If no, use the end of this location instead. + SourceLocation LParenLoc = Tok.getLocation(); // Get '('. PP.LexNonComment(Tok); // Ensure we have a '('. if (Tok.isNot(tok::l_paren)) { - PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName(); - return false; - } - - // Save '(' location for possible missing ')' message. - LParenLoc = Tok.getLocation(); + // No '(', use end of last token. + LParenLoc = PP.getLocForEndOfToken(LParenLoc); + PP.Diag(LParenLoc, diag::err_pp_missing_lparen) << II->getName(); + // If the next token looks like a filename or the start of one, + // assume it is and process it as such. + if (!Tok.is(tok::angle_string_literal) && !Tok.is(tok::string_literal) && + !Tok.is(tok::less)) + return false; + } else { + // Save '(' location for possible missing ')' message. + LParenLoc = Tok.getLocation(); - // Get the file name. - PP.getCurrentLexer()->LexIncludeFilename(Tok); + // Get the file name. + PP.getCurrentLexer()->LexIncludeFilename(Tok); + } // Reserve a buffer to get the spelling. SmallString<128> FilenameBuffer; @@ -965,8 +973,11 @@ static bool EvaluateHasIncludeCommon(Token &Tok, // This could be a file coming from a macro expansion. In this // case, glue the tokens together into FilenameBuffer and interpret those. FilenameBuffer.push_back('<'); - if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc)) + if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc)) { + // Let the caller know a was found by changing the Token kind. + Tok.setKind(tok::eod); return false; // Found but no ">"? Diagnostic already emitted. + } Filename = FilenameBuffer.str(); break; default: @@ -974,12 +985,15 @@ static bool EvaluateHasIncludeCommon(Token &Tok, return false; } + SourceLocation FilenameLoc = Tok.getLocation(); + // Get ')'. PP.LexNonComment(Tok); // Ensure we have a trailing ). if (Tok.isNot(tok::r_paren)) { - PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName(); + PP.Diag(PP.getLocForEndOfToken(FilenameLoc), diag::err_pp_missing_rparen) + << II->getName(); PP.Diag(LParenLoc, diag::note_matching) << "("; return false; } @@ -1252,7 +1266,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { else Value = EvaluateHasIncludeNext(Tok, II, *this); OS << (int)Value; - Tok.setKind(tok::numeric_constant); + if (Tok.is(tok::r_paren)) + Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_warning) { // The argument should be a parenthesized string literal. // The argument to these builtins should be a parenthesized identifier. diff --git a/test/Preprocessor/has_include.c b/test/Preprocessor/has_include.c index 13c8d56622..10f7795fc3 100644 --- a/test/Preprocessor/has_include.c +++ b/test/Preprocessor/has_include.c @@ -67,7 +67,7 @@ // Try badly formed expressions. // FIXME: We can recover better in almost all of these cases. (PR13335) -// expected-error@+1 {{missing '(' after '__has_include'}} expected-error@+1 {{expected end of line}} +// expected-error@+1 {{missing '(' after '__has_include'}} #if __has_include "stdint.h") #endif @@ -83,11 +83,11 @@ #if __has_include) #endif -// expected-error@+1 {{missing '(' after '__has_include'}} expected-error@+1 {{token is not a valid binary operator in a preprocessor subexpression}} +// expected-error@+1 {{missing '(' after '__has_include'}} #if __has_include) #endif -// expected-error@+1 {{expected "FILENAME" or }} expected-warning@+1 {{missing terminating '"' character}} +// expected-error@+1 {{expected "FILENAME" or }} expected-warning@+1 {{missing terminating '"' character}} expected-error@+1 {{invalid token at start of a preprocessor expression}} #if __has_include("stdint.h) #endif @@ -99,11 +99,25 @@ #if __has_include(stdint.h>) #endif +// expected-error@+1 {{missing '(' after '__has_include'}} +__has_include + +// expected-error@+1 {{missing ')' after '__has_include'}} // expected-error@+1 {{expected value in expression}} // expected-note@+1 {{to match this '('}} +#if __has_include("stdint.h" +#endif -// FIXME: These test cases cause the compiler to crash. (PR13334) -//#if __has_include("stdint.h" -//#if __has_include( -//#if __has_include -//#if __has_include( -//#if __has_include(}} // expected-error@+1 {{expected value in expression}} +#if __has_include( +#endif +// expected-error@+1 {{missing '(' after '__has_include'}} // expected-error@+1 {{expected value in expression}} +#if __has_include +#endif + +// expected-error@+1 {{missing ')' after '__has_include'}} // expected-error@+1 {{expected value in expression}} // expected-note@+1 {{to match this '('}} +#if __has_include( +#endif + +// expected-error@+1 {{expected "FILENAME" or }} // expected-error@+1 {{expected value in expression}} +#if __has_include(