Fully handle globals and functions in CGDebugInfo::getDeclarationOrDefinition()

Currently this function would return nothing for functions or globals that
haven't seen a definition yet. Make it return a forward declaration that will
get RAUWed with the definition if one is seen at a later point. The strategy
used to implement this is similar to what's done for types: the forward
declarations are stored in a vector and post processed upon finilization to
perform the required RAUWs.

For now the only user of getDeclarationOrDefinition() is EmitUsingDecl(), thus
this patch allows to emit correct imported declarations even in the absence of
an actual definition of the imported entity.

(Another user will be the debug info generation for argument default values
that I need to resurect).

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

llvm-svn: 222220
This commit is contained in:
Frederic Riss 2014-11-18 03:40:51 +00:00
parent 9db79f17c0
commit d253ed6565
3 changed files with 122 additions and 18 deletions

View File

@ -2374,6 +2374,58 @@ void CGDebugInfo::collectVarDeclProps(const VarDecl *VD, llvm::DIFile &Unit,
: VD->getDeclContext()));
}
llvm::DISubprogram
CGDebugInfo::getFunctionForwardDeclaration(const FunctionDecl *FD) {
llvm::DIArray TParamsArray;
StringRef Name, LinkageName;
unsigned Flags = 0;
SourceLocation Loc = FD->getLocation();
llvm::DIFile Unit = getOrCreateFile(Loc);
llvm::DIDescriptor DContext(Unit);
unsigned Line = getLineNumber(Loc);
collectFunctionDeclProps(FD, Unit, Name, LinkageName, DContext,
TParamsArray, Flags);
// Build function type.
SmallVector<QualType, 16> ArgTypes;
for (const ParmVarDecl *Parm: FD->parameters())
ArgTypes.push_back(Parm->getType());
QualType FnType =
CGM.getContext().getFunctionType(FD->getReturnType(), ArgTypes,
FunctionProtoType::ExtProtoInfo());
llvm::DISubprogram SP =
DBuilder.createTempFunctionFwdDecl(DContext, Name, LinkageName, Unit, Line,
getOrCreateFunctionType(FD, FnType, Unit),
!FD->isExternallyVisible(),
false /*declaration*/, 0, Flags,
CGM.getLangOpts().Optimize, nullptr,
TParamsArray, getFunctionDeclaration(FD));
const FunctionDecl *CanonDecl = cast<FunctionDecl>(FD->getCanonicalDecl());
FwdDeclReplaceMap.push_back(std::make_pair(CanonDecl,
static_cast<llvm::Value *>(SP)));
return SP;
}
llvm::DIGlobalVariable
CGDebugInfo::getGlobalVariableForwardDeclaration(const VarDecl *VD) {
QualType T;
StringRef Name, LinkageName;
SourceLocation Loc = VD->getLocation();
llvm::DIFile Unit = getOrCreateFile(Loc);
llvm::DIDescriptor DContext(Unit);
unsigned Line = getLineNumber(Loc);
collectVarDeclProps(VD, Unit, Line, T, Name, LinkageName, DContext);
llvm::DIGlobalVariable GV =
DBuilder.createTempGlobalVariableFwdDecl(DContext, Name, LinkageName, Unit,
Line, getOrCreateType(T, Unit),
!VD->isExternallyVisible(),
nullptr, nullptr);
FwdDeclReplaceMap.push_back(std::make_pair(cast<VarDecl>(VD->getCanonicalDecl()),
static_cast<llvm::Value *>(GV)));
return GV;
}
llvm::DIDescriptor CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
// We only need a declaration (not a definition) of the type - so use whatever
// we would otherwise do to get a type for a pointee. (forward declarations in
@ -2382,19 +2434,22 @@ llvm::DIDescriptor CGDebugInfo::getDeclarationOrDefinition(const Decl *D) {
if (const TypeDecl *TD = dyn_cast<TypeDecl>(D))
return getOrCreateType(CGM.getContext().getTypeDeclType(TD),
getOrCreateFile(TD->getLocation()));
// Otherwise fall back to a fairly rudimentary cache of existing declarations.
// This doesn't handle providing declarations (for functions or variables) for
// entities without definitions in this TU, nor when the definition proceeds
// the call to this function.
// FIXME: This should be split out into more specific maps with support for
// emitting forward declarations and merging definitions with declarations,
// the same way as we do for types.
llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator I =
DeclCache.find(D->getCanonicalDecl());
if (I == DeclCache.end())
return llvm::DIScope();
llvm::Value *V = I->second;
return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V));
if (I != DeclCache.end()) {
llvm::Value *V = I->second;
return llvm::DIDescriptor(dyn_cast_or_null<llvm::MDNode>(V));
}
// No definition for now. Emit a forward definition that might be
// merged with a potential upcoming definition.
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D))
return getFunctionForwardDeclaration(FD);
else if (const auto *VD = dyn_cast<VarDecl>(D))
return getGlobalVariableForwardDeclaration(VD);
return llvm::DIDescriptor();
}
/// getFunctionDeclaration - Return debug info descriptor to describe method
@ -3330,6 +3385,23 @@ void CGDebugInfo::finalize() {
Ty.replaceAllUsesWith(CGM.getLLVMContext(), RepTy);
}
for (const auto &p : FwdDeclReplaceMap) {
assert(p.second);
llvm::DIDescriptor FwdDecl(cast<llvm::MDNode>(p.second));
llvm::WeakVH VH;
auto it = DeclCache.find(p.first);
// If there has been no definition for the declaration, call RAUV
// with ourselves, that will destroy the temporary MDNode and
// replace it with a standard one, avoiding leaking memory.
if (it == DeclCache.end())
VH = p.second;
else
VH = it->second;
FwdDecl.replaceAllUsesWith(CGM.getLLVMContext(),
llvm::DIDescriptor(cast<llvm::MDNode>(VH)));
}
// We keep our own list of retained types, because we need to look
// up the final type in the type cache.
for (std::vector<void *>::const_iterator RI = RetainedTypes.begin(),

View File

@ -87,6 +87,10 @@ class CGDebugInfo {
/// compilation.
std::vector<std::pair<const TagType *, llvm::WeakVH>> ReplaceMap;
/// \brief Cache of replaceable forward declarartions (functions and
/// variables) to RAUW at the end of compilation.
std::vector<std::pair<const DeclaratorDecl *, llvm::WeakVH>> FwdDeclReplaceMap;
// LexicalBlockStack - Keep track of our current nested lexical block.
std::vector<llvm::TrackingVH<llvm::MDNode> > LexicalBlockStack;
llvm::DenseMap<const Decl *, llvm::WeakVH> RegionMap;
@ -376,6 +380,14 @@ private:
llvm::DIDerivedType
getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D);
/// \brief Create a DISubprogram describing the forward
/// decalration represented in the given FunctionDecl.
llvm::DISubprogram getFunctionForwardDeclaration(const FunctionDecl *FD);
/// \brief Create a DIGlobalVariable describing the forward
/// decalration represented in the given VarDecl.
llvm::DIGlobalVariable getGlobalVariableForwardDeclaration(const VarDecl *VD);
/// Return a global variable that represents one of the collection of
/// global variables created for an anonmyous union.
llvm::DIGlobalVariable

View File

@ -11,6 +11,10 @@ void f1(int) { }
struct foo;
struct bar { };
typedef bar baz;
extern int var_decl;
void func_decl(void);
extern int var_fwd;
void func_fwd(void);
}
}
namespace A {
@ -33,12 +37,20 @@ int func(bool b) {
using B::baz;
namespace X = A;
namespace Y = X;
using B::var_decl;
using B::func_decl;
using B::var_fwd;
using B::func_fwd;
return i + X::B::i + Y::B::i;
}
namespace A {
using B::i;
namespace B {
int var_fwd = i;
}
}
void B::func_fwd() {}
// This should work even if 'i' and 'func' were declarations & not definitions,
// but it doesn't yet.
@ -53,16 +65,19 @@ using B::i;
// CHECK: [[F1:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] [line 4] [def] [f1]
// CHECK: [[FILE2]]} ; [ DW_TAG_file_type ] [{{.*}}foo.cpp]
// CHECK: [[FUNC:![0-9]*]] {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
// CHECK: [[FUNC_FWD:![0-9]*]] {{.*}} [ DW_TAG_subprogram ] [line 47] [def] [func_fwd]
// CHECK: [[I:![0-9]*]] = metadata !{metadata !"0x34\00i\00{{.*}}", metadata [[NS]], {{.*}} ; [ DW_TAG_variable ] [i]
// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]], metadata [[M5:![0-9]*]], metadata [[M6:![0-9]*]], metadata [[M7:![0-9]*]], metadata [[M8:![0-9]*]], metadata [[M9:![0-9]*]], metadata [[M10:![0-9]*]], metadata [[M11:![0-9]*]], metadata [[M12:![0-9]*]], metadata [[M13:![0-9]*]]}
// CHECK: [[M1]] = metadata !{metadata !"0x3a\0011\00", metadata [[CTXT]], metadata [[NS]]} ; [ DW_TAG_imported_module ]
// CHECK: [[VAR_FWD:![0-9]*]] = metadata !{metadata !"0x34\00var_fwd\00{{.*}}", metadata [[NS]], {{.*}}} ; [ DW_TAG_variable ] [var_fwd] [line 44] [def]
// CHECK: [[MODULES]] = metadata !{metadata [[M1:![0-9]*]], metadata [[M2:![0-9]*]], metadata [[M3:![0-9]*]], metadata [[M4:![0-9]*]], metadata [[M5:![0-9]*]], metadata [[M6:![0-9]*]], metadata [[M7:![0-9]*]], metadata [[M8:![0-9]*]], metadata [[M9:![0-9]*]], metadata [[M10:![0-9]*]], metadata [[M11:![0-9]*]], metadata [[M12:![0-9]*]], metadata [[M13:![0-9]*]], metadata [[M14:![0-9]*]], metadata [[M15:![0-9]*]], metadata [[M16:![0-9]*]], metadata [[M17:![0-9]*]]}
// CHECK: [[M1]] = metadata !{metadata !"0x3a\0015\00", metadata [[CTXT]], metadata [[NS]]} ; [ DW_TAG_imported_module ]
// CHECK: [[M2]] = metadata !{metadata !"0x3a\00{{[0-9]+}}\00", metadata [[CU]], metadata [[CTXT]]} ; [ DW_TAG_imported_module ]
// CHECK: [[M3]] = metadata !{metadata !"0x8\0015\00E", metadata [[CU]], metadata [[CTXT]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M4]] = metadata !{metadata !"0x3a\0019\00", metadata [[LEX2:![0-9]*]], metadata [[NS]]} ; [ DW_TAG_imported_module ]
// CHECK: [[M3]] = metadata !{metadata !"0x8\0019\00E", metadata [[CU]], metadata [[CTXT]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M4]] = metadata !{metadata !"0x3a\0023\00", metadata [[LEX2:![0-9]*]], metadata [[NS]]} ; [ DW_TAG_imported_module ]
// CHECK: [[LEX2]] = metadata !{metadata !"0xb\00{{[0-9]*}}\000\00{{.*}}", metadata [[FILE2]], metadata [[LEX1:![0-9]+]]} ; [ DW_TAG_lexical_block ]
// CHECK: [[LEX1]] = metadata !{metadata !"0xb\00{{[0-9]*}}\000\00{{.*}}", metadata [[FILE2]], metadata [[FUNC]]} ; [ DW_TAG_lexical_block ]
// CHECK: [[M5]] = metadata !{metadata !"0x3a\00{{[0-9]+}}\00", metadata [[FUNC]], metadata [[CTXT]]} ; [ DW_TAG_imported_module ]
// CHECK: [[M6]] = metadata !{metadata !"0x8\0023\00", metadata [[FUNC]], metadata [[FOO:!"_ZTSN1A1B3fooE"]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M6]] = metadata !{metadata !"0x8\0027\00", metadata [[FUNC]], metadata [[FOO:!"_ZTSN1A1B3fooE"]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M7]] = metadata !{metadata !"0x8\00{{[0-9]+}}\00", metadata [[FUNC]], metadata [[BAR:!"_ZTSN1A1B3barE"]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M8]] = metadata !{metadata !"0x8\00{{[0-9]+}}\00", metadata [[FUNC]], metadata [[F1]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M9]] = metadata !{metadata !"0x8\00{{[0-9]+}}\00", metadata [[FUNC]], metadata [[I]]} ; [ DW_TAG_imported_declaration ]
@ -70,8 +85,13 @@ using B::i;
// CHECK: [[BAZ]] = metadata !{metadata !"0x16\00baz\00{{.*}}", metadata [[FOOCPP]], metadata [[NS]], metadata !"_ZTSN1A1B3barE"} ; [ DW_TAG_typedef ] [baz] {{.*}} [from _ZTSN1A1B3barE]
// CHECK: [[M11]] = metadata !{metadata !"0x8\00{{[0-9]+}}\00X", metadata [[FUNC]], metadata [[CTXT]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M12]] = metadata !{metadata !"0x8\00{{[0-9]+}}\00Y", metadata [[FUNC]], metadata [[M11]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M13]] = metadata !{metadata !"0x8\00{{[0-9]+}}\00", metadata [[CTXT]], metadata [[I]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M13]] = metadata !{metadata !"0x8\00{{[0-9]+}}\00", metadata [[FUNC]], metadata [[VAR_DECL:![0-9]*]]} ; [ DW_TAG_imported_declaration ]
// CHECK [[VAR_DECL]] = metadata !{metadata !"0x34\00var_decl\00{{.*}}", metadata [[NS]], {{.*}}} ; [ DW_TAG_variable ] [var_decl] [line 8]
// CHECK: [[M14]] = metadata !{metadata !"0x8\00{{[0-9]+}}\00", metadata [[FUNC]], metadata [[FUNC_DECL:![0-9]*]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[FUNC_DECL]] = metadata !{metadata !"0x2e\00func_decl\00{{.*}}", metadata [[FOOCPP]], metadata [[NS]], {{.*}}} ; [ DW_TAG_subprogram ] [line 9] [scope 0] [func_decl]
// CHECK: [[M15]] = metadata !{metadata !"0x8\00{{[0-9]+}}\00", metadata [[FUNC]], metadata [[VAR_FWD:![0-9]*]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M16]] = metadata !{metadata !"0x8\00{{[0-9]+}}\00", metadata [[FUNC]], metadata [[FUNC_FWD:![0-9]*]]} ; [ DW_TAG_imported_declaration ]
// CHECK: [[M17]] = metadata !{metadata !"0x8\00{{[0-9]+}}\00", metadata [[CTXT]], metadata [[I]]} ; [ DW_TAG_imported_declaration ]
// CHECK-GMLT: [[CU:![0-9]*]] = metadata !{metadata !"0x11\00{{.*}}\002"{{.*}}, metadata [[MODULES:![0-9]*]]} ; [ DW_TAG_compile_unit ]
// CHECK-GMLT: [[MODULES]] = metadata !{}