Fix a bug involving deferred decl emission and PCH
For various reasons, involving dllexport and class linkage compuations, we have to wait until after the semicolon after a class declaration to emit inline methods. These are "deferred" decls. Before this change, finishing the tag decl would trigger us to deserialize some PCH so that we could make a "pretty" IR-level type. Deserializing the PCH triggered calls to HandleTopLevelDecl, which, when done, checked the deferred decl list, and emitted some dllexported decls that weren't ready. Avoid this re-entrancy. Deferred decls should not get emitted when a tag is finished, they should only be emitted after a real top level decl in the main file. llvm-svn: 267186
This commit is contained in:
parent
658d9dbe56
commit
ea53dba78b
|
@ -36,13 +36,21 @@ namespace {
|
||||||
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
|
const CodeGenOptions CodeGenOpts; // Intentionally copied in.
|
||||||
|
|
||||||
unsigned HandlingTopLevelDecls;
|
unsigned HandlingTopLevelDecls;
|
||||||
|
|
||||||
|
/// Use this when emitting decls to block re-entrant decl emission. It will
|
||||||
|
/// emit all deferred decls on scope exit. Set EmitDeferred to false if decl
|
||||||
|
/// emission must be deferred longer, like at the end of a tag definition.
|
||||||
struct HandlingTopLevelDeclRAII {
|
struct HandlingTopLevelDeclRAII {
|
||||||
CodeGeneratorImpl &Self;
|
CodeGeneratorImpl &Self;
|
||||||
HandlingTopLevelDeclRAII(CodeGeneratorImpl &Self) : Self(Self) {
|
bool EmitDeferred;
|
||||||
|
HandlingTopLevelDeclRAII(CodeGeneratorImpl &Self,
|
||||||
|
bool EmitDeferred = true)
|
||||||
|
: Self(Self), EmitDeferred(EmitDeferred) {
|
||||||
++Self.HandlingTopLevelDecls;
|
++Self.HandlingTopLevelDecls;
|
||||||
}
|
}
|
||||||
~HandlingTopLevelDeclRAII() {
|
~HandlingTopLevelDeclRAII() {
|
||||||
if (--Self.HandlingTopLevelDecls == 0)
|
unsigned Level = --Self.HandlingTopLevelDecls;
|
||||||
|
if (Level == 0 && EmitDeferred)
|
||||||
Self.EmitDeferredDecls();
|
Self.EmitDeferredDecls();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -185,6 +193,10 @@ namespace {
|
||||||
if (Diags.hasErrorOccurred())
|
if (Diags.hasErrorOccurred())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Don't allow re-entrant calls to CodeGen triggered by PCH
|
||||||
|
// deserialization to emit deferred decls.
|
||||||
|
HandlingTopLevelDeclRAII HandlingDecl(*this, /*EmitDeferred=*/false);
|
||||||
|
|
||||||
Builder->UpdateCompletedType(D);
|
Builder->UpdateCompletedType(D);
|
||||||
|
|
||||||
// For MSVC compatibility, treat declarations of static data members with
|
// For MSVC compatibility, treat declarations of static data members with
|
||||||
|
@ -214,6 +226,10 @@ namespace {
|
||||||
if (Diags.hasErrorOccurred())
|
if (Diags.hasErrorOccurred())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Don't allow re-entrant calls to CodeGen triggered by PCH
|
||||||
|
// deserialization to emit deferred decls.
|
||||||
|
HandlingTopLevelDeclRAII HandlingDecl(*this, /*EmitDeferred=*/false);
|
||||||
|
|
||||||
if (CodeGen::CGDebugInfo *DI = Builder->getModuleDebugInfo())
|
if (CodeGen::CGDebugInfo *DI = Builder->getModuleDebugInfo())
|
||||||
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
|
if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
|
||||||
DI->completeRequiredType(RD);
|
DI->completeRequiredType(RD);
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
struct Info {
|
||||||
|
virtual ~Info();
|
||||||
|
void hash() {}
|
||||||
|
};
|
|
@ -0,0 +1,14 @@
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -x c++ %S/Inputs/pr27445.h -emit-pch -o %t.pch
|
||||||
|
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions %s -include-pch %t.pch -emit-llvm -o - | FileCheck %s
|
||||||
|
|
||||||
|
class A;
|
||||||
|
void fn1(A &) {}
|
||||||
|
|
||||||
|
class __declspec(dllexport) A {
|
||||||
|
int operator=(A) { return field_; }
|
||||||
|
void (*on_arena_allocation_)(Info);
|
||||||
|
int field_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// CHECK: %class.A = type { void (%struct.Info*)*, i32 }
|
||||||
|
// CHECK: %struct.Info = type { i32 (...)** }
|
Loading…
Reference in New Issue