Index: cfe/trunk/lib/CodeGen/ModuleBuilder.cpp =================================================================== --- cfe/trunk/lib/CodeGen/ModuleBuilder.cpp +++ cfe/trunk/lib/CodeGen/ModuleBuilder.cpp @@ -93,6 +93,12 @@ // 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; } @@ -102,12 +108,15 @@ assert(D->doesThisDeclarationHaveABody()); - // We may have member functions that need to be emitted at this point. - if (!D->isDependentContext() && - (D->hasAttr() || D->hasAttr() || - D->hasAttr())) { - 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 @@ -168,6 +177,9 @@ void HandleDependentLibrary(llvm::StringRef Lib) override { Builder->AddDependentLib(Lib); } + + private: + std::vector DeferredInlineMethodDefinitions; }; } Index: cfe/trunk/test/CodeGenCXX/attr-used.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/attr-used.cpp +++ cfe/trunk/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, + // otherwise foo() would not be emitted. + void __attribute__((used)) bar() { foo(); } + void foo() { } + + // CHECK: define linkonce_odr {{.*}} @_ZN2X23barEv + // CHECK: define linkonce_odr {{.*}} @_ZN2X23fooEv +}; Index: cfe/trunk/test/CodeGenCXX/dllexport-members.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/dllexport-members.cpp +++ cfe/trunk/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: cfe/trunk/test/CodeGenCXX/dllexport.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/dllexport.cpp +++ cfe/trunk/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" +}