]> granicus.if.org Git - clang/commitdiff
Fully handle globals and functions in CGDebugInfo::getDeclarationOrDefinition()
authorFrederic Riss <friss@apple.com>
Tue, 18 Nov 2014 03:40:51 +0000 (03:40 +0000)
committerFrederic Riss <friss@apple.com>
Tue, 18 Nov 2014 03:40:51 +0000 (03:40 +0000)
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

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

lib/CodeGen/CGDebugInfo.cpp
lib/CodeGen/CGDebugInfo.h
test/CodeGenCXX/debug-info-namespace.cpp

index 8ba69eaa5c5a2249a6a48aaee6480a3e861e5d6a..b2a3f7e0e98bcc03c4b2131b97e167bc3d1aa023 100644 (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(),
index 896c54f13fdd9d92f3eaba7dbe18fde81a51d8b3..49d99aac2647ef4a5d0e86a33d9bdfc0c4fc827e 100644 (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
index da2fefdc328576b5c34cea7636f801222627d9a4..c999ce298c2478e95069179b23e1c060205b2024 100644 (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 !{}