clang 19.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 "Context.h"
11#include "InterpState.h"
12#include "Record.h"
13#include "clang/AST/ExprCXX.h"
14
15namespace clang {
16namespace interp {
17
19 assert(!empty());
20 switch (Kind) {
21 case LValue:
22 // Either a pointer or a function pointer.
23 if (const auto *P = std::get_if<Pointer>(&Value))
24 return P->toAPValue();
25 else if (const auto *FP = std::get_if<FunctionPointer>(&Value))
26 return FP->toAPValue();
27 else
28 llvm_unreachable("Unhandled LValue type");
29 break;
30 case RValue:
31 return std::get<APValue>(Value);
32 case Valid:
33 return APValue();
34 default:
35 llvm_unreachable("Unhandled result kind?");
36 }
37}
38
39std::optional<APValue> EvaluationResult::toRValue() const {
40 if (Kind == RValue)
41 return toAPValue();
42
43 assert(Kind == LValue);
44
45 // We have a pointer and want an RValue.
46 if (const auto *P = std::get_if<Pointer>(&Value))
47 return P->toRValue(*Ctx);
48 else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
49 return FP->toAPValue();
50 llvm_unreachable("Unhandled lvalue kind");
51}
52
54 const FieldDecl *SubObjDecl) {
55 assert(SubObjDecl && "Subobject declaration does not exist");
56 S.FFDiag(Loc, diag::note_constexpr_uninitialized)
57 << /*(name)*/ 1 << SubObjDecl;
58 S.Note(SubObjDecl->getLocation(),
59 diag::note_constexpr_subobject_declared_here);
60}
61
62static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
63 const Pointer &BasePtr, const Record *R);
64
66 const Pointer &BasePtr,
67 const ConstantArrayType *CAT) {
68 bool Result = true;
69 size_t NumElems = CAT->getZExtSize();
70 QualType ElemType = CAT->getElementType();
71
72 if (ElemType->isRecordType()) {
73 const Record *R = BasePtr.getElemRecord();
74 for (size_t I = 0; I != NumElems; ++I) {
75 Pointer ElemPtr = BasePtr.atIndex(I).narrow();
76 Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);
77 }
78 } else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
79 for (size_t I = 0; I != NumElems; ++I) {
80 Pointer ElemPtr = BasePtr.atIndex(I).narrow();
81 Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);
82 }
83 } else {
84 for (size_t I = 0; I != NumElems; ++I) {
85 if (!BasePtr.atIndex(I).isInitialized()) {
87 Result = false;
88 }
89 }
90 }
91
92 return Result;
93}
94
96 const Pointer &BasePtr, const Record *R) {
97 assert(R);
98 bool Result = true;
99 // Check all fields of this record are initialized.
100 for (const Record::Field &F : R->fields()) {
101 Pointer FieldPtr = BasePtr.atField(F.Offset);
102 QualType FieldType = F.Decl->getType();
103
104 if (FieldType->isRecordType()) {
105 Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());
106 } else if (FieldType->isIncompleteArrayType()) {
107 // Nothing to do here.
108 } else if (F.Decl->isUnnamedBitfield()) {
109 // Nothing do do here.
110 } else if (FieldType->isArrayType()) {
111 const auto *CAT =
112 cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
113 Result &= CheckArrayInitialized(S, Loc, FieldPtr, CAT);
114 } else if (!FieldPtr.isInitialized()) {
115 DiagnoseUninitializedSubobject(S, Loc, F.Decl);
116 Result = false;
117 }
118 }
119
120 // Check Fields in all bases
121 for (const Record::Base &B : R->bases()) {
122 Pointer P = BasePtr.atField(B.Offset);
123 if (!P.isInitialized()) {
124 S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(),
125 diag::note_constexpr_uninitialized_base)
126 << B.Desc->getType();
127 return false;
128 }
129 Result &= CheckFieldsInitialized(S, Loc, P, B.R);
130 }
131
132 // TODO: Virtual bases
133
134 return Result;
135}
136
138 const Pointer &Ptr) const {
139 assert(Source);
140 assert(empty());
141
142 // Our Source must be a VarDecl.
143 const Decl *SourceDecl = Source.dyn_cast<const Decl *>();
144 assert(SourceDecl);
145 const auto *VD = cast<VarDecl>(SourceDecl);
146 assert(VD->getType()->isRecordType() || VD->getType()->isArrayType());
147 SourceLocation InitLoc = VD->getAnyInitializer()->getExprLoc();
148
149 assert(!Ptr.isZero());
150
151 if (const Record *R = Ptr.getRecord())
152 return CheckFieldsInitialized(S, InitLoc, Ptr, R);
153 const auto *CAT =
154 cast<ConstantArrayType>(Ptr.getType()->getAsArrayTypeUnsafe());
155 return CheckArrayInitialized(S, InitLoc, Ptr, CAT);
156}
157
159 assert(Ctx);
160 auto &OS = llvm::errs();
161 const ASTContext &ASTCtx = Ctx->getASTContext();
162
163 switch (Kind) {
164 case Empty:
165 OS << "Empty\n";
166 break;
167 case RValue:
168 OS << "RValue: ";
169 std::get<APValue>(Value).dump(OS, ASTCtx);
170 break;
171 case LValue: {
172 assert(Source);
173 QualType SourceType;
174 if (const auto *D = Source.dyn_cast<const Decl *>()) {
175 if (const auto *VD = dyn_cast<ValueDecl>(D))
176 SourceType = VD->getType();
177 } else if (const auto *E = Source.dyn_cast<const Expr *>()) {
178 SourceType = E->getType();
179 }
180
181 OS << "LValue: ";
182 if (const auto *P = std::get_if<Pointer>(&Value))
183 P->toAPValue().printPretty(OS, ASTCtx, SourceType);
184 else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
185 FP->toAPValue().printPretty(OS, ASTCtx, SourceType);
186 OS << "\n";
187 break;
188 }
189 case Invalid:
190 OS << "Invalid\n";
191 break;
192 case Valid:
193 OS << "Valid\n";
194 break;
195 }
196}
197
198} // namespace interp
199} // namespace clang
StringRef P
Defines the clang::Expr interface and subclasses for C++ expressions.
llvm::MachO::Record Record
Definition: MachO.h:30
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
QualType getElementType() const
Definition: Type.h:3320
Represents the canonical version of C arrays with a specified constant size.
Definition: Type.h:3346
uint64_t getZExtSize() const
Return the size zero-extended as a uint64_t.
Definition: Type.h:3422
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:85
SourceLocation getLocation() const
Definition: DeclBase.h:444
This represents one expression.
Definition: Expr.h:110
Represents a member of a struct/union/class.
Definition: Decl.h:3037
A (possibly-)qualified type.
Definition: Type.h:738
Encodes a location in the source.
bool isIncompleteArrayType() const
Definition: Type.h:7476
bool isArrayType() const
Definition: Type.h:7468
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition: Type.h:7966
bool isRecordType() const
Definition: Type.h:7496
ASTContext & getASTContext() const
Returns the AST context.
Definition: Context.h:61
void dump() const
Dump to stderr.
std::optional< APValue > toRValue() const
If the result is an LValue, convert that to an RValue and return it.
APValue toAPValue() const
Returns an APValue for the evaluation result.
bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const
Interpreter context.
Definition: InterpState.h:35
A pointer to a memory block, live or dead.
Definition: Pointer.h:80
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:170
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:216
Pointer atIndex(unsigned Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:137
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:154
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:321
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:243
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:269
const Record * getElemRecord() const
Returns the element record type, if this is a non-primive array.
Definition: Pointer.h:435
const FieldDecl * getField() const
Returns the field information.
Definition: Pointer.h:440
const Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:433
Structure/Class descriptor.
Definition: Record.h:25
llvm::iterator_range< const_base_iter > bases() const
Definition: Record.h:85
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:77
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.
const Decl * asDecl() const
Definition: Descriptor.h:169