Hi rnk, rsmith,
We would previously fail to emit a definition of bar() for the following code:
struct __declspec(dllexport) S {
void foo() {
t->bar();
}
struct T {
void bar() {}
};
T *t;
};
Note that foo() is an exported method, but bar() is not. However, foo() refers
to bar() so we need to emit its definition. To make this work, we need to delay
the codegen of foo() until the bodies of all the other inline methods have been
parsed.
The same problem applies to inline methods that are marked used.
http://reviews.llvm.org/D4038
Files:
lib/CodeGen/CodeGenModule.cpp
lib/CodeGen/CodeGenModule.h
lib/CodeGen/ModuleBuilder.cpp
test/CodeGenCXX/attr-used.cpp
test/CodeGenCXX/dllexport-members.cpp
test/CodeGenCXX/dllexport.cpp
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -312,6 +312,7 @@
void CodeGenModule::clear() {
DeferredDeclsToEmit.clear();
+ DeferredTopLevelDeclsToEmit.clear();
}
void CodeGenModule::Release() {
@@ -1017,10 +1018,12 @@
}
void CodeGenModule::EmitDeferred() {
+ for (Decl *D : DeferredTopLevelDeclsToEmit)
+ EmitTopLevelDecl(D);
+
// Emit code for any potentially referenced deferred decls. Since a
// previously unused static decl may become used during the generation of code
// for a static function, iterate until no changes are made.
-
while (true) {
if (!DeferredVTables.empty()) {
EmitDeferredVTables();
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h
+++ lib/CodeGen/CodeGenModule.h
@@ -301,6 +301,8 @@
DeferredDeclsToEmit.push_back(DeferredGlobal(GV, GD));
}
+ std::vector<Decl*> DeferredTopLevelDeclsToEmit;
+
/// List of alias we have emitted. Used to make sure that what they point to
/// is defined once we get to the end of the of the translation unit.
std::vector<GlobalDecl> Aliases;
@@ -792,6 +794,11 @@
/// Emit code for a single top level declaration.
void EmitTopLevelDecl(Decl *D);
+ /// Add a top level decl to be emitted at the end of codegen.
+ void AddDeferredTopLevelDeclToEmit(Decl* D) {
+ DeferredTopLevelDeclsToEmit.push_back(D);
+ }
+
/// Tell the consumer that this variable has been instantiated.
void HandleCXXStaticMemberVarInstantiation(VarDecl *VD);
@@ -1006,6 +1013,8 @@
/// are emitted lazily.
void EmitGlobal(GlobalDecl D);
+ void AddDeferredFunctionDefinition(FunctionDecl *D);
+
private:
llvm::GlobalValue *GetGlobalValue(StringRef Ref);
Index: lib/CodeGen/ModuleBuilder.cpp
===================================================================
--- lib/CodeGen/ModuleBuilder.cpp
+++ lib/CodeGen/ModuleBuilder.cpp
@@ -91,7 +91,10 @@
if (!D->isDependentContext() &&
(D->hasAttr<UsedAttr>() || D->hasAttr<ConstructorAttr>() ||
D->hasAttr<DLLExportAttr>())) {
- Builder->EmitTopLevelDecl(D);
+ // Defer emission to make sure that all other members, members of nested
+ // classes, etc. have been parsed before doing codegen for this method,
+ // in case it references any of them.
+ Builder->AddDeferredTopLevelDeclToEmit(D);
}
}
Index: test/CodeGenCXX/attr-used.cpp
===================================================================
--- test/CodeGenCXX/attr-used.cpp
+++ test/CodeGenCXX/attr-used.cpp
@@ -15,3 +15,13 @@
void __attribute__((used)) f() {}
};
};
+
+struct X2 {
+ // We must delay emission of bar() until foo() has had its body parsed,
+ // othersie foo() would not be emitted.
+ void __attribute__((used)) bar() { foo(); }
+ void foo() { }
+
+ // CHECK: define linkonce_odr {{.*}} @_ZN2X23barEv
+ // CHECK: define linkonce_odr {{.*}} @_ZN2X23fooEv
+};
Index: test/CodeGenCXX/dllexport-members.cpp
===================================================================
--- test/CodeGenCXX/dllexport-members.cpp
+++ test/CodeGenCXX/dllexport-members.cpp
@@ -40,10 +40,12 @@
// G64-DAG: define weak_odr dllexport void @_ZN13ExportMembers15normalInlineDefEv(%struct.ExportMembers* %this)
// G32-DAG: define weak_odr dllexport x86_thiscallcc void @_ZN13ExportMembers16normalInlineDeclEv(%struct.ExportMembers* %this)
// G64-DAG: define weak_odr dllexport void @_ZN13ExportMembers16normalInlineDeclEv(%struct.ExportMembers* %this)
+ // M32-DAG: define linkonce_odr x86_thiscallcc void @"\01?referencedNonExportedInClass@ExportMembers@@QAEXXZ"
__declspec(dllexport) void normalDef();
- __declspec(dllexport) void normalInclass() {}
+ __declspec(dllexport) void normalInclass() { referencedNonExportedInClass(); }
__declspec(dllexport) void normalInlineDef();
__declspec(dllexport) inline void normalInlineDecl();
+ void referencedNonExportedInClass() {}
// M32-DAG: define dllexport x86_thiscallcc void @"\01?virtualDef@ExportMembers@@UAEXXZ"(%struct.ExportMembers* %this)
// M64-DAG: define dllexport void @"\01?virtualDef@ExportMembers@@UEAAXXZ"(%struct.ExportMembers* %this)
Index: test/CodeGenCXX/dllexport.cpp
===================================================================
--- test/CodeGenCXX/dllexport.cpp
+++ test/CodeGenCXX/dllexport.cpp
@@ -538,3 +538,17 @@
~DefaultedCtorsDtors() = default;
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01??1DefaultedCtorsDtors@@QAE@XZ"
};
+
+namespace ReferencedInlineMethodInNestedClass {
+ struct __declspec(dllexport) S {
+ void foo() {
+ t->bar();
+ }
+ struct T {
+ void bar() {}
+ };
+ T *t;
+ };
+ // M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?foo@S@ReferencedInlineMethodInNestedClass@@QAEXXZ"
+ // M32-DAG: define linkonce_odr x86_thiscallcc void @"\01?bar@T@S@ReferencedInlineMethodInNestedClass@@QAEXXZ"
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits