Don't segfault in EmitCXXGlobalInitFunc when main file is a membuf

Summary: When the main file is created from a membuffer, there is no file entry that can be retrieved. This uses "__GLOBAL_I_a" in that case which is what was always used before r208128.

Reviewers: majnemer, thakis

Reviewed By: thakis

Subscribers: yaron.keren, rsmith, cfe-commits

Differential Revision: http://reviews.llvm.org/D5043

llvm-svn: 216495
This commit is contained in:
Keno Fischer
2014-08-26 22:10:15 +00:00
parent 9455c5ab81
commit 84778b2a1c
6 changed files with 130 additions and 7 deletions

View File

@@ -409,19 +409,25 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
AddGlobalCtor(Fn, Priority);
}
}
// Include the filename in the symbol name. Including "sub_" matches gcc and
// makes sure these symbols appear lexicographically behind the symbols with
// priority emitted above.
SmallString<128> FileName;
SourceManager &SM = Context.getSourceManager();
SmallString<128> FileName(llvm::sys::path::filename(
SM.getFileEntryForID(SM.getMainFileID())->getName()));
if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) {
// Include the filename in the symbol name. Including "sub_" matches gcc and
// makes sure these symbols appear lexicographically behind the symbols with
// priority emitted above.
FileName = llvm::sys::path::filename(MainFile->getName());
} else {
FileName = SmallString<128>("<null>");
}
for (size_t i = 0; i < FileName.size(); ++i) {
// Replace everything that's not [a-zA-Z0-9._] with a _. This set happens
// to be the set of C preprocessing numbers.
if (!isPreprocessingNumberBody(FileName[i]))
FileName[i] = '_';
}
llvm::Function *Fn = CreateGlobalInitOrDestructFunction(
*this, FTy, llvm::Twine("_GLOBAL__sub_I_", FileName));

View File

@@ -20,6 +20,7 @@ add_subdirectory(AST)
add_subdirectory(Tooling)
add_subdirectory(Format)
add_subdirectory(Sema)
add_subdirectory(CodeGen)
# FIXME: Why are the libclang unit tests disabled on Windows?
if(NOT WIN32)
add_subdirectory(libclang)

View File

@@ -0,0 +1,78 @@
//===- unittests/CodeGen/BufferSourceTest.cpp - MemoryBuffer source tests -===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Sema/Sema.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/IR/LLVMContext.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace clang;
namespace {
// Emitting constructors for global objects involves looking
// at the source file name. This makes sure that we don't crash
// if the source file is a memory buffer.
const char TestProgram[] =
"class EmitCXXGlobalInitFunc "
"{ "
"public: "
" EmitCXXGlobalInitFunc() {} "
"}; "
"EmitCXXGlobalInitFunc test; ";
TEST(BufferSourceTest, EmitCXXGlobalInitFunc) {
CompilerInstance compiler;
compiler.createDiagnostics();
compiler.getLangOpts().CPlusPlus = 1;
compiler.getLangOpts().CPlusPlus11 = 1;
compiler.getTargetOpts().Triple = llvm::Triple::normalize(
llvm::sys::getProcessTriple());
compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
compiler.getDiagnostics(),
std::make_shared<clang::TargetOptions>(
compiler.getTargetOpts())));
compiler.createFileManager();
compiler.createSourceManager(compiler.getFileManager());
compiler.createPreprocessor(clang::TU_Prefix);
compiler.createASTContext();
compiler.setASTConsumer(std::unique_ptr<ASTConsumer>(
CreateLLVMCodeGen(
compiler.getDiagnostics(),
"EmitCXXGlobalInitFuncTest",
compiler.getCodeGenOpts(),
compiler.getTargetOpts(),
llvm::getGlobalContext())));
compiler.createSema(clang::TU_Prefix,NULL);
clang::SourceManager &sm = compiler.getSourceManager();
sm.setMainFileID(sm.createFileID(
llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User));
clang::ParseAST(compiler.getSema(), false, false);
}
}

View File

@@ -0,0 +1,17 @@
set(LLVM_LINK_COMPONENTS
Support
)
add_clang_unittest(CodeGenTests
BufferSourceTest.cpp
)
target_link_libraries(CodeGenTests
clangAST
clangBasic
clangFrontend
clangParse
clangSema
clangTooling
clangCodeGen
)

View File

@@ -0,0 +1,20 @@
##===- unittests/CodeGen/Makefile --------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
CLANG_LEVEL = ../..
TESTNAME = CodeGen
include $(CLANG_LEVEL)/../../Makefile.config
LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
clangRewrite.a clangRewriteFrontend.a \
clangParse.a clangSema.a clangAnalysis.a \
clangEdit.a clangAST.a clangASTMatchers.a clangLex.a clangBasic.a \
clangCodeGen.a
include $(CLANG_LEVEL)/unittests/Makefile

View File

@@ -14,7 +14,8 @@ ifndef CLANG_LEVEL
IS_UNITTEST_LEVEL := 1
CLANG_LEVEL := ..
PARALLEL_DIRS = Basic Lex Driver libclang Format ASTMatchers AST Tooling Sema
PARALLEL_DIRS = CodeGen Basic Lex Driver libclang Format ASTMatchers AST Tooling \
Sema
include $(CLANG_LEVEL)/../..//Makefile.config