clang 24.0.0git
EvaluationResult.cpp
Go to the documentation of this file.
1//===----- EvaluationResult.cpp - Result class for the VM ------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "EvaluationResult.h"
10#include "../ExprConstShared.h"
11#include "InterpState.h"
12#include "Pointer.h"
13#include "Record.h"
15#include "clang/AST/Expr.h"
16#include "clang/AST/ExprCXX.h"
17#include "clang/AST/ExprObjC.h"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/SmallPtrSet.h"
20#include <iterator>
21
22namespace clang {
23namespace interp {
24
25QualType EvaluationResult::getStorageType() const {
26 if (const auto *E = Source.asExpr()) {
27 if (E->isPRValue())
28 return E->getType();
29
30 return Ctx.getASTContext().getLValueReferenceType(E->getType());
31 }
32
33 if (const auto *D = Source.asValueDecl())
34 return D->getType();
35 return QualType();
36}
37
39 const FieldDecl *SubObjDecl) {
40 assert(SubObjDecl && "Subobject declaration does not exist");
41 S.FFDiag(Loc, diag::note_constexpr_uninitialized)
42 << /*(name)*/ 1 << SubObjDecl;
43 S.Note(SubObjDecl->getLocation(),
44 diag::note_constexpr_subobject_declared_here);
45}
46
47static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
48 PtrView BasePtr, const Record *R,
49 bool IsCompleteClass = true);
50
52 PtrView BasePtr) {
53 const Descriptor *BaseDesc = BasePtr.getFieldDesc();
54 assert(BaseDesc->isArray());
55
56 size_t NumElems = BaseDesc->getNumElems();
57 if (NumElems == 0)
58 return true;
59
60 bool Result = true;
61
62 if (BaseDesc->isPrimitiveArray()) {
63 if (BasePtr.allElementsInitialized())
64 return true;
66 return false;
67 }
68 const Descriptor *ElemDesc = BaseDesc->ElemDesc;
69
70 if (ElemDesc->isRecord()) {
71 const Record *R = ElemDesc->ElemRecord;
72 for (size_t I = 0; I != NumElems; ++I) {
73 PtrView ElemPtr = BasePtr.atIndex(I).narrow();
74 Result &= CheckFieldsInitialized(S, Loc, ElemPtr, R);
75 }
76 } else if (ElemDesc->isArray()) {
77 for (size_t I = 0; I != NumElems; ++I) {
78 PtrView ElemPtr = BasePtr.atIndex(I).narrow();
79 Result &= CheckArrayInitialized(S, Loc, ElemPtr);
80 }
81 }
82
83 return Result;
84}
85
87 PtrView BasePtr, const Record *R,
88 bool IsCompleteClass) {
89 assert(R);
90 bool Result = true;
91 // Check all fields of this record are initialized.
92 for (const Record::Field &F : R->fields()) {
93 PtrView FieldPtr = BasePtr.atField(F.Offset);
94
95 // Don't check inactive union members.
96 if (R->isUnion() && !FieldPtr.isActive())
97 continue;
98
99 QualType FieldType = F.Decl->getType();
100 const Descriptor *FieldDesc = FieldPtr.getFieldDesc();
101
102 if (FieldDesc->isRecord()) {
103 Result &= CheckFieldsInitialized(S, Loc, FieldPtr, FieldPtr.getRecord());
104 } else if (FieldType->isIncompleteArrayType()) {
105 // Nothing to do here.
106 } else if (F.Decl->isUnnamedBitField()) {
107 // Nothing do do here.
108 } else if (FieldDesc->isArray()) {
109 Result &= CheckArrayInitialized(S, Loc, FieldPtr);
110 } else if (!FieldPtr.isInitialized()) {
111 DiagnoseUninitializedSubobject(S, Loc, F.Decl);
112 Result = false;
113 }
114 }
115
116 auto diagnoseBase = [&](const Record::Base &B, unsigned Index) -> bool {
117 const Descriptor *Desc = BasePtr.getDeclDesc();
118 if (const auto *CD = dyn_cast_if_present<CXXRecordDecl>(R->getDecl())) {
119 const auto &BS = *std::next(CD->bases_begin(), Index);
120 SourceLocation TypeBeginLoc = BS.getBaseTypeLoc();
121 S.FFDiag(TypeBeginLoc, diag::note_constexpr_uninitialized_base)
122 << B.Desc->getType() << SourceRange(TypeBeginLoc, BS.getEndLoc());
123 } else {
124 S.FFDiag(Desc->getLocation(), diag::note_constexpr_uninitialized_base)
125 << B.Desc->getType();
126 }
127 return false;
128 };
129
130 // Check Fields in all bases.
131 for (auto [I, B] : llvm::enumerate(R->bases())) {
132 PtrView P = BasePtr.atField(B.Offset);
133 if (!P.isInitialized())
134 return diagnoseBase(B, I);
135 Result &= CheckFieldsInitialized(S, Loc, P, B.R, /*IsCompleteClass=*/false);
136 }
137
138 // And virtual bases.
139 if (IsCompleteClass) {
140 for (auto [I, B] : llvm::enumerate(R->virtual_bases())) {
141 PtrView P = BasePtr.atField(B.Offset);
142 if (!P.isInitialized())
143 return diagnoseBase(B, I);
144 Result &=
145 CheckFieldsInitialized(S, Loc, P, B.R, /*IsCompleteClass=*/false);
146 }
147 }
148
149 return Result;
150}
151
153 const Pointer &Ptr) const {
154 assert(Source);
155 assert(empty());
156
157 if (Ptr.isZero())
158 return true;
159 if (!Ptr.isBlockPointer())
160 return true;
161
162 // We can't inspect dead pointers at all. Return true here so we can
163 // diagnose them later.
164 if (!Ptr.isLive())
165 return true;
166
167 SourceLocation InitLoc;
168 if (const auto *D = Source.asDecl())
169 InitLoc = cast<VarDecl>(D)->getAnyInitializer()->getExprLoc();
170 else if (const auto *E = Source.asExpr())
171 InitLoc = E->getExprLoc();
172
173 if (const Record *R = Ptr.getRecord())
174 return CheckFieldsInitialized(S, InitLoc, Ptr.view(), R);
175
176 if (isa_and_nonnull<ConstantArrayType>(Ptr.getType()->getAsArrayTypeUnsafe()))
177 return CheckArrayInitialized(S, InitLoc, Ptr.view());
178
179 return true;
180}
181
182static bool isOrHasPtr(const Descriptor *D) {
183 if ((D->isPrimitive() || D->isPrimitiveArray()) && D->getPrimType() == PT_Ptr)
184 return true;
185
186 if (D->ElemRecord)
187 return D->ElemRecord->hasPtrField();
188 return false;
189}
190
191static void collectBlocks(PtrView Ptr,
193 bool IsCompleteClass = true) {
194 auto isUsefulPtr = [](const Pointer &P) -> bool {
195 return P.isLive() && P.isBlockPointer() && !P.isZero() && !P.isDummy() &&
196 P.isDereferencable() && !P.isUnknownSizeArray() && !P.isOnePastEnd();
197 };
198
199 if (!Ptr.isLive() || Ptr.isZero() || Ptr.isUnknownSizeArray() ||
200 Ptr.isOnePastEnd())
201 return;
202
203 Blocks.insert(Ptr.Pointee);
204
205 const Descriptor *Desc = Ptr.getFieldDesc();
206 if (!Desc)
207 return;
208
209 if (const Record *R = Desc->ElemRecord) {
210 if (!R->hasPtrField())
211 return;
212
213 for (const Record::Base &B : R->bases()) {
214 if (!B.R->hasPtrField())
215 continue;
216 PtrView BasePtr = Ptr.atField(B.Offset);
217 collectBlocks(BasePtr, Blocks, /*IsCompleteClass=*/false);
218 }
219
220 for (const Record::Field &F : R->fields()) {
221 if (!isOrHasPtr(F.Desc))
222 continue;
223 PtrView FieldPtr = Ptr.atField(F.Offset);
224 collectBlocks(FieldPtr, Blocks);
225 }
226
227 if (IsCompleteClass) {
228 for (const Record::Base &B : R->virtual_bases()) {
229 if (!B.R->hasPtrField())
230 continue;
231 PtrView BasePtr = Ptr.atField(B.Offset);
232 collectBlocks(BasePtr, Blocks, /*IsCompleteClass=*/false);
233 }
234 }
235
236 return;
237 }
238
239 if (Desc->isPrimitive() && Desc->getPrimType() == PT_Ptr) {
240 Pointer Pointee = Ptr.deref<Pointer>();
241 if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.block()))
242 collectBlocks(Pointee.view(), Blocks);
243
244 return;
245 }
246
247 if (Desc->isPrimitiveArray() && Desc->getPrimType() == PT_Ptr) {
248 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
249 Pointer ElemPointee = Ptr.elem<Pointer>(I);
250 if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.block()))
251 collectBlocks(ElemPointee.view(), Blocks);
252 }
253 return;
254 }
255
256 if (Desc->isCompositeArray() && isOrHasPtr(Desc->ElemDesc)) {
257 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
258 PtrView ElemPtr = Ptr.atIndex(I).narrow();
259 collectBlocks(ElemPtr, Blocks);
260 }
261 }
262}
263
265 const Pointer &Ptr,
266 SourceInfo Info) const {
267 if (!Ptr.isBlockPointer())
268 return true;
269
270 // Collect all blocks that this pointer (transitively) points to and
271 // return false if any of them is a dynamic block.
273
274 collectBlocks(Ptr.view(), Blocks);
275
276 for (const Block *B : Blocks) {
277 if (B->isDynamic()) {
278 assert(B->getDescriptor());
279 assert(B->getDescriptor()->asExpr());
280
281 bool IsSubobj = !Ptr.isRoot() || Ptr.isArrayElement();
282 S.FFDiag(Info, diag::note_constexpr_dynamic_alloc)
283 << Ptr.getType()->isReferenceType() << IsSubobj;
284 S.Note(B->getDescriptor()->asExpr()->getExprLoc(),
285 diag::note_constexpr_dynamic_alloc_here);
286 return false;
287 }
288 }
289
290 return true;
291}
292
293static bool isGlobalLValue(const Pointer &Ptr) {
294 if (Ptr.isDynamic())
295 return true;
296 if (Ptr.isTypeidPointer())
297 return true;
298
299 return ::isGlobalLValue(Ptr.getRootValueDecl(), Ptr.getRootExpr());
300}
301
302/// Check if the given function pointer can be returned from an evaluation.
303static bool checkFunctionPtr(InterpState &S, const Pointer &Ptr,
304 QualType PtrType, SourceInfo Info,
305 ConstantExprKind ConstexprKind) {
306 assert(Ptr.isFunctionPointer());
307 const FunctionPointer &FuncPtr = Ptr.asFunctionPointer();
308
309 if (!FuncPtr.Func)
310 return true;
311
312 const FunctionDecl *FD = FuncPtr.Func->getDecl();
313 // E.g. ObjC block pointers.
314 if (!FD)
315 return true;
316 if (FD->isImmediateFunction()) {
317 S.FFDiag(Info, diag::note_consteval_address_accessible)
318 << !PtrType->isAnyPointerType();
319 S.Note(FD->getLocation(), diag::note_declared_at);
320 return false;
321 }
322
323 // __declspec(dllimport) must be handled very carefully:
324 // We must never initialize an expression with the thunk in C++.
325 // Doing otherwise would allow the same id-expression to yield
326 // different addresses for the same function in different translation
327 // units. However, this means that we must dynamically initialize the
328 // expression with the contents of the import address table at runtime.
329 //
330 // The C language has no notion of ODR; furthermore, it has no notion of
331 // dynamic initialization. This means that we are permitted to
332 // perform initialization with the address of the thunk.
333 if (S.getLangOpts().CPlusPlus && !isForManglingOnly(ConstexprKind) &&
334 FD->hasAttr<DLLImportAttr>())
335 // FIXME: Diagnostic!
336 return false;
337 return true;
338}
339
340static bool lvalFields(InterpState &S, const ASTContext &Ctx, PtrView Ptr,
341 QualType PtrType, SourceInfo Info,
342 ConstantExprKind ConstexprKind,
344static bool lval(InterpState &S, const ASTContext &Ctx, const Pointer &Ptr,
345 QualType PtrType, SourceInfo Info,
346 ConstantExprKind ConstexprKind,
348 if (Ptr.isFunctionPointer())
349 return checkFunctionPtr(S, Ptr, PtrType, Info, ConstexprKind);
350
351 if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer())
352 return true;
353
354 const Expr *BaseE = Ptr.getRootExpr();
355 const ValueDecl *BaseVD = Ptr.getRootValueDecl();
356 assert(BaseE || BaseVD);
357 bool IsReferenceType = PtrType->isReferenceType();
358 bool IsSubObj = !Ptr.isRoot() || (Ptr.inArray() && !Ptr.isArrayRoot());
359
360 if (!isGlobalLValue(Ptr)) {
361 if (S.getLangOpts().CPlusPlus11) {
362 S.FFDiag(Info, diag::note_constexpr_non_global, 1)
363 << IsReferenceType << IsSubObj << !!BaseVD << BaseVD;
364 const VarDecl *VarD = dyn_cast_if_present<VarDecl>(BaseVD);
365 if (VarD && VarD->isConstexpr()) {
366 // Non-static local constexpr variables have unintuitive semantics:
367 // constexpr int a = 1;
368 // constexpr const int *p = &a;
369 // ... is invalid because the address of 'a' is not constant. Suggest
370 // adding a 'static' in this case.
371 S.Note(VarD->getLocation(), diag::note_constexpr_not_static)
372 << VarD
373 << FixItHint::CreateInsertion(VarD->getBeginLoc(), "static ");
374 } else {
375 if (BaseVD)
376 S.Note(BaseVD->getLocation(), diag::note_declared_at);
377 else if (BaseE)
378 S.Note(BaseE->getExprLoc(), diag::note_constexpr_temporary_here);
379 }
380 } else {
381 S.FFDiag(Info);
382 }
383 return false;
384 }
385
386 if (const auto *VD = dyn_cast_if_present<VarDecl>(BaseVD)) {
387 // Check if this is a thread-local variable.
388 if (VD->getTLSKind()) {
389 // FIXME: Diagnostic!
390 return false;
391 }
392
393 // A dllimport variable never acts like a constant, unless we're
394 // evaluating a value for use only in name mangling, and unless it's a
395 // static local. For the latter case, we'd still need to evaluate the
396 // constant expression in case we're inside a (inlined) function.
397 if (!isForManglingOnly(ConstexprKind) && VD->hasAttr<DLLImportAttr>() &&
398 !VD->isStaticLocal())
399 return false;
400
401 // Address of a managed variable is never a constant expression.
402 if (S.getLangOpts().CUDA && VD->hasAttr<HIPManagedAttr>())
403 return false;
404
405 // In CUDA/HIP device compilation, only device side variables have
406 // constant addresses.
407 if (S.getLangOpts().CUDA && S.getLangOpts().CUDAIsDevice &&
409 if ((!VD->hasAttr<CUDADeviceAttr>() && !VD->hasAttr<CUDAConstantAttr>() &&
410 !VD->getType()->isCUDADeviceBuiltinSurfaceType() &&
411 !VD->getType()->isCUDADeviceBuiltinTextureType()))
412 return false;
413 }
414
415 return true;
416 }
417
418 if (const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(BaseE)) {
419 QualType TempType = Ptr.getType();
420
421 if (TempType.isDestructedType()) {
422 S.FFDiag(MTE->getExprLoc(),
423 diag::note_constexpr_unsupported_temporary_nontrivial_dtor)
424 << TempType;
425 return false;
426 }
427
428 if (Ptr.getFieldDesc()->isPrimitive() &&
429 Ptr.getFieldDesc()->getPrimType() == PT_Ptr) {
430 // Recurse!
431 Pointer Pointee = Ptr.deref<Pointer>();
432 if (!Pointee.isBlockPointer() ||
433 CheckedBlocks.insert(Pointee.block()).second) {
434 if (!lval(S, Ctx, Pointee, Pointee.getType(),
435 Ptr.getDeclDesc()->getLoc(), ConstexprKind, CheckedBlocks))
436 return false;
437 }
438 } else {
439 if (!lvalFields(S, Ctx, Ptr.view(), TempType, Info, ConstexprKind,
440 CheckedBlocks))
441 return false;
442 }
443 }
444
445 return true;
446}
447
448static bool lvalFields(InterpState &S, const ASTContext &Ctx, PtrView Ptr,
449 QualType PtrType, SourceInfo Info,
450 ConstantExprKind ConstexprKind,
452 const Descriptor *FieldDesc = Ptr.getFieldDesc();
453 if (const Record *R = Ptr.getRecord()) {
454 if (!R->hasPtrField())
455 return true;
456
457 for (const Record::Base &B : R->bases()) {
458 if (!B.R->hasPtrField())
459 continue;
460
461 PtrView BasePtr = Ptr.atField(B.Offset);
462 if (!lvalFields(S, Ctx, BasePtr, B.Desc->getType(), Info, ConstexprKind,
463 CheckedBlocks))
464 return false;
465 }
466
467 for (const Record::Field &F : R->fields()) {
468 PtrView FieldPtr = Ptr.atField(F.Offset);
469 if (!isOrHasPtr(F.Desc))
470 continue;
471
472 if (F.Desc->isPrimitive() && F.Desc->getPrimType() == PT_Ptr) {
473 if (!FieldPtr.isLive())
474 return false;
475
476 Pointer Pointee = FieldPtr.deref<Pointer>();
477 if (!Pointee.isBlockPointer() ||
478 CheckedBlocks.insert(Pointee.block()).second) {
479 QualType FieldType = F.Decl->getType();
480 if (!lval(S, Ctx, Pointee, FieldType, Info, ConstexprKind,
481 CheckedBlocks))
482 return false;
483 }
484 } else {
485 if (!lvalFields(S, Ctx, FieldPtr, F.Decl->getType(), Info,
486 ConstexprKind, CheckedBlocks))
487 return false;
488 }
489 }
490
491 for (const Record::Base &B : R->virtual_bases()) {
492 if (!B.R->hasPtrField())
493 continue;
494 PtrView BasePtr = Ptr.atField(B.Offset);
495 if (!lvalFields(S, Ctx, BasePtr, B.Desc->getType(), Info, ConstexprKind,
496 CheckedBlocks))
497 return false;
498 }
499 return true;
500 }
501
502 if (FieldDesc->isPrimitiveArray() && FieldDesc->getPrimType() == PT_Ptr) {
503 for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
504 if (!Ptr.isLive())
505 return false;
506 Pointer Pointee = Ptr.elem<Pointer>(I);
507
508 if (!Pointee.isBlockPointer() ||
509 CheckedBlocks.insert(Pointee.block()).second) {
510 if (!lval(S, Ctx, Pointee, FieldDesc->getElemQualType(), Info,
511 ConstexprKind, CheckedBlocks))
512 return false;
513 }
514 }
515 return true;
516 }
517
518 if (FieldDesc->isCompositeArray()) {
519 if (FieldDesc->ElemRecord && !FieldDesc->ElemRecord->hasPtrField())
520 return true;
521
522 for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
523 PtrView Elem = Ptr.atIndex(I).narrow();
524 if (!lvalFields(S, Ctx, Elem, FieldDesc->getElemQualType(), Info,
525 ConstexprKind, CheckedBlocks))
526 return false;
527 }
528 return true;
529 }
530 if (FieldDesc->isPrimitive() && FieldDesc->getPrimType() == PT_MemberPtr) {
531 MemberPointer MP = Ptr.deref<MemberPointer>();
532 if (!EvaluationResult::checkMemberPointer(S, MP, Info, ConstexprKind))
533 return false;
534 }
535
536 return true;
537}
538
539/// Toplevel accessor to check all lvalue fields.
541 SourceInfo Info,
542 ConstantExprKind ConstexprKind) const {
543 if (!Ptr.isBlockPointer())
544 return true;
545
546 QualType SourceType = getStorageType();
548
549 return lvalFields(S, Ctx.getASTContext(), Ptr.view(), SourceType, Info,
550 ConstexprKind, CheckedBlocks);
551}
552
554 SourceInfo Info,
555 ConstantExprKind ConstexprKind) const {
556 QualType SourceType = getStorageType();
557 if (Ptr.isFunctionPointer())
558 return checkFunctionPtr(S, Ptr, SourceType, Info, ConstexprKind);
559
560 if (Ptr.isZero())
561 return true;
562
563 bool IsReferenceType = SourceType->isReferenceType();
564 if (Ptr.isTypeidPointer()) {
565 if (isTemplateArgument(ConstexprKind)) {
566 S.FFDiag(Info, diag::note_constexpr_invalid_template_arg)
567 << IsReferenceType << /*IsSubObj=*/false << /*InvalidBaseKind=*/0;
568 return false;
569 }
570 return true;
571 }
572
573 if (Ptr.isStringPointer()) {
574 // Additional restrictions apply in a template argument. We only enforce the
575 // C++20 restrictions here; additional syntactic and semantic restrictions
576 // are applied elsewhere.
577 if (isTemplateArgument(ConstexprKind)) {
578 bool IsSubObj = Ptr.asStringPointer().Decayed || Ptr.getIndex() != 0;
579 int InvalidBaseKind = -1;
580 StringRef Ident;
581 const Expr *BaseE = Ptr.asStringPointer().Base;
582 if (isa_and_nonnull<StringLiteral>(BaseE))
583 InvalidBaseKind = 1;
584 else if (const auto *PE = dyn_cast_if_present<PredefinedExpr>(BaseE)) {
585 InvalidBaseKind = 3;
586 Ident = PE->getIdentKindName();
587 }
588
589 if (InvalidBaseKind != -1) {
590 S.FFDiag(Info, diag::note_constexpr_invalid_template_arg)
591 << IsReferenceType << IsSubObj << InvalidBaseKind << Ident;
592 return false;
593 }
594 }
595 return true;
596 }
597
598 if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer())
599 return true;
600
601 // Additional restrictions apply in a template argument. We only enforce the
602 // C++20 restrictions here; additional syntactic and semantic restrictions
603 // are applied elsewhere.
604 if (isTemplateArgument(ConstexprKind)) {
605 const Expr *BaseE = Ptr.getRootExpr();
606 const ValueDecl *BaseVD = Ptr.getRootValueDecl();
607 assert(BaseE || BaseVD);
608 if (isa_and_nonnull<MaterializeTemporaryExpr>(BaseE) ||
609 isa_and_nonnull<LifetimeExtendedTemporaryDecl>(BaseVD)) {
610 bool IsSubObj = !Ptr.isRoot() || (Ptr.inArray() && !Ptr.isArrayRoot());
611 S.FFDiag(Info, diag::note_constexpr_invalid_template_arg)
612 << IsReferenceType << IsSubObj << 2;
613 return false;
614 }
615 }
616
618 if (!lval(S, Ctx.getASTContext(), Ptr, SourceType, Info, ConstexprKind,
619 CheckedBlocks)) {
620 return false;
621 }
622
623 return true;
624}
625
627 const MemberPointer &MemberPtr,
628 SourceInfo Info,
629 ConstantExprKind ConstexprKind) {
630 const CXXMethodDecl *MD = MemberPtr.getMemberFunction();
631 if (!MD)
632 return true;
633
634 if (MD->isImmediateFunction()) {
635 S.FFDiag(Info, diag::note_consteval_address_accessible)
636 << /*pointer=*/false;
637 S.Note(MD->getLocation(), diag::note_declared_at);
638 return false;
639 }
640
641 if (isForManglingOnly(ConstexprKind) || MD->isVirtual() ||
642 !MD->hasAttr<DLLImportAttr>()) {
643 return true;
644 }
645 return false;
646}
647
649 InterpState &S, const Pointer &Ptr, SourceInfo Info,
650 ConstantExprKind ConstexprKind) const {
651 return checkFunctionPtr(S, Ptr, getStorageType(), Info, ConstexprKind);
652}
653
654} // namespace interp
655} // namespace clang
Defines the C++ template declaration subclasses.
Defines the clang::Expr interface and subclasses for C++ expressions.
bool isTemplateArgument(ConstantExprKind Kind)
bool isForManglingOnly(ConstantExprKind Kind)
Determines whether the given kind of constant expression is only ever used for name mangling.
llvm::MachO::Record Record
Definition MachO.h:31
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:239
struct clang::ASTContext::CUDAConstantEvalContext CUDAConstantEvalCtx
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2150
bool isVirtual() const
Definition DeclCXX.h:2205
SourceLocation getLocation() const
Definition DeclBase.h:447
bool hasAttr() const
Definition DeclBase.h:585
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Decl.h:832
This represents one expression.
Definition Expr.h:113
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:283
Represents a member of a struct/union/class.
Definition Decl.h:3295
static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)
Create a code modification hint that inserts the given code string at a specific location.
Definition Diagnostic.h:103
Represents a function declaration or definition.
Definition Decl.h:2059
bool isImmediateFunction() const
Definition Decl.cpp:3382
A (possibly-)qualified type.
Definition TypeBase.h:938
DestructionKind isDestructedType() const
Returns a nonzero value if objects of this type require non-trivial work to clean up after.
Definition TypeBase.h:1561
Encodes a location in the source.
A trivial tuple used to represent a source range.
bool isIncompleteArrayType() const
Definition TypeBase.h:8790
bool isReferenceType() const
Definition TypeBase.h:8707
bool isAnyPointerType() const
Definition TypeBase.h:8691
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:713
Represents a variable declaration or definition.
Definition Decl.h:933
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
Definition Decl.h:1594
A memory block, either on the stack or in the heap.
Definition InterpBlock.h:43
static bool checkMemberPointer(InterpState &S, const MemberPointer &MemberPtr, SourceInfo Info, ConstantExprKind ConstexprKind)
Check if the given member pointer can be returned from an evaluation.
bool checkFunctionPointer(InterpState &S, const Pointer &Ptr, SourceInfo Info, ConstantExprKind ConstexprKind) const
Check if the given function pointer can be returned from an evaluation.
bool checkLValue(InterpState &S, const Pointer &Ptr, SourceInfo Info, ConstantExprKind ConstexprKind) const
Check the given pointer as an lvalue, i.e.
bool checkDynamicAllocations(InterpState &S, const Pointer &Ptr, SourceInfo Info) const
Check that none of the blocks the given pointer (transitively) points to are dynamically allocated.
bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const
Check that all subobjects of the given pointer have been initialized.
bool checkLValueFields(InterpState &S, const Pointer &Ptr, SourceInfo Info, ConstantExprKind ConstexprKind) const
Check all fields of the given pointer.
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition Function.h:133
Interpreter context.
Definition InterpState.h:47
A pointer to a memory block, live or dead.
Definition Pointer.h:546
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:726
bool isBlockPointer() const
Definition Pointer.h:860
const Block * block() const
Definition Pointer.h:1007
PtrView view() const
Definition Pointer.h:605
Structure/Class descriptor.
Definition Record.h:27
bool hasPtrField() const
If this record (or any of its bases) contains a field of type PT_Ptr.
Definition Record.h:85
Describes the statement/declaration an opcode was generated from.
Definition Source.h:77
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
Definition State.cpp:86
OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)
Diagnose that the evaluation could not be folded (FF => FoldFailure)
Definition State.cpp:37
ASTContext & getASTContext() const
Definition State.h:90
const LangOptions & getLangOpts() const
Definition State.h:91
static bool lvalFields(InterpState &S, const ASTContext &Ctx, PtrView Ptr, QualType PtrType, SourceInfo Info, ConstantExprKind ConstexprKind, llvm::SmallPtrSet< const Block *, 4 > &CheckedBlocks)
static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc, PtrView BasePtr)
static bool isOrHasPtr(const Descriptor *D)
static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc, PtrView BasePtr, const Record *R, bool IsCompleteClass=true)
static bool isGlobalLValue(const Pointer &Ptr)
static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc, const FieldDecl *SubObjDecl)
static bool lval(InterpState &S, const ASTContext &Ctx, const Pointer &Ptr, QualType PtrType, SourceInfo Info, ConstantExprKind ConstexprKind, llvm::SmallPtrSet< const Block *, 4 > &CheckedBlocks)
static bool checkFunctionPtr(InterpState &S, const Pointer &Ptr, QualType PtrType, SourceInfo Info, ConstantExprKind ConstexprKind)
Check if the given function pointer can be returned from an evaluation.
static void collectBlocks(PtrView Ptr, llvm::SmallPtrSet< const Block *, 4 > &Blocks, bool IsCompleteClass=true)
Top level wrappers for InstallAPI frontend operations.
Expr::ConstantExprKind ConstantExprKind
Definition Expr.h:1062
@ Result
The result type of a method or function.
Definition TypeBase.h:906
U cast(CodeGen::Address addr)
Definition Address.h:327
bool NoWrongSidedVars
Do not allow wrong-sided variables in constant expressions.
Definition ASTContext.h:863
Describes a memory block created by an allocation site.
Definition Descriptor.h:122
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:246
SourceLocation getLocation() const
Definition Descriptor.h:198
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:260
QualType getElemQualType() const
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition Descriptor.h:253
const Descriptor *const ElemDesc
Descriptor of the array element.
Definition Descriptor.h:148
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:251
PrimType getPrimType() const
Definition Descriptor.h:231
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:265
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:146
bool isArray() const
Checks if the descriptor is of an array.
Definition Descriptor.h:263
const Descriptor * getDeclDesc() const
Definition Pointer.h:89
bool allElementsInitialized() const
Definition Pointer.cpp:870
PtrView atField(unsigned Offset) const
Definition Pointer.h:277
const Record * getRecord() const
Definition Pointer.h:157
const Descriptor * getFieldDesc() const
Definition Pointer.h:83
const FieldDecl * getField() const
Definition Pointer.h:162
PtrView atIndex(unsigned Idx) const
Definition Pointer.h:213
PtrView narrow() const
Definition Pointer.h:93
bool isInitialized() const
Definition Pointer.h:305
QualType getType() const
Definition Pointer.h:282
bool isActive() const
Definition Pointer.h:45
bool isLive() const
Definition Pointer.h:44
T & deref() const
Definition Pointer.h:248