diff --git a/include/clang/AST/ASTConsumer.h b/include/clang/AST/ASTConsumer.h index fde114711bf11a3f1ffb9e7bbe22ed5ae4fb5ca8..6fa7cd861143034c1f6624afd9aafc06ff9693d5 100644 --- a/include/clang/AST/ASTConsumer.h +++ b/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 @@ public: /// \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. diff --git a/include/clang/Frontend/MultiplexConsumer.h b/include/clang/Frontend/MultiplexConsumer.h index 6ea1d73d2824bd95f9698c8cabf6a2063086dec5..a7e0444885f1619ad1fe50e6523af4ebb93fe4bf 100644 --- a/include/clang/Frontend/MultiplexConsumer.h +++ b/include/clang/Frontend/MultiplexConsumer.h @@ -36,6 +36,7 @@ public: 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; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index f1354e5b8ff4b9b0aba930e2b64ac4db92e81025..578cc1fe1809c78fbd11b53200b6f32fe6fb18bb 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1670,6 +1670,7 @@ public: 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. diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp index 5c0b6a9fd8e8c850036b348823e3f03b3e41dc22..2fe984226e184e5a58292a86b8175e7cc0c8d75d 100644 --- a/lib/CodeGen/CodeGenAction.cpp +++ b/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 @@ namespace clang { 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"); diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp index 7873f44f1de8434fa87d72302b5f17379ba53b05..78cb82dc558cc45a65f4a3a45f420a951b097079 100644 --- a/lib/CodeGen/ModuleBuilder.cpp +++ b/lib/CodeGen/ModuleBuilder.cpp @@ -81,6 +81,20 @@ namespace { 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<UsedAttr>() || D->hasAttr<ConstructorAttr>() || + D->hasAttr<DLLExportAttr>())) { + 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 @@ namespace { 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<CXXMethodDecl>(M)) - if (Method->doesThisDeclarationHaveABody() && - (Method->hasAttr<UsedAttr>() || - Method->hasAttr<ConstructorAttr>())) - Builder->EmitTopLevelDecl(Method); - } } void HandleTagDeclRequiredDefinition(const TagDecl *D) override { diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp index 4b4804f035076d9a085c89cf257728b30e5ea950..058cee8244b3e6c0f5f117f4b684a7716e35abbd 100644 --- a/lib/Frontend/MultiplexConsumer.cpp +++ b/lib/Frontend/MultiplexConsumer.cpp @@ -226,6 +226,11 @@ bool MultiplexConsumer::HandleTopLevelDecl(DeclGroupRef D) { 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); diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index 8b368cc4054362c046163c08974e100af9eb2794..19aa664031d78ff8817f76dc0401407ed629a32f 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -467,6 +467,9 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof)) ConsumeAnyToken(); } + + if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(LM.D)) + Actions.ActOnFinishInlineMethodDef(MD); } /// ParseLexedMemberInitializers - We finished parsing the member specification diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a522ef4784b418a7c6340b7a6ba04c694c8dea74..d7b5ba427d674cbe819da9f7c7e5bc788c373fee 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -9515,6 +9515,10 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { 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. diff --git a/test/CodeGenCXX/attr-used.cpp b/test/CodeGenCXX/attr-used.cpp index 86dd6b959bfb93d386a21d0dfec54d3b1c1aa386..26c1597b5897d71c1e512a0ca6ade1fab6e08863 100644 --- a/test/CodeGenCXX/attr-used.cpp +++ b/test/CodeGenCXX/attr-used.cpp @@ -7,3 +7,11 @@ struct X0 { // 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() {} + }; +}; diff --git a/test/CodeGenCXX/dllexport.cpp b/test/CodeGenCXX/dllexport.cpp index 7f11d455e3f30e7b5c7ff8268d49a209b59f3a55..04413574dcc342f37679a1bd155dbbc3abea59df 100644 --- a/test/CodeGenCXX/dllexport.cpp +++ b/test/CodeGenCXX/dllexport.cpp @@ -15,10 +15,14 @@ template void DLLEXPORT c<int>(); 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; }