Index: cfe/trunk/include/clang/AST/ASTConsumer.h =================================================================== --- cfe/trunk/include/clang/AST/ASTConsumer.h +++ cfe/trunk/include/clang/AST/ASTConsumer.h @@ -18,6 +18,7 @@ namespace clang { class ASTContext; + class CXXMethodDecl; class CXXRecordDecl; class Decl; class DeclGroupRef; @@ -56,6 +57,10 @@ /// \returns true to continue parsing, or false to abort parsing. virtual bool HandleTopLevelDecl(DeclGroupRef D); + /// \brief This callback is invoked each time an inline method definition is + /// completed. + virtual void HandleInlineMethodDefinition(CXXMethodDecl *D) {} + /// HandleInterestingDecl - Handle the specified interesting declaration. This /// is called by the AST reader when deserializing things that might interest /// the consumer. The default implementation forwards to HandleTopLevelDecl. Index: cfe/trunk/include/clang/Frontend/MultiplexConsumer.h =================================================================== --- cfe/trunk/include/clang/Frontend/MultiplexConsumer.h +++ cfe/trunk/include/clang/Frontend/MultiplexConsumer.h @@ -36,6 +36,7 @@ void Initialize(ASTContext &Context) override; void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override; bool HandleTopLevelDecl(DeclGroupRef D) override; + void HandleInlineMethodDefinition(CXXMethodDecl *D) override; void HandleInterestingDecl(DeclGroupRef D) override; void HandleTranslationUnit(ASTContext &Ctx) override; void HandleTagDeclDefinition(TagDecl *D) override; Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -1670,6 +1670,7 @@ Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); Decl *ActOnSkippedFunctionBody(Decl *Decl); + void ActOnFinishInlineMethodDef(CXXMethodDecl *D); /// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an /// attribute for which parsing is delayed. Index: cfe/trunk/lib/CodeGen/CodeGenAction.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CodeGenAction.cpp +++ cfe/trunk/lib/CodeGen/CodeGenAction.cpp @@ -11,6 +11,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclGroup.h" +#include "clang/AST/DeclCXX.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -104,6 +105,19 @@ return true; } + void HandleInlineMethodDefinition(CXXMethodDecl *D) override { + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + Context->getSourceManager(), + "LLVM IR generation of inline method"); + if (llvm::TimePassesIsEnabled) + LLVMIRGeneration.startTimer(); + + Gen->HandleInlineMethodDefinition(D); + + if (llvm::TimePassesIsEnabled) + LLVMIRGeneration.stopTimer(); + } + void HandleTranslationUnit(ASTContext &C) override { { PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); Index: cfe/trunk/lib/CodeGen/ModuleBuilder.cpp =================================================================== --- cfe/trunk/lib/CodeGen/ModuleBuilder.cpp +++ cfe/trunk/lib/CodeGen/ModuleBuilder.cpp @@ -81,6 +81,20 @@ return true; } + void HandleInlineMethodDefinition(CXXMethodDecl *D) override { + if (Diags.hasErrorOccurred()) + return; + + 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); + } + } + /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl /// to (e.g. struct, union, enum, class) is completed. This allows the /// client hack on the type, which can occur at any point in the file @@ -90,17 +104,6 @@ return; Builder->UpdateCompletedType(D); - - // In C++, we may have member functions that need to be emitted at this - // point. - if (Ctx->getLangOpts().CPlusPlus && !D->isDependentContext()) { - for (auto *M : D->decls()) - if (auto *Method = dyn_cast(M)) - if (Method->doesThisDeclarationHaveABody() && - (Method->hasAttr() || - Method->hasAttr())) - Builder->EmitTopLevelDecl(Method); - } } void HandleTagDeclRequiredDefinition(const TagDecl *D) override { Index: cfe/trunk/lib/Frontend/MultiplexConsumer.cpp =================================================================== --- cfe/trunk/lib/Frontend/MultiplexConsumer.cpp +++ cfe/trunk/lib/Frontend/MultiplexConsumer.cpp @@ -226,6 +226,11 @@ return Continue; } +void MultiplexConsumer::HandleInlineMethodDefinition(CXXMethodDecl *D) { + for (size_t i = 0, e = Consumers.size(); i != e; ++i) + Consumers[i]->HandleInlineMethodDefinition(D); +} + void MultiplexConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) { for (size_t i = 0, e = Consumers.size(); i != e; ++i) Consumers[i]->HandleCXXStaticMemberVarInstantiation(VD); Index: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp =================================================================== --- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp +++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp @@ -467,6 +467,9 @@ while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); } + + if (CXXMethodDecl *MD = dyn_cast_or_null(LM.D)) + Actions.ActOnFinishInlineMethodDef(MD); } /// ParseLexedMemberInitializers - We finished parsing the member specification Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -9515,6 +9515,10 @@ return ActOnStartOfFunctionDef(FnBodyScope, DP); } +void Sema::ActOnFinishInlineMethodDef(CXXMethodDecl *D) { + Consumer.HandleInlineMethodDefinition(D); +} + static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, const FunctionDecl*& PossibleZeroParamPrototype) { // Don't warn about invalid declarations. Index: cfe/trunk/test/CodeGenCXX/attr-used.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/attr-used.cpp +++ cfe/trunk/test/CodeGenCXX/attr-used.cpp @@ -7,3 +7,11 @@ // CHECK: define linkonce_odr {{.*}} @_ZN2X0D1Ev __attribute__((used)) ~X0() {} }; + +// PR19743: not emitting __attribute__((used)) inline methods in nested classes. +struct X1 { + struct Nested { + // CHECK: define linkonce_odr {{.*}} @_ZN2X16Nested1fEv + void __attribute__((used)) f() {} + }; +}; Index: cfe/trunk/test/CodeGenCXX/dllexport.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/dllexport.cpp +++ cfe/trunk/test/CodeGenCXX/dllexport.cpp @@ -15,10 +15,14 @@ struct S { void DLLEXPORT a() {} // CHECK-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?a@S@@QAEXXZ" + + struct T { + void DLLEXPORT a() {} + // CHECK-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?a@T@S@@QAEXXZ" + }; }; + void user() { a(); - // FIXME: dllexported methods must be emitted even if they're not referenced in this TU. - &S::a; }