mirror of https://github.com/microsoft/clang.git
[MS] Defer dllexport inline friend functions like other inline methods
This special case was added in r264841, but the code breaks our invariants by calling EmitTopLevelDecl without first creating a HandlingTopLevelDeclRAII scope. This fixes the PCH crash in https://crbug.com/884427. I was never able to make a satisfactory reduction, unfortunately. I'm not very worried about this regressing since this change makes the code simpler while passing the existing test that shows we do emit dllexported friend function definitions. Now we just defer their emission until the tag is fully complete, which is generally good. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@342516 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
6f42893d10
commit
c8df8c22bd
|
@ -64,7 +64,7 @@ namespace {
|
||||||
std::unique_ptr<CodeGen::CodeGenModule> Builder;
|
std::unique_ptr<CodeGen::CodeGenModule> Builder;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SmallVector<CXXMethodDecl *, 8> DeferredInlineMethodDefinitions;
|
SmallVector<FunctionDecl *, 8> DeferredInlineMemberFuncDefs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName,
|
CodeGeneratorImpl(DiagnosticsEngine &diags, llvm::StringRef ModuleName,
|
||||||
|
@ -80,7 +80,7 @@ namespace {
|
||||||
|
|
||||||
~CodeGeneratorImpl() override {
|
~CodeGeneratorImpl() override {
|
||||||
// There should normally not be any leftover inline method definitions.
|
// There should normally not be any leftover inline method definitions.
|
||||||
assert(DeferredInlineMethodDefinitions.empty() ||
|
assert(DeferredInlineMemberFuncDefs.empty() ||
|
||||||
Diags.hasErrorOccurred());
|
Diags.hasErrorOccurred());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,16 +163,16 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitDeferredDecls() {
|
void EmitDeferredDecls() {
|
||||||
if (DeferredInlineMethodDefinitions.empty())
|
if (DeferredInlineMemberFuncDefs.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Emit any deferred inline method definitions. Note that more deferred
|
// Emit any deferred inline method definitions. Note that more deferred
|
||||||
// methods may be added during this loop, since ASTConsumer callbacks
|
// methods may be added during this loop, since ASTConsumer callbacks
|
||||||
// can be invoked if AST inspection results in declarations being added.
|
// can be invoked if AST inspection results in declarations being added.
|
||||||
HandlingTopLevelDeclRAII HandlingDecl(*this);
|
HandlingTopLevelDeclRAII HandlingDecl(*this);
|
||||||
for (unsigned I = 0; I != DeferredInlineMethodDefinitions.size(); ++I)
|
for (unsigned I = 0; I != DeferredInlineMemberFuncDefs.size(); ++I)
|
||||||
Builder->EmitTopLevelDecl(DeferredInlineMethodDefinitions[I]);
|
Builder->EmitTopLevelDecl(DeferredInlineMemberFuncDefs[I]);
|
||||||
DeferredInlineMethodDefinitions.clear();
|
DeferredInlineMemberFuncDefs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleInlineFunctionDefinition(FunctionDecl *D) override {
|
void HandleInlineFunctionDefinition(FunctionDecl *D) override {
|
||||||
|
@ -181,17 +181,6 @@ namespace {
|
||||||
|
|
||||||
assert(D->doesThisDeclarationHaveABody());
|
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
|
// 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
|
// 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,
|
// are inside of something that will change the method's final linkage,
|
||||||
|
@ -200,13 +189,13 @@ namespace {
|
||||||
// void bar();
|
// void bar();
|
||||||
// void foo() { bar(); }
|
// void foo() { bar(); }
|
||||||
// } A;
|
// } A;
|
||||||
DeferredInlineMethodDefinitions.push_back(MD);
|
DeferredInlineMemberFuncDefs.push_back(D);
|
||||||
|
|
||||||
// Provide some coverage mapping even for methods that aren't emitted.
|
// Provide some coverage mapping even for methods that aren't emitted.
|
||||||
// Don't do this for templated classes though, as they may not be
|
// Don't do this for templated classes though, as they may not be
|
||||||
// instantiable.
|
// instantiable.
|
||||||
if (!MD->getParent()->isDependentContext())
|
if (!D->getLexicalDeclContext()->isDependentContext())
|
||||||
Builder->AddDeferredUnusedCoverageMapping(MD);
|
Builder->AddDeferredUnusedCoverageMapping(D);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
|
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
|
||||||
|
|
Loading…
Reference in New Issue