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