Home | History | Annotate | Line # | Download | only in Interp
      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