clang 24.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 PtrView BasePtr, const Record *R,
31 bool IsCompleteClass = true);
32
34 PtrView BasePtr) {
35 const Descriptor *BaseDesc = BasePtr.getFieldDesc();
36 assert(BaseDesc->isArray());
37
38 size_t NumElems = BaseDesc->getNumElems();
39 if (NumElems == 0)
40 return true;
41
42 bool Result = true;
43
44 if (BaseDesc->isPrimitiveArray()) {
45 if (BasePtr.allElementsInitialized())
46 return true;
48 return false;
49 }
50 const Descriptor *ElemDesc = BaseDesc->ElemDesc;
51
52 if (ElemDesc->isRecord()) {
53 const Record *R = ElemDesc->ElemRecord;
54 for (size_t I = 0; I != NumElems; ++I) {
55 PtrView ElemPtr = BasePtr.atIndex(I).narrow();
56 Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);
57 }
58 } else {
59 assert(ElemDesc->isArray());
60 for (size_t I = 0; I != NumElems; ++I) {
61 PtrView ElemPtr = BasePtr.atIndex(I).narrow();
62 Result &= CheckArrayInitialized(S, Loc, ElemPtr);
63 }
64 }
65
66 return Result;
67}
68
70 PtrView BasePtr, const Record *R,
71 bool IsCompleteClass) {
72 assert(R);
73 bool Result = true;
74 // Check all fields of this record are initialized.
75 for (const Record::Field &F : R->fields()) {
76 PtrView FieldPtr = BasePtr.atField(F.Offset);
77
78 // Don't check inactive union members.
79 if (R->isUnion() && !FieldPtr.isActive())
80 continue;
81
82 QualType FieldType = F.Decl->getType();
83 const Descriptor *FieldDesc = FieldPtr.getFieldDesc();
84
85 if (FieldDesc->isRecord()) {
86 Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());
87 } else if (FieldType->isIncompleteArrayType()) {
88 // Nothing to do here.
89 } else if (F.Decl->isUnnamedBitField()) {
90 // Nothing do do here.
91 } else if (FieldDesc->isArray()) {
92 Result &= CheckArrayInitialized(S, Loc, FieldPtr);
93 } else if (!FieldPtr.isInitialized()) {
94 DiagnoseUninitializedSubobject(S, Loc, F.Decl);
95 Result = false;
96 }
97 }
98
99 auto diagnoseBase = [&](const Record::Base &B, unsigned Index) -> bool {
100 const Descriptor *Desc = BasePtr.getDeclDesc();
101 if (const auto *CD = dyn_cast_if_present<CXXRecordDecl>(R->getDecl())) {
102 const auto &BS = *std::next(CD->bases_begin(), Index);
103 SourceLocation TypeBeginLoc = BS.getBaseTypeLoc();
104 S.FFDiag(TypeBeginLoc, diag::note_constexpr_uninitialized_base)
105 << B.Desc->getType() << SourceRange(TypeBeginLoc, BS.getEndLoc());
106 } else {
107 S.FFDiag(Desc->getLocation(), diag::note_constexpr_uninitialized_base)
108 << B.Desc->getType();
109 }
110 return false;
111 };
112
113 // Check Fields in all bases.
114 for (auto [I, B] : llvm::enumerate(R->bases())) {
115 PtrView P = BasePtr.atField(B.Offset);
116 if (!P.isInitialized())
117 return diagnoseBase(B, I);
118 Result &= CheckFieldsInitialized(S, Loc, P, B.R, /*IsCompleteClass=*/false);
119 }
120
121 // And virtual bases.
122 if (IsCompleteClass) {
123 for (auto [I, B] : llvm::enumerate(R->virtual_bases())) {
124 PtrView P = BasePtr.atField(B.Offset);
125 if (!P.isInitialized())
126 return diagnoseBase(B, I);
127 Result &=
128 CheckFieldsInitialized(S, Loc, P, B.R, /*IsCompleteClass=*/false);
129 }
130 }
131
132 return Result;
133}
134
136 const Pointer &Ptr) const {
137 assert(Source);
138 assert(empty());
139
140 if (Ptr.isZero())
141 return true;
142 if (!Ptr.isBlockPointer())
143 return true;
144
145 // We can't inspect dead pointers at all. Return true here so we can
146 // diagnose them later.
147 if (!Ptr.isLive())
148 return true;
149
150 SourceLocation InitLoc;
151 if (const auto *D = dyn_cast<const Decl *>(Source))
152 InitLoc = cast<VarDecl>(D)->getAnyInitializer()->getExprLoc();
153 else if (const auto *E = dyn_cast<const Expr *>(Source))
154 InitLoc = E->getExprLoc();
155
156 if (const Record *R = Ptr.getRecord())
157 return CheckFieldsInitialized(S, InitLoc, Ptr.view(), R);
158
159 if (isa_and_nonnull<ConstantArrayType>(Ptr.getType()->getAsArrayTypeUnsafe()))
160 return CheckArrayInitialized(S, InitLoc, Ptr.view());
161
162 return true;
163}
164
165static bool isOrHasPtr(const Descriptor *D) {
166 if ((D->isPrimitive() || D->isPrimitiveArray()) && D->getPrimType() == PT_Ptr)
167 return true;
168
169 if (D->ElemRecord)
170 return D->ElemRecord->hasPtrField();
171 return false;
172}
173
174static void collectBlocks(PtrView Ptr, llvm::SetVector<const Block *> &Blocks,
175 bool IsCompleteClass = true) {
176 auto isUsefulPtr = [](const Pointer &P) -> bool {
177 return P.isLive() && P.isBlockPointer() && !P.isZero() && !P.isDummy() &&
178 P.isDereferencable() && !P.isUnknownSizeArray() && !P.isOnePastEnd();
179 };
180
181 if (!Ptr.isLive() || Ptr.isZero() || Ptr.isDummy() ||
182 Ptr.isUnknownSizeArray() || Ptr.isOnePastEnd())
183 return;
184
185 Blocks.insert(Ptr.Pointee);
186
187 const Descriptor *Desc = Ptr.getFieldDesc();
188 if (!Desc)
189 return;
190
191 if (const Record *R = Desc->ElemRecord) {
192 if (!R->hasPtrField())
193 return;
194
195 for (const Record::Base &B : R->bases()) {
196 if (!B.R->hasPtrField())
197 continue;
198 PtrView BasePtr = Ptr.atField(B.Offset);
199 collectBlocks(BasePtr, Blocks, /*IsCompleteClass=*/false);
200 }
201
202 for (const Record::Field &F : R->fields()) {
203 if (!isOrHasPtr(F.Desc))
204 continue;
205 PtrView FieldPtr = Ptr.atField(F.Offset);
206 collectBlocks(FieldPtr, Blocks);
207 }
208
209 if (IsCompleteClass) {
210 for (const Record::Base &B : R->virtual_bases()) {
211 if (!B.R->hasPtrField())
212 continue;
213 PtrView BasePtr = Ptr.atField(B.Offset);
214 collectBlocks(BasePtr, Blocks, /*IsCompleteClass=*/false);
215 }
216 }
217
218 return;
219 }
220
221 if (Desc->isPrimitive() && Desc->getPrimType() == PT_Ptr) {
222 Pointer Pointee = Ptr.deref<Pointer>();
223 if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.block()))
224 collectBlocks(Pointee.view(), Blocks);
225
226 return;
227 }
228
229 if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) {
230 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
231 Pointer ElemPointee = Ptr.elem<Pointer>(I);
232 if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block()))
233 collectBlocks(ElemPointee.view(), Blocks);
234 }
235 return;
236 }
237
238 if (Desc->isCompositeArray() && isOrHasPtr(Desc->ElemDesc)) {
239 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
240 PtrView ElemPtr = Ptr.atIndex(I).narrow();
241 collectBlocks(ElemPtr, Blocks);
242 }
243 }
244}
245
247 const Context &Ctx,
248 const Pointer &Ptr,
249 SourceInfo Info) {
250 if (!Ptr.isBlockPointer())
251 return true;
252 // Collect all blocks that this pointer (transitively) points to and
253 // return false if any of them is a dynamic block.
254 llvm::SetVector<const Block *> Blocks;
255
256 collectBlocks(Ptr.view(), Blocks);
257
258 for (const Block *B : Blocks) {
259 if (B->isDynamic()) {
260 assert(B->getDescriptor());
261 assert(B->getDescriptor()->asExpr());
262
263 bool IsSubobj = !Ptr.isRoot() || Ptr.isArrayElement();
264 S.FFDiag(Info, diag::note_constexpr_dynamic_alloc)
265 << Ptr.getType()->isReferenceType() << IsSubobj;
266 S.Note(B->getDescriptor()->asExpr()->getExprLoc(),
267 diag::note_constexpr_dynamic_alloc_here);
268 return false;
269 }
270 }
271
272 return true;
273}
274
275} // namespace interp
276} // 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:3204
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:8798
bool isReferenceType() const
Definition TypeBase.h:8715
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9337
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 checkFullyInitialized(InterpState &S, const Pointer &Ptr) const
Check that all subobjects of the given pointer have been initialized.
bool checkDynamicAllocations(InterpState &S, const Context &Ctx, const Pointer &Ptr, SourceInfo Info)
Check that none of the blocks the given pointer (transitively) points to are dynamically allocated.
Interpreter context.
Definition InterpState.h:43
A pointer to a memory block, live or dead.
Definition Pointer.h:405
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:574
bool isArrayElement() const
Checks if the pointer points to an array.
Definition Pointer.h:642
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:522
bool isZero() const
Checks if the pointer is null.
Definition Pointer.h:508
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:649
bool isBlockPointer() const
Definition Pointer.h:679
const Block * block() const
Definition Pointer.h:814
PtrView view() const
Definition Pointer.h:461
const Record * getRecord() const
Returns the record descriptor of a class.
Definition Pointer.h:685
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:76
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
Definition State.cpp:66
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 void collectBlocks(PtrView Ptr, llvm::SetVector< const Block * > &Blocks, bool IsCompleteClass=true)
static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc, PtrView BasePtr)
static bool isOrHasPtr(const Descriptor *D)
static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc, PtrView BasePtr, const Record *R, bool IsCompleteClass=true)
static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc, const FieldDecl *SubObjDecl)
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
bool isUnknownSizeArray() const
Definition Pointer.h:171
const Descriptor * getDeclDesc() const
Definition Pointer.h:87
bool allElementsInitialized() const
Definition Pointer.cpp:701
PtrView atField(unsigned Offset) const
Definition Pointer.h:264
const Record * getRecord() const
Definition Pointer.h:156
const Descriptor * getFieldDesc() const
Definition Pointer.h:81
const FieldDecl * getField() const
Definition Pointer.h:161
PtrView atIndex(unsigned Idx) const
Definition Pointer.h:200
PtrView narrow() const
Definition Pointer.h:91
T & elem(unsigned I) const
Definition Pointer.h:246
bool isInitialized() const
Definition Pointer.h:292
bool isZero() const
Definition Pointer.h:43
bool isOnePastEnd() const
Definition Pointer.h:191
bool isActive() const
Definition Pointer.h:46
bool isDummy() const
Definition Pointer.h:45
bool isLive() const
Definition Pointer.h:44
T & deref() const
Definition Pointer.h:235