aprantl created this revision.
aprantl added reviewers: vsk, rjmccall.
aprantl added a project: debug-info.
aprantl added a reviewer: davide.

This fixes a crash in Clang.

Starting with DWARF 5 we are emitting ObjC method declarations as
children of their containing entity. This worked for interfaces, but
didn't consider the case of synthessized properties. When a property
of a protocol is synthesized in an interface implementation the
ObjCMethodDecl that was passed to CGF::StartFunction was the property
*declaration* which obviously couldn't have a containing
interface. This patch passes the containing interface all the way
through to CGDebugInfo, so the function declaration can be created
with the correct parent (= the class implementing the protocol).

rdar://problem/53782400


https://reviews.llvm.org/D66121

Files:
  clang/lib/CodeGen/CGDebugInfo.cpp
  clang/lib/CodeGen/CGDebugInfo.h
  clang/lib/CodeGen/CGObjC.cpp
  clang/lib/CodeGen/CodeGenFunction.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/test/CodeGenObjC/debug-info-objc-property-dwarf5.m

Index: clang/test/CodeGenObjC/debug-info-objc-property-dwarf5.m
===================================================================
--- /dev/null
+++ clang/test/CodeGenObjC/debug-info-objc-property-dwarf5.m
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -emit-llvm -debug-info-kind=standalone -dwarf-version=5 %s -o - | FileCheck %s
+
+@protocol NSObject
+@end
+
+@interface NSObject <NSObject> {}
+@end
+
+struct Bar {};
+
+@protocol BarProto
+@property struct Bar *bar;
+@end
+
+@interface Foo <BarProto>
+@end
+
+@implementation Foo {}
+@synthesize bar = _bar;
+- (void)f {}
+@end
+
+// CHECK: ![[FOO:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo"
+
+// CHECK: ![[DECL:[0-9]+]] = !DISubprogram(name: "-[Foo setBar:]",
+// CHECK-SAME:  scope: ![[FOO]]
+
+// CHECK: distinct !DISubprogram(name: "-[Foo setBar:]",
+// CHECK-SAME:  declaration: ![[DECL:[0-9]+]]
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -1836,13 +1836,16 @@
   /// Emit code for the start of a function.
   /// \param Loc       The location to be associated with the function.
   /// \param StartLoc  The location of the function body.
+  /// \param CD        For synthesized Objective-C properties, this is the
+  ///                  container which they are synthesized for.
   void StartFunction(GlobalDecl GD,
                      QualType RetTy,
                      llvm::Function *Fn,
                      const CGFunctionInfo &FnInfo,
                      const FunctionArgList &Args,
                      SourceLocation Loc = SourceLocation(),
-                     SourceLocation StartLoc = SourceLocation());
+                     SourceLocation StartLoc = SourceLocation(),
+                     const ObjCContainerDecl *CD = nullptr);
 
   static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor);
 
Index: clang/lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.cpp
+++ clang/lib/CodeGen/CodeGenFunction.cpp
@@ -638,13 +638,12 @@
   return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM);
 }
 
-void CodeGenFunction::StartFunction(GlobalDecl GD,
-                                    QualType RetTy,
+void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
                                     llvm::Function *Fn,
                                     const CGFunctionInfo &FnInfo,
                                     const FunctionArgList &Args,
-                                    SourceLocation Loc,
-                                    SourceLocation StartLoc) {
+                                    SourceLocation Loc, SourceLocation StartLoc,
+                                    const ObjCContainerDecl *CD) {
   assert(!CurFn &&
          "Do not use a CodeGenFunction object for more than one function");
 
@@ -855,7 +854,7 @@
     QualType FnType = getContext().getFunctionType(
         RetTy, ArgTypes, FunctionProtoType::ExtProtoInfo(CC));
     DI->EmitFunctionStart(GD, Loc, StartLoc, FnType, CurFn, CurFuncIsThunk,
-                          Builder);
+                          Builder, CD);
   }
 
   if (ShouldInstrumentFunction()) {
Index: clang/lib/CodeGen/CGObjC.cpp
===================================================================
--- clang/lib/CodeGen/CGObjC.cpp
+++ clang/lib/CodeGen/CGObjC.cpp
@@ -694,7 +694,7 @@
   CurEHLocation = OMD->getEndLoc();
 
   StartFunction(OMD, OMD->getReturnType(), Fn, FI, args,
-                OMD->getLocation(), StartLoc);
+                OMD->getLocation(), StartLoc, CD);
 
   // In ARC, certain methods get an extra cleanup.
   if (CGM.getLangOpts().ObjCAutoRefCount &&
Index: clang/lib/CodeGen/CGDebugInfo.h
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.h
+++ clang/lib/CodeGen/CGDebugInfo.h
@@ -398,10 +398,12 @@
   /// start of a new function.
   /// \param Loc       The location of the function header.
   /// \param ScopeLoc  The location of the function body.
+  /// \param CD        For synthesized Objective-C properties, their container.
   void EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
                          SourceLocation ScopeLoc, QualType FnType,
                          llvm::Function *Fn, bool CurFnIsThunk,
-                         CGBuilderTy &Builder);
+                         CGBuilderTy &Builder,
+                         const ObjCContainerDecl *CD = nullptr);
 
   /// Start a new scope for an inlined function.
   void EmitInlineFunctionStart(CGBuilderTy &Builder, GlobalDecl GD);
@@ -601,6 +603,19 @@
   /// declaration for the given method definition.
   llvm::DISubprogram *getFunctionDeclaration(const Decl *D);
 
+  /// \return          debug info descriptor to the describe method declaration
+  ///                  for the given method definition.
+  /// \param CD        For synthesized Objective-C properties, their container.
+  /// \param FnType    For Objective-C methods, their type.
+  /// \param LineNo    The declaration's line number.
+  /// \param Flags     The DIFlags for the method declaration.
+  /// \param SPFlags   The subprogram-spcific flags for the method declaration.
+  llvm::DISubprogram *
+  getObjCMethodDeclaration(const Decl *D, const ObjCContainerDecl *CD,
+                           llvm::DISubroutineType *FnType, unsigned LineNo,
+                           llvm::DINode::DIFlags Flags,
+                           llvm::DISubprogram::DISPFlags SPFlags);
+
   /// \return debug info descriptor to describe in-class static data
   /// member declaration for the given out-of-class definition.  If D
   /// is an out-of-class definition of a static data member of a
Index: clang/lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.cpp
+++ clang/lib/CodeGen/CGDebugInfo.cpp
@@ -3442,6 +3442,40 @@
   return nullptr;
 }
 
+llvm::DISubprogram *CGDebugInfo::getObjCMethodDeclaration(
+    const Decl *D, const ObjCContainerDecl *CD, llvm::DISubroutineType *FnType,
+    unsigned LineNo, llvm::DINode::DIFlags Flags,
+    llvm::DISubprogram::DISPFlags SPFlags) {
+  if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly)
+    return nullptr;
+
+  if (CGM.getCodeGenOpts().DwarfVersion < 5)
+    return nullptr;
+
+  // Starting with DWARF V5 method declarations are emitted as children of
+  // the interface type.
+  if (const auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
+    auto *ID = dyn_cast_or_null<ObjCInterfaceDecl>(CD);
+    if (!ID)
+      ID = OMD->getClassInterface();
+    if (ID) {
+      QualType QTy(ID->getTypeForDecl(), 0);
+      auto It = TypeCache.find(QTy.getAsOpaquePtr());
+      if (It != TypeCache.end()) {
+        auto *InterfaceType = cast<llvm::DICompositeType>(It->second);
+        llvm::DISubprogram *FD = DBuilder.createFunction(
+            InterfaceType, getObjCMethodName(OMD), StringRef(),
+            InterfaceType->getFile(), LineNo, FnType, LineNo, Flags,
+            SPFlags);
+        DBuilder.finalizeSubprogram(FD);
+        ObjCMethodCache[ID].push_back(FD);
+        return FD;
+      }
+    }
+  }
+  return nullptr;
+}
+
 // getOrCreateFunctionType - Construct type. If it is a c++ method, include
 // implicit parameter "this".
 llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D,
@@ -3517,7 +3551,8 @@
 void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc,
                                     SourceLocation ScopeLoc, QualType FnType,
                                     llvm::Function *Fn, bool CurFuncIsThunk,
-                                    CGBuilderTy &Builder) {
+                                    CGBuilderTy &Builder,
+                                    const ObjCContainerDecl *CD) {
 
   StringRef Name;
   StringRef LinkageName;
@@ -3584,6 +3619,7 @@
 
   unsigned LineNo = getLineNumber(Loc);
   unsigned ScopeLine = getLineNumber(ScopeLoc);
+  llvm::DISubroutineType *DIFnType = getOrCreateFunctionType(D, FnType, Unit);
 
   // FIXME: The function declaration we're constructing here is mostly reusing
   // declarations from CXXMethodDecl and not constructing new ones for arbitrary
@@ -3591,9 +3627,11 @@
   // all subprograms instead of the actual context since subprogram definitions
   // are emitted as CU level entities by the backend.
   llvm::DISubprogram *SP = DBuilder.createFunction(
-      FDContext, Name, LinkageName, Unit, LineNo,
-      getOrCreateFunctionType(D, FnType, Unit), ScopeLine, FlagsForDef,
-      SPFlagsForDef, TParamsArray.get(), getFunctionDeclaration(D));
+      FDContext, Name, LinkageName, Unit, LineNo, DIFnType, ScopeLine,
+      FlagsForDef, SPFlagsForDef, TParamsArray.get(),
+      isa<ObjCMethodDecl>(D)
+          ? getObjCMethodDeclaration(D, CD, DIFnType, LineNo, Flags, SPFlags)
+          : getFunctionDeclaration(D));
   Fn->setSubprogram(SP);
   // We might get here with a VarDecl in the case we're generating
   // code for the initialization of globals. Do not record these decls
@@ -3610,26 +3648,6 @@
       if (FD->hasBody() && !FD->param_empty())
         SPDefCache[FD].reset(SP);
 
-  if (CGM.getCodeGenOpts().DwarfVersion >= 5) {
-    // Starting with DWARF V5 method declarations are emitted as children of
-    // the interface type.
-    if (const auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) {
-      const ObjCInterfaceDecl *ID = OMD->getClassInterface();
-      QualType QTy(ID->getTypeForDecl(), 0);
-      auto It = TypeCache.find(QTy.getAsOpaquePtr());
-      if (It != TypeCache.end()) {
-        llvm::DICompositeType *InterfaceDecl =
-            cast<llvm::DICompositeType>(It->second);
-        llvm::DISubprogram *FD = DBuilder.createFunction(
-            InterfaceDecl, Name, LinkageName, Unit, LineNo,
-            getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags,
-            TParamsArray.get());
-        DBuilder.finalizeSubprogram(FD);
-        ObjCMethodCache[ID].push_back(FD);
-      }
-    }
-  }
-
   // Push the function onto the lexical block stack.
   LexicalBlockStack.emplace_back(SP);
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to