From: Chris Lattner Date: Mon, 23 Jul 2007 04:56:47 +0000 (+0000) Subject: implement a missing feature in the #include handler, where X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=706ab50019c0a4ae135a64861a7066927585471b;p=clang implement a missing feature in the #include handler, where it did not handle 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 --- 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 +/// #include FOO +/// because in this case, "" 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 &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 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 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 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. diff --git a/test/Preprocessor/includeexpand2.c b/test/Preprocessor/includeexpand2.c new file mode 100644 index 0000000000..970c9abe40 --- /dev/null +++ b/test/Preprocessor/includeexpand2.c @@ -0,0 +1,4 @@ +// RUN: clang -Eonly %s -I. +# define HEADER + +# include HEADER