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) 386 << /*(name)*/ 1 << SubObjDecl; 387 S.Note(SubObjDecl->getLocation(), 388 diag::note_constexpr_subobject_declared_here); 389 } 390 391 static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC, 392 const Pointer &BasePtr, const Record *R); 393 394 static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC, 395 const Pointer &BasePtr, 396 const ConstantArrayType *CAT) { 397 bool Result = true; 398 size_t NumElems = CAT->getSize().getZExtValue(); 399 QualType ElemType = CAT->getElementType(); 400 401 if (ElemType->isRecordType()) { 402 const Record *R = BasePtr.getElemRecord(); 403 for (size_t I = 0; I != NumElems; ++I) { 404 Pointer ElemPtr = BasePtr.atIndex(I).narrow(); 405 Result &= CheckFieldsInitialized(S, OpPC, ElemPtr, R); 406 } 407 } else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) { 408 for (size_t I = 0; I != NumElems; ++I) { 409 Pointer ElemPtr = BasePtr.atIndex(I).narrow(); 410 Result &= CheckArrayInitialized(S, OpPC, ElemPtr, ElemCAT); 411 } 412 } else { 413 for (size_t I = 0; I != NumElems; ++I) { 414 if (!BasePtr.atIndex(I).isInitialized()) { 415 DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), 416 BasePtr.getField()); 417 Result = false; 418 } 419 } 420 } 421 422 return Result; 423 } 424 425 static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC, 426 const Pointer &BasePtr, const Record *R) { 427 assert(R); 428 bool Result = true; 429 // Check all fields of this record are initialized. 430 for (const Record::Field &F : R->fields()) { 431 Pointer FieldPtr = BasePtr.atField(F.Offset); 432 QualType FieldType = F.Decl->getType(); 433 434 if (FieldType->isRecordType()) { 435 Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord()); 436 } else if (FieldType->isArrayType()) { 437 const auto *CAT = 438 cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe()); 439 Result &= CheckArrayInitialized(S, OpPC, FieldPtr, CAT); 440 } else if (!FieldPtr.isInitialized()) { 441 DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), F.Decl); 442 Result = false; 443 } 444 } 445 446 // Check Fields in all bases 447 for (const Record::Base &B : R->bases()) { 448 Pointer P = BasePtr.atField(B.Offset); 449 Result &= CheckFieldsInitialized(S, OpPC, P, B.R); 450 } 451 452 // TODO: Virtual bases 453 454 return Result; 455 } 456 457 bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) { 458 assert(!This.isZero()); 459 if (const Record *R = This.getRecord()) 460 return CheckFieldsInitialized(S, OpPC, This, R); 461 const auto *CAT = 462 cast<ConstantArrayType>(This.getType()->getAsArrayTypeUnsafe()); 463 return CheckArrayInitialized(S, OpPC, This, CAT); 464 } 465 466 bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status) { 467 // In a constant context, assume that any dynamic rounding mode or FP 468 // exception state matches the default floating-point environment. 469 if (S.inConstantContext()) 470 return true; 471 472 const SourceInfo &E = S.Current->getSource(OpPC); 473 FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(S.Ctx.getLangOpts()); 474 475 if ((Status & APFloat::opInexact) && 476 FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) { 477 // Inexact result means that it depends on rounding mode. If the requested 478 // mode is dynamic, the evaluation cannot be made in compile time. 479 S.FFDiag(E, diag::note_constexpr_dynamic_rounding); 480 return false; 481 } 482 483 if ((Status != APFloat::opOK) && 484 (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic || 485 FPO.getExceptionMode() != LangOptions::FPE_Ignore || 486 FPO.getAllowFEnvAccess())) { 487 S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict); 488 return false; 489 } 490 491 if ((Status & APFloat::opStatus::opInvalidOp) && 492 FPO.getExceptionMode() != LangOptions::FPE_Ignore) { 493 // There is no usefully definable result. 494 S.FFDiag(E); 495 return false; 496 } 497 498 return true; 499 } 500 501 bool Interpret(InterpState &S, APValue &Result) { 502 // The current stack frame when we started Interpret(). 503 // This is being used by the ops to determine wheter 504 // to return from this function and thus terminate 505 // interpretation. 506 const InterpFrame *StartFrame = S.Current; 507 assert(!S.Current->isRoot()); 508 CodePtr PC = S.Current->getPC(); 509 510 // Empty program. 511 if (!PC) 512 return true; 513 514 for (;;) { 515 auto Op = PC.read<Opcode>(); 516 CodePtr OpPC = PC; 517 518 switch (Op) { 519 #define GET_INTERP 520 #include "Opcodes.inc" 521 #undef GET_INTERP 522 } 523 } 524 } 525 526 } // namespace interp 527 } // namespace clang 528