1 //===--- InterpState.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 const auto &Src = S.Current->getSource(OpPC); 205 if (Ptr.isZero()) { 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 bool IsTemp = Ptr.isTemporary(); 217 218 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp; 219 220 if (IsTemp) 221 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here); 222 else 223 S.Note(Ptr.getDeclLoc(), diag::note_declared_at); 224 225 return false; 226 } 227 228 return true; 229 } 230 231 bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 232 CheckSubobjectKind CSK) { 233 if (!Ptr.isZero()) 234 return true; 235 const SourceInfo &Loc = S.Current->getSource(OpPC); 236 S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK; 237 return false; 238 } 239 240 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 241 AccessKinds AK) { 242 if (!Ptr.isOnePastEnd()) 243 return true; 244 const SourceInfo &Loc = S.Current->getSource(OpPC); 245 S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK; 246 return false; 247 } 248 249 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 250 CheckSubobjectKind CSK) { 251 if (!Ptr.isElementPastEnd()) 252 return true; 253 const SourceInfo &Loc = S.Current->getSource(OpPC); 254 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK; 255 return false; 256 } 257 258 bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 259 assert(Ptr.isLive() && "Pointer is not live"); 260 if (!Ptr.isConst()) { 261 return true; 262 } 263 264 const QualType Ty = Ptr.getType(); 265 const SourceInfo &Loc = S.Current->getSource(OpPC); 266 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty; 267 return false; 268 } 269 270 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 271 assert(Ptr.isLive() && "Pointer is not live"); 272 if (!Ptr.isMutable()) { 273 return true; 274 } 275 276 const SourceInfo &Loc = S.Current->getSource(OpPC); 277 const FieldDecl *Field = Ptr.getField(); 278 S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field; 279 S.Note(Field->getLocation(), diag::note_declared_at); 280 return false; 281 } 282 283 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 284 if (!CheckLive(S, OpPC, Ptr, AK_Read)) 285 return false; 286 if (!CheckExtern(S, OpPC, Ptr)) 287 return false; 288 if (!CheckRange(S, OpPC, Ptr, AK_Read)) 289 return false; 290 if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) 291 return false; 292 if (!CheckActive(S, OpPC, Ptr, AK_Read)) 293 return false; 294 if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) 295 return false; 296 if (!CheckMutable(S, OpPC, Ptr)) 297 return false; 298 return true; 299 } 300 301 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 302 if (!CheckLive(S, OpPC, Ptr, AK_Assign)) 303 return false; 304 if (!CheckExtern(S, OpPC, Ptr)) 305 return false; 306 if (!CheckRange(S, OpPC, Ptr, AK_Assign)) 307 return false; 308 if (!CheckGlobal(S, OpPC, Ptr)) 309 return false; 310 if (!CheckConst(S, OpPC, Ptr)) 311 return false; 312 return true; 313 } 314 315 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 316 if (!CheckLive(S, OpPC, Ptr, AK_MemberCall)) 317 return false; 318 if (!CheckExtern(S, OpPC, Ptr)) 319 return false; 320 if (!CheckRange(S, OpPC, Ptr, AK_MemberCall)) 321 return false; 322 return true; 323 } 324 325 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 326 if (!CheckLive(S, OpPC, Ptr, AK_Assign)) 327 return false; 328 if (!CheckRange(S, OpPC, Ptr, AK_Assign)) 329 return false; 330 return true; 331 } 332 333 bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F) { 334 const SourceLocation &Loc = S.Current->getLocation(OpPC); 335 336 if (F->isVirtual()) { 337 if (!S.getLangOpts().CPlusPlus20) { 338 S.CCEDiag(Loc, diag::note_constexpr_virtual_call); 339 return false; 340 } 341 } 342 343 if (!F->isConstexpr()) { 344 if (S.getLangOpts().CPlusPlus11) { 345 const FunctionDecl *DiagDecl = F->getDecl(); 346 347 // If this function is not constexpr because it is an inherited 348 // non-constexpr constructor, diagnose that directly. 349 auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl); 350 if (CD && CD->isInheritingConstructor()) { 351 auto *Inherited = CD->getInheritedConstructor().getConstructor(); 352 if (!Inherited->isConstexpr()) 353 DiagDecl = CD = Inherited; 354 } 355 356 // FIXME: If DiagDecl is an implicitly-declared special member function 357 // or an inheriting constructor, we should be much more explicit about why 358 // it's not constexpr. 359 if (CD && CD->isInheritingConstructor()) 360 S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1) 361 << CD->getInheritedConstructor().getConstructor()->getParent(); 362 else 363 S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1) 364 << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; 365 S.Note(DiagDecl->getLocation(), diag::note_declared_at); 366 } else { 367 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr); 368 } 369 return false; 370 } 371 372 return true; 373 } 374 375 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) { 376 if (!This.isZero()) 377 return true; 378 379 const SourceInfo &Loc = S.Current->getSource(OpPC); 380 381 bool IsImplicit = false; 382 if (auto *E = dyn_cast_or_null<CXXThisExpr>(Loc.asExpr())) 383 IsImplicit = E->isImplicit(); 384 385 if (S.getLangOpts().CPlusPlus11) 386 S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit; 387 else 388 S.FFDiag(Loc); 389 390 return false; 391 } 392 393 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) { 394 if (!MD->isPure()) 395 return true; 396 const SourceInfo &E = S.Current->getSource(OpPC); 397 S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD; 398 S.Note(MD->getLocation(), diag::note_declared_at); 399 return false; 400 } 401 bool Interpret(InterpState &S, APValue &Result) { 402 CodePtr PC = S.Current->getPC(); 403 404 for (;;) { 405 auto Op = PC.read<Opcode>(); 406 CodePtr OpPC = PC; 407 408 switch (Op) { 409 #define GET_INTERP 410 #include "Opcodes.inc" 411 #undef GET_INTERP 412 } 413 } 414 } 415 416 } // namespace interp 417 } // namespace clang 418