// Make sure to emit all elements of a Decl.
for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
Builder->EmitTopLevelDecl(*I);
+
+ // Emit any deferred inline method definitions.
+ for (CXXMethodDecl *MD : DeferredInlineMethodDefinitions)
+ Builder->EmitTopLevelDecl(MD);
+ DeferredInlineMethodDefinitions.clear();
+
return true;
}
assert(D->doesThisDeclarationHaveABody());
- // We may have member functions that need to be emitted at this point.
- if (!D->isDependentContext() &&
- (D->hasAttr<UsedAttr>() || D->hasAttr<ConstructorAttr>() ||
- D->hasAttr<DLLExportAttr>())) {
- Builder->EmitTopLevelDecl(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,
+ // e.g.
+ // typedef struct {
+ // void bar();
+ // void foo() { bar(); }
+ // } A;
+ DeferredInlineMethodDefinitions.push_back(D);
}
/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl
void HandleDependentLibrary(llvm::StringRef Lib) override {
Builder->AddDependentLib(Lib);
}
+
+ private:
+ std::vector<CXXMethodDecl *> DeferredInlineMethodDefinitions;
};
}
void __attribute__((used)) f() {}
};
};
+
+struct X2 {
+ // We must delay emission of bar() until foo() has had its body parsed,
+ // otherwise foo() would not be emitted.
+ void __attribute__((used)) bar() { foo(); }
+ void foo() { }
+
+ // CHECK: define linkonce_odr {{.*}} @_ZN2X23barEv
+ // CHECK: define linkonce_odr {{.*}} @_ZN2X23fooEv
+};
// 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)
~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"
+}