1 //===------- Interp.cpp - Interpreter for the constexpr 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 "Interp.h" 10 #include <limits> 11 #include <vector> 12 #include "Function.h" 13 #include "InterpFrame.h" 14 #include "InterpStack.h" 15 #include "Opcode.h" 16 #include "PrimType.h" 17 #include "Program.h" 18 #include "State.h" 19 #include "clang/AST/ASTContext.h" 20 #include "clang/AST/ASTDiagnostic.h" 21 #include "clang/AST/CXXInheritance.h" 22 #include "clang/AST/Expr.h" 23 #include "clang/AST/ExprCXX.h" 24 #include "llvm/ADT/APSInt.h" 25 26 using namespace clang; 27 using namespace clang::interp; 28 29 //===----------------------------------------------------------------------===// 30 // Ret 31 //===----------------------------------------------------------------------===// 32 33 template <PrimType Name, class T = typename PrimConv<Name>::T> 34 static bool Ret(InterpState &S, CodePtr &PC, APValue &Result) { 35 S.CallStackDepth--; 36 const T &Ret = S.Stk.pop<T>(); 37 38 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); 39 if (!S.checkingPotentialConstantExpression()) 40 S.Current->popArgs(); 41 42 if (InterpFrame *Caller = S.Current->Caller) { 43 PC = S.Current->getRetPC(); 44 delete S.Current; 45 S.Current = Caller; 46 S.Stk.push<T>(Ret); 47 } else { 48 delete S.Current; 49 S.Current = nullptr; 50 if (!ReturnValue<T>(Ret, Result)) 51 return false; 52 } 53 return true; 54 } 55 56 static bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) { 57 S.CallStackDepth--; 58 59 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); 60 if (!S.checkingPotentialConstantExpression()) 61 S.Current->popArgs(); 62 63 if (InterpFrame *Caller = S.Current->Caller) { 64 PC = S.Current->getRetPC(); 65 delete S.Current; 66 S.Current = Caller; 67 } else { 68 delete S.Current; 69 S.Current = nullptr; 70 } 71 return true; 72 } 73 74 static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) { 75 llvm::report_fatal_error("Interpreter cannot return values"); 76 } 77 78 //===----------------------------------------------------------------------===// 79 // Jmp, Jt, Jf 80 //===----------------------------------------------------------------------===// 81 82 static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) { 83 PC += Offset; 84 return true; 85 } 86 87 static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) { 88 if (S.Stk.pop<bool>()) { 89 PC += Offset; 90 } 91 return true; 92 } 93 94 static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) { 95 if (!S.Stk.pop<bool>()) { 96 PC += Offset; 97 } 98 return true; 99 } 100 101 static bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 102 AccessKinds AK) { 103 if (Ptr.isInitialized()) 104 return true; 105 if (!S.checkingPotentialConstantExpression()) { 106 const SourceInfo &Loc = S.Current->getSource(OpPC); 107 S.FFDiag(Loc, diag::note_constexpr_access_uninit) << AK << false; 108 } 109 return false; 110 } 111 112 static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 113 AccessKinds AK) { 114 if (Ptr.isActive()) 115 return true; 116 117 // Get the inactive field descriptor. 118 const FieldDecl *InactiveField = Ptr.getField(); 119 120 // Walk up the pointer chain to find the union which is not active. 121 Pointer U = Ptr.getBase(); 122 while (!U.isActive()) { 123 U = U.getBase(); 124 } 125 126 // Find the active field of the union. 127 Record *R = U.getRecord(); 128 assert(R && R->isUnion() && "Not a union"); 129 const FieldDecl *ActiveField = nullptr; 130 for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) { 131 const Pointer &Field = U.atField(R->getField(I)->Offset); 132 if (Field.isActive()) { 133 ActiveField = Field.getField(); 134 break; 135 } 136 } 137 138 const SourceInfo &Loc = S.Current->getSource(OpPC); 139 S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member) 140 << AK << InactiveField << !ActiveField << ActiveField; 141 return false; 142 } 143 144 static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 145 AccessKinds AK) { 146 if (auto ID = Ptr.getDeclID()) { 147 if (!Ptr.isStaticTemporary()) 148 return true; 149 150 if (Ptr.getDeclDesc()->getType().isConstQualified()) 151 return true; 152 153 if (S.P.getCurrentDecl() == ID) 154 return true; 155 156 const SourceInfo &E = S.Current->getSource(OpPC); 157 S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK; 158 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here); 159 return false; 160 } 161 return true; 162 } 163 164 static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 165 if (auto ID = Ptr.getDeclID()) { 166 if (!Ptr.isStatic()) 167 return true; 168 169 if (S.P.getCurrentDecl() == ID) 170 return true; 171 172 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global); 173 return false; 174 } 175 return true; 176 } 177 178 namespace clang { 179 namespace interp { 180 181 bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 182 if (!Ptr.isExtern()) 183 return true; 184 185 if (!S.checkingPotentialConstantExpression()) { 186 auto *VD = Ptr.getDeclDesc()->asValueDecl(); 187 const SourceInfo &Loc = S.Current->getSource(OpPC); 188 S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD; 189 S.Note(VD->getLocation(), diag::note_declared_at); 190 } 191 return false; 192 } 193 194 bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 195 if (!Ptr.isUnknownSizeArray()) 196 return true; 197 const SourceInfo &E = S.Current->getSource(OpPC); 198 S.FFDiag(E, diag::note_constexpr_unsized_array_indexed); 199 return false; 200 } 201 202 bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 203 AccessKinds AK) { 204 if (Ptr.isZero()) { 205 const auto &Src = S.Current->getSource(OpPC); 206 207 if (Ptr.isField()) 208 S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field; 209 else 210 S.FFDiag(Src, diag::note_constexpr_access_null) << AK; 211 212 return false; 213 } 214 215 if (!Ptr.isLive()) { 216 const auto &Src = S.Current->getSource(OpPC); 217 bool IsTemp = Ptr.isTemporary(); 218 219 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp; 220 221 if (IsTemp) 222 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here); 223 else 224 S.Note(Ptr.getDeclLoc(), diag::note_declared_at); 225 226 return false; 227 } 228 229 return true; 230 } 231 232 bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 233 CheckSubobjectKind CSK) { 234 if (!Ptr.isZero()) 235 return true; 236 const SourceInfo &Loc = S.Current->getSource(OpPC); 237 S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK; 238 return false; 239 } 240 241 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 242 AccessKinds AK) { 243 if (!Ptr.isOnePastEnd()) 244 return true; 245 const SourceInfo &Loc = S.Current->getSource(OpPC); 246 S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK; 247 return false; 248 } 249 250 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 251 CheckSubobjectKind CSK) { 252 if (!Ptr.isElementPastEnd()) 253 return true; 254 const SourceInfo &Loc = S.Current->getSource(OpPC); 255 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK; 256 return false; 257 } 258 259 bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 260 assert(Ptr.isLive() && "Pointer is not live"); 261 if (!Ptr.isConst()) { 262 return true; 263 } 264 265 const QualType Ty = Ptr.getType(); 266 const SourceInfo &Loc = S.Current->getSource(OpPC); 267 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty; 268 return false; 269 } 270 271 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 272 assert(Ptr.isLive() && "Pointer is not live"); 273 if (!Ptr.isMutable()) { 274 return true; 275 } 276 277 const SourceInfo &Loc = S.Current->getSource(OpPC); 278 const FieldDecl *Field = Ptr.getField(); 279 S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field; 280 S.Note(Field->getLocation(), diag::note_declared_at); 281 return false; 282 } 283 284 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 285 if (!CheckLive(S, OpPC, Ptr, AK_Read)) 286 return false; 287 if (!CheckExtern(S, OpPC, Ptr)) 288 return false; 289 if (!CheckRange(S, OpPC, Ptr, AK_Read)) 290 return false; 291 if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) 292 return false; 293 if (!CheckActive(S, OpPC, Ptr, AK_Read)) 294 return false; 295 if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) 296 return false; 297 if (!CheckMutable(S, OpPC, Ptr)) 298 return false; 299 return true; 300 } 301 302 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 303 if (!CheckLive(S, OpPC, Ptr, AK_Assign)) 304 return false; 305 if (!CheckExtern(S, OpPC, Ptr)) 306 return false; 307 if (!CheckRange(S, OpPC, Ptr, AK_Assign)) 308 return false; 309 if (!CheckGlobal(S, OpPC, Ptr)) 310 return false; 311 if (!CheckConst(S, OpPC, Ptr)) 312 return false; 313 return true; 314 } 315 316 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 317 if (!CheckLive(S, OpPC, Ptr, AK_MemberCall)) 318 return false; 319 if (!CheckExtern(S, OpPC, Ptr)) 320 return false; 321 if (!CheckRange(S, OpPC, Ptr, AK_MemberCall)) 322 return false; 323 return true; 324 } 325 326 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 327 if (!CheckLive(S, OpPC, Ptr, AK_Assign)) 328 return false; 329 if (!CheckRange(S, OpPC, Ptr, AK_Assign)) 330 return false; 331 return true; 332 } 333 334 bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { 335 336 if (F->isVirtual()) { 337 if (!S.getLangOpts().CPlusPlus20) { 338 const SourceLocation &Loc = S.Current->getLocation(OpPC); 339 S.CCEDiag(Loc, diag::note_constexpr_virtual_call); 340 return false; 341 } 342 } 343 344 if (!F->isConstexpr()) { 345 const SourceLocation &Loc = S.Current->getLocation(OpPC); 346 if (S.getLangOpts().CPlusPlus11) { 347 const FunctionDecl *DiagDecl = F->getDecl(); 348 349 // If this function is not constexpr because it is an inherited 350 // non-constexpr constructor, diagnose that directly. 351 auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl); 352 if (CD && CD->isInheritingConstructor()) { 353 auto *Inherited = CD->getInheritedConstructor().getConstructor(); 354 if (!Inherited->isConstexpr()) 355 DiagDecl = CD = Inherited; 356 } 357 358 // FIXME: If DiagDecl is an implicitly-declared special member function 359 // or an inheriting constructor, we should be much more explicit about why 360 // it's not constexpr. 361 if (CD && CD->isInheritingConstructor()) 362 S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1) 363 << CD->getInheritedConstructor().getConstructor()->getParent(); 364 else 365 S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1) 366 << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; 367 S.Note(DiagDecl->getLocation(), diag::note_declared_at); 368 } else { 369 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr); 370 } 371 return false; 372 } 373 374 return true; 375 } 376 377 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) { 378 if (!This.isZero()) 379 return true; 380 381 const SourceInfo &Loc = S.Current->getSource(OpPC); 382 383 bool IsImplicit = false; 384 if (auto *E = dyn_cast_or_null<CXXThisExpr>(Loc.asExpr())) 385 IsImplicit = E->isImplicit(); 386 387 if (S.getLangOpts().CPlusPlus11) 388 S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit; 389 else 390 S.FFDiag(Loc); 391 392 return false; 393 } 394 395 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) { 396 if (!MD->isPure()) 397 return true; 398 const SourceInfo &E = S.Current->getSource(OpPC); 399 S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD; 400 S.Note(MD->getLocation(), diag::note_declared_at); 401 return false; 402 } 403 404 static void DiagnoseUninitializedSubobject(InterpState &S, const SourceInfo &SI, 405 QualType SubObjType, 406 SourceLocation SubObjLoc) { 407 S.FFDiag(SI, diag::note_constexpr_uninitialized) << true << SubObjType; 408 if (SubObjLoc.isValid()) 409 S.Note(SubObjLoc, diag::note_constexpr_subobject_declared_here); 410 } 411 412 static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC, 413 const Pointer &BasePtr, const Record *R); 414 415 static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC, 416 const Pointer &BasePtr, 417 const ConstantArrayType *CAT) { 418 bool Result = true; 419 size_t NumElems = CAT->getSize().getZExtValue(); 420 QualType ElemType = CAT->getElementType(); 421 422 if (isa<RecordType>(ElemType.getTypePtr())) { 423 const Record *R = BasePtr.getElemRecord(); 424 for (size_t I = 0; I != NumElems; ++I) { 425 Pointer ElemPtr = BasePtr.atIndex(I).narrow(); 426 Result &= CheckFieldsInitialized(S, OpPC, ElemPtr, R); 427 } 428 } else if (auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) { 429 for (size_t I = 0; I != NumElems; ++I) { 430 Pointer ElemPtr = BasePtr.atIndex(I).narrow(); 431 Result &= CheckArrayInitialized(S, OpPC, ElemPtr, ElemCAT); 432 } 433 } else { 434 for (size_t I = 0; I != NumElems; ++I) { 435 if (!BasePtr.atIndex(I).isInitialized()) { 436 DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), ElemType, 437 BasePtr.getFieldDesc()->getLocation()); 438 Result = false; 439 } 440 } 441 } 442 443 return Result; 444 } 445 446 static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC, 447 const Pointer &BasePtr, const Record *R) { 448 assert(R); 449 bool Result = true; 450 // Check all fields of this record are initialized. 451 for (const Record::Field &F : R->fields()) { 452 Pointer FieldPtr = BasePtr.atField(F.Offset); 453 QualType FieldType = F.Decl->getType(); 454 455 if (FieldType->isRecordType()) { 456 Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord()); 457 } else if (FieldType->isArrayType()) { 458 const auto *CAT = 459 cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe()); 460 Result &= CheckArrayInitialized(S, OpPC, FieldPtr, CAT); 461 } else if (!FieldPtr.isInitialized()) { 462 DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), 463 F.Decl->getType(), F.Decl->getLocation()); 464 Result = false; 465 } 466 } 467 return Result; 468 } 469 470 bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) { 471 assert(!This.isZero()); 472 const Record *R = This.getRecord(); 473 return CheckFieldsInitialized(S, OpPC, This, R); 474 } 475 476 bool Interpret(InterpState &S, APValue &Result) { 477 // The current stack frame when we started Interpret(). 478 // This is being used by the ops to determine wheter 479 // to return from this function and thus terminate 480 // interpretation. 481 const InterpFrame *StartFrame = S.Current; 482 assert(!S.Current->isRoot()); 483 CodePtr PC = S.Current->getPC(); 484 485 // Empty program. 486 if (!PC) 487 return true; 488 489 for (;;) { 490 auto Op = PC.read<Opcode>(); 491 CodePtr OpPC = PC; 492 493 switch (Op) { 494 #define GET_INTERP 495 #include "Opcodes.inc" 496 #undef GET_INTERP 497 } 498 } 499 } 500 501 } // namespace interp 502 } // namespace clang 503