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 // We might allow creating pointers into invalid records, but do not allow
388 // returning them from an evaluation.
389 if (const RecordDecl *TypeRD = VD->getType()->getAsRecordDecl();
390 TypeRD && TypeRD->isInvalidDecl())
391 return false;
392 // Check if this is a thread-local variable.
393 if (VD->getTLSKind()) {
394 // FIXME: Diagnostic!
395 return false;
396 }
397
398 // A dllimport variable never acts like a constant, unless we're
399 // evaluating a value for use only in name mangling, and unless it's a
400 // static local. For the latter case, we'd still need to evaluate the
401 // constant expression in case we're inside a (inlined) function.
402 if (!isForManglingOnly(Kind: ConstexprKind) && VD->hasAttr<DLLImportAttr>() &&
403 !VD->isStaticLocal())
404 return false;
405
406 // Address of a managed variable is never a constant expression.
407 if (S.getLangOpts().CUDA && VD->hasAttr<HIPManagedAttr>())
408 return false;
409
410 // In CUDA/HIP device compilation, only device side variables have
411 // constant addresses.
412 if (S.getLangOpts().CUDA && S.getLangOpts().CUDAIsDevice &&
413 Ctx.CUDAConstantEvalCtx.NoWrongSidedVars) {
414 if ((!VD->hasAttr<CUDADeviceAttr>() && !VD->hasAttr<CUDAConstantAttr>() &&
415 !VD->getType()->isCUDADeviceBuiltinSurfaceType() &&
416 !VD->getType()->isCUDADeviceBuiltinTextureType()))
417 return false;
418 }
419
420 return true;
421 }
422
423 if (const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(Val: BaseE)) {
424 QualType TempType = Ptr.getType();
425
426 if (TempType.isDestructedType()) {
427 S.FFDiag(Loc: MTE->getExprLoc(),
428 DiagId: diag::note_constexpr_unsupported_temporary_nontrivial_dtor)
429 << TempType;
430 return false;
431 }
432
433 if (Ptr.getFieldDesc()->isPrimitive() &&
434 Ptr.getFieldDesc()->getPrimType() == PT_Ptr) {
435 // Recurse!
436 Pointer Pointee = Ptr.deref<Pointer>();
437 if (!Pointee.isBlockPointer() ||
438 CheckedBlocks.insert(Ptr: Pointee.block()).second) {
439 if (!lval(S, Ctx, Ptr: Pointee, PtrType: Pointee.getType(),
440 Info: Ptr.getDeclDesc()->getLoc(), ConstexprKind, CheckedBlocks))
441 return false;
442 }
443 } else {
444 if (!lvalFields(S, Ctx, Ptr: Ptr.view(), PtrType: TempType, Info, ConstexprKind,
445 CheckedBlocks))
446 return false;
447 }
448 }
449
450 return true;
451}
452
453static bool lvalFields(InterpState &S, const ASTContext &Ctx, PtrView Ptr,
454 QualType PtrType, SourceInfo Info,
455 ConstantExprKind ConstexprKind,
456 llvm::SmallPtrSet<const Block *, 4> &CheckedBlocks) {
457 const Descriptor *FieldDesc = Ptr.getFieldDesc();
458 if (const Record *R = Ptr.getRecord()) {
459 if (!R->hasPtrField())
460 return true;
461
462 for (const Record::Base &B : R->bases()) {
463 if (!B.R->hasPtrField())
464 continue;
465
466 PtrView BasePtr = Ptr.atField(Offset: B.Offset);
467 if (!lvalFields(S, Ctx, Ptr: BasePtr, PtrType: B.Desc->getType(), Info, ConstexprKind,
468 CheckedBlocks))
469 return false;
470 }
471
472 for (const Record::Field &F : R->fields()) {
473 PtrView FieldPtr = Ptr.atField(Offset: F.Offset);
474 if (!isOrHasPtr(D: F.Desc))
475 continue;
476
477 if (F.Desc->isPrimitive() && F.Desc->getPrimType() == PT_Ptr) {
478 if (!FieldPtr.isLive())
479 return false;
480
481 Pointer Pointee = FieldPtr.deref<Pointer>();
482 if (!Pointee.isBlockPointer() ||
483 CheckedBlocks.insert(Ptr: Pointee.block()).second) {
484 QualType FieldType = F.Decl->getType();
485 if (!lval(S, Ctx, Ptr: Pointee, PtrType: FieldType, Info, ConstexprKind,
486 CheckedBlocks))
487 return false;
488 }
489 } else {
490 if (!lvalFields(S, Ctx, Ptr: FieldPtr, PtrType: F.Decl->getType(), Info,
491 ConstexprKind, CheckedBlocks))
492 return false;
493 }
494 }
495
496 for (const Record::Base &B : R->virtual_bases()) {
497 if (!B.R->hasPtrField())
498 continue;
499 PtrView BasePtr = Ptr.atField(Offset: B.Offset);
500 if (!lvalFields(S, Ctx, Ptr: BasePtr, PtrType: B.Desc->getType(), Info, ConstexprKind,
501 CheckedBlocks))
502 return false;
503 }
504 return true;
505 }
506
507 if (FieldDesc->isPrimitiveArray() && FieldDesc->getPrimType() == PT_Ptr) {
508 for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
509 if (!Ptr.isLive())
510 return false;
511 Pointer Pointee = Ptr.elem<Pointer>(I);
512
513 if (!Pointee.isBlockPointer() ||
514 CheckedBlocks.insert(Ptr: Pointee.block()).second) {
515 if (!lval(S, Ctx, Ptr: Pointee, PtrType: FieldDesc->getElemQualType(), Info,
516 ConstexprKind, CheckedBlocks))
517 return false;
518 }
519 }
520 return true;
521 }
522
523 if (FieldDesc->isCompositeArray()) {
524 if (FieldDesc->ElemRecord && !FieldDesc->ElemRecord->hasPtrField())
525 return true;
526
527 for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
528 PtrView Elem = Ptr.atIndex(Idx: I).narrow();
529 if (!lvalFields(S, Ctx, Ptr: Elem, PtrType: FieldDesc->getElemQualType(), Info,
530 ConstexprKind, CheckedBlocks))
531 return false;
532 }
533 return true;
534 }
535 if (FieldDesc->isPrimitive() && FieldDesc->getPrimType() == PT_MemberPtr) {
536 MemberPointer MP = Ptr.deref<MemberPointer>();
537 if (!EvaluationResult::checkMemberPointer(S, MemberPtr: MP, Info, ConstexprKind))
538 return false;
539 }
540
541 return true;
542}
543
544/// Toplevel accessor to check all lvalue fields.
545bool EvaluationResult::checkLValueFields(InterpState &S, const Pointer &Ptr,
546 SourceInfo Info,
547 ConstantExprKind ConstexprKind) const {
548 if (!Ptr.isBlockPointer())
549 return true;
550
551 QualType SourceType = getStorageType();
552 llvm::SmallPtrSet<const Block *, 4> CheckedBlocks;
553
554 return lvalFields(S, Ctx: Ctx.getASTContext(), Ptr: Ptr.view(), PtrType: SourceType, Info,
555 ConstexprKind, CheckedBlocks);
556}
557
558bool EvaluationResult::checkLValue(InterpState &S, const Pointer &Ptr,
559 SourceInfo Info,
560 ConstantExprKind ConstexprKind) const {
561 QualType SourceType = getStorageType();
562 if (Ptr.isFunctionPointer())
563 return checkFunctionPtr(S, Ptr, PtrType: SourceType, Info, ConstexprKind);
564
565 if (Ptr.isZero())
566 return true;
567
568 bool IsReferenceType = SourceType->isReferenceType();
569 if (Ptr.isTypeidPointer()) {
570 if (isTemplateArgument(Kind: ConstexprKind)) {
571 S.FFDiag(SI: Info, DiagId: diag::note_constexpr_invalid_template_arg)
572 << IsReferenceType << /*IsSubObj=*/false << /*InvalidBaseKind=*/0;
573 return false;
574 }
575 return true;
576 }
577
578 if (Ptr.isStringPointer()) {
579 // Additional restrictions apply in a template argument. We only enforce the
580 // C++20 restrictions here; additional syntactic and semantic restrictions
581 // are applied elsewhere.
582 if (isTemplateArgument(Kind: ConstexprKind)) {
583 bool IsSubObj = Ptr.asStringPointer().Decayed || Ptr.getIndex() != 0;
584 int InvalidBaseKind = -1;
585 StringRef Ident;
586 const Expr *BaseE = Ptr.asStringPointer().Base;
587 if (isa_and_nonnull<StringLiteral>(Val: BaseE))
588 InvalidBaseKind = 1;
589 else if (const auto *PE = dyn_cast_if_present<PredefinedExpr>(Val: BaseE)) {
590 InvalidBaseKind = 3;
591 Ident = PE->getIdentKindName();
592 }
593
594 if (InvalidBaseKind != -1) {
595 S.FFDiag(SI: Info, DiagId: diag::note_constexpr_invalid_template_arg)
596 << IsReferenceType << IsSubObj << InvalidBaseKind << Ident;
597 return false;
598 }
599 }
600 return true;
601 }
602
603 if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer())
604 return true;
605
606 // Additional restrictions apply in a template argument. We only enforce the
607 // C++20 restrictions here; additional syntactic and semantic restrictions
608 // are applied elsewhere.
609 if (isTemplateArgument(Kind: ConstexprKind)) {
610 const Expr *BaseE = Ptr.getRootExpr();
611 const ValueDecl *BaseVD = Ptr.getRootValueDecl();
612 assert(BaseE || BaseVD);
613 if (isa_and_nonnull<MaterializeTemporaryExpr>(Val: BaseE) ||
614 isa_and_nonnull<LifetimeExtendedTemporaryDecl>(Val: BaseVD)) {
615 bool IsSubObj = !Ptr.isRoot() || (Ptr.inArray() && !Ptr.isArrayRoot());
616 S.FFDiag(SI: Info, DiagId: diag::note_constexpr_invalid_template_arg)
617 << IsReferenceType << IsSubObj << 2;
618 return false;
619 }
620 }
621
622 llvm::SmallPtrSet<const Block *, 4> CheckedBlocks;
623 if (!lval(S, Ctx: Ctx.getASTContext(), Ptr, PtrType: SourceType, Info, ConstexprKind,
624 CheckedBlocks)) {
625 return false;
626 }
627
628 return true;
629}
630
631bool EvaluationResult::checkMemberPointer(InterpState &S,
632 const MemberPointer &MemberPtr,
633 SourceInfo Info,
634 ConstantExprKind ConstexprKind) {
635 const CXXMethodDecl *MD = MemberPtr.getMemberFunction();
636 if (!MD)
637 return true;
638
639 if (MD->isImmediateFunction()) {
640 S.FFDiag(SI: Info, DiagId: diag::note_consteval_address_accessible)
641 << /*pointer=*/false;
642 S.Note(Loc: MD->getLocation(), DiagId: diag::note_declared_at);
643 return false;
644 }
645
646 if (isForManglingOnly(Kind: ConstexprKind) || MD->isVirtual() ||
647 !MD->hasAttr<DLLImportAttr>()) {
648 return true;
649 }
650 return false;
651}
652
653bool EvaluationResult::checkFunctionPointer(
654 InterpState &S, const Pointer &Ptr, SourceInfo Info,
655 ConstantExprKind ConstexprKind) const {
656 return checkFunctionPtr(S, Ptr, PtrType: getStorageType(), Info, ConstexprKind);
657}
658
659} // namespace interp
660} // namespace clang
661