clang 23.0.0git
EvaluationResult.cpp
Go to the documentation of this file.
1//===----- EvaluationResult.cpp - Result class for the VM ------*- C++ -*-===//
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#include "EvaluationResult.h"
10#include "InterpState.h"
11#include "Pointer.h"
12#include "Record.h"
13#include "llvm/ADT/STLExtras.h"
14#include "llvm/ADT/SetVector.h"
15#include <iterator>
16
17namespace clang {
18namespace interp {
19
21 const FieldDecl *SubObjDecl) {
22 assert(SubObjDecl && "Subobject declaration does not exist");
23 S.FFDiag(Loc, diag::note_constexpr_uninitialized)
24 << /*(name)*/ 1 << SubObjDecl;
25 S.Note(SubObjDecl->getLocation(),
26 diag::note_constexpr_subobject_declared_here);
27}
28
29static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
30 const Pointer &BasePtr, const Record *R);
31
33 const Pointer &BasePtr) {
34 const Descriptor *BaseDesc = BasePtr.getFieldDesc();
35 assert(BaseDesc->isArray());
36 size_t NumElems = BaseDesc->getNumElems();
37
38 if (NumElems == 0)
39 return true;
40
41 bool Result = true;
42
43 if (BaseDesc->isPrimitiveArray()) {
44 if (BasePtr.allElementsInitialized())
45 return true;
47 return false;
48 }
49 const Descriptor *ElemDesc = BaseDesc->ElemDesc;
50
51 if (ElemDesc->isRecord()) {
52 const Record *R = ElemDesc->ElemRecord;
53 for (size_t I = 0; I != NumElems; ++I) {
54 Pointer ElemPtr = BasePtr.atIndex(I).narrow();
55 Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);
56 }
57 } else {
58 assert(ElemDesc->isArray());
59 for (size_t I = 0; I != NumElems; ++I) {
60 Pointer ElemPtr = BasePtr.atIndex(I).narrow();
61 Result &= CheckArrayInitialized(S, Loc, ElemPtr);
62 }
63 }
64
65 return Result;
66}
67
69 const Pointer &BasePtr, const Record *R) {
70 assert(R);
71 bool Result = true;
72 // Check all fields of this record are initialized.
73 for (const Record::Field &F : R->fields()) {
74 Pointer FieldPtr = BasePtr.atField(F.Offset);
75
76 // Don't check inactive union members.
77 if (R->isUnion() && !FieldPtr.isActive())
78 continue;
79
80 QualType FieldType = F.Decl->getType();
81 const Descriptor *FieldDesc = FieldPtr.getFieldDesc();
82
83 if (FieldDesc->isRecord()) {
84 Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());
85 } else if (FieldType->isIncompleteArrayType()) {
86 // Nothing to do here.
87 } else if (F.Decl->isUnnamedBitField()) {
88 // Nothing do do here.
89 } else if (FieldDesc->isArray()) {
90 Result &= CheckArrayInitialized(S, Loc, FieldPtr);
91 } else if (!FieldPtr.isInitialized()) {
92 DiagnoseUninitializedSubobject(S, Loc, F.Decl);
93 Result = false;
94 }
95 }
96
97 // Check Fields in all bases
98 for (auto [I, B] : llvm::enumerate(R->bases())) {
99 Pointer P = BasePtr.atField(B.Offset);
100 if (!P.isInitialized()) {
101 const Descriptor *Desc = BasePtr.getDeclDesc();
102 if (const auto *CD = dyn_cast_if_present<CXXRecordDecl>(R->getDecl())) {
103 const auto &BS = *std::next(CD->bases_begin(), I);
104 SourceLocation TypeBeginLoc = BS.getBaseTypeLoc();
105 S.FFDiag(TypeBeginLoc, diag::note_constexpr_uninitialized_base)
106 << B.Desc->getType() << SourceRange(TypeBeginLoc, BS.getEndLoc());
107 } else {
108 S.FFDiag(Desc->getLocation(), diag::note_constexpr_uninitialized_base)
109 << B.Desc->getType();
110 }
111 return false;
112 }
113 Result &= CheckFieldsInitialized(S, Loc, P, B.R);
114 }
115
116 // TODO: Virtual bases
117
118 return Result;
119}
120
122 const Pointer &Ptr) const {
123 assert(Source);
124 assert(empty());
125
126 if (Ptr.isZero())
127 return true;
128 if (!Ptr.isBlockPointer())
129 return true;
130
131 // We can't inspect dead pointers at all. Return true here so we can
132 // diagnose them later.
133 if (!Ptr.isLive())
134 return true;
135
136 SourceLocation InitLoc;
137 if (const auto *D = dyn_cast<const Decl *>(Source))
138 InitLoc = cast<VarDecl>(D)->getAnyInitializer()->getExprLoc();
139 else if (const auto *E = dyn_cast<const Expr *>(Source))
140 InitLoc = E->getExprLoc();
141
142 if (const Record *R = Ptr.getRecord())
143 return CheckFieldsInitialized(S, InitLoc, Ptr, R);
144
145 if (isa_and_nonnull<ConstantArrayType>(Ptr.getType()->getAsArrayTypeUnsafe()))
146 return CheckArrayInitialized(S, InitLoc, Ptr);
147
148 return true;
149}
150
151static bool isOrHasPtr(const Descriptor *D) {
152 if ((D->isPrimitive() || D->isPrimitiveArray()) && D->getPrimType() == PT_Ptr)
153 return true;
154
155 if (D->ElemRecord)
156 return D->ElemRecord->hasPtrField();
157 return false;
158}
159
160static void collectBlocks(const Pointer &Ptr,
161 llvm::SetVector<const Block *> &Blocks) {
162 auto isUsefulPtr = [](const Pointer &P) -> bool {
163 return P.isLive() && P.isBlockPointer() && !P.isZero() && !P.isDummy() &&
164 P.isDereferencable() && !P.isUnknownSizeArray() && !P.isOnePastEnd();
165 };
166
167 if (!isUsefulPtr(Ptr))
168 return;
169
170 Blocks.insert(Ptr.block());
171
172 const Descriptor *Desc = Ptr.getFieldDesc();
173 if (!Desc)
174 return;
175
176 if (const Record *R = Desc->ElemRecord; R && R->hasPtrField()) {
177
178 for (const Record::Field &F : R->fields()) {
179 if (!isOrHasPtr(F.Desc))
180 continue;
181 Pointer FieldPtr = Ptr.atField(F.Offset);
182 assert(FieldPtr.block() == Ptr.block());
183 collectBlocks(FieldPtr, Blocks);
184 }
185 } else if (Desc->isPrimitive() && Desc->getPrimType() == PT_Ptr) {
186 Pointer Pointee = Ptr.deref<Pointer>();
187 if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.block()))
188 collectBlocks(Pointee, Blocks);
189
190 } else if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) {
191 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
192 Pointer ElemPointee = Ptr.elem<Pointer>(I);
193 if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block()))
194 collectBlocks(ElemPointee, Blocks);
195 }
196 } else if (Desc->isCompositeArray() && isOrHasPtr(Desc->ElemDesc)) {
197 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
198 Pointer ElemPtr = Ptr.atIndex(I).narrow();
199 collectBlocks(ElemPtr, Blocks);
200 }
201 }
202}
203
205 const Pointer &Ptr,
206 const SourceInfo &Info) {
207 // Collect all blocks that this pointer (transitively) points to and
208 // return false if any of them is a dynamic block.
209 llvm::SetVector<const Block *> Blocks;
210
211 collectBlocks(Ptr, Blocks);
212
213 for (const Block *B : Blocks) {
214 if (B->isDynamic()) {
215 assert(B->getDescriptor());
216 assert(B->getDescriptor()->asExpr());
217
218 bool IsSubobj = !Ptr.isRoot() || Ptr.isArrayElement();
219 S.FFDiag(Info, diag::note_constexpr_dynamic_alloc)
220 << Ptr.getType()->isReferenceType() << IsSubobj;
221 S.Note(B->getDescriptor()->asExpr()->getExprLoc(),
222 diag::note_constexpr_dynamic_alloc_here);
223 return false;
224 }
225 }
226
227 return true;
228}
229
230} // namespace interp
231} // namespace clang
llvm::MachO::Record Record
Definition MachO.h:31
SourceLocation getLocation() const
Definition DeclBase.h:447
Represents a member of a struct/union/class.
Definition Decl.h:3178
A (possibly-)qualified type.
Definition TypeBase.h:937
Encodes a location in the source.
A trivial tuple used to represent a source range.
bool isIncompleteArrayType() const
Definition TypeBase.h:8780
bool isReferenceType() const
Definition TypeBase.h:8697
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9319
A memory block, either on the stack or in the heap.
Definition InterpBlock.h:44
Holds all information required to evaluate constexpr code in a module.
Definition Context.h:47
bool checkReturnValue(InterpState &S, const Context &Ctx, const Pointer &Ptr, const SourceInfo &Info)
Check that none of the blocks the given pointer (transitively) points to are dynamically allocated.
bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const
Check that all subobjects of the given pointer have been initialized.
Interpreter context.
Definition InterpState.h:36
A pointer to a memory block, live or dead.
Definition Pointer.h:97
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition Pointer.h:194
bool isInitialized() const
Checks if an object was initialized.
Definition Pointer.cpp:443
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition Pointer.h:162
bool isActive() const
Checks if the object is active.
Definition Pointer.h:551
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition Pointer.h:179
T & deref() const
Dereferences the pointer, if it's live.
Definition Pointer.h:687
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:346
bool isArrayElement() const
Checks if the pointer points to an array.
Definition Pointer.h:432
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:278
T & elem(unsigned I) const
Dereferences the element at index I.
Definition Pointer.h:703
bool isZero() const
Checks if the pointer is null.
Definition Pointer.h:264
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:448
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition Pointer.h:292
const FieldDecl * getField() const
Returns the field information.
Definition Pointer.h:492
bool isBlockPointer() const
Definition Pointer.h:479
bool allElementsInitialized() const
Definition Pointer.cpp:590
const Block * block() const
Definition Pointer.h:617
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:336
const Record * getRecord() const
Returns the record descriptor of a class.
Definition Pointer.h:485
Structure/Class descriptor.
Definition Record.h:25
bool hasPtrField() const
If this record (or any of its bases) contains a field of type PT_Ptr.
Definition Record.h:83
Describes the statement/declaration an opcode was generated from.
Definition Source.h:74
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
Definition State.cpp:63
OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation could not be folded (FF => FoldFailure)
Definition State.cpp:21
static bool isOrHasPtr(const Descriptor *D)
static void collectBlocks(const Pointer &Ptr, llvm::SetVector< const Block * > &Blocks)
static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc, const Pointer &BasePtr, const Record *R)
static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc, const FieldDecl *SubObjDecl)
static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc, const Pointer &BasePtr)
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
Definition TypeBase.h:905
U cast(CodeGen::Address addr)
Definition Address.h:327
Describes a memory block created by an allocation site.
Definition Descriptor.h:123
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:260
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:274
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition Descriptor.h:267
const Descriptor *const ElemDesc
Descriptor of the array element.
Definition Descriptor.h:156
SourceLocation getLocation() const
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:265
PrimType getPrimType() const
Definition Descriptor.h:242
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:279
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:154
bool isArray() const
Checks if the descriptor is of an array.
Definition Descriptor.h:277