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"
14#include "clang/AST/DeclTemplate.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(T: E->getType());
31 }
32
33 if (const auto *D = Source.asValueDecl())
34 return D->getType();
35 return QualType();
36}
37
38static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc,
39 const FieldDecl *SubObjDecl) {
40 assert(SubObjDecl && "Subobject declaration does not exist");
41 S.FFDiag(Loc, DiagId: diag::note_constexpr_uninitialized)
42 << /*(name)*/ 1 << SubObjDecl;
43 S.Note(Loc: SubObjDecl->getLocation(),
44 DiagId: 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
51static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
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;
65 DiagnoseUninitializedSubobject(S, Loc, SubObjDecl: BasePtr.getField());
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(Idx: I).narrow();
74 Result &= CheckFieldsInitialized(S, Loc, BasePtr: ElemPtr, R);
75 }
76 } else if (ElemDesc->isArray()) {
77 for (size_t I = 0; I != NumElems; ++I) {
78 PtrView ElemPtr = BasePtr.atIndex(Idx: I).narrow();
79 Result &= CheckArrayInitialized(S, Loc, BasePtr: ElemPtr);
80 }
81 }
82
83 return Result;
84}
85
86static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
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(Offset: 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, BasePtr: FieldPtr, R: 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, BasePtr: FieldPtr);
110 } else if (!FieldPtr.isInitialized()) {
111 DiagnoseUninitializedSubobject(S, Loc, SubObjDecl: 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>(Val: R->getDecl())) {
119 const auto &BS = *std::next(x: CD->bases_begin(), n: Index);
120 SourceLocation TypeBeginLoc = BS.getBaseTypeLoc();
121 S.FFDiag(Loc: TypeBeginLoc, DiagId: diag::note_constexpr_uninitialized_base)
122 << B.Desc->getType() << SourceRange(TypeBeginLoc, BS.getEndLoc());
123 } else {
124 S.FFDiag(Loc: Desc->getLocation(), DiagId: 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(First: R->bases())) {
132 PtrView P = BasePtr.atField(Offset: B.Offset);
133 if (!P.isInitialized())
134 return diagnoseBase(B, I);
135 Result &= CheckFieldsInitialized(S, Loc, BasePtr: P, R: B.R, /*IsCompleteClass=*/false);
136 }
137
138 // And virtual bases.
139 if (IsCompleteClass) {
140 for (auto [I, B] : llvm::enumerate(First: R->virtual_bases())) {
141 PtrView P = BasePtr.atField(Offset: B.Offset);
142 if (!P.isInitialized())
143 return diagnoseBase(B, I);
144 Result &=
145 CheckFieldsInitialized(S, Loc, BasePtr: P, R: B.R, /*IsCompleteClass=*/false);
146 }
147 }
148
149 return Result;
150}
151
152bool EvaluationResult::checkFullyInitialized(InterpState &S,
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>(Val: 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, Loc: InitLoc, BasePtr: Ptr.view(), R);
175
176 if (isa_and_nonnull<ConstantArrayType>(Val: Ptr.getType()->getAsArrayTypeUnsafe()))
177 return CheckArrayInitialized(S, Loc: InitLoc, BasePtr: 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,
192 llvm::SmallPtrSet<const Block *, 4> &Blocks,
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: 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(Offset: B.Offset);
217 collectBlocks(Ptr: BasePtr, Blocks, /*IsCompleteClass=*/false);
218 }
219
220 for (const Record::Field &F : R->fields()) {
221 if (!isOrHasPtr(D: F.Desc))
222 continue;
223 PtrView FieldPtr = Ptr.atField(Offset: F.Offset);
224 collectBlocks(Ptr: 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(Offset: B.Offset);
232 collectBlocks(Ptr: 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(Ptr: Pointee.block()))
242 collectBlocks(Ptr: 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(Ptr: ElemPointee.block()))
251 collectBlocks(Ptr: ElemPointee.view(), Blocks);
252 }
253 return;
254 }
255
256 if (Desc->isCompositeArray() && isOrHasPtr(D: Desc->ElemDesc)) {
257 for (unsigned I = 0; I != Desc->getNumElems(); ++I) {
258 PtrView ElemPtr = Ptr.atIndex(Idx: I).narrow();
259 collectBlocks(Ptr: ElemPtr, Blocks);
260 }
261 }
262}
263
264bool EvaluationResult::checkDynamicAllocations(InterpState &S,
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.
272 llvm::SmallPtrSet<const Block *, 4> Blocks;
273
274 collectBlocks(Ptr: 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(SI: Info, DiagId: diag::note_constexpr_dynamic_alloc)
283 << Ptr.getType()->isReferenceType() << IsSubobj;
284 S.Note(Loc: B->getDescriptor()->asExpr()->getExprLoc(),
285 DiagId: 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(D: Ptr.getRootValueDecl(), E: 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(SI: Info, DiagId: diag::note_consteval_address_accessible)
318 << !PtrType->isAnyPointerType();
319 S.Note(Loc: FD->getLocation(), DiagId: 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(Kind: 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,
343 llvm::SmallPtrSet<const Block *, 4> &CheckedBlocks);
344static bool lval(InterpState &S, const ASTContext &Ctx, const Pointer &Ptr,
345 QualType PtrType, SourceInfo Info,
346 ConstantExprKind ConstexprKind,
347 llvm::SmallPtrSet<const Block *, 4> &CheckedBlocks) {
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(SI: Info, DiagId: diag::note_constexpr_non_global, ExtraNotes: 1)
363 << IsReferenceType << IsSubObj << !!BaseVD << BaseVD;
364 const VarDecl *VarD = dyn_cast_if_present<VarDecl>(Val: 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(Loc: VarD->getLocation(), DiagId: diag::note_constexpr_not_static)
372 << VarD
373 << FixItHint::CreateInsertion(InsertionLoc: VarD->getBeginLoc(), Code: "static ");
374 } else {
375 if (BaseVD)
376 S.Note(Loc: BaseVD->getLocation(), DiagId: diag::note_declared_at);
377 else if (BaseE)
378 S.Note(Loc: BaseE->getExprLoc(), DiagId: diag::note_constexpr_temporary_here);
379 }
380 } else {
381 S.FFDiag(SI: Info);
382 }
383 return false;
384 }
385
386 if (const auto *VD = dyn_cast_if_present<VarDecl>(Val: 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(Kind: 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 &&
408 Ctx.CUDAConstantEvalCtx.NoWrongSidedVars) {
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>(Val: BaseE)) {
419 QualType TempType = Ptr.getType();
420
421 if (TempType.isDestructedType()) {
422 S.FFDiag(Loc: MTE->getExprLoc(),
423 DiagId: 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(Ptr: Pointee.block()).second) {
434 if (!lval(S, Ctx, Ptr: Pointee, PtrType: Pointee.getType(),
435 Info: Ptr.getDeclDesc()->getLoc(), ConstexprKind, CheckedBlocks))
436 return false;
437 }
438 } else {
439 if (!lvalFields(S, Ctx, Ptr: Ptr.view(), PtrType: 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,
451 llvm::SmallPtrSet<const Block *, 4> &CheckedBlocks) {
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(Offset: B.Offset);
462 if (!lvalFields(S, Ctx, Ptr: BasePtr, PtrType: 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(Offset: F.Offset);
469 if (!isOrHasPtr(D: 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(Ptr: Pointee.block()).second) {
479 QualType FieldType = F.Decl->getType();
480 if (!lval(S, Ctx, Ptr: Pointee, PtrType: FieldType, Info, ConstexprKind,
481 CheckedBlocks))
482 return false;
483 }
484 } else {
485 if (!lvalFields(S, Ctx, Ptr: FieldPtr, PtrType: 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(Offset: B.Offset);
495 if (!lvalFields(S, Ctx, Ptr: BasePtr, PtrType: 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(Ptr: Pointee.block()).second) {
510 if (!lval(S, Ctx, Ptr: Pointee, PtrType: 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(Idx: I).narrow();
524 if (!lvalFields(S, Ctx, Ptr: Elem, PtrType: 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, MemberPtr: MP, Info, ConstexprKind))
533 return false;
534 }
535
536 return true;
537}
538
539/// Toplevel accessor to check all lvalue fields.
540bool EvaluationResult::checkLValueFields(InterpState &S, const Pointer &Ptr,
541 SourceInfo Info,
542 ConstantExprKind ConstexprKind) const {
543 if (!Ptr.isBlockPointer())
544 return true;
545
546 QualType SourceType = getStorageType();
547 llvm::SmallPtrSet<const Block *, 4> CheckedBlocks;
548
549 return lvalFields(S, Ctx: Ctx.getASTContext(), Ptr: Ptr.view(), PtrType: SourceType, Info,
550 ConstexprKind, CheckedBlocks);
551}
552
553bool EvaluationResult::checkLValue(InterpState &S, const Pointer &Ptr,
554 SourceInfo Info,
555 ConstantExprKind ConstexprKind) const {
556 QualType SourceType = getStorageType();
557 if (Ptr.isFunctionPointer())
558 return checkFunctionPtr(S, Ptr, PtrType: SourceType, Info, ConstexprKind);
559
560 if (Ptr.isZero())
561 return true;
562
563 bool IsReferenceType = SourceType->isReferenceType();
564 if (Ptr.isTypeidPointer()) {
565 if (isTemplateArgument(Kind: ConstexprKind)) {
566 S.FFDiag(SI: Info, DiagId: 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(Kind: 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>(Val: BaseE))
583 InvalidBaseKind = 1;
584 else if (const auto *PE = dyn_cast_if_present<PredefinedExpr>(Val: BaseE)) {
585 InvalidBaseKind = 3;
586 Ident = PE->getIdentKindName();
587 }
588
589 if (InvalidBaseKind != -1) {
590 S.FFDiag(SI: Info, DiagId: 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(Kind: ConstexprKind)) {
605 const Expr *BaseE = Ptr.getRootExpr();
606 const ValueDecl *BaseVD = Ptr.getRootValueDecl();
607 assert(BaseE || BaseVD);
608 if (isa_and_nonnull<MaterializeTemporaryExpr>(Val: BaseE) ||
609 isa_and_nonnull<LifetimeExtendedTemporaryDecl>(Val: BaseVD)) {
610 bool IsSubObj = !Ptr.isRoot() || (Ptr.inArray() && !Ptr.isArrayRoot());
611 S.FFDiag(SI: Info, DiagId: diag::note_constexpr_invalid_template_arg)
612 << IsReferenceType << IsSubObj << 2;
613 return false;
614 }
615 }
616
617 llvm::SmallPtrSet<const Block *, 4> CheckedBlocks;
618 if (!lval(S, Ctx: Ctx.getASTContext(), Ptr, PtrType: SourceType, Info, ConstexprKind,
619 CheckedBlocks)) {
620 return false;
621 }
622
623 return true;
624}
625
626bool EvaluationResult::checkMemberPointer(InterpState &S,
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(SI: Info, DiagId: diag::note_consteval_address_accessible)
636 << /*pointer=*/false;
637 S.Note(Loc: MD->getLocation(), DiagId: diag::note_declared_at);
638 return false;
639 }
640
641 if (isForManglingOnly(Kind: ConstexprKind) || MD->isVirtual() ||
642 !MD->hasAttr<DLLImportAttr>()) {
643 return true;
644 }
645 return false;
646}
647
648bool EvaluationResult::checkFunctionPointer(
649 InterpState &S, const Pointer &Ptr, SourceInfo Info,
650 ConstantExprKind ConstexprKind) const {
651 return checkFunctionPtr(S, Ptr, PtrType: getStorageType(), Info, ConstexprKind);
652}
653
654} // namespace interp
655} // namespace clang
656