18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/SmallPtrSet.h"
25QualType EvaluationResult::getStorageType()
const {
26 if (
const auto *E = Source.asExpr()) {
30 return Ctx.getASTContext().getLValueReferenceType(E->getType());
33 if (
const auto *D = Source.asValueDecl())
40 assert(SubObjDecl &&
"Subobject declaration does not exist");
41 S.
FFDiag(Loc, diag::note_constexpr_uninitialized)
44 diag::note_constexpr_subobject_declared_here);
48 PtrView BasePtr,
const Record *R,
49 bool IsCompleteClass =
true);
72 for (
size_t I = 0; I != NumElems; ++I) {
76 }
else if (ElemDesc->
isArray()) {
77 for (
size_t I = 0; I != NumElems; ++I) {
88 bool IsCompleteClass) {
92 for (
const Record::Field &F : R->fields()) {
96 if (R->isUnion() && !FieldPtr.
isActive())
99 QualType FieldType = F.Decl->getType();
106 }
else if (F.Decl->isUnnamedBitField()) {
108 }
else if (FieldDesc->
isArray()) {
116 auto diagnoseBase = [&](
const Record::Base &B,
unsigned Index) ->
bool {
118 if (
const auto *CD = dyn_cast_if_present<CXXRecordDecl>(R->getDecl())) {
119 const auto &BS = *std::next(CD->bases_begin(), Index);
121 S.
FFDiag(TypeBeginLoc, diag::note_constexpr_uninitialized_base)
122 << B.Desc->getType() <<
SourceRange(TypeBeginLoc, BS.getEndLoc());
125 << B.Desc->getType();
131 for (
auto [I, B] : llvm::enumerate(R->bases())) {
134 return diagnoseBase(B, I);
139 if (IsCompleteClass) {
140 for (
auto [I, B] : llvm::enumerate(R->virtual_bases())) {
143 return diagnoseBase(B, I);
159 if (!Ptr.isBlockPointer())
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();
173 if (
const Record *R = Ptr.getRecord())
176 if (isa_and_nonnull<ConstantArrayType>(Ptr.getType()->getAsArrayTypeUnsafe()))
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();
199 if (!Ptr.isLive() || Ptr.isZero() || Ptr.isUnknownSizeArray() ||
203 Blocks.insert(Ptr.Pointee);
210 if (!R->hasPtrField())
213 for (
const Record::Base &B : R->bases()) {
214 if (!B.R->hasPtrField())
216 PtrView BasePtr = Ptr.atField(B.Offset);
220 for (
const Record::Field &F : R->fields()) {
223 PtrView FieldPtr = Ptr.atField(F.Offset);
227 if (IsCompleteClass) {
228 for (
const Record::Base &B : R->virtual_bases()) {
229 if (!B.R->hasPtrField())
231 PtrView BasePtr = Ptr.atField(B.Offset);
241 if (isUsefulPtr(Pointee) && !Blocks.contains(Pointee.
block()))
248 for (
unsigned I = 0; I != Desc->
getNumElems(); ++I) {
250 if (isUsefulPtr(ElemPointee) && !Blocks.contains(ElemPointee.
block()))
257 for (
unsigned I = 0; I != Desc->
getNumElems(); ++I) {
258 PtrView ElemPtr = Ptr.atIndex(I).narrow();
267 if (!Ptr.isBlockPointer())
276 for (
const Block *B : Blocks) {
277 if (B->isDynamic()) {
278 assert(B->getDescriptor());
279 assert(B->getDescriptor()->asExpr());
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);
296 if (Ptr.isTypeidPointer())
299 return ::isGlobalLValue(Ptr.getRootValueDecl(), Ptr.getRootExpr());
306 assert(Ptr.isFunctionPointer());
317 S.
FFDiag(Info, diag::note_consteval_address_accessible)
348 if (Ptr.isFunctionPointer())
351 if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer())
354 const Expr *BaseE = Ptr.getRootExpr();
355 const ValueDecl *BaseVD = Ptr.getRootValueDecl();
356 assert(BaseE || BaseVD);
358 bool IsSubObj = !Ptr.isRoot() || (Ptr.inArray() && !Ptr.isArrayRoot());
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);
376 S.
Note(BaseVD->getLocation(), diag::note_declared_at);
386 if (
const auto *VD = dyn_cast_if_present<VarDecl>(BaseVD)) {
389 if (
const RecordDecl *TypeRD = VD->getType()->getAsRecordDecl();
393 if (VD->getTLSKind()) {
403 !VD->isStaticLocal())
407 if (S.
getLangOpts().CUDA && VD->hasAttr<HIPManagedAttr>())
414 if ((!VD->hasAttr<CUDADeviceAttr>() && !VD->hasAttr<CUDAConstantAttr>() &&
415 !VD->getType()->isCUDADeviceBuiltinSurfaceType() &&
416 !VD->getType()->isCUDADeviceBuiltinTextureType()))
423 if (
const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(BaseE)) {
427 S.
FFDiag(MTE->getExprLoc(),
428 diag::note_constexpr_unsupported_temporary_nontrivial_dtor)
433 if (Ptr.getFieldDesc()->isPrimitive() &&
434 Ptr.getFieldDesc()->getPrimType() ==
PT_Ptr) {
438 CheckedBlocks.insert(Pointee.
block()).second) {
440 Ptr.getDeclDesc()->getLoc(), ConstexprKind, CheckedBlocks))
444 if (!
lvalFields(S, Ctx, Ptr.view(), TempType, Info, ConstexprKind,
457 const Descriptor *FieldDesc = Ptr.getFieldDesc();
458 if (
const Record *R = Ptr.getRecord()) {
459 if (!R->hasPtrField())
462 for (
const Record::Base &B : R->bases()) {
463 if (!B.R->hasPtrField())
466 PtrView BasePtr = Ptr.atField(B.Offset);
472 for (
const Record::Field &F : R->fields()) {
473 PtrView FieldPtr = Ptr.atField(F.Offset);
477 if (F.Desc->isPrimitive() && F.Desc->getPrimType() ==
PT_Ptr) {
483 CheckedBlocks.insert(Pointee.
block()).second) {
484 QualType FieldType = F.Decl->getType();
485 if (!
lval(S, Ctx, Pointee, FieldType, Info, ConstexprKind,
491 ConstexprKind, CheckedBlocks))
496 for (
const Record::Base &B : R->virtual_bases()) {
497 if (!B.R->hasPtrField())
499 PtrView BasePtr = Ptr.atField(B.Offset);
508 for (
unsigned I = 0; I != FieldDesc->
getNumElems(); ++I) {
514 CheckedBlocks.insert(Pointee.
block()).second) {
516 ConstexprKind, CheckedBlocks))
527 for (
unsigned I = 0; I != FieldDesc->
getNumElems(); ++I) {
528 PtrView Elem = Ptr.atIndex(I).narrow();
530 ConstexprKind, CheckedBlocks))
548 if (!Ptr.isBlockPointer())
551 QualType SourceType = getStorageType();
555 ConstexprKind, CheckedBlocks);
561 QualType SourceType = getStorageType();
562 if (Ptr.isFunctionPointer())
569 if (Ptr.isTypeidPointer()) {
571 S.
FFDiag(Info, diag::note_constexpr_invalid_template_arg)
572 << IsReferenceType <<
false << 0;
578 if (Ptr.isStringPointer()) {
583 bool IsSubObj = Ptr.asStringPointer().Decayed || Ptr.getIndex() != 0;
584 int InvalidBaseKind = -1;
586 const Expr *BaseE = Ptr.asStringPointer().Base;
587 if (isa_and_nonnull<StringLiteral>(BaseE))
589 else if (
const auto *PE = dyn_cast_if_present<PredefinedExpr>(BaseE)) {
591 Ident = PE->getIdentKindName();
594 if (InvalidBaseKind != -1) {
595 S.
FFDiag(Info, diag::note_constexpr_invalid_template_arg)
596 << IsReferenceType << IsSubObj << InvalidBaseKind << Ident;
603 if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer())
610 const Expr *BaseE = Ptr.getRootExpr();
611 const ValueDecl *BaseVD = Ptr.getRootValueDecl();
612 assert(BaseE || BaseVD);
613 if (isa_and_nonnull<MaterializeTemporaryExpr>(BaseE) ||
614 isa_and_nonnull<LifetimeExtendedTemporaryDecl>(BaseVD)) {
615 bool IsSubObj = !Ptr.isRoot() || (Ptr.inArray() && !Ptr.isArrayRoot());
616 S.
FFDiag(Info, diag::note_constexpr_invalid_template_arg)
617 << IsReferenceType << IsSubObj << 2;
640 S.
FFDiag(Info, diag::note_consteval_address_accessible)
647 !MD->
hasAttr<DLLImportAttr>()) {
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
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
struct clang::ASTContext::CUDAConstantEvalContext CUDAConstantEvalCtx
Represents a static or instance method of a struct/union/class.
bool isInvalidDecl() const
SourceLocation getLocation() const
SourceLocation getBeginLoc() const LLVM_READONLY
This represents one expression.
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Represents a member of a struct/union/class.
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.
Represents a function declaration or definition.
bool isImmediateFunction() const
A (possibly-)qualified type.
DestructionKind isDestructedType() const
Returns a nonzero value if objects of this type require non-trivial work to clean up after.
Represents a struct/union/class.
Encodes a location in the source.
A trivial tuple used to represent a source range.
bool isIncompleteArrayType() const
bool isReferenceType() const
bool isAnyPointerType() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
bool isConstexpr() const
Whether this variable is (C++11) constexpr.
A memory block, either on the stack or in the heap.
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.
A pointer to a memory block, live or dead.
QualType getType() const
Returns the type of the innermost field.
bool isBlockPointer() const
const Block * block() const
Structure/Class descriptor.
bool hasPtrField() const
If this record (or any of its bases) contains a field of type PT_Ptr.
Describes the statement/declaration an opcode was generated from.
OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)
Add a note to a prior diagnostic.
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)
ASTContext & getASTContext() const
const LangOptions & getLangOpts() const
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
@ Result
The result type of a method or function.
U cast(CodeGen::Address addr)
bool NoWrongSidedVars
Do not allow wrong-sided variables in constant expressions.
Describes a memory block created by an allocation site.
unsigned getNumElems() const
Returns the number of elements stored in the block.
SourceLocation getLocation() const
bool isPrimitive() const
Checks if the descriptor is of a primitive.
QualType getElemQualType() const
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
const Descriptor *const ElemDesc
Descriptor of the array element.
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
PrimType getPrimType() const
bool isRecord() const
Checks if the descriptor is of a record.
const Record *const ElemRecord
Pointer to the record, if block contains records.
bool isArray() const
Checks if the descriptor is of an array.
const Descriptor * getDeclDesc() const
bool allElementsInitialized() const
PtrView atField(unsigned Offset) const
const Record * getRecord() const
const Descriptor * getFieldDesc() const
const FieldDecl * getField() const
PtrView atIndex(unsigned Idx) const
bool isInitialized() const