LLVM 23.0.0git
DWARFLinkerDeclContext.cpp
Go to the documentation of this file.
1//===- DWARFLinkerDeclContext.cpp -----------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
16
17namespace llvm {
18
19static std::optional<std::string>
21 std::string Result = Name.str();
22 raw_string_ostream OS(Result);
24 Printer.appendAndTerminateTemplateParameters(DIE);
25 if (Result == Name)
26 return std::nullopt;
27 return Result;
28}
29
30using namespace dwarf_linker;
31using namespace dwarf_linker::classic;
32
33/// Set the last DIE/CU a context was seen in and, possibly invalidate the
34/// context if it is ambiguous.
35///
36/// In the current implementation, we don't handle overloaded functions well,
37/// because the argument types are not taken into account when computing the
38/// DeclContext tree.
39///
40/// Some of this is mitigated byt using mangled names that do contain the
41/// arguments types, but sometimes (e.g. with function templates) we don't have
42/// that. In that case, just do not unique anything that refers to the contexts
43/// we are not able to distinguish.
44///
45/// If a context that is not a namespace appears twice in the same CU, we know
46/// it is ambiguous. Make it invalid.
48 if (LastSeenCompileUnitID == U.getUniqueID()) {
49 DWARFUnit &OrigUnit = U.getOrigUnit();
50 uint32_t FirstIdx = OrigUnit.getDIEIndex(LastSeenDIE);
51 U.getInfo(FirstIdx).Ctxt = nullptr;
52 return false;
53 }
54
55 LastSeenCompileUnitID = U.getUniqueID();
56 LastSeenDIE = Die;
57 return true;
58}
59
62 CompileUnit &U, bool InClangModule) {
63 unsigned Tag = DIE.getTag();
64
65 // FIXME: dsymutil-classic compat: We should bail out here if we
66 // have a specification or an abstract_origin. We will get the
67 // parent context wrong here.
68
69 switch (Tag) {
70 default:
71 // By default stop gathering child contexts.
73 case dwarf::DW_TAG_module:
74 break;
75 case dwarf::DW_TAG_compile_unit:
76 return PointerIntPair<DeclContext *, 1>(&Context);
77 case dwarf::DW_TAG_subprogram:
78 // Do not unique anything inside CU local functions.
79 if ((Context.getTag() == dwarf::DW_TAG_namespace ||
80 Context.getTag() == dwarf::DW_TAG_compile_unit) &&
81 !dwarf::toUnsigned(DIE.find(dwarf::DW_AT_external), 0))
83 [[fallthrough]];
84 case dwarf::DW_TAG_member:
85 case dwarf::DW_TAG_namespace:
86 case dwarf::DW_TAG_structure_type:
87 case dwarf::DW_TAG_class_type:
88 case dwarf::DW_TAG_union_type:
89 case dwarf::DW_TAG_enumeration_type:
90 case dwarf::DW_TAG_typedef:
91 // Artificial things might be ambiguous, because they might be created on
92 // demand. For example implicitly defined constructors are ambiguous
93 // because of the way we identify contexts, and they won't be generated
94 // every time everywhere.
95 if (dwarf::toUnsigned(DIE.find(dwarf::DW_AT_artificial), 0))
97 break;
98 }
99
100 StringRef Name = DIE.getShortName();
101 StringRef NameForUniquing;
102 StringRef FileRef;
103
104 if (const char *LinkageName = DIE.getLinkageName()) {
105 NameForUniquing = StringPool.internString(LinkageName);
106 } else if (!Name.empty()) {
107 // With -gsimple-template-names, DW_AT_name omits template parameters
108 // ("vector" instead of "vector<int>"). Reconstruct them from child
109 // DW_TAG_template_*_parameter DIEs so different specializations get
110 // distinct uniquing names.
111 bool HasTemplateParamsInName =
112 Name.ends_with(">") && !Name.ends_with("<=>") && Name.contains('<');
113 std::optional<std::string> FullName;
114 if (!HasTemplateParamsInName)
115 FullName = makeSimpleTemplateNameWithParams(Name, DIE);
116 NameForUniquing = StringPool.internString(FullName ? *FullName : Name);
117 }
118
119 bool IsAnonymousNamespace =
120 NameForUniquing.empty() && Tag == dwarf::DW_TAG_namespace;
121 if (IsAnonymousNamespace) {
122 // FIXME: For dsymutil-classic compatibility. I think uniquing within
123 // anonymous namespaces is wrong. There is no ODR guarantee there.
124 NameForUniquing = "(anonymous namespace)";
125 }
126
127 if (Tag != dwarf::DW_TAG_class_type && Tag != dwarf::DW_TAG_structure_type &&
128 Tag != dwarf::DW_TAG_union_type &&
129 Tag != dwarf::DW_TAG_enumeration_type && NameForUniquing.empty())
130 return PointerIntPair<DeclContext *, 1>(nullptr);
131
132 unsigned Line = 0;
133 unsigned ByteSize = std::numeric_limits<uint32_t>::max();
134
135 if (!InClangModule) {
136 // Gather some discriminating data about the DeclContext we will be
137 // creating: File, line number and byte size. This shouldn't be necessary,
138 // because the ODR is just about names, but given that we do some
139 // approximations with overloaded functions and anonymous namespaces, use
140 // these additional data points to make the process safer.
141 //
142 // This is disabled for clang modules, because forward declarations of
143 // module-defined types do not have a file and line.
144 ByteSize = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_byte_size),
145 std::numeric_limits<uint64_t>::max());
146 if (Tag != dwarf::DW_TAG_namespace || IsAnonymousNamespace) {
147 if (unsigned FileNum =
148 dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_file), 0)) {
149 if (const auto *LT = U.getOrigUnit().getContext().getLineTableForUnit(
150 &U.getOrigUnit())) {
151 // FIXME: dsymutil-classic compatibility. I'd rather not
152 // unique anything in anonymous namespaces, but if we do, then
153 // verify that the file and line correspond.
154 if (IsAnonymousNamespace)
155 FileNum = 1;
156
157 if (LT->hasFileAtIndex(FileNum)) {
158 Line = dwarf::toUnsigned(DIE.find(dwarf::DW_AT_decl_line), 0);
159 // Cache the resolved paths based on the index in the line table,
160 // because calling realpath is expensive.
161 FileRef = getResolvedPath(U, FileNum, *LT);
162 }
163 }
164 }
165 }
166 }
167
168 if (!Line && NameForUniquing.empty())
169 return PointerIntPair<DeclContext *, 1>(nullptr);
170
171 // We hash NameForUniquing, which is the mangled name, in order to get most
172 // overloaded functions resolve correctly.
173 //
174 // Strictly speaking, hashing the Tag is only necessary for a
175 // DW_TAG_module, to prevent uniquing of a module and a namespace
176 // with the same name.
177 //
178 // FIXME: dsymutil-classic won't unique the same type presented
179 // once as a struct and once as a class. Using the Tag in the fully
180 // qualified name hash to get the same effect.
181 unsigned Hash =
182 hash_combine(Context.getQualifiedNameHash(), Tag, NameForUniquing);
183
184 // FIXME: dsymutil-classic compatibility: when we don't have a name,
185 // use the filename.
186 if (IsAnonymousNamespace)
187 Hash = hash_combine(Hash, FileRef);
188
189 // Now look if this context already exists.
190 DeclContext Key(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef,
191 Context);
192 auto ContextIter = Contexts.find(&Key);
193
194 if (ContextIter == Contexts.end()) {
195 // The context wasn't found.
196 bool Inserted;
197 DeclContext *NewContext = new (Allocator)
198 DeclContext(Hash, Line, ByteSize, Tag, Name, NameForUniquing, FileRef,
199 Context, DIE, U.getUniqueID());
200 std::tie(ContextIter, Inserted) = Contexts.insert(NewContext);
201 assert(Inserted && "Failed to insert DeclContext");
202 (void)Inserted;
203 } else if (Tag != dwarf::DW_TAG_namespace &&
204 !(*ContextIter)->setLastSeenDIE(U, DIE)) {
205 // The context was found, but it is ambiguous with another context
206 // in the same file. Mark it invalid.
207 return PointerIntPair<DeclContext *, 1>(*ContextIter, /* IntVal= */ 1);
208 }
209
210 assert(ContextIter != Contexts.end());
211 // FIXME: dsymutil-classic compatibility. Union types aren't
212 // uniques, but their children might be.
213 if ((Tag == dwarf::DW_TAG_subprogram &&
214 Context.getTag() != dwarf::DW_TAG_structure_type &&
215 Context.getTag() != dwarf::DW_TAG_class_type) ||
216 (Tag == dwarf::DW_TAG_union_type))
217 return PointerIntPair<DeclContext *, 1>(*ContextIter, /* IntVal= */ 1);
218
219 return PointerIntPair<DeclContext *, 1>(*ContextIter);
220}
221
223DeclContextTree::getResolvedPath(CompileUnit &CU, unsigned FileNum,
224 const DWARFDebugLine::LineTable &LineTable) {
225 std::pair<unsigned, unsigned> Key = {CU.getUniqueID(), FileNum};
226
227 ResolvedPathsMap::const_iterator It = ResolvedPaths.find(Key);
228 if (It == ResolvedPaths.end()) {
229 std::string FileName;
230 bool FoundFileName = LineTable.getFileNameByIndex(
231 FileNum, CU.getOrigUnit().getCompilationDir(),
233 (void)FoundFileName;
234 assert(FoundFileName && "Must get file name from line table");
235
236 // Second level of caching, this time based on the file's parent
237 // path.
238 StringRef ResolvedPath = PathResolver.resolve(FileName, StringPool);
239
240 It = ResolvedPaths.insert(std::make_pair(Key, ResolvedPath)).first;
241 }
242
243 return It->second;
244}
245
246} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
amdgpu next use AMDGPU Next Use Analysis Printer
A structured debug information entry.
Definition DIE.h:828
dwarf::Tag getTag() const
Definition DIE.h:864
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
Definition DWARFDie.h:43
uint32_t getDIEIndex(const DWARFDebugInfoEntry *Die) const
Return the index of a Die entry inside the unit's DIE vector.
Definition DWARFUnit.h:276
PointerIntPair - This class implements a pair of a pointer and small integer.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
constexpr bool empty() const
empty - Check if the string is empty.
Definition StringRef.h:140
StringRef resolve(const std::string &Path, NonRelocatableStringpool &StringPool)
Resolve a path by calling realpath and cache its result.
Stores all information relating to a compile unit, be it in its original instance in the object file ...
PointerIntPair< DeclContext *, 1 > getChildDeclContext(DeclContext &Context, const DWARFDie &DIE, CompileUnit &Unit, bool InClangModule)
Get the child of Context described by DIE in Unit.
A DeclContext is a named program scope that is used for ODR uniquing of types.
bool setLastSeenDIE(CompileUnit &U, const DWARFDie &Die)
Set the last DIE/CU a context was seen in and, possibly invalidate the context if it is ambiguous.
A raw_ostream that writes to an std::string.
std::optional< uint64_t > toUnsigned(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an unsigned constant.
This is an optimization pass for GlobalISel generic memory operations.
static std::optional< std::string > makeSimpleTemplateNameWithParams(StringRef Name, const DWARFDie &DIE)
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition Hashing.h:592
bool getFileNameByIndex(uint64_t FileIndex, StringRef CompDir, DILineInfoSpecifier::FileLineInfoKind Kind, std::string &Result) const
Extracts filename by its index in filename table in prologue.