Use filename in linemarker when compiling preprocessed source

Summary:
Clang appears to always use name as specified on the command
line, whereas gcc uses the name as specified in the linemarker at the
first line when compiling a preprocessed source. This results mismatch
between two compilers in FILE symbol table entry. This patch makes clang
to resemble gcc's behavior in finding the original source file name and
use it as an input file name.

Even with this patch, values of FILE symbol table entry may still be
different because clang uses dirname+basename for the entry whlie gcc
uses basename only. I'll write a patch for that once this patch is
committed.

Reviewers: dblaikie, inglorion

Reviewed By: inglorion

Subscribers: inglorion, aprantl, bruno

Differential Revision: https://reviews.llvm.org/D28796

llvm-svn: 293004
This commit is contained in:
David Callahan 2017-01-25 01:55:28 +00:00
parent 86f9e46365
commit ae7e0da4f8
3 changed files with 58 additions and 3 deletions

View File

@ -81,7 +81,7 @@ enum InputKind {
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 @@ public:
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());

View File

@ -19,6 +19,7 @@
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Frontend/Utils.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Parse/ParseAST.h"
@ -187,6 +188,42 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
return llvm::make_unique<MultiplexConsumer>(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<Lexer> RawLexer(
new Lexer(MainFileID, MainFileBuf, SourceMgr, CI.getLangOpts()));
// If the first line has the syntax of
//
// # NUM "FILENAME"
//
// we use FILENAME as the input file name.
Token T;
if (RawLexer->LexFromRawLexer(T) || T.getKind() != tok::hash)
return false;
if (RawLexer->LexFromRawLexer(T) || T.isAtStartOfLine() ||
T.getKind() != tok::numeric_constant)
return false;
RawLexer->LexFromRawLexer(T);
if (T.isAtStartOfLine() || T.getKind() != tok::string_literal)
return false;
StringLiteralParser Literal(T, CI.getPreprocessor());
if (Literal.hadError)
return false;
InputFile = Literal.GetString().str();
return true;
}
bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
const FrontendInputFile &Input) {
assert(!Instance && "Already processing a source file!");
@ -335,6 +372,13 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
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<ASTConsumer> Consumer =
CreateWrappedASTConsumer(CI, InputFile);
if (!Consumer)
@ -421,9 +465,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// 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<ExternalASTSource>
IntrusiveRefCntPtr<ExternalASTSource>
Override(new LayoutOverrideSource(
CI.getFrontendOpts().OverrideRecordLayoutsFile));
CI.getASTContext().setExternalSource(Override);

View File

@ -0,0 +1,4 @@
// RUN: %clang -E -o %t.i %s
// RUN: %clang -Xclang -triple -Xclang i686-linux-gnu -c -o %t.o %t.i
// RUN: llvm-objdump -t %t.o | FileCheck %s
// CHECK: l{{ +}}df{{ +}}*ABS*{{ +}}{{0+}}{{.+}}preprocessed-input.c{{$}}