1bdd1243dSDimitry Andric //===------- Interp.cpp - Interpreter for the constexpr VM ------*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric
9a7dea167SDimitry Andric #include "Interp.h"
10a7dea167SDimitry Andric #include "Function.h"
11a7dea167SDimitry Andric #include "InterpFrame.h"
120fca6ea1SDimitry Andric #include "InterpShared.h"
13a7dea167SDimitry Andric #include "InterpStack.h"
14a7dea167SDimitry Andric #include "Opcode.h"
15a7dea167SDimitry Andric #include "PrimType.h"
16a7dea167SDimitry Andric #include "Program.h"
17a7dea167SDimitry Andric #include "State.h"
18a7dea167SDimitry Andric #include "clang/AST/ASTContext.h"
19a7dea167SDimitry Andric #include "clang/AST/ASTDiagnostic.h"
20a7dea167SDimitry Andric #include "clang/AST/CXXInheritance.h"
210fca6ea1SDimitry Andric #include "clang/AST/DeclObjC.h"
22a7dea167SDimitry Andric #include "clang/AST/Expr.h"
23a7dea167SDimitry Andric #include "clang/AST/ExprCXX.h"
24a7dea167SDimitry Andric #include "llvm/ADT/APSInt.h"
250fca6ea1SDimitry Andric #include "llvm/ADT/StringExtras.h"
260fca6ea1SDimitry Andric #include <limits>
270fca6ea1SDimitry Andric #include <vector>
280fca6ea1SDimitry Andric
290fca6ea1SDimitry Andric using namespace clang;
30a7dea167SDimitry Andric
31a7dea167SDimitry Andric using namespace clang;
32a7dea167SDimitry Andric using namespace clang::interp;
33a7dea167SDimitry Andric
RetValue(InterpState & S,CodePtr & Pt,APValue & Result)34a7dea167SDimitry Andric static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
35a7dea167SDimitry Andric llvm::report_fatal_error("Interpreter cannot return values");
36a7dea167SDimitry Andric }
37a7dea167SDimitry Andric
38a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
39a7dea167SDimitry Andric // Jmp, Jt, Jf
40a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
41a7dea167SDimitry Andric
Jmp(InterpState & S,CodePtr & PC,int32_t Offset)42a7dea167SDimitry Andric static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
43a7dea167SDimitry Andric PC += Offset;
44a7dea167SDimitry Andric return true;
45a7dea167SDimitry Andric }
46a7dea167SDimitry Andric
Jt(InterpState & S,CodePtr & PC,int32_t Offset)47a7dea167SDimitry Andric static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
48a7dea167SDimitry Andric if (S.Stk.pop<bool>()) {
49a7dea167SDimitry Andric PC += Offset;
50a7dea167SDimitry Andric }
51a7dea167SDimitry Andric return true;
52a7dea167SDimitry Andric }
53a7dea167SDimitry Andric
Jf(InterpState & S,CodePtr & PC,int32_t Offset)54a7dea167SDimitry Andric static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
55a7dea167SDimitry Andric if (!S.Stk.pop<bool>()) {
56a7dea167SDimitry Andric PC += Offset;
57a7dea167SDimitry Andric }
58a7dea167SDimitry Andric return true;
59a7dea167SDimitry Andric }
60a7dea167SDimitry Andric
diagnoseMissingInitializer(InterpState & S,CodePtr OpPC,const ValueDecl * VD)610fca6ea1SDimitry Andric static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC,
620fca6ea1SDimitry Andric const ValueDecl *VD) {
630fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
640fca6ea1SDimitry Andric S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
650fca6ea1SDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
660fca6ea1SDimitry Andric }
670fca6ea1SDimitry Andric
680fca6ea1SDimitry Andric static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
690fca6ea1SDimitry Andric const ValueDecl *VD);
diagnoseUnknownDecl(InterpState & S,CodePtr OpPC,const ValueDecl * D)700fca6ea1SDimitry Andric static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,
710fca6ea1SDimitry Andric const ValueDecl *D) {
720fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
730fca6ea1SDimitry Andric
740fca6ea1SDimitry Andric if (isa<ParmVarDecl>(D)) {
750fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus11) {
760fca6ea1SDimitry Andric S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D;
770fca6ea1SDimitry Andric S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
780fca6ea1SDimitry Andric } else {
790fca6ea1SDimitry Andric S.FFDiag(E);
800fca6ea1SDimitry Andric }
810fca6ea1SDimitry Andric return false;
820fca6ea1SDimitry Andric }
830fca6ea1SDimitry Andric
840fca6ea1SDimitry Andric if (!D->getType().isConstQualified())
850fca6ea1SDimitry Andric diagnoseNonConstVariable(S, OpPC, D);
860fca6ea1SDimitry Andric else if (const auto *VD = dyn_cast<VarDecl>(D);
870fca6ea1SDimitry Andric VD && !VD->getAnyInitializer())
880fca6ea1SDimitry Andric diagnoseMissingInitializer(S, OpPC, VD);
890fca6ea1SDimitry Andric
900fca6ea1SDimitry Andric return false;
910fca6ea1SDimitry Andric }
920fca6ea1SDimitry Andric
diagnoseNonConstVariable(InterpState & S,CodePtr OpPC,const ValueDecl * VD)937a6dacacSDimitry Andric static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
947a6dacacSDimitry Andric const ValueDecl *VD) {
957a6dacacSDimitry Andric if (!S.getLangOpts().CPlusPlus)
967a6dacacSDimitry Andric return;
977a6dacacSDimitry Andric
987a6dacacSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
990fca6ea1SDimitry Andric if (const auto *VarD = dyn_cast<VarDecl>(VD);
1000fca6ea1SDimitry Andric VarD && VarD->getType().isConstQualified() &&
1010fca6ea1SDimitry Andric !VarD->getAnyInitializer()) {
1020fca6ea1SDimitry Andric diagnoseMissingInitializer(S, OpPC, VD);
1030fca6ea1SDimitry Andric return;
1040fca6ea1SDimitry Andric }
1057a6dacacSDimitry Andric
1060fca6ea1SDimitry Andric // Rather random, but this is to match the diagnostic output of the current
1070fca6ea1SDimitry Andric // interpreter.
1080fca6ea1SDimitry Andric if (isa<ObjCIvarDecl>(VD))
1090fca6ea1SDimitry Andric return;
1100fca6ea1SDimitry Andric
1110fca6ea1SDimitry Andric if (VD->getType()->isIntegralOrEnumerationType()) {
1127a6dacacSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
1130fca6ea1SDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at);
1140fca6ea1SDimitry Andric return;
1150fca6ea1SDimitry Andric }
1160fca6ea1SDimitry Andric
1177a6dacacSDimitry Andric S.FFDiag(Loc,
1180fca6ea1SDimitry Andric S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
1197a6dacacSDimitry Andric : diag::note_constexpr_ltor_non_integral,
1207a6dacacSDimitry Andric 1)
1217a6dacacSDimitry Andric << VD << VD->getType();
1227a6dacacSDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at);
1237a6dacacSDimitry Andric }
1247a6dacacSDimitry Andric
CheckActive(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)125a7dea167SDimitry Andric static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
126a7dea167SDimitry Andric AccessKinds AK) {
127a7dea167SDimitry Andric if (Ptr.isActive())
128a7dea167SDimitry Andric return true;
129a7dea167SDimitry Andric
130a7dea167SDimitry Andric // Get the inactive field descriptor.
131a7dea167SDimitry Andric const FieldDecl *InactiveField = Ptr.getField();
132a7dea167SDimitry Andric
133a7dea167SDimitry Andric // Walk up the pointer chain to find the union which is not active.
134a7dea167SDimitry Andric Pointer U = Ptr.getBase();
135a7dea167SDimitry Andric while (!U.isActive()) {
136a7dea167SDimitry Andric U = U.getBase();
137a7dea167SDimitry Andric }
138a7dea167SDimitry Andric
139a7dea167SDimitry Andric // Find the active field of the union.
14006c3fb27SDimitry Andric const Record *R = U.getRecord();
141a7dea167SDimitry Andric assert(R && R->isUnion() && "Not a union");
142a7dea167SDimitry Andric const FieldDecl *ActiveField = nullptr;
143a7dea167SDimitry Andric for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
144a7dea167SDimitry Andric const Pointer &Field = U.atField(R->getField(I)->Offset);
145a7dea167SDimitry Andric if (Field.isActive()) {
146a7dea167SDimitry Andric ActiveField = Field.getField();
147a7dea167SDimitry Andric break;
148a7dea167SDimitry Andric }
149a7dea167SDimitry Andric }
150a7dea167SDimitry Andric
151a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
152a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
153a7dea167SDimitry Andric << AK << InactiveField << !ActiveField << ActiveField;
154a7dea167SDimitry Andric return false;
155a7dea167SDimitry Andric }
156a7dea167SDimitry Andric
CheckTemporary(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)157a7dea167SDimitry Andric static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
158a7dea167SDimitry Andric AccessKinds AK) {
159a7dea167SDimitry Andric if (auto ID = Ptr.getDeclID()) {
160a7dea167SDimitry Andric if (!Ptr.isStaticTemporary())
161a7dea167SDimitry Andric return true;
162a7dea167SDimitry Andric
163a7dea167SDimitry Andric if (Ptr.getDeclDesc()->getType().isConstQualified())
164a7dea167SDimitry Andric return true;
165a7dea167SDimitry Andric
166a7dea167SDimitry Andric if (S.P.getCurrentDecl() == ID)
167a7dea167SDimitry Andric return true;
168a7dea167SDimitry Andric
169a7dea167SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
170a7dea167SDimitry Andric S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
171a7dea167SDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
172a7dea167SDimitry Andric return false;
173a7dea167SDimitry Andric }
174a7dea167SDimitry Andric return true;
175a7dea167SDimitry Andric }
176a7dea167SDimitry Andric
CheckGlobal(InterpState & S,CodePtr OpPC,const Pointer & Ptr)177a7dea167SDimitry Andric static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
178a7dea167SDimitry Andric if (auto ID = Ptr.getDeclID()) {
179a7dea167SDimitry Andric if (!Ptr.isStatic())
180a7dea167SDimitry Andric return true;
181a7dea167SDimitry Andric
182a7dea167SDimitry Andric if (S.P.getCurrentDecl() == ID)
183a7dea167SDimitry Andric return true;
184a7dea167SDimitry Andric
185a7dea167SDimitry Andric S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
186a7dea167SDimitry Andric return false;
187a7dea167SDimitry Andric }
188a7dea167SDimitry Andric return true;
189a7dea167SDimitry Andric }
190a7dea167SDimitry Andric
191a7dea167SDimitry Andric namespace clang {
192a7dea167SDimitry Andric namespace interp {
popArg(InterpState & S,const Expr * Arg)1935f757f3fSDimitry Andric static void popArg(InterpState &S, const Expr *Arg) {
1940fca6ea1SDimitry Andric PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr);
1955f757f3fSDimitry Andric TYPE_SWITCH(Ty, S.Stk.discard<T>());
1965f757f3fSDimitry Andric }
1975f757f3fSDimitry Andric
cleanupAfterFunctionCall(InterpState & S,CodePtr OpPC)1985f757f3fSDimitry Andric void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {
1995f757f3fSDimitry Andric assert(S.Current);
2005f757f3fSDimitry Andric const Function *CurFunc = S.Current->getFunction();
2015f757f3fSDimitry Andric assert(CurFunc);
2025f757f3fSDimitry Andric
2035f757f3fSDimitry Andric if (CurFunc->isUnevaluatedBuiltin())
2045f757f3fSDimitry Andric return;
2055f757f3fSDimitry Andric
206297eecfbSDimitry Andric // Some builtin functions require us to only look at the call site, since
207297eecfbSDimitry Andric // the classified parameter types do not match.
208297eecfbSDimitry Andric if (CurFunc->isBuiltin()) {
209297eecfbSDimitry Andric const auto *CE =
210297eecfbSDimitry Andric cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
211297eecfbSDimitry Andric for (int32_t I = CE->getNumArgs() - 1; I >= 0; --I) {
212297eecfbSDimitry Andric const Expr *A = CE->getArg(I);
213297eecfbSDimitry Andric popArg(S, A);
214297eecfbSDimitry Andric }
215297eecfbSDimitry Andric return;
216297eecfbSDimitry Andric }
217297eecfbSDimitry Andric
2185f757f3fSDimitry Andric if (S.Current->Caller && CurFunc->isVariadic()) {
2195f757f3fSDimitry Andric // CallExpr we're look for is at the return PC of the current function, i.e.
2205f757f3fSDimitry Andric // in the caller.
2215f757f3fSDimitry Andric // This code path should be executed very rarely.
2220fca6ea1SDimitry Andric unsigned NumVarArgs;
2230fca6ea1SDimitry Andric const Expr *const *Args = nullptr;
2240fca6ea1SDimitry Andric unsigned NumArgs = 0;
2250fca6ea1SDimitry Andric const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());
2260fca6ea1SDimitry Andric if (const auto *CE = dyn_cast<CallExpr>(CallSite)) {
2270fca6ea1SDimitry Andric Args = CE->getArgs();
2280fca6ea1SDimitry Andric NumArgs = CE->getNumArgs();
2290fca6ea1SDimitry Andric } else if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {
2300fca6ea1SDimitry Andric Args = CE->getArgs();
2310fca6ea1SDimitry Andric NumArgs = CE->getNumArgs();
2320fca6ea1SDimitry Andric } else
2330fca6ea1SDimitry Andric assert(false && "Can't get arguments from that expression type");
2340fca6ea1SDimitry Andric
2350fca6ea1SDimitry Andric assert(NumArgs >= CurFunc->getNumWrittenParams());
2360fca6ea1SDimitry Andric NumVarArgs = NumArgs - CurFunc->getNumWrittenParams();
2370fca6ea1SDimitry Andric for (unsigned I = 0; I != NumVarArgs; ++I) {
2380fca6ea1SDimitry Andric const Expr *A = Args[NumArgs - 1 - I];
2395f757f3fSDimitry Andric popArg(S, A);
2405f757f3fSDimitry Andric }
2415f757f3fSDimitry Andric }
2420fca6ea1SDimitry Andric
2435f757f3fSDimitry Andric // And in any case, remove the fixed parameters (the non-variadic ones)
2445f757f3fSDimitry Andric // at the end.
2455f757f3fSDimitry Andric S.Current->popArgs();
2465f757f3fSDimitry Andric }
247a7dea167SDimitry Andric
CheckExtern(InterpState & S,CodePtr OpPC,const Pointer & Ptr)248a7dea167SDimitry Andric bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
249a7dea167SDimitry Andric if (!Ptr.isExtern())
250a7dea167SDimitry Andric return true;
251a7dea167SDimitry Andric
2520fca6ea1SDimitry Andric if (Ptr.isInitialized() ||
2530fca6ea1SDimitry Andric (Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl))
2540fca6ea1SDimitry Andric return true;
2550fca6ea1SDimitry Andric
2565f757f3fSDimitry Andric if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) {
25706c3fb27SDimitry Andric const auto *VD = Ptr.getDeclDesc()->asValueDecl();
2587a6dacacSDimitry Andric diagnoseNonConstVariable(S, OpPC, VD);
259a7dea167SDimitry Andric }
260a7dea167SDimitry Andric return false;
261a7dea167SDimitry Andric }
262a7dea167SDimitry Andric
CheckArray(InterpState & S,CodePtr OpPC,const Pointer & Ptr)263a7dea167SDimitry Andric bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
264a7dea167SDimitry Andric if (!Ptr.isUnknownSizeArray())
265a7dea167SDimitry Andric return true;
266a7dea167SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
267a7dea167SDimitry Andric S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
268a7dea167SDimitry Andric return false;
269a7dea167SDimitry Andric }
270a7dea167SDimitry Andric
CheckLive(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)271a7dea167SDimitry Andric bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
272a7dea167SDimitry Andric AccessKinds AK) {
273a7dea167SDimitry Andric if (Ptr.isZero()) {
274bdd1243dSDimitry Andric const auto &Src = S.Current->getSource(OpPC);
275a7dea167SDimitry Andric
276a7dea167SDimitry Andric if (Ptr.isField())
277a7dea167SDimitry Andric S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
278a7dea167SDimitry Andric else
279a7dea167SDimitry Andric S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
280a7dea167SDimitry Andric
281a7dea167SDimitry Andric return false;
282a7dea167SDimitry Andric }
283a7dea167SDimitry Andric
284a7dea167SDimitry Andric if (!Ptr.isLive()) {
285bdd1243dSDimitry Andric const auto &Src = S.Current->getSource(OpPC);
286a7dea167SDimitry Andric bool IsTemp = Ptr.isTemporary();
287a7dea167SDimitry Andric
288a7dea167SDimitry Andric S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
289a7dea167SDimitry Andric
290a7dea167SDimitry Andric if (IsTemp)
291a7dea167SDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
292a7dea167SDimitry Andric else
293a7dea167SDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
294a7dea167SDimitry Andric
295a7dea167SDimitry Andric return false;
296a7dea167SDimitry Andric }
297a7dea167SDimitry Andric
298a7dea167SDimitry Andric return true;
299a7dea167SDimitry Andric }
300a7dea167SDimitry Andric
CheckConstant(InterpState & S,CodePtr OpPC,const Descriptor * Desc)3017a6dacacSDimitry Andric bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
3027a6dacacSDimitry Andric assert(Desc);
3037a6dacacSDimitry Andric
3047a6dacacSDimitry Andric auto IsConstType = [&S](const VarDecl *VD) -> bool {
3057a6dacacSDimitry Andric if (VD->isConstexpr())
3067a6dacacSDimitry Andric return true;
3077a6dacacSDimitry Andric
3087a6dacacSDimitry Andric QualType T = VD->getType();
3090fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)
3100fca6ea1SDimitry Andric return (T->isSignedIntegerOrEnumerationType() ||
3110fca6ea1SDimitry Andric T->isUnsignedIntegerOrEnumerationType()) &&
3120fca6ea1SDimitry Andric T.isConstQualified();
3130fca6ea1SDimitry Andric
3147a6dacacSDimitry Andric if (T.isConstQualified())
3157a6dacacSDimitry Andric return true;
3167a6dacacSDimitry Andric
3177a6dacacSDimitry Andric if (const auto *RT = T->getAs<ReferenceType>())
3187a6dacacSDimitry Andric return RT->getPointeeType().isConstQualified();
3197a6dacacSDimitry Andric
3207a6dacacSDimitry Andric if (const auto *PT = T->getAs<PointerType>())
3217a6dacacSDimitry Andric return PT->getPointeeType().isConstQualified();
3227a6dacacSDimitry Andric
3237a6dacacSDimitry Andric return false;
3247a6dacacSDimitry Andric };
3257a6dacacSDimitry Andric
3260fca6ea1SDimitry Andric if (const auto *D = Desc->asVarDecl();
3270fca6ea1SDimitry Andric D && D->hasGlobalStorage() && D != S.EvaluatingDecl && !IsConstType(D)) {
3280fca6ea1SDimitry Andric diagnoseNonConstVariable(S, OpPC, D);
3297a6dacacSDimitry Andric return S.inConstantContext();
3307a6dacacSDimitry Andric }
3317a6dacacSDimitry Andric
3327a6dacacSDimitry Andric return true;
3337a6dacacSDimitry Andric }
3347a6dacacSDimitry Andric
CheckConstant(InterpState & S,CodePtr OpPC,const Pointer & Ptr)3357a6dacacSDimitry Andric static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
3360fca6ea1SDimitry Andric if (Ptr.isIntegralPointer())
3370fca6ea1SDimitry Andric return true;
3387a6dacacSDimitry Andric return CheckConstant(S, OpPC, Ptr.getDeclDesc());
3397a6dacacSDimitry Andric }
3407a6dacacSDimitry Andric
CheckNull(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)341a7dea167SDimitry Andric bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
342a7dea167SDimitry Andric CheckSubobjectKind CSK) {
343a7dea167SDimitry Andric if (!Ptr.isZero())
344a7dea167SDimitry Andric return true;
345a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
3460fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_null_subobject)
3470fca6ea1SDimitry Andric << CSK << S.Current->getRange(OpPC);
3480fca6ea1SDimitry Andric
349a7dea167SDimitry Andric return false;
350a7dea167SDimitry Andric }
351a7dea167SDimitry Andric
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)352a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
353a7dea167SDimitry Andric AccessKinds AK) {
354a7dea167SDimitry Andric if (!Ptr.isOnePastEnd())
355a7dea167SDimitry Andric return true;
356a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
3570fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_past_end)
3580fca6ea1SDimitry Andric << AK << S.Current->getRange(OpPC);
359a7dea167SDimitry Andric return false;
360a7dea167SDimitry Andric }
361a7dea167SDimitry Andric
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)362a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
363a7dea167SDimitry Andric CheckSubobjectKind CSK) {
364a7dea167SDimitry Andric if (!Ptr.isElementPastEnd())
365a7dea167SDimitry Andric return true;
366a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
3670fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
3680fca6ea1SDimitry Andric << CSK << S.Current->getRange(OpPC);
369a7dea167SDimitry Andric return false;
370a7dea167SDimitry Andric }
371a7dea167SDimitry Andric
CheckSubobject(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)3725f757f3fSDimitry Andric bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
3735f757f3fSDimitry Andric CheckSubobjectKind CSK) {
3745f757f3fSDimitry Andric if (!Ptr.isOnePastEnd())
3755f757f3fSDimitry Andric return true;
3765f757f3fSDimitry Andric
3775f757f3fSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
3780fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
3790fca6ea1SDimitry Andric << CSK << S.Current->getRange(OpPC);
3800fca6ea1SDimitry Andric return false;
3810fca6ea1SDimitry Andric }
3820fca6ea1SDimitry Andric
CheckDowncast(InterpState & S,CodePtr OpPC,const Pointer & Ptr,uint32_t Offset)3830fca6ea1SDimitry Andric bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
3840fca6ea1SDimitry Andric uint32_t Offset) {
3850fca6ea1SDimitry Andric uint32_t MinOffset = Ptr.getDeclDesc()->getMetadataSize();
3860fca6ea1SDimitry Andric uint32_t PtrOffset = Ptr.getByteOffset();
3870fca6ea1SDimitry Andric
3880fca6ea1SDimitry Andric // We subtract Offset from PtrOffset. The result must be at least
3890fca6ea1SDimitry Andric // MinOffset.
3900fca6ea1SDimitry Andric if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)
3910fca6ea1SDimitry Andric return true;
3920fca6ea1SDimitry Andric
3930fca6ea1SDimitry Andric const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));
3940fca6ea1SDimitry Andric QualType TargetQT = E->getType()->getPointeeType();
3950fca6ea1SDimitry Andric QualType MostDerivedQT = Ptr.getDeclPtr().getType();
3960fca6ea1SDimitry Andric
3970fca6ea1SDimitry Andric S.CCEDiag(E, diag::note_constexpr_invalid_downcast)
3980fca6ea1SDimitry Andric << MostDerivedQT << TargetQT;
3990fca6ea1SDimitry Andric
4005f757f3fSDimitry Andric return false;
4015f757f3fSDimitry Andric }
4025f757f3fSDimitry Andric
CheckConst(InterpState & S,CodePtr OpPC,const Pointer & Ptr)403a7dea167SDimitry Andric bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
404a7dea167SDimitry Andric assert(Ptr.isLive() && "Pointer is not live");
4050fca6ea1SDimitry Andric if (!Ptr.isConst() || Ptr.isMutable())
40606c3fb27SDimitry Andric return true;
40706c3fb27SDimitry Andric
40806c3fb27SDimitry Andric // The This pointer is writable in constructors and destructors,
40906c3fb27SDimitry Andric // even if isConst() returns true.
4100fca6ea1SDimitry Andric // TODO(perf): We could be hitting this code path quite a lot in complex
4110fca6ea1SDimitry Andric // constructors. Is there a better way to do this?
4120fca6ea1SDimitry Andric if (S.Current->getFunction()) {
4130fca6ea1SDimitry Andric for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {
4140fca6ea1SDimitry Andric if (const Function *Func = Frame->getFunction();
41506c3fb27SDimitry Andric Func && (Func->isConstructor() || Func->isDestructor()) &&
4160fca6ea1SDimitry Andric Ptr.block() == Frame->getThis().block()) {
417a7dea167SDimitry Andric return true;
418a7dea167SDimitry Andric }
4190fca6ea1SDimitry Andric }
4200fca6ea1SDimitry Andric }
4210fca6ea1SDimitry Andric
4220fca6ea1SDimitry Andric if (!Ptr.isBlockPointer())
4230fca6ea1SDimitry Andric return false;
424a7dea167SDimitry Andric
425a7dea167SDimitry Andric const QualType Ty = Ptr.getType();
426a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
427a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
428a7dea167SDimitry Andric return false;
429a7dea167SDimitry Andric }
430a7dea167SDimitry Andric
CheckMutable(InterpState & S,CodePtr OpPC,const Pointer & Ptr)431a7dea167SDimitry Andric bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
432a7dea167SDimitry Andric assert(Ptr.isLive() && "Pointer is not live");
4330fca6ea1SDimitry Andric if (!Ptr.isMutable())
434a7dea167SDimitry Andric return true;
4350fca6ea1SDimitry Andric
4360fca6ea1SDimitry Andric // In C++14 onwards, it is permitted to read a mutable member whose
4370fca6ea1SDimitry Andric // lifetime began within the evaluation.
4380fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus14 &&
4390fca6ea1SDimitry Andric Ptr.block()->getEvalID() == S.Ctx.getEvalID())
4400fca6ea1SDimitry Andric return true;
441a7dea167SDimitry Andric
442a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
443a7dea167SDimitry Andric const FieldDecl *Field = Ptr.getField();
444a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
445a7dea167SDimitry Andric S.Note(Field->getLocation(), diag::note_declared_at);
446a7dea167SDimitry Andric return false;
447a7dea167SDimitry Andric }
448a7dea167SDimitry Andric
CheckVolatile(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)4490fca6ea1SDimitry Andric bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
4500fca6ea1SDimitry Andric AccessKinds AK) {
4510fca6ea1SDimitry Andric assert(Ptr.isLive());
4520fca6ea1SDimitry Andric
4530fca6ea1SDimitry Andric // FIXME: This check here might be kinda expensive. Maybe it would be better
4540fca6ea1SDimitry Andric // to have another field in InlineDescriptor for this?
4550fca6ea1SDimitry Andric if (!Ptr.isBlockPointer())
4560fca6ea1SDimitry Andric return true;
4570fca6ea1SDimitry Andric
4580fca6ea1SDimitry Andric QualType PtrType = Ptr.getType();
4590fca6ea1SDimitry Andric if (!PtrType.isVolatileQualified())
4600fca6ea1SDimitry Andric return true;
4610fca6ea1SDimitry Andric
4620fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
4630fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus)
4640fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_volatile_type) << AK << PtrType;
4650fca6ea1SDimitry Andric else
4660fca6ea1SDimitry Andric S.FFDiag(Loc);
4670fca6ea1SDimitry Andric return false;
4680fca6ea1SDimitry Andric }
4690fca6ea1SDimitry Andric
CheckInitialized(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)47006c3fb27SDimitry Andric bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
47106c3fb27SDimitry Andric AccessKinds AK) {
4720fca6ea1SDimitry Andric assert(Ptr.isLive());
4730fca6ea1SDimitry Andric
47406c3fb27SDimitry Andric if (Ptr.isInitialized())
47506c3fb27SDimitry Andric return true;
47606c3fb27SDimitry Andric
4770fca6ea1SDimitry Andric if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
4780fca6ea1SDimitry Andric VD && VD->hasGlobalStorage()) {
4790fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
4800fca6ea1SDimitry Andric if (VD->getAnyInitializer()) {
4810fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
4820fca6ea1SDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at);
4830fca6ea1SDimitry Andric } else {
4840fca6ea1SDimitry Andric diagnoseMissingInitializer(S, OpPC, VD);
4850fca6ea1SDimitry Andric }
4860fca6ea1SDimitry Andric return false;
4870fca6ea1SDimitry Andric }
4880fca6ea1SDimitry Andric
48906c3fb27SDimitry Andric if (!S.checkingPotentialConstantExpression()) {
4905f757f3fSDimitry Andric S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
4915f757f3fSDimitry Andric << AK << /*uninitialized=*/true << S.Current->getRange(OpPC);
49206c3fb27SDimitry Andric }
49306c3fb27SDimitry Andric return false;
49406c3fb27SDimitry Andric }
49506c3fb27SDimitry Andric
CheckGlobalInitialized(InterpState & S,CodePtr OpPC,const Pointer & Ptr)4960fca6ea1SDimitry Andric bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
4970fca6ea1SDimitry Andric if (Ptr.isInitialized())
4980fca6ea1SDimitry Andric return true;
4990fca6ea1SDimitry Andric
5000fca6ea1SDimitry Andric assert(S.getLangOpts().CPlusPlus);
5010fca6ea1SDimitry Andric const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl());
5020fca6ea1SDimitry Andric if ((!VD->hasConstantInitialization() &&
5030fca6ea1SDimitry Andric VD->mightBeUsableInConstantExpressions(S.getCtx())) ||
5040fca6ea1SDimitry Andric (S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 &&
5050fca6ea1SDimitry Andric !VD->hasICEInitializer(S.getCtx()))) {
5060fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
5070fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
5080fca6ea1SDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at);
5090fca6ea1SDimitry Andric }
5100fca6ea1SDimitry Andric return false;
5110fca6ea1SDimitry Andric }
5120fca6ea1SDimitry Andric
CheckLoad(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)5130fca6ea1SDimitry Andric bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
5140fca6ea1SDimitry Andric AccessKinds AK) {
5150fca6ea1SDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK))
516a7dea167SDimitry Andric return false;
5177a6dacacSDimitry Andric if (!CheckConstant(S, OpPC, Ptr))
5187a6dacacSDimitry Andric return false;
5197a6dacacSDimitry Andric
5200fca6ea1SDimitry Andric if (!CheckDummy(S, OpPC, Ptr, AK))
5211db9f3b2SDimitry Andric return false;
522a7dea167SDimitry Andric if (!CheckExtern(S, OpPC, Ptr))
523a7dea167SDimitry Andric return false;
5240fca6ea1SDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK))
525a7dea167SDimitry Andric return false;
5260fca6ea1SDimitry Andric if (!CheckActive(S, OpPC, Ptr, AK))
527a7dea167SDimitry Andric return false;
5280fca6ea1SDimitry Andric if (!CheckInitialized(S, OpPC, Ptr, AK))
529a7dea167SDimitry Andric return false;
5300fca6ea1SDimitry Andric if (!CheckTemporary(S, OpPC, Ptr, AK))
531a7dea167SDimitry Andric return false;
532a7dea167SDimitry Andric if (!CheckMutable(S, OpPC, Ptr))
533a7dea167SDimitry Andric return false;
5340fca6ea1SDimitry Andric if (!CheckVolatile(S, OpPC, Ptr, AK))
5350fca6ea1SDimitry Andric return false;
536a7dea167SDimitry Andric return true;
537a7dea167SDimitry Andric }
538a7dea167SDimitry Andric
CheckStore(InterpState & S,CodePtr OpPC,const Pointer & Ptr)539a7dea167SDimitry Andric bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
540a7dea167SDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_Assign))
541a7dea167SDimitry Andric return false;
5420fca6ea1SDimitry Andric if (!CheckDummy(S, OpPC, Ptr, AK_Assign))
5430fca6ea1SDimitry Andric return false;
544a7dea167SDimitry Andric if (!CheckExtern(S, OpPC, Ptr))
545a7dea167SDimitry Andric return false;
546a7dea167SDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_Assign))
547a7dea167SDimitry Andric return false;
548a7dea167SDimitry Andric if (!CheckGlobal(S, OpPC, Ptr))
549a7dea167SDimitry Andric return false;
550a7dea167SDimitry Andric if (!CheckConst(S, OpPC, Ptr))
551a7dea167SDimitry Andric return false;
552a7dea167SDimitry Andric return true;
553a7dea167SDimitry Andric }
554a7dea167SDimitry Andric
CheckInvoke(InterpState & S,CodePtr OpPC,const Pointer & Ptr)555a7dea167SDimitry Andric bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
556a7dea167SDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
557a7dea167SDimitry Andric return false;
5580fca6ea1SDimitry Andric if (!Ptr.isDummy()) {
559a7dea167SDimitry Andric if (!CheckExtern(S, OpPC, Ptr))
560a7dea167SDimitry Andric return false;
561a7dea167SDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
562a7dea167SDimitry Andric return false;
5630fca6ea1SDimitry Andric }
564a7dea167SDimitry Andric return true;
565a7dea167SDimitry Andric }
566a7dea167SDimitry Andric
CheckInit(InterpState & S,CodePtr OpPC,const Pointer & Ptr)567a7dea167SDimitry Andric bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
568a7dea167SDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_Assign))
569a7dea167SDimitry Andric return false;
570a7dea167SDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_Assign))
571a7dea167SDimitry Andric return false;
572a7dea167SDimitry Andric return true;
573a7dea167SDimitry Andric }
574a7dea167SDimitry Andric
CheckCallable(InterpState & S,CodePtr OpPC,const Function * F)575bdd1243dSDimitry Andric bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
576a7dea167SDimitry Andric
57706c3fb27SDimitry Andric if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {
578bdd1243dSDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC);
579a7dea167SDimitry Andric S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
580a7dea167SDimitry Andric return false;
581a7dea167SDimitry Andric }
582a7dea167SDimitry Andric
5830fca6ea1SDimitry Andric if (F->isConstexpr() && F->hasBody() &&
5840fca6ea1SDimitry Andric (F->getDecl()->isConstexpr() || F->getDecl()->hasAttr<MSConstexprAttr>()))
5850fca6ea1SDimitry Andric return true;
5860fca6ea1SDimitry Andric
5870fca6ea1SDimitry Andric // Implicitly constexpr.
5880fca6ea1SDimitry Andric if (F->isLambdaStaticInvoker())
5890fca6ea1SDimitry Andric return true;
5900fca6ea1SDimitry Andric
591bdd1243dSDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC);
592a7dea167SDimitry Andric if (S.getLangOpts().CPlusPlus11) {
593a7dea167SDimitry Andric const FunctionDecl *DiagDecl = F->getDecl();
594a7dea167SDimitry Andric
5950fca6ea1SDimitry Andric // Invalid decls have been diagnosed before.
5960fca6ea1SDimitry Andric if (DiagDecl->isInvalidDecl())
5970fca6ea1SDimitry Andric return false;
5980fca6ea1SDimitry Andric
599a7dea167SDimitry Andric // If this function is not constexpr because it is an inherited
600a7dea167SDimitry Andric // non-constexpr constructor, diagnose that directly.
60106c3fb27SDimitry Andric const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
602a7dea167SDimitry Andric if (CD && CD->isInheritingConstructor()) {
60306c3fb27SDimitry Andric const auto *Inherited = CD->getInheritedConstructor().getConstructor();
604a7dea167SDimitry Andric if (!Inherited->isConstexpr())
605a7dea167SDimitry Andric DiagDecl = CD = Inherited;
606a7dea167SDimitry Andric }
607a7dea167SDimitry Andric
608a7dea167SDimitry Andric // FIXME: If DiagDecl is an implicitly-declared special member function
609a7dea167SDimitry Andric // or an inheriting constructor, we should be much more explicit about why
610a7dea167SDimitry Andric // it's not constexpr.
6115f757f3fSDimitry Andric if (CD && CD->isInheritingConstructor()) {
612a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1)
613a7dea167SDimitry Andric << CD->getInheritedConstructor().getConstructor()->getParent();
6145f757f3fSDimitry Andric S.Note(DiagDecl->getLocation(), diag::note_declared_at);
6155f757f3fSDimitry Andric } else {
6165f757f3fSDimitry Andric // Don't emit anything if the function isn't defined and we're checking
6175f757f3fSDimitry Andric // for a constant expression. It might be defined at the point we're
6185f757f3fSDimitry Andric // actually calling it.
6190fca6ea1SDimitry Andric bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
6200fca6ea1SDimitry Andric if (!DiagDecl->isDefined() && !IsExtern && DiagDecl->isConstexpr() &&
6210fca6ea1SDimitry Andric S.checkingPotentialConstantExpression())
6220fca6ea1SDimitry Andric return false;
6230fca6ea1SDimitry Andric
6240fca6ea1SDimitry Andric // If the declaration is defined, declared 'constexpr' _and_ has a body,
6250fca6ea1SDimitry Andric // the below diagnostic doesn't add anything useful.
6260fca6ea1SDimitry Andric if (DiagDecl->isDefined() && DiagDecl->isConstexpr() &&
6270fca6ea1SDimitry Andric DiagDecl->hasBody())
6285f757f3fSDimitry Andric return false;
6295f757f3fSDimitry Andric
630a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1)
631a7dea167SDimitry Andric << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
632a7dea167SDimitry Andric S.Note(DiagDecl->getLocation(), diag::note_declared_at);
6335f757f3fSDimitry Andric }
634a7dea167SDimitry Andric } else {
635a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
636a7dea167SDimitry Andric }
637a7dea167SDimitry Andric
6380fca6ea1SDimitry Andric return false;
639a7dea167SDimitry Andric }
640a7dea167SDimitry Andric
CheckCallDepth(InterpState & S,CodePtr OpPC)64106c3fb27SDimitry Andric bool CheckCallDepth(InterpState &S, CodePtr OpPC) {
64206c3fb27SDimitry Andric if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {
64306c3fb27SDimitry Andric S.FFDiag(S.Current->getSource(OpPC),
64406c3fb27SDimitry Andric diag::note_constexpr_depth_limit_exceeded)
64506c3fb27SDimitry Andric << S.getLangOpts().ConstexprCallDepth;
64606c3fb27SDimitry Andric return false;
64706c3fb27SDimitry Andric }
64806c3fb27SDimitry Andric
64906c3fb27SDimitry Andric return true;
65006c3fb27SDimitry Andric }
65106c3fb27SDimitry Andric
CheckThis(InterpState & S,CodePtr OpPC,const Pointer & This)652a7dea167SDimitry Andric bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
653a7dea167SDimitry Andric if (!This.isZero())
654a7dea167SDimitry Andric return true;
655a7dea167SDimitry Andric
656a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
657a7dea167SDimitry Andric
658a7dea167SDimitry Andric bool IsImplicit = false;
65906c3fb27SDimitry Andric if (const auto *E = dyn_cast_if_present<CXXThisExpr>(Loc.asExpr()))
660a7dea167SDimitry Andric IsImplicit = E->isImplicit();
661a7dea167SDimitry Andric
662a7dea167SDimitry Andric if (S.getLangOpts().CPlusPlus11)
663a7dea167SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit;
664a7dea167SDimitry Andric else
665a7dea167SDimitry Andric S.FFDiag(Loc);
666a7dea167SDimitry Andric
667a7dea167SDimitry Andric return false;
668a7dea167SDimitry Andric }
669a7dea167SDimitry Andric
CheckPure(InterpState & S,CodePtr OpPC,const CXXMethodDecl * MD)670a7dea167SDimitry Andric bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
6717a6dacacSDimitry Andric if (!MD->isPureVirtual())
672a7dea167SDimitry Andric return true;
673a7dea167SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
674a7dea167SDimitry Andric S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD;
675a7dea167SDimitry Andric S.Note(MD->getLocation(), diag::note_declared_at);
676a7dea167SDimitry Andric return false;
677a7dea167SDimitry Andric }
678bdd1243dSDimitry Andric
CheckFloatResult(InterpState & S,CodePtr OpPC,const Floating & Result,APFloat::opStatus Status)6795f757f3fSDimitry Andric bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
6805f757f3fSDimitry Andric APFloat::opStatus Status) {
6815f757f3fSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
6825f757f3fSDimitry Andric
6835f757f3fSDimitry Andric // [expr.pre]p4:
6845f757f3fSDimitry Andric // If during the evaluation of an expression, the result is not
6855f757f3fSDimitry Andric // mathematically defined [...], the behavior is undefined.
6865f757f3fSDimitry Andric // FIXME: C++ rules require us to not conform to IEEE 754 here.
6875f757f3fSDimitry Andric if (Result.isNan()) {
6885f757f3fSDimitry Andric S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
6895f757f3fSDimitry Andric << /*NaN=*/true << S.Current->getRange(OpPC);
6905f757f3fSDimitry Andric return S.noteUndefinedBehavior();
6915f757f3fSDimitry Andric }
6925f757f3fSDimitry Andric
69306c3fb27SDimitry Andric // In a constant context, assume that any dynamic rounding mode or FP
69406c3fb27SDimitry Andric // exception state matches the default floating-point environment.
69506c3fb27SDimitry Andric if (S.inConstantContext())
69606c3fb27SDimitry Andric return true;
69706c3fb27SDimitry Andric
69806c3fb27SDimitry Andric FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(S.Ctx.getLangOpts());
69906c3fb27SDimitry Andric
70006c3fb27SDimitry Andric if ((Status & APFloat::opInexact) &&
70106c3fb27SDimitry Andric FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
70206c3fb27SDimitry Andric // Inexact result means that it depends on rounding mode. If the requested
70306c3fb27SDimitry Andric // mode is dynamic, the evaluation cannot be made in compile time.
70406c3fb27SDimitry Andric S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
70506c3fb27SDimitry Andric return false;
70606c3fb27SDimitry Andric }
70706c3fb27SDimitry Andric
70806c3fb27SDimitry Andric if ((Status != APFloat::opOK) &&
70906c3fb27SDimitry Andric (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
71006c3fb27SDimitry Andric FPO.getExceptionMode() != LangOptions::FPE_Ignore ||
71106c3fb27SDimitry Andric FPO.getAllowFEnvAccess())) {
71206c3fb27SDimitry Andric S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
71306c3fb27SDimitry Andric return false;
71406c3fb27SDimitry Andric }
71506c3fb27SDimitry Andric
71606c3fb27SDimitry Andric if ((Status & APFloat::opStatus::opInvalidOp) &&
71706c3fb27SDimitry Andric FPO.getExceptionMode() != LangOptions::FPE_Ignore) {
71806c3fb27SDimitry Andric // There is no usefully definable result.
71906c3fb27SDimitry Andric S.FFDiag(E);
72006c3fb27SDimitry Andric return false;
72106c3fb27SDimitry Andric }
72206c3fb27SDimitry Andric
72306c3fb27SDimitry Andric return true;
724bdd1243dSDimitry Andric }
725bdd1243dSDimitry Andric
CheckDynamicMemoryAllocation(InterpState & S,CodePtr OpPC)7260fca6ea1SDimitry Andric bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC) {
7270fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus20)
7280fca6ea1SDimitry Andric return true;
7290fca6ea1SDimitry Andric
7300fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
7310fca6ea1SDimitry Andric S.CCEDiag(E, diag::note_constexpr_new);
7320fca6ea1SDimitry Andric return true;
7330fca6ea1SDimitry Andric }
7340fca6ea1SDimitry Andric
CheckNewDeleteForms(InterpState & S,CodePtr OpPC,bool NewWasArray,bool DeleteIsArray,const Descriptor * D,const Expr * NewExpr)7350fca6ea1SDimitry Andric bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,
7360fca6ea1SDimitry Andric bool DeleteIsArray, const Descriptor *D,
7370fca6ea1SDimitry Andric const Expr *NewExpr) {
7380fca6ea1SDimitry Andric if (NewWasArray == DeleteIsArray)
7390fca6ea1SDimitry Andric return true;
7400fca6ea1SDimitry Andric
7410fca6ea1SDimitry Andric QualType TypeToDiagnose;
7420fca6ea1SDimitry Andric // We need to shuffle things around a bit here to get a better diagnostic,
7430fca6ea1SDimitry Andric // because the expression we allocated the block for was of type int*,
7440fca6ea1SDimitry Andric // but we want to get the array size right.
7450fca6ea1SDimitry Andric if (D->isArray()) {
7460fca6ea1SDimitry Andric QualType ElemQT = D->getType()->getPointeeType();
7470fca6ea1SDimitry Andric TypeToDiagnose = S.getCtx().getConstantArrayType(
7480fca6ea1SDimitry Andric ElemQT, APInt(64, static_cast<uint64_t>(D->getNumElems()), false),
7490fca6ea1SDimitry Andric nullptr, ArraySizeModifier::Normal, 0);
7500fca6ea1SDimitry Andric } else
7510fca6ea1SDimitry Andric TypeToDiagnose = D->getType()->getPointeeType();
7520fca6ea1SDimitry Andric
7530fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
7540fca6ea1SDimitry Andric S.FFDiag(E, diag::note_constexpr_new_delete_mismatch)
7550fca6ea1SDimitry Andric << DeleteIsArray << 0 << TypeToDiagnose;
7560fca6ea1SDimitry Andric S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here)
7570fca6ea1SDimitry Andric << NewExpr->getSourceRange();
7580fca6ea1SDimitry Andric return false;
7590fca6ea1SDimitry Andric }
7600fca6ea1SDimitry Andric
CheckDeleteSource(InterpState & S,CodePtr OpPC,const Expr * Source,const Pointer & Ptr)7610fca6ea1SDimitry Andric bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
7620fca6ea1SDimitry Andric const Pointer &Ptr) {
7630fca6ea1SDimitry Andric if (Source && isa<CXXNewExpr>(Source))
7640fca6ea1SDimitry Andric return true;
7650fca6ea1SDimitry Andric
7660fca6ea1SDimitry Andric // Whatever this is, we didn't heap allocate it.
7670fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
7680fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
7690fca6ea1SDimitry Andric << Ptr.toDiagnosticString(S.getCtx());
7700fca6ea1SDimitry Andric
7710fca6ea1SDimitry Andric if (Ptr.isTemporary())
7720fca6ea1SDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
7730fca6ea1SDimitry Andric else
7740fca6ea1SDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
7750fca6ea1SDimitry Andric return false;
7760fca6ea1SDimitry Andric }
7770fca6ea1SDimitry Andric
7785f757f3fSDimitry Andric /// We aleady know the given DeclRefExpr is invalid for some reason,
7795f757f3fSDimitry Andric /// now figure out why and print appropriate diagnostics.
CheckDeclRef(InterpState & S,CodePtr OpPC,const DeclRefExpr * DR)7805f757f3fSDimitry Andric bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
7815f757f3fSDimitry Andric const ValueDecl *D = DR->getDecl();
7820fca6ea1SDimitry Andric return diagnoseUnknownDecl(S, OpPC, D);
7830fca6ea1SDimitry Andric }
7845f757f3fSDimitry Andric
CheckDummy(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)7850fca6ea1SDimitry Andric bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
7860fca6ea1SDimitry Andric AccessKinds AK) {
7870fca6ea1SDimitry Andric if (!Ptr.isDummy())
7880fca6ea1SDimitry Andric return true;
7890fca6ea1SDimitry Andric
7900fca6ea1SDimitry Andric const Descriptor *Desc = Ptr.getDeclDesc();
7910fca6ea1SDimitry Andric const ValueDecl *D = Desc->asValueDecl();
7920fca6ea1SDimitry Andric if (!D)
7930fca6ea1SDimitry Andric return false;
7940fca6ea1SDimitry Andric
7950fca6ea1SDimitry Andric if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement)
7960fca6ea1SDimitry Andric return diagnoseUnknownDecl(S, OpPC, D);
7970fca6ea1SDimitry Andric
7980fca6ea1SDimitry Andric assert(AK == AK_Assign);
7995f757f3fSDimitry Andric if (S.getLangOpts().CPlusPlus11) {
8000fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
8010fca6ea1SDimitry Andric S.FFDiag(E, diag::note_constexpr_modify_global);
8025f757f3fSDimitry Andric }
8035f757f3fSDimitry Andric return false;
8045f757f3fSDimitry Andric }
8055f757f3fSDimitry Andric
CheckNonNullArgs(InterpState & S,CodePtr OpPC,const Function * F,const CallExpr * CE,unsigned ArgSize)8060fca6ea1SDimitry Andric bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
8070fca6ea1SDimitry Andric const CallExpr *CE, unsigned ArgSize) {
8080fca6ea1SDimitry Andric auto Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs());
8090fca6ea1SDimitry Andric auto NonNullArgs = collectNonNullArgs(F->getDecl(), Args);
8100fca6ea1SDimitry Andric unsigned Offset = 0;
8110fca6ea1SDimitry Andric unsigned Index = 0;
8120fca6ea1SDimitry Andric for (const Expr *Arg : Args) {
8130fca6ea1SDimitry Andric if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
8140fca6ea1SDimitry Andric const Pointer &ArgPtr = S.Stk.peek<Pointer>(ArgSize - Offset);
8150fca6ea1SDimitry Andric if (ArgPtr.isZero()) {
8160fca6ea1SDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC);
8170fca6ea1SDimitry Andric S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
8185f757f3fSDimitry Andric return false;
8195f757f3fSDimitry Andric }
8205f757f3fSDimitry Andric }
8215f757f3fSDimitry Andric
8220fca6ea1SDimitry Andric Offset += align(primSize(S.Ctx.classify(Arg).value_or(PT_Ptr)));
8230fca6ea1SDimitry Andric ++Index;
8240fca6ea1SDimitry Andric }
8250fca6ea1SDimitry Andric return true;
8260fca6ea1SDimitry Andric }
8270fca6ea1SDimitry Andric
8280fca6ea1SDimitry Andric // FIXME: This is similar to code we already have in Compiler.cpp.
8290fca6ea1SDimitry Andric // I think it makes sense to instead add the field and base destruction stuff
8300fca6ea1SDimitry Andric // to the destructor Function itself. Then destroying a record would really
8310fca6ea1SDimitry Andric // _just_ be calling its destructor. That would also help with the diagnostic
8320fca6ea1SDimitry Andric // difference when the destructor or a field/base fails.
runRecordDestructor(InterpState & S,CodePtr OpPC,const Pointer & BasePtr,const Descriptor * Desc)8330fca6ea1SDimitry Andric static bool runRecordDestructor(InterpState &S, CodePtr OpPC,
8340fca6ea1SDimitry Andric const Pointer &BasePtr,
8350fca6ea1SDimitry Andric const Descriptor *Desc) {
8360fca6ea1SDimitry Andric assert(Desc->isRecord());
8370fca6ea1SDimitry Andric const Record *R = Desc->ElemRecord;
8380fca6ea1SDimitry Andric assert(R);
8390fca6ea1SDimitry Andric
8400fca6ea1SDimitry Andric // Fields.
8410fca6ea1SDimitry Andric for (const Record::Field &Field : llvm::reverse(R->fields())) {
8420fca6ea1SDimitry Andric const Descriptor *D = Field.Desc;
8430fca6ea1SDimitry Andric if (D->isRecord()) {
8440fca6ea1SDimitry Andric if (!runRecordDestructor(S, OpPC, BasePtr.atField(Field.Offset), D))
8455f757f3fSDimitry Andric return false;
8460fca6ea1SDimitry Andric } else if (D->isCompositeArray()) {
8470fca6ea1SDimitry Andric const Descriptor *ElemDesc = Desc->ElemDesc;
8480fca6ea1SDimitry Andric assert(ElemDesc->isRecord());
8490fca6ea1SDimitry Andric for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
8500fca6ea1SDimitry Andric if (!runRecordDestructor(S, OpPC, BasePtr.atIndex(I).narrow(),
8510fca6ea1SDimitry Andric ElemDesc))
8520fca6ea1SDimitry Andric return false;
8530fca6ea1SDimitry Andric }
8540fca6ea1SDimitry Andric }
8550fca6ea1SDimitry Andric }
8560fca6ea1SDimitry Andric
8570fca6ea1SDimitry Andric // Destructor of this record.
8580fca6ea1SDimitry Andric if (const CXXDestructorDecl *Dtor = R->getDestructor();
8590fca6ea1SDimitry Andric Dtor && !Dtor->isTrivial()) {
8600fca6ea1SDimitry Andric const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
8610fca6ea1SDimitry Andric if (!DtorFunc)
8620fca6ea1SDimitry Andric return false;
8630fca6ea1SDimitry Andric
8640fca6ea1SDimitry Andric S.Stk.push<Pointer>(BasePtr);
8650fca6ea1SDimitry Andric if (!Call(S, OpPC, DtorFunc, 0))
8660fca6ea1SDimitry Andric return false;
8670fca6ea1SDimitry Andric }
8680fca6ea1SDimitry Andric
8690fca6ea1SDimitry Andric // Bases.
8700fca6ea1SDimitry Andric for (const Record::Base &Base : llvm::reverse(R->bases())) {
8710fca6ea1SDimitry Andric if (!runRecordDestructor(S, OpPC, BasePtr.atField(Base.Offset), Base.Desc))
8720fca6ea1SDimitry Andric return false;
8730fca6ea1SDimitry Andric }
8740fca6ea1SDimitry Andric
8750fca6ea1SDimitry Andric return true;
8760fca6ea1SDimitry Andric }
8770fca6ea1SDimitry Andric
RunDestructors(InterpState & S,CodePtr OpPC,const Block * B)8780fca6ea1SDimitry Andric bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {
8790fca6ea1SDimitry Andric assert(B);
8800fca6ea1SDimitry Andric const Descriptor *Desc = B->getDescriptor();
8810fca6ea1SDimitry Andric
8820fca6ea1SDimitry Andric if (Desc->isPrimitive() || Desc->isPrimitiveArray())
8830fca6ea1SDimitry Andric return true;
8840fca6ea1SDimitry Andric
8850fca6ea1SDimitry Andric assert(Desc->isRecord() || Desc->isCompositeArray());
8860fca6ea1SDimitry Andric
8870fca6ea1SDimitry Andric if (Desc->isCompositeArray()) {
8880fca6ea1SDimitry Andric const Descriptor *ElemDesc = Desc->ElemDesc;
8890fca6ea1SDimitry Andric assert(ElemDesc->isRecord());
8900fca6ea1SDimitry Andric
8910fca6ea1SDimitry Andric Pointer RP(const_cast<Block *>(B));
8920fca6ea1SDimitry Andric for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
8930fca6ea1SDimitry Andric if (!runRecordDestructor(S, OpPC, RP.atIndex(I).narrow(), ElemDesc))
8940fca6ea1SDimitry Andric return false;
8950fca6ea1SDimitry Andric }
8960fca6ea1SDimitry Andric return true;
8970fca6ea1SDimitry Andric }
8980fca6ea1SDimitry Andric
8990fca6ea1SDimitry Andric assert(Desc->isRecord());
9000fca6ea1SDimitry Andric return runRecordDestructor(S, OpPC, Pointer(const_cast<Block *>(B)), Desc);
9010fca6ea1SDimitry Andric }
9020fca6ea1SDimitry Andric
diagnoseEnumValue(InterpState & S,CodePtr OpPC,const EnumDecl * ED,const APSInt & Value)9030fca6ea1SDimitry Andric void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
9040fca6ea1SDimitry Andric const APSInt &Value) {
9050fca6ea1SDimitry Andric llvm::APInt Min;
9060fca6ea1SDimitry Andric llvm::APInt Max;
9070fca6ea1SDimitry Andric
9080fca6ea1SDimitry Andric if (S.EvaluatingDecl && !S.EvaluatingDecl->isConstexpr())
9090fca6ea1SDimitry Andric return;
9100fca6ea1SDimitry Andric
9110fca6ea1SDimitry Andric ED->getValueRange(Max, Min);
9120fca6ea1SDimitry Andric --Max;
9130fca6ea1SDimitry Andric
9140fca6ea1SDimitry Andric if (ED->getNumNegativeBits() &&
9150fca6ea1SDimitry Andric (Max.slt(Value.getSExtValue()) || Min.sgt(Value.getSExtValue()))) {
9160fca6ea1SDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC);
9170fca6ea1SDimitry Andric S.report(Loc, diag::warn_constexpr_unscoped_enum_out_of_range)
9180fca6ea1SDimitry Andric << llvm::toString(Value, 10) << Min.getSExtValue() << Max.getSExtValue()
9190fca6ea1SDimitry Andric << ED;
9200fca6ea1SDimitry Andric } else if (!ED->getNumNegativeBits() && Max.ult(Value.getZExtValue())) {
9210fca6ea1SDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC);
9220fca6ea1SDimitry Andric S.report(Loc, diag::warn_constexpr_unscoped_enum_out_of_range)
9230fca6ea1SDimitry Andric << llvm::toString(Value, 10) << Min.getZExtValue() << Max.getZExtValue()
9240fca6ea1SDimitry Andric << ED;
9250fca6ea1SDimitry Andric }
9265f757f3fSDimitry Andric }
9275f757f3fSDimitry Andric
928*415efcecSDimitry Andric // https://github.com/llvm/llvm-project/issues/102513
929*415efcecSDimitry Andric #if defined(_WIN32) && !defined(__clang__) && !defined(NDEBUG)
930*415efcecSDimitry Andric #pragma optimize("", off)
931*415efcecSDimitry Andric #endif
Interpret(InterpState & S,APValue & Result)932a7dea167SDimitry Andric bool Interpret(InterpState &S, APValue &Result) {
933bdd1243dSDimitry Andric // The current stack frame when we started Interpret().
934bdd1243dSDimitry Andric // This is being used by the ops to determine wheter
935bdd1243dSDimitry Andric // to return from this function and thus terminate
936bdd1243dSDimitry Andric // interpretation.
937bdd1243dSDimitry Andric const InterpFrame *StartFrame = S.Current;
938bdd1243dSDimitry Andric assert(!S.Current->isRoot());
939a7dea167SDimitry Andric CodePtr PC = S.Current->getPC();
940a7dea167SDimitry Andric
941bdd1243dSDimitry Andric // Empty program.
942bdd1243dSDimitry Andric if (!PC)
943bdd1243dSDimitry Andric return true;
944bdd1243dSDimitry Andric
945a7dea167SDimitry Andric for (;;) {
946a7dea167SDimitry Andric auto Op = PC.read<Opcode>();
947a7dea167SDimitry Andric CodePtr OpPC = PC;
948a7dea167SDimitry Andric
949a7dea167SDimitry Andric switch (Op) {
950a7dea167SDimitry Andric #define GET_INTERP
951a7dea167SDimitry Andric #include "Opcodes.inc"
952a7dea167SDimitry Andric #undef GET_INTERP
953a7dea167SDimitry Andric }
954a7dea167SDimitry Andric }
955a7dea167SDimitry Andric }
956*415efcecSDimitry Andric // https://github.com/llvm/llvm-project/issues/102513
957*415efcecSDimitry Andric #if defined(_WIN32) && !defined(__clang__) && !defined(NDEBUG)
958*415efcecSDimitry Andric #pragma optimize("", on)
959*415efcecSDimitry Andric #endif
960a7dea167SDimitry Andric
961a7dea167SDimitry Andric } // namespace interp
962a7dea167SDimitry Andric } // namespace clang
963