1*700637cbSDimitry Andric //===------- Interp.cpp - Interpreter for the constexpr VM ------*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric
9*700637cbSDimitry Andric #include "Interp.h"
10*700637cbSDimitry Andric #include "Compiler.h"
11*700637cbSDimitry Andric #include "Function.h"
12*700637cbSDimitry Andric #include "InterpFrame.h"
13*700637cbSDimitry Andric #include "InterpShared.h"
14*700637cbSDimitry Andric #include "InterpStack.h"
15*700637cbSDimitry Andric #include "Opcode.h"
16*700637cbSDimitry Andric #include "PrimType.h"
17*700637cbSDimitry Andric #include "Program.h"
18*700637cbSDimitry Andric #include "State.h"
19*700637cbSDimitry Andric #include "clang/AST/ASTContext.h"
20*700637cbSDimitry Andric #include "clang/AST/CXXInheritance.h"
21*700637cbSDimitry Andric #include "clang/AST/DeclObjC.h"
22*700637cbSDimitry Andric #include "clang/AST/Expr.h"
23*700637cbSDimitry Andric #include "clang/AST/ExprCXX.h"
24*700637cbSDimitry Andric #include "clang/Basic/DiagnosticSema.h"
25*700637cbSDimitry Andric #include "clang/Basic/TargetInfo.h"
26*700637cbSDimitry Andric #include "llvm/ADT/StringExtras.h"
27*700637cbSDimitry Andric
28*700637cbSDimitry Andric using namespace clang;
29*700637cbSDimitry Andric using namespace clang::interp;
30*700637cbSDimitry Andric
RetValue(InterpState & S,CodePtr & Pt)31*700637cbSDimitry Andric static bool RetValue(InterpState &S, CodePtr &Pt) {
32*700637cbSDimitry Andric llvm::report_fatal_error("Interpreter cannot return values");
33*700637cbSDimitry Andric }
34*700637cbSDimitry Andric
35*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
36*700637cbSDimitry Andric // Jmp, Jt, Jf
37*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
38*700637cbSDimitry Andric
Jmp(InterpState & S,CodePtr & PC,int32_t Offset)39*700637cbSDimitry Andric static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) {
40*700637cbSDimitry Andric PC += Offset;
41*700637cbSDimitry Andric return true;
42*700637cbSDimitry Andric }
43*700637cbSDimitry Andric
Jt(InterpState & S,CodePtr & PC,int32_t Offset)44*700637cbSDimitry Andric static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) {
45*700637cbSDimitry Andric if (S.Stk.pop<bool>()) {
46*700637cbSDimitry Andric PC += Offset;
47*700637cbSDimitry Andric }
48*700637cbSDimitry Andric return true;
49*700637cbSDimitry Andric }
50*700637cbSDimitry Andric
Jf(InterpState & S,CodePtr & PC,int32_t Offset)51*700637cbSDimitry Andric static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) {
52*700637cbSDimitry Andric if (!S.Stk.pop<bool>()) {
53*700637cbSDimitry Andric PC += Offset;
54*700637cbSDimitry Andric }
55*700637cbSDimitry Andric return true;
56*700637cbSDimitry Andric }
57*700637cbSDimitry Andric
58*700637cbSDimitry Andric // https://github.com/llvm/llvm-project/issues/102513
59*700637cbSDimitry Andric #if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
60*700637cbSDimitry Andric #pragma optimize("", off)
61*700637cbSDimitry Andric #endif
62*700637cbSDimitry Andric // FIXME: We have the large switch over all opcodes here again, and in
63*700637cbSDimitry Andric // Interpret().
BCP(InterpState & S,CodePtr & RealPC,int32_t Offset,PrimType PT)64*700637cbSDimitry Andric static bool BCP(InterpState &S, CodePtr &RealPC, int32_t Offset, PrimType PT) {
65*700637cbSDimitry Andric [[maybe_unused]] CodePtr PCBefore = RealPC;
66*700637cbSDimitry Andric size_t StackSizeBefore = S.Stk.size();
67*700637cbSDimitry Andric
68*700637cbSDimitry Andric auto SpeculativeInterp = [&S, RealPC]() -> bool {
69*700637cbSDimitry Andric const InterpFrame *StartFrame = S.Current;
70*700637cbSDimitry Andric CodePtr PC = RealPC;
71*700637cbSDimitry Andric
72*700637cbSDimitry Andric for (;;) {
73*700637cbSDimitry Andric auto Op = PC.read<Opcode>();
74*700637cbSDimitry Andric if (Op == OP_EndSpeculation)
75*700637cbSDimitry Andric return true;
76*700637cbSDimitry Andric CodePtr OpPC = PC;
77*700637cbSDimitry Andric
78*700637cbSDimitry Andric switch (Op) {
79*700637cbSDimitry Andric #define GET_INTERP
80*700637cbSDimitry Andric #include "Opcodes.inc"
81*700637cbSDimitry Andric #undef GET_INTERP
82*700637cbSDimitry Andric }
83*700637cbSDimitry Andric }
84*700637cbSDimitry Andric llvm_unreachable("We didn't see an EndSpeculation op?");
85*700637cbSDimitry Andric };
86*700637cbSDimitry Andric
87*700637cbSDimitry Andric if (SpeculativeInterp()) {
88*700637cbSDimitry Andric if (PT == PT_Ptr) {
89*700637cbSDimitry Andric const auto &Ptr = S.Stk.pop<Pointer>();
90*700637cbSDimitry Andric assert(S.Stk.size() == StackSizeBefore);
91*700637cbSDimitry Andric S.Stk.push<Integral<32, true>>(
92*700637cbSDimitry Andric Integral<32, true>::from(CheckBCPResult(S, Ptr)));
93*700637cbSDimitry Andric } else {
94*700637cbSDimitry Andric // Pop the result from the stack and return success.
95*700637cbSDimitry Andric TYPE_SWITCH(PT, S.Stk.pop<T>(););
96*700637cbSDimitry Andric assert(S.Stk.size() == StackSizeBefore);
97*700637cbSDimitry Andric S.Stk.push<Integral<32, true>>(Integral<32, true>::from(1));
98*700637cbSDimitry Andric }
99*700637cbSDimitry Andric } else {
100*700637cbSDimitry Andric if (!S.inConstantContext())
101*700637cbSDimitry Andric return Invalid(S, RealPC);
102*700637cbSDimitry Andric
103*700637cbSDimitry Andric S.Stk.clearTo(StackSizeBefore);
104*700637cbSDimitry Andric S.Stk.push<Integral<32, true>>(Integral<32, true>::from(0));
105*700637cbSDimitry Andric }
106*700637cbSDimitry Andric
107*700637cbSDimitry Andric // RealPC should not have been modified.
108*700637cbSDimitry Andric assert(*RealPC == *PCBefore);
109*700637cbSDimitry Andric
110*700637cbSDimitry Andric // Jump to end label. This is a little tricker than just RealPC += Offset
111*700637cbSDimitry Andric // because our usual jump instructions don't have any arguments, to the offset
112*700637cbSDimitry Andric // we get is a little too much and we need to subtract the size of the
113*700637cbSDimitry Andric // bool and PrimType arguments again.
114*700637cbSDimitry Andric int32_t ParamSize = align(sizeof(PrimType));
115*700637cbSDimitry Andric assert(Offset >= ParamSize);
116*700637cbSDimitry Andric RealPC += Offset - ParamSize;
117*700637cbSDimitry Andric
118*700637cbSDimitry Andric [[maybe_unused]] CodePtr PCCopy = RealPC;
119*700637cbSDimitry Andric assert(PCCopy.read<Opcode>() == OP_EndSpeculation);
120*700637cbSDimitry Andric
121*700637cbSDimitry Andric return true;
122*700637cbSDimitry Andric }
123*700637cbSDimitry Andric // https://github.com/llvm/llvm-project/issues/102513
124*700637cbSDimitry Andric #if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
125*700637cbSDimitry Andric #pragma optimize("", on)
126*700637cbSDimitry Andric #endif
127*700637cbSDimitry Andric
diagnoseMissingInitializer(InterpState & S,CodePtr OpPC,const ValueDecl * VD)128*700637cbSDimitry Andric static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC,
129*700637cbSDimitry Andric const ValueDecl *VD) {
130*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
131*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD;
132*700637cbSDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
133*700637cbSDimitry Andric }
134*700637cbSDimitry Andric
135*700637cbSDimitry Andric static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
136*700637cbSDimitry Andric const ValueDecl *VD);
diagnoseUnknownDecl(InterpState & S,CodePtr OpPC,const ValueDecl * D)137*700637cbSDimitry Andric static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,
138*700637cbSDimitry Andric const ValueDecl *D) {
139*700637cbSDimitry Andric // This function tries pretty hard to produce a good diagnostic. Just skip
140*700637cbSDimitry Andric // tha if nobody will see it anyway.
141*700637cbSDimitry Andric if (!S.diagnosing())
142*700637cbSDimitry Andric return false;
143*700637cbSDimitry Andric
144*700637cbSDimitry Andric if (isa<ParmVarDecl>(D)) {
145*700637cbSDimitry Andric if (D->getType()->isReferenceType())
146*700637cbSDimitry Andric return false;
147*700637cbSDimitry Andric
148*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
149*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus11) {
150*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_function_param_value_unknown) << D;
151*700637cbSDimitry Andric S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange();
152*700637cbSDimitry Andric } else {
153*700637cbSDimitry Andric S.FFDiag(Loc);
154*700637cbSDimitry Andric }
155*700637cbSDimitry Andric return false;
156*700637cbSDimitry Andric }
157*700637cbSDimitry Andric
158*700637cbSDimitry Andric if (!D->getType().isConstQualified()) {
159*700637cbSDimitry Andric diagnoseNonConstVariable(S, OpPC, D);
160*700637cbSDimitry Andric } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
161*700637cbSDimitry Andric if (!VD->getAnyInitializer()) {
162*700637cbSDimitry Andric diagnoseMissingInitializer(S, OpPC, VD);
163*700637cbSDimitry Andric } else {
164*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
165*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
166*700637cbSDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at);
167*700637cbSDimitry Andric }
168*700637cbSDimitry Andric }
169*700637cbSDimitry Andric
170*700637cbSDimitry Andric return false;
171*700637cbSDimitry Andric }
172*700637cbSDimitry Andric
diagnoseNonConstVariable(InterpState & S,CodePtr OpPC,const ValueDecl * VD)173*700637cbSDimitry Andric static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
174*700637cbSDimitry Andric const ValueDecl *VD) {
175*700637cbSDimitry Andric if (!S.diagnosing())
176*700637cbSDimitry Andric return;
177*700637cbSDimitry Andric
178*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
179*700637cbSDimitry Andric if (!S.getLangOpts().CPlusPlus) {
180*700637cbSDimitry Andric S.FFDiag(Loc);
181*700637cbSDimitry Andric return;
182*700637cbSDimitry Andric }
183*700637cbSDimitry Andric
184*700637cbSDimitry Andric if (const auto *VarD = dyn_cast<VarDecl>(VD);
185*700637cbSDimitry Andric VarD && VarD->getType().isConstQualified() &&
186*700637cbSDimitry Andric !VarD->getAnyInitializer()) {
187*700637cbSDimitry Andric diagnoseMissingInitializer(S, OpPC, VD);
188*700637cbSDimitry Andric return;
189*700637cbSDimitry Andric }
190*700637cbSDimitry Andric
191*700637cbSDimitry Andric // Rather random, but this is to match the diagnostic output of the current
192*700637cbSDimitry Andric // interpreter.
193*700637cbSDimitry Andric if (isa<ObjCIvarDecl>(VD))
194*700637cbSDimitry Andric return;
195*700637cbSDimitry Andric
196*700637cbSDimitry Andric if (VD->getType()->isIntegralOrEnumerationType()) {
197*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
198*700637cbSDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at);
199*700637cbSDimitry Andric return;
200*700637cbSDimitry Andric }
201*700637cbSDimitry Andric
202*700637cbSDimitry Andric S.FFDiag(Loc,
203*700637cbSDimitry Andric S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr
204*700637cbSDimitry Andric : diag::note_constexpr_ltor_non_integral,
205*700637cbSDimitry Andric 1)
206*700637cbSDimitry Andric << VD << VD->getType();
207*700637cbSDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at);
208*700637cbSDimitry Andric }
209*700637cbSDimitry Andric
CheckTemporary(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)210*700637cbSDimitry Andric static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
211*700637cbSDimitry Andric AccessKinds AK) {
212*700637cbSDimitry Andric if (auto ID = Ptr.getDeclID()) {
213*700637cbSDimitry Andric if (!Ptr.isStaticTemporary())
214*700637cbSDimitry Andric return true;
215*700637cbSDimitry Andric
216*700637cbSDimitry Andric const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(
217*700637cbSDimitry Andric Ptr.getDeclDesc()->asExpr());
218*700637cbSDimitry Andric if (!MTE)
219*700637cbSDimitry Andric return true;
220*700637cbSDimitry Andric
221*700637cbSDimitry Andric // FIXME(perf): Since we do this check on every Load from a static
222*700637cbSDimitry Andric // temporary, it might make sense to cache the value of the
223*700637cbSDimitry Andric // isUsableInConstantExpressions call.
224*700637cbSDimitry Andric if (!MTE->isUsableInConstantExpressions(S.getASTContext()) &&
225*700637cbSDimitry Andric Ptr.block()->getEvalID() != S.Ctx.getEvalID()) {
226*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
227*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
228*700637cbSDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
229*700637cbSDimitry Andric return false;
230*700637cbSDimitry Andric }
231*700637cbSDimitry Andric }
232*700637cbSDimitry Andric return true;
233*700637cbSDimitry Andric }
234*700637cbSDimitry Andric
CheckGlobal(InterpState & S,CodePtr OpPC,const Pointer & Ptr)235*700637cbSDimitry Andric static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
236*700637cbSDimitry Andric if (auto ID = Ptr.getDeclID()) {
237*700637cbSDimitry Andric if (!Ptr.isStatic())
238*700637cbSDimitry Andric return true;
239*700637cbSDimitry Andric
240*700637cbSDimitry Andric if (S.P.getCurrentDecl() == ID)
241*700637cbSDimitry Andric return true;
242*700637cbSDimitry Andric
243*700637cbSDimitry Andric S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global);
244*700637cbSDimitry Andric return false;
245*700637cbSDimitry Andric }
246*700637cbSDimitry Andric return true;
247*700637cbSDimitry Andric }
248*700637cbSDimitry Andric
249*700637cbSDimitry Andric namespace clang {
250*700637cbSDimitry Andric namespace interp {
popArg(InterpState & S,const Expr * Arg)251*700637cbSDimitry Andric static void popArg(InterpState &S, const Expr *Arg) {
252*700637cbSDimitry Andric PrimType Ty = S.getContext().classify(Arg).value_or(PT_Ptr);
253*700637cbSDimitry Andric TYPE_SWITCH(Ty, S.Stk.discard<T>());
254*700637cbSDimitry Andric }
255*700637cbSDimitry Andric
cleanupAfterFunctionCall(InterpState & S,CodePtr OpPC,const Function * Func)256*700637cbSDimitry Andric void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
257*700637cbSDimitry Andric const Function *Func) {
258*700637cbSDimitry Andric assert(S.Current);
259*700637cbSDimitry Andric assert(Func);
260*700637cbSDimitry Andric
261*700637cbSDimitry Andric if (S.Current->Caller && Func->isVariadic()) {
262*700637cbSDimitry Andric // CallExpr we're look for is at the return PC of the current function, i.e.
263*700637cbSDimitry Andric // in the caller.
264*700637cbSDimitry Andric // This code path should be executed very rarely.
265*700637cbSDimitry Andric unsigned NumVarArgs;
266*700637cbSDimitry Andric const Expr *const *Args = nullptr;
267*700637cbSDimitry Andric unsigned NumArgs = 0;
268*700637cbSDimitry Andric const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());
269*700637cbSDimitry Andric if (const auto *CE = dyn_cast<CallExpr>(CallSite)) {
270*700637cbSDimitry Andric Args = CE->getArgs();
271*700637cbSDimitry Andric NumArgs = CE->getNumArgs();
272*700637cbSDimitry Andric } else if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {
273*700637cbSDimitry Andric Args = CE->getArgs();
274*700637cbSDimitry Andric NumArgs = CE->getNumArgs();
275*700637cbSDimitry Andric } else
276*700637cbSDimitry Andric assert(false && "Can't get arguments from that expression type");
277*700637cbSDimitry Andric
278*700637cbSDimitry Andric assert(NumArgs >= Func->getNumWrittenParams());
279*700637cbSDimitry Andric NumVarArgs = NumArgs - (Func->getNumWrittenParams() +
280*700637cbSDimitry Andric isa<CXXOperatorCallExpr>(CallSite));
281*700637cbSDimitry Andric for (unsigned I = 0; I != NumVarArgs; ++I) {
282*700637cbSDimitry Andric const Expr *A = Args[NumArgs - 1 - I];
283*700637cbSDimitry Andric popArg(S, A);
284*700637cbSDimitry Andric }
285*700637cbSDimitry Andric }
286*700637cbSDimitry Andric
287*700637cbSDimitry Andric // And in any case, remove the fixed parameters (the non-variadic ones)
288*700637cbSDimitry Andric // at the end.
289*700637cbSDimitry Andric for (PrimType Ty : Func->args_reverse())
290*700637cbSDimitry Andric TYPE_SWITCH(Ty, S.Stk.discard<T>());
291*700637cbSDimitry Andric }
292*700637cbSDimitry Andric
isConstexprUnknown(const Pointer & P)293*700637cbSDimitry Andric bool isConstexprUnknown(const Pointer &P) {
294*700637cbSDimitry Andric if (!P.isBlockPointer())
295*700637cbSDimitry Andric return false;
296*700637cbSDimitry Andric
297*700637cbSDimitry Andric if (P.isDummy())
298*700637cbSDimitry Andric return isa_and_nonnull<ParmVarDecl>(P.getDeclDesc()->asValueDecl());
299*700637cbSDimitry Andric
300*700637cbSDimitry Andric return P.getDeclDesc()->IsConstexprUnknown;
301*700637cbSDimitry Andric }
302*700637cbSDimitry Andric
CheckBCPResult(InterpState & S,const Pointer & Ptr)303*700637cbSDimitry Andric bool CheckBCPResult(InterpState &S, const Pointer &Ptr) {
304*700637cbSDimitry Andric if (Ptr.isDummy())
305*700637cbSDimitry Andric return false;
306*700637cbSDimitry Andric if (Ptr.isZero())
307*700637cbSDimitry Andric return true;
308*700637cbSDimitry Andric if (Ptr.isFunctionPointer())
309*700637cbSDimitry Andric return false;
310*700637cbSDimitry Andric if (Ptr.isIntegralPointer())
311*700637cbSDimitry Andric return true;
312*700637cbSDimitry Andric if (Ptr.isTypeidPointer())
313*700637cbSDimitry Andric return true;
314*700637cbSDimitry Andric
315*700637cbSDimitry Andric if (Ptr.getType()->isAnyComplexType())
316*700637cbSDimitry Andric return true;
317*700637cbSDimitry Andric
318*700637cbSDimitry Andric if (const Expr *Base = Ptr.getDeclDesc()->asExpr())
319*700637cbSDimitry Andric return isa<StringLiteral>(Base) && Ptr.getIndex() == 0;
320*700637cbSDimitry Andric return false;
321*700637cbSDimitry Andric }
322*700637cbSDimitry Andric
CheckActive(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)323*700637cbSDimitry Andric bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
324*700637cbSDimitry Andric AccessKinds AK) {
325*700637cbSDimitry Andric if (Ptr.isActive())
326*700637cbSDimitry Andric return true;
327*700637cbSDimitry Andric
328*700637cbSDimitry Andric assert(Ptr.inUnion());
329*700637cbSDimitry Andric assert(Ptr.isField() && Ptr.getField());
330*700637cbSDimitry Andric
331*700637cbSDimitry Andric Pointer U = Ptr.getBase();
332*700637cbSDimitry Andric Pointer C = Ptr;
333*700637cbSDimitry Andric while (!U.isRoot() && !U.isActive()) {
334*700637cbSDimitry Andric // A little arbitrary, but this is what the current interpreter does.
335*700637cbSDimitry Andric // See the AnonymousUnion test in test/AST/ByteCode/unions.cpp.
336*700637cbSDimitry Andric // GCC's output is more similar to what we would get without
337*700637cbSDimitry Andric // this condition.
338*700637cbSDimitry Andric if (U.getRecord() && U.getRecord()->isAnonymousUnion())
339*700637cbSDimitry Andric break;
340*700637cbSDimitry Andric
341*700637cbSDimitry Andric C = U;
342*700637cbSDimitry Andric U = U.getBase();
343*700637cbSDimitry Andric }
344*700637cbSDimitry Andric assert(C.isField());
345*700637cbSDimitry Andric
346*700637cbSDimitry Andric // Consider:
347*700637cbSDimitry Andric // union U {
348*700637cbSDimitry Andric // struct {
349*700637cbSDimitry Andric // int x;
350*700637cbSDimitry Andric // int y;
351*700637cbSDimitry Andric // } a;
352*700637cbSDimitry Andric // }
353*700637cbSDimitry Andric //
354*700637cbSDimitry Andric // When activating x, we will also activate a. If we now try to read
355*700637cbSDimitry Andric // from y, we will get to CheckActive, because y is not active. In that
356*700637cbSDimitry Andric // case, our U will be a (not a union). We return here and let later code
357*700637cbSDimitry Andric // handle this.
358*700637cbSDimitry Andric if (!U.getFieldDesc()->isUnion())
359*700637cbSDimitry Andric return true;
360*700637cbSDimitry Andric
361*700637cbSDimitry Andric // Get the inactive field descriptor.
362*700637cbSDimitry Andric assert(!C.isActive());
363*700637cbSDimitry Andric const FieldDecl *InactiveField = C.getField();
364*700637cbSDimitry Andric assert(InactiveField);
365*700637cbSDimitry Andric
366*700637cbSDimitry Andric // Find the active field of the union.
367*700637cbSDimitry Andric const Record *R = U.getRecord();
368*700637cbSDimitry Andric assert(R && R->isUnion() && "Not a union");
369*700637cbSDimitry Andric
370*700637cbSDimitry Andric const FieldDecl *ActiveField = nullptr;
371*700637cbSDimitry Andric for (const Record::Field &F : R->fields()) {
372*700637cbSDimitry Andric const Pointer &Field = U.atField(F.Offset);
373*700637cbSDimitry Andric if (Field.isActive()) {
374*700637cbSDimitry Andric ActiveField = Field.getField();
375*700637cbSDimitry Andric break;
376*700637cbSDimitry Andric }
377*700637cbSDimitry Andric }
378*700637cbSDimitry Andric
379*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
380*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member)
381*700637cbSDimitry Andric << AK << InactiveField << !ActiveField << ActiveField;
382*700637cbSDimitry Andric return false;
383*700637cbSDimitry Andric }
384*700637cbSDimitry Andric
CheckExtern(InterpState & S,CodePtr OpPC,const Pointer & Ptr)385*700637cbSDimitry Andric bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
386*700637cbSDimitry Andric if (!Ptr.isExtern())
387*700637cbSDimitry Andric return true;
388*700637cbSDimitry Andric
389*700637cbSDimitry Andric if (Ptr.isInitialized() ||
390*700637cbSDimitry Andric (Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl))
391*700637cbSDimitry Andric return true;
392*700637cbSDimitry Andric
393*700637cbSDimitry Andric if (S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus &&
394*700637cbSDimitry Andric Ptr.isConst())
395*700637cbSDimitry Andric return false;
396*700637cbSDimitry Andric
397*700637cbSDimitry Andric const auto *VD = Ptr.getDeclDesc()->asValueDecl();
398*700637cbSDimitry Andric diagnoseNonConstVariable(S, OpPC, VD);
399*700637cbSDimitry Andric return false;
400*700637cbSDimitry Andric }
401*700637cbSDimitry Andric
CheckArray(InterpState & S,CodePtr OpPC,const Pointer & Ptr)402*700637cbSDimitry Andric bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
403*700637cbSDimitry Andric if (!Ptr.isUnknownSizeArray())
404*700637cbSDimitry Andric return true;
405*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
406*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_unsized_array_indexed);
407*700637cbSDimitry Andric return false;
408*700637cbSDimitry Andric }
409*700637cbSDimitry Andric
CheckLive(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)410*700637cbSDimitry Andric bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
411*700637cbSDimitry Andric AccessKinds AK) {
412*700637cbSDimitry Andric if (Ptr.isZero()) {
413*700637cbSDimitry Andric const auto &Src = S.Current->getSource(OpPC);
414*700637cbSDimitry Andric
415*700637cbSDimitry Andric if (Ptr.isField())
416*700637cbSDimitry Andric S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
417*700637cbSDimitry Andric else
418*700637cbSDimitry Andric S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
419*700637cbSDimitry Andric
420*700637cbSDimitry Andric return false;
421*700637cbSDimitry Andric }
422*700637cbSDimitry Andric
423*700637cbSDimitry Andric if (!Ptr.isLive()) {
424*700637cbSDimitry Andric const auto &Src = S.Current->getSource(OpPC);
425*700637cbSDimitry Andric
426*700637cbSDimitry Andric if (Ptr.isDynamic()) {
427*700637cbSDimitry Andric S.FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;
428*700637cbSDimitry Andric } else if (!S.checkingPotentialConstantExpression()) {
429*700637cbSDimitry Andric bool IsTemp = Ptr.isTemporary();
430*700637cbSDimitry Andric S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
431*700637cbSDimitry Andric
432*700637cbSDimitry Andric if (IsTemp)
433*700637cbSDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
434*700637cbSDimitry Andric else
435*700637cbSDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
436*700637cbSDimitry Andric }
437*700637cbSDimitry Andric
438*700637cbSDimitry Andric return false;
439*700637cbSDimitry Andric }
440*700637cbSDimitry Andric
441*700637cbSDimitry Andric return true;
442*700637cbSDimitry Andric }
443*700637cbSDimitry Andric
CheckConstant(InterpState & S,CodePtr OpPC,const Descriptor * Desc)444*700637cbSDimitry Andric bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
445*700637cbSDimitry Andric assert(Desc);
446*700637cbSDimitry Andric
447*700637cbSDimitry Andric const auto *D = Desc->asVarDecl();
448*700637cbSDimitry Andric if (!D || D == S.EvaluatingDecl || D->isConstexpr())
449*700637cbSDimitry Andric return true;
450*700637cbSDimitry Andric
451*700637cbSDimitry Andric // If we're evaluating the initializer for a constexpr variable in C23, we may
452*700637cbSDimitry Andric // only read other contexpr variables. Abort here since this one isn't
453*700637cbSDimitry Andric // constexpr.
454*700637cbSDimitry Andric if (const auto *VD = dyn_cast_if_present<VarDecl>(S.EvaluatingDecl);
455*700637cbSDimitry Andric VD && VD->isConstexpr() && S.getLangOpts().C23)
456*700637cbSDimitry Andric return Invalid(S, OpPC);
457*700637cbSDimitry Andric
458*700637cbSDimitry Andric QualType T = D->getType();
459*700637cbSDimitry Andric bool IsConstant = T.isConstant(S.getASTContext());
460*700637cbSDimitry Andric if (T->isIntegralOrEnumerationType()) {
461*700637cbSDimitry Andric if (!IsConstant) {
462*700637cbSDimitry Andric diagnoseNonConstVariable(S, OpPC, D);
463*700637cbSDimitry Andric return false;
464*700637cbSDimitry Andric }
465*700637cbSDimitry Andric return true;
466*700637cbSDimitry Andric }
467*700637cbSDimitry Andric
468*700637cbSDimitry Andric if (IsConstant) {
469*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus) {
470*700637cbSDimitry Andric S.CCEDiag(S.Current->getLocation(OpPC),
471*700637cbSDimitry Andric S.getLangOpts().CPlusPlus11
472*700637cbSDimitry Andric ? diag::note_constexpr_ltor_non_constexpr
473*700637cbSDimitry Andric : diag::note_constexpr_ltor_non_integral,
474*700637cbSDimitry Andric 1)
475*700637cbSDimitry Andric << D << T;
476*700637cbSDimitry Andric S.Note(D->getLocation(), diag::note_declared_at);
477*700637cbSDimitry Andric } else {
478*700637cbSDimitry Andric S.CCEDiag(S.Current->getLocation(OpPC));
479*700637cbSDimitry Andric }
480*700637cbSDimitry Andric return true;
481*700637cbSDimitry Andric }
482*700637cbSDimitry Andric
483*700637cbSDimitry Andric if (T->isPointerOrReferenceType()) {
484*700637cbSDimitry Andric if (!T->getPointeeType().isConstant(S.getASTContext()) ||
485*700637cbSDimitry Andric !S.getLangOpts().CPlusPlus11) {
486*700637cbSDimitry Andric diagnoseNonConstVariable(S, OpPC, D);
487*700637cbSDimitry Andric return false;
488*700637cbSDimitry Andric }
489*700637cbSDimitry Andric return true;
490*700637cbSDimitry Andric }
491*700637cbSDimitry Andric
492*700637cbSDimitry Andric diagnoseNonConstVariable(S, OpPC, D);
493*700637cbSDimitry Andric return false;
494*700637cbSDimitry Andric }
495*700637cbSDimitry Andric
CheckConstant(InterpState & S,CodePtr OpPC,const Pointer & Ptr)496*700637cbSDimitry Andric static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
497*700637cbSDimitry Andric if (!Ptr.isStatic() || !Ptr.isBlockPointer())
498*700637cbSDimitry Andric return true;
499*700637cbSDimitry Andric if (!Ptr.getDeclID())
500*700637cbSDimitry Andric return true;
501*700637cbSDimitry Andric return CheckConstant(S, OpPC, Ptr.getDeclDesc());
502*700637cbSDimitry Andric }
503*700637cbSDimitry Andric
CheckNull(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)504*700637cbSDimitry Andric bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
505*700637cbSDimitry Andric CheckSubobjectKind CSK) {
506*700637cbSDimitry Andric if (!Ptr.isZero())
507*700637cbSDimitry Andric return true;
508*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
509*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_null_subobject)
510*700637cbSDimitry Andric << CSK << S.Current->getRange(OpPC);
511*700637cbSDimitry Andric
512*700637cbSDimitry Andric return false;
513*700637cbSDimitry Andric }
514*700637cbSDimitry Andric
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)515*700637cbSDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
516*700637cbSDimitry Andric AccessKinds AK) {
517*700637cbSDimitry Andric if (!Ptr.isOnePastEnd())
518*700637cbSDimitry Andric return true;
519*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus) {
520*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
521*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_past_end)
522*700637cbSDimitry Andric << AK << S.Current->getRange(OpPC);
523*700637cbSDimitry Andric }
524*700637cbSDimitry Andric return false;
525*700637cbSDimitry Andric }
526*700637cbSDimitry Andric
CheckRange(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)527*700637cbSDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
528*700637cbSDimitry Andric CheckSubobjectKind CSK) {
529*700637cbSDimitry Andric if (!Ptr.isElementPastEnd())
530*700637cbSDimitry Andric return true;
531*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
532*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
533*700637cbSDimitry Andric << CSK << S.Current->getRange(OpPC);
534*700637cbSDimitry Andric return false;
535*700637cbSDimitry Andric }
536*700637cbSDimitry Andric
CheckSubobject(InterpState & S,CodePtr OpPC,const Pointer & Ptr,CheckSubobjectKind CSK)537*700637cbSDimitry Andric bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
538*700637cbSDimitry Andric CheckSubobjectKind CSK) {
539*700637cbSDimitry Andric if (!Ptr.isOnePastEnd())
540*700637cbSDimitry Andric return true;
541*700637cbSDimitry Andric
542*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
543*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
544*700637cbSDimitry Andric << CSK << S.Current->getRange(OpPC);
545*700637cbSDimitry Andric return false;
546*700637cbSDimitry Andric }
547*700637cbSDimitry Andric
CheckDowncast(InterpState & S,CodePtr OpPC,const Pointer & Ptr,uint32_t Offset)548*700637cbSDimitry Andric bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
549*700637cbSDimitry Andric uint32_t Offset) {
550*700637cbSDimitry Andric uint32_t MinOffset = Ptr.getDeclDesc()->getMetadataSize();
551*700637cbSDimitry Andric uint32_t PtrOffset = Ptr.getByteOffset();
552*700637cbSDimitry Andric
553*700637cbSDimitry Andric // We subtract Offset from PtrOffset. The result must be at least
554*700637cbSDimitry Andric // MinOffset.
555*700637cbSDimitry Andric if (Offset < PtrOffset && (PtrOffset - Offset) >= MinOffset)
556*700637cbSDimitry Andric return true;
557*700637cbSDimitry Andric
558*700637cbSDimitry Andric const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));
559*700637cbSDimitry Andric QualType TargetQT = E->getType()->getPointeeType();
560*700637cbSDimitry Andric QualType MostDerivedQT = Ptr.getDeclPtr().getType();
561*700637cbSDimitry Andric
562*700637cbSDimitry Andric S.CCEDiag(E, diag::note_constexpr_invalid_downcast)
563*700637cbSDimitry Andric << MostDerivedQT << TargetQT;
564*700637cbSDimitry Andric
565*700637cbSDimitry Andric return false;
566*700637cbSDimitry Andric }
567*700637cbSDimitry Andric
CheckConst(InterpState & S,CodePtr OpPC,const Pointer & Ptr)568*700637cbSDimitry Andric bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
569*700637cbSDimitry Andric assert(Ptr.isLive() && "Pointer is not live");
570*700637cbSDimitry Andric if (!Ptr.isConst() || Ptr.isMutable())
571*700637cbSDimitry Andric return true;
572*700637cbSDimitry Andric
573*700637cbSDimitry Andric if (!Ptr.isBlockPointer())
574*700637cbSDimitry Andric return false;
575*700637cbSDimitry Andric
576*700637cbSDimitry Andric // The This pointer is writable in constructors and destructors,
577*700637cbSDimitry Andric // even if isConst() returns true.
578*700637cbSDimitry Andric if (llvm::find(S.InitializingBlocks, Ptr.block()))
579*700637cbSDimitry Andric return true;
580*700637cbSDimitry Andric
581*700637cbSDimitry Andric const QualType Ty = Ptr.getType();
582*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
583*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
584*700637cbSDimitry Andric return false;
585*700637cbSDimitry Andric }
586*700637cbSDimitry Andric
CheckMutable(InterpState & S,CodePtr OpPC,const Pointer & Ptr)587*700637cbSDimitry Andric bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
588*700637cbSDimitry Andric assert(Ptr.isLive() && "Pointer is not live");
589*700637cbSDimitry Andric if (!Ptr.isMutable())
590*700637cbSDimitry Andric return true;
591*700637cbSDimitry Andric
592*700637cbSDimitry Andric // In C++14 onwards, it is permitted to read a mutable member whose
593*700637cbSDimitry Andric // lifetime began within the evaluation.
594*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus14 &&
595*700637cbSDimitry Andric Ptr.block()->getEvalID() == S.Ctx.getEvalID()) {
596*700637cbSDimitry Andric // FIXME: This check is necessary because (of the way) we revisit
597*700637cbSDimitry Andric // variables in Compiler.cpp:visitDeclRef. Revisiting a so far
598*700637cbSDimitry Andric // unknown variable will get the same EvalID and we end up allowing
599*700637cbSDimitry Andric // reads from mutable members of it.
600*700637cbSDimitry Andric if (!S.inConstantContext() && isConstexprUnknown(Ptr))
601*700637cbSDimitry Andric return false;
602*700637cbSDimitry Andric return true;
603*700637cbSDimitry Andric }
604*700637cbSDimitry Andric
605*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
606*700637cbSDimitry Andric const FieldDecl *Field = Ptr.getField();
607*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field;
608*700637cbSDimitry Andric S.Note(Field->getLocation(), diag::note_declared_at);
609*700637cbSDimitry Andric return false;
610*700637cbSDimitry Andric }
611*700637cbSDimitry Andric
CheckVolatile(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)612*700637cbSDimitry Andric static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
613*700637cbSDimitry Andric AccessKinds AK) {
614*700637cbSDimitry Andric assert(Ptr.isLive());
615*700637cbSDimitry Andric
616*700637cbSDimitry Andric if (!Ptr.isVolatile())
617*700637cbSDimitry Andric return true;
618*700637cbSDimitry Andric
619*700637cbSDimitry Andric if (!S.getLangOpts().CPlusPlus)
620*700637cbSDimitry Andric return Invalid(S, OpPC);
621*700637cbSDimitry Andric
622*700637cbSDimitry Andric // The reason why Ptr is volatile might be further up the hierarchy.
623*700637cbSDimitry Andric // Find that pointer.
624*700637cbSDimitry Andric Pointer P = Ptr;
625*700637cbSDimitry Andric while (!P.isRoot()) {
626*700637cbSDimitry Andric if (P.getType().isVolatileQualified())
627*700637cbSDimitry Andric break;
628*700637cbSDimitry Andric P = P.getBase();
629*700637cbSDimitry Andric }
630*700637cbSDimitry Andric
631*700637cbSDimitry Andric const NamedDecl *ND = nullptr;
632*700637cbSDimitry Andric int DiagKind;
633*700637cbSDimitry Andric SourceLocation Loc;
634*700637cbSDimitry Andric if (const auto *F = P.getField()) {
635*700637cbSDimitry Andric DiagKind = 2;
636*700637cbSDimitry Andric Loc = F->getLocation();
637*700637cbSDimitry Andric ND = F;
638*700637cbSDimitry Andric } else if (auto *VD = P.getFieldDesc()->asValueDecl()) {
639*700637cbSDimitry Andric DiagKind = 1;
640*700637cbSDimitry Andric Loc = VD->getLocation();
641*700637cbSDimitry Andric ND = VD;
642*700637cbSDimitry Andric } else {
643*700637cbSDimitry Andric DiagKind = 0;
644*700637cbSDimitry Andric if (const auto *E = P.getFieldDesc()->asExpr())
645*700637cbSDimitry Andric Loc = E->getExprLoc();
646*700637cbSDimitry Andric }
647*700637cbSDimitry Andric
648*700637cbSDimitry Andric S.FFDiag(S.Current->getLocation(OpPC),
649*700637cbSDimitry Andric diag::note_constexpr_access_volatile_obj, 1)
650*700637cbSDimitry Andric << AK << DiagKind << ND;
651*700637cbSDimitry Andric S.Note(Loc, diag::note_constexpr_volatile_here) << DiagKind;
652*700637cbSDimitry Andric return false;
653*700637cbSDimitry Andric }
654*700637cbSDimitry Andric
CheckInitialized(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)655*700637cbSDimitry Andric bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
656*700637cbSDimitry Andric AccessKinds AK) {
657*700637cbSDimitry Andric assert(Ptr.isLive());
658*700637cbSDimitry Andric
659*700637cbSDimitry Andric if (Ptr.isInitialized())
660*700637cbSDimitry Andric return true;
661*700637cbSDimitry Andric
662*700637cbSDimitry Andric if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
663*700637cbSDimitry Andric VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {
664*700637cbSDimitry Andric
665*700637cbSDimitry Andric if (VD == S.EvaluatingDecl &&
666*700637cbSDimitry Andric !(S.getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType())) {
667*700637cbSDimitry Andric if (!S.getLangOpts().CPlusPlus14 &&
668*700637cbSDimitry Andric !VD->getType().isConstant(S.getASTContext())) {
669*700637cbSDimitry Andric // Diagnose as non-const read.
670*700637cbSDimitry Andric diagnoseNonConstVariable(S, OpPC, VD);
671*700637cbSDimitry Andric } else {
672*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
673*700637cbSDimitry Andric // Diagnose as "read of object outside its lifetime".
674*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_access_uninit)
675*700637cbSDimitry Andric << AK << /*IsIndeterminate=*/false;
676*700637cbSDimitry Andric }
677*700637cbSDimitry Andric return false;
678*700637cbSDimitry Andric }
679*700637cbSDimitry Andric
680*700637cbSDimitry Andric if (VD->getAnyInitializer()) {
681*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
682*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
683*700637cbSDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at);
684*700637cbSDimitry Andric } else {
685*700637cbSDimitry Andric diagnoseMissingInitializer(S, OpPC, VD);
686*700637cbSDimitry Andric }
687*700637cbSDimitry Andric return false;
688*700637cbSDimitry Andric }
689*700637cbSDimitry Andric
690*700637cbSDimitry Andric if (!S.checkingPotentialConstantExpression()) {
691*700637cbSDimitry Andric S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
692*700637cbSDimitry Andric << AK << /*uninitialized=*/true << S.Current->getRange(OpPC);
693*700637cbSDimitry Andric }
694*700637cbSDimitry Andric return false;
695*700637cbSDimitry Andric }
696*700637cbSDimitry Andric
CheckLifetime(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)697*700637cbSDimitry Andric static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
698*700637cbSDimitry Andric AccessKinds AK) {
699*700637cbSDimitry Andric if (Ptr.getLifetime() == Lifetime::Started)
700*700637cbSDimitry Andric return true;
701*700637cbSDimitry Andric
702*700637cbSDimitry Andric if (!S.checkingPotentialConstantExpression()) {
703*700637cbSDimitry Andric S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
704*700637cbSDimitry Andric << AK << /*uninitialized=*/false << S.Current->getRange(OpPC);
705*700637cbSDimitry Andric }
706*700637cbSDimitry Andric return false;
707*700637cbSDimitry Andric }
708*700637cbSDimitry Andric
CheckGlobalInitialized(InterpState & S,CodePtr OpPC,const Pointer & Ptr)709*700637cbSDimitry Andric bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
710*700637cbSDimitry Andric if (Ptr.isInitialized())
711*700637cbSDimitry Andric return true;
712*700637cbSDimitry Andric
713*700637cbSDimitry Andric assert(S.getLangOpts().CPlusPlus);
714*700637cbSDimitry Andric const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl());
715*700637cbSDimitry Andric if ((!VD->hasConstantInitialization() &&
716*700637cbSDimitry Andric VD->mightBeUsableInConstantExpressions(S.getASTContext())) ||
717*700637cbSDimitry Andric (S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 &&
718*700637cbSDimitry Andric !VD->hasICEInitializer(S.getASTContext()))) {
719*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
720*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;
721*700637cbSDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at);
722*700637cbSDimitry Andric }
723*700637cbSDimitry Andric return false;
724*700637cbSDimitry Andric }
725*700637cbSDimitry Andric
CheckWeak(InterpState & S,CodePtr OpPC,const Pointer & Ptr)726*700637cbSDimitry Andric static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
727*700637cbSDimitry Andric if (!Ptr.isWeak())
728*700637cbSDimitry Andric return true;
729*700637cbSDimitry Andric
730*700637cbSDimitry Andric const auto *VD = Ptr.getDeclDesc()->asVarDecl();
731*700637cbSDimitry Andric assert(VD);
732*700637cbSDimitry Andric S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_var_init_weak)
733*700637cbSDimitry Andric << VD;
734*700637cbSDimitry Andric S.Note(VD->getLocation(), diag::note_declared_at);
735*700637cbSDimitry Andric
736*700637cbSDimitry Andric return false;
737*700637cbSDimitry Andric }
738*700637cbSDimitry Andric
CheckLoad(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)739*700637cbSDimitry Andric bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
740*700637cbSDimitry Andric AccessKinds AK) {
741*700637cbSDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK))
742*700637cbSDimitry Andric return false;
743*700637cbSDimitry Andric if (!CheckExtern(S, OpPC, Ptr))
744*700637cbSDimitry Andric return false;
745*700637cbSDimitry Andric if (!CheckConstant(S, OpPC, Ptr))
746*700637cbSDimitry Andric return false;
747*700637cbSDimitry Andric if (!CheckDummy(S, OpPC, Ptr, AK))
748*700637cbSDimitry Andric return false;
749*700637cbSDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK))
750*700637cbSDimitry Andric return false;
751*700637cbSDimitry Andric if (!CheckActive(S, OpPC, Ptr, AK))
752*700637cbSDimitry Andric return false;
753*700637cbSDimitry Andric if (!CheckLifetime(S, OpPC, Ptr, AK))
754*700637cbSDimitry Andric return false;
755*700637cbSDimitry Andric if (!CheckInitialized(S, OpPC, Ptr, AK))
756*700637cbSDimitry Andric return false;
757*700637cbSDimitry Andric if (!CheckTemporary(S, OpPC, Ptr, AK))
758*700637cbSDimitry Andric return false;
759*700637cbSDimitry Andric if (!CheckWeak(S, OpPC, Ptr))
760*700637cbSDimitry Andric return false;
761*700637cbSDimitry Andric if (!CheckMutable(S, OpPC, Ptr))
762*700637cbSDimitry Andric return false;
763*700637cbSDimitry Andric if (!CheckVolatile(S, OpPC, Ptr, AK))
764*700637cbSDimitry Andric return false;
765*700637cbSDimitry Andric return true;
766*700637cbSDimitry Andric }
767*700637cbSDimitry Andric
768*700637cbSDimitry Andric /// This is not used by any of the opcodes directly. It's used by
769*700637cbSDimitry Andric /// EvalEmitter to do the final lvalue-to-rvalue conversion.
CheckFinalLoad(InterpState & S,CodePtr OpPC,const Pointer & Ptr)770*700637cbSDimitry Andric bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
771*700637cbSDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_Read))
772*700637cbSDimitry Andric return false;
773*700637cbSDimitry Andric if (!CheckConstant(S, OpPC, Ptr))
774*700637cbSDimitry Andric return false;
775*700637cbSDimitry Andric
776*700637cbSDimitry Andric if (!CheckDummy(S, OpPC, Ptr, AK_Read))
777*700637cbSDimitry Andric return false;
778*700637cbSDimitry Andric if (!CheckExtern(S, OpPC, Ptr))
779*700637cbSDimitry Andric return false;
780*700637cbSDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_Read))
781*700637cbSDimitry Andric return false;
782*700637cbSDimitry Andric if (!CheckActive(S, OpPC, Ptr, AK_Read))
783*700637cbSDimitry Andric return false;
784*700637cbSDimitry Andric if (!CheckLifetime(S, OpPC, Ptr, AK_Read))
785*700637cbSDimitry Andric return false;
786*700637cbSDimitry Andric if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
787*700637cbSDimitry Andric return false;
788*700637cbSDimitry Andric if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
789*700637cbSDimitry Andric return false;
790*700637cbSDimitry Andric if (!CheckWeak(S, OpPC, Ptr))
791*700637cbSDimitry Andric return false;
792*700637cbSDimitry Andric if (!CheckMutable(S, OpPC, Ptr))
793*700637cbSDimitry Andric return false;
794*700637cbSDimitry Andric return true;
795*700637cbSDimitry Andric }
796*700637cbSDimitry Andric
CheckStore(InterpState & S,CodePtr OpPC,const Pointer & Ptr)797*700637cbSDimitry Andric bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
798*700637cbSDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_Assign))
799*700637cbSDimitry Andric return false;
800*700637cbSDimitry Andric if (!CheckDummy(S, OpPC, Ptr, AK_Assign))
801*700637cbSDimitry Andric return false;
802*700637cbSDimitry Andric if (!CheckLifetime(S, OpPC, Ptr, AK_Assign))
803*700637cbSDimitry Andric return false;
804*700637cbSDimitry Andric if (!CheckExtern(S, OpPC, Ptr))
805*700637cbSDimitry Andric return false;
806*700637cbSDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_Assign))
807*700637cbSDimitry Andric return false;
808*700637cbSDimitry Andric if (!CheckGlobal(S, OpPC, Ptr))
809*700637cbSDimitry Andric return false;
810*700637cbSDimitry Andric if (!CheckConst(S, OpPC, Ptr))
811*700637cbSDimitry Andric return false;
812*700637cbSDimitry Andric if (!S.inConstantContext() && isConstexprUnknown(Ptr))
813*700637cbSDimitry Andric return false;
814*700637cbSDimitry Andric return true;
815*700637cbSDimitry Andric }
816*700637cbSDimitry Andric
CheckInvoke(InterpState & S,CodePtr OpPC,const Pointer & Ptr)817*700637cbSDimitry Andric bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
818*700637cbSDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_MemberCall))
819*700637cbSDimitry Andric return false;
820*700637cbSDimitry Andric if (!Ptr.isDummy()) {
821*700637cbSDimitry Andric if (!CheckExtern(S, OpPC, Ptr))
822*700637cbSDimitry Andric return false;
823*700637cbSDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_MemberCall))
824*700637cbSDimitry Andric return false;
825*700637cbSDimitry Andric }
826*700637cbSDimitry Andric return true;
827*700637cbSDimitry Andric }
828*700637cbSDimitry Andric
CheckInit(InterpState & S,CodePtr OpPC,const Pointer & Ptr)829*700637cbSDimitry Andric bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
830*700637cbSDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_Assign))
831*700637cbSDimitry Andric return false;
832*700637cbSDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_Assign))
833*700637cbSDimitry Andric return false;
834*700637cbSDimitry Andric return true;
835*700637cbSDimitry Andric }
836*700637cbSDimitry Andric
CheckCallable(InterpState & S,CodePtr OpPC,const Function * F)837*700637cbSDimitry Andric bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
838*700637cbSDimitry Andric
839*700637cbSDimitry Andric if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) {
840*700637cbSDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC);
841*700637cbSDimitry Andric S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
842*700637cbSDimitry Andric return false;
843*700637cbSDimitry Andric }
844*700637cbSDimitry Andric
845*700637cbSDimitry Andric if (S.checkingPotentialConstantExpression() && S.Current->getDepth() != 0)
846*700637cbSDimitry Andric return false;
847*700637cbSDimitry Andric
848*700637cbSDimitry Andric if (F->isValid() && F->hasBody() && F->isConstexpr())
849*700637cbSDimitry Andric return true;
850*700637cbSDimitry Andric
851*700637cbSDimitry Andric // Implicitly constexpr.
852*700637cbSDimitry Andric if (F->isLambdaStaticInvoker())
853*700637cbSDimitry Andric return true;
854*700637cbSDimitry Andric
855*700637cbSDimitry Andric // Bail out if the function declaration itself is invalid. We will
856*700637cbSDimitry Andric // have produced a relevant diagnostic while parsing it, so just
857*700637cbSDimitry Andric // note the problematic sub-expression.
858*700637cbSDimitry Andric if (F->getDecl()->isInvalidDecl())
859*700637cbSDimitry Andric return Invalid(S, OpPC);
860*700637cbSDimitry Andric
861*700637cbSDimitry Andric // Diagnose failed assertions specially.
862*700637cbSDimitry Andric if (S.Current->getLocation(OpPC).isMacroID() &&
863*700637cbSDimitry Andric F->getDecl()->getIdentifier()) {
864*700637cbSDimitry Andric // FIXME: Instead of checking for an implementation-defined function,
865*700637cbSDimitry Andric // check and evaluate the assert() macro.
866*700637cbSDimitry Andric StringRef Name = F->getDecl()->getName();
867*700637cbSDimitry Andric bool AssertFailed =
868*700637cbSDimitry Andric Name == "__assert_rtn" || Name == "__assert_fail" || Name == "_wassert";
869*700637cbSDimitry Andric if (AssertFailed) {
870*700637cbSDimitry Andric S.FFDiag(S.Current->getLocation(OpPC),
871*700637cbSDimitry Andric diag::note_constexpr_assert_failed);
872*700637cbSDimitry Andric return false;
873*700637cbSDimitry Andric }
874*700637cbSDimitry Andric }
875*700637cbSDimitry Andric
876*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus11) {
877*700637cbSDimitry Andric const FunctionDecl *DiagDecl = F->getDecl();
878*700637cbSDimitry Andric
879*700637cbSDimitry Andric // Invalid decls have been diagnosed before.
880*700637cbSDimitry Andric if (DiagDecl->isInvalidDecl())
881*700637cbSDimitry Andric return false;
882*700637cbSDimitry Andric
883*700637cbSDimitry Andric // If this function is not constexpr because it is an inherited
884*700637cbSDimitry Andric // non-constexpr constructor, diagnose that directly.
885*700637cbSDimitry Andric const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl);
886*700637cbSDimitry Andric if (CD && CD->isInheritingConstructor()) {
887*700637cbSDimitry Andric const auto *Inherited = CD->getInheritedConstructor().getConstructor();
888*700637cbSDimitry Andric if (!Inherited->isConstexpr())
889*700637cbSDimitry Andric DiagDecl = CD = Inherited;
890*700637cbSDimitry Andric }
891*700637cbSDimitry Andric
892*700637cbSDimitry Andric // Silently reject constructors of invalid classes. The invalid class
893*700637cbSDimitry Andric // has been rejected elsewhere before.
894*700637cbSDimitry Andric if (CD && CD->getParent()->isInvalidDecl())
895*700637cbSDimitry Andric return false;
896*700637cbSDimitry Andric
897*700637cbSDimitry Andric // FIXME: If DiagDecl is an implicitly-declared special member function
898*700637cbSDimitry Andric // or an inheriting constructor, we should be much more explicit about why
899*700637cbSDimitry Andric // it's not constexpr.
900*700637cbSDimitry Andric if (CD && CD->isInheritingConstructor()) {
901*700637cbSDimitry Andric S.FFDiag(S.Current->getLocation(OpPC),
902*700637cbSDimitry Andric diag::note_constexpr_invalid_inhctor, 1)
903*700637cbSDimitry Andric << CD->getInheritedConstructor().getConstructor()->getParent();
904*700637cbSDimitry Andric S.Note(DiagDecl->getLocation(), diag::note_declared_at);
905*700637cbSDimitry Andric } else {
906*700637cbSDimitry Andric // Don't emit anything if the function isn't defined and we're checking
907*700637cbSDimitry Andric // for a constant expression. It might be defined at the point we're
908*700637cbSDimitry Andric // actually calling it.
909*700637cbSDimitry Andric bool IsExtern = DiagDecl->getStorageClass() == SC_Extern;
910*700637cbSDimitry Andric bool IsDefined = F->isDefined();
911*700637cbSDimitry Andric if (!IsDefined && !IsExtern && DiagDecl->isConstexpr() &&
912*700637cbSDimitry Andric S.checkingPotentialConstantExpression())
913*700637cbSDimitry Andric return false;
914*700637cbSDimitry Andric
915*700637cbSDimitry Andric // If the declaration is defined, declared 'constexpr' _and_ has a body,
916*700637cbSDimitry Andric // the below diagnostic doesn't add anything useful.
917*700637cbSDimitry Andric if (DiagDecl->isDefined() && DiagDecl->isConstexpr() &&
918*700637cbSDimitry Andric DiagDecl->hasBody())
919*700637cbSDimitry Andric return false;
920*700637cbSDimitry Andric
921*700637cbSDimitry Andric S.FFDiag(S.Current->getLocation(OpPC),
922*700637cbSDimitry Andric diag::note_constexpr_invalid_function, 1)
923*700637cbSDimitry Andric << DiagDecl->isConstexpr() << (bool)CD << DiagDecl;
924*700637cbSDimitry Andric
925*700637cbSDimitry Andric if (DiagDecl->getDefinition())
926*700637cbSDimitry Andric S.Note(DiagDecl->getDefinition()->getLocation(),
927*700637cbSDimitry Andric diag::note_declared_at);
928*700637cbSDimitry Andric else
929*700637cbSDimitry Andric S.Note(DiagDecl->getLocation(), diag::note_declared_at);
930*700637cbSDimitry Andric }
931*700637cbSDimitry Andric } else {
932*700637cbSDimitry Andric S.FFDiag(S.Current->getLocation(OpPC),
933*700637cbSDimitry Andric diag::note_invalid_subexpr_in_const_expr);
934*700637cbSDimitry Andric }
935*700637cbSDimitry Andric
936*700637cbSDimitry Andric return false;
937*700637cbSDimitry Andric }
938*700637cbSDimitry Andric
CheckCallDepth(InterpState & S,CodePtr OpPC)939*700637cbSDimitry Andric bool CheckCallDepth(InterpState &S, CodePtr OpPC) {
940*700637cbSDimitry Andric if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) {
941*700637cbSDimitry Andric S.FFDiag(S.Current->getSource(OpPC),
942*700637cbSDimitry Andric diag::note_constexpr_depth_limit_exceeded)
943*700637cbSDimitry Andric << S.getLangOpts().ConstexprCallDepth;
944*700637cbSDimitry Andric return false;
945*700637cbSDimitry Andric }
946*700637cbSDimitry Andric
947*700637cbSDimitry Andric return true;
948*700637cbSDimitry Andric }
949*700637cbSDimitry Andric
CheckThis(InterpState & S,CodePtr OpPC,const Pointer & This)950*700637cbSDimitry Andric bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) {
951*700637cbSDimitry Andric if (!This.isZero())
952*700637cbSDimitry Andric return true;
953*700637cbSDimitry Andric
954*700637cbSDimitry Andric const Expr *E = S.Current->getExpr(OpPC);
955*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus11) {
956*700637cbSDimitry Andric bool IsImplicit = false;
957*700637cbSDimitry Andric if (const auto *TE = dyn_cast<CXXThisExpr>(E))
958*700637cbSDimitry Andric IsImplicit = TE->isImplicit();
959*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_this) << IsImplicit;
960*700637cbSDimitry Andric } else {
961*700637cbSDimitry Andric S.FFDiag(E);
962*700637cbSDimitry Andric }
963*700637cbSDimitry Andric
964*700637cbSDimitry Andric return false;
965*700637cbSDimitry Andric }
966*700637cbSDimitry Andric
CheckFloatResult(InterpState & S,CodePtr OpPC,const Floating & Result,APFloat::opStatus Status,FPOptions FPO)967*700637cbSDimitry Andric bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
968*700637cbSDimitry Andric APFloat::opStatus Status, FPOptions FPO) {
969*700637cbSDimitry Andric // [expr.pre]p4:
970*700637cbSDimitry Andric // If during the evaluation of an expression, the result is not
971*700637cbSDimitry Andric // mathematically defined [...], the behavior is undefined.
972*700637cbSDimitry Andric // FIXME: C++ rules require us to not conform to IEEE 754 here.
973*700637cbSDimitry Andric if (Result.isNan()) {
974*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
975*700637cbSDimitry Andric S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
976*700637cbSDimitry Andric << /*NaN=*/true << S.Current->getRange(OpPC);
977*700637cbSDimitry Andric return S.noteUndefinedBehavior();
978*700637cbSDimitry Andric }
979*700637cbSDimitry Andric
980*700637cbSDimitry Andric // In a constant context, assume that any dynamic rounding mode or FP
981*700637cbSDimitry Andric // exception state matches the default floating-point environment.
982*700637cbSDimitry Andric if (S.inConstantContext())
983*700637cbSDimitry Andric return true;
984*700637cbSDimitry Andric
985*700637cbSDimitry Andric if ((Status & APFloat::opInexact) &&
986*700637cbSDimitry Andric FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) {
987*700637cbSDimitry Andric // Inexact result means that it depends on rounding mode. If the requested
988*700637cbSDimitry Andric // mode is dynamic, the evaluation cannot be made in compile time.
989*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
990*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_dynamic_rounding);
991*700637cbSDimitry Andric return false;
992*700637cbSDimitry Andric }
993*700637cbSDimitry Andric
994*700637cbSDimitry Andric if ((Status != APFloat::opOK) &&
995*700637cbSDimitry Andric (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic ||
996*700637cbSDimitry Andric FPO.getExceptionMode() != LangOptions::FPE_Ignore ||
997*700637cbSDimitry Andric FPO.getAllowFEnvAccess())) {
998*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
999*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
1000*700637cbSDimitry Andric return false;
1001*700637cbSDimitry Andric }
1002*700637cbSDimitry Andric
1003*700637cbSDimitry Andric if ((Status & APFloat::opStatus::opInvalidOp) &&
1004*700637cbSDimitry Andric FPO.getExceptionMode() != LangOptions::FPE_Ignore) {
1005*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
1006*700637cbSDimitry Andric // There is no usefully definable result.
1007*700637cbSDimitry Andric S.FFDiag(E);
1008*700637cbSDimitry Andric return false;
1009*700637cbSDimitry Andric }
1010*700637cbSDimitry Andric
1011*700637cbSDimitry Andric return true;
1012*700637cbSDimitry Andric }
1013*700637cbSDimitry Andric
CheckDynamicMemoryAllocation(InterpState & S,CodePtr OpPC)1014*700637cbSDimitry Andric bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC) {
1015*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus20)
1016*700637cbSDimitry Andric return true;
1017*700637cbSDimitry Andric
1018*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
1019*700637cbSDimitry Andric S.CCEDiag(E, diag::note_constexpr_new);
1020*700637cbSDimitry Andric return true;
1021*700637cbSDimitry Andric }
1022*700637cbSDimitry Andric
CheckNewDeleteForms(InterpState & S,CodePtr OpPC,DynamicAllocator::Form AllocForm,DynamicAllocator::Form DeleteForm,const Descriptor * D,const Expr * NewExpr)1023*700637cbSDimitry Andric bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,
1024*700637cbSDimitry Andric DynamicAllocator::Form AllocForm,
1025*700637cbSDimitry Andric DynamicAllocator::Form DeleteForm, const Descriptor *D,
1026*700637cbSDimitry Andric const Expr *NewExpr) {
1027*700637cbSDimitry Andric if (AllocForm == DeleteForm)
1028*700637cbSDimitry Andric return true;
1029*700637cbSDimitry Andric
1030*700637cbSDimitry Andric QualType TypeToDiagnose = D->getDataType(S.getASTContext());
1031*700637cbSDimitry Andric
1032*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
1033*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_new_delete_mismatch)
1034*700637cbSDimitry Andric << static_cast<int>(DeleteForm) << static_cast<int>(AllocForm)
1035*700637cbSDimitry Andric << TypeToDiagnose;
1036*700637cbSDimitry Andric S.Note(NewExpr->getExprLoc(), diag::note_constexpr_dynamic_alloc_here)
1037*700637cbSDimitry Andric << NewExpr->getSourceRange();
1038*700637cbSDimitry Andric return false;
1039*700637cbSDimitry Andric }
1040*700637cbSDimitry Andric
CheckDeleteSource(InterpState & S,CodePtr OpPC,const Expr * Source,const Pointer & Ptr)1041*700637cbSDimitry Andric bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,
1042*700637cbSDimitry Andric const Pointer &Ptr) {
1043*700637cbSDimitry Andric // Regular new type(...) call.
1044*700637cbSDimitry Andric if (isa_and_nonnull<CXXNewExpr>(Source))
1045*700637cbSDimitry Andric return true;
1046*700637cbSDimitry Andric // operator new.
1047*700637cbSDimitry Andric if (const auto *CE = dyn_cast_if_present<CallExpr>(Source);
1048*700637cbSDimitry Andric CE && CE->getBuiltinCallee() == Builtin::BI__builtin_operator_new)
1049*700637cbSDimitry Andric return true;
1050*700637cbSDimitry Andric // std::allocator.allocate() call
1051*700637cbSDimitry Andric if (const auto *MCE = dyn_cast_if_present<CXXMemberCallExpr>(Source);
1052*700637cbSDimitry Andric MCE && MCE->getMethodDecl()->getIdentifier()->isStr("allocate"))
1053*700637cbSDimitry Andric return true;
1054*700637cbSDimitry Andric
1055*700637cbSDimitry Andric // Whatever this is, we didn't heap allocate it.
1056*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
1057*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
1058*700637cbSDimitry Andric << Ptr.toDiagnosticString(S.getASTContext());
1059*700637cbSDimitry Andric
1060*700637cbSDimitry Andric if (Ptr.isTemporary())
1061*700637cbSDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
1062*700637cbSDimitry Andric else
1063*700637cbSDimitry Andric S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
1064*700637cbSDimitry Andric return false;
1065*700637cbSDimitry Andric }
1066*700637cbSDimitry Andric
1067*700637cbSDimitry Andric /// We aleady know the given DeclRefExpr is invalid for some reason,
1068*700637cbSDimitry Andric /// now figure out why and print appropriate diagnostics.
CheckDeclRef(InterpState & S,CodePtr OpPC,const DeclRefExpr * DR)1069*700637cbSDimitry Andric bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
1070*700637cbSDimitry Andric const ValueDecl *D = DR->getDecl();
1071*700637cbSDimitry Andric return diagnoseUnknownDecl(S, OpPC, D);
1072*700637cbSDimitry Andric }
1073*700637cbSDimitry Andric
CheckDummy(InterpState & S,CodePtr OpPC,const Pointer & Ptr,AccessKinds AK)1074*700637cbSDimitry Andric bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1075*700637cbSDimitry Andric AccessKinds AK) {
1076*700637cbSDimitry Andric if (!Ptr.isDummy())
1077*700637cbSDimitry Andric return true;
1078*700637cbSDimitry Andric
1079*700637cbSDimitry Andric const Descriptor *Desc = Ptr.getDeclDesc();
1080*700637cbSDimitry Andric const ValueDecl *D = Desc->asValueDecl();
1081*700637cbSDimitry Andric if (!D)
1082*700637cbSDimitry Andric return false;
1083*700637cbSDimitry Andric
1084*700637cbSDimitry Andric if (AK == AK_Read || AK == AK_Increment || AK == AK_Decrement)
1085*700637cbSDimitry Andric return diagnoseUnknownDecl(S, OpPC, D);
1086*700637cbSDimitry Andric
1087*700637cbSDimitry Andric if (AK == AK_Destroy || S.getLangOpts().CPlusPlus14) {
1088*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
1089*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_modify_global);
1090*700637cbSDimitry Andric }
1091*700637cbSDimitry Andric return false;
1092*700637cbSDimitry Andric }
1093*700637cbSDimitry Andric
CheckNonNullArgs(InterpState & S,CodePtr OpPC,const Function * F,const CallExpr * CE,unsigned ArgSize)1094*700637cbSDimitry Andric bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
1095*700637cbSDimitry Andric const CallExpr *CE, unsigned ArgSize) {
1096*700637cbSDimitry Andric auto Args = ArrayRef(CE->getArgs(), CE->getNumArgs());
1097*700637cbSDimitry Andric auto NonNullArgs = collectNonNullArgs(F->getDecl(), Args);
1098*700637cbSDimitry Andric unsigned Offset = 0;
1099*700637cbSDimitry Andric unsigned Index = 0;
1100*700637cbSDimitry Andric for (const Expr *Arg : Args) {
1101*700637cbSDimitry Andric if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
1102*700637cbSDimitry Andric const Pointer &ArgPtr = S.Stk.peek<Pointer>(ArgSize - Offset);
1103*700637cbSDimitry Andric if (ArgPtr.isZero()) {
1104*700637cbSDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC);
1105*700637cbSDimitry Andric S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
1106*700637cbSDimitry Andric return false;
1107*700637cbSDimitry Andric }
1108*700637cbSDimitry Andric }
1109*700637cbSDimitry Andric
1110*700637cbSDimitry Andric Offset += align(primSize(S.Ctx.classify(Arg).value_or(PT_Ptr)));
1111*700637cbSDimitry Andric ++Index;
1112*700637cbSDimitry Andric }
1113*700637cbSDimitry Andric return true;
1114*700637cbSDimitry Andric }
1115*700637cbSDimitry Andric
runRecordDestructor(InterpState & S,CodePtr OpPC,const Pointer & BasePtr,const Descriptor * Desc)1116*700637cbSDimitry Andric static bool runRecordDestructor(InterpState &S, CodePtr OpPC,
1117*700637cbSDimitry Andric const Pointer &BasePtr,
1118*700637cbSDimitry Andric const Descriptor *Desc) {
1119*700637cbSDimitry Andric assert(Desc->isRecord());
1120*700637cbSDimitry Andric const Record *R = Desc->ElemRecord;
1121*700637cbSDimitry Andric assert(R);
1122*700637cbSDimitry Andric
1123*700637cbSDimitry Andric if (Pointer::pointToSameBlock(BasePtr, S.Current->getThis()) &&
1124*700637cbSDimitry Andric S.Current->getFunction()->isDestructor()) {
1125*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
1126*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_double_destroy);
1127*700637cbSDimitry Andric return false;
1128*700637cbSDimitry Andric }
1129*700637cbSDimitry Andric
1130*700637cbSDimitry Andric // Destructor of this record.
1131*700637cbSDimitry Andric if (const CXXDestructorDecl *Dtor = R->getDestructor();
1132*700637cbSDimitry Andric Dtor && !Dtor->isTrivial()) {
1133*700637cbSDimitry Andric const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
1134*700637cbSDimitry Andric if (!DtorFunc)
1135*700637cbSDimitry Andric return false;
1136*700637cbSDimitry Andric
1137*700637cbSDimitry Andric S.Stk.push<Pointer>(BasePtr);
1138*700637cbSDimitry Andric if (!Call(S, OpPC, DtorFunc, 0))
1139*700637cbSDimitry Andric return false;
1140*700637cbSDimitry Andric }
1141*700637cbSDimitry Andric return true;
1142*700637cbSDimitry Andric }
1143*700637cbSDimitry Andric
RunDestructors(InterpState & S,CodePtr OpPC,const Block * B)1144*700637cbSDimitry Andric static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {
1145*700637cbSDimitry Andric assert(B);
1146*700637cbSDimitry Andric const Descriptor *Desc = B->getDescriptor();
1147*700637cbSDimitry Andric
1148*700637cbSDimitry Andric if (Desc->isPrimitive() || Desc->isPrimitiveArray())
1149*700637cbSDimitry Andric return true;
1150*700637cbSDimitry Andric
1151*700637cbSDimitry Andric assert(Desc->isRecord() || Desc->isCompositeArray());
1152*700637cbSDimitry Andric
1153*700637cbSDimitry Andric if (Desc->isCompositeArray()) {
1154*700637cbSDimitry Andric unsigned N = Desc->getNumElems();
1155*700637cbSDimitry Andric if (N == 0)
1156*700637cbSDimitry Andric return true;
1157*700637cbSDimitry Andric const Descriptor *ElemDesc = Desc->ElemDesc;
1158*700637cbSDimitry Andric assert(ElemDesc->isRecord());
1159*700637cbSDimitry Andric
1160*700637cbSDimitry Andric Pointer RP(const_cast<Block *>(B));
1161*700637cbSDimitry Andric for (int I = static_cast<int>(N) - 1; I >= 0; --I) {
1162*700637cbSDimitry Andric if (!runRecordDestructor(S, OpPC, RP.atIndex(I).narrow(), ElemDesc))
1163*700637cbSDimitry Andric return false;
1164*700637cbSDimitry Andric }
1165*700637cbSDimitry Andric return true;
1166*700637cbSDimitry Andric }
1167*700637cbSDimitry Andric
1168*700637cbSDimitry Andric assert(Desc->isRecord());
1169*700637cbSDimitry Andric return runRecordDestructor(S, OpPC, Pointer(const_cast<Block *>(B)), Desc);
1170*700637cbSDimitry Andric }
1171*700637cbSDimitry Andric
hasVirtualDestructor(QualType T)1172*700637cbSDimitry Andric static bool hasVirtualDestructor(QualType T) {
1173*700637cbSDimitry Andric if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
1174*700637cbSDimitry Andric if (const CXXDestructorDecl *DD = RD->getDestructor())
1175*700637cbSDimitry Andric return DD->isVirtual();
1176*700637cbSDimitry Andric return false;
1177*700637cbSDimitry Andric }
1178*700637cbSDimitry Andric
Free(InterpState & S,CodePtr OpPC,bool DeleteIsArrayForm,bool IsGlobalDelete)1179*700637cbSDimitry Andric bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
1180*700637cbSDimitry Andric bool IsGlobalDelete) {
1181*700637cbSDimitry Andric if (!CheckDynamicMemoryAllocation(S, OpPC))
1182*700637cbSDimitry Andric return false;
1183*700637cbSDimitry Andric
1184*700637cbSDimitry Andric DynamicAllocator &Allocator = S.getAllocator();
1185*700637cbSDimitry Andric
1186*700637cbSDimitry Andric const Expr *Source = nullptr;
1187*700637cbSDimitry Andric const Block *BlockToDelete = nullptr;
1188*700637cbSDimitry Andric {
1189*700637cbSDimitry Andric // Extra scope for this so the block doesn't have this pointer
1190*700637cbSDimitry Andric // pointing to it when we destroy it.
1191*700637cbSDimitry Andric Pointer Ptr = S.Stk.pop<Pointer>();
1192*700637cbSDimitry Andric
1193*700637cbSDimitry Andric // Deleteing nullptr is always fine.
1194*700637cbSDimitry Andric if (Ptr.isZero())
1195*700637cbSDimitry Andric return true;
1196*700637cbSDimitry Andric
1197*700637cbSDimitry Andric // Remove base casts.
1198*700637cbSDimitry Andric QualType InitialType = Ptr.getType();
1199*700637cbSDimitry Andric while (Ptr.isBaseClass())
1200*700637cbSDimitry Andric Ptr = Ptr.getBase();
1201*700637cbSDimitry Andric
1202*700637cbSDimitry Andric Source = Ptr.getDeclDesc()->asExpr();
1203*700637cbSDimitry Andric BlockToDelete = Ptr.block();
1204*700637cbSDimitry Andric
1205*700637cbSDimitry Andric // Check that new[]/delete[] or new/delete were used, not a mixture.
1206*700637cbSDimitry Andric const Descriptor *BlockDesc = BlockToDelete->getDescriptor();
1207*700637cbSDimitry Andric if (std::optional<DynamicAllocator::Form> AllocForm =
1208*700637cbSDimitry Andric Allocator.getAllocationForm(Source)) {
1209*700637cbSDimitry Andric DynamicAllocator::Form DeleteForm =
1210*700637cbSDimitry Andric DeleteIsArrayForm ? DynamicAllocator::Form::Array
1211*700637cbSDimitry Andric : DynamicAllocator::Form::NonArray;
1212*700637cbSDimitry Andric if (!CheckNewDeleteForms(S, OpPC, *AllocForm, DeleteForm, BlockDesc,
1213*700637cbSDimitry Andric Source))
1214*700637cbSDimitry Andric return false;
1215*700637cbSDimitry Andric }
1216*700637cbSDimitry Andric
1217*700637cbSDimitry Andric // For the non-array case, the types must match if the static type
1218*700637cbSDimitry Andric // does not have a virtual destructor.
1219*700637cbSDimitry Andric if (!DeleteIsArrayForm && Ptr.getType() != InitialType &&
1220*700637cbSDimitry Andric !hasVirtualDestructor(InitialType)) {
1221*700637cbSDimitry Andric S.FFDiag(S.Current->getSource(OpPC),
1222*700637cbSDimitry Andric diag::note_constexpr_delete_base_nonvirt_dtor)
1223*700637cbSDimitry Andric << InitialType << Ptr.getType();
1224*700637cbSDimitry Andric return false;
1225*700637cbSDimitry Andric }
1226*700637cbSDimitry Andric
1227*700637cbSDimitry Andric if (!Ptr.isRoot() || Ptr.isOnePastEnd() ||
1228*700637cbSDimitry Andric (Ptr.isArrayElement() && Ptr.getIndex() != 0)) {
1229*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
1230*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
1231*700637cbSDimitry Andric << Ptr.toDiagnosticString(S.getASTContext()) << Ptr.isOnePastEnd();
1232*700637cbSDimitry Andric return false;
1233*700637cbSDimitry Andric }
1234*700637cbSDimitry Andric
1235*700637cbSDimitry Andric if (!CheckDeleteSource(S, OpPC, Source, Ptr))
1236*700637cbSDimitry Andric return false;
1237*700637cbSDimitry Andric
1238*700637cbSDimitry Andric // For a class type with a virtual destructor, the selected operator delete
1239*700637cbSDimitry Andric // is the one looked up when building the destructor.
1240*700637cbSDimitry Andric if (!DeleteIsArrayForm && !IsGlobalDelete) {
1241*700637cbSDimitry Andric QualType AllocType = Ptr.getType();
1242*700637cbSDimitry Andric auto getVirtualOperatorDelete = [](QualType T) -> const FunctionDecl * {
1243*700637cbSDimitry Andric if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
1244*700637cbSDimitry Andric if (const CXXDestructorDecl *DD = RD->getDestructor())
1245*700637cbSDimitry Andric return DD->isVirtual() ? DD->getOperatorDelete() : nullptr;
1246*700637cbSDimitry Andric return nullptr;
1247*700637cbSDimitry Andric };
1248*700637cbSDimitry Andric
1249*700637cbSDimitry Andric if (const FunctionDecl *VirtualDelete =
1250*700637cbSDimitry Andric getVirtualOperatorDelete(AllocType);
1251*700637cbSDimitry Andric VirtualDelete &&
1252*700637cbSDimitry Andric !VirtualDelete
1253*700637cbSDimitry Andric ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
1254*700637cbSDimitry Andric S.FFDiag(S.Current->getSource(OpPC),
1255*700637cbSDimitry Andric diag::note_constexpr_new_non_replaceable)
1256*700637cbSDimitry Andric << isa<CXXMethodDecl>(VirtualDelete) << VirtualDelete;
1257*700637cbSDimitry Andric return false;
1258*700637cbSDimitry Andric }
1259*700637cbSDimitry Andric }
1260*700637cbSDimitry Andric }
1261*700637cbSDimitry Andric assert(Source);
1262*700637cbSDimitry Andric assert(BlockToDelete);
1263*700637cbSDimitry Andric
1264*700637cbSDimitry Andric // Invoke destructors before deallocating the memory.
1265*700637cbSDimitry Andric if (!RunDestructors(S, OpPC, BlockToDelete))
1266*700637cbSDimitry Andric return false;
1267*700637cbSDimitry Andric
1268*700637cbSDimitry Andric if (!Allocator.deallocate(Source, BlockToDelete, S)) {
1269*700637cbSDimitry Andric // Nothing has been deallocated, this must be a double-delete.
1270*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
1271*700637cbSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_double_delete);
1272*700637cbSDimitry Andric return false;
1273*700637cbSDimitry Andric }
1274*700637cbSDimitry Andric
1275*700637cbSDimitry Andric return true;
1276*700637cbSDimitry Andric }
1277*700637cbSDimitry Andric
diagnoseEnumValue(InterpState & S,CodePtr OpPC,const EnumDecl * ED,const APSInt & Value)1278*700637cbSDimitry Andric void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,
1279*700637cbSDimitry Andric const APSInt &Value) {
1280*700637cbSDimitry Andric if (S.EvaluatingDecl && !S.EvaluatingDecl->isConstexpr())
1281*700637cbSDimitry Andric return;
1282*700637cbSDimitry Andric
1283*700637cbSDimitry Andric llvm::APInt Min;
1284*700637cbSDimitry Andric llvm::APInt Max;
1285*700637cbSDimitry Andric ED->getValueRange(Max, Min);
1286*700637cbSDimitry Andric --Max;
1287*700637cbSDimitry Andric
1288*700637cbSDimitry Andric if (ED->getNumNegativeBits() &&
1289*700637cbSDimitry Andric (Max.slt(Value.getSExtValue()) || Min.sgt(Value.getSExtValue()))) {
1290*700637cbSDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC);
1291*700637cbSDimitry Andric S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1292*700637cbSDimitry Andric << llvm::toString(Value, 10) << Min.getSExtValue() << Max.getSExtValue()
1293*700637cbSDimitry Andric << ED;
1294*700637cbSDimitry Andric } else if (!ED->getNumNegativeBits() && Max.ult(Value.getZExtValue())) {
1295*700637cbSDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC);
1296*700637cbSDimitry Andric S.CCEDiag(Loc, diag::note_constexpr_unscoped_enum_out_of_range)
1297*700637cbSDimitry Andric << llvm::toString(Value, 10) << Min.getZExtValue() << Max.getZExtValue()
1298*700637cbSDimitry Andric << ED;
1299*700637cbSDimitry Andric }
1300*700637cbSDimitry Andric }
1301*700637cbSDimitry Andric
CheckLiteralType(InterpState & S,CodePtr OpPC,const Type * T)1302*700637cbSDimitry Andric bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) {
1303*700637cbSDimitry Andric assert(T);
1304*700637cbSDimitry Andric assert(!S.getLangOpts().CPlusPlus23);
1305*700637cbSDimitry Andric
1306*700637cbSDimitry Andric // C++1y: A constant initializer for an object o [...] may also invoke
1307*700637cbSDimitry Andric // constexpr constructors for o and its subobjects even if those objects
1308*700637cbSDimitry Andric // are of non-literal class types.
1309*700637cbSDimitry Andric //
1310*700637cbSDimitry Andric // C++11 missed this detail for aggregates, so classes like this:
1311*700637cbSDimitry Andric // struct foo_t { union { int i; volatile int j; } u; };
1312*700637cbSDimitry Andric // are not (obviously) initializable like so:
1313*700637cbSDimitry Andric // __attribute__((__require_constant_initialization__))
1314*700637cbSDimitry Andric // static const foo_t x = {{0}};
1315*700637cbSDimitry Andric // because "i" is a subobject with non-literal initialization (due to the
1316*700637cbSDimitry Andric // volatile member of the union). See:
1317*700637cbSDimitry Andric // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677
1318*700637cbSDimitry Andric // Therefore, we use the C++1y behavior.
1319*700637cbSDimitry Andric
1320*700637cbSDimitry Andric if (S.Current->getFunction() && S.Current->getFunction()->isConstructor() &&
1321*700637cbSDimitry Andric S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl) {
1322*700637cbSDimitry Andric return true;
1323*700637cbSDimitry Andric }
1324*700637cbSDimitry Andric
1325*700637cbSDimitry Andric const Expr *E = S.Current->getExpr(OpPC);
1326*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus11)
1327*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType();
1328*700637cbSDimitry Andric else
1329*700637cbSDimitry Andric S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
1330*700637cbSDimitry Andric return false;
1331*700637cbSDimitry Andric }
1332*700637cbSDimitry Andric
getField(InterpState & S,CodePtr OpPC,const Pointer & Ptr,uint32_t Off)1333*700637cbSDimitry Andric static bool getField(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
1334*700637cbSDimitry Andric uint32_t Off) {
1335*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&
1336*700637cbSDimitry Andric !CheckNull(S, OpPC, Ptr, CSK_Field))
1337*700637cbSDimitry Andric return false;
1338*700637cbSDimitry Andric
1339*700637cbSDimitry Andric if (!CheckRange(S, OpPC, Ptr, CSK_Field))
1340*700637cbSDimitry Andric return false;
1341*700637cbSDimitry Andric if (!CheckArray(S, OpPC, Ptr))
1342*700637cbSDimitry Andric return false;
1343*700637cbSDimitry Andric if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))
1344*700637cbSDimitry Andric return false;
1345*700637cbSDimitry Andric
1346*700637cbSDimitry Andric if (Ptr.isIntegralPointer()) {
1347*700637cbSDimitry Andric S.Stk.push<Pointer>(Ptr.asIntPointer().atOffset(S.getASTContext(), Off));
1348*700637cbSDimitry Andric return true;
1349*700637cbSDimitry Andric }
1350*700637cbSDimitry Andric
1351*700637cbSDimitry Andric if (!Ptr.isBlockPointer()) {
1352*700637cbSDimitry Andric // FIXME: The only time we (seem to) get here is when trying to access a
1353*700637cbSDimitry Andric // field of a typeid pointer. In that case, we're supposed to diagnose e.g.
1354*700637cbSDimitry Andric // `typeid(int).name`, but we currently diagnose `&typeid(int)`.
1355*700637cbSDimitry Andric S.FFDiag(S.Current->getSource(OpPC),
1356*700637cbSDimitry Andric diag::note_constexpr_access_unreadable_object)
1357*700637cbSDimitry Andric << AK_Read << Ptr.toDiagnosticString(S.getASTContext());
1358*700637cbSDimitry Andric return false;
1359*700637cbSDimitry Andric }
1360*700637cbSDimitry Andric
1361*700637cbSDimitry Andric if ((Ptr.getByteOffset() + Off) >= Ptr.block()->getSize())
1362*700637cbSDimitry Andric return false;
1363*700637cbSDimitry Andric
1364*700637cbSDimitry Andric S.Stk.push<Pointer>(Ptr.atField(Off));
1365*700637cbSDimitry Andric return true;
1366*700637cbSDimitry Andric }
1367*700637cbSDimitry Andric
GetPtrField(InterpState & S,CodePtr OpPC,uint32_t Off)1368*700637cbSDimitry Andric bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
1369*700637cbSDimitry Andric const auto &Ptr = S.Stk.peek<Pointer>();
1370*700637cbSDimitry Andric return getField(S, OpPC, Ptr, Off);
1371*700637cbSDimitry Andric }
1372*700637cbSDimitry Andric
GetPtrFieldPop(InterpState & S,CodePtr OpPC,uint32_t Off)1373*700637cbSDimitry Andric bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {
1374*700637cbSDimitry Andric const auto &Ptr = S.Stk.pop<Pointer>();
1375*700637cbSDimitry Andric return getField(S, OpPC, Ptr, Off);
1376*700637cbSDimitry Andric }
1377*700637cbSDimitry Andric
checkConstructor(InterpState & S,CodePtr OpPC,const Function * Func,const Pointer & ThisPtr)1378*700637cbSDimitry Andric static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func,
1379*700637cbSDimitry Andric const Pointer &ThisPtr) {
1380*700637cbSDimitry Andric assert(Func->isConstructor());
1381*700637cbSDimitry Andric
1382*700637cbSDimitry Andric if (Func->getParentDecl()->isInvalidDecl())
1383*700637cbSDimitry Andric return false;
1384*700637cbSDimitry Andric
1385*700637cbSDimitry Andric const Descriptor *D = ThisPtr.getFieldDesc();
1386*700637cbSDimitry Andric // FIXME: I think this case is not 100% correct. E.g. a pointer into a
1387*700637cbSDimitry Andric // subobject of a composite array.
1388*700637cbSDimitry Andric if (!D->ElemRecord)
1389*700637cbSDimitry Andric return true;
1390*700637cbSDimitry Andric
1391*700637cbSDimitry Andric if (D->ElemRecord->getNumVirtualBases() == 0)
1392*700637cbSDimitry Andric return true;
1393*700637cbSDimitry Andric
1394*700637cbSDimitry Andric S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_virtual_base)
1395*700637cbSDimitry Andric << Func->getParentDecl();
1396*700637cbSDimitry Andric return false;
1397*700637cbSDimitry Andric }
1398*700637cbSDimitry Andric
CheckDestructor(InterpState & S,CodePtr OpPC,const Pointer & Ptr)1399*700637cbSDimitry Andric bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
1400*700637cbSDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_Destroy))
1401*700637cbSDimitry Andric return false;
1402*700637cbSDimitry Andric if (!CheckTemporary(S, OpPC, Ptr, AK_Destroy))
1403*700637cbSDimitry Andric return false;
1404*700637cbSDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_Destroy))
1405*700637cbSDimitry Andric return false;
1406*700637cbSDimitry Andric
1407*700637cbSDimitry Andric // Can't call a dtor on a global variable.
1408*700637cbSDimitry Andric if (Ptr.block()->isStatic()) {
1409*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
1410*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_modify_global);
1411*700637cbSDimitry Andric return false;
1412*700637cbSDimitry Andric }
1413*700637cbSDimitry Andric return CheckActive(S, OpPC, Ptr, AK_Destroy);
1414*700637cbSDimitry Andric }
1415*700637cbSDimitry Andric
compileFunction(InterpState & S,const Function * Func)1416*700637cbSDimitry Andric static void compileFunction(InterpState &S, const Function *Func) {
1417*700637cbSDimitry Andric Compiler<ByteCodeEmitter>(S.getContext(), S.P)
1418*700637cbSDimitry Andric .compileFunc(Func->getDecl()->getMostRecentDecl(),
1419*700637cbSDimitry Andric const_cast<Function *>(Func));
1420*700637cbSDimitry Andric }
1421*700637cbSDimitry Andric
CallVar(InterpState & S,CodePtr OpPC,const Function * Func,uint32_t VarArgSize)1422*700637cbSDimitry Andric bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
1423*700637cbSDimitry Andric uint32_t VarArgSize) {
1424*700637cbSDimitry Andric if (Func->hasThisPointer()) {
1425*700637cbSDimitry Andric size_t ArgSize = Func->getArgSize() + VarArgSize;
1426*700637cbSDimitry Andric size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1427*700637cbSDimitry Andric const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1428*700637cbSDimitry Andric
1429*700637cbSDimitry Andric // If the current function is a lambda static invoker and
1430*700637cbSDimitry Andric // the function we're about to call is a lambda call operator,
1431*700637cbSDimitry Andric // skip the CheckInvoke, since the ThisPtr is a null pointer
1432*700637cbSDimitry Andric // anyway.
1433*700637cbSDimitry Andric if (!(S.Current->getFunction() &&
1434*700637cbSDimitry Andric S.Current->getFunction()->isLambdaStaticInvoker() &&
1435*700637cbSDimitry Andric Func->isLambdaCallOperator())) {
1436*700637cbSDimitry Andric if (!CheckInvoke(S, OpPC, ThisPtr))
1437*700637cbSDimitry Andric return false;
1438*700637cbSDimitry Andric }
1439*700637cbSDimitry Andric
1440*700637cbSDimitry Andric if (S.checkingPotentialConstantExpression())
1441*700637cbSDimitry Andric return false;
1442*700637cbSDimitry Andric }
1443*700637cbSDimitry Andric
1444*700637cbSDimitry Andric if (!Func->isFullyCompiled())
1445*700637cbSDimitry Andric compileFunction(S, Func);
1446*700637cbSDimitry Andric
1447*700637cbSDimitry Andric if (!CheckCallable(S, OpPC, Func))
1448*700637cbSDimitry Andric return false;
1449*700637cbSDimitry Andric
1450*700637cbSDimitry Andric if (!CheckCallDepth(S, OpPC))
1451*700637cbSDimitry Andric return false;
1452*700637cbSDimitry Andric
1453*700637cbSDimitry Andric auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
1454*700637cbSDimitry Andric InterpFrame *FrameBefore = S.Current;
1455*700637cbSDimitry Andric S.Current = NewFrame.get();
1456*700637cbSDimitry Andric
1457*700637cbSDimitry Andric // Note that we cannot assert(CallResult.hasValue()) here since
1458*700637cbSDimitry Andric // Ret() above only sets the APValue if the curent frame doesn't
1459*700637cbSDimitry Andric // have a caller set.
1460*700637cbSDimitry Andric if (Interpret(S)) {
1461*700637cbSDimitry Andric NewFrame.release(); // Frame was delete'd already.
1462*700637cbSDimitry Andric assert(S.Current == FrameBefore);
1463*700637cbSDimitry Andric return true;
1464*700637cbSDimitry Andric }
1465*700637cbSDimitry Andric
1466*700637cbSDimitry Andric // Interpreting the function failed somehow. Reset to
1467*700637cbSDimitry Andric // previous state.
1468*700637cbSDimitry Andric S.Current = FrameBefore;
1469*700637cbSDimitry Andric return false;
1470*700637cbSDimitry Andric }
Call(InterpState & S,CodePtr OpPC,const Function * Func,uint32_t VarArgSize)1471*700637cbSDimitry Andric bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
1472*700637cbSDimitry Andric uint32_t VarArgSize) {
1473*700637cbSDimitry Andric assert(Func);
1474*700637cbSDimitry Andric auto cleanup = [&]() -> bool {
1475*700637cbSDimitry Andric cleanupAfterFunctionCall(S, OpPC, Func);
1476*700637cbSDimitry Andric return false;
1477*700637cbSDimitry Andric };
1478*700637cbSDimitry Andric
1479*700637cbSDimitry Andric if (Func->hasThisPointer()) {
1480*700637cbSDimitry Andric size_t ArgSize = Func->getArgSize() + VarArgSize;
1481*700637cbSDimitry Andric size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1482*700637cbSDimitry Andric
1483*700637cbSDimitry Andric const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1484*700637cbSDimitry Andric
1485*700637cbSDimitry Andric // C++23 [expr.const]p5.6
1486*700637cbSDimitry Andric // an invocation of a virtual function ([class.virtual]) for an object whose
1487*700637cbSDimitry Andric // dynamic type is constexpr-unknown;
1488*700637cbSDimitry Andric if (ThisPtr.isDummy() && Func->isVirtual())
1489*700637cbSDimitry Andric return false;
1490*700637cbSDimitry Andric
1491*700637cbSDimitry Andric // If the current function is a lambda static invoker and
1492*700637cbSDimitry Andric // the function we're about to call is a lambda call operator,
1493*700637cbSDimitry Andric // skip the CheckInvoke, since the ThisPtr is a null pointer
1494*700637cbSDimitry Andric // anyway.
1495*700637cbSDimitry Andric if (S.Current->getFunction() &&
1496*700637cbSDimitry Andric S.Current->getFunction()->isLambdaStaticInvoker() &&
1497*700637cbSDimitry Andric Func->isLambdaCallOperator()) {
1498*700637cbSDimitry Andric assert(ThisPtr.isZero());
1499*700637cbSDimitry Andric } else {
1500*700637cbSDimitry Andric if (!CheckInvoke(S, OpPC, ThisPtr))
1501*700637cbSDimitry Andric return cleanup();
1502*700637cbSDimitry Andric if (!Func->isConstructor() && !Func->isDestructor() &&
1503*700637cbSDimitry Andric !Func->isCopyOrMoveOperator() &&
1504*700637cbSDimitry Andric !CheckActive(S, OpPC, ThisPtr, AK_MemberCall))
1505*700637cbSDimitry Andric return false;
1506*700637cbSDimitry Andric }
1507*700637cbSDimitry Andric
1508*700637cbSDimitry Andric if (Func->isConstructor() && !checkConstructor(S, OpPC, Func, ThisPtr))
1509*700637cbSDimitry Andric return false;
1510*700637cbSDimitry Andric if (Func->isDestructor() && !CheckDestructor(S, OpPC, ThisPtr))
1511*700637cbSDimitry Andric return false;
1512*700637cbSDimitry Andric
1513*700637cbSDimitry Andric if (Func->isConstructor() || Func->isDestructor())
1514*700637cbSDimitry Andric S.InitializingBlocks.push_back(ThisPtr.block());
1515*700637cbSDimitry Andric }
1516*700637cbSDimitry Andric
1517*700637cbSDimitry Andric if (!Func->isFullyCompiled())
1518*700637cbSDimitry Andric compileFunction(S, Func);
1519*700637cbSDimitry Andric
1520*700637cbSDimitry Andric if (!CheckCallable(S, OpPC, Func))
1521*700637cbSDimitry Andric return cleanup();
1522*700637cbSDimitry Andric
1523*700637cbSDimitry Andric // FIXME: The isConstructor() check here is not always right. The current
1524*700637cbSDimitry Andric // constant evaluator is somewhat inconsistent in when it allows a function
1525*700637cbSDimitry Andric // call when checking for a constant expression.
1526*700637cbSDimitry Andric if (Func->hasThisPointer() && S.checkingPotentialConstantExpression() &&
1527*700637cbSDimitry Andric !Func->isConstructor())
1528*700637cbSDimitry Andric return cleanup();
1529*700637cbSDimitry Andric
1530*700637cbSDimitry Andric if (!CheckCallDepth(S, OpPC))
1531*700637cbSDimitry Andric return cleanup();
1532*700637cbSDimitry Andric
1533*700637cbSDimitry Andric auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
1534*700637cbSDimitry Andric InterpFrame *FrameBefore = S.Current;
1535*700637cbSDimitry Andric S.Current = NewFrame.get();
1536*700637cbSDimitry Andric
1537*700637cbSDimitry Andric InterpStateCCOverride CCOverride(S, Func->isImmediate());
1538*700637cbSDimitry Andric // Note that we cannot assert(CallResult.hasValue()) here since
1539*700637cbSDimitry Andric // Ret() above only sets the APValue if the curent frame doesn't
1540*700637cbSDimitry Andric // have a caller set.
1541*700637cbSDimitry Andric bool Success = Interpret(S);
1542*700637cbSDimitry Andric // Remove initializing block again.
1543*700637cbSDimitry Andric if (Func->isConstructor() || Func->isDestructor())
1544*700637cbSDimitry Andric S.InitializingBlocks.pop_back();
1545*700637cbSDimitry Andric
1546*700637cbSDimitry Andric if (!Success) {
1547*700637cbSDimitry Andric // Interpreting the function failed somehow. Reset to
1548*700637cbSDimitry Andric // previous state.
1549*700637cbSDimitry Andric S.Current = FrameBefore;
1550*700637cbSDimitry Andric return false;
1551*700637cbSDimitry Andric }
1552*700637cbSDimitry Andric
1553*700637cbSDimitry Andric NewFrame.release(); // Frame was delete'd already.
1554*700637cbSDimitry Andric assert(S.Current == FrameBefore);
1555*700637cbSDimitry Andric return true;
1556*700637cbSDimitry Andric }
1557*700637cbSDimitry Andric
CallVirt(InterpState & S,CodePtr OpPC,const Function * Func,uint32_t VarArgSize)1558*700637cbSDimitry Andric bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
1559*700637cbSDimitry Andric uint32_t VarArgSize) {
1560*700637cbSDimitry Andric assert(Func->hasThisPointer());
1561*700637cbSDimitry Andric assert(Func->isVirtual());
1562*700637cbSDimitry Andric size_t ArgSize = Func->getArgSize() + VarArgSize;
1563*700637cbSDimitry Andric size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
1564*700637cbSDimitry Andric Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);
1565*700637cbSDimitry Andric const FunctionDecl *Callee = Func->getDecl();
1566*700637cbSDimitry Andric
1567*700637cbSDimitry Andric if (!Func->isFullyCompiled())
1568*700637cbSDimitry Andric compileFunction(S, Func);
1569*700637cbSDimitry Andric
1570*700637cbSDimitry Andric // C++2a [class.abstract]p6:
1571*700637cbSDimitry Andric // the effect of making a virtual call to a pure virtual function [...] is
1572*700637cbSDimitry Andric // undefined
1573*700637cbSDimitry Andric if (Callee->isPureVirtual()) {
1574*700637cbSDimitry Andric S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_pure_virtual_call,
1575*700637cbSDimitry Andric 1)
1576*700637cbSDimitry Andric << Callee;
1577*700637cbSDimitry Andric S.Note(Callee->getLocation(), diag::note_declared_at);
1578*700637cbSDimitry Andric return false;
1579*700637cbSDimitry Andric }
1580*700637cbSDimitry Andric
1581*700637cbSDimitry Andric const CXXRecordDecl *DynamicDecl = nullptr;
1582*700637cbSDimitry Andric {
1583*700637cbSDimitry Andric Pointer TypePtr = ThisPtr;
1584*700637cbSDimitry Andric while (TypePtr.isBaseClass())
1585*700637cbSDimitry Andric TypePtr = TypePtr.getBase();
1586*700637cbSDimitry Andric
1587*700637cbSDimitry Andric QualType DynamicType = TypePtr.getType();
1588*700637cbSDimitry Andric if (DynamicType->isPointerType() || DynamicType->isReferenceType())
1589*700637cbSDimitry Andric DynamicDecl = DynamicType->getPointeeCXXRecordDecl();
1590*700637cbSDimitry Andric else
1591*700637cbSDimitry Andric DynamicDecl = DynamicType->getAsCXXRecordDecl();
1592*700637cbSDimitry Andric }
1593*700637cbSDimitry Andric assert(DynamicDecl);
1594*700637cbSDimitry Andric
1595*700637cbSDimitry Andric const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
1596*700637cbSDimitry Andric const auto *InitialFunction = cast<CXXMethodDecl>(Callee);
1597*700637cbSDimitry Andric const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
1598*700637cbSDimitry Andric DynamicDecl, StaticDecl, InitialFunction);
1599*700637cbSDimitry Andric
1600*700637cbSDimitry Andric if (Overrider != InitialFunction) {
1601*700637cbSDimitry Andric // DR1872: An instantiated virtual constexpr function can't be called in a
1602*700637cbSDimitry Andric // constant expression (prior to C++20). We can still constant-fold such a
1603*700637cbSDimitry Andric // call.
1604*700637cbSDimitry Andric if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {
1605*700637cbSDimitry Andric const Expr *E = S.Current->getExpr(OpPC);
1606*700637cbSDimitry Andric S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();
1607*700637cbSDimitry Andric }
1608*700637cbSDimitry Andric
1609*700637cbSDimitry Andric Func = S.getContext().getOrCreateFunction(Overrider);
1610*700637cbSDimitry Andric
1611*700637cbSDimitry Andric const CXXRecordDecl *ThisFieldDecl =
1612*700637cbSDimitry Andric ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();
1613*700637cbSDimitry Andric if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {
1614*700637cbSDimitry Andric // If the function we call is further DOWN the hierarchy than the
1615*700637cbSDimitry Andric // FieldDesc of our pointer, just go up the hierarchy of this field
1616*700637cbSDimitry Andric // the furthest we can go.
1617*700637cbSDimitry Andric while (ThisPtr.isBaseClass())
1618*700637cbSDimitry Andric ThisPtr = ThisPtr.getBase();
1619*700637cbSDimitry Andric }
1620*700637cbSDimitry Andric }
1621*700637cbSDimitry Andric
1622*700637cbSDimitry Andric if (!Call(S, OpPC, Func, VarArgSize))
1623*700637cbSDimitry Andric return false;
1624*700637cbSDimitry Andric
1625*700637cbSDimitry Andric // Covariant return types. The return type of Overrider is a pointer
1626*700637cbSDimitry Andric // or reference to a class type.
1627*700637cbSDimitry Andric if (Overrider != InitialFunction &&
1628*700637cbSDimitry Andric Overrider->getReturnType()->isPointerOrReferenceType() &&
1629*700637cbSDimitry Andric InitialFunction->getReturnType()->isPointerOrReferenceType()) {
1630*700637cbSDimitry Andric QualType OverriderPointeeType =
1631*700637cbSDimitry Andric Overrider->getReturnType()->getPointeeType();
1632*700637cbSDimitry Andric QualType InitialPointeeType =
1633*700637cbSDimitry Andric InitialFunction->getReturnType()->getPointeeType();
1634*700637cbSDimitry Andric // We've called Overrider above, but calling code expects us to return what
1635*700637cbSDimitry Andric // InitialFunction returned. According to the rules for covariant return
1636*700637cbSDimitry Andric // types, what InitialFunction returns needs to be a base class of what
1637*700637cbSDimitry Andric // Overrider returns. So, we need to do an upcast here.
1638*700637cbSDimitry Andric unsigned Offset = S.getContext().collectBaseOffset(
1639*700637cbSDimitry Andric InitialPointeeType->getAsRecordDecl(),
1640*700637cbSDimitry Andric OverriderPointeeType->getAsRecordDecl());
1641*700637cbSDimitry Andric return GetPtrBasePop(S, OpPC, Offset, /*IsNullOK=*/true);
1642*700637cbSDimitry Andric }
1643*700637cbSDimitry Andric
1644*700637cbSDimitry Andric return true;
1645*700637cbSDimitry Andric }
1646*700637cbSDimitry Andric
CallBI(InterpState & S,CodePtr OpPC,const CallExpr * CE,uint32_t BuiltinID)1647*700637cbSDimitry Andric bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE,
1648*700637cbSDimitry Andric uint32_t BuiltinID) {
1649*700637cbSDimitry Andric // A little arbitrary, but the current interpreter allows evaluation
1650*700637cbSDimitry Andric // of builtin functions in this mode, with some exceptions.
1651*700637cbSDimitry Andric if (BuiltinID == Builtin::BI__builtin_operator_new &&
1652*700637cbSDimitry Andric S.checkingPotentialConstantExpression())
1653*700637cbSDimitry Andric return false;
1654*700637cbSDimitry Andric
1655*700637cbSDimitry Andric return InterpretBuiltin(S, OpPC, CE, BuiltinID);
1656*700637cbSDimitry Andric }
1657*700637cbSDimitry Andric
CallPtr(InterpState & S,CodePtr OpPC,uint32_t ArgSize,const CallExpr * CE)1658*700637cbSDimitry Andric bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
1659*700637cbSDimitry Andric const CallExpr *CE) {
1660*700637cbSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>();
1661*700637cbSDimitry Andric
1662*700637cbSDimitry Andric if (Ptr.isZero()) {
1663*700637cbSDimitry Andric const auto *E = cast<CallExpr>(S.Current->getExpr(OpPC));
1664*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_null_callee)
1665*700637cbSDimitry Andric << const_cast<Expr *>(E->getCallee()) << E->getSourceRange();
1666*700637cbSDimitry Andric return false;
1667*700637cbSDimitry Andric }
1668*700637cbSDimitry Andric
1669*700637cbSDimitry Andric if (!Ptr.isFunctionPointer())
1670*700637cbSDimitry Andric return Invalid(S, OpPC);
1671*700637cbSDimitry Andric
1672*700637cbSDimitry Andric const FunctionPointer &FuncPtr = Ptr.asFunctionPointer();
1673*700637cbSDimitry Andric const Function *F = FuncPtr.getFunction();
1674*700637cbSDimitry Andric assert(F);
1675*700637cbSDimitry Andric // Don't allow calling block pointers.
1676*700637cbSDimitry Andric if (!F->getDecl())
1677*700637cbSDimitry Andric return Invalid(S, OpPC);
1678*700637cbSDimitry Andric
1679*700637cbSDimitry Andric // This happens when the call expression has been cast to
1680*700637cbSDimitry Andric // something else, but we don't support that.
1681*700637cbSDimitry Andric if (S.Ctx.classify(F->getDecl()->getReturnType()) !=
1682*700637cbSDimitry Andric S.Ctx.classify(CE->getCallReturnType(S.getASTContext())))
1683*700637cbSDimitry Andric return false;
1684*700637cbSDimitry Andric
1685*700637cbSDimitry Andric // Check argument nullability state.
1686*700637cbSDimitry Andric if (F->hasNonNullAttr()) {
1687*700637cbSDimitry Andric if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
1688*700637cbSDimitry Andric return false;
1689*700637cbSDimitry Andric }
1690*700637cbSDimitry Andric
1691*700637cbSDimitry Andric assert(ArgSize >= F->getWrittenArgSize());
1692*700637cbSDimitry Andric uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();
1693*700637cbSDimitry Andric
1694*700637cbSDimitry Andric // We need to do this explicitly here since we don't have the necessary
1695*700637cbSDimitry Andric // information to do it automatically.
1696*700637cbSDimitry Andric if (F->isThisPointerExplicit())
1697*700637cbSDimitry Andric VarArgSize -= align(primSize(PT_Ptr));
1698*700637cbSDimitry Andric
1699*700637cbSDimitry Andric if (F->isVirtual())
1700*700637cbSDimitry Andric return CallVirt(S, OpPC, F, VarArgSize);
1701*700637cbSDimitry Andric
1702*700637cbSDimitry Andric return Call(S, OpPC, F, VarArgSize);
1703*700637cbSDimitry Andric }
1704*700637cbSDimitry Andric
startLifetimeRecurse(const Pointer & Ptr)1705*700637cbSDimitry Andric static void startLifetimeRecurse(const Pointer &Ptr) {
1706*700637cbSDimitry Andric if (const Record *R = Ptr.getRecord()) {
1707*700637cbSDimitry Andric Ptr.startLifetime();
1708*700637cbSDimitry Andric for (const Record::Field &Fi : R->fields())
1709*700637cbSDimitry Andric startLifetimeRecurse(Ptr.atField(Fi.Offset));
1710*700637cbSDimitry Andric return;
1711*700637cbSDimitry Andric }
1712*700637cbSDimitry Andric
1713*700637cbSDimitry Andric if (const Descriptor *FieldDesc = Ptr.getFieldDesc();
1714*700637cbSDimitry Andric FieldDesc->isCompositeArray()) {
1715*700637cbSDimitry Andric assert(Ptr.getLifetime() == Lifetime::Started);
1716*700637cbSDimitry Andric for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I)
1717*700637cbSDimitry Andric startLifetimeRecurse(Ptr.atIndex(I).narrow());
1718*700637cbSDimitry Andric return;
1719*700637cbSDimitry Andric }
1720*700637cbSDimitry Andric
1721*700637cbSDimitry Andric Ptr.startLifetime();
1722*700637cbSDimitry Andric }
1723*700637cbSDimitry Andric
StartLifetime(InterpState & S,CodePtr OpPC)1724*700637cbSDimitry Andric bool StartLifetime(InterpState &S, CodePtr OpPC) {
1725*700637cbSDimitry Andric const auto &Ptr = S.Stk.peek<Pointer>();
1726*700637cbSDimitry Andric if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
1727*700637cbSDimitry Andric return false;
1728*700637cbSDimitry Andric startLifetimeRecurse(Ptr.narrow());
1729*700637cbSDimitry Andric return true;
1730*700637cbSDimitry Andric }
1731*700637cbSDimitry Andric
1732*700637cbSDimitry Andric // FIXME: It might be better to the recursing as part of the generated code for
1733*700637cbSDimitry Andric // a destructor?
endLifetimeRecurse(const Pointer & Ptr)1734*700637cbSDimitry Andric static void endLifetimeRecurse(const Pointer &Ptr) {
1735*700637cbSDimitry Andric if (const Record *R = Ptr.getRecord()) {
1736*700637cbSDimitry Andric Ptr.endLifetime();
1737*700637cbSDimitry Andric for (const Record::Field &Fi : R->fields())
1738*700637cbSDimitry Andric endLifetimeRecurse(Ptr.atField(Fi.Offset));
1739*700637cbSDimitry Andric return;
1740*700637cbSDimitry Andric }
1741*700637cbSDimitry Andric
1742*700637cbSDimitry Andric if (const Descriptor *FieldDesc = Ptr.getFieldDesc();
1743*700637cbSDimitry Andric FieldDesc->isCompositeArray()) {
1744*700637cbSDimitry Andric // No endLifetime() for array roots.
1745*700637cbSDimitry Andric assert(Ptr.getLifetime() == Lifetime::Started);
1746*700637cbSDimitry Andric for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I)
1747*700637cbSDimitry Andric endLifetimeRecurse(Ptr.atIndex(I).narrow());
1748*700637cbSDimitry Andric return;
1749*700637cbSDimitry Andric }
1750*700637cbSDimitry Andric
1751*700637cbSDimitry Andric Ptr.endLifetime();
1752*700637cbSDimitry Andric }
1753*700637cbSDimitry Andric
1754*700637cbSDimitry Andric /// Ends the lifetime of the peek'd pointer.
EndLifetime(InterpState & S,CodePtr OpPC)1755*700637cbSDimitry Andric bool EndLifetime(InterpState &S, CodePtr OpPC) {
1756*700637cbSDimitry Andric const auto &Ptr = S.Stk.peek<Pointer>();
1757*700637cbSDimitry Andric if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
1758*700637cbSDimitry Andric return false;
1759*700637cbSDimitry Andric endLifetimeRecurse(Ptr.narrow());
1760*700637cbSDimitry Andric return true;
1761*700637cbSDimitry Andric }
1762*700637cbSDimitry Andric
1763*700637cbSDimitry Andric /// Ends the lifetime of the pop'd pointer.
EndLifetimePop(InterpState & S,CodePtr OpPC)1764*700637cbSDimitry Andric bool EndLifetimePop(InterpState &S, CodePtr OpPC) {
1765*700637cbSDimitry Andric const auto &Ptr = S.Stk.pop<Pointer>();
1766*700637cbSDimitry Andric if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
1767*700637cbSDimitry Andric return false;
1768*700637cbSDimitry Andric endLifetimeRecurse(Ptr.narrow());
1769*700637cbSDimitry Andric return true;
1770*700637cbSDimitry Andric }
1771*700637cbSDimitry Andric
CheckNewTypeMismatch(InterpState & S,CodePtr OpPC,const Expr * E,std::optional<uint64_t> ArraySize)1772*700637cbSDimitry Andric bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
1773*700637cbSDimitry Andric std::optional<uint64_t> ArraySize) {
1774*700637cbSDimitry Andric const Pointer &Ptr = S.Stk.peek<Pointer>();
1775*700637cbSDimitry Andric
1776*700637cbSDimitry Andric // Similar to CheckStore(), but with the additional CheckTemporary() call and
1777*700637cbSDimitry Andric // the AccessKinds are different.
1778*700637cbSDimitry Andric if (!CheckTemporary(S, OpPC, Ptr, AK_Construct))
1779*700637cbSDimitry Andric return false;
1780*700637cbSDimitry Andric if (!CheckLive(S, OpPC, Ptr, AK_Construct))
1781*700637cbSDimitry Andric return false;
1782*700637cbSDimitry Andric if (!CheckDummy(S, OpPC, Ptr, AK_Construct))
1783*700637cbSDimitry Andric return false;
1784*700637cbSDimitry Andric
1785*700637cbSDimitry Andric // CheckLifetime for this and all base pointers.
1786*700637cbSDimitry Andric for (Pointer P = Ptr;;) {
1787*700637cbSDimitry Andric if (!CheckLifetime(S, OpPC, P, AK_Construct))
1788*700637cbSDimitry Andric return false;
1789*700637cbSDimitry Andric
1790*700637cbSDimitry Andric if (P.isRoot())
1791*700637cbSDimitry Andric break;
1792*700637cbSDimitry Andric P = P.getBase();
1793*700637cbSDimitry Andric }
1794*700637cbSDimitry Andric if (!CheckExtern(S, OpPC, Ptr))
1795*700637cbSDimitry Andric return false;
1796*700637cbSDimitry Andric if (!CheckRange(S, OpPC, Ptr, AK_Construct))
1797*700637cbSDimitry Andric return false;
1798*700637cbSDimitry Andric if (!CheckGlobal(S, OpPC, Ptr))
1799*700637cbSDimitry Andric return false;
1800*700637cbSDimitry Andric if (!CheckConst(S, OpPC, Ptr))
1801*700637cbSDimitry Andric return false;
1802*700637cbSDimitry Andric if (!S.inConstantContext() && isConstexprUnknown(Ptr))
1803*700637cbSDimitry Andric return false;
1804*700637cbSDimitry Andric
1805*700637cbSDimitry Andric if (!InvalidNewDeleteExpr(S, OpPC, E))
1806*700637cbSDimitry Andric return false;
1807*700637cbSDimitry Andric
1808*700637cbSDimitry Andric const auto *NewExpr = cast<CXXNewExpr>(E);
1809*700637cbSDimitry Andric QualType StorageType = Ptr.getFieldDesc()->getDataType(S.getASTContext());
1810*700637cbSDimitry Andric const ASTContext &ASTCtx = S.getASTContext();
1811*700637cbSDimitry Andric QualType AllocType;
1812*700637cbSDimitry Andric if (ArraySize) {
1813*700637cbSDimitry Andric AllocType = ASTCtx.getConstantArrayType(
1814*700637cbSDimitry Andric NewExpr->getAllocatedType(),
1815*700637cbSDimitry Andric APInt(64, static_cast<uint64_t>(*ArraySize), false), nullptr,
1816*700637cbSDimitry Andric ArraySizeModifier::Normal, 0);
1817*700637cbSDimitry Andric } else {
1818*700637cbSDimitry Andric AllocType = NewExpr->getAllocatedType();
1819*700637cbSDimitry Andric }
1820*700637cbSDimitry Andric
1821*700637cbSDimitry Andric unsigned StorageSize = 1;
1822*700637cbSDimitry Andric unsigned AllocSize = 1;
1823*700637cbSDimitry Andric if (const auto *CAT = dyn_cast<ConstantArrayType>(AllocType))
1824*700637cbSDimitry Andric AllocSize = CAT->getZExtSize();
1825*700637cbSDimitry Andric if (const auto *CAT = dyn_cast<ConstantArrayType>(StorageType))
1826*700637cbSDimitry Andric StorageSize = CAT->getZExtSize();
1827*700637cbSDimitry Andric
1828*700637cbSDimitry Andric if (AllocSize > StorageSize ||
1829*700637cbSDimitry Andric !ASTCtx.hasSimilarType(ASTCtx.getBaseElementType(AllocType),
1830*700637cbSDimitry Andric ASTCtx.getBaseElementType(StorageType))) {
1831*700637cbSDimitry Andric S.FFDiag(S.Current->getLocation(OpPC),
1832*700637cbSDimitry Andric diag::note_constexpr_placement_new_wrong_type)
1833*700637cbSDimitry Andric << StorageType << AllocType;
1834*700637cbSDimitry Andric return false;
1835*700637cbSDimitry Andric }
1836*700637cbSDimitry Andric
1837*700637cbSDimitry Andric // Can't activate fields in a union, unless the direct base is the union.
1838*700637cbSDimitry Andric if (Ptr.inUnion() && !Ptr.isActive() && !Ptr.getBase().getRecord()->isUnion())
1839*700637cbSDimitry Andric return CheckActive(S, OpPC, Ptr, AK_Construct);
1840*700637cbSDimitry Andric
1841*700637cbSDimitry Andric return true;
1842*700637cbSDimitry Andric }
1843*700637cbSDimitry Andric
InvalidNewDeleteExpr(InterpState & S,CodePtr OpPC,const Expr * E)1844*700637cbSDimitry Andric bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E) {
1845*700637cbSDimitry Andric assert(E);
1846*700637cbSDimitry Andric
1847*700637cbSDimitry Andric if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
1848*700637cbSDimitry Andric const FunctionDecl *OperatorNew = NewExpr->getOperatorNew();
1849*700637cbSDimitry Andric
1850*700637cbSDimitry Andric if (NewExpr->getNumPlacementArgs() > 0) {
1851*700637cbSDimitry Andric // This is allowed pre-C++26, but only an std function.
1852*700637cbSDimitry Andric if (S.getLangOpts().CPlusPlus26 || S.Current->isStdFunction())
1853*700637cbSDimitry Andric return true;
1854*700637cbSDimitry Andric S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)
1855*700637cbSDimitry Andric << /*C++26 feature*/ 1 << E->getSourceRange();
1856*700637cbSDimitry Andric } else if (
1857*700637cbSDimitry Andric !OperatorNew
1858*700637cbSDimitry Andric ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
1859*700637cbSDimitry Andric S.FFDiag(S.Current->getSource(OpPC),
1860*700637cbSDimitry Andric diag::note_constexpr_new_non_replaceable)
1861*700637cbSDimitry Andric << isa<CXXMethodDecl>(OperatorNew) << OperatorNew;
1862*700637cbSDimitry Andric return false;
1863*700637cbSDimitry Andric } else if (!S.getLangOpts().CPlusPlus26 &&
1864*700637cbSDimitry Andric NewExpr->getNumPlacementArgs() == 1 &&
1865*700637cbSDimitry Andric !OperatorNew->isReservedGlobalPlacementOperator()) {
1866*700637cbSDimitry Andric if (!S.getLangOpts().CPlusPlus26) {
1867*700637cbSDimitry Andric S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_placement)
1868*700637cbSDimitry Andric << /*Unsupported*/ 0 << E->getSourceRange();
1869*700637cbSDimitry Andric return false;
1870*700637cbSDimitry Andric }
1871*700637cbSDimitry Andric return true;
1872*700637cbSDimitry Andric }
1873*700637cbSDimitry Andric } else {
1874*700637cbSDimitry Andric const auto *DeleteExpr = cast<CXXDeleteExpr>(E);
1875*700637cbSDimitry Andric const FunctionDecl *OperatorDelete = DeleteExpr->getOperatorDelete();
1876*700637cbSDimitry Andric if (!OperatorDelete
1877*700637cbSDimitry Andric ->isUsableAsGlobalAllocationFunctionInConstantEvaluation()) {
1878*700637cbSDimitry Andric S.FFDiag(S.Current->getSource(OpPC),
1879*700637cbSDimitry Andric diag::note_constexpr_new_non_replaceable)
1880*700637cbSDimitry Andric << isa<CXXMethodDecl>(OperatorDelete) << OperatorDelete;
1881*700637cbSDimitry Andric return false;
1882*700637cbSDimitry Andric }
1883*700637cbSDimitry Andric }
1884*700637cbSDimitry Andric
1885*700637cbSDimitry Andric return false;
1886*700637cbSDimitry Andric }
1887*700637cbSDimitry Andric
handleFixedPointOverflow(InterpState & S,CodePtr OpPC,const FixedPoint & FP)1888*700637cbSDimitry Andric bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,
1889*700637cbSDimitry Andric const FixedPoint &FP) {
1890*700637cbSDimitry Andric const Expr *E = S.Current->getExpr(OpPC);
1891*700637cbSDimitry Andric if (S.checkingForUndefinedBehavior()) {
1892*700637cbSDimitry Andric S.getASTContext().getDiagnostics().Report(
1893*700637cbSDimitry Andric E->getExprLoc(), diag::warn_fixedpoint_constant_overflow)
1894*700637cbSDimitry Andric << FP.toDiagnosticString(S.getASTContext()) << E->getType();
1895*700637cbSDimitry Andric }
1896*700637cbSDimitry Andric S.CCEDiag(E, diag::note_constexpr_overflow)
1897*700637cbSDimitry Andric << FP.toDiagnosticString(S.getASTContext()) << E->getType();
1898*700637cbSDimitry Andric return S.noteUndefinedBehavior();
1899*700637cbSDimitry Andric }
1900*700637cbSDimitry Andric
InvalidShuffleVectorIndex(InterpState & S,CodePtr OpPC,uint32_t Index)1901*700637cbSDimitry Andric bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index) {
1902*700637cbSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC);
1903*700637cbSDimitry Andric S.FFDiag(Loc,
1904*700637cbSDimitry Andric diag::err_shufflevector_minus_one_is_undefined_behavior_constexpr)
1905*700637cbSDimitry Andric << Index;
1906*700637cbSDimitry Andric return false;
1907*700637cbSDimitry Andric }
1908*700637cbSDimitry Andric
CheckPointerToIntegralCast(InterpState & S,CodePtr OpPC,const Pointer & Ptr,unsigned BitWidth)1909*700637cbSDimitry Andric bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,
1910*700637cbSDimitry Andric const Pointer &Ptr, unsigned BitWidth) {
1911*700637cbSDimitry Andric if (Ptr.isDummy())
1912*700637cbSDimitry Andric return false;
1913*700637cbSDimitry Andric if (Ptr.isFunctionPointer())
1914*700637cbSDimitry Andric return true;
1915*700637cbSDimitry Andric
1916*700637cbSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC);
1917*700637cbSDimitry Andric S.CCEDiag(E, diag::note_constexpr_invalid_cast)
1918*700637cbSDimitry Andric << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);
1919*700637cbSDimitry Andric
1920*700637cbSDimitry Andric if (Ptr.isBlockPointer() && !Ptr.isZero()) {
1921*700637cbSDimitry Andric // Only allow based lvalue casts if they are lossless.
1922*700637cbSDimitry Andric if (S.getASTContext().getTargetInfo().getPointerWidth(LangAS::Default) !=
1923*700637cbSDimitry Andric BitWidth)
1924*700637cbSDimitry Andric return Invalid(S, OpPC);
1925*700637cbSDimitry Andric }
1926*700637cbSDimitry Andric return true;
1927*700637cbSDimitry Andric }
1928*700637cbSDimitry Andric
CastPointerIntegralAP(InterpState & S,CodePtr OpPC,uint32_t BitWidth)1929*700637cbSDimitry Andric bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1930*700637cbSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>();
1931*700637cbSDimitry Andric
1932*700637cbSDimitry Andric if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))
1933*700637cbSDimitry Andric return false;
1934*700637cbSDimitry Andric
1935*700637cbSDimitry Andric auto Result = S.allocAP<IntegralAP<false>>(BitWidth);
1936*700637cbSDimitry Andric Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation()));
1937*700637cbSDimitry Andric
1938*700637cbSDimitry Andric S.Stk.push<IntegralAP<false>>(Result);
1939*700637cbSDimitry Andric return true;
1940*700637cbSDimitry Andric }
1941*700637cbSDimitry Andric
CastPointerIntegralAPS(InterpState & S,CodePtr OpPC,uint32_t BitWidth)1942*700637cbSDimitry Andric bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
1943*700637cbSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>();
1944*700637cbSDimitry Andric
1945*700637cbSDimitry Andric if (!CheckPointerToIntegralCast(S, OpPC, Ptr, BitWidth))
1946*700637cbSDimitry Andric return false;
1947*700637cbSDimitry Andric
1948*700637cbSDimitry Andric auto Result = S.allocAP<IntegralAP<true>>(BitWidth);
1949*700637cbSDimitry Andric Result.copy(APInt(BitWidth, Ptr.getIntegerRepresentation()));
1950*700637cbSDimitry Andric
1951*700637cbSDimitry Andric S.Stk.push<IntegralAP<true>>(Result);
1952*700637cbSDimitry Andric return true;
1953*700637cbSDimitry Andric }
1954*700637cbSDimitry Andric
CheckBitCast(InterpState & S,CodePtr OpPC,bool HasIndeterminateBits,bool TargetIsUCharOrByte)1955*700637cbSDimitry Andric bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
1956*700637cbSDimitry Andric bool TargetIsUCharOrByte) {
1957*700637cbSDimitry Andric // This is always fine.
1958*700637cbSDimitry Andric if (!HasIndeterminateBits)
1959*700637cbSDimitry Andric return true;
1960*700637cbSDimitry Andric
1961*700637cbSDimitry Andric // Indeterminate bits can only be bitcast to unsigned char or std::byte.
1962*700637cbSDimitry Andric if (TargetIsUCharOrByte)
1963*700637cbSDimitry Andric return true;
1964*700637cbSDimitry Andric
1965*700637cbSDimitry Andric const Expr *E = S.Current->getExpr(OpPC);
1966*700637cbSDimitry Andric QualType ExprType = E->getType();
1967*700637cbSDimitry Andric S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)
1968*700637cbSDimitry Andric << ExprType << S.getLangOpts().CharIsSigned << E->getSourceRange();
1969*700637cbSDimitry Andric return false;
1970*700637cbSDimitry Andric }
1971*700637cbSDimitry Andric
GetTypeid(InterpState & S,CodePtr OpPC,const Type * TypePtr,const Type * TypeInfoType)1972*700637cbSDimitry Andric bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,
1973*700637cbSDimitry Andric const Type *TypeInfoType) {
1974*700637cbSDimitry Andric S.Stk.push<Pointer>(TypePtr, TypeInfoType);
1975*700637cbSDimitry Andric return true;
1976*700637cbSDimitry Andric }
1977*700637cbSDimitry Andric
GetTypeidPtr(InterpState & S,CodePtr OpPC,const Type * TypeInfoType)1978*700637cbSDimitry Andric bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
1979*700637cbSDimitry Andric const auto &P = S.Stk.pop<Pointer>();
1980*700637cbSDimitry Andric
1981*700637cbSDimitry Andric if (!P.isBlockPointer())
1982*700637cbSDimitry Andric return false;
1983*700637cbSDimitry Andric
1984*700637cbSDimitry Andric // Pick the most-derived type.
1985*700637cbSDimitry Andric const Type *T = P.getDeclPtr().getType().getTypePtr();
1986*700637cbSDimitry Andric // ... unless we're currently constructing this object.
1987*700637cbSDimitry Andric // FIXME: We have a similar check to this in more places.
1988*700637cbSDimitry Andric if (S.Current->getFunction()) {
1989*700637cbSDimitry Andric for (const InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {
1990*700637cbSDimitry Andric if (const Function *Func = Frame->getFunction();
1991*700637cbSDimitry Andric Func && (Func->isConstructor() || Func->isDestructor()) &&
1992*700637cbSDimitry Andric P.block() == Frame->getThis().block()) {
1993*700637cbSDimitry Andric T = Func->getParentDecl()->getTypeForDecl();
1994*700637cbSDimitry Andric break;
1995*700637cbSDimitry Andric }
1996*700637cbSDimitry Andric }
1997*700637cbSDimitry Andric }
1998*700637cbSDimitry Andric
1999*700637cbSDimitry Andric S.Stk.push<Pointer>(T->getCanonicalTypeUnqualified().getTypePtr(),
2000*700637cbSDimitry Andric TypeInfoType);
2001*700637cbSDimitry Andric return true;
2002*700637cbSDimitry Andric }
2003*700637cbSDimitry Andric
DiagTypeid(InterpState & S,CodePtr OpPC)2004*700637cbSDimitry Andric bool DiagTypeid(InterpState &S, CodePtr OpPC) {
2005*700637cbSDimitry Andric const auto *E = cast<CXXTypeidExpr>(S.Current->getExpr(OpPC));
2006*700637cbSDimitry Andric S.CCEDiag(E, diag::note_constexpr_typeid_polymorphic)
2007*700637cbSDimitry Andric << E->getExprOperand()->getType()
2008*700637cbSDimitry Andric << E->getExprOperand()->getSourceRange();
2009*700637cbSDimitry Andric return false;
2010*700637cbSDimitry Andric }
2011*700637cbSDimitry Andric
arePotentiallyOverlappingStringLiterals(const Pointer & LHS,const Pointer & RHS)2012*700637cbSDimitry Andric bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,
2013*700637cbSDimitry Andric const Pointer &RHS) {
2014*700637cbSDimitry Andric unsigned LHSOffset = LHS.getIndex();
2015*700637cbSDimitry Andric unsigned RHSOffset = RHS.getIndex();
2016*700637cbSDimitry Andric unsigned LHSLength = (LHS.getNumElems() - 1) * LHS.elemSize();
2017*700637cbSDimitry Andric unsigned RHSLength = (RHS.getNumElems() - 1) * RHS.elemSize();
2018*700637cbSDimitry Andric
2019*700637cbSDimitry Andric StringRef LHSStr((const char *)LHS.atIndex(0).getRawAddress(), LHSLength);
2020*700637cbSDimitry Andric StringRef RHSStr((const char *)RHS.atIndex(0).getRawAddress(), RHSLength);
2021*700637cbSDimitry Andric int32_t IndexDiff = RHSOffset - LHSOffset;
2022*700637cbSDimitry Andric if (IndexDiff < 0) {
2023*700637cbSDimitry Andric if (static_cast<int32_t>(LHSLength) < -IndexDiff)
2024*700637cbSDimitry Andric return false;
2025*700637cbSDimitry Andric LHSStr = LHSStr.drop_front(-IndexDiff);
2026*700637cbSDimitry Andric } else {
2027*700637cbSDimitry Andric if (static_cast<int32_t>(RHSLength) < IndexDiff)
2028*700637cbSDimitry Andric return false;
2029*700637cbSDimitry Andric RHSStr = RHSStr.drop_front(IndexDiff);
2030*700637cbSDimitry Andric }
2031*700637cbSDimitry Andric
2032*700637cbSDimitry Andric unsigned ShorterCharWidth;
2033*700637cbSDimitry Andric StringRef Shorter;
2034*700637cbSDimitry Andric StringRef Longer;
2035*700637cbSDimitry Andric if (LHSLength < RHSLength) {
2036*700637cbSDimitry Andric ShorterCharWidth = LHS.elemSize();
2037*700637cbSDimitry Andric Shorter = LHSStr;
2038*700637cbSDimitry Andric Longer = RHSStr;
2039*700637cbSDimitry Andric } else {
2040*700637cbSDimitry Andric ShorterCharWidth = RHS.elemSize();
2041*700637cbSDimitry Andric Shorter = RHSStr;
2042*700637cbSDimitry Andric Longer = LHSStr;
2043*700637cbSDimitry Andric }
2044*700637cbSDimitry Andric
2045*700637cbSDimitry Andric // The null terminator isn't included in the string data, so check for it
2046*700637cbSDimitry Andric // manually. If the longer string doesn't have a null terminator where the
2047*700637cbSDimitry Andric // shorter string ends, they aren't potentially overlapping.
2048*700637cbSDimitry Andric for (unsigned NullByte : llvm::seq(ShorterCharWidth)) {
2049*700637cbSDimitry Andric if (Shorter.size() + NullByte >= Longer.size())
2050*700637cbSDimitry Andric break;
2051*700637cbSDimitry Andric if (Longer[Shorter.size() + NullByte])
2052*700637cbSDimitry Andric return false;
2053*700637cbSDimitry Andric }
2054*700637cbSDimitry Andric return Shorter == Longer.take_front(Shorter.size());
2055*700637cbSDimitry Andric }
2056*700637cbSDimitry Andric
copyPrimitiveMemory(InterpState & S,const Pointer & Ptr,PrimType T)2057*700637cbSDimitry Andric static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr,
2058*700637cbSDimitry Andric PrimType T) {
2059*700637cbSDimitry Andric
2060*700637cbSDimitry Andric if (T == PT_IntAPS) {
2061*700637cbSDimitry Andric auto &Val = Ptr.deref<IntegralAP<true>>();
2062*700637cbSDimitry Andric if (!Val.singleWord()) {
2063*700637cbSDimitry Andric uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
2064*700637cbSDimitry Andric Val.take(NewMemory);
2065*700637cbSDimitry Andric }
2066*700637cbSDimitry Andric } else if (T == PT_IntAP) {
2067*700637cbSDimitry Andric auto &Val = Ptr.deref<IntegralAP<false>>();
2068*700637cbSDimitry Andric if (!Val.singleWord()) {
2069*700637cbSDimitry Andric uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
2070*700637cbSDimitry Andric Val.take(NewMemory);
2071*700637cbSDimitry Andric }
2072*700637cbSDimitry Andric } else if (T == PT_Float) {
2073*700637cbSDimitry Andric auto &Val = Ptr.deref<Floating>();
2074*700637cbSDimitry Andric if (!Val.singleWord()) {
2075*700637cbSDimitry Andric uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
2076*700637cbSDimitry Andric Val.take(NewMemory);
2077*700637cbSDimitry Andric }
2078*700637cbSDimitry Andric }
2079*700637cbSDimitry Andric }
2080*700637cbSDimitry Andric
2081*700637cbSDimitry Andric template <typename T>
copyPrimitiveMemory(InterpState & S,const Pointer & Ptr)2082*700637cbSDimitry Andric static void copyPrimitiveMemory(InterpState &S, const Pointer &Ptr) {
2083*700637cbSDimitry Andric assert(needsAlloc<T>());
2084*700637cbSDimitry Andric auto &Val = Ptr.deref<T>();
2085*700637cbSDimitry Andric if (!Val.singleWord()) {
2086*700637cbSDimitry Andric uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];
2087*700637cbSDimitry Andric Val.take(NewMemory);
2088*700637cbSDimitry Andric }
2089*700637cbSDimitry Andric }
2090*700637cbSDimitry Andric
finishGlobalRecurse(InterpState & S,const Pointer & Ptr)2091*700637cbSDimitry Andric static void finishGlobalRecurse(InterpState &S, const Pointer &Ptr) {
2092*700637cbSDimitry Andric if (const Record *R = Ptr.getRecord()) {
2093*700637cbSDimitry Andric for (const Record::Field &Fi : R->fields()) {
2094*700637cbSDimitry Andric if (Fi.Desc->isPrimitive()) {
2095*700637cbSDimitry Andric TYPE_SWITCH_ALLOC(Fi.Desc->getPrimType(), {
2096*700637cbSDimitry Andric copyPrimitiveMemory<T>(S, Ptr.atField(Fi.Offset));
2097*700637cbSDimitry Andric });
2098*700637cbSDimitry Andric copyPrimitiveMemory(S, Ptr.atField(Fi.Offset), Fi.Desc->getPrimType());
2099*700637cbSDimitry Andric } else
2100*700637cbSDimitry Andric finishGlobalRecurse(S, Ptr.atField(Fi.Offset));
2101*700637cbSDimitry Andric }
2102*700637cbSDimitry Andric return;
2103*700637cbSDimitry Andric }
2104*700637cbSDimitry Andric
2105*700637cbSDimitry Andric if (const Descriptor *D = Ptr.getFieldDesc(); D && D->isArray()) {
2106*700637cbSDimitry Andric unsigned NumElems = D->getNumElems();
2107*700637cbSDimitry Andric if (NumElems == 0)
2108*700637cbSDimitry Andric return;
2109*700637cbSDimitry Andric
2110*700637cbSDimitry Andric if (D->isPrimitiveArray()) {
2111*700637cbSDimitry Andric PrimType PT = D->getPrimType();
2112*700637cbSDimitry Andric if (!needsAlloc(PT))
2113*700637cbSDimitry Andric return;
2114*700637cbSDimitry Andric assert(NumElems >= 1);
2115*700637cbSDimitry Andric const Pointer EP = Ptr.atIndex(0);
2116*700637cbSDimitry Andric bool AllSingleWord = true;
2117*700637cbSDimitry Andric TYPE_SWITCH_ALLOC(PT, {
2118*700637cbSDimitry Andric if (!EP.deref<T>().singleWord()) {
2119*700637cbSDimitry Andric copyPrimitiveMemory<T>(S, EP);
2120*700637cbSDimitry Andric AllSingleWord = false;
2121*700637cbSDimitry Andric }
2122*700637cbSDimitry Andric });
2123*700637cbSDimitry Andric if (AllSingleWord)
2124*700637cbSDimitry Andric return;
2125*700637cbSDimitry Andric for (unsigned I = 1; I != D->getNumElems(); ++I) {
2126*700637cbSDimitry Andric const Pointer EP = Ptr.atIndex(I);
2127*700637cbSDimitry Andric copyPrimitiveMemory(S, EP, PT);
2128*700637cbSDimitry Andric }
2129*700637cbSDimitry Andric } else {
2130*700637cbSDimitry Andric assert(D->isCompositeArray());
2131*700637cbSDimitry Andric for (unsigned I = 0; I != D->getNumElems(); ++I) {
2132*700637cbSDimitry Andric const Pointer EP = Ptr.atIndex(I).narrow();
2133*700637cbSDimitry Andric finishGlobalRecurse(S, EP);
2134*700637cbSDimitry Andric }
2135*700637cbSDimitry Andric }
2136*700637cbSDimitry Andric }
2137*700637cbSDimitry Andric }
2138*700637cbSDimitry Andric
FinishInitGlobal(InterpState & S,CodePtr OpPC)2139*700637cbSDimitry Andric bool FinishInitGlobal(InterpState &S, CodePtr OpPC) {
2140*700637cbSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>();
2141*700637cbSDimitry Andric
2142*700637cbSDimitry Andric finishGlobalRecurse(S, Ptr);
2143*700637cbSDimitry Andric if (Ptr.canBeInitialized()) {
2144*700637cbSDimitry Andric Ptr.initialize();
2145*700637cbSDimitry Andric Ptr.activate();
2146*700637cbSDimitry Andric }
2147*700637cbSDimitry Andric
2148*700637cbSDimitry Andric return true;
2149*700637cbSDimitry Andric }
2150*700637cbSDimitry Andric
2151*700637cbSDimitry Andric // https://github.com/llvm/llvm-project/issues/102513
2152*700637cbSDimitry Andric #if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
2153*700637cbSDimitry Andric #pragma optimize("", off)
2154*700637cbSDimitry Andric #endif
Interpret(InterpState & S)2155*700637cbSDimitry Andric bool Interpret(InterpState &S) {
2156*700637cbSDimitry Andric // The current stack frame when we started Interpret().
2157*700637cbSDimitry Andric // This is being used by the ops to determine wheter
2158*700637cbSDimitry Andric // to return from this function and thus terminate
2159*700637cbSDimitry Andric // interpretation.
2160*700637cbSDimitry Andric const InterpFrame *StartFrame = S.Current;
2161*700637cbSDimitry Andric assert(!S.Current->isRoot());
2162*700637cbSDimitry Andric CodePtr PC = S.Current->getPC();
2163*700637cbSDimitry Andric
2164*700637cbSDimitry Andric // Empty program.
2165*700637cbSDimitry Andric if (!PC)
2166*700637cbSDimitry Andric return true;
2167*700637cbSDimitry Andric
2168*700637cbSDimitry Andric for (;;) {
2169*700637cbSDimitry Andric auto Op = PC.read<Opcode>();
2170*700637cbSDimitry Andric CodePtr OpPC = PC;
2171*700637cbSDimitry Andric
2172*700637cbSDimitry Andric switch (Op) {
2173*700637cbSDimitry Andric #define GET_INTERP
2174*700637cbSDimitry Andric #include "Opcodes.inc"
2175*700637cbSDimitry Andric #undef GET_INTERP
2176*700637cbSDimitry Andric }
2177*700637cbSDimitry Andric }
2178*700637cbSDimitry Andric }
2179*700637cbSDimitry Andric // https://github.com/llvm/llvm-project/issues/102513
2180*700637cbSDimitry Andric #if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
2181*700637cbSDimitry Andric #pragma optimize("", on)
2182*700637cbSDimitry Andric #endif
2183*700637cbSDimitry Andric
2184*700637cbSDimitry Andric } // namespace interp
2185*700637cbSDimitry Andric } // namespace clang
2186