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(D)) { + auto *ID = dyn_cast_or_null(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(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(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(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(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); 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/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/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 {} +@end + +struct Bar {}; + +@protocol BarProto +@property struct Bar *bar; +@end + +@interface Foo +@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]+]]