forked from OSchip/llvm-project
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:
parent
e9ff01b2a7
commit
17d7d14571
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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() {}
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue