xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/EvaluationResult.cpp (revision a90b9d0159070121c221b966469c3e36d912bf82)
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 
15 namespace clang {
16 namespace interp {
17 
18 APValue EvaluationResult::toAPValue() const {
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 
39 std::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 
53 static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc,
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 
62 static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
63                                    const Pointer &BasePtr, const Record *R);
64 
65 static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
66                                   const Pointer &BasePtr,
67                                   const ConstantArrayType *CAT) {
68   bool Result = true;
69   size_t NumElems = CAT->getSize().getZExtValue();
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()) {
86         DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
87         Result = false;
88       }
89     }
90   }
91 
92   return Result;
93 }
94 
95 static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
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 (FieldType->isArrayType()) {
109       const auto *CAT =
110           cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
111       Result &= CheckArrayInitialized(S, Loc, FieldPtr, CAT);
112     } else if (!FieldPtr.isInitialized()) {
113       DiagnoseUninitializedSubobject(S, Loc, F.Decl);
114       Result = false;
115     }
116   }
117 
118   // Check Fields in all bases
119   for (const Record::Base &B : R->bases()) {
120     Pointer P = BasePtr.atField(B.Offset);
121     if (!P.isInitialized()) {
122       S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(),
123                diag::note_constexpr_uninitialized_base)
124           << B.Desc->getType();
125       return false;
126     }
127     Result &= CheckFieldsInitialized(S, Loc, P, B.R);
128   }
129 
130   // TODO: Virtual bases
131 
132   return Result;
133 }
134 
135 bool EvaluationResult::checkFullyInitialized(InterpState &S) const {
136   assert(Source);
137   assert(isLValue());
138 
139   // Our Source must be a VarDecl.
140   const Decl *SourceDecl = Source.dyn_cast<const Decl *>();
141   assert(SourceDecl);
142   const auto *VD = cast<VarDecl>(SourceDecl);
143   assert(VD->getType()->isRecordType() || VD->getType()->isArrayType());
144   SourceLocation InitLoc = VD->getAnyInitializer()->getExprLoc();
145 
146   const Pointer &Ptr = *std::get_if<Pointer>(&Value);
147   assert(!Ptr.isZero());
148 
149   if (const Record *R = Ptr.getRecord())
150     return CheckFieldsInitialized(S, InitLoc, Ptr, R);
151   const auto *CAT =
152       cast<ConstantArrayType>(Ptr.getType()->getAsArrayTypeUnsafe());
153   return CheckArrayInitialized(S, InitLoc, Ptr, CAT);
154 
155   return true;
156 }
157 
158 void EvaluationResult::dump() const {
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 
190   default:
191     llvm_unreachable("Can't print that.");
192   }
193 }
194 
195 } // namespace interp
196 } // namespace clang
197