150
|
1 //===--- APValue.cpp - Union class for APFloat/APSInt/Complex -------------===//
|
|
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 //
|
|
9 // This file implements the APValue class.
|
|
10 //
|
|
11 //===----------------------------------------------------------------------===//
|
|
12
|
|
13 #include "clang/AST/APValue.h"
|
|
14 #include "clang/AST/ASTContext.h"
|
|
15 #include "clang/AST/CharUnits.h"
|
|
16 #include "clang/AST/DeclCXX.h"
|
|
17 #include "clang/AST/Expr.h"
|
|
18 #include "clang/AST/Type.h"
|
|
19 #include "llvm/Support/ErrorHandling.h"
|
|
20 #include "llvm/Support/raw_ostream.h"
|
|
21 using namespace clang;
|
|
22
|
|
23 /// The identity of a type_info object depends on the canonical unqualified
|
|
24 /// type only.
|
|
25 TypeInfoLValue::TypeInfoLValue(const Type *T)
|
|
26 : T(T->getCanonicalTypeUnqualified().getTypePtr()) {}
|
|
27
|
|
28 void TypeInfoLValue::print(llvm::raw_ostream &Out,
|
|
29 const PrintingPolicy &Policy) const {
|
|
30 Out << "typeid(";
|
|
31 QualType(getType(), 0).print(Out, Policy);
|
|
32 Out << ")";
|
|
33 }
|
|
34
|
|
35 static_assert(
|
|
36 1 << llvm::PointerLikeTypeTraits<TypeInfoLValue>::NumLowBitsAvailable <=
|
|
37 alignof(Type),
|
|
38 "Type is insufficiently aligned");
|
|
39
|
|
40 APValue::LValueBase::LValueBase(const ValueDecl *P, unsigned I, unsigned V)
|
|
41 : Ptr(P), Local{I, V} {}
|
|
42 APValue::LValueBase::LValueBase(const Expr *P, unsigned I, unsigned V)
|
|
43 : Ptr(P), Local{I, V} {}
|
|
44
|
|
45 APValue::LValueBase APValue::LValueBase::getDynamicAlloc(DynamicAllocLValue LV,
|
|
46 QualType Type) {
|
|
47 LValueBase Base;
|
|
48 Base.Ptr = LV;
|
|
49 Base.DynamicAllocType = Type.getAsOpaquePtr();
|
|
50 return Base;
|
|
51 }
|
|
52
|
|
53 APValue::LValueBase APValue::LValueBase::getTypeInfo(TypeInfoLValue LV,
|
|
54 QualType TypeInfo) {
|
|
55 LValueBase Base;
|
|
56 Base.Ptr = LV;
|
|
57 Base.TypeInfoType = TypeInfo.getAsOpaquePtr();
|
|
58 return Base;
|
|
59 }
|
|
60
|
|
61 unsigned APValue::LValueBase::getCallIndex() const {
|
|
62 return (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) ? 0
|
|
63 : Local.CallIndex;
|
|
64 }
|
|
65
|
|
66 unsigned APValue::LValueBase::getVersion() const {
|
|
67 return (is<TypeInfoLValue>() || is<DynamicAllocLValue>()) ? 0 : Local.Version;
|
|
68 }
|
|
69
|
|
70 QualType APValue::LValueBase::getTypeInfoType() const {
|
|
71 assert(is<TypeInfoLValue>() && "not a type_info lvalue");
|
|
72 return QualType::getFromOpaquePtr(TypeInfoType);
|
|
73 }
|
|
74
|
|
75 QualType APValue::LValueBase::getDynamicAllocType() const {
|
|
76 assert(is<DynamicAllocLValue>() && "not a dynamic allocation lvalue");
|
|
77 return QualType::getFromOpaquePtr(DynamicAllocType);
|
|
78 }
|
|
79
|
|
80 namespace clang {
|
|
81 bool operator==(const APValue::LValueBase &LHS,
|
|
82 const APValue::LValueBase &RHS) {
|
|
83 if (LHS.Ptr != RHS.Ptr)
|
|
84 return false;
|
|
85 if (LHS.is<TypeInfoLValue>())
|
|
86 return true;
|
|
87 return LHS.Local.CallIndex == RHS.Local.CallIndex &&
|
|
88 LHS.Local.Version == RHS.Local.Version;
|
|
89 }
|
|
90 }
|
|
91
|
|
92 namespace {
|
|
93 struct LVBase {
|
|
94 APValue::LValueBase Base;
|
|
95 CharUnits Offset;
|
|
96 unsigned PathLength;
|
|
97 bool IsNullPtr : 1;
|
|
98 bool IsOnePastTheEnd : 1;
|
|
99 };
|
|
100 }
|
|
101
|
|
102 void *APValue::LValueBase::getOpaqueValue() const {
|
|
103 return Ptr.getOpaqueValue();
|
|
104 }
|
|
105
|
|
106 bool APValue::LValueBase::isNull() const {
|
|
107 return Ptr.isNull();
|
|
108 }
|
|
109
|
|
110 APValue::LValueBase::operator bool () const {
|
|
111 return static_cast<bool>(Ptr);
|
|
112 }
|
|
113
|
|
114 clang::APValue::LValueBase
|
|
115 llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() {
|
|
116 return clang::APValue::LValueBase(
|
|
117 DenseMapInfo<const ValueDecl*>::getEmptyKey());
|
|
118 }
|
|
119
|
|
120 clang::APValue::LValueBase
|
|
121 llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() {
|
|
122 return clang::APValue::LValueBase(
|
|
123 DenseMapInfo<const ValueDecl*>::getTombstoneKey());
|
|
124 }
|
|
125
|
|
126 namespace clang {
|
|
127 llvm::hash_code hash_value(const APValue::LValueBase &Base) {
|
|
128 if (Base.is<TypeInfoLValue>() || Base.is<DynamicAllocLValue>())
|
|
129 return llvm::hash_value(Base.getOpaqueValue());
|
|
130 return llvm::hash_combine(Base.getOpaqueValue(), Base.getCallIndex(),
|
|
131 Base.getVersion());
|
|
132 }
|
|
133 }
|
|
134
|
|
135 unsigned llvm::DenseMapInfo<clang::APValue::LValueBase>::getHashValue(
|
|
136 const clang::APValue::LValueBase &Base) {
|
|
137 return hash_value(Base);
|
|
138 }
|
|
139
|
|
140 bool llvm::DenseMapInfo<clang::APValue::LValueBase>::isEqual(
|
|
141 const clang::APValue::LValueBase &LHS,
|
|
142 const clang::APValue::LValueBase &RHS) {
|
|
143 return LHS == RHS;
|
|
144 }
|
|
145
|
|
146 struct APValue::LV : LVBase {
|
|
147 static const unsigned InlinePathSpace =
|
|
148 (DataSize - sizeof(LVBase)) / sizeof(LValuePathEntry);
|
|
149
|
|
150 /// Path - The sequence of base classes, fields and array indices to follow to
|
|
151 /// walk from Base to the subobject. When performing GCC-style folding, there
|
|
152 /// may not be such a path.
|
|
153 union {
|
|
154 LValuePathEntry Path[InlinePathSpace];
|
|
155 LValuePathEntry *PathPtr;
|
|
156 };
|
|
157
|
|
158 LV() { PathLength = (unsigned)-1; }
|
|
159 ~LV() { resizePath(0); }
|
|
160
|
|
161 void resizePath(unsigned Length) {
|
|
162 if (Length == PathLength)
|
|
163 return;
|
|
164 if (hasPathPtr())
|
|
165 delete [] PathPtr;
|
|
166 PathLength = Length;
|
|
167 if (hasPathPtr())
|
|
168 PathPtr = new LValuePathEntry[Length];
|
|
169 }
|
|
170
|
|
171 bool hasPath() const { return PathLength != (unsigned)-1; }
|
|
172 bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; }
|
|
173
|
|
174 LValuePathEntry *getPath() { return hasPathPtr() ? PathPtr : Path; }
|
|
175 const LValuePathEntry *getPath() const {
|
|
176 return hasPathPtr() ? PathPtr : Path;
|
|
177 }
|
|
178 };
|
|
179
|
|
180 namespace {
|
|
181 struct MemberPointerBase {
|
|
182 llvm::PointerIntPair<const ValueDecl*, 1, bool> MemberAndIsDerivedMember;
|
|
183 unsigned PathLength;
|
|
184 };
|
|
185 }
|
|
186
|
|
187 struct APValue::MemberPointerData : MemberPointerBase {
|
|
188 static const unsigned InlinePathSpace =
|
|
189 (DataSize - sizeof(MemberPointerBase)) / sizeof(const CXXRecordDecl*);
|
|
190 typedef const CXXRecordDecl *PathElem;
|
|
191 union {
|
|
192 PathElem Path[InlinePathSpace];
|
|
193 PathElem *PathPtr;
|
|
194 };
|
|
195
|
|
196 MemberPointerData() { PathLength = 0; }
|
|
197 ~MemberPointerData() { resizePath(0); }
|
|
198
|
|
199 void resizePath(unsigned Length) {
|
|
200 if (Length == PathLength)
|
|
201 return;
|
|
202 if (hasPathPtr())
|
|
203 delete [] PathPtr;
|
|
204 PathLength = Length;
|
|
205 if (hasPathPtr())
|
|
206 PathPtr = new PathElem[Length];
|
|
207 }
|
|
208
|
|
209 bool hasPathPtr() const { return PathLength > InlinePathSpace; }
|
|
210
|
|
211 PathElem *getPath() { return hasPathPtr() ? PathPtr : Path; }
|
|
212 const PathElem *getPath() const {
|
|
213 return hasPathPtr() ? PathPtr : Path;
|
|
214 }
|
|
215 };
|
|
216
|
|
217 // FIXME: Reduce the malloc traffic here.
|
|
218
|
|
219 APValue::Arr::Arr(unsigned NumElts, unsigned Size) :
|
|
220 Elts(new APValue[NumElts + (NumElts != Size ? 1 : 0)]),
|
|
221 NumElts(NumElts), ArrSize(Size) {}
|
|
222 APValue::Arr::~Arr() { delete [] Elts; }
|
|
223
|
|
224 APValue::StructData::StructData(unsigned NumBases, unsigned NumFields) :
|
|
225 Elts(new APValue[NumBases+NumFields]),
|
|
226 NumBases(NumBases), NumFields(NumFields) {}
|
|
227 APValue::StructData::~StructData() {
|
|
228 delete [] Elts;
|
|
229 }
|
|
230
|
|
231 APValue::UnionData::UnionData() : Field(nullptr), Value(new APValue) {}
|
|
232 APValue::UnionData::~UnionData () {
|
|
233 delete Value;
|
|
234 }
|
|
235
|
|
236 APValue::APValue(const APValue &RHS) : Kind(None) {
|
|
237 switch (RHS.getKind()) {
|
|
238 case None:
|
|
239 case Indeterminate:
|
|
240 Kind = RHS.getKind();
|
|
241 break;
|
|
242 case Int:
|
|
243 MakeInt();
|
|
244 setInt(RHS.getInt());
|
|
245 break;
|
|
246 case Float:
|
|
247 MakeFloat();
|
|
248 setFloat(RHS.getFloat());
|
|
249 break;
|
|
250 case FixedPoint: {
|
|
251 APFixedPoint FXCopy = RHS.getFixedPoint();
|
|
252 MakeFixedPoint(std::move(FXCopy));
|
|
253 break;
|
|
254 }
|
|
255 case Vector:
|
|
256 MakeVector();
|
|
257 setVector(((const Vec *)(const char *)RHS.Data.buffer)->Elts,
|
|
258 RHS.getVectorLength());
|
|
259 break;
|
|
260 case ComplexInt:
|
|
261 MakeComplexInt();
|
|
262 setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag());
|
|
263 break;
|
|
264 case ComplexFloat:
|
|
265 MakeComplexFloat();
|
|
266 setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag());
|
|
267 break;
|
|
268 case LValue:
|
|
269 MakeLValue();
|
|
270 if (RHS.hasLValuePath())
|
|
271 setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(),
|
|
272 RHS.isLValueOnePastTheEnd(), RHS.isNullPointer());
|
|
273 else
|
|
274 setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(),
|
|
275 RHS.isNullPointer());
|
|
276 break;
|
|
277 case Array:
|
|
278 MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize());
|
|
279 for (unsigned I = 0, N = RHS.getArrayInitializedElts(); I != N; ++I)
|
|
280 getArrayInitializedElt(I) = RHS.getArrayInitializedElt(I);
|
|
281 if (RHS.hasArrayFiller())
|
|
282 getArrayFiller() = RHS.getArrayFiller();
|
|
283 break;
|
|
284 case Struct:
|
|
285 MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields());
|
|
286 for (unsigned I = 0, N = RHS.getStructNumBases(); I != N; ++I)
|
|
287 getStructBase(I) = RHS.getStructBase(I);
|
|
288 for (unsigned I = 0, N = RHS.getStructNumFields(); I != N; ++I)
|
|
289 getStructField(I) = RHS.getStructField(I);
|
|
290 break;
|
|
291 case Union:
|
|
292 MakeUnion();
|
|
293 setUnion(RHS.getUnionField(), RHS.getUnionValue());
|
|
294 break;
|
|
295 case MemberPointer:
|
|
296 MakeMemberPointer(RHS.getMemberPointerDecl(),
|
|
297 RHS.isMemberPointerToDerivedMember(),
|
|
298 RHS.getMemberPointerPath());
|
|
299 break;
|
|
300 case AddrLabelDiff:
|
|
301 MakeAddrLabelDiff();
|
|
302 setAddrLabelDiff(RHS.getAddrLabelDiffLHS(), RHS.getAddrLabelDiffRHS());
|
|
303 break;
|
|
304 }
|
|
305 }
|
|
306
|
|
307 void APValue::DestroyDataAndMakeUninit() {
|
|
308 if (Kind == Int)
|
|
309 ((APSInt*)(char*)Data.buffer)->~APSInt();
|
|
310 else if (Kind == Float)
|
|
311 ((APFloat*)(char*)Data.buffer)->~APFloat();
|
|
312 else if (Kind == FixedPoint)
|
|
313 ((APFixedPoint *)(char *)Data.buffer)->~APFixedPoint();
|
|
314 else if (Kind == Vector)
|
|
315 ((Vec*)(char*)Data.buffer)->~Vec();
|
|
316 else if (Kind == ComplexInt)
|
|
317 ((ComplexAPSInt*)(char*)Data.buffer)->~ComplexAPSInt();
|
|
318 else if (Kind == ComplexFloat)
|
|
319 ((ComplexAPFloat*)(char*)Data.buffer)->~ComplexAPFloat();
|
|
320 else if (Kind == LValue)
|
|
321 ((LV*)(char*)Data.buffer)->~LV();
|
|
322 else if (Kind == Array)
|
|
323 ((Arr*)(char*)Data.buffer)->~Arr();
|
|
324 else if (Kind == Struct)
|
|
325 ((StructData*)(char*)Data.buffer)->~StructData();
|
|
326 else if (Kind == Union)
|
|
327 ((UnionData*)(char*)Data.buffer)->~UnionData();
|
|
328 else if (Kind == MemberPointer)
|
|
329 ((MemberPointerData*)(char*)Data.buffer)->~MemberPointerData();
|
|
330 else if (Kind == AddrLabelDiff)
|
|
331 ((AddrLabelDiffData*)(char*)Data.buffer)->~AddrLabelDiffData();
|
|
332 Kind = None;
|
|
333 }
|
|
334
|
|
335 bool APValue::needsCleanup() const {
|
|
336 switch (getKind()) {
|
|
337 case None:
|
|
338 case Indeterminate:
|
|
339 case AddrLabelDiff:
|
|
340 return false;
|
|
341 case Struct:
|
|
342 case Union:
|
|
343 case Array:
|
|
344 case Vector:
|
|
345 return true;
|
|
346 case Int:
|
|
347 return getInt().needsCleanup();
|
|
348 case Float:
|
|
349 return getFloat().needsCleanup();
|
|
350 case FixedPoint:
|
|
351 return getFixedPoint().getValue().needsCleanup();
|
|
352 case ComplexFloat:
|
|
353 assert(getComplexFloatImag().needsCleanup() ==
|
|
354 getComplexFloatReal().needsCleanup() &&
|
|
355 "In _Complex float types, real and imaginary values always have the "
|
|
356 "same size.");
|
|
357 return getComplexFloatReal().needsCleanup();
|
|
358 case ComplexInt:
|
|
359 assert(getComplexIntImag().needsCleanup() ==
|
|
360 getComplexIntReal().needsCleanup() &&
|
|
361 "In _Complex int types, real and imaginary values must have the "
|
|
362 "same size.");
|
|
363 return getComplexIntReal().needsCleanup();
|
|
364 case LValue:
|
|
365 return reinterpret_cast<const LV *>(Data.buffer)->hasPathPtr();
|
|
366 case MemberPointer:
|
|
367 return reinterpret_cast<const MemberPointerData *>(Data.buffer)
|
|
368 ->hasPathPtr();
|
|
369 }
|
|
370 llvm_unreachable("Unknown APValue kind!");
|
|
371 }
|
|
372
|
|
373 void APValue::swap(APValue &RHS) {
|
|
374 std::swap(Kind, RHS.Kind);
|
|
375 char TmpData[DataSize];
|
|
376 memcpy(TmpData, Data.buffer, DataSize);
|
|
377 memcpy(Data.buffer, RHS.Data.buffer, DataSize);
|
|
378 memcpy(RHS.Data.buffer, TmpData, DataSize);
|
|
379 }
|
|
380
|
|
381 LLVM_DUMP_METHOD void APValue::dump() const {
|
|
382 dump(llvm::errs());
|
|
383 llvm::errs() << '\n';
|
|
384 }
|
|
385
|
|
386 static double GetApproxValue(const llvm::APFloat &F) {
|
|
387 llvm::APFloat V = F;
|
|
388 bool ignored;
|
|
389 V.convert(llvm::APFloat::IEEEdouble(), llvm::APFloat::rmNearestTiesToEven,
|
|
390 &ignored);
|
|
391 return V.convertToDouble();
|
|
392 }
|
|
393
|
|
394 void APValue::dump(raw_ostream &OS) const {
|
|
395 switch (getKind()) {
|
|
396 case None:
|
|
397 OS << "None";
|
|
398 return;
|
|
399 case Indeterminate:
|
|
400 OS << "Indeterminate";
|
|
401 return;
|
|
402 case Int:
|
|
403 OS << "Int: " << getInt();
|
|
404 return;
|
|
405 case Float:
|
|
406 OS << "Float: " << GetApproxValue(getFloat());
|
|
407 return;
|
|
408 case FixedPoint:
|
|
409 OS << "FixedPoint : " << getFixedPoint();
|
|
410 return;
|
|
411 case Vector:
|
|
412 OS << "Vector: ";
|
|
413 getVectorElt(0).dump(OS);
|
|
414 for (unsigned i = 1; i != getVectorLength(); ++i) {
|
|
415 OS << ", ";
|
|
416 getVectorElt(i).dump(OS);
|
|
417 }
|
|
418 return;
|
|
419 case ComplexInt:
|
|
420 OS << "ComplexInt: " << getComplexIntReal() << ", " << getComplexIntImag();
|
|
421 return;
|
|
422 case ComplexFloat:
|
|
423 OS << "ComplexFloat: " << GetApproxValue(getComplexFloatReal())
|
|
424 << ", " << GetApproxValue(getComplexFloatImag());
|
|
425 return;
|
|
426 case LValue:
|
|
427 OS << "LValue: <todo>";
|
|
428 return;
|
|
429 case Array:
|
|
430 OS << "Array: ";
|
|
431 for (unsigned I = 0, N = getArrayInitializedElts(); I != N; ++I) {
|
|
432 getArrayInitializedElt(I).dump(OS);
|
|
433 if (I != getArraySize() - 1) OS << ", ";
|
|
434 }
|
|
435 if (hasArrayFiller()) {
|
|
436 OS << getArraySize() - getArrayInitializedElts() << " x ";
|
|
437 getArrayFiller().dump(OS);
|
|
438 }
|
|
439 return;
|
|
440 case Struct:
|
|
441 OS << "Struct ";
|
|
442 if (unsigned N = getStructNumBases()) {
|
|
443 OS << " bases: ";
|
|
444 getStructBase(0).dump(OS);
|
|
445 for (unsigned I = 1; I != N; ++I) {
|
|
446 OS << ", ";
|
|
447 getStructBase(I).dump(OS);
|
|
448 }
|
|
449 }
|
|
450 if (unsigned N = getStructNumFields()) {
|
|
451 OS << " fields: ";
|
|
452 getStructField(0).dump(OS);
|
|
453 for (unsigned I = 1; I != N; ++I) {
|
|
454 OS << ", ";
|
|
455 getStructField(I).dump(OS);
|
|
456 }
|
|
457 }
|
|
458 return;
|
|
459 case Union:
|
|
460 OS << "Union: ";
|
|
461 getUnionValue().dump(OS);
|
|
462 return;
|
|
463 case MemberPointer:
|
|
464 OS << "MemberPointer: <todo>";
|
|
465 return;
|
|
466 case AddrLabelDiff:
|
|
467 OS << "AddrLabelDiff: <todo>";
|
|
468 return;
|
|
469 }
|
|
470 llvm_unreachable("Unknown APValue kind!");
|
|
471 }
|
|
472
|
|
473 void APValue::printPretty(raw_ostream &Out, const ASTContext &Ctx,
|
|
474 QualType Ty) const {
|
|
475 switch (getKind()) {
|
|
476 case APValue::None:
|
|
477 Out << "<out of lifetime>";
|
|
478 return;
|
|
479 case APValue::Indeterminate:
|
|
480 Out << "<uninitialized>";
|
|
481 return;
|
|
482 case APValue::Int:
|
|
483 if (Ty->isBooleanType())
|
|
484 Out << (getInt().getBoolValue() ? "true" : "false");
|
|
485 else
|
|
486 Out << getInt();
|
|
487 return;
|
|
488 case APValue::Float:
|
|
489 Out << GetApproxValue(getFloat());
|
|
490 return;
|
|
491 case APValue::FixedPoint:
|
|
492 Out << getFixedPoint();
|
|
493 return;
|
|
494 case APValue::Vector: {
|
|
495 Out << '{';
|
|
496 QualType ElemTy = Ty->castAs<VectorType>()->getElementType();
|
|
497 getVectorElt(0).printPretty(Out, Ctx, ElemTy);
|
|
498 for (unsigned i = 1; i != getVectorLength(); ++i) {
|
|
499 Out << ", ";
|
|
500 getVectorElt(i).printPretty(Out, Ctx, ElemTy);
|
|
501 }
|
|
502 Out << '}';
|
|
503 return;
|
|
504 }
|
|
505 case APValue::ComplexInt:
|
|
506 Out << getComplexIntReal() << "+" << getComplexIntImag() << "i";
|
|
507 return;
|
|
508 case APValue::ComplexFloat:
|
|
509 Out << GetApproxValue(getComplexFloatReal()) << "+"
|
|
510 << GetApproxValue(getComplexFloatImag()) << "i";
|
|
511 return;
|
|
512 case APValue::LValue: {
|
|
513 bool IsReference = Ty->isReferenceType();
|
|
514 QualType InnerTy
|
|
515 = IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType();
|
|
516 if (InnerTy.isNull())
|
|
517 InnerTy = Ty;
|
|
518
|
|
519 LValueBase Base = getLValueBase();
|
|
520 if (!Base) {
|
|
521 if (isNullPointer()) {
|
|
522 Out << (Ctx.getLangOpts().CPlusPlus11 ? "nullptr" : "0");
|
|
523 } else if (IsReference) {
|
|
524 Out << "*(" << InnerTy.stream(Ctx.getPrintingPolicy()) << "*)"
|
|
525 << getLValueOffset().getQuantity();
|
|
526 } else {
|
|
527 Out << "(" << Ty.stream(Ctx.getPrintingPolicy()) << ")"
|
|
528 << getLValueOffset().getQuantity();
|
|
529 }
|
|
530 return;
|
|
531 }
|
|
532
|
|
533 if (!hasLValuePath()) {
|
|
534 // No lvalue path: just print the offset.
|
|
535 CharUnits O = getLValueOffset();
|
|
536 CharUnits S = Ctx.getTypeSizeInChars(InnerTy);
|
|
537 if (!O.isZero()) {
|
|
538 if (IsReference)
|
|
539 Out << "*(";
|
|
540 if (O % S) {
|
|
541 Out << "(char*)";
|
|
542 S = CharUnits::One();
|
|
543 }
|
|
544 Out << '&';
|
|
545 } else if (!IsReference) {
|
|
546 Out << '&';
|
|
547 }
|
|
548
|
|
549 if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>())
|
|
550 Out << *VD;
|
|
551 else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
|
|
552 TI.print(Out, Ctx.getPrintingPolicy());
|
|
553 } else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
|
|
554 Out << "{*new "
|
|
555 << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#"
|
|
556 << DA.getIndex() << "}";
|
|
557 } else {
|
|
558 assert(Base.get<const Expr *>() != nullptr &&
|
|
559 "Expecting non-null Expr");
|
|
560 Base.get<const Expr*>()->printPretty(Out, nullptr,
|
|
561 Ctx.getPrintingPolicy());
|
|
562 }
|
|
563
|
|
564 if (!O.isZero()) {
|
|
565 Out << " + " << (O / S);
|
|
566 if (IsReference)
|
|
567 Out << ')';
|
|
568 }
|
|
569 return;
|
|
570 }
|
|
571
|
|
572 // We have an lvalue path. Print it out nicely.
|
|
573 if (!IsReference)
|
|
574 Out << '&';
|
|
575 else if (isLValueOnePastTheEnd())
|
|
576 Out << "*(&";
|
|
577
|
|
578 QualType ElemTy;
|
|
579 if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) {
|
|
580 Out << *VD;
|
|
581 ElemTy = VD->getType();
|
|
582 } else if (TypeInfoLValue TI = Base.dyn_cast<TypeInfoLValue>()) {
|
|
583 TI.print(Out, Ctx.getPrintingPolicy());
|
|
584 ElemTy = Base.getTypeInfoType();
|
|
585 } else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
|
|
586 Out << "{*new "
|
|
587 << Base.getDynamicAllocType().stream(Ctx.getPrintingPolicy()) << "#"
|
|
588 << DA.getIndex() << "}";
|
|
589 ElemTy = Base.getDynamicAllocType();
|
|
590 } else {
|
|
591 const Expr *E = Base.get<const Expr*>();
|
|
592 assert(E != nullptr && "Expecting non-null Expr");
|
|
593 E->printPretty(Out, nullptr, Ctx.getPrintingPolicy());
|
|
594 // FIXME: This is wrong if E is a MaterializeTemporaryExpr with an lvalue
|
|
595 // adjustment.
|
|
596 ElemTy = E->getType();
|
|
597 }
|
|
598
|
|
599 ArrayRef<LValuePathEntry> Path = getLValuePath();
|
|
600 const CXXRecordDecl *CastToBase = nullptr;
|
|
601 for (unsigned I = 0, N = Path.size(); I != N; ++I) {
|
|
602 if (ElemTy->getAs<RecordType>()) {
|
|
603 // The lvalue refers to a class type, so the next path entry is a base
|
|
604 // or member.
|
|
605 const Decl *BaseOrMember = Path[I].getAsBaseOrMember().getPointer();
|
|
606 if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
|
|
607 CastToBase = RD;
|
|
608 ElemTy = Ctx.getRecordType(RD);
|
|
609 } else {
|
|
610 const ValueDecl *VD = cast<ValueDecl>(BaseOrMember);
|
|
611 Out << ".";
|
|
612 if (CastToBase)
|
|
613 Out << *CastToBase << "::";
|
|
614 Out << *VD;
|
|
615 ElemTy = VD->getType();
|
|
616 }
|
|
617 } else {
|
|
618 // The lvalue must refer to an array.
|
|
619 Out << '[' << Path[I].getAsArrayIndex() << ']';
|
|
620 ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType();
|
|
621 }
|
|
622 }
|
|
623
|
|
624 // Handle formatting of one-past-the-end lvalues.
|
|
625 if (isLValueOnePastTheEnd()) {
|
|
626 // FIXME: If CastToBase is non-0, we should prefix the output with
|
|
627 // "(CastToBase*)".
|
|
628 Out << " + 1";
|
|
629 if (IsReference)
|
|
630 Out << ')';
|
|
631 }
|
|
632 return;
|
|
633 }
|
|
634 case APValue::Array: {
|
|
635 const ArrayType *AT = Ctx.getAsArrayType(Ty);
|
|
636 QualType ElemTy = AT->getElementType();
|
|
637 Out << '{';
|
|
638 if (unsigned N = getArrayInitializedElts()) {
|
|
639 getArrayInitializedElt(0).printPretty(Out, Ctx, ElemTy);
|
|
640 for (unsigned I = 1; I != N; ++I) {
|
|
641 Out << ", ";
|
|
642 if (I == 10) {
|
|
643 // Avoid printing out the entire contents of large arrays.
|
|
644 Out << "...";
|
|
645 break;
|
|
646 }
|
|
647 getArrayInitializedElt(I).printPretty(Out, Ctx, ElemTy);
|
|
648 }
|
|
649 }
|
|
650 Out << '}';
|
|
651 return;
|
|
652 }
|
|
653 case APValue::Struct: {
|
|
654 Out << '{';
|
|
655 const RecordDecl *RD = Ty->castAs<RecordType>()->getDecl();
|
|
656 bool First = true;
|
|
657 if (unsigned N = getStructNumBases()) {
|
|
658 const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD);
|
|
659 CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin();
|
|
660 for (unsigned I = 0; I != N; ++I, ++BI) {
|
|
661 assert(BI != CD->bases_end());
|
|
662 if (!First)
|
|
663 Out << ", ";
|
|
664 getStructBase(I).printPretty(Out, Ctx, BI->getType());
|
|
665 First = false;
|
|
666 }
|
|
667 }
|
|
668 for (const auto *FI : RD->fields()) {
|
|
669 if (!First)
|
|
670 Out << ", ";
|
|
671 if (FI->isUnnamedBitfield()) continue;
|
|
672 getStructField(FI->getFieldIndex()).
|
|
673 printPretty(Out, Ctx, FI->getType());
|
|
674 First = false;
|
|
675 }
|
|
676 Out << '}';
|
|
677 return;
|
|
678 }
|
|
679 case APValue::Union:
|
|
680 Out << '{';
|
|
681 if (const FieldDecl *FD = getUnionField()) {
|
|
682 Out << "." << *FD << " = ";
|
|
683 getUnionValue().printPretty(Out, Ctx, FD->getType());
|
|
684 }
|
|
685 Out << '}';
|
|
686 return;
|
|
687 case APValue::MemberPointer:
|
|
688 // FIXME: This is not enough to unambiguously identify the member in a
|
|
689 // multiple-inheritance scenario.
|
|
690 if (const ValueDecl *VD = getMemberPointerDecl()) {
|
|
691 Out << '&' << *cast<CXXRecordDecl>(VD->getDeclContext()) << "::" << *VD;
|
|
692 return;
|
|
693 }
|
|
694 Out << "0";
|
|
695 return;
|
|
696 case APValue::AddrLabelDiff:
|
|
697 Out << "&&" << getAddrLabelDiffLHS()->getLabel()->getName();
|
|
698 Out << " - ";
|
|
699 Out << "&&" << getAddrLabelDiffRHS()->getLabel()->getName();
|
|
700 return;
|
|
701 }
|
|
702 llvm_unreachable("Unknown APValue kind!");
|
|
703 }
|
|
704
|
|
705 std::string APValue::getAsString(const ASTContext &Ctx, QualType Ty) const {
|
|
706 std::string Result;
|
|
707 llvm::raw_string_ostream Out(Result);
|
|
708 printPretty(Out, Ctx, Ty);
|
|
709 Out.flush();
|
|
710 return Result;
|
|
711 }
|
|
712
|
|
713 bool APValue::toIntegralConstant(APSInt &Result, QualType SrcTy,
|
|
714 const ASTContext &Ctx) const {
|
|
715 if (isInt()) {
|
|
716 Result = getInt();
|
|
717 return true;
|
|
718 }
|
|
719
|
|
720 if (isLValue() && isNullPointer()) {
|
|
721 Result = Ctx.MakeIntValue(Ctx.getTargetNullPointerValue(SrcTy), SrcTy);
|
|
722 return true;
|
|
723 }
|
|
724
|
|
725 if (isLValue() && !getLValueBase()) {
|
|
726 Result = Ctx.MakeIntValue(getLValueOffset().getQuantity(), SrcTy);
|
|
727 return true;
|
|
728 }
|
|
729
|
|
730 return false;
|
|
731 }
|
|
732
|
|
733 const APValue::LValueBase APValue::getLValueBase() const {
|
|
734 assert(isLValue() && "Invalid accessor");
|
|
735 return ((const LV*)(const void*)Data.buffer)->Base;
|
|
736 }
|
|
737
|
|
738 bool APValue::isLValueOnePastTheEnd() const {
|
|
739 assert(isLValue() && "Invalid accessor");
|
|
740 return ((const LV*)(const void*)Data.buffer)->IsOnePastTheEnd;
|
|
741 }
|
|
742
|
|
743 CharUnits &APValue::getLValueOffset() {
|
|
744 assert(isLValue() && "Invalid accessor");
|
|
745 return ((LV*)(void*)Data.buffer)->Offset;
|
|
746 }
|
|
747
|
|
748 bool APValue::hasLValuePath() const {
|
|
749 assert(isLValue() && "Invalid accessor");
|
|
750 return ((const LV*)(const char*)Data.buffer)->hasPath();
|
|
751 }
|
|
752
|
|
753 ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
|
|
754 assert(isLValue() && hasLValuePath() && "Invalid accessor");
|
|
755 const LV &LVal = *((const LV*)(const char*)Data.buffer);
|
|
756 return llvm::makeArrayRef(LVal.getPath(), LVal.PathLength);
|
|
757 }
|
|
758
|
|
759 unsigned APValue::getLValueCallIndex() const {
|
|
760 assert(isLValue() && "Invalid accessor");
|
|
761 return ((const LV*)(const char*)Data.buffer)->Base.getCallIndex();
|
|
762 }
|
|
763
|
|
764 unsigned APValue::getLValueVersion() const {
|
|
765 assert(isLValue() && "Invalid accessor");
|
|
766 return ((const LV*)(const char*)Data.buffer)->Base.getVersion();
|
|
767 }
|
|
768
|
|
769 bool APValue::isNullPointer() const {
|
|
770 assert(isLValue() && "Invalid usage");
|
|
771 return ((const LV*)(const char*)Data.buffer)->IsNullPtr;
|
|
772 }
|
|
773
|
|
774 void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
|
|
775 bool IsNullPtr) {
|
|
776 assert(isLValue() && "Invalid accessor");
|
|
777 LV &LVal = *((LV*)(char*)Data.buffer);
|
|
778 LVal.Base = B;
|
|
779 LVal.IsOnePastTheEnd = false;
|
|
780 LVal.Offset = O;
|
|
781 LVal.resizePath((unsigned)-1);
|
|
782 LVal.IsNullPtr = IsNullPtr;
|
|
783 }
|
|
784
|
|
785 void APValue::setLValue(LValueBase B, const CharUnits &O,
|
|
786 ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd,
|
|
787 bool IsNullPtr) {
|
|
788 assert(isLValue() && "Invalid accessor");
|
|
789 LV &LVal = *((LV*)(char*)Data.buffer);
|
|
790 LVal.Base = B;
|
|
791 LVal.IsOnePastTheEnd = IsOnePastTheEnd;
|
|
792 LVal.Offset = O;
|
|
793 LVal.resizePath(Path.size());
|
|
794 memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));
|
|
795 LVal.IsNullPtr = IsNullPtr;
|
|
796 }
|
|
797
|
|
798 const ValueDecl *APValue::getMemberPointerDecl() const {
|
|
799 assert(isMemberPointer() && "Invalid accessor");
|
|
800 const MemberPointerData &MPD =
|
|
801 *((const MemberPointerData *)(const char *)Data.buffer);
|
|
802 return MPD.MemberAndIsDerivedMember.getPointer();
|
|
803 }
|
|
804
|
|
805 bool APValue::isMemberPointerToDerivedMember() const {
|
|
806 assert(isMemberPointer() && "Invalid accessor");
|
|
807 const MemberPointerData &MPD =
|
|
808 *((const MemberPointerData *)(const char *)Data.buffer);
|
|
809 return MPD.MemberAndIsDerivedMember.getInt();
|
|
810 }
|
|
811
|
|
812 ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
|
|
813 assert(isMemberPointer() && "Invalid accessor");
|
|
814 const MemberPointerData &MPD =
|
|
815 *((const MemberPointerData *)(const char *)Data.buffer);
|
|
816 return llvm::makeArrayRef(MPD.getPath(), MPD.PathLength);
|
|
817 }
|
|
818
|
|
819 void APValue::MakeLValue() {
|
|
820 assert(isAbsent() && "Bad state change");
|
|
821 static_assert(sizeof(LV) <= DataSize, "LV too big");
|
|
822 new ((void*)(char*)Data.buffer) LV();
|
|
823 Kind = LValue;
|
|
824 }
|
|
825
|
|
826 void APValue::MakeArray(unsigned InitElts, unsigned Size) {
|
|
827 assert(isAbsent() && "Bad state change");
|
|
828 new ((void*)(char*)Data.buffer) Arr(InitElts, Size);
|
|
829 Kind = Array;
|
|
830 }
|
|
831
|
|
832 void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
|
|
833 ArrayRef<const CXXRecordDecl*> Path) {
|
|
834 assert(isAbsent() && "Bad state change");
|
|
835 MemberPointerData *MPD = new ((void*)(char*)Data.buffer) MemberPointerData;
|
|
836 Kind = MemberPointer;
|
|
837 MPD->MemberAndIsDerivedMember.setPointer(Member);
|
|
838 MPD->MemberAndIsDerivedMember.setInt(IsDerivedMember);
|
|
839 MPD->resizePath(Path.size());
|
|
840 memcpy(MPD->getPath(), Path.data(), Path.size()*sizeof(const CXXRecordDecl*));
|
|
841 }
|