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)) {
388 if (VD->getTLSKind()) {
398 !VD->isStaticLocal())
402 if (S.
getLangOpts().CUDA && VD->hasAttr<HIPManagedAttr>())
409 if ((!VD->hasAttr<CUDADeviceAttr>() && !VD->hasAttr<CUDAConstantAttr>() &&
410 !VD->getType()->isCUDADeviceBuiltinSurfaceType() &&
411 !VD->getType()->isCUDADeviceBuiltinTextureType()))
418 if (
const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(BaseE)) {
422 S.
FFDiag(MTE->getExprLoc(),
423 diag::note_constexpr_unsupported_temporary_nontrivial_dtor)
428 if (Ptr.getFieldDesc()->isPrimitive() &&
429 Ptr.getFieldDesc()->getPrimType() ==
PT_Ptr) {
433 CheckedBlocks.insert(Pointee.
block()).second) {
435 Ptr.getDeclDesc()->getLoc(), ConstexprKind, CheckedBlocks))
439 if (!
lvalFields(S, Ctx, Ptr.view(), TempType, Info, ConstexprKind,
452 const Descriptor *FieldDesc = Ptr.getFieldDesc();
453 if (
const Record *R = Ptr.getRecord()) {
454 if (!R->hasPtrField())
457 for (
const Record::Base &B : R->bases()) {
458 if (!B.R->hasPtrField())
461 PtrView BasePtr = Ptr.atField(B.Offset);
467 for (
const Record::Field &F : R->fields()) {
468 PtrView FieldPtr = Ptr.atField(F.Offset);
472 if (F.Desc->isPrimitive() && F.Desc->getPrimType() ==
PT_Ptr) {
478 CheckedBlocks.insert(Pointee.
block()).second) {
479 QualType FieldType = F.Decl->getType();
480 if (!
lval(S, Ctx, Pointee, FieldType, Info, ConstexprKind,
486 ConstexprKind, CheckedBlocks))
491 for (
const Record::Base &B : R->virtual_bases()) {
492 if (!B.R->hasPtrField())
494 PtrView BasePtr = Ptr.atField(B.Offset);
503 for (
unsigned I = 0; I != FieldDesc->
getNumElems(); ++I) {
509 CheckedBlocks.insert(Pointee.
block()).second) {
511 ConstexprKind, CheckedBlocks))
522 for (
unsigned I = 0; I != FieldDesc->
getNumElems(); ++I) {
523 PtrView Elem = Ptr.atIndex(I).narrow();
525 ConstexprKind, CheckedBlocks))
543 if (!Ptr.isBlockPointer())
546 QualType SourceType = getStorageType();
550 ConstexprKind, CheckedBlocks);
556 QualType SourceType = getStorageType();
557 if (Ptr.isFunctionPointer())
564 if (Ptr.isTypeidPointer()) {
566 S.
FFDiag(Info, diag::note_constexpr_invalid_template_arg)
567 << IsReferenceType <<
false << 0;
573 if (Ptr.isStringPointer()) {
578 bool IsSubObj = Ptr.asStringPointer().Decayed || Ptr.getIndex() != 0;
579 int InvalidBaseKind = -1;
581 const Expr *BaseE = Ptr.asStringPointer().Base;
582 if (isa_and_nonnull<StringLiteral>(BaseE))
584 else if (
const auto *PE = dyn_cast_if_present<PredefinedExpr>(BaseE)) {
586 Ident = PE->getIdentKindName();
589 if (InvalidBaseKind != -1) {
590 S.
FFDiag(Info, diag::note_constexpr_invalid_template_arg)
591 << IsReferenceType << IsSubObj << InvalidBaseKind << Ident;
598 if (!Ptr.isBlockPointer() && !Ptr.isOpaquePointer())
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;
635 S.
FFDiag(Info, diag::note_consteval_address_accessible)
642 !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.
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.
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