xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/EvaluationResult.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
1*7a6dacacSDimitry Andric //===----- EvaluationResult.cpp - Result class  for the VM ------*- C++ -*-===//
2*7a6dacacSDimitry Andric //
3*7a6dacacSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*7a6dacacSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*7a6dacacSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*7a6dacacSDimitry Andric //
7*7a6dacacSDimitry Andric //===----------------------------------------------------------------------===//
8*7a6dacacSDimitry Andric 
9*7a6dacacSDimitry Andric #include "EvaluationResult.h"
10*7a6dacacSDimitry Andric #include "Context.h"
11*7a6dacacSDimitry Andric #include "InterpState.h"
12*7a6dacacSDimitry Andric #include "Record.h"
13*7a6dacacSDimitry Andric #include "clang/AST/ExprCXX.h"
14*7a6dacacSDimitry Andric 
15*7a6dacacSDimitry Andric namespace clang {
16*7a6dacacSDimitry Andric namespace interp {
17*7a6dacacSDimitry Andric 
18*7a6dacacSDimitry Andric APValue EvaluationResult::toAPValue() const {
19*7a6dacacSDimitry Andric   assert(!empty());
20*7a6dacacSDimitry Andric   switch (Kind) {
21*7a6dacacSDimitry Andric   case LValue:
22*7a6dacacSDimitry Andric     // Either a pointer or a function pointer.
23*7a6dacacSDimitry Andric     if (const auto *P = std::get_if<Pointer>(&Value))
24*7a6dacacSDimitry Andric       return P->toAPValue();
25*7a6dacacSDimitry Andric     else if (const auto *FP = std::get_if<FunctionPointer>(&Value))
26*7a6dacacSDimitry Andric       return FP->toAPValue();
27*7a6dacacSDimitry Andric     else
28*7a6dacacSDimitry Andric       llvm_unreachable("Unhandled LValue type");
29*7a6dacacSDimitry Andric     break;
30*7a6dacacSDimitry Andric   case RValue:
31*7a6dacacSDimitry Andric     return std::get<APValue>(Value);
32*7a6dacacSDimitry Andric   case Valid:
33*7a6dacacSDimitry Andric     return APValue();
34*7a6dacacSDimitry Andric   default:
35*7a6dacacSDimitry Andric     llvm_unreachable("Unhandled result kind?");
36*7a6dacacSDimitry Andric   }
37*7a6dacacSDimitry Andric }
38*7a6dacacSDimitry Andric 
39*7a6dacacSDimitry Andric std::optional<APValue> EvaluationResult::toRValue() const {
40*7a6dacacSDimitry Andric   if (Kind == RValue)
41*7a6dacacSDimitry Andric     return toAPValue();
42*7a6dacacSDimitry Andric 
43*7a6dacacSDimitry Andric   assert(Kind == LValue);
44*7a6dacacSDimitry Andric 
45*7a6dacacSDimitry Andric   // We have a pointer and want an RValue.
46*7a6dacacSDimitry Andric   if (const auto *P = std::get_if<Pointer>(&Value))
47*7a6dacacSDimitry Andric     return P->toRValue(*Ctx);
48*7a6dacacSDimitry Andric   else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
49*7a6dacacSDimitry Andric     return FP->toAPValue();
50*7a6dacacSDimitry Andric   llvm_unreachable("Unhandled lvalue kind");
51*7a6dacacSDimitry Andric }
52*7a6dacacSDimitry Andric 
53*7a6dacacSDimitry Andric static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc,
54*7a6dacacSDimitry Andric                                            const FieldDecl *SubObjDecl) {
55*7a6dacacSDimitry Andric   assert(SubObjDecl && "Subobject declaration does not exist");
56*7a6dacacSDimitry Andric   S.FFDiag(Loc, diag::note_constexpr_uninitialized)
57*7a6dacacSDimitry Andric       << /*(name)*/ 1 << SubObjDecl;
58*7a6dacacSDimitry Andric   S.Note(SubObjDecl->getLocation(),
59*7a6dacacSDimitry Andric          diag::note_constexpr_subobject_declared_here);
60*7a6dacacSDimitry Andric }
61*7a6dacacSDimitry Andric 
62*7a6dacacSDimitry Andric static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
63*7a6dacacSDimitry Andric                                    const Pointer &BasePtr, const Record *R);
64*7a6dacacSDimitry Andric 
65*7a6dacacSDimitry Andric static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
66*7a6dacacSDimitry Andric                                   const Pointer &BasePtr,
67*7a6dacacSDimitry Andric                                   const ConstantArrayType *CAT) {
68*7a6dacacSDimitry Andric   bool Result = true;
69*7a6dacacSDimitry Andric   size_t NumElems = CAT->getSize().getZExtValue();
70*7a6dacacSDimitry Andric   QualType ElemType = CAT->getElementType();
71*7a6dacacSDimitry Andric 
72*7a6dacacSDimitry Andric   if (ElemType->isRecordType()) {
73*7a6dacacSDimitry Andric     const Record *R = BasePtr.getElemRecord();
74*7a6dacacSDimitry Andric     for (size_t I = 0; I != NumElems; ++I) {
75*7a6dacacSDimitry Andric       Pointer ElemPtr = BasePtr.atIndex(I).narrow();
76*7a6dacacSDimitry Andric       Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);
77*7a6dacacSDimitry Andric     }
78*7a6dacacSDimitry Andric   } else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
79*7a6dacacSDimitry Andric     for (size_t I = 0; I != NumElems; ++I) {
80*7a6dacacSDimitry Andric       Pointer ElemPtr = BasePtr.atIndex(I).narrow();
81*7a6dacacSDimitry Andric       Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);
82*7a6dacacSDimitry Andric     }
83*7a6dacacSDimitry Andric   } else {
84*7a6dacacSDimitry Andric     for (size_t I = 0; I != NumElems; ++I) {
85*7a6dacacSDimitry Andric       if (!BasePtr.atIndex(I).isInitialized()) {
86*7a6dacacSDimitry Andric         DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
87*7a6dacacSDimitry Andric         Result = false;
88*7a6dacacSDimitry Andric       }
89*7a6dacacSDimitry Andric     }
90*7a6dacacSDimitry Andric   }
91*7a6dacacSDimitry Andric 
92*7a6dacacSDimitry Andric   return Result;
93*7a6dacacSDimitry Andric }
94*7a6dacacSDimitry Andric 
95*7a6dacacSDimitry Andric static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
96*7a6dacacSDimitry Andric                                    const Pointer &BasePtr, const Record *R) {
97*7a6dacacSDimitry Andric   assert(R);
98*7a6dacacSDimitry Andric   bool Result = true;
99*7a6dacacSDimitry Andric   // Check all fields of this record are initialized.
100*7a6dacacSDimitry Andric   for (const Record::Field &F : R->fields()) {
101*7a6dacacSDimitry Andric     Pointer FieldPtr = BasePtr.atField(F.Offset);
102*7a6dacacSDimitry Andric     QualType FieldType = F.Decl->getType();
103*7a6dacacSDimitry Andric 
104*7a6dacacSDimitry Andric     if (FieldType->isRecordType()) {
105*7a6dacacSDimitry Andric       Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());
106*7a6dacacSDimitry Andric     } else if (FieldType->isIncompleteArrayType()) {
107*7a6dacacSDimitry Andric       // Nothing to do here.
108*7a6dacacSDimitry Andric     } else if (FieldType->isArrayType()) {
109*7a6dacacSDimitry Andric       const auto *CAT =
110*7a6dacacSDimitry Andric           cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
111*7a6dacacSDimitry Andric       Result &= CheckArrayInitialized(S, Loc, FieldPtr, CAT);
112*7a6dacacSDimitry Andric     } else if (!FieldPtr.isInitialized()) {
113*7a6dacacSDimitry Andric       DiagnoseUninitializedSubobject(S, Loc, F.Decl);
114*7a6dacacSDimitry Andric       Result = false;
115*7a6dacacSDimitry Andric     }
116*7a6dacacSDimitry Andric   }
117*7a6dacacSDimitry Andric 
118*7a6dacacSDimitry Andric   // Check Fields in all bases
119*7a6dacacSDimitry Andric   for (const Record::Base &B : R->bases()) {
120*7a6dacacSDimitry Andric     Pointer P = BasePtr.atField(B.Offset);
121*7a6dacacSDimitry Andric     if (!P.isInitialized()) {
122*7a6dacacSDimitry Andric       S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(),
123*7a6dacacSDimitry Andric                diag::note_constexpr_uninitialized_base)
124*7a6dacacSDimitry Andric           << B.Desc->getType();
125*7a6dacacSDimitry Andric       return false;
126*7a6dacacSDimitry Andric     }
127*7a6dacacSDimitry Andric     Result &= CheckFieldsInitialized(S, Loc, P, B.R);
128*7a6dacacSDimitry Andric   }
129*7a6dacacSDimitry Andric 
130*7a6dacacSDimitry Andric   // TODO: Virtual bases
131*7a6dacacSDimitry Andric 
132*7a6dacacSDimitry Andric   return Result;
133*7a6dacacSDimitry Andric }
134*7a6dacacSDimitry Andric 
135*7a6dacacSDimitry Andric bool EvaluationResult::checkFullyInitialized(InterpState &S) const {
136*7a6dacacSDimitry Andric   assert(Source);
137*7a6dacacSDimitry Andric   assert(isLValue());
138*7a6dacacSDimitry Andric 
139*7a6dacacSDimitry Andric   // Our Source must be a VarDecl.
140*7a6dacacSDimitry Andric   const Decl *SourceDecl = Source.dyn_cast<const Decl *>();
141*7a6dacacSDimitry Andric   assert(SourceDecl);
142*7a6dacacSDimitry Andric   const auto *VD = cast<VarDecl>(SourceDecl);
143*7a6dacacSDimitry Andric   assert(VD->getType()->isRecordType() || VD->getType()->isArrayType());
144*7a6dacacSDimitry Andric   SourceLocation InitLoc = VD->getAnyInitializer()->getExprLoc();
145*7a6dacacSDimitry Andric 
146*7a6dacacSDimitry Andric   const Pointer &Ptr = *std::get_if<Pointer>(&Value);
147*7a6dacacSDimitry Andric   assert(!Ptr.isZero());
148*7a6dacacSDimitry Andric 
149*7a6dacacSDimitry Andric   if (const Record *R = Ptr.getRecord())
150*7a6dacacSDimitry Andric     return CheckFieldsInitialized(S, InitLoc, Ptr, R);
151*7a6dacacSDimitry Andric   const auto *CAT =
152*7a6dacacSDimitry Andric       cast<ConstantArrayType>(Ptr.getType()->getAsArrayTypeUnsafe());
153*7a6dacacSDimitry Andric   return CheckArrayInitialized(S, InitLoc, Ptr, CAT);
154*7a6dacacSDimitry Andric 
155*7a6dacacSDimitry Andric   return true;
156*7a6dacacSDimitry Andric }
157*7a6dacacSDimitry Andric 
158*7a6dacacSDimitry Andric void EvaluationResult::dump() const {
159*7a6dacacSDimitry Andric   assert(Ctx);
160*7a6dacacSDimitry Andric   auto &OS = llvm::errs();
161*7a6dacacSDimitry Andric   const ASTContext &ASTCtx = Ctx->getASTContext();
162*7a6dacacSDimitry Andric 
163*7a6dacacSDimitry Andric   switch (Kind) {
164*7a6dacacSDimitry Andric   case Empty:
165*7a6dacacSDimitry Andric     OS << "Empty\n";
166*7a6dacacSDimitry Andric     break;
167*7a6dacacSDimitry Andric   case RValue:
168*7a6dacacSDimitry Andric     OS << "RValue: ";
169*7a6dacacSDimitry Andric     std::get<APValue>(Value).dump(OS, ASTCtx);
170*7a6dacacSDimitry Andric     break;
171*7a6dacacSDimitry Andric   case LValue: {
172*7a6dacacSDimitry Andric     assert(Source);
173*7a6dacacSDimitry Andric     QualType SourceType;
174*7a6dacacSDimitry Andric     if (const auto *D = Source.dyn_cast<const Decl *>()) {
175*7a6dacacSDimitry Andric       if (const auto *VD = dyn_cast<ValueDecl>(D))
176*7a6dacacSDimitry Andric         SourceType = VD->getType();
177*7a6dacacSDimitry Andric     } else if (const auto *E = Source.dyn_cast<const Expr *>()) {
178*7a6dacacSDimitry Andric       SourceType = E->getType();
179*7a6dacacSDimitry Andric     }
180*7a6dacacSDimitry Andric 
181*7a6dacacSDimitry Andric     OS << "LValue: ";
182*7a6dacacSDimitry Andric     if (const auto *P = std::get_if<Pointer>(&Value))
183*7a6dacacSDimitry Andric       P->toAPValue().printPretty(OS, ASTCtx, SourceType);
184*7a6dacacSDimitry Andric     else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
185*7a6dacacSDimitry Andric       FP->toAPValue().printPretty(OS, ASTCtx, SourceType);
186*7a6dacacSDimitry Andric     OS << "\n";
187*7a6dacacSDimitry Andric     break;
188*7a6dacacSDimitry Andric   }
189*7a6dacacSDimitry Andric 
190*7a6dacacSDimitry Andric   default:
191*7a6dacacSDimitry Andric     llvm_unreachable("Can't print that.");
192*7a6dacacSDimitry Andric   }
193*7a6dacacSDimitry Andric }
194*7a6dacacSDimitry Andric 
195*7a6dacacSDimitry Andric } // namespace interp
196*7a6dacacSDimitry Andric } // namespace clang
197