For MS ABI, emit dllexport friend functions defined inline in class

...as that is apparently what MSVC does.  This is an updated version of r263738,
which had to be reverted in r263740 due to test failures.  The original version
had erroneously emitted functions that are defined in class templates, too (see
the updated "Handle friend functions" code in EmitDeferredDecls,
lib/CodeGen/ModuleBuilder.cpp).  (The updated tests needed to be split out into
their own dllexport-ms-friend.cpp because of the CHECK-NOTs which would have
interfered with subsequent CHECK-DAGs in dllexport.cpp.)

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

llvm-svn: 264841
This commit is contained in:
Stephan Bergmann 2016-03-30 06:27:31 +00:00
parent e9ff01b2a7
commit 17d7d14571
9 changed files with 53 additions and 18 deletions

View File

@ -55,9 +55,9 @@ public:
/// \returns true to continue parsing, or false to abort parsing.
virtual bool HandleTopLevelDecl(DeclGroupRef D);
/// \brief This callback is invoked each time an inline method definition is
/// completed.
virtual void HandleInlineMethodDefinition(CXXMethodDecl *D) {}
/// \brief This callback is invoked each time an inline (method or friend)
/// function definition in a class is completed.
virtual void HandleInlineFunctionDefinition(FunctionDecl *D) {}
/// HandleInterestingDecl - Handle the specified interesting declaration. This
/// is called by the AST reader when deserializing things that might interest

View File

@ -36,7 +36,7 @@ public:
void Initialize(ASTContext &Context) override;
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override;
bool HandleTopLevelDecl(DeclGroupRef D) override;
void HandleInlineMethodDefinition(CXXMethodDecl *D) override;
void HandleInlineFunctionDefinition(FunctionDecl *D) override;
void HandleInterestingDecl(DeclGroupRef D) override;
void HandleTranslationUnit(ASTContext &Ctx) override;
void HandleTagDeclDefinition(TagDecl *D) override;

View File

@ -1773,7 +1773,7 @@ public:
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body);
Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation);
Decl *ActOnSkippedFunctionBody(Decl *Decl);
void ActOnFinishInlineMethodDef(CXXMethodDecl *D);
void ActOnFinishInlineFunctionDef(FunctionDecl *D);
/// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an
/// attribute for which parsing is delayed.

View File

@ -123,14 +123,14 @@ namespace clang {
return true;
}
void HandleInlineMethodDefinition(CXXMethodDecl *D) override {
void HandleInlineFunctionDefinition(FunctionDecl *D) override {
PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
Context->getSourceManager(),
"LLVM IR generation of inline method");
"LLVM IR generation of inline function");
if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.startTimer();
Gen->HandleInlineMethodDefinition(D);
Gen->HandleInlineFunctionDefinition(D);
if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.stopTimer();

View File

@ -143,12 +143,23 @@ namespace {
DeferredInlineMethodDefinitions.clear();
}
void HandleInlineMethodDefinition(CXXMethodDecl *D) override {
void HandleInlineFunctionDefinition(FunctionDecl *D) override {
if (Diags.hasErrorOccurred())
return;
assert(D->doesThisDeclarationHaveABody());
// Handle friend functions.
if (D->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend)) {
if (Ctx->getTargetInfo().getCXXABI().isMicrosoft()
&& !D->getLexicalDeclContext()->isDependentContext())
Builder->EmitTopLevelDecl(D);
return;
}
// Otherwise, must be a method.
auto MD = cast<CXXMethodDecl>(D);
// We may want to emit this definition. However, that decision might be
// based on computing the linkage, and we have to defer that in case we
// are inside of something that will change the method's final linkage,
@ -157,13 +168,13 @@ namespace {
// void bar();
// void foo() { bar(); }
// } A;
DeferredInlineMethodDefinitions.push_back(D);
DeferredInlineMethodDefinitions.push_back(MD);
// Provide some coverage mapping even for methods that aren't emitted.
// Don't do this for templated classes though, as they may not be
// instantiable.
if (!D->getParent()->getDescribedClassTemplate())
Builder->AddDeferredUnusedCoverageMapping(D);
if (!MD->getParent()->getDescribedClassTemplate())
Builder->AddDeferredUnusedCoverageMapping(MD);
}
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl

View File

@ -272,9 +272,9 @@ bool MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) {
return Continue;
}
void MultiplexConsumer::HandleInlineMethodDefinition(CXXMethodDecl *D) {
void MultiplexConsumer::HandleInlineFunctionDefinition(FunctionDecl *D) {
for (auto &Consumer : Consumers)
Consumer->HandleInlineMethodDefinition(D);
Consumer->HandleInlineFunctionDefinition(D);
}
void MultiplexConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {

View File

@ -564,8 +564,10 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) {
if (Tok.is(tok::eof) && Tok.getEofData() == LM.D)
ConsumeAnyToken();
if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(LM.D))
Actions.ActOnFinishInlineMethodDef(MD);
if (auto *FD = dyn_cast_or_null<FunctionDecl>(LM.D))
if (isa<CXXMethodDecl>(FD) ||
FD->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend))
Actions.ActOnFinishInlineFunctionDef(FD);
}
/// ParseLexedMemberInitializers - We finished parsing the member specification

View File

@ -10875,8 +10875,8 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D,
return ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody);
}
void Sema::ActOnFinishInlineMethodDef(CXXMethodDecl *D) {
Consumer.HandleInlineMethodDefinition(D);
void Sema::ActOnFinishInlineFunctionDef(FunctionDecl *D) {
Consumer.HandleInlineFunctionDefinition(D);
}
static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,

View File

@ -0,0 +1,22 @@
// RUN: %clang_cc1 -triple %ms_abi_triple -fms-extensions -emit-llvm -O0 -o - %s | FileCheck %s
// Friend functions defined in classes are emitted.
// CHECK: define weak_odr dllexport void @"\01?friend1@@YAXXZ"()
struct FuncFriend1 {
friend __declspec(dllexport) void friend1() {}
};
// But function templates and functions defined in class templates are not
// emitted.
// CHECK-NOT: friend2
// CHECK-NOT: friend3
// CHECK-NOT: friend4
struct FuncFriend2 {
template<typename> friend __declspec(dllexport) void friend2() {}
};
template<typename> struct FuncFriend3 {
friend __declspec(dllexport) void friend3() {}
struct Inner {
friend __declspec(dllexport) void friend4() {}
};
};