diff options
author | Chris Lattner <sabre@nondot.org> | 2007-07-23 04:56:47 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2007-07-23 04:56:47 +0000 |
commit | 706ab50019c0a4ae135a64861a7066927585471b (patch) | |
tree | ff815b7be7045392c73ade59b1b91fbae6c57196 /Lex | |
parent | f1c99acc544a4e70f308db4e7200ca04cd5a06d2 (diff) |
implement a missing feature in the #include handler, where
it did not handle <xyz> headers coming from macro expansions.
This requires special treatment, as the include name is lexed
as multiple tokens, which require reassembly before processing.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40418 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'Lex')
-rw-r--r-- | Lex/Preprocessor.cpp | 90 |
1 files changed, 81 insertions, 9 deletions
diff --git a/Lex/Preprocessor.cpp b/Lex/Preprocessor.cpp index e6cb218b82..96d9c9ec53 100644 --- a/Lex/Preprocessor.cpp +++ b/Lex/Preprocessor.cpp @@ -1625,6 +1625,55 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, return isAngled; } +/// ConcatenateIncludeName - Handle cases where the #include name is expanded +/// from a macro as multiple tokens, which need to be glued together. This +/// occurs for code like: +/// #define FOO <a/b.h> +/// #include FOO +/// because in this case, "<a/b.h>" is returned as 7 tokens, not one. +/// +/// This code concatenates and consumes tokens up to the '>' token. It returns +/// false if the > was found, otherwise it returns true if it finds and consumes +/// the EOM marker. +static bool ConcatenateIncludeName(llvm::SmallVector<char, 128> &FilenameBuffer, + Preprocessor &PP) { + Token CurTok; + + PP.Lex(CurTok); + while (CurTok.getKind() != tok::eom) { + // Append the spelling of this token to the buffer. If there was a space + // before it, add it now. + if (CurTok.hasLeadingSpace()) + FilenameBuffer.push_back(' '); + + // Get the spelling of the token, directly into FilenameBuffer if possible. + unsigned PreAppendSize = FilenameBuffer.size(); + FilenameBuffer.resize(PreAppendSize+CurTok.getLength()); + + const char *BufPtr = &FilenameBuffer[PreAppendSize]; + unsigned ActualLen = PP.getSpelling(CurTok, BufPtr); + + // If the token was spelled somewhere else, copy it into FilenameBuffer. + if (BufPtr != &FilenameBuffer[PreAppendSize]) + memcpy(&FilenameBuffer[PreAppendSize], BufPtr, ActualLen); + + // Resize FilenameBuffer to the correct size. + if (CurTok.getLength() != ActualLen) + FilenameBuffer.resize(PreAppendSize+ActualLen); + + // If we found the '>' marker, return success. + if (CurTok.getKind() == tok::greater) + return false; + + PP.Lex(CurTok); + } + + // If we hit the eom marker, emit an error and return true so that the caller + // knows the EOM has been read. + PP.Diag(CurTok.getLocation(), diag::err_pp_expects_filename); + return true; +} + /// HandleIncludeDirective - The "#include" tokens have just been read, read the /// file to be included from the lexer, then include it! This is a common /// routine with functionality shared between #include, #include_next and @@ -1636,23 +1685,46 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok, Token FilenameTok; CurLexer->LexIncludeFilename(FilenameTok); - // If the token kind is EOM, the error has already been diagnosed. - if (FilenameTok.getKind() == tok::eom) - return; - // Reserve a buffer to get the spelling. llvm::SmallVector<char, 128> FilenameBuffer; - FilenameBuffer.resize(FilenameTok.getLength()); + const char *FilenameStart, *FilenameEnd; + + switch (FilenameTok.getKind()) { + case tok::eom: + // If the token kind is EOM, the error has already been diagnosed. + return; + + case tok::angle_string_literal: + case tok::string_literal: + FilenameBuffer.resize(FilenameTok.getLength()); + FilenameStart = &FilenameBuffer[0]; + unsigned Len = getSpelling(FilenameTok, FilenameStart); + FilenameEnd = FilenameStart+Len; + break; + + case tok::less: + // This could be a <foo/bar.h> file coming from a macro expansion. In this + // case, glue the tokens together into FilenameBuffer and interpret those. + FilenameBuffer.push_back('<'); + if (ConcatenateIncludeName(FilenameBuffer, *this)) + return; // Found <eom> but no ">"? Diagnostic already emitted. + FilenameStart = &FilenameBuffer[0]; + FilenameEnd = &FilenameBuffer[FilenameBuffer.size()]; + break; + default: + Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); + DiscardUntilEndOfDirective(); + return; + } - const char *FilenameStart = &FilenameBuffer[0]; - unsigned Len = getSpelling(FilenameTok, FilenameStart); - const char *FilenameEnd = FilenameStart+Len; bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(), FilenameStart, FilenameEnd); // If GetIncludeFilenameSpelling set the start ptr to null, there was an // error. - if (FilenameStart == 0) + if (FilenameStart == 0) { + DiscardUntilEndOfDirective(); return; + } // Verify that there is nothing after the filename, other than EOM. Use the // preprocessor to lex this in case lexing the filename entered a macro. |