clang 22.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 ConstantArrayType *CAT) {
35 size_t NumElems = CAT->getZExtSize();
36
37 if (NumElems == 0)
38 return true;
39
40 bool Result = true;
41 QualType ElemType = CAT->getElementType();
42
43 if (ElemType->isRecordType()) {
44 const Record *R = BasePtr.getElemRecord();
45 for (size_t I = 0; I != NumElems; ++I) {
46 Pointer ElemPtr = BasePtr.atIndex(I).narrow();
47 Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);
48 }
49 } else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
50 for (size_t I = 0; I != NumElems; ++I) {
51 Pointer ElemPtr = BasePtr.atIndex(I).narrow();
52 Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);
53 }
54 } else {
55 // Primitive arrays.
56 if (S.getContext().canClassify(ElemType)) {
57 if (BasePtr.allElementsInitialized()) {
58 return true;
59 } else {
61 return false;
62 }
63 }
64
65 for (size_t I = 0; I != NumElems; ++I) {
66 if (!BasePtr.isElementInitialized(I)) {
68 Result = false;
69 }
70 }
71 }
72
73 return Result;
74}
75
77 const Pointer &BasePtr, const Record *R) {
78 assert(R);
79 bool Result = true;
80 // Check all fields of this record are initialized.
81 for (const Record::Field &F : R->fields()) {
82 Pointer FieldPtr = BasePtr.atField(F.Offset);
83 QualType FieldType = F.Decl->getType();
84
85 // Don't check inactive union members.
86 if (R->isUnion() && !FieldPtr.isActive())
87 continue;
88
89 if (FieldType->isRecordType()) {
90 Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());
91 } else if (FieldType->isIncompleteArrayType()) {
92 // Nothing to do here.
93 } else if (F.Decl->isUnnamedBitField()) {
94 // Nothing do do here.
95 } else if (FieldType->isArrayType()) {
96 const auto *CAT =
98 Result &= CheckArrayInitialized(S, Loc, FieldPtr, CAT);
99 } else if (!FieldPtr.isInitialized()) {
100 DiagnoseUninitializedSubobject(S, Loc, F.Decl);
101 Result = false;
102 }
103 }
104
105 // Check Fields in all bases
106 for (auto [I, B] : llvm::enumerate(R->bases())) {
107 Pointer P = BasePtr.atField(B.Offset);
108 if (!P.isInitialized()) {
109 const Descriptor *Desc = BasePtr.getDeclDesc();
110 if (const auto *CD = dyn_cast_if_present<CXXRecordDecl>(R->getDecl())) {
111 const auto &BS = *std::next(CD->bases_begin(), I);
112 SourceLocation TypeBeginLoc = BS.getBaseTypeLoc();
113 S.FFDiag(TypeBeginLoc, diag::note_constexpr_uninitialized_base)
114 << B.Desc->getType() << SourceRange(TypeBeginLoc, BS.getEndLoc());
115 } else {
116 S.FFDiag(Desc->getLocation(), diag::note_constexpr_uninitialized_base)
117 << B.Desc->getType();
118 }
119 return false;
120 }
121 Result &= CheckFieldsInitialized(S, Loc, P, B.R);
122 }
123
124 // TODO: Virtual bases
125
126 return Result;
127}
128
130 const Pointer &Ptr) const {
131 assert(Source);
132 assert(empty());
133
134 if (Ptr.isZero())
135 return true;
136
137 // We can't inspect dead pointers at all. Return true here so we can
138 // diagnose them later.
139 if (!Ptr.isLive())
140 return true;
141
142 SourceLocation InitLoc;
143 if (const auto *D = dyn_cast<const Decl *>(Source))
144 InitLoc = cast<VarDecl>(D)->getAnyInitializer()->getExprLoc();
145 else if (const auto *E = dyn_cast<const Expr *>(Source))
146 InitLoc = E->getExprLoc();
147
148 if (const Record *R = Ptr.getRecord())
149 return CheckFieldsInitialized(S, InitLoc, Ptr, R);
150
151 if (const auto *CAT = dyn_cast_if_present<ConstantArrayType>(
153 return CheckArrayInitialized(S, InitLoc, Ptr, CAT);
154
155 return true;
156}
157
158static void collectBlocks(const Pointer &Ptr,
159 llvm::SetVector<const Block *> &Blocks) {
160 auto isUsefulPtr = [](const Pointer &P) -> bool {
161 return P.isLive() && P.isBlockPointer() && !P.isZero() && !P.isDummy() &&
162 P.isDereferencable() && !P.isUnknownSizeArray() && !P.isOnePastEnd();
163 };
164
165 if (!isUsefulPtr(Ptr))
166 return;
167
168 Blocks.insert(Ptr.block());
169
170 const Descriptor *Desc = Ptr.getFieldDesc();
171 if (!Desc)
172 return;
173
174 if (const Record *R = Desc->ElemRecord) {
175 for (const Record::Field &F : R->fields()) {
176 const Pointer &FieldPtr = Ptr.atField(F.Offset);
177 assert(FieldPtr.block() == Ptr.block());
178 collectBlocks(FieldPtr, Blocks);
179 }
180 } else if (Desc->isPrimitive() && Desc->getPrimType() == PT_Ptr) {
181 const Pointer &Pointee = Ptr.deref<Pointer>();
182 if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.block()))
183 collectBlocks(Pointee, Blocks);
184
185 } else if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) {
186 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
187 const Pointer &ElemPointee = Ptr.elem<Pointer>(I);
188 if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block()))
189 collectBlocks(ElemPointee, Blocks);
190 }
191 } else if (Desc->isCompositeArray()) {
192 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
193 const Pointer &ElemPtr = Ptr.atIndex(I).narrow();
194 collectBlocks(ElemPtr, Blocks);
195 }
196 }
197}
198
200 const Pointer &Ptr,
201 const SourceInfo &Info) {
202 // Collect all blocks that this pointer (transitively) points to and
203 // return false if any of them is a dynamic block.
204 llvm::SetVector<const Block *> Blocks;
205
206 collectBlocks(Ptr, Blocks);
207
208 for (const Block *B : Blocks) {
209 if (B->isDynamic()) {
210 assert(B->getDescriptor());
211 assert(B->getDescriptor()->asExpr());
212
213 bool IsSubobj = !Ptr.isRoot() || Ptr.isArrayElement();
214 S.FFDiag(Info, diag::note_constexpr_dynamic_alloc)
215 << Ptr.getType()->isReferenceType() << IsSubobj;
216 S.Note(B->getDescriptor()->asExpr()->getExprLoc(),
217 diag::note_constexpr_dynamic_alloc_here);
218 return false;
219 }
220 }
221
222 return true;
223}
224
225} // namespace interp
226} // namespace clang
llvm::MachO::Record Record
Definition MachO.h:31
QualType getElementType() const
Definition TypeBase.h:3732
Represents the canonical version of C arrays with a specified constant size.
Definition TypeBase.h:3758
uint64_t getZExtSize() const
Return the size zero-extended as a uint64_t.
Definition TypeBase.h:3834
SourceLocation getLocation() const
Definition DeclBase.h:439
Represents a member of a struct/union/class.
Definition Decl.h:3157
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:8629
bool isArrayType() const
Definition TypeBase.h:8621
bool isReferenceType() const
Definition TypeBase.h:8546
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9151
bool isRecordType() const
Definition TypeBase.h:8649
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:41
bool canClassify(QualType T)
Definition Context.h:97
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:43
Context & getContext() const
A pointer to a memory block, live or dead.
Definition Pointer.h:91
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition Pointer.h:188
bool isInitialized() const
Checks if an object was initialized.
Definition Pointer.cpp:432
bool isElementInitialized(unsigned Index) const
Like isInitialized(), but for primitive arrays.
Definition Pointer.cpp:455
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition Pointer.h:156
bool isActive() const
Checks if the object is active.
Definition Pointer.h:533
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition Pointer.h:173
T & deref() const
Dereferences the pointer, if it's live.
Definition Pointer.h:660
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:333
bool isArrayElement() const
Checks if the pointer points to an array.
Definition Pointer.h:418
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:265
T & elem(unsigned I) const
Dereferences the element at index I.
Definition Pointer.h:676
bool isZero() const
Checks if the pointer is null.
Definition Pointer.h:254
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:434
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition Pointer.h:279
const Record * getElemRecord() const
Returns the element record type, if this is a non-primive array.
Definition Pointer.h:473
const FieldDecl * getField() const
Returns the field information.
Definition Pointer.h:478
bool allElementsInitialized() const
Definition Pointer.cpp:550
const Block * block() const
Definition Pointer.h:599
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:323
const Record * getRecord() const
Returns the record descriptor of a class.
Definition Pointer.h:471
Structure/Class descriptor.
Definition Record.h:25
const RecordDecl * getDecl() const
Returns the underlying declaration.
Definition Record.h:53
bool isUnion() const
Checks if the record is a union.
Definition Record.h:57
llvm::iterator_range< const_base_iter > bases() const
Definition Record.h:92
llvm::iterator_range< const_field_iter > fields() const
Definition Record.h:84
Describes the statement/declaration an opcode was generated from.
Definition Source.h:73
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 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, const ConstantArrayType *CAT)
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:122
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:249
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:263
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition Descriptor.h:256
SourceLocation getLocation() const
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:254
PrimType getPrimType() const
Definition Descriptor.h:236
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:153