Index: include/clang/Frontend/FrontendOptions.h =================================================================== --- include/clang/Frontend/FrontendOptions.h +++ include/clang/Frontend/FrontendOptions.h @@ -81,7 +81,7 @@ IK_LLVM_IR }; - + /// \brief An input file for the front end. class FrontendInputFile { /// \brief The file name, or "-" to read from standard input. @@ -109,6 +109,13 @@ bool isEmpty() const { return File.empty() && Buffer == nullptr; } bool isFile() const { return !isBuffer(); } bool isBuffer() const { return Buffer != nullptr; } + bool isPreprocessed() const { + return Kind == IK_PreprocessedC || + Kind == IK_PreprocessedCXX || + Kind == IK_PreprocessedObjC || + Kind == IK_PreprocessedObjCXX || + Kind == IK_PreprocessedCuda; + } StringRef getFile() const { assert(isFile()); Index: lib/Frontend/FrontendAction.cpp =================================================================== --- lib/Frontend/FrontendAction.cpp +++ lib/Frontend/FrontendAction.cpp @@ -187,6 +187,55 @@ return llvm::make_unique(std::move(Consumers)); } +// For preprocessed files, if the first line is the linemarker and specifies +// the original source file name, use that name as the input file name. +static bool ReadOriginalFileName(CompilerInstance &CI, std::string *InputFile) +{ + bool Invalid = false; + auto &SourceMgr = CI.getSourceManager(); + auto MainFileID = SourceMgr.getMainFileID(); + const auto *MainFileBuf = SourceMgr.getBuffer(MainFileID, &Invalid); + if (Invalid) + return false; + + std::unique_ptr RawLexer( + new Lexer(MainFileID, MainFileBuf, SourceMgr, CI.getLangOpts())); + + SmallVector Tokens; + Token Result; + // Read the first token + if (!RawLexer->LexFromRawLexer(Result)) { + Tokens.push_back(Result); + + // Push tokens in the first line into the vector + while (!RawLexer->LexFromRawLexer(Result)) { + if (Result.isAtStartOfLine()) + break; + Tokens.push_back(Result); + } + } + + // If the first line has the syntax of + // + // # NUM "FILENAME" + // + // we use FILENAME as the input file name. + if (Tokens.size() >= 3 && + Tokens[0].getKind() == tok::hash && + Tokens[1].getKind() == tok::numeric_constant && + Tokens[2].getKind() == tok::string_literal) { + auto OrigFileName + = RawLexer->getSpelling(Tokens[2], SourceMgr, CI.getLangOpts(), &Invalid); + auto OrigFileNameLen = OrigFileName.size(); + if (OrigFileName[0] != '\"' || OrigFileName[OrigFileNameLen-1] != '\"') + return false; + + *InputFile = OrigFileName.substr(1, OrigFileNameLen - 2); + return true; + } + return false; +} + bool FrontendAction::BeginSourceFile(CompilerInstance &CI, const FrontendInputFile &Input) { assert(!Instance && "Already processing a source file!"); @@ -335,6 +384,13 @@ if (!isModelParsingAction()) CI.createASTContext(); + // For preprocessed files, check if the first line specifies the original + // source file name with a linemarker. + std::string OrigFile; + if (Input.isPreprocessed()) + if (ReadOriginalFileName(CI, &OrigFile)) + InputFile = OrigFile; + std::unique_ptr Consumer = CreateWrappedASTConsumer(CI, InputFile); if (!Consumer) @@ -421,9 +477,9 @@ // If there is a layout overrides file, attach an external AST source that // provides the layouts from that file. - if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() && + if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() && CI.hasASTContext() && !CI.getASTContext().getExternalSource()) { - IntrusiveRefCntPtr + IntrusiveRefCntPtr Override(new LayoutOverrideSource( CI.getFrontendOpts().OverrideRecordLayoutsFile)); CI.getASTContext().setExternalSource(Override); Index: test/Frontend/preprocessed-input.c =================================================================== --- /dev/null +++ test/Frontend/preprocessed-input.c @@ -0,0 +1,4 @@ +// RUN: %clang -E -o %t.i %s +// RUN: %clang -c -o %t.o %t.i +// RUN: readelf -a --wide %t.o | FileCheck %s +// CHECK: FILE{{ +}}LOCAL{{ +}}DEFAULT{{ +}}ABS{{.+}}preprocessed-input.c{{$}}