]> granicus.if.org Git - clang/commitdiff
Emit used/dllexport inline method definitions in nested classes (PR19743, PR11170)
authorHans Wennborg <hans@hanshq.net>
Fri, 23 May 2014 20:37:38 +0000 (20:37 +0000)
committerHans Wennborg <hans@hanshq.net>
Fri, 23 May 2014 20:37:38 +0000 (20:37 +0000)
The previous code that was supposed to handle this didn't work
since parsing of inline method definitions is delayed to the end
of the outer class definition. Thus, when HandleTagDeclDefinition()
got called for the inner class, the inline functions in that class
had not been parsed yet.

Richard suggested that the way to do this is by handling inline
method definitions through a new ASTConsumer callback.

I really wanted to call ASTContext::DeclMustBeEmitted() instead of
checking for attributes, but doing that causes us to compute linkage,
and then we fail with "error: unsupported: typedef changes linkage
of anonymous type, but linkage was already computed" on tests like
this: (from SemaCXX/undefined-internal.cpp) :-/

  namespace test7 {
    typedef struct {
      void bar();
      void foo() { bar(); }
    } A;
  }

Differential Revision: http://reviews.llvm.org/D3809

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@209549 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTConsumer.h
include/clang/Frontend/MultiplexConsumer.h
include/clang/Sema/Sema.h
lib/CodeGen/CodeGenAction.cpp
lib/CodeGen/ModuleBuilder.cpp
lib/Frontend/MultiplexConsumer.cpp
lib/Parse/ParseCXXInlineMethods.cpp
lib/Sema/SemaDecl.cpp
test/CodeGenCXX/attr-used.cpp
test/CodeGenCXX/dllexport.cpp

index fde114711bf11a3f1ffb9e7bbe22ed5ae4fb5ca8..6fa7cd861143034c1f6624afd9aafc06ff9693d5 100644 (file)
@@ -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.
index 6ea1d73d2824bd95f9698c8cabf6a2063086dec5..a7e0444885f1619ad1fe50e6523af4ebb93fe4bf 100644 (file)
@@ -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;
index f1354e5b8ff4b9b0aba930e2b64ac4db92e81025..578cc1fe1809c78fbd11b53200b6f32fe6fb18bb 100644 (file)
@@ -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.
index 5c0b6a9fd8e8c850036b348823e3f03b3e41dc22..2fe984226e184e5a58292a86b8175e7cc0c8d75d 100644 (file)
@@ -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");
index 7873f44f1de8434fa87d72302b5f17379ba53b05..78cb82dc558cc45a65f4a3a45f420a951b097079 100644 (file)
@@ -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 {
index 4b4804f035076d9a085c89cf257728b30e5ea950..058cee8244b3e6c0f5f117f4b684a7716e35abbd 100644 (file)
@@ -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);
index 8b368cc4054362c046163c08974e100af9eb2794..19aa664031d78ff8817f76dc0401407ed629a32f 100644 (file)
@@ -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
index a522ef4784b418a7c6340b7a6ba04c694c8dea74..d7b5ba427d674cbe819da9f7c7e5bc788c373fee 100644 (file)
@@ -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.
index 86dd6b959bfb93d386a21d0dfec54d3b1c1aa386..26c1597b5897d71c1e512a0ca6ade1fab6e08863 100644 (file)
@@ -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() {}
+  };
+};
index 7f11d455e3f30e7b5c7ff8268d49a209b59f3a55..04413574dcc342f37679a1bd155dbbc3abea59df 100644 (file)
@@ -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;
 }