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