Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -1375,21 +1375,32 @@ }; class ImplicitParamDecl : public VarDecl { + friend class ASTDeclReader; + + /// Whether this parameter represents implicit 'this'|'self' argument in + /// member functions. + bool IsThisOrSelf; void anchor() override; + public: static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, IdentifierInfo *Id, - QualType T); + QualType T, bool IsThisOrSelf = false); static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID); ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, - IdentifierInfo *Id, QualType Type) - : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type, - /*tinfo*/ nullptr, SC_None) { + IdentifierInfo *Id, QualType Type, + bool IsThisOrSelf = false) + : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type, + /*tinfo*/ nullptr, SC_None), + IsThisOrSelf(IsThisOrSelf) { setImplicit(); } + /// Returns true if the parameter represents implicit 'this' or 'self' + /// argument in member functions. + bool isThisOrSelfParam() const { return IsThisOrSelf; } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == ImplicitParam; } Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -4107,9 +4107,9 @@ ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, - IdentifierInfo *Id, - QualType Type) { - return new (C, DC) ImplicitParamDecl(C, DC, IdLoc, Id, Type); + IdentifierInfo *Id, QualType Type, + bool IsThisOrSelf) { + return new (C, DC) ImplicitParamDecl(C, DC, IdLoc, Id, Type, IsThisOrSelf); } ImplicitParamDecl *ImplicitParamDecl::CreateDeserialized(ASTContext &C, Index: lib/AST/DeclObjC.cpp =================================================================== --- lib/AST/DeclObjC.cpp +++ lib/AST/DeclObjC.cpp @@ -1070,9 +1070,9 @@ bool selfIsPseudoStrong, selfIsConsumed; QualType selfTy = getSelfType(Context, OID, selfIsPseudoStrong, selfIsConsumed); - ImplicitParamDecl *self - = ImplicitParamDecl::Create(Context, this, SourceLocation(), - &Context.Idents.get("self"), selfTy); + ImplicitParamDecl *self = ImplicitParamDecl::Create( + Context, this, SourceLocation(), &Context.Idents.get("self"), selfTy, + /*IsThisOrSelf=*/true); setSelfDecl(self); if (selfIsConsumed) Index: lib/CodeGen/CGCXXABI.cpp =================================================================== --- lib/CodeGen/CGCXXABI.cpp +++ lib/CodeGen/CGCXXABI.cpp @@ -159,10 +159,10 @@ // FIXME: I'm not entirely sure I like using a fake decl just for code // generation. Maybe we can come up with a better way? - ImplicitParamDecl *ThisDecl - = ImplicitParamDecl::Create(CGM.getContext(), nullptr, MD->getLocation(), - &CGM.getContext().Idents.get("this"), - MD->getThisType(CGM.getContext())); + ImplicitParamDecl *ThisDecl = ImplicitParamDecl::Create( + CGM.getContext(), nullptr, MD->getLocation(), + &CGM.getContext().Idents.get("this"), MD->getThisType(CGM.getContext()), + /*IsThisOrSelf=*/true); params.push_back(ThisDecl); CGF.CXXABIThisDecl = ThisDecl; Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -3462,13 +3462,12 @@ unsigned AddressSpace = CGM.getContext().getTargetAddressSpace(VD->getType()); AppendAddressSpaceXDeref(AddressSpace, Expr); - // If this is the first argument and it is implicit then - // give it an object pointer flag. - // FIXME: There has to be a better way to do this, but for static - // functions there won't be an implicit param at arg1 and - // otherwise it is 'self' or 'this'. - if (isa(VD) && ArgNo && *ArgNo == 1) - Flags |= llvm::DINode::FlagObjectPointer; + // If this is the first argument, it is implicit and has ThisOrSelf attribute + // then give it an object pointer flag. + if (ArgNo && *ArgNo == 1) + if (auto *IPD = dyn_cast(VD)) + if (IPD->isThisOrSelfParam()) + Flags |= llvm::DINode::FlagObjectPointer; // Note: Older versions of clang used to emit byval references with an extra // DW_OP_deref, because they referenced the IR arg directly instead of Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -1278,6 +1278,7 @@ void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) { VisitVarDecl(PD); + PD->IsThisOrSelf = Record.readInt(); } void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -967,6 +967,7 @@ void ASTDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) { VisitVarDecl(D); + Record.push_back(D->isThisOrSelfParam()); Code = serialization::DECL_IMPLICIT_PARAM; } Index: test/CodeGen/captured-statements.c =================================================================== --- test/CodeGen/captured-statements.c +++ test/CodeGen/captured-statements.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o %t +// RUN: %clang_cc1 -triple %itanium_abi_triple -emit-llvm %s -o %t -debug-info-kind=limited // RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-GLOBALS // RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-1 // RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-2 @@ -98,3 +98,8 @@ // CHECK-GLOBALS: load i32, i32* @global // CHECK-GLOBALS: load i32, i32* @ // CHECK-GLOBALS: load i32, i32* @e + +// CHECK-GLOBALS-NOT: DIFlagObjectPointer +// CHECK-1-NOT: DIFlagObjectPointer +// CHECK-2-NOT: DIFlagObjectPointer +// CHECK-3-NOT: DIFlagObjectPointer Index: test/CodeGenCXX/captured-statements.cpp =================================================================== --- test/CodeGenCXX/captured-statements.cpp +++ test/CodeGenCXX/captured-statements.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -emit-llvm %s -o %t +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -emit-llvm %s -o %t -debug-info-kind=limited // RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-1 // RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-2 // RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-3 @@ -194,3 +194,18 @@ void call_test_captured_linkage() { test_captured_linkage(); } + +// CHECK-1-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer) +// CHECK-1-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial) +// CHECK-2-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer) +// CHECK-2-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial) +// CHECK-3-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer) +// CHECK-3-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial) +// CHECK-4-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer) +// CHECK-4-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial) +// CHECK-5-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer) +// CHECK-5-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial) +// CHECK-6-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer) +// CHECK-6-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial) +// CHECK-7-DAG: !DILocalVariable(name: "this", {{.*}}, flags: DIFlagArtificial | DIFlagObjectPointer) +// CHECK-7-DAG: !DILocalVariable(name: "__context", {{.*}}, flags: DIFlagArtificial)