summaryrefslogtreecommitdiff
path: root/clang/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST')
-rw-r--r--clang/lib/AST/APValue.cpp3
-rw-r--r--clang/lib/AST/ASTContext.cpp165
-rw-r--r--clang/lib/AST/ASTImporter.cpp39
-rw-r--r--clang/lib/AST/ASTStructuralEquivalence.cpp4
-rw-r--r--clang/lib/AST/ByteCode/Compiler.cpp211
-rw-r--r--clang/lib/AST/ByteCode/Compiler.h8
-rw-r--r--clang/lib/AST/ByteCode/Context.cpp9
-rw-r--r--clang/lib/AST/ByteCode/Descriptor.cpp108
-rw-r--r--clang/lib/AST/ByteCode/Disasm.cpp55
-rw-r--r--clang/lib/AST/ByteCode/EvalEmitter.cpp17
-rw-r--r--clang/lib/AST/ByteCode/EvaluationResult.cpp58
-rw-r--r--clang/lib/AST/ByteCode/EvaluationResult.h57
-rw-r--r--clang/lib/AST/ByteCode/Integral.h5
-rw-r--r--clang/lib/AST/ByteCode/Interp.cpp32
-rw-r--r--clang/lib/AST/ByteCode/Interp.h10
-rw-r--r--clang/lib/AST/ByteCode/InterpBuiltin.cpp427
-rw-r--r--clang/lib/AST/ByteCode/InterpFrame.cpp6
-rw-r--r--clang/lib/AST/ByteCode/InterpFrame.h2
-rw-r--r--clang/lib/AST/ByteCode/InterpState.cpp38
-rw-r--r--clang/lib/AST/ByteCode/InterpState.h24
-rw-r--r--clang/lib/AST/ByteCode/Pointer.cpp75
-rw-r--r--clang/lib/AST/ByteCode/Pointer.h217
-rw-r--r--clang/lib/AST/ByteCode/PrimType.h10
-rw-r--r--clang/lib/AST/ByteCode/Program.cpp39
-rw-r--r--clang/lib/AST/ByteCode/Program.h18
-rw-r--r--clang/lib/AST/ByteCode/Record.cpp11
-rw-r--r--clang/lib/AST/ByteCode/Record.h4
-rw-r--r--clang/lib/AST/ByteCode/State.h25
-rw-r--r--clang/lib/AST/CXXInheritance.cpp38
-rw-r--r--clang/lib/AST/Decl.cpp34
-rw-r--r--clang/lib/AST/DeclCXX.cpp51
-rw-r--r--clang/lib/AST/DeclTemplate.cpp6
-rw-r--r--clang/lib/AST/DeclarationName.cpp5
-rw-r--r--clang/lib/AST/DynamicRecursiveASTVisitor.cpp2
-rw-r--r--clang/lib/AST/Expr.cpp68
-rw-r--r--clang/lib/AST/ExprConstant.cpp813
-rw-r--r--clang/lib/AST/FormatString.cpp12
-rw-r--r--clang/lib/AST/InheritViz.cpp4
-rw-r--r--clang/lib/AST/ItaniumCXXABI.cpp3
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp27
-rw-r--r--clang/lib/AST/JSONNodeDumper.cpp9
-rw-r--r--clang/lib/AST/Mangle.cpp37
-rw-r--r--clang/lib/AST/MicrosoftMangle.cpp10
-rw-r--r--clang/lib/AST/OpenACCClause.cpp6
-rw-r--r--clang/lib/AST/OpenMPClause.cpp9
-rw-r--r--clang/lib/AST/PrintfFormatString.cpp4
-rw-r--r--clang/lib/AST/RecordLayoutBuilder.cpp34
-rw-r--r--clang/lib/AST/ScanfFormatString.cpp3
-rw-r--r--clang/lib/AST/Stmt.cpp13
-rw-r--r--clang/lib/AST/StmtOpenMP.cpp13
-rw-r--r--clang/lib/AST/StmtPrinter.cpp13
-rw-r--r--clang/lib/AST/StmtProfile.cpp31
-rw-r--r--clang/lib/AST/TemplateBase.cpp4
-rw-r--r--clang/lib/AST/TemplateName.cpp38
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp22
-rw-r--r--clang/lib/AST/Type.cpp241
-rw-r--r--clang/lib/AST/TypeLoc.cpp12
-rw-r--r--clang/lib/AST/TypePrinter.cpp2
-rw-r--r--clang/lib/AST/VTTBuilder.cpp16
59 files changed, 1913 insertions, 1344 deletions
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index 2d62209bbc28..7173c2a0e1a2 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -903,8 +903,7 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy,
case APValue::Struct: {
Out << '{';
bool First = true;
- const RecordDecl *RD =
- Ty->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *RD = Ty->castAsRecordDecl();
if (unsigned N = getStructNumBases()) {
const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD);
CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin();
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index bbb957067c4c..ed4c6b0e38be 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -654,9 +654,9 @@ comments::FullComment *ASTContext::getCommentForDecl(
// does not have one of its own.
QualType QT = TD->getUnderlyingType();
if (const auto *TT = QT->getAs<TagType>())
- if (const Decl *TD = TT->getOriginalDecl())
- if (comments::FullComment *FC = getCommentForDecl(TD, PP))
- return cloneFullComment(FC, D);
+ if (comments::FullComment *FC =
+ getCommentForDecl(TT->getOriginalDecl(), PP))
+ return cloneFullComment(FC, D);
}
else if (const auto *IC = dyn_cast<ObjCInterfaceDecl>(D)) {
while (IC->getSuperClass()) {
@@ -1708,7 +1708,7 @@ void ASTContext::setRelocationInfoForCXXRecord(
}
static bool primaryBaseHaseAddressDiscriminatedVTableAuthentication(
- ASTContext &Context, const CXXRecordDecl *Class) {
+ const ASTContext &Context, const CXXRecordDecl *Class) {
if (!Class->isPolymorphic())
return false;
const CXXRecordDecl *BaseType = Context.baseForVTableAuthentication(Class);
@@ -1723,7 +1723,8 @@ static bool primaryBaseHaseAddressDiscriminatedVTableAuthentication(
return AddressDiscrimination == AuthAttr::AddressDiscrimination;
}
-ASTContext::PointerAuthContent ASTContext::findPointerAuthContent(QualType T) {
+ASTContext::PointerAuthContent
+ASTContext::findPointerAuthContent(QualType T) const {
assert(isPointerAuthenticationAvailable());
T = T.getCanonicalType();
@@ -1933,12 +1934,9 @@ TypeInfoChars ASTContext::getTypeInfoDataSizeInChars(QualType T) const {
// of a base-class subobject. We decide whether that's possible
// during class layout, so here we can just trust the layout results.
if (getLangOpts().CPlusPlus) {
- if (const auto *RT = T->getAs<RecordType>()) {
- const auto *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
- if (!RD->isInvalidDecl()) {
- const ASTRecordLayout &layout = getASTRecordLayout(RD);
- Info.Width = layout.getDataSize();
- }
+ if (const auto *RD = T->getAsCXXRecordDecl(); RD && !RD->isInvalidDecl()) {
+ const ASTRecordLayout &layout = getASTRecordLayout(RD);
+ Info.Width = layout.getDataSize();
}
}
@@ -2004,8 +2002,7 @@ bool ASTContext::isPromotableIntegerType(QualType T) const {
// Enumerated types are promotable to their compatible integer types
// (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2).
- if (const auto *ET = T->getAs<EnumType>()) {
- const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ if (const auto *ED = T->getAsEnumDecl()) {
if (T->isDependentType() || ED->getPromotionType().isNull() ||
ED->isScoped())
return false;
@@ -2618,10 +2615,10 @@ unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const {
return I->second;
unsigned UnadjustedAlign;
- if (const auto *RT = T->getAs<RecordType>()) {
+ if (const auto *RT = T->getAsCanonical<RecordType>()) {
const ASTRecordLayout &Layout = getASTRecordLayout(RT->getOriginalDecl());
UnadjustedAlign = toBits(Layout.getUnadjustedAlignment());
- } else if (const auto *ObjCI = T->getAs<ObjCInterfaceType>()) {
+ } else if (const auto *ObjCI = T->getAsCanonical<ObjCInterfaceType>()) {
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
UnadjustedAlign = toBits(Layout.getUnadjustedAlignment());
} else {
@@ -2694,9 +2691,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
if (!Target->allowsLargerPreferedTypeAlignment())
return ABIAlign;
- if (const auto *RT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
-
+ if (const auto *RD = T->getAsRecordDecl()) {
// When used as part of a typedef, or together with a 'packed' attribute,
// the 'aligned' attribute can be used to decrease alignment. Note that the
// 'packed' case is already taken into consideration when computing the
@@ -2717,11 +2712,8 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
// possible.
if (const auto *CT = T->getAs<ComplexType>())
T = CT->getElementType().getTypePtr();
- if (const auto *ET = T->getAs<EnumType>())
- T = ET->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->getIntegerType()
- .getTypePtr();
+ if (const auto *ED = T->getAsEnumDecl())
+ T = ED->getIntegerType().getTypePtr();
if (T->isSpecificBuiltinType(BuiltinType::Double) ||
T->isSpecificBuiltinType(BuiltinType::LongLong) ||
T->isSpecificBuiltinType(BuiltinType::ULongLong) ||
@@ -2887,12 +2879,10 @@ structHasUniqueObjectRepresentations(const ASTContext &Context,
static std::optional<int64_t>
getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context,
bool CheckIfTriviallyCopyable) {
- if (Field->getType()->isRecordType()) {
- const RecordDecl *RD = Field->getType()->getAsRecordDecl();
- if (!RD->isUnion())
- return structHasUniqueObjectRepresentations(Context, RD,
- CheckIfTriviallyCopyable);
- }
+ if (const auto *RD = Field->getType()->getAsRecordDecl();
+ RD && !RD->isUnion())
+ return structHasUniqueObjectRepresentations(Context, RD,
+ CheckIfTriviallyCopyable);
// A _BitInt type may not be unique if it has padding bits
// but if it is a bitfield the padding bits are not used.
@@ -3040,17 +3030,14 @@ bool ASTContext::hasUniqueObjectRepresentations(
return true;
}
- // All other pointers (except __ptrauth pointers) are unique.
+ // All other pointers are unique.
if (Ty->isPointerType())
return !Ty.hasAddressDiscriminatedPointerAuth();
if (const auto *MPT = Ty->getAs<MemberPointerType>())
return !ABI->getMemberPointerInfo(MPT).HasPadding;
- if (Ty->isRecordType()) {
- const RecordDecl *Record =
- Ty->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
-
+ if (const auto *Record = Ty->getAsRecordDecl()) {
if (Record->isInvalidDecl())
return false;
@@ -3422,10 +3409,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
// type, or an unsigned integer type.
//
// So we have to treat enum types as integers.
- QualType UnderlyingType = cast<EnumType>(T)
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->getIntegerType();
+ QualType UnderlyingType = T->castAsEnumDecl()->getIntegerType();
return encodeTypeForFunctionPointerAuth(
Ctx, OS, UnderlyingType.isNull() ? Ctx.IntTy : UnderlyingType);
}
@@ -3569,8 +3553,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
llvm_unreachable("should never get here");
}
case Type::Record: {
- const RecordDecl *RD =
- T->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
+ const RecordDecl *RD = T->castAsCanonical<RecordType>()->getOriginalDecl();
const IdentifierInfo *II = RD->getIdentifier();
// In C++, an immediate typedef of an anonymous struct or union
@@ -5333,7 +5316,8 @@ ASTContext::getTypedefType(ElaboratedTypeKeyword Keyword,
}
llvm::FoldingSetNodeID ID;
- TypedefType::Profile(ID, Keyword, Qualifier, Decl, UnderlyingType);
+ TypedefType::Profile(ID, Keyword, Qualifier, Decl,
+ *TypeMatchesDeclOrNone ? QualType() : UnderlyingType);
void *InsertPos = nullptr;
if (FoldingSetPlaceholder<TypedefType> *Placeholder =
@@ -5484,18 +5468,15 @@ TagType *ASTContext::getTagTypeInternal(ElaboratedTypeKeyword Keyword,
return T;
}
-static bool getNonInjectedClassName(const TagDecl *&TD) {
+static const TagDecl *getNonInjectedClassName(const TagDecl *TD) {
if (const auto *RD = dyn_cast<CXXRecordDecl>(TD);
- RD && RD->isInjectedClassName()) {
- TD = cast<TagDecl>(RD->getDeclContext());
- return true;
- }
- return false;
+ RD && RD->isInjectedClassName())
+ return cast<TagDecl>(RD->getDeclContext());
+ return TD;
}
CanQualType ASTContext::getCanonicalTagType(const TagDecl *TD) const {
- ::getNonInjectedClassName(TD);
- TD = TD->getCanonicalDecl();
+ TD = ::getNonInjectedClassName(TD)->getCanonicalDecl();
if (TD->TypeForDecl)
return TD->TypeForDecl->getCanonicalTypeUnqualified();
@@ -5511,40 +5492,42 @@ CanQualType ASTContext::getCanonicalTagType(const TagDecl *TD) const {
QualType ASTContext::getTagType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier Qualifier,
const TagDecl *TD, bool OwnsTag) const {
+
+ const TagDecl *NonInjectedTD = ::getNonInjectedClassName(TD);
+ bool IsInjected = TD != NonInjectedTD;
+
ElaboratedTypeKeyword PreferredKeyword =
- getLangOpts().CPlusPlus
- ? ElaboratedTypeKeyword::None
- : KeywordHelpers::getKeywordForTagTypeKind(TD->getTagKind());
+ getLangOpts().CPlusPlus ? ElaboratedTypeKeyword::None
+ : KeywordHelpers::getKeywordForTagTypeKind(
+ NonInjectedTD->getTagKind());
if (Keyword == PreferredKeyword && !Qualifier && !OwnsTag) {
if (const Type *T = TD->TypeForDecl; T && !T->isCanonicalUnqualified())
return QualType(T, 0);
- bool IsInjected = ::getNonInjectedClassName(TD);
- const Type *CanonicalType = getCanonicalTagType(TD).getTypePtr();
+ const Type *CanonicalType = getCanonicalTagType(NonInjectedTD).getTypePtr();
const Type *T =
getTagTypeInternal(Keyword,
- /*Qualifier=*/std::nullopt, TD,
+ /*Qualifier=*/std::nullopt, NonInjectedTD,
/*OwnsTag=*/false, IsInjected, CanonicalType,
/*WithFoldingSetNode=*/false);
TD->TypeForDecl = T;
return QualType(T, 0);
}
- bool IsInjected = ::getNonInjectedClassName(TD);
-
llvm::FoldingSetNodeID ID;
- TagTypeFoldingSetPlaceholder::Profile(ID, Keyword, Qualifier, TD, OwnsTag,
- IsInjected);
+ TagTypeFoldingSetPlaceholder::Profile(ID, Keyword, Qualifier, NonInjectedTD,
+ OwnsTag, IsInjected);
void *InsertPos = nullptr;
if (TagTypeFoldingSetPlaceholder *T =
TagTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(T->getTagType(), 0);
- const Type *CanonicalType = getCanonicalTagType(TD).getTypePtr();
- TagType *T = getTagTypeInternal(Keyword, Qualifier, TD, OwnsTag, IsInjected,
- CanonicalType, /*WithFoldingSetNode=*/true);
+ const Type *CanonicalType = getCanonicalTagType(NonInjectedTD).getTypePtr();
+ TagType *T =
+ getTagTypeInternal(Keyword, Qualifier, NonInjectedTD, OwnsTag, IsInjected,
+ CanonicalType, /*WithFoldingSetNode=*/true);
TagTypes.InsertNode(TagTypeFoldingSetPlaceholder::fromTagType(T), InsertPos);
return QualType(T, 0);
}
@@ -8362,8 +8345,8 @@ QualType ASTContext::isPromotableBitField(Expr *E) const {
QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
assert(!Promotable.isNull());
assert(isPromotableIntegerType(Promotable));
- if (const auto *ET = Promotable->getAs<EnumType>())
- return ET->getOriginalDecl()->getDefinitionOrSelf()->getPromotionType();
+ if (const auto *ED = Promotable->getAsEnumDecl())
+ return ED->getPromotionType();
if (const auto *BT = Promotable->getAs<BuiltinType>()) {
// C++ [conv.prom]: A prvalue of type char16_t, char32_t, or wchar_t
@@ -8582,10 +8565,9 @@ QualType ASTContext::getObjCSuperType() const {
}
void ASTContext::setCFConstantStringType(QualType T) {
- const auto *TD = T->castAs<TypedefType>();
- CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl());
- const auto *TagType = TD->castAs<RecordType>();
- CFConstantStringTagDecl = TagType->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *TT = T->castAs<TypedefType>();
+ CFConstantStringTypeDecl = cast<TypedefDecl>(TT->getDecl());
+ CFConstantStringTagDecl = TT->castAsRecordDecl();
}
QualType ASTContext::getBlockDescriptorType() const {
@@ -9296,8 +9278,8 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C,
llvm_unreachable("invalid BuiltinType::Kind value");
}
-static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) {
- EnumDecl *Enum = ET->getOriginalDecl()->getDefinitionOrSelf();
+static char ObjCEncodingForEnumDecl(const ASTContext *C, const EnumDecl *ED) {
+ EnumDecl *Enum = ED->getDefinitionOrSelf();
// The encoding of an non-fixed enum type is always 'i', regardless of size.
if (!Enum->isFixed())
@@ -9340,8 +9322,8 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
S += llvm::utostr(Offset);
- if (const auto *ET = T->getAs<EnumType>())
- S += ObjCEncodingForEnumType(Ctx, ET);
+ if (const auto *ET = T->getAsCanonical<EnumType>())
+ S += ObjCEncodingForEnumDecl(Ctx, ET->getOriginalDecl());
else {
const auto *BT = T->castAs<BuiltinType>();
S += getObjCEncodingForPrimitiveType(Ctx, BT);
@@ -9398,7 +9380,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
if (const auto *BT = dyn_cast<BuiltinType>(CT))
S += getObjCEncodingForPrimitiveType(this, BT);
else
- S += ObjCEncodingForEnumType(this, cast<EnumType>(CT));
+ S += ObjCEncodingForEnumDecl(this, cast<EnumType>(CT)->getOriginalDecl());
return;
case Type::Complex:
@@ -9465,7 +9447,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
S += '*';
return;
}
- } else if (const auto *RTy = PointeeTy->getAs<RecordType>()) {
+ } else if (const auto *RTy = PointeeTy->getAsCanonical<RecordType>()) {
const IdentifierInfo *II = RTy->getOriginalDecl()->getIdentifier();
// GCC binary compat: Need to convert "struct objc_class *" to "#".
if (II == &Idents.get("objc_class")) {
@@ -10457,6 +10439,12 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier Qualifier,
assert(Template.getKind() == TemplateName::Template ||
Template.getKind() == TemplateName::UsingTemplate);
+ if (Template.getAsTemplateDecl()->getKind() == Decl::TemplateTemplateParm) {
+ assert(!Qualifier && "unexpected qualified template template parameter");
+ assert(TemplateKeyword == false);
+ return Template;
+ }
+
// FIXME: Canonicalization?
llvm::FoldingSetNodeID ID;
QualifiedTemplateName::Profile(ID, Qualifier, TemplateKeyword, Template);
@@ -11672,9 +11660,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
// Look at the converted type of enum types, since that is the type used
// to pass enum values.
- if (const auto *Enum = paramTy->getAs<EnumType>()) {
- paramTy =
- Enum->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
+ if (const auto *ED = paramTy->getAsEnumDecl()) {
+ paramTy = ED->getIntegerType();
if (paramTy.isNull())
return {};
}
@@ -11832,10 +11819,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
if (LHSClass != RHSClass) {
// Note that we only have special rules for turning block enum
// returns into block int returns, not vice-versa.
- if (const auto *ETy = LHS->getAs<EnumType>()) {
+ if (const auto *ETy = LHS->getAsCanonical<EnumType>()) {
return mergeEnumWithInteger(*this, ETy, RHS, false);
}
- if (const EnumType* ETy = RHS->getAs<EnumType>()) {
+ if (const EnumType *ETy = RHS->getAsCanonical<EnumType>()) {
return mergeEnumWithInteger(*this, ETy, LHS, BlockReturnType);
}
// allow block pointer type to match an 'id' type.
@@ -12265,8 +12252,8 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
//===----------------------------------------------------------------------===//
unsigned ASTContext::getIntWidth(QualType T) const {
- if (const auto *ET = T->getAs<EnumType>())
- T = ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
+ if (const auto *ED = T->getAsEnumDecl())
+ T = ED->getIntegerType();
if (T->isBooleanType())
return 1;
if (const auto *EIT = T->getAs<BitIntType>())
@@ -12291,8 +12278,8 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
// For enums, get the underlying integer type of the enum, and let the general
// integer type signchanging code handle it.
- if (const auto *ETy = T->getAs<EnumType>())
- T = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
+ if (const auto *ED = T->getAsEnumDecl())
+ T = ED->getIntegerType();
switch (T->castAs<BuiltinType>()->getKind()) {
case BuiltinType::Char_U:
@@ -12365,8 +12352,8 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const {
// For enums, get the underlying integer type of the enum, and let the general
// integer type signchanging code handle it.
- if (const auto *ETy = T->getAs<EnumType>())
- T = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
+ if (const auto *ED = T->getAsEnumDecl())
+ T = ED->getIntegerType();
switch (T->castAs<BuiltinType>()->getKind()) {
case BuiltinType::Char_S:
@@ -14208,7 +14195,11 @@ static QualType getCommonNonSugarTypeNode(const ASTContext &Ctx, const Type *X,
FunctionProtoType::ExtProtoInfo EPIX = FX->getExtProtoInfo(),
EPIY = FY->getExtProtoInfo();
assert(EPIX.ExtInfo == EPIY.ExtInfo);
- assert(EPIX.ExtParameterInfos == EPIY.ExtParameterInfos);
+ assert(!EPIX.ExtParameterInfos == !EPIY.ExtParameterInfos);
+ assert(!EPIX.ExtParameterInfos ||
+ llvm::equal(
+ llvm::ArrayRef(EPIX.ExtParameterInfos, FX->getNumParams()),
+ llvm::ArrayRef(EPIY.ExtParameterInfos, FY->getNumParams())));
assert(EPIX.RefQualifier == EPIY.RefQualifier);
assert(EPIX.TypeQuals == EPIY.TypeQuals);
assert(EPIX.Variadic == EPIY.Variadic);
@@ -15203,7 +15194,7 @@ StringRef ASTContext::getCUIDHash() const {
}
const CXXRecordDecl *
-ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) {
+ASTContext::baseForVTableAuthentication(const CXXRecordDecl *ThisClass) const {
assert(ThisClass);
assert(ThisClass->isPolymorphic());
const CXXRecordDecl *PrimaryBase = ThisClass;
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 6299efaf6bbf..fe7f1e5eb031 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -1740,10 +1740,21 @@ ExpectedType ASTNodeImporter::VisitDeducedTemplateSpecializationType(
}
ExpectedType ASTNodeImporter::VisitTagType(const TagType *T) {
- Expected<TagDecl *> ToDeclOrErr = import(T->getOriginalDecl());
+ TagDecl *DeclForType = T->getOriginalDecl();
+ Expected<TagDecl *> ToDeclOrErr = import(DeclForType);
if (!ToDeclOrErr)
return ToDeclOrErr.takeError();
+ if (DeclForType->isUsed()) {
+ // If there is a definition of the 'OriginalDecl', it should be imported to
+ // have all information for the type in the "To" AST. (In some cases no
+ // other reference may exist to the definition decl and it would not be
+ // imported otherwise.)
+ Expected<TagDecl *> ToDefDeclOrErr = import(DeclForType->getDefinition());
+ if (!ToDefDeclOrErr)
+ return ToDefDeclOrErr.takeError();
+ }
+
if (T->isCanonicalUnqualified())
return Importer.getToContext().getCanonicalTagType(*ToDeclOrErr);
@@ -7337,18 +7348,28 @@ ExpectedStmt ASTNodeImporter::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
ToGotoLoc, ToStarLoc, ToTarget);
}
+template <typename StmtClass>
+static ExpectedStmt ImportLoopControlStmt(ASTNodeImporter &NodeImporter,
+ ASTImporter &Importer, StmtClass *S) {
+ Error Err = Error::success();
+ auto ToLoc = NodeImporter.importChecked(Err, S->getKwLoc());
+ auto ToLabelLoc = S->hasLabelTarget()
+ ? NodeImporter.importChecked(Err, S->getLabelLoc())
+ : SourceLocation();
+ auto ToDecl = S->hasLabelTarget()
+ ? NodeImporter.importChecked(Err, S->getLabelDecl())
+ : nullptr;
+ if (Err)
+ return std::move(Err);
+ return new (Importer.getToContext()) StmtClass(ToLoc, ToLabelLoc, ToDecl);
+}
+
ExpectedStmt ASTNodeImporter::VisitContinueStmt(ContinueStmt *S) {
- ExpectedSLoc ToContinueLocOrErr = import(S->getContinueLoc());
- if (!ToContinueLocOrErr)
- return ToContinueLocOrErr.takeError();
- return new (Importer.getToContext()) ContinueStmt(*ToContinueLocOrErr);
+ return ImportLoopControlStmt(*this, Importer, S);
}
ExpectedStmt ASTNodeImporter::VisitBreakStmt(BreakStmt *S) {
- auto ToBreakLocOrErr = import(S->getBreakLoc());
- if (!ToBreakLocOrErr)
- return ToBreakLocOrErr.takeError();
- return new (Importer.getToContext()) BreakStmt(*ToBreakLocOrErr);
+ return ImportLoopControlStmt(*this, Importer, S);
}
ExpectedStmt ASTNodeImporter::VisitReturnStmt(ReturnStmt *S) {
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 6d83de384ee1..1292c30d4758 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -878,10 +878,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
// Treat the enumeration as its underlying type and use the builtin type
// class comparison.
if (T1->getTypeClass() == Type::Enum) {
- T1 = T1->getAs<EnumType>()->getOriginalDecl()->getIntegerType();
+ T1 = cast<EnumType>(T1)->getOriginalDecl()->getIntegerType();
assert(T2->isBuiltinType() && !T1.isNull()); // Sanity check
} else if (T2->getTypeClass() == Type::Enum) {
- T2 = T2->getAs<EnumType>()->getOriginalDecl()->getIntegerType();
+ T2 = cast<EnumType>(T2)->getOriginalDecl()->getIntegerType();
assert(T1->isBuiltinType() && !T2.isNull()); // Sanity check
}
TC = Type::Builtin;
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index e3235d34e230..a21358338250 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -62,7 +62,7 @@ public:
OptionScope(Compiler<Emitter> *Ctx, bool NewDiscardResult,
bool NewInitializing, bool NewToLValue)
: Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
- OldInitializing(Ctx->Initializing), OldToLValue(NewToLValue) {
+ OldInitializing(Ctx->Initializing), OldToLValue(Ctx->ToLValue) {
Ctx->DiscardResult = NewDiscardResult;
Ctx->Initializing = NewInitializing;
Ctx->ToLValue = NewToLValue;
@@ -559,8 +559,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
// Possibly diagnose casts to enum types if the target type does not
// have a fixed size.
if (Ctx.getLangOpts().CPlusPlus && CE->getType()->isEnumeralType()) {
- const auto *ET = CE->getType().getCanonicalType()->castAs<EnumType>();
- const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *ED = CE->getType()->castAsEnumDecl();
if (!ED->isFixed()) {
if (!this->emitCheckEnumValue(*FromT, ED, CE))
return false;
@@ -943,7 +942,7 @@ bool Compiler<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
if (!Result)
return false;
if (DiscardResult)
- return this->emitPop(*T, BO);
+ return this->emitPopBool(BO);
if (T != PT_Bool)
return this->emitCast(PT_Bool, *T, BO);
return true;
@@ -1377,14 +1376,20 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
template <class Emitter>
bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) {
+ const Expr *LHS = E->getLHS();
+ const Expr *RHS = E->getRHS();
assert(!E->isCommaOp() &&
"Comma op should be handled in VisitBinaryOperator");
assert(E->getType()->isVectorType());
- assert(E->getLHS()->getType()->isVectorType());
- assert(E->getRHS()->getType()->isVectorType());
+ assert(LHS->getType()->isVectorType());
+ assert(RHS->getType()->isVectorType());
+
+ // We can only handle vectors with primitive element types.
+ if (!canClassify(LHS->getType()->castAs<VectorType>()->getElementType()))
+ return false;
// Prepare storage for result.
- if (!Initializing && !E->isCompoundAssignmentOp()) {
+ if (!Initializing && !E->isCompoundAssignmentOp() && !E->isAssignmentOp()) {
UnsignedOrNone LocalIndex = allocateTemporary(E);
if (!LocalIndex)
return false;
@@ -1392,8 +1397,6 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) {
return false;
}
- const Expr *LHS = E->getLHS();
- const Expr *RHS = E->getRHS();
const auto *VecTy = E->getType()->getAs<VectorType>();
auto Op = E->isCompoundAssignmentOp()
? BinaryOperator::getOpForCompoundAssignment(E->getOpcode())
@@ -1403,6 +1406,21 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) {
PrimType RHSElemT = this->classifyVectorElementType(RHS->getType());
PrimType ResultElemT = this->classifyVectorElementType(E->getType());
+ if (E->getOpcode() == BO_Assign) {
+ assert(Ctx.getASTContext().hasSameUnqualifiedType(
+ LHS->getType()->castAs<VectorType>()->getElementType(),
+ RHS->getType()->castAs<VectorType>()->getElementType()));
+ if (!this->visit(LHS))
+ return false;
+ if (!this->visit(RHS))
+ return false;
+ if (!this->emitCopyArray(ElemT, 0, 0, VecTy->getNumElements(), E))
+ return false;
+ if (DiscardResult)
+ return this->emitPopPtr(E);
+ return true;
+ }
+
// Evaluate LHS and save value to LHSOffset.
unsigned LHSOffset =
this->allocateLocalPrimitive(LHS, PT_Ptr, /*IsConst=*/true);
@@ -2248,7 +2266,9 @@ bool Compiler<Emitter>::VisitUnaryExprOrTypeTraitExpr(
assert(VAT);
if (VAT->getElementType()->isArrayType()) {
std::optional<APSInt> Res =
- VAT->getSizeExpr()->getIntegerConstantExpr(ASTCtx);
+ VAT->getSizeExpr()
+ ? VAT->getSizeExpr()->getIntegerConstantExpr(ASTCtx)
+ : std::nullopt;
if (Res) {
if (DiscardResult)
return true;
@@ -2892,25 +2912,20 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
OptPrimType SubExprT = classify(SubExpr);
bool IsStatic = E->getStorageDuration() == SD_Static;
if (IsStatic) {
- std::optional<unsigned> GlobalIndex = P.createGlobal(E);
+
+ UnsignedOrNone GlobalIndex = P.createGlobal(E);
if (!GlobalIndex)
return false;
const LifetimeExtendedTemporaryDecl *TempDecl =
E->getLifetimeExtendedTemporaryDecl();
- if (IsStatic)
- assert(TempDecl);
+ assert(TempDecl);
if (SubExprT) {
if (!this->visit(SubExpr))
return false;
- if (IsStatic) {
- if (!this->emitInitGlobalTemp(*SubExprT, *GlobalIndex, TempDecl, E))
- return false;
- } else {
- if (!this->emitInitGlobal(*SubExprT, *GlobalIndex, E))
- return false;
- }
+ if (!this->emitInitGlobalTemp(*SubExprT, *GlobalIndex, TempDecl, E))
+ return false;
return this->emitGetPtrGlobal(*GlobalIndex, E);
}
@@ -2921,9 +2936,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
return false;
if (!this->visitInitializer(SubExpr))
return false;
- if (IsStatic)
- return this->emitInitGlobalTempComp(TempDecl, E);
- return true;
+ return this->emitInitGlobalTempComp(TempDecl, E);
}
// For everyhing else, use local variables.
@@ -2989,7 +3002,7 @@ bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
if (T && !E->isLValue())
return this->delegate(Init);
- std::optional<unsigned> GlobalIndex = P.createGlobal(E);
+ UnsignedOrNone GlobalIndex = P.createGlobal(E);
if (!GlobalIndex)
return false;
@@ -3333,7 +3346,7 @@ bool Compiler<Emitter>::VisitSourceLocExpr(const SourceLocExpr *E) {
auto *UGCD = cast<UnnamedGlobalConstantDecl>(BaseDecl);
- std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(UGCD);
+ UnsignedOrNone GlobalIndex = P.getOrCreateGlobal(UGCD);
if (!GlobalIndex)
return false;
@@ -3856,7 +3869,7 @@ bool Compiler<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
if (!RD->isCompleteDefinition())
return this->emitDummyPtr(GuidDecl, E);
- std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(GuidDecl);
+ UnsignedOrNone GlobalIndex = P.getOrCreateGlobal(GuidDecl);
if (!GlobalIndex)
return false;
if (!this->emitGetPtrGlobal(*GlobalIndex, E))
@@ -3879,6 +3892,8 @@ bool Compiler<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
template <class Emitter>
bool Compiler<Emitter>::VisitRequiresExpr(const RequiresExpr *E) {
assert(classifyPrim(E->getType()) == PT_Bool);
+ if (E->isValueDependent())
+ return false;
if (DiscardResult)
return true;
return this->emitConstBool(E->isSatisfied(), E);
@@ -4169,6 +4184,31 @@ template <class Emitter> bool Compiler<Emitter>::delegate(const Expr *E) {
return this->Visit(E);
}
+static const Expr *stripCheckedDerivedToBaseCasts(const Expr *E) {
+ if (const auto *PE = dyn_cast<ParenExpr>(E))
+ return stripCheckedDerivedToBaseCasts(PE->getSubExpr());
+
+ if (const auto *CE = dyn_cast<CastExpr>(E);
+ CE &&
+ (CE->getCastKind() == CK_DerivedToBase || CE->getCastKind() == CK_NoOp))
+ return stripCheckedDerivedToBaseCasts(CE->getSubExpr());
+
+ return E;
+}
+
+static const Expr *stripDerivedToBaseCasts(const Expr *E) {
+ if (const auto *PE = dyn_cast<ParenExpr>(E))
+ return stripDerivedToBaseCasts(PE->getSubExpr());
+
+ if (const auto *CE = dyn_cast<CastExpr>(E);
+ CE && (CE->getCastKind() == CK_DerivedToBase ||
+ CE->getCastKind() == CK_UncheckedDerivedToBase ||
+ CE->getCastKind() == CK_NoOp))
+ return stripDerivedToBaseCasts(CE->getSubExpr());
+
+ return E;
+}
+
template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) {
if (E->getType().isNull())
return false;
@@ -4177,9 +4217,8 @@ template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) {
return this->discard(E);
// Create local variable to hold the return value.
- if (!E->isGLValue() && !E->getType()->isAnyComplexType() &&
- !canClassify(E->getType())) {
- UnsignedOrNone LocalIndex = allocateLocal(E);
+ if (!E->isGLValue() && !canClassify(E->getType())) {
+ UnsignedOrNone LocalIndex = allocateLocal(stripDerivedToBaseCasts(E));
if (!LocalIndex)
return false;
@@ -4608,8 +4647,8 @@ UnsignedOrNone Compiler<Emitter>::allocateTemporary(const Expr *E) {
template <class Emitter>
const RecordType *Compiler<Emitter>::getRecordTy(QualType Ty) {
if (const PointerType *PT = dyn_cast<PointerType>(Ty))
- return PT->getPointeeType()->getAs<RecordType>();
- return Ty->getAs<RecordType>();
+ return PT->getPointeeType()->getAsCanonical<RecordType>();
+ return Ty->getAsCanonical<RecordType>();
}
template <class Emitter> Record *Compiler<Emitter>::getRecord(QualType Ty) {
@@ -4822,7 +4861,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
DeclScope<Emitter> LocalScope(this, VD);
// We've already seen and initialized this global.
- if (std::optional<unsigned> GlobalIndex = P.getGlobal(VD)) {
+ if (UnsignedOrNone GlobalIndex = P.getGlobal(VD)) {
if (P.getPtrGlobal(*GlobalIndex).isInitialized())
return checkDecl();
@@ -4831,7 +4870,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
return Init && checkDecl() && initGlobal(*GlobalIndex);
}
- std::optional<unsigned> GlobalIndex = P.createGlobal(VD, Init);
+ UnsignedOrNone GlobalIndex = P.createGlobal(VD, Init);
if (!GlobalIndex)
return false;
@@ -5057,18 +5096,6 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E,
return true;
}
-static const Expr *stripDerivedToBaseCasts(const Expr *E) {
- if (const auto *PE = dyn_cast<ParenExpr>(E))
- return stripDerivedToBaseCasts(PE->getSubExpr());
-
- if (const auto *CE = dyn_cast<CastExpr>(E);
- CE &&
- (CE->getCastKind() == CK_DerivedToBase || CE->getCastKind() == CK_NoOp))
- return stripDerivedToBaseCasts(CE->getSubExpr());
-
- return E;
-}
-
template <class Emitter>
bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
const FunctionDecl *FuncDecl = E->getDirectCallee();
@@ -5173,7 +5200,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
const auto *InstancePtr = MC->getImplicitObjectArgument();
if (isa_and_nonnull<CXXDestructorDecl>(CompilingFunction) ||
isa_and_nonnull<CXXConstructorDecl>(CompilingFunction)) {
- const auto *Stripped = stripDerivedToBaseCasts(InstancePtr);
+ const auto *Stripped = stripCheckedDerivedToBaseCasts(InstancePtr);
if (isa<CXXThisExpr>(Stripped)) {
FuncDecl =
cast<CXXMethodDecl>(FuncDecl)->getCorrespondingMethodInClass(
@@ -5228,6 +5255,12 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
const Function *Func = getFunction(FuncDecl);
if (!Func)
return false;
+
+ // In error cases, the function may be called with fewer arguments than
+ // parameters.
+ if (E->getNumArgs() < Func->getNumWrittenParams())
+ return false;
+
assert(HasRVO == Func->hasRVO());
bool HasQualifier = false;
@@ -6244,26 +6277,21 @@ bool Compiler<Emitter>::compileDestructor(const CXXDestructorDecl *Dtor) {
// First, destroy all fields.
for (const Record::Field &Field : llvm::reverse(R->fields())) {
const Descriptor *D = Field.Desc;
- if (!D->isPrimitive() && !D->isPrimitiveArray()) {
- if (!this->emitGetPtrField(Field.Offset, SourceInfo{}))
- return false;
- if (!this->emitDestruction(D, SourceInfo{}))
- return false;
- if (!this->emitPopPtr(SourceInfo{}))
- return false;
- }
+ if (D->hasTrivialDtor())
+ continue;
+ if (!this->emitGetPtrField(Field.Offset, SourceInfo{}))
+ return false;
+ if (!this->emitDestructionPop(D, SourceInfo{}))
+ return false;
}
}
for (const Record::Base &Base : llvm::reverse(R->bases())) {
- if (Base.R->isAnonymousUnion())
+ if (Base.R->hasTrivialDtor())
continue;
-
if (!this->emitGetPtrBase(Base.Offset, SourceInfo{}))
return false;
- if (!this->emitRecordDestruction(Base.R, {}))
- return false;
- if (!this->emitPopPtr(SourceInfo{}))
+ if (!this->emitRecordDestructionPop(Base.R, {}))
return false;
}
@@ -6775,7 +6803,7 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
return F && this->emitGetFnPtr(F, E);
}
if (const auto *TPOD = dyn_cast<TemplateParamObjectDecl>(D)) {
- if (std::optional<unsigned> Index = P.getOrCreateGlobal(D)) {
+ if (UnsignedOrNone Index = P.getOrCreateGlobal(D)) {
if (!this->emitGetPtrGlobal(*Index, E))
return false;
if (OptPrimType T = classify(E->getType())) {
@@ -7160,71 +7188,56 @@ bool Compiler<Emitter>::emitComplexComparison(const Expr *LHS, const Expr *RHS,
/// on the stack.
/// Emit destruction of record types (or arrays of record types).
template <class Emitter>
-bool Compiler<Emitter>::emitRecordDestruction(const Record *R, SourceInfo Loc) {
+bool Compiler<Emitter>::emitRecordDestructionPop(const Record *R,
+ SourceInfo Loc) {
assert(R);
- assert(!R->isAnonymousUnion());
+ assert(!R->hasTrivialDtor());
const CXXDestructorDecl *Dtor = R->getDestructor();
- if (!Dtor || Dtor->isTrivial())
- return true;
-
assert(Dtor);
const Function *DtorFunc = getFunction(Dtor);
if (!DtorFunc)
return false;
assert(DtorFunc->hasThisPointer());
assert(DtorFunc->getNumParams() == 1);
- if (!this->emitDupPtr(Loc))
- return false;
return this->emitCall(DtorFunc, 0, Loc);
}
/// When calling this, we have a pointer of the local-to-destroy
/// on the stack.
/// Emit destruction of record types (or arrays of record types).
template <class Emitter>
-bool Compiler<Emitter>::emitDestruction(const Descriptor *Desc,
- SourceInfo Loc) {
+bool Compiler<Emitter>::emitDestructionPop(const Descriptor *Desc,
+ SourceInfo Loc) {
assert(Desc);
- assert(!Desc->isPrimitive());
- assert(!Desc->isPrimitiveArray());
+ assert(!Desc->hasTrivialDtor());
// Arrays.
if (Desc->isArray()) {
const Descriptor *ElemDesc = Desc->ElemDesc;
assert(ElemDesc);
- // Don't need to do anything for these.
- if (ElemDesc->isPrimitiveArray())
- return true;
+ unsigned N = Desc->getNumElems();
+ if (N == 0)
+ return this->emitPopPtr(Loc);
- // If this is an array of record types, check if we need
- // to call the element destructors at all. If not, try
- // to save the work.
- if (const Record *ElemRecord = ElemDesc->ElemRecord) {
- if (const CXXDestructorDecl *Dtor = ElemRecord->getDestructor();
- !Dtor || Dtor->isTrivial())
- return true;
- }
-
- if (unsigned N = Desc->getNumElems()) {
- for (ssize_t I = N - 1; I >= 0; --I) {
- if (!this->emitConstUint64(I, Loc))
- return false;
- if (!this->emitArrayElemPtrUint64(Loc))
- return false;
- if (!this->emitDestruction(ElemDesc, Loc))
- return false;
- if (!this->emitPopPtr(Loc))
- return false;
- }
+ for (ssize_t I = N - 1; I >= 1; --I) {
+ if (!this->emitConstUint64(I, Loc))
+ return false;
+ if (!this->emitArrayElemPtrUint64(Loc))
+ return false;
+ if (!this->emitDestructionPop(ElemDesc, Loc))
+ return false;
}
- return true;
+ // Last iteration, removes the instance pointer from the stack.
+ if (!this->emitConstUint64(0, Loc))
+ return false;
+ if (!this->emitArrayElemPtrPopUint64(Loc))
+ return false;
+ return this->emitDestructionPop(ElemDesc, Loc);
}
assert(Desc->ElemRecord);
- if (Desc->ElemRecord->isAnonymousUnion())
- return true;
-
- return this->emitRecordDestruction(Desc->ElemRecord, Loc);
+ assert(!Desc->ElemRecord->hasTrivialDtor());
+ return this->emitRecordDestructionPop(Desc->ElemRecord, Loc);
}
/// Create a dummy pointer for the given decl (or expr) and
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index 475faee4d3fd..bb8c66042731 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -391,8 +391,8 @@ private:
bool emitComplexBoolCast(const Expr *E);
bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
const BinaryOperator *E);
- bool emitRecordDestruction(const Record *R, SourceInfo Loc);
- bool emitDestruction(const Descriptor *Desc, SourceInfo Loc);
+ bool emitRecordDestructionPop(const Record *R, SourceInfo Loc);
+ bool emitDestructionPop(const Descriptor *Desc, SourceInfo Loc);
bool emitDummyPtr(const DeclTy &D, const Expr *E);
bool emitFloat(const APFloat &F, const Expr *E);
unsigned collectBaseOffset(const QualType BaseType,
@@ -587,11 +587,9 @@ public:
if (!this->Ctx->emitGetPtrLocal(Local.Offset, E))
return false;
- if (!this->Ctx->emitDestruction(Local.Desc, Local.Desc->getLoc()))
+ if (!this->Ctx->emitDestructionPop(Local.Desc, Local.Desc->getLoc()))
return false;
- if (!this->Ctx->emitPopPtr(E))
- return false;
removeIfStoredOpaqueValue(Local);
}
return true;
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index 36eb7607e70b..859899668146 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -91,7 +91,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
#endif
}
- Result = Res.toAPValue();
+ Result = Res.stealAPValue();
return true;
}
@@ -121,7 +121,7 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result,
#endif
}
- Result = Res.toAPValue();
+ Result = Res.stealAPValue();
return true;
}
@@ -153,7 +153,7 @@ bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
#endif
}
- Result = Res.toAPValue();
+ Result = Res.stealAPValue();
return true;
}
@@ -364,8 +364,7 @@ OptPrimType Context::classify(QualType T) const {
return integralTypeToPrimTypeU(BT->getNumBits());
}
- if (const auto *ET = T->getAs<EnumType>()) {
- const auto *D = ET->getOriginalDecl()->getDefinitionOrSelf();
+ if (const auto *D = T->getAsEnumDecl()) {
if (!D->isComplete())
return std::nullopt;
return classify(D->getIntegerType());
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp
index 9ecc7b673cf2..0a819599287e 100644
--- a/clang/lib/AST/ByteCode/Descriptor.cpp
+++ b/clang/lib/AST/ByteCode/Descriptor.cpp
@@ -50,14 +50,6 @@ static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) {
}
template <typename T>
-static void moveTy(Block *, std::byte *Src, std::byte *Dst,
- const Descriptor *) {
- auto *SrcPtr = reinterpret_cast<T *>(Src);
- auto *DstPtr = reinterpret_cast<T *>(Dst);
- new (DstPtr) T(std::move(*SrcPtr));
-}
-
-template <typename T>
static void ctorArrayTy(Block *, std::byte *Ptr, bool, bool, bool, bool, bool,
const Descriptor *D) {
new (Ptr) InitMapPtr(std::nullopt);
@@ -85,28 +77,6 @@ static void dtorArrayTy(Block *, std::byte *Ptr, const Descriptor *D) {
}
}
-template <typename T>
-static void moveArrayTy(Block *, std::byte *Src, std::byte *Dst,
- const Descriptor *D) {
- InitMapPtr &SrcIMP = *reinterpret_cast<InitMapPtr *>(Src);
- if (SrcIMP) {
- // We only ever invoke the moveFunc when moving block contents to a
- // DeadBlock. DeadBlocks don't need InitMaps, so we destroy them here.
- SrcIMP = std::nullopt;
- }
- Src += sizeof(InitMapPtr);
- Dst += sizeof(InitMapPtr);
- if constexpr (!needsCtor<T>()) {
- std::memcpy(Dst, Src, D->getNumElems() * D->getElemSize());
- } else {
- for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
- auto *SrcPtr = &reinterpret_cast<T *>(Src)[I];
- auto *DstPtr = &reinterpret_cast<T *>(Dst)[I];
- new (DstPtr) T(std::move(*SrcPtr));
- }
- }
-}
-
static void ctorArrayDesc(Block *B, std::byte *Ptr, bool IsConst,
bool IsMutable, bool IsVolatile, bool IsActive,
bool InUnion, const Descriptor *D) {
@@ -144,12 +114,14 @@ static void dtorArrayDesc(Block *B, std::byte *Ptr, const Descriptor *D) {
D->ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
unsigned ElemOffset = 0;
- for (unsigned I = 0; I < NumElems; ++I, ElemOffset += ElemSize) {
+ auto Dtor = D->ElemDesc->DtorFn;
+ assert(Dtor &&
+ "a composite array without an elem dtor shouldn't have a dtor itself");
+ for (unsigned I = 0; I != NumElems; ++I, ElemOffset += ElemSize) {
auto *ElemPtr = Ptr + ElemOffset;
auto *Desc = reinterpret_cast<InlineDescriptor *>(ElemPtr);
auto *ElemLoc = reinterpret_cast<std::byte *>(Desc + 1);
- if (auto Fn = D->ElemDesc->DtorFn)
- Fn(B, ElemLoc, D->ElemDesc);
+ Dtor(B, ElemLoc, D->ElemDesc);
}
}
@@ -246,34 +218,59 @@ static void dtorRecord(Block *B, std::byte *Ptr, const Descriptor *D) {
destroyBase(B, Ptr, F.Desc, F.Offset);
}
-static BlockCtorFn getCtorPrim(PrimType Type) {
- // Floating types are special. They are primitives, but need their
- // constructor called.
- if (Type == PT_Float)
+/// Whether a record needs its descriptor dtor function called.
+static bool needsRecordDtor(const Record *R) {
+ for (const auto &B : R->bases()) {
+ if (B.Desc->DtorFn)
+ return true;
+ }
+
+ for (const auto &F : R->fields()) {
+ if (F.Desc->DtorFn)
+ return true;
+ }
+
+ for (const auto &V : R->virtual_bases()) {
+ if (V.Desc->DtorFn)
+ return true;
+ }
+ return false;
+}
+
+static BlockCtorFn getCtorPrim(PrimType T) {
+ switch (T) {
+ case PT_Float:
return ctorTy<PrimConv<PT_Float>::T>;
- if (Type == PT_IntAP)
+ case PT_IntAP:
return ctorTy<PrimConv<PT_IntAP>::T>;
- if (Type == PT_IntAPS)
+ case PT_IntAPS:
return ctorTy<PrimConv<PT_IntAPS>::T>;
- if (Type == PT_MemberPtr)
+ case PT_Ptr:
+ return ctorTy<PrimConv<PT_Ptr>::T>;
+ case PT_MemberPtr:
return ctorTy<PrimConv<PT_MemberPtr>::T>;
-
- COMPOSITE_TYPE_SWITCH(Type, return ctorTy<T>, return nullptr);
+ default:
+ return nullptr;
+ }
+ llvm_unreachable("Unhandled PrimType");
}
-static BlockDtorFn getDtorPrim(PrimType Type) {
- // Floating types are special. They are primitives, but need their
- // destructor called, since they might allocate memory.
- if (Type == PT_Float)
+static BlockDtorFn getDtorPrim(PrimType T) {
+ switch (T) {
+ case PT_Float:
return dtorTy<PrimConv<PT_Float>::T>;
- if (Type == PT_IntAP)
+ case PT_IntAP:
return dtorTy<PrimConv<PT_IntAP>::T>;
- if (Type == PT_IntAPS)
+ case PT_IntAPS:
return dtorTy<PrimConv<PT_IntAPS>::T>;
- if (Type == PT_MemberPtr)
+ case PT_Ptr:
+ return dtorTy<PrimConv<PT_Ptr>::T>;
+ case PT_MemberPtr:
return dtorTy<PrimConv<PT_MemberPtr>::T>;
-
- COMPOSITE_TYPE_SWITCH(Type, return dtorTy<T>, return nullptr);
+ default:
+ return nullptr;
+ }
+ llvm_unreachable("Unhandled PrimType");
}
static BlockCtorFn getCtorArrayPrim(PrimType Type) {
@@ -336,7 +333,7 @@ Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy,
AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),
ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),
IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc),
- DtorFn(dtorArrayDesc) {
+ DtorFn(Elem->DtorFn ? dtorArrayDesc : nullptr) {
assert(Source && "Missing source");
}
@@ -347,7 +344,7 @@ Descriptor::Descriptor(const DeclTy &D, const Descriptor *Elem, MetadataSize MD,
Size(UnknownSizeMark), MDSize(MD.value_or(0)),
AllocSize(MDSize + alignof(void *)), ElemDesc(Elem), IsConst(true),
IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
- CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc) {
+ CtorFn(ctorArrayDesc), DtorFn(Elem->DtorFn ? dtorArrayDesc : nullptr) {
assert(Source && "Missing source");
}
@@ -359,7 +356,7 @@ Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,
Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),
IsTemporary(IsTemporary), IsVolatile(IsVolatile), CtorFn(ctorRecord),
- DtorFn(dtorRecord) {
+ DtorFn(needsRecordDtor(R) ? dtorRecord : nullptr) {
assert(Source && "Missing source");
}
@@ -460,8 +457,7 @@ bool Descriptor::hasTrivialDtor() const {
if (isRecord()) {
assert(ElemRecord);
- const CXXDestructorDecl *Dtor = ElemRecord->getDestructor();
- return !Dtor || Dtor->isTrivial();
+ return ElemRecord->hasTrivialDtor();
}
if (!ElemDesc)
diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp
index 58e6d1a722af..ab3b9f7c3b1d 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -44,7 +44,20 @@ inline static std::string printArg(Program &P, CodePtr &OpPC) {
std::string Result;
llvm::raw_string_ostream SS(Result);
auto Arg = OpPC.read<T>();
- SS << Arg;
+ // Make sure we print the integral value of chars.
+ if constexpr (std::is_integral_v<T>) {
+ if constexpr (sizeof(T) == 1) {
+ if constexpr (std::is_signed_v<T>)
+ SS << static_cast<int32_t>(Arg);
+ else
+ SS << static_cast<uint32_t>(Arg);
+ } else {
+ SS << Arg;
+ }
+ } else {
+ SS << Arg;
+ }
+
return Result;
}
}
@@ -549,41 +562,17 @@ LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
}
LLVM_DUMP_METHOD void EvaluationResult::dump() const {
- assert(Ctx);
auto &OS = llvm::errs();
- const ASTContext &ASTCtx = Ctx->getASTContext();
- switch (Kind) {
- case Empty:
+ if (empty()) {
OS << "Empty\n";
- break;
- case RValue:
- OS << "RValue: ";
- std::get<APValue>(Value).dump(OS, ASTCtx);
- break;
- case LValue: {
- assert(Source);
- QualType SourceType;
- if (const auto *D = dyn_cast<const Decl *>(Source)) {
- if (const auto *VD = dyn_cast<ValueDecl>(D))
- SourceType = VD->getType();
- } else if (const auto *E = dyn_cast<const Expr *>(Source)) {
- SourceType = E->getType();
- }
-
- OS << "LValue: ";
- if (const auto *P = std::get_if<Pointer>(&Value))
- P->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
- else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
- FP->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
- OS << "\n";
- break;
- }
- case Invalid:
+ } else if (isInvalid()) {
OS << "Invalid\n";
- break;
- case Valid:
- OS << "Valid\n";
- break;
+ } else {
+ OS << "Value: ";
+#ifndef NDEBUG
+ assert(Ctx);
+ Value.dump(OS, Ctx->getASTContext());
+#endif
}
}
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index 1ebadae811bd..d0aa8d8df236 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -184,7 +184,7 @@ template <PrimType OpType> bool EvalEmitter::emitRet(const SourceInfo &Info) {
return true;
using T = typename PrimConv<OpType>::T;
- EvalResult.setValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(S.Stk.pop<T>().toAPValue(Ctx.getASTContext()));
return true;
}
@@ -195,7 +195,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.isFunctionPointer()) {
- EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
return true;
}
@@ -213,6 +213,9 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
if (!Ptr.isZero() && !Ptr.isDereferencable())
return false;
+ if (Ptr.pointsToStringLiteral() && Ptr.isArrayRoot())
+ return false;
+
if (!Ptr.isZero() && !CheckFinalLoad(S, OpPC, Ptr))
return false;
@@ -224,7 +227,7 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
if (std::optional<APValue> V =
Ptr.toRValue(Ctx, EvalResult.getSourceType())) {
- EvalResult.setValue(*V);
+ EvalResult.takeValue(std::move(*V));
} else {
return false;
}
@@ -233,14 +236,14 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
// the result, even if the pointer is dead.
// This will later be diagnosed by CheckLValueConstantExpression.
if (Ptr.isBlockPointer() && !Ptr.block()->isStatic()) {
- EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
return true;
}
if (!Ptr.isLive() && !Ptr.isTemporary())
return false;
- EvalResult.setValue(Ptr.toAPValue(Ctx.getASTContext()));
+ EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext()));
}
return true;
@@ -261,7 +264,7 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
if (std::optional<APValue> APV =
Ptr.toRValue(S.getASTContext(), EvalResult.getSourceType())) {
- EvalResult.setValue(*APV);
+ EvalResult.takeValue(std::move(*APV));
return true;
}
@@ -328,7 +331,7 @@ bool EvalEmitter::emitDestroy(uint32_t I, const SourceInfo &Info) {
/// This is what we do here.
void EvalEmitter::updateGlobalTemporaries() {
for (const auto &[E, Temp] : S.SeenGlobalTemporaries) {
- if (std::optional<unsigned> GlobalIndex = P.getGlobal(E)) {
+ if (UnsignedOrNone GlobalIndex = P.getGlobal(E)) {
const Pointer &Ptr = P.getPtrGlobal(*GlobalIndex);
APValue *Cached = Temp->getOrCreateValue(true);
diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp
index b11531f4296a..ba818788d702 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.cpp
+++ b/clang/lib/AST/ByteCode/EvaluationResult.cpp
@@ -8,6 +8,7 @@
#include "EvaluationResult.h"
#include "InterpState.h"
+#include "Pointer.h"
#include "Record.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
@@ -16,41 +17,6 @@
namespace clang {
namespace interp {
-APValue EvaluationResult::toAPValue() const {
- assert(!empty());
- switch (Kind) {
- case LValue:
- // Either a pointer or a function pointer.
- if (const auto *P = std::get_if<Pointer>(&Value))
- return P->toAPValue(Ctx->getASTContext());
- else if (const auto *FP = std::get_if<FunctionPointer>(&Value))
- return FP->toAPValue(Ctx->getASTContext());
- else
- llvm_unreachable("Unhandled LValue type");
- break;
- case RValue:
- return std::get<APValue>(Value);
- case Valid:
- return APValue();
- default:
- llvm_unreachable("Unhandled result kind?");
- }
-}
-
-std::optional<APValue> EvaluationResult::toRValue() const {
- if (Kind == RValue)
- return toAPValue();
-
- assert(Kind == LValue);
-
- // We have a pointer and want an RValue.
- if (const auto *P = std::get_if<Pointer>(&Value))
- return P->toRValue(*Ctx, getSourceType());
- else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
- return FP->toAPValue(Ctx->getASTContext());
- llvm_unreachable("Unhandled lvalue kind");
-}
-
static void DiagnoseUninitializedSubobject(InterpState &S, SourceLocation Loc,
const FieldDecl *SubObjDecl) {
assert(SubObjDecl && "Subobject declaration does not exist");
@@ -66,8 +32,12 @@ static bool CheckFieldsInitialized(InterpState &S, SourceLocation Loc,
static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
const Pointer &BasePtr,
const ConstantArrayType *CAT) {
- bool Result = true;
size_t NumElems = CAT->getZExtSize();
+
+ if (NumElems == 0)
+ return true;
+
+ bool Result = true;
QualType ElemType = CAT->getElementType();
if (ElemType->isRecordType()) {
@@ -82,8 +52,18 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc,
Result &= CheckArrayInitialized(S, Loc, ElemPtr, ElemCAT);
}
} else {
+ // Primitive arrays.
+ if (S.getContext().canClassify(ElemType)) {
+ if (BasePtr.allElementsInitialized()) {
+ return true;
+ } else {
+ DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
+ return false;
+ }
+ }
+
for (size_t I = 0; I != NumElems; ++I) {
- if (!BasePtr.atIndex(I).isInitialized()) {
+ if (!BasePtr.isElementInitialized(I)) {
DiagnoseUninitializedSubobject(S, Loc, BasePtr.getField());
Result = false;
}
@@ -178,8 +158,8 @@ bool EvaluationResult::checkFullyInitialized(InterpState &S,
static void collectBlocks(const Pointer &Ptr,
llvm::SetVector<const Block *> &Blocks) {
auto isUsefulPtr = [](const Pointer &P) -> bool {
- return P.isLive() && !P.isZero() && !P.isDummy() && P.isDereferencable() &&
- !P.isUnknownSizeArray() && !P.isOnePastEnd();
+ return P.isLive() && P.isBlockPointer() && !P.isZero() && !P.isDummy() &&
+ P.isDereferencable() && !P.isUnknownSizeArray() && !P.isOnePastEnd();
};
if (!isUsefulPtr(Ptr))
diff --git a/clang/lib/AST/ByteCode/EvaluationResult.h b/clang/lib/AST/ByteCode/EvaluationResult.h
index 3b6c65eff1ef..c296cc98ca37 100644
--- a/clang/lib/AST/ByteCode/EvaluationResult.h
+++ b/clang/lib/AST/ByteCode/EvaluationResult.h
@@ -9,23 +9,22 @@
#ifndef LLVM_CLANG_AST_INTERP_EVALUATION_RESULT_H
#define LLVM_CLANG_AST_INTERP_EVALUATION_RESULT_H
-#include "FunctionPointer.h"
-#include "Pointer.h"
#include "clang/AST/APValue.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
-#include <optional>
-#include <variant>
namespace clang {
namespace interp {
class EvalEmitter;
class Context;
+class Pointer;
+class SourceInfo;
+class InterpState;
/// Defines the result of an evaluation.
///
-/// The result might be in different forms--one of the pointer types,
-/// an APValue, or nothing.
+/// The Kind defined if the evaluation was invalid, valid (but empty, e.g. for
+/// void expressions) or if we have a valid evaluation result.
///
/// We use this class to inspect and diagnose the result, as well as
/// convert it to the requested form.
@@ -33,8 +32,6 @@ class EvaluationResult final {
public:
enum ResultKind {
Empty, // Initial state.
- LValue, // Result is an lvalue/pointer.
- RValue, // Result is an rvalue.
Invalid, // Result is invalid.
Valid, // Result is valid and empty.
};
@@ -42,29 +39,18 @@ public:
using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
private:
+#ifndef NDEBUG
const Context *Ctx = nullptr;
- std::variant<std::monostate, Pointer, FunctionPointer, APValue> Value;
+#endif
+ APValue Value;
ResultKind Kind = Empty;
- DeclTy Source = nullptr; // Currently only needed for dump().
-
- EvaluationResult(ResultKind Kind) : Kind(Kind) {
- // Leave everything empty. Can be used as an
- // error marker or for void return values.
- assert(Kind == Valid || Kind == Invalid);
- }
+ DeclTy Source = nullptr;
void setSource(DeclTy D) { Source = D; }
- void setValue(const APValue &V) {
- // V could still be an LValue.
+ void takeValue(APValue &&V) {
assert(empty());
Value = std::move(V);
- Kind = RValue;
- }
- void setFunctionPointer(const FunctionPointer &P) {
- assert(empty());
- Value = P;
- Kind = LValue;
}
void setInvalid() {
// We are NOT asserting empty() here, since setting it to invalid
@@ -77,22 +63,23 @@ private:
}
public:
+#ifndef NDEBUG
EvaluationResult(const Context *Ctx) : Ctx(Ctx) {}
+#else
+ EvaluationResult(const Context *Ctx) {}
+#endif
bool empty() const { return Kind == Empty; }
bool isInvalid() const { return Kind == Invalid; }
- bool isLValue() const { return Kind == LValue; }
- bool isRValue() const { return Kind == RValue; }
- bool isPointer() const { return std::holds_alternative<Pointer>(Value); }
- /// Returns an APValue for the evaluation result. The returned
- /// APValue might be an LValue or RValue.
- APValue toAPValue() const;
+ /// Returns an APValue for the evaluation result.
+ APValue toAPValue() const {
+ assert(!empty());
+ assert(!isInvalid());
+ return Value;
+ }
- /// If the result is an LValue, convert that to an RValue
- /// and return it. This may fail, e.g. if the result is an
- /// LValue and we can't read from it.
- std::optional<APValue> toRValue() const;
+ APValue stealAPValue() { return std::move(Value); }
/// Check that all subobjects of the given pointer have been initialized.
bool checkFullyInitialized(InterpState &S, const Pointer &Ptr) const;
@@ -105,7 +92,7 @@ public:
if (const auto *D =
dyn_cast_if_present<ValueDecl>(Source.dyn_cast<const Decl *>()))
return D->getType();
- else if (const auto *E = Source.dyn_cast<const Expr *>())
+ if (const auto *E = Source.dyn_cast<const Expr *>())
return E->getType();
return QualType();
}
diff --git a/clang/lib/AST/ByteCode/Integral.h b/clang/lib/AST/ByteCode/Integral.h
index af5cd2d13ecc..131802439f0c 100644
--- a/clang/lib/AST/ByteCode/Integral.h
+++ b/clang/lib/AST/ByteCode/Integral.h
@@ -318,6 +318,11 @@ private:
template <typename T> static bool CheckMulUB(T A, T B, T &R) {
if constexpr (std::is_signed_v<T>) {
return llvm::MulOverflow<T>(A, B, R);
+ } else if constexpr (sizeof(T) < sizeof(int)) {
+ // Silly integer promotion rules will convert both A and B to int,
+ // even it T is unsigned. Prevent that by manually casting to uint first.
+ R = static_cast<T>(static_cast<unsigned>(A) * static_cast<unsigned>(B));
+ return false;
} else {
R = A * B;
return false;
diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp
index 796c24e9071e..b64ed8c2fb49 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -792,6 +792,7 @@ bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
+ // Block pointers are the only ones we can actually read from.
if (!Ptr.isBlockPointer()) {
if (Ptr.isZero()) {
const auto &Src = S.Current->getSource(OpPC);
@@ -804,7 +805,6 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}
- // Block pointers are the only ones we can actually read from.
if (!Ptr.block()->isAccessible()) {
if (!CheckLive(S, OpPC, Ptr, AK))
return false;
@@ -812,8 +812,7 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
if (!CheckDummy(S, OpPC, Ptr.block(), AK))
return false;
- if (!CheckWeak(S, OpPC, Ptr.block()))
- return false;
+ return CheckWeak(S, OpPC, Ptr.block());
}
if (!CheckConstant(S, OpPC, Ptr))
@@ -870,7 +869,7 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
}
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- if (!Ptr.isBlockPointer())
+ if (!Ptr.isBlockPointer() || Ptr.isZero())
return false;
if (!Ptr.block()->isAccessible()) {
@@ -1207,17 +1206,15 @@ static bool runRecordDestructor(InterpState &S, CodePtr OpPC,
}
// Destructor of this record.
- if (const CXXDestructorDecl *Dtor = R->getDestructor();
- Dtor && !Dtor->isTrivial()) {
- const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
- if (!DtorFunc)
- return false;
+ const CXXDestructorDecl *Dtor = R->getDestructor();
+ assert(Dtor);
+ assert(!Dtor->isTrivial());
+ const Function *DtorFunc = S.getContext().getOrCreateFunction(Dtor);
+ if (!DtorFunc)
+ return false;
- S.Stk.push<Pointer>(BasePtr);
- if (!Call(S, OpPC, DtorFunc, 0))
- return false;
- }
- return true;
+ S.Stk.push<Pointer>(BasePtr);
+ return Call(S, OpPC, DtorFunc, 0);
}
static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {
@@ -1229,6 +1226,9 @@ static bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B) {
assert(Desc->isRecord() || Desc->isCompositeArray());
+ if (Desc->hasTrivialDtor())
+ return true;
+
if (Desc->isCompositeArray()) {
unsigned N = Desc->getNumElems();
if (N == 0)
@@ -2117,8 +2117,8 @@ bool DiagTypeid(InterpState &S, CodePtr OpPC) {
bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,
const Pointer &RHS) {
- unsigned LHSOffset = LHS.getIndex();
- unsigned RHSOffset = RHS.getIndex();
+ unsigned LHSOffset = LHS.isOnePastEnd() ? LHS.getNumElems() : LHS.getIndex();
+ unsigned RHSOffset = RHS.isOnePastEnd() ? RHS.getNumElems() : RHS.getIndex();
unsigned LHSLength = (LHS.getNumElems() - 1) * LHS.elemSize();
unsigned RHSLength = (RHS.getNumElems() - 1) * RHS.elemSize();
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 92e60b6b88e6..2da220237803 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -3490,7 +3490,15 @@ inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,
S.Stk.push<Pointer>(0, nullptr);
return true;
}
- assert(NumElements.isPositive());
+ if (NumElements.isNegative()) {
+ if (!IsNoThrow) {
+ S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_negative)
+ << NumElements.toDiagnosticString(S.getASTContext());
+ return false;
+ }
+ S.Stk.push<Pointer>(0, nullptr);
+ return true;
+ }
if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements)))
return false;
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 2e28814abfdd..d418e0ac5d09 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -141,6 +141,22 @@ static void diagnoseNonConstexprBuiltin(InterpState &S, CodePtr OpPC,
S.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
}
+static llvm::APSInt convertBoolVectorToInt(const Pointer &Val) {
+ assert(Val.getFieldDesc()->isPrimitiveArray() &&
+ Val.getFieldDesc()->getElemQualType()->isBooleanType() &&
+ "Not a boolean vector");
+ unsigned NumElems = Val.getNumElems();
+
+ // Each element is one bit, so create an integer with NumElts bits.
+ llvm::APSInt Result(NumElems, 0);
+ for (unsigned I = 0; I != NumElems; ++I) {
+ if (Val.elem<bool>(I))
+ Result.setBit(I);
+ }
+
+ return Result;
+}
+
static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
@@ -643,8 +659,14 @@ static bool interp__builtin_abs(InterpState &S, CodePtr OpPC,
static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
- PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
- APSInt Val = popToAPSInt(S.Stk, ArgT);
+ APSInt Val;
+ if (Call->getArg(0)->getType()->isExtVectorBoolType()) {
+ const Pointer &Arg = S.Stk.pop<Pointer>();
+ Val = convertBoolVectorToInt(Arg);
+ } else {
+ PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
+ Val = popToAPSInt(S.Stk, ArgT);
+ }
pushInteger(S, Val.popcount(), Call->getType());
return true;
}
@@ -940,8 +962,14 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
Fallback = popToAPSInt(S.Stk, FallbackT);
}
- PrimType ValT = *S.getContext().classify(Call->getArg(0));
- const APSInt &Val = popToAPSInt(S.Stk, ValT);
+ APSInt Val;
+ if (Call->getArg(0)->getType()->isExtVectorBoolType()) {
+ const Pointer &Arg = S.Stk.pop<Pointer>();
+ Val = convertBoolVectorToInt(Arg);
+ } else {
+ PrimType ValT = *S.getContext().classify(Call->getArg(0));
+ Val = popToAPSInt(S.Stk, ValT);
+ }
// When the argument is 0, the result of GCC builtins is undefined, whereas
// for Microsoft intrinsics, the result is the bit-width of the argument.
@@ -971,8 +999,14 @@ static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC,
PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
Fallback = popToAPSInt(S.Stk, FallbackT);
}
- PrimType ValT = *S.getContext().classify(Call->getArg(0));
- const APSInt &Val = popToAPSInt(S.Stk, ValT);
+ APSInt Val;
+ if (Call->getArg(0)->getType()->isExtVectorBoolType()) {
+ const Pointer &Arg = S.Stk.pop<Pointer>();
+ Val = convertBoolVectorToInt(Arg);
+ } else {
+ PrimType ValT = *S.getContext().classify(Call->getArg(0));
+ Val = popToAPSInt(S.Stk, ValT);
+ }
if (Val == 0) {
if (Fallback) {
@@ -2505,12 +2539,8 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
}
// Check if we're currently running an initializer.
- for (InterpFrame *Frame = S.Current; Frame; Frame = Frame->Caller) {
- if (const Function *F = Frame->getFunction();
- F && F->isConstructor() && Frame->getThis().block() == Ptr.block()) {
- return Error(2);
- }
- }
+ if (llvm::is_contained(S.InitializingBlocks, Ptr.block()))
+ return Error(2);
if (S.EvaluatingDecl && Ptr.getDeclDesc()->asVarDecl() == S.EvaluatingDecl)
return Error(2);
@@ -2518,9 +2548,9 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
return true;
}
-static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
- const CallExpr *Call,
- unsigned BuiltinID) {
+static bool interp__builtin_elementwise_int_binop(
+ InterpState &S, CodePtr OpPC, const CallExpr *Call,
+ llvm::function_ref<APInt(const APSInt &, const APSInt &)> Fn) {
assert(Call->getNumArgs() == 2);
// Single integer case.
@@ -2530,23 +2560,39 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
S.Stk, *S.getContext().classify(Call->getArg(1)->getType()));
APSInt LHS = popToAPSInt(
S.Stk, *S.getContext().classify(Call->getArg(0)->getType()));
- APInt Result;
- if (BuiltinID == Builtin::BI__builtin_elementwise_add_sat) {
- Result = LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS);
- } else if (BuiltinID == Builtin::BI__builtin_elementwise_sub_sat) {
- Result = LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
- } else {
- llvm_unreachable("Wrong builtin ID");
- }
-
+ APInt Result = Fn(LHS, RHS);
pushInteger(S, APSInt(std::move(Result), !LHS.isSigned()), Call->getType());
return true;
}
+ const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>();
+ assert(VT->getElementType()->isIntegralOrEnumerationType());
+ PrimType ElemT = *S.getContext().classify(VT->getElementType());
+ unsigned NumElems = VT->getNumElements();
+ bool DestUnsigned = Call->getType()->isUnsignedIntegerOrEnumerationType();
+
+ // Vector + Scalar case.
+ if (!Call->getArg(1)->getType()->isVectorType()) {
+ assert(Call->getArg(1)->getType()->isIntegralOrEnumerationType());
+
+ APSInt RHS = popToAPSInt(
+ S.Stk, *S.getContext().classify(Call->getArg(1)->getType()));
+ const Pointer &LHS = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+
+ for (unsigned I = 0; I != NumElems; ++I) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, {
+ Dst.elem<T>(I) = static_cast<T>(
+ APSInt(Fn(LHS.elem<T>(I).toAPSInt(), RHS), DestUnsigned));
+ });
+ }
+ Dst.initializeAllElements();
+ return true;
+ }
+
// Vector case.
assert(Call->getArg(0)->getType()->isVectorType() &&
Call->getArg(1)->getType()->isVectorType());
- const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>();
assert(VT->getElementType() ==
Call->getArg(1)->getType()->castAs<VectorType>()->getElementType());
assert(VT->getNumElements() ==
@@ -2556,46 +2602,12 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
const Pointer &RHS = S.Stk.pop<Pointer>();
const Pointer &LHS = S.Stk.pop<Pointer>();
const Pointer &Dst = S.Stk.peek<Pointer>();
- PrimType ElemT = *S.getContext().classify(VT->getElementType());
- unsigned NumElems = VT->getNumElements();
for (unsigned I = 0; I != NumElems; ++I) {
- APSInt Elem1;
- APSInt Elem2;
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
- Elem1 = LHS.elem<T>(I).toAPSInt();
- Elem2 = RHS.elem<T>(I).toAPSInt();
+ APSInt Elem1 = LHS.elem<T>(I).toAPSInt();
+ APSInt Elem2 = RHS.elem<T>(I).toAPSInt();
+ Dst.elem<T>(I) = static_cast<T>(APSInt(Fn(Elem1, Elem2), DestUnsigned));
});
-
- APSInt Result;
- switch (BuiltinID) {
- case Builtin::BI__builtin_elementwise_add_sat:
- Result = APSInt(Elem1.isSigned() ? Elem1.sadd_sat(Elem2)
- : Elem1.uadd_sat(Elem2),
- Call->getType()->isUnsignedIntegerOrEnumerationType());
- break;
- case Builtin::BI__builtin_elementwise_sub_sat:
- Result = APSInt(Elem1.isSigned() ? Elem1.ssub_sat(Elem2)
- : Elem1.usub_sat(Elem2),
- Call->getType()->isUnsignedIntegerOrEnumerationType());
- break;
- case clang::X86::BI__builtin_ia32_pmulhuw128:
- case clang::X86::BI__builtin_ia32_pmulhuw256:
- case clang::X86::BI__builtin_ia32_pmulhuw512:
- Result = APSInt(llvm::APIntOps::mulhu(Elem1, Elem2),
- /*isUnsigned=*/true);
- break;
- case clang::X86::BI__builtin_ia32_pmulhw128:
- case clang::X86::BI__builtin_ia32_pmulhw256:
- case clang::X86::BI__builtin_ia32_pmulhw512:
- Result = APSInt(llvm::APIntOps::mulhs(Elem1, Elem2),
- /*isUnsigned=*/false);
- break;
- default:
- llvm_unreachable("Wrong builtin ID");
- }
-
- INT_TYPE_SWITCH_NO_BOOL(ElemT,
- { Dst.elem<T>(I) = static_cast<T>(Result); });
}
Dst.initializeAllElements();
@@ -2724,8 +2736,11 @@ static bool interp__builtin_ia32_pmul(InterpState &S, CodePtr OpPC,
return true;
}
-static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC,
- const CallExpr *Call) {
+static bool interp__builtin_elementwise_triop_fp(
+ InterpState &S, CodePtr OpPC, const CallExpr *Call,
+ llvm::function_ref<APFloat(const APFloat &, const APFloat &,
+ const APFloat &, llvm::RoundingMode)>
+ Fn) {
assert(Call->getNumArgs() == 3);
FPOptions FPO = Call->getFPFeaturesInEffect(S.Ctx.getLangOpts());
@@ -2744,8 +2759,7 @@ static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC,
const Floating &Z = S.Stk.pop<Floating>();
const Floating &Y = S.Stk.pop<Floating>();
const Floating &X = S.Stk.pop<Floating>();
- APFloat F = X.getAPFloat();
- F.fusedMultiplyAdd(Y.getAPFloat(), Z.getAPFloat(), RM);
+ APFloat F = Fn(X.getAPFloat(), Y.getAPFloat(), Z.getAPFloat(), RM);
Floating Result = S.allocFloat(X.getSemantics());
Result.copy(F);
S.Stk.push<Floating>(Result);
@@ -2776,8 +2790,8 @@ static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC,
APFloat X = VX.elem<T>(I).getAPFloat();
APFloat Y = VY.elem<T>(I).getAPFloat();
APFloat Z = VZ.elem<T>(I).getAPFloat();
- (void)X.fusedMultiplyAdd(Y, Z, RM);
- Dst.elem<Floating>(I) = Floating(X);
+ APFloat F = Fn(X, Y, Z, RM);
+ Dst.elem<Floating>(I) = Floating(F);
}
Dst.initializeAllElements();
return true;
@@ -2817,6 +2831,72 @@ static bool interp__builtin_select(InterpState &S, CodePtr OpPC,
return true;
}
+static bool interp__builtin_elementwise_triop(
+ InterpState &S, CodePtr OpPC, const CallExpr *Call,
+ llvm::function_ref<APInt(const APSInt &, const APSInt &, const APSInt &)>
+ Fn) {
+ assert(Call->getNumArgs() == 3);
+
+ QualType Arg0Type = Call->getArg(0)->getType();
+ QualType Arg1Type = Call->getArg(1)->getType();
+ QualType Arg2Type = Call->getArg(2)->getType();
+
+ // Non-vector integer types.
+ if (!Arg0Type->isVectorType()) {
+ const APSInt &Op2 = popToAPSInt(S.Stk, *S.getContext().classify(Arg2Type));
+ const APSInt &Op1 = popToAPSInt(S.Stk, *S.getContext().classify(Arg1Type));
+ const APSInt &Op0 = popToAPSInt(S.Stk, *S.getContext().classify(Arg0Type));
+ APSInt Result = APSInt(Fn(Op0, Op1, Op2), Op0.isUnsigned());
+ pushInteger(S, Result, Call->getType());
+ return true;
+ }
+
+ const auto *VecT = Arg0Type->castAs<VectorType>();
+ const PrimType &ElemT = *S.getContext().classify(VecT->getElementType());
+ unsigned NumElems = VecT->getNumElements();
+ bool DestUnsigned = Call->getType()->isUnsignedIntegerOrEnumerationType();
+
+ // Vector + Vector + Scalar case.
+ if (!Arg2Type->isVectorType()) {
+ APSInt Op2 = popToAPSInt(
+ S.Stk, *S.getContext().classify(Call->getArg(2)->getType()));
+
+ const Pointer &Op1 = S.Stk.pop<Pointer>();
+ const Pointer &Op0 = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+ for (unsigned I = 0; I != NumElems; ++I) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, {
+ Dst.elem<T>(I) = static_cast<T>(APSInt(
+ Fn(Op0.elem<T>(I).toAPSInt(), Op1.elem<T>(I).toAPSInt(), Op2),
+ DestUnsigned));
+ });
+ }
+ Dst.initializeAllElements();
+
+ return true;
+ }
+
+ // Vector type.
+ const Pointer &Op2 = S.Stk.pop<Pointer>();
+ const Pointer &Op1 = S.Stk.pop<Pointer>();
+ const Pointer &Op0 = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+ for (unsigned I = 0; I != NumElems; ++I) {
+ APSInt Val0, Val1, Val2;
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, {
+ Val0 = Op0.elem<T>(I).toAPSInt();
+ Val1 = Op1.elem<T>(I).toAPSInt();
+ Val2 = Op2.elem<T>(I).toAPSInt();
+ });
+ APSInt Result = APSInt(Fn(Val0, Val1, Val2), Val0.isUnsigned());
+ INT_TYPE_SWITCH_NO_BOOL(ElemT,
+ { Dst.elem<T>(I) = static_cast<T>(Result); });
+ }
+ Dst.initializeAllElements();
+
+ return true;
+}
+
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
uint32_t BuiltinID) {
if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID))
@@ -3229,14 +3309,139 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
return interp__builtin_is_within_lifetime(S, OpPC, Call);
case Builtin::BI__builtin_elementwise_add_sat:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) {
+ return LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS);
+ });
+
case Builtin::BI__builtin_elementwise_sub_sat:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) {
+ return LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
+ });
+
+ case clang::X86::BI__builtin_ia32_pavgb128:
+ case clang::X86::BI__builtin_ia32_pavgw128:
+ case clang::X86::BI__builtin_ia32_pavgb256:
+ case clang::X86::BI__builtin_ia32_pavgw256:
+ case clang::X86::BI__builtin_ia32_pavgb512:
+ case clang::X86::BI__builtin_ia32_pavgw512:
+ return interp__builtin_elementwise_int_binop(S, OpPC, Call,
+ llvm::APIntOps::avgCeilU);
+
case clang::X86::BI__builtin_ia32_pmulhuw128:
case clang::X86::BI__builtin_ia32_pmulhuw256:
case clang::X86::BI__builtin_ia32_pmulhuw512:
+ return interp__builtin_elementwise_int_binop(S, OpPC, Call,
+ llvm::APIntOps::mulhu);
+
case clang::X86::BI__builtin_ia32_pmulhw128:
case clang::X86::BI__builtin_ia32_pmulhw256:
case clang::X86::BI__builtin_ia32_pmulhw512:
- return interp__builtin_elementwise_sat(S, OpPC, Call, BuiltinID);
+ return interp__builtin_elementwise_int_binop(S, OpPC, Call,
+ llvm::APIntOps::mulhs);
+
+ case clang::X86::BI__builtin_ia32_psllv2di:
+ case clang::X86::BI__builtin_ia32_psllv4di:
+ case clang::X86::BI__builtin_ia32_psllv4si:
+ case clang::X86::BI__builtin_ia32_psllv8di:
+ case clang::X86::BI__builtin_ia32_psllv8hi:
+ case clang::X86::BI__builtin_ia32_psllv8si:
+ case clang::X86::BI__builtin_ia32_psllv16hi:
+ case clang::X86::BI__builtin_ia32_psllv16si:
+ case clang::X86::BI__builtin_ia32_psllv32hi:
+ case clang::X86::BI__builtin_ia32_psllwi128:
+ case clang::X86::BI__builtin_ia32_psllwi256:
+ case clang::X86::BI__builtin_ia32_psllwi512:
+ case clang::X86::BI__builtin_ia32_pslldi128:
+ case clang::X86::BI__builtin_ia32_pslldi256:
+ case clang::X86::BI__builtin_ia32_pslldi512:
+ case clang::X86::BI__builtin_ia32_psllqi128:
+ case clang::X86::BI__builtin_ia32_psllqi256:
+ case clang::X86::BI__builtin_ia32_psllqi512:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(LHS.getBitWidth())) {
+ return APInt::getZero(LHS.getBitWidth());
+ }
+ return LHS.shl(RHS.getZExtValue());
+ });
+
+ case clang::X86::BI__builtin_ia32_psrav4si:
+ case clang::X86::BI__builtin_ia32_psrav8di:
+ case clang::X86::BI__builtin_ia32_psrav8hi:
+ case clang::X86::BI__builtin_ia32_psrav8si:
+ case clang::X86::BI__builtin_ia32_psrav16hi:
+ case clang::X86::BI__builtin_ia32_psrav16si:
+ case clang::X86::BI__builtin_ia32_psrav32hi:
+ case clang::X86::BI__builtin_ia32_psravq128:
+ case clang::X86::BI__builtin_ia32_psravq256:
+ case clang::X86::BI__builtin_ia32_psrawi128:
+ case clang::X86::BI__builtin_ia32_psrawi256:
+ case clang::X86::BI__builtin_ia32_psrawi512:
+ case clang::X86::BI__builtin_ia32_psradi128:
+ case clang::X86::BI__builtin_ia32_psradi256:
+ case clang::X86::BI__builtin_ia32_psradi512:
+ case clang::X86::BI__builtin_ia32_psraqi128:
+ case clang::X86::BI__builtin_ia32_psraqi256:
+ case clang::X86::BI__builtin_ia32_psraqi512:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(LHS.getBitWidth())) {
+ return LHS.ashr(LHS.getBitWidth() - 1);
+ }
+ return LHS.ashr(RHS.getZExtValue());
+ });
+
+ case clang::X86::BI__builtin_ia32_psrlv2di:
+ case clang::X86::BI__builtin_ia32_psrlv4di:
+ case clang::X86::BI__builtin_ia32_psrlv4si:
+ case clang::X86::BI__builtin_ia32_psrlv8di:
+ case clang::X86::BI__builtin_ia32_psrlv8hi:
+ case clang::X86::BI__builtin_ia32_psrlv8si:
+ case clang::X86::BI__builtin_ia32_psrlv16hi:
+ case clang::X86::BI__builtin_ia32_psrlv16si:
+ case clang::X86::BI__builtin_ia32_psrlv32hi:
+ case clang::X86::BI__builtin_ia32_psrlwi128:
+ case clang::X86::BI__builtin_ia32_psrlwi256:
+ case clang::X86::BI__builtin_ia32_psrlwi512:
+ case clang::X86::BI__builtin_ia32_psrldi128:
+ case clang::X86::BI__builtin_ia32_psrldi256:
+ case clang::X86::BI__builtin_ia32_psrldi512:
+ case clang::X86::BI__builtin_ia32_psrlqi128:
+ case clang::X86::BI__builtin_ia32_psrlqi256:
+ case clang::X86::BI__builtin_ia32_psrlqi512:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, [](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(LHS.getBitWidth())) {
+ return APInt::getZero(LHS.getBitWidth());
+ }
+ return LHS.lshr(RHS.getZExtValue());
+ });
+
+ case clang::X86::BI__builtin_ia32_vprotbi:
+ case clang::X86::BI__builtin_ia32_vprotdi:
+ case clang::X86::BI__builtin_ia32_vprotqi:
+ case clang::X86::BI__builtin_ia32_vprotwi:
+ case clang::X86::BI__builtin_ia32_prold128:
+ case clang::X86::BI__builtin_ia32_prold256:
+ case clang::X86::BI__builtin_ia32_prold512:
+ case clang::X86::BI__builtin_ia32_prolq128:
+ case clang::X86::BI__builtin_ia32_prolq256:
+ case clang::X86::BI__builtin_ia32_prolq512:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call,
+ [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotl(RHS); });
+
+ case clang::X86::BI__builtin_ia32_prord128:
+ case clang::X86::BI__builtin_ia32_prord256:
+ case clang::X86::BI__builtin_ia32_prord512:
+ case clang::X86::BI__builtin_ia32_prorq128:
+ case clang::X86::BI__builtin_ia32_prorq256:
+ case clang::X86::BI__builtin_ia32_prorq512:
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call,
+ [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotr(RHS); });
case Builtin::BI__builtin_elementwise_max:
case Builtin::BI__builtin_elementwise_min:
@@ -3251,7 +3456,61 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
return interp__builtin_ia32_pmul(S, OpPC, Call, BuiltinID);
case Builtin::BI__builtin_elementwise_fma:
- return interp__builtin_elementwise_fma(S, OpPC, Call);
+ return interp__builtin_elementwise_triop_fp(
+ S, OpPC, Call,
+ [](const APFloat &X, const APFloat &Y, const APFloat &Z,
+ llvm::RoundingMode RM) {
+ APFloat F = X;
+ F.fusedMultiplyAdd(Y, Z, RM);
+ return F;
+ });
+
+ case X86::BI__builtin_ia32_vpshldd128:
+ case X86::BI__builtin_ia32_vpshldd256:
+ case X86::BI__builtin_ia32_vpshldd512:
+ case X86::BI__builtin_ia32_vpshldq128:
+ case X86::BI__builtin_ia32_vpshldq256:
+ case X86::BI__builtin_ia32_vpshldq512:
+ case X86::BI__builtin_ia32_vpshldw128:
+ case X86::BI__builtin_ia32_vpshldw256:
+ case X86::BI__builtin_ia32_vpshldw512:
+ return interp__builtin_elementwise_triop(
+ S, OpPC, Call,
+ [](const APSInt &Hi, const APSInt &Lo, const APSInt &Amt) {
+ return llvm::APIntOps::fshl(Hi, Lo, Amt);
+ });
+
+ case X86::BI__builtin_ia32_vpshrdd128:
+ case X86::BI__builtin_ia32_vpshrdd256:
+ case X86::BI__builtin_ia32_vpshrdd512:
+ case X86::BI__builtin_ia32_vpshrdq128:
+ case X86::BI__builtin_ia32_vpshrdq256:
+ case X86::BI__builtin_ia32_vpshrdq512:
+ case X86::BI__builtin_ia32_vpshrdw128:
+ case X86::BI__builtin_ia32_vpshrdw256:
+ case X86::BI__builtin_ia32_vpshrdw512:
+ // NOTE: Reversed Hi/Lo operands.
+ return interp__builtin_elementwise_triop(
+ S, OpPC, Call,
+ [](const APSInt &Lo, const APSInt &Hi, const APSInt &Amt) {
+ return llvm::APIntOps::fshr(Hi, Lo, Amt);
+ });
+
+ case clang::X86::BI__builtin_ia32_blendvpd:
+ case clang::X86::BI__builtin_ia32_blendvpd256:
+ case clang::X86::BI__builtin_ia32_blendvps:
+ case clang::X86::BI__builtin_ia32_blendvps256:
+ return interp__builtin_elementwise_triop_fp(
+ S, OpPC, Call,
+ [](const APFloat &F, const APFloat &T, const APFloat &C,
+ llvm::RoundingMode) { return C.isNegative() ? T : F; });
+
+ case clang::X86::BI__builtin_ia32_pblendvb128:
+ case clang::X86::BI__builtin_ia32_pblendvb256:
+ return interp__builtin_elementwise_triop(
+ S, OpPC, Call, [](const APSInt &F, const APSInt &T, const APSInt &C) {
+ return ((APInt)C).isNegative() ? T : F;
+ });
case X86::BI__builtin_ia32_selectb_128:
case X86::BI__builtin_ia32_selectb_256:
@@ -3279,6 +3538,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case X86::BI__builtin_ia32_selectpd_512:
return interp__builtin_select(S, OpPC, Call);
+ case Builtin::BI__builtin_elementwise_fshl:
+ return interp__builtin_elementwise_triop(S, OpPC, Call,
+ llvm::APIntOps::fshl);
+ case Builtin::BI__builtin_elementwise_fshr:
+ return interp__builtin_elementwise_triop(S, OpPC, Call,
+ llvm::APIntOps::fshr);
+
default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
@@ -3303,11 +3569,8 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
switch (Node.getKind()) {
case OffsetOfNode::Field: {
const FieldDecl *MemberDecl = Node.getField();
- const RecordType *RT = CurrentType->getAs<RecordType>();
- if (!RT)
- return false;
- const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
- if (RD->isInvalidDecl())
+ const auto *RD = CurrentType->getAsRecordDecl();
+ if (!RD || RD->isInvalidDecl())
return false;
const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD);
unsigned FieldIndex = MemberDecl->getFieldIndex();
@@ -3336,23 +3599,19 @@ bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
return false;
// Find the layout of the class whose base we are looking into.
- const RecordType *RT = CurrentType->getAs<RecordType>();
- if (!RT)
- return false;
- const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
- if (RD->isInvalidDecl())
+ const auto *RD = CurrentType->getAsCXXRecordDecl();
+ if (!RD || RD->isInvalidDecl())
return false;
const ASTRecordLayout &RL = S.getASTContext().getASTRecordLayout(RD);
// Find the base class itself.
CurrentType = BaseSpec->getType();
- const RecordType *BaseRT = CurrentType->getAs<RecordType>();
- if (!BaseRT)
+ const auto *BaseRD = CurrentType->getAsCXXRecordDecl();
+ if (!BaseRD)
return false;
// Add the offset to the base.
- Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(
- BaseRT->getOriginalDecl()->getDefinitionOrSelf()));
+ Result += RL.getBaseClassOffset(BaseRD);
break;
}
case OffsetOfNode::Identifier:
diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp
index 18400b10c47b..b9dc2aed2311 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -195,12 +195,6 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
OS << ")";
}
-Frame *InterpFrame::getCaller() const {
- if (Caller->Caller)
- return Caller;
- return S.getSplitFrame();
-}
-
SourceRange InterpFrame::getCallRange() const {
if (!Caller->Func) {
if (SourceRange NullRange = S.getRange(nullptr, {}); NullRange.isValid())
diff --git a/clang/lib/AST/ByteCode/InterpFrame.h b/clang/lib/AST/ByteCode/InterpFrame.h
index 4be53911b615..cf4d27d341e9 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.h
+++ b/clang/lib/AST/ByteCode/InterpFrame.h
@@ -59,7 +59,7 @@ public:
void describe(llvm::raw_ostream &OS) const override;
/// Returns the parent frame object.
- Frame *getCaller() const override;
+ Frame *getCaller() const override { return Caller; }
/// Returns the location of the call to the frame.
SourceRange getCallRange() const override;
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp
index f89967759ff9..1ec4191d2ba3 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -20,19 +20,29 @@ using namespace clang::interp;
InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
Context &Ctx, SourceMapper *M)
: Parent(Parent), M(M), P(P), Stk(Stk), Ctx(Ctx), BottomFrame(*this),
- Current(&BottomFrame) {}
+ Current(&BottomFrame) {
+ InConstantContext = Parent.InConstantContext;
+ CheckingPotentialConstantExpression =
+ Parent.CheckingPotentialConstantExpression;
+ CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
+}
InterpState::InterpState(State &Parent, Program &P, InterpStack &Stk,
Context &Ctx, const Function *Func)
: Parent(Parent), M(nullptr), P(P), Stk(Stk), Ctx(Ctx),
BottomFrame(*this, Func, nullptr, CodePtr(), Func->getArgSize()),
- Current(&BottomFrame) {}
+ Current(&BottomFrame) {
+ InConstantContext = Parent.InConstantContext;
+ CheckingPotentialConstantExpression =
+ Parent.CheckingPotentialConstantExpression;
+ CheckingForUndefinedBehavior = Parent.CheckingForUndefinedBehavior;
+}
bool InterpState::inConstantContext() const {
if (ConstantContextOverride)
return *ConstantContextOverride;
- return Parent.InConstantContext;
+ return InConstantContext;
}
InterpState::~InterpState() {
@@ -59,20 +69,11 @@ InterpState::~InterpState() {
void InterpState::cleanup() {
// As a last resort, make sure all pointers still pointing to a dead block
// don't point to it anymore.
- Alloc.cleanup();
-}
-
-Frame *InterpState::getCurrentFrame() {
- if (Current && Current->Caller)
- return Current;
- return Parent.getCurrentFrame();
+ if (Alloc)
+ Alloc->cleanup();
}
-bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) {
- QualType Type = E->getType();
- CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
- return noteUndefinedBehavior();
-}
+Frame *InterpState::getCurrentFrame() { return Current; }
void InterpState::deallocate(Block *B) {
assert(B);
@@ -103,10 +104,13 @@ void InterpState::deallocate(Block *B) {
}
bool InterpState::maybeDiagnoseDanglingAllocations() {
- bool NoAllocationsLeft = !Alloc.hasAllocations();
+ if (!Alloc)
+ return true;
+
+ bool NoAllocationsLeft = !Alloc->hasAllocations();
if (!checkingPotentialConstantExpression()) {
- for (const auto &[Source, Site] : Alloc.allocation_sites()) {
+ for (const auto &[Source, Site] : Alloc->allocation_sites()) {
assert(!Site.empty());
CCEDiag(Source->getExprLoc(), diag::note_constexpr_memory_leak)
diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h
index 861e4c38049a..e095908bce98 100644
--- a/clang/lib/AST/ByteCode/InterpState.h
+++ b/clang/lib/AST/ByteCode/InterpState.h
@@ -57,14 +57,11 @@ public:
bool diagnosing() const { return getEvalStatus().Diag != nullptr; }
// Stack frame accessors.
- Frame *getSplitFrame() { return Parent.getCurrentFrame(); }
Frame *getCurrentFrame() override;
unsigned getCallStackDepth() override {
return Current ? (Current->getDepth() + 1) : 1;
}
- const Frame *getBottomFrame() const override {
- return Parent.getBottomFrame();
- }
+ const Frame *getBottomFrame() const override { return &BottomFrame; }
// Access objects from the walker context.
Expr::EvalStatus &getEvalStatus() const override {
@@ -73,18 +70,12 @@ public:
ASTContext &getASTContext() const override { return Parent.getASTContext(); }
// Forward status checks and updates to the walker.
- bool checkingForUndefinedBehavior() const override {
- return Parent.checkingForUndefinedBehavior();
- }
bool keepEvaluatingAfterFailure() const override {
return Parent.keepEvaluatingAfterFailure();
}
bool keepEvaluatingAfterSideEffect() const override {
return Parent.keepEvaluatingAfterSideEffect();
}
- bool checkingPotentialConstantExpression() const override {
- return Parent.checkingPotentialConstantExpression();
- }
bool noteUndefinedBehavior() override {
return Parent.noteUndefinedBehavior();
}
@@ -99,9 +90,6 @@ public:
bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); }
bool noteSideEffect() override { return Parent.noteSideEffect(); }
- /// Reports overflow and return true if evaluation should continue.
- bool reportOverflow(const Expr *E, const llvm::APSInt &Value);
-
/// Deallocates a pointer.
void deallocate(Block *B);
@@ -118,7 +106,13 @@ public:
void setEvalLocation(SourceLocation SL) { this->EvalLocation = SL; }
- DynamicAllocator &getAllocator() { return Alloc; }
+ DynamicAllocator &getAllocator() {
+ if (!Alloc) {
+ Alloc = std::make_unique<DynamicAllocator>();
+ }
+
+ return *Alloc.get();
+ }
/// Diagnose any dynamic allocations that haven't been freed yet.
/// Will return \c false if there were any allocations to diagnose,
@@ -164,7 +158,7 @@ private:
/// Reference to the offset-source mapping.
SourceMapper *M;
/// Allocator used for dynamic allocations performed via the program.
- DynamicAllocator Alloc;
+ std::unique_ptr<DynamicAllocator> Alloc;
public:
/// Reference to the module containing all bytecode.
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index 38856ad256a6..ef75b0ded4f1 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -442,26 +442,42 @@ bool Pointer::isInitialized() const {
assert(BS.Pointee && "Cannot check if null pointer was initialized");
const Descriptor *Desc = getFieldDesc();
assert(Desc);
- if (Desc->isPrimitiveArray()) {
- if (isStatic() && BS.Base == 0)
- return true;
+ if (Desc->isPrimitiveArray())
+ return isElementInitialized(getIndex());
- InitMapPtr &IM = getInitMap();
+ if (asBlockPointer().Base == 0)
+ return true;
+ // Field has its bit in an inline descriptor.
+ return getInlineDesc()->IsInitialized;
+}
+
+bool Pointer::isElementInitialized(unsigned Index) const {
+ if (!isBlockPointer())
+ return true;
+ const Descriptor *Desc = getFieldDesc();
+ assert(Desc);
+
+ if (isStatic() && BS.Base == 0)
+ return true;
+
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+ const GlobalInlineDescriptor &GD =
+ *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
+ return GD.InitState == GlobalInitState::Initialized;
+ }
+
+ if (Desc->isPrimitiveArray()) {
+ InitMapPtr &IM = getInitMap();
if (!IM)
return false;
if (IM->first)
return true;
- return IM->second->isElementInitialized(getIndex());
+ return IM->second->isElementInitialized(Index);
}
-
- if (asBlockPointer().Base == 0)
- return true;
-
- // Field has its bit in an inline descriptor.
- return getInlineDesc()->IsInitialized;
+ return isInitialized();
}
void Pointer::initialize() const {
@@ -524,6 +540,23 @@ void Pointer::initializeAllElements() const {
}
}
+bool Pointer::allElementsInitialized() const {
+ assert(getFieldDesc()->isPrimitiveArray());
+ assert(isArrayRoot());
+
+ if (isStatic() && BS.Base == 0)
+ return true;
+
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
+ const GlobalInlineDescriptor &GD =
+ *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
+ return GD.InitState == GlobalInitState::Initialized;
+ }
+
+ InitMapPtr &IM = getInitMap();
+ return IM && IM->first;
+}
+
void Pointer::activate() const {
// Field has its bit in an inline descriptor.
assert(BS.Base != 0 && "Only composite fields can be activated");
@@ -594,9 +627,6 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
if (A.isTypeidPointer() && B.isTypeidPointer())
return true;
- if (A.isIntegralPointer() || B.isIntegralPointer())
- return A.getSource() == B.getSource();
-
if (A.StorageKind != B.StorageKind)
return false;
@@ -700,7 +730,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
return true;
}
- if (const auto *RT = Ty->getAs<RecordType>()) {
+ if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
const auto *Record = Ptr.getRecord();
assert(Record && "Missing record descriptor");
@@ -771,13 +801,13 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
R = APValue(APValue::UninitArray{}, NumElems, NumElems);
bool Ok = true;
- for (unsigned I = 0; I < NumElems; ++I) {
+ OptPrimType ElemT = Ctx.classify(ElemTy);
+ for (unsigned I = 0; I != NumElems; ++I) {
APValue &Slot = R.getArrayInitializedElt(I);
- const Pointer &EP = Ptr.atIndex(I);
- if (OptPrimType T = Ctx.classify(ElemTy)) {
- TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
+ if (ElemT) {
+ TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
} else {
- Ok &= Composite(ElemTy, EP.narrow(), Slot);
+ Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);
}
}
return Ok;
@@ -785,8 +815,11 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
// Complex types.
if (const auto *CT = Ty->getAs<ComplexType>()) {
- QualType ElemTy = CT->getElementType();
+ // Can happen via C casts.
+ if (!Ptr.getFieldDesc()->isPrimitiveArray())
+ return false;
+ QualType ElemTy = CT->getElementType();
if (ElemTy->isIntegerType()) {
OptPrimType ElemT = Ctx.classify(ElemTy);
assert(ElemT);
diff --git a/clang/lib/AST/ByteCode/Pointer.h b/clang/lib/AST/ByteCode/Pointer.h
index 0ce54ab0a17d..49d701c3e27b 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -103,9 +103,7 @@ public:
Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0)
: Offset(Offset), StorageKind(Storage::Int), Int{Desc, Address} {}
Pointer(const Function *F, uint64_t Offset = 0)
- : Offset(Offset), StorageKind(Storage::Fn), Fn(F) {
- Fn = FunctionPointer(F);
- }
+ : Offset(Offset), StorageKind(Storage::Fn), Fn(F) {}
Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0)
: Offset(Offset), StorageKind(Storage::Typeid) {
Typeid.TypePtr = TypePtr;
@@ -122,17 +120,14 @@ public:
if (P.StorageKind != StorageKind)
return false;
if (isIntegralPointer())
- return P.asIntPointer().Value == asIntPointer().Value &&
- P.asIntPointer().Desc == asIntPointer().Desc && P.Offset == Offset;
+ return P.Int.Value == Int.Value && P.Int.Desc == Int.Desc &&
+ P.Offset == Offset;
if (isFunctionPointer())
- return P.asFunctionPointer().getFunction() ==
- asFunctionPointer().getFunction() &&
- P.Offset == Offset;
+ return P.Fn.getFunction() == Fn.getFunction() && P.Offset == Offset;
assert(isBlockPointer());
- return P.asBlockPointer().Pointee == asBlockPointer().Pointee &&
- P.asBlockPointer().Base == asBlockPointer().Base &&
+ return P.BS.Pointee == BS.Pointee && P.BS.Base == BS.Base &&
P.Offset == Offset;
}
@@ -146,10 +141,10 @@ public:
uint64_t getIntegerRepresentation() const {
if (isIntegralPointer())
- return asIntPointer().Value + (Offset * elemSize());
+ return Int.Value + (Offset * elemSize());
if (isFunctionPointer())
- return asFunctionPointer().getIntegerRepresentation() + Offset;
- return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset;
+ return Fn.getIntegerRepresentation() + Offset;
+ return reinterpret_cast<uint64_t>(BS.Pointee) + Offset;
}
/// Converts the pointer to an APValue that is an rvalue.
@@ -159,27 +154,25 @@ public:
/// Offsets a pointer inside an array.
[[nodiscard]] Pointer atIndex(uint64_t Idx) const {
if (isIntegralPointer())
- return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx);
+ return Pointer(Int.Value, Int.Desc, Idx);
if (isFunctionPointer())
- return Pointer(asFunctionPointer().getFunction(), Idx);
+ return Pointer(Fn.getFunction(), Idx);
- if (asBlockPointer().Base == RootPtrMark)
- return Pointer(asBlockPointer().Pointee, RootPtrMark,
- getDeclDesc()->getSize());
+ if (BS.Base == RootPtrMark)
+ return Pointer(BS.Pointee, RootPtrMark, getDeclDesc()->getSize());
uint64_t Off = Idx * elemSize();
if (getFieldDesc()->ElemDesc)
Off += sizeof(InlineDescriptor);
else
Off += sizeof(InitMapPtr);
- return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
- asBlockPointer().Base + Off);
+ return Pointer(BS.Pointee, BS.Base, BS.Base + Off);
}
/// Creates a pointer to a field.
[[nodiscard]] Pointer atField(unsigned Off) const {
assert(isBlockPointer());
unsigned Field = Offset + Off;
- return Pointer(asBlockPointer().Pointee, Field, Field);
+ return Pointer(BS.Pointee, Field, Field);
}
/// Subtract the given offset from the current Base and Offset
@@ -187,7 +180,7 @@ public:
[[nodiscard]] Pointer atFieldSub(unsigned Off) const {
assert(Offset >= Off);
unsigned O = Offset - Off;
- return Pointer(asBlockPointer().Pointee, O, O);
+ return Pointer(BS.Pointee, O, O);
}
/// Restricts the scope of an array element pointer.
@@ -199,15 +192,15 @@ public:
if (isZero() || isUnknownSizeArray())
return *this;
- unsigned Base = asBlockPointer().Base;
+ unsigned Base = BS.Base;
// Pointer to an array of base types - enter block.
if (Base == RootPtrMark)
- return Pointer(asBlockPointer().Pointee, sizeof(InlineDescriptor),
+ return Pointer(BS.Pointee, sizeof(InlineDescriptor),
Offset == 0 ? Offset : PastEndMark);
// Pointer is one past end - magic offset marks that.
if (isOnePastEnd())
- return Pointer(asBlockPointer().Pointee, Base, PastEndMark);
+ return Pointer(BS.Pointee, Base, PastEndMark);
if (Offset != Base) {
// If we're pointing to a primitive array element, there's nothing to do.
@@ -215,7 +208,7 @@ public:
return *this;
// Pointer is to a composite array element - enter it.
if (Offset != Base)
- return Pointer(asBlockPointer().Pointee, Offset, Offset);
+ return Pointer(BS.Pointee, Offset, Offset);
}
// Otherwise, we're pointing to a non-array element or
@@ -226,7 +219,7 @@ public:
/// Expands a pointer to the containing array, undoing narrowing.
[[nodiscard]] Pointer expand() const {
assert(isBlockPointer());
- Block *Pointee = asBlockPointer().Pointee;
+ Block *Pointee = BS.Pointee;
if (isElementPastEnd()) {
// Revert to an outer one-past-end pointer.
@@ -235,19 +228,18 @@ public:
Adjust = sizeof(InitMapPtr);
else
Adjust = sizeof(InlineDescriptor);
- return Pointer(Pointee, asBlockPointer().Base,
- asBlockPointer().Base + getSize() + Adjust);
+ return Pointer(Pointee, BS.Base, BS.Base + getSize() + Adjust);
}
// Do not step out of array elements.
- if (asBlockPointer().Base != Offset)
+ if (BS.Base != Offset)
return *this;
if (isRoot())
- return Pointer(Pointee, asBlockPointer().Base, asBlockPointer().Base);
+ return Pointer(Pointee, BS.Base, BS.Base);
// Step into the containing array, if inside one.
- unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset;
+ unsigned Next = BS.Base - getInlineDesc()->Offset;
const Descriptor *Desc =
(Next == Pointee->getDescriptor()->getMetadataSize())
? getDeclDesc()
@@ -260,19 +252,19 @@ public:
/// Checks if the pointer is null.
bool isZero() const {
if (isBlockPointer())
- return asBlockPointer().Pointee == nullptr;
+ return BS.Pointee == nullptr;
if (isFunctionPointer())
- return asFunctionPointer().isZero();
+ return Fn.isZero();
if (isTypeidPointer())
return false;
assert(isIntegralPointer());
- return asIntPointer().Value == 0 && Offset == 0;
+ return Int.Value == 0 && Offset == 0;
}
/// Checks if the pointer is live.
bool isLive() const {
if (!isBlockPointer())
return true;
- return asBlockPointer().Pointee && !asBlockPointer().Pointee->isDead();
+ return BS.Pointee && !BS.Pointee->isDead();
}
/// Checks if the item is a field in an object.
bool isField() const {
@@ -285,13 +277,13 @@ public:
/// Accessor for information about the declaration site.
const Descriptor *getDeclDesc() const {
if (isIntegralPointer())
- return asIntPointer().Desc;
+ return Int.Desc;
if (isFunctionPointer() || isTypeidPointer())
return nullptr;
assert(isBlockPointer());
- assert(asBlockPointer().Pointee);
- return asBlockPointer().Pointee->Desc;
+ assert(BS.Pointee);
+ return BS.Pointee->Desc;
}
SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); }
@@ -300,37 +292,36 @@ public:
if (isBlockPointer())
return getDeclDesc()->getSource();
if (isFunctionPointer()) {
- const Function *F = asFunctionPointer().getFunction();
+ const Function *F = Fn.getFunction();
return F ? F->getDecl() : DeclTy();
}
assert(isIntegralPointer());
- return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy();
+ return Int.Desc ? Int.Desc->getSource() : DeclTy();
}
/// Returns a pointer to the object of which this pointer is a field.
[[nodiscard]] Pointer getBase() const {
- if (asBlockPointer().Base == RootPtrMark) {
+ if (BS.Base == RootPtrMark) {
assert(Offset == PastEndMark && "cannot get base of a block");
- return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);
+ return Pointer(BS.Pointee, BS.Base, 0);
}
- unsigned NewBase = asBlockPointer().Base - getInlineDesc()->Offset;
- return Pointer(asBlockPointer().Pointee, NewBase, NewBase);
+ unsigned NewBase = BS.Base - getInlineDesc()->Offset;
+ return Pointer(BS.Pointee, NewBase, NewBase);
}
/// Returns the parent array.
[[nodiscard]] Pointer getArray() const {
- if (asBlockPointer().Base == RootPtrMark) {
+ if (BS.Base == RootPtrMark) {
assert(Offset != 0 && Offset != PastEndMark && "not an array element");
- return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);
+ return Pointer(BS.Pointee, BS.Base, 0);
}
- assert(Offset != asBlockPointer().Base && "not an array element");
- return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
- asBlockPointer().Base);
+ assert(Offset != BS.Base && "not an array element");
+ return Pointer(BS.Pointee, BS.Base, BS.Base);
}
/// Accessors for information about the innermost field.
const Descriptor *getFieldDesc() const {
if (isIntegralPointer())
- return asIntPointer().Desc;
+ return Int.Desc;
if (isRoot())
return getDeclDesc();
@@ -342,9 +333,9 @@ public:
if (isTypeidPointer())
return QualType(Typeid.TypeInfoType, 0);
if (isFunctionPointer())
- return asFunctionPointer().getFunction()->getDecl()->getType();
+ return Fn.getFunction()->getDecl()->getType();
- if (inPrimitiveArray() && Offset != asBlockPointer().Base) {
+ if (inPrimitiveArray() && Offset != BS.Base) {
// Unfortunately, complex and vector types are not array types in clang,
// but they are for us.
if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe())
@@ -357,19 +348,17 @@ public:
return getFieldDesc()->getType();
}
- [[nodiscard]] Pointer getDeclPtr() const {
- return Pointer(asBlockPointer().Pointee);
- }
+ [[nodiscard]] Pointer getDeclPtr() const { return Pointer(BS.Pointee); }
/// Returns the element size of the innermost field.
size_t elemSize() const {
if (isIntegralPointer()) {
- if (!asIntPointer().Desc)
+ if (!Int.Desc)
return 1;
- return asIntPointer().Desc->getElemSize();
+ return Int.Desc->getElemSize();
}
- if (asBlockPointer().Base == RootPtrMark)
+ if (BS.Base == RootPtrMark)
return getDeclDesc()->getSize();
return getFieldDesc()->getElemSize();
}
@@ -383,24 +372,22 @@ public:
unsigned getOffset() const {
assert(Offset != PastEndMark && "invalid offset");
assert(isBlockPointer());
- if (asBlockPointer().Base == RootPtrMark)
+ if (BS.Base == RootPtrMark)
return Offset;
unsigned Adjust = 0;
- if (Offset != asBlockPointer().Base) {
+ if (Offset != BS.Base) {
if (getFieldDesc()->ElemDesc)
Adjust = sizeof(InlineDescriptor);
else
Adjust = sizeof(InitMapPtr);
}
- return Offset - asBlockPointer().Base - Adjust;
+ return Offset - BS.Base - Adjust;
}
/// Whether this array refers to an array, but not
/// to the first element.
- bool isArrayRoot() const {
- return inArray() && Offset == asBlockPointer().Base;
- }
+ bool isArrayRoot() const { return inArray() && Offset == BS.Base; }
/// Checks if the innermost field is an array.
bool inArray() const {
@@ -409,7 +396,7 @@ public:
return false;
}
bool inUnion() const {
- if (isBlockPointer() && asBlockPointer().Base >= sizeof(InlineDescriptor))
+ if (isBlockPointer() && BS.Base >= sizeof(InlineDescriptor))
return getInlineDesc()->InUnion;
return false;
};
@@ -431,7 +418,7 @@ public:
if (!isBlockPointer())
return false;
- const BlockPointer &BP = asBlockPointer();
+ const BlockPointer &BP = BS;
if (inArray() && BP.Base != Offset)
return true;
@@ -446,16 +433,15 @@ public:
bool isRoot() const {
if (isZero() || !isBlockPointer())
return true;
- return (asBlockPointer().Base ==
- asBlockPointer().Pointee->getDescriptor()->getMetadataSize() ||
- asBlockPointer().Base == 0);
+ return (BS.Base == BS.Pointee->getDescriptor()->getMetadataSize() ||
+ BS.Base == 0);
}
/// If this pointer has an InlineDescriptor we can use to initialize.
bool canBeInitialized() const {
if (!isBlockPointer())
return false;
- return asBlockPointer().Pointee && asBlockPointer().Base > 0;
+ return BS.Pointee && BS.Base > 0;
}
[[nodiscard]] const BlockPointer &asBlockPointer() const {
@@ -497,29 +483,29 @@ public:
/// Checks if the storage is extern.
bool isExtern() const {
if (isBlockPointer())
- return asBlockPointer().Pointee && asBlockPointer().Pointee->isExtern();
+ return BS.Pointee && BS.Pointee->isExtern();
return false;
}
/// Checks if the storage is static.
bool isStatic() const {
if (!isBlockPointer())
return true;
- assert(asBlockPointer().Pointee);
- return asBlockPointer().Pointee->isStatic();
+ assert(BS.Pointee);
+ return BS.Pointee->isStatic();
}
/// Checks if the storage is temporary.
bool isTemporary() const {
if (isBlockPointer()) {
- assert(asBlockPointer().Pointee);
- return asBlockPointer().Pointee->isTemporary();
+ assert(BS.Pointee);
+ return BS.Pointee->isTemporary();
}
return false;
}
/// Checks if the storage has been dynamically allocated.
bool isDynamic() const {
if (isBlockPointer()) {
- assert(asBlockPointer().Pointee);
- return asBlockPointer().Pointee->isDynamic();
+ assert(BS.Pointee);
+ return BS.Pointee->isDynamic();
}
return false;
}
@@ -535,15 +521,13 @@ public:
bool isWeak() const {
if (isFunctionPointer())
- return asFunctionPointer().isWeak();
+ return Fn.isWeak();
if (!isBlockPointer())
return false;
assert(isBlockPointer());
- return asBlockPointer().Pointee->isWeak();
+ return BS.Pointee->isWeak();
}
- /// Checks if an object was initialized.
- bool isInitialized() const;
/// Checks if the object is active.
bool isActive() const {
if (!isBlockPointer())
@@ -560,7 +544,7 @@ public:
if (!isBlockPointer())
return false;
- if (const Block *Pointee = asBlockPointer().Pointee)
+ if (const Block *Pointee = BS.Pointee)
return Pointee->isDummy();
return false;
}
@@ -587,8 +571,8 @@ public:
/// Returns the declaration ID.
UnsignedOrNone getDeclID() const {
if (isBlockPointer()) {
- assert(asBlockPointer().Pointee);
- return asBlockPointer().Pointee->getDeclID();
+ assert(BS.Pointee);
+ return BS.Pointee->getDeclID();
}
return std::nullopt;
}
@@ -596,9 +580,9 @@ public:
/// Returns the byte offset from the start.
uint64_t getByteOffset() const {
if (isIntegralPointer())
- return asIntPointer().Value + Offset;
+ return Int.Value + Offset;
if (isTypeidPointer())
- return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
+ return reinterpret_cast<uintptr_t>(Typeid.TypePtr) + Offset;
if (isOnePastEnd())
return PastEndMark;
return Offset;
@@ -611,13 +595,13 @@ public:
return getSize() / elemSize();
}
- const Block *block() const { return asBlockPointer().Pointee; }
+ const Block *block() const { return BS.Pointee; }
/// If backed by actual data (i.e. a block pointer), return
/// an address to that data.
const std::byte *getRawAddress() const {
assert(isBlockPointer());
- return asBlockPointer().Pointee->rawData() + Offset;
+ return BS.Pointee->rawData() + Offset;
}
/// Returns the index into an array.
@@ -629,8 +613,7 @@ public:
return 0;
// narrow()ed element in a composite array.
- if (asBlockPointer().Base > sizeof(InlineDescriptor) &&
- asBlockPointer().Base == Offset)
+ if (BS.Base > sizeof(InlineDescriptor) && BS.Base == Offset)
return 0;
if (auto ElemSize = elemSize())
@@ -643,7 +626,7 @@ public:
if (!isBlockPointer())
return false;
- if (!asBlockPointer().Pointee)
+ if (!BS.Pointee)
return false;
if (isUnknownSizeArray())
@@ -676,16 +659,15 @@ public:
template <typename T> T &deref() const {
assert(isLive() && "Invalid pointer");
assert(isBlockPointer());
- assert(asBlockPointer().Pointee);
+ assert(BS.Pointee);
assert(isDereferencable());
- assert(Offset + sizeof(T) <=
- asBlockPointer().Pointee->getDescriptor()->getAllocSize());
+ assert(Offset + sizeof(T) <= BS.Pointee->getDescriptor()->getAllocSize());
if (isArrayRoot())
- return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() +
- asBlockPointer().Base + sizeof(InitMapPtr));
+ return *reinterpret_cast<T *>(BS.Pointee->rawData() + BS.Base +
+ sizeof(InitMapPtr));
- return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset);
+ return *reinterpret_cast<T *>(BS.Pointee->rawData() + Offset);
}
/// Dereferences the element at index \p I.
@@ -693,18 +675,17 @@ public:
template <typename T> T &elem(unsigned I) const {
assert(isLive() && "Invalid pointer");
assert(isBlockPointer());
- assert(asBlockPointer().Pointee);
+ assert(BS.Pointee);
assert(isDereferencable());
assert(getFieldDesc()->isPrimitiveArray());
+ assert(I < getFieldDesc()->getNumElems());
unsigned ElemByteOffset = I * getFieldDesc()->getElemSize();
- if (isArrayRoot())
- return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() +
- asBlockPointer().Base + sizeof(InitMapPtr) +
- ElemByteOffset);
+ unsigned ReadOffset = BS.Base + sizeof(InitMapPtr) + ElemByteOffset;
+ assert(ReadOffset + sizeof(T) <=
+ BS.Pointee->getDescriptor()->getAllocSize());
- return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset +
- ElemByteOffset);
+ return *reinterpret_cast<T *>(BS.Pointee->rawData() + ReadOffset);
}
/// Whether this block can be read from at all. This is only true for
@@ -724,6 +705,11 @@ public:
/// used in situations where we *know* we have initialized *all* elements
/// of a primtive array.
void initializeAllElements() const;
+ /// Checks if an object was initialized.
+ bool isInitialized() const;
+ /// Like isInitialized(), but for primitive arrays.
+ bool isElementInitialized(unsigned Index) const;
+ bool allElementsInitialized() const;
/// Activats a field.
void activate() const;
/// Deactivates an entire strurcutre.
@@ -732,7 +718,7 @@ public:
Lifetime getLifetime() const {
if (!isBlockPointer())
return Lifetime::Started;
- if (asBlockPointer().Base < sizeof(InlineDescriptor))
+ if (BS.Base < sizeof(InlineDescriptor))
return Lifetime::Started;
return getInlineDesc()->LifeState;
}
@@ -740,7 +726,7 @@ public:
void endLifetime() const {
if (!isBlockPointer())
return;
- if (asBlockPointer().Base < sizeof(InlineDescriptor))
+ if (BS.Base < sizeof(InlineDescriptor))
return;
getInlineDesc()->LifeState = Lifetime::Ended;
}
@@ -748,7 +734,7 @@ public:
void startLifetime() const {
if (!isBlockPointer())
return;
- if (asBlockPointer().Base < sizeof(InlineDescriptor))
+ if (BS.Base < sizeof(InlineDescriptor))
return;
getInlineDesc()->LifeState = Lifetime::Started;
}
@@ -801,10 +787,10 @@ private:
/// Returns the embedded descriptor preceding a field.
InlineDescriptor *getInlineDesc() const {
assert(isBlockPointer());
- assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor));
- assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize());
- assert(asBlockPointer().Base >= sizeof(InlineDescriptor));
- return getDescriptor(asBlockPointer().Base);
+ assert(BS.Base != sizeof(GlobalInlineDescriptor));
+ assert(BS.Base <= BS.Pointee->getSize());
+ assert(BS.Base >= sizeof(InlineDescriptor));
+ return getDescriptor(BS.Base);
}
/// Returns a descriptor at a given offset.
@@ -812,8 +798,8 @@ private:
assert(Offset != 0 && "Not a nested pointer");
assert(isBlockPointer());
assert(!isZero());
- return reinterpret_cast<InlineDescriptor *>(
- asBlockPointer().Pointee->rawData() + Offset) -
+ return reinterpret_cast<InlineDescriptor *>(BS.Pointee->rawData() +
+ Offset) -
1;
}
@@ -821,8 +807,7 @@ private:
InitMapPtr &getInitMap() const {
assert(isBlockPointer());
assert(!isZero());
- return *reinterpret_cast<InitMapPtr *>(asBlockPointer().Pointee->rawData() +
- asBlockPointer().Base);
+ return *reinterpret_cast<InitMapPtr *>(BS.Pointee->rawData() + BS.Base);
}
/// Offset into the storage.
diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h
index 6e3a49cadcbf..54fd39ac6fcc 100644
--- a/clang/lib/AST/ByteCode/PrimType.h
+++ b/clang/lib/AST/ByteCode/PrimType.h
@@ -272,14 +272,4 @@ static inline bool aligned(const void *P) {
} \
} while (0)
-#define COMPOSITE_TYPE_SWITCH(Expr, B, D) \
- do { \
- switch (Expr) { \
- TYPE_SWITCH_CASE(PT_Ptr, B) \
- default: { \
- D; \
- break; \
- } \
- } \
- } while (0)
#endif
diff --git a/clang/lib/AST/ByteCode/Program.cpp b/clang/lib/AST/ByteCode/Program.cpp
index 5d72044af969..75bfd9fd2d8e 100644
--- a/clang/lib/AST/ByteCode/Program.cpp
+++ b/clang/lib/AST/ByteCode/Program.cpp
@@ -101,7 +101,7 @@ unsigned Program::createGlobalString(const StringLiteral *S, const Expr *Base) {
}
}
}
- Ptr.initialize();
+ Ptr.initializeAllElements();
return GlobalIndex;
}
@@ -111,7 +111,7 @@ Pointer Program::getPtrGlobal(unsigned Idx) const {
return Pointer(Globals[Idx]->block());
}
-std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
+UnsignedOrNone Program::getGlobal(const ValueDecl *VD) {
if (auto It = GlobalIndices.find(VD); It != GlobalIndices.end())
return It->second;
@@ -131,14 +131,14 @@ std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
return std::nullopt;
}
-std::optional<unsigned> Program::getGlobal(const Expr *E) {
+UnsignedOrNone Program::getGlobal(const Expr *E) {
if (auto It = GlobalIndices.find(E); It != GlobalIndices.end())
return It->second;
return std::nullopt;
}
-std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,
- const Expr *Init) {
+UnsignedOrNone Program::getOrCreateGlobal(const ValueDecl *VD,
+ const Expr *Init) {
if (auto Idx = getGlobal(VD))
return Idx;
@@ -195,8 +195,7 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) {
return I;
}
-std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
- const Expr *Init) {
+UnsignedOrNone Program::createGlobal(const ValueDecl *VD, const Expr *Init) {
bool IsStatic, IsExtern;
bool IsWeak = VD->isWeak();
if (const auto *Var = dyn_cast<VarDecl>(VD)) {
@@ -213,7 +212,7 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
// Register all previous declarations as well. For extern blocks, just replace
// the index with the new variable.
- std::optional<unsigned> Idx =
+ UnsignedOrNone Idx =
createGlobal(VD, VD->getType(), IsStatic, IsExtern, IsWeak, Init);
if (!Idx)
return std::nullopt;
@@ -240,7 +239,7 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
return *Idx;
}
-std::optional<unsigned> Program::createGlobal(const Expr *E) {
+UnsignedOrNone Program::createGlobal(const Expr *E) {
if (auto Idx = getGlobal(E))
return Idx;
if (auto Idx = createGlobal(E, E->getType(), /*isStatic=*/true,
@@ -251,9 +250,9 @@ std::optional<unsigned> Program::createGlobal(const Expr *E) {
return std::nullopt;
}
-std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
- bool IsStatic, bool IsExtern,
- bool IsWeak, const Expr *Init) {
+UnsignedOrNone Program::createGlobal(const DeclTy &D, QualType Ty,
+ bool IsStatic, bool IsExtern, bool IsWeak,
+ const Expr *Init) {
// Create a descriptor for the global.
Descriptor *Desc;
const bool IsConst = Ty.isConstQualified();
@@ -332,10 +331,9 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
continue;
// In error cases, the base might not be a RecordType.
- const auto *RT = Spec.getType()->getAs<RecordType>();
- if (!RT)
+ const auto *BD = Spec.getType()->getAsCXXRecordDecl();
+ if (!BD)
return nullptr;
- const RecordDecl *BD = RT->getOriginalDecl()->getDefinitionOrSelf();
const Record *BR = getOrCreateRecord(BD);
const Descriptor *Desc = GetBaseDesc(BD, BR);
@@ -348,11 +346,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
}
for (const CXXBaseSpecifier &Spec : CD->vbases()) {
- const auto *RT = Spec.getType()->getAs<RecordType>();
- if (!RT)
- return nullptr;
-
- const RecordDecl *BD = RT->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *BD = Spec.getType()->castAsCXXRecordDecl();
const Record *BR = getOrCreateRecord(BD);
const Descriptor *Desc = GetBaseDesc(BD, BR);
@@ -408,9 +402,8 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
const Expr *Init) {
// Classes and structures.
- if (const auto *RT = Ty->getAs<RecordType>()) {
- if (const auto *Record =
- getOrCreateRecord(RT->getOriginalDecl()->getDefinitionOrSelf()))
+ if (const auto *RD = Ty->getAsRecordDecl()) {
+ if (const auto *Record = getOrCreateRecord(RD))
return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary,
IsMutable, IsVolatile);
return allocateDescriptor(D, MDSize);
diff --git a/clang/lib/AST/ByteCode/Program.h b/clang/lib/AST/ByteCode/Program.h
index 90b48ee5b669..28fcc97f5339 100644
--- a/clang/lib/AST/ByteCode/Program.h
+++ b/clang/lib/AST/ByteCode/Program.h
@@ -78,21 +78,21 @@ public:
}
/// Finds a global's index.
- std::optional<unsigned> getGlobal(const ValueDecl *VD);
- std::optional<unsigned> getGlobal(const Expr *E);
+ UnsignedOrNone getGlobal(const ValueDecl *VD);
+ UnsignedOrNone getGlobal(const Expr *E);
/// Returns or creates a global an creates an index to it.
- std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD,
- const Expr *Init = nullptr);
+ UnsignedOrNone getOrCreateGlobal(const ValueDecl *VD,
+ const Expr *Init = nullptr);
/// Returns or creates a dummy value for unknown declarations.
unsigned getOrCreateDummy(const DeclTy &D);
/// Creates a global and returns its index.
- std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *Init);
+ UnsignedOrNone createGlobal(const ValueDecl *VD, const Expr *Init);
/// Creates a global from a lifetime-extended temporary.
- std::optional<unsigned> createGlobal(const Expr *E);
+ UnsignedOrNone createGlobal(const Expr *E);
/// Creates a new function from a code range.
template <typename... Ts>
@@ -165,9 +165,9 @@ public:
private:
friend class DeclScope;
- std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
- bool IsStatic, bool IsExtern,
- bool IsWeak, const Expr *Init = nullptr);
+ UnsignedOrNone createGlobal(const DeclTy &D, QualType Ty, bool IsStatic,
+ bool IsExtern, bool IsWeak,
+ const Expr *Init = nullptr);
/// Reference to the VM context.
Context &Ctx;
diff --git a/clang/lib/AST/ByteCode/Record.cpp b/clang/lib/AST/ByteCode/Record.cpp
index a7934ccb4e55..ff5c82d24457 100644
--- a/clang/lib/AST/ByteCode/Record.cpp
+++ b/clang/lib/AST/ByteCode/Record.cpp
@@ -37,6 +37,13 @@ std::string Record::getName() const {
return Ret;
}
+bool Record::hasTrivialDtor() const {
+ if (isAnonymousUnion())
+ return true;
+ const CXXDestructorDecl *Dtor = getDestructor();
+ return !Dtor || Dtor->isTrivial();
+}
+
const Record::Field *Record::getField(const FieldDecl *FD) const {
auto It = FieldMap.find(FD->getFirstDecl());
assert(It != FieldMap.end() && "Missing field");
@@ -50,10 +57,8 @@ const Record::Base *Record::getBase(const RecordDecl *FD) const {
}
const Record::Base *Record::getBase(QualType T) const {
- if (auto *RT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
+ if (auto *RD = T->getAsCXXRecordDecl())
return BaseMap.lookup(RD);
- }
return nullptr;
}
diff --git a/clang/lib/AST/ByteCode/Record.h b/clang/lib/AST/ByteCode/Record.h
index 93ca43046180..8245eeff2f20 100644
--- a/clang/lib/AST/ByteCode/Record.h
+++ b/clang/lib/AST/ByteCode/Record.h
@@ -76,6 +76,10 @@ public:
return nullptr;
}
+ /// Returns true for anonymous unions and records
+ /// with no destructor or for those with a trivial destructor.
+ bool hasTrivialDtor() const;
+
using const_field_iter = FieldList::const_iterator;
llvm::iterator_range<const_field_iter> fields() const {
return llvm::make_range(Fields.begin(), Fields.end());
diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h
index 6fc33222ac95..387ce396a723 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -59,8 +59,6 @@ class State {
public:
virtual ~State();
- virtual bool checkingForUndefinedBehavior() const = 0;
- virtual bool checkingPotentialConstantExpression() const = 0;
virtual bool noteUndefinedBehavior() = 0;
virtual bool keepEvaluatingAfterFailure() const = 0;
virtual bool keepEvaluatingAfterSideEffect() const = 0;
@@ -75,6 +73,16 @@ public:
virtual unsigned getCallStackDepth() = 0;
virtual bool noteSideEffect() = 0;
+ /// Are we checking whether the expression is a potential constant
+ /// expression?
+ bool checkingPotentialConstantExpression() const {
+ return CheckingPotentialConstantExpression;
+ }
+ /// Are we checking an expression for overflow?
+ bool checkingForUndefinedBehavior() const {
+ return CheckingForUndefinedBehavior;
+ }
+
public:
State() = default;
/// Diagnose that the evaluation could not be folded (FF => FoldFailure)
@@ -128,6 +136,19 @@ public:
/// constant value.
bool InConstantContext = false;
+ /// Whether we're checking that an expression is a potential constant
+ /// expression. If so, do not fail on constructs that could become constant
+ /// later on (such as a use of an undefined global).
+ bool CheckingPotentialConstantExpression = false;
+
+ /// Whether we're checking for an expression that has undefined behavior.
+ /// If so, we will produce warnings if we encounter an operation that is
+ /// always undefined.
+ ///
+ /// Note that we still need to evaluate the expression normally when this
+ /// is set; this is used when evaluating ICEs in C.
+ bool CheckingForUndefinedBehavior = false;
+
private:
void addCallStack(unsigned Limit);
diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp
index e4b77edc063d..7a3e7ea4e5b8 100644
--- a/clang/lib/AST/CXXInheritance.cpp
+++ b/clang/lib/AST/CXXInheritance.cpp
@@ -128,17 +128,11 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches) const {
const CXXRecordDecl *Record = this;
while (true) {
for (const auto &I : Record->bases()) {
- const RecordType *Ty = I.getType()->getAs<RecordType>();
- if (!Ty)
+ const auto *Base = I.getType()->getAsCXXRecordDecl();
+ if (!Base || !(Base->isBeingDefined() || Base->isCompleteDefinition()))
return false;
-
- CXXRecordDecl *Base = cast_if_present<CXXRecordDecl>(
- Ty->getOriginalDecl()->getDefinition());
- if (!Base ||
- (Base->isDependentContext() &&
- !Base->isCurrentInstantiation(Record))) {
+ if (Base->isDependentContext() && !Base->isCurrentInstantiation(Record))
return false;
- }
Queue.push_back(Base);
if (!BaseMatches(Base))
@@ -196,7 +190,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
if (isDetectingVirtual() && DetectedVirtual == nullptr) {
// If this is the first virtual we find, remember it. If it turns out
// there is no base path here, we'll reset it later.
- DetectedVirtual = BaseType->getAs<RecordType>();
+ DetectedVirtual = BaseType->getAsCanonical<RecordType>();
SetVirtual = true;
}
} else {
@@ -255,9 +249,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
const TemplateSpecializationType *TST =
BaseSpec.getType()->getAs<TemplateSpecializationType>();
if (!TST) {
- if (auto *RT = BaseSpec.getType()->getAs<RecordType>())
- BaseRecord = cast<CXXRecordDecl>(RT->getOriginalDecl())
- ->getDefinitionOrSelf();
+ BaseRecord = BaseSpec.getType()->getAsCXXRecordDecl();
} else {
TemplateName TN = TST->getTemplateName();
if (auto *TD =
@@ -271,7 +263,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
BaseRecord = nullptr;
}
} else {
- BaseRecord = cast<CXXRecordDecl>(BaseSpec.getType()->getAsRecordDecl());
+ BaseRecord = BaseSpec.getType()->castAsCXXRecordDecl();
}
if (BaseRecord &&
lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) {
@@ -335,10 +327,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches,
if (!PE.Base->isVirtual())
continue;
- CXXRecordDecl *VBase = nullptr;
- if (const RecordType *Record = PE.Base->getType()->getAs<RecordType>())
- VBase = cast<CXXRecordDecl>(Record->getOriginalDecl())
- ->getDefinitionOrSelf();
+ auto *VBase = PE.Base->getType()->getAsCXXRecordDecl();
if (!VBase)
break;
@@ -347,11 +336,8 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches,
// base is a subobject of any other path; if so, then the
// declaration in this path are hidden by that patch.
for (const CXXBasePath &HidingP : Paths) {
- CXXRecordDecl *HidingClass = nullptr;
- if (const RecordType *Record =
- HidingP.back().Base->getType()->getAs<RecordType>())
- HidingClass = cast<CXXRecordDecl>(Record->getOriginalDecl())
- ->getDefinitionOrSelf();
+ auto *HidingClass =
+ HidingP.back().Base->getType()->getAsCXXRecordDecl();
if (!HidingClass)
break;
@@ -407,7 +393,7 @@ bool CXXRecordDecl::hasMemberName(DeclarationName Name) const {
CXXBasePaths Paths(false, false, false);
return lookupInBases(
[Name](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
- return findOrdinaryMember(Specifier->getType()->getAsCXXRecordDecl(),
+ return findOrdinaryMember(Specifier->getType()->castAsCXXRecordDecl(),
Path, Name);
},
Paths);
@@ -470,9 +456,7 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD,
= ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())];
for (const auto &Base : RD->bases()) {
- if (const RecordType *RT = Base.getType()->getAs<RecordType>()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf();
+ if (const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl()) {
if (!BaseDecl->isPolymorphic())
continue;
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 4507f415ce60..d8dffb7f5dc4 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2861,9 +2861,8 @@ VarDecl::needsDestruction(const ASTContext &Ctx) const {
bool VarDecl::hasFlexibleArrayInit(const ASTContext &Ctx) const {
assert(hasInit() && "Expect initializer to check for flexible array init");
- auto *Ty = getType()->getAs<RecordType>();
- if (!Ty ||
- !Ty->getOriginalDecl()->getDefinitionOrSelf()->hasFlexibleArrayMember())
+ auto *D = getType()->getAsRecordDecl();
+ if (!D || !D->hasFlexibleArrayMember())
return false;
auto *List = dyn_cast<InitListExpr>(getInit()->IgnoreParens());
if (!List)
@@ -2877,11 +2876,8 @@ bool VarDecl::hasFlexibleArrayInit(const ASTContext &Ctx) const {
CharUnits VarDecl::getFlexibleArrayInitChars(const ASTContext &Ctx) const {
assert(hasInit() && "Expect initializer to check for flexible array init");
- auto *Ty = getType()->getAs<RecordType>();
- if (!Ty)
- return CharUnits::Zero();
- const RecordDecl *RD = Ty->getOriginalDecl()->getDefinitionOrSelf();
- if (!Ty || !RD->hasFlexibleArrayMember())
+ auto *RD = getType()->getAsRecordDecl();
+ if (!RD || !RD->hasFlexibleArrayMember())
return CharUnits::Zero();
auto *List = dyn_cast<InitListExpr>(getInit()->IgnoreParens());
if (!List || List->getNumInits() == 0)
@@ -2992,7 +2988,7 @@ bool ParmVarDecl::isDestroyedInCallee() const {
// FIXME: isParamDestroyedInCallee() should probably imply
// isDestructedType()
- const auto *RT = getType()->getAs<RecordType>();
+ const auto *RT = getType()->getAsCanonical<RecordType>();
if (RT &&
RT->getOriginalDecl()
->getDefinitionOrSelf()
@@ -3507,7 +3503,7 @@ bool FunctionDecl::isUsableAsGlobalAllocationFunctionInConstantEvaluation(
while (const auto *TD = T->getAs<TypedefType>())
T = TD->getDecl()->getUnderlyingType();
const IdentifierInfo *II =
- T->castAs<EnumType>()->getOriginalDecl()->getIdentifier();
+ T->castAsCanonical<EnumType>()->getOriginalDecl()->getIdentifier();
if (II && II->isStr("__hot_cold_t"))
Consume();
}
@@ -3604,6 +3600,10 @@ bool FunctionDecl::isNoReturn() const {
return false;
}
+bool FunctionDecl::isAnalyzerNoReturn() const {
+ return hasAttr<AnalyzerNoReturnAttr>();
+}
+
bool FunctionDecl::isMemberLikeConstrainedFriend() const {
// C++20 [temp.friend]p9:
// A non-template friend declaration with a requires-clause [or]
@@ -4657,7 +4657,7 @@ bool FieldDecl::isAnonymousStructOrUnion() const {
if (!isImplicit() || getDeclName())
return false;
- if (const auto *Record = getType()->getAs<RecordType>())
+ if (const auto *Record = getType()->getAsCanonical<RecordType>())
return Record->getOriginalDecl()->isAnonymousStructOrUnion();
return false;
@@ -4715,7 +4715,7 @@ bool FieldDecl::isZeroSize(const ASTContext &Ctx) const {
return false;
// -- is not of class type, or
- const auto *RT = getType()->getAs<RecordType>();
+ const auto *RT = getType()->getAsCanonical<RecordType>();
if (!RT)
return false;
const RecordDecl *RD = RT->getOriginalDecl()->getDefinition();
@@ -4738,7 +4738,7 @@ bool FieldDecl::isZeroSize(const ASTContext &Ctx) const {
// MS ABI: has nonzero size if it is a class type with class type fields,
// whether or not they have nonzero size
return !llvm::any_of(CXXRD->fields(), [](const FieldDecl *Field) {
- return Field->getType()->getAs<RecordType>();
+ return Field->getType()->isRecordType();
});
}
@@ -5142,7 +5142,7 @@ bool RecordDecl::isOrContainsUnion() const {
if (const RecordDecl *Def = getDefinition()) {
for (const FieldDecl *FD : Def->fields()) {
- const RecordType *RT = FD->getType()->getAs<RecordType>();
+ const RecordType *RT = FD->getType()->getAsCanonical<RecordType>();
if (RT && RT->getOriginalDecl()->isOrContainsUnion())
return true;
}
@@ -5274,10 +5274,8 @@ const FieldDecl *RecordDecl::findFirstNamedDataMember() const {
if (I->getIdentifier())
return I;
- if (const auto *RT = I->getType()->getAs<RecordType>())
- if (const FieldDecl *NamedDataMember = RT->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->findFirstNamedDataMember())
+ if (const auto *RD = I->getType()->getAsRecordDecl())
+ if (const FieldDecl *NamedDataMember = RD->findFirstNamedDataMember())
return NamedDataMember;
}
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 50b1a1d00009..aa1f5a114659 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -216,9 +216,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// Skip dependent types; we can't do any checking on them now.
if (BaseType->isDependentType())
continue;
- auto *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->castAs<RecordType>()->getOriginalDecl())
- ->getDefinitionOrSelf();
+ auto *BaseClassDecl = BaseType->castAsCXXRecordDecl();
// C++2a [class]p7:
// A standard-layout class is a class that:
@@ -1207,9 +1205,8 @@ void CXXRecordDecl::addedMember(Decl *D) {
// those because they are always unnamed.
bool IsZeroSize = Field->isZeroSize(Context);
- if (const auto *RecordTy = T->getAs<RecordType>()) {
- auto *FieldRec = cast<CXXRecordDecl>(RecordTy->getOriginalDecl());
- if (FieldRec->getDefinition()) {
+ if (auto *FieldRec = T->getAsCXXRecordDecl()) {
+ if (FieldRec->isBeingDefined() || FieldRec->isCompleteDefinition()) {
addedClassSubobject(FieldRec);
// We may need to perform overload resolution to determine whether a
@@ -1438,6 +1435,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().StructuralIfLiteral = false;
}
+ // If this type contains any address discriminated values we should
+ // have already indicated that the only special member functions that
+ // can possibly be trivial are the default constructor and destructor.
+ if (T.hasAddressDiscriminatedPointerAuth())
+ data().HasTrivialSpecialMembers &=
+ SMF_DefaultConstructor | SMF_Destructor;
+
// C++14 [meta.unary.prop]p4:
// T is a class type [...] with [...] no non-static data members other
// than subobjects of zero size
@@ -1908,15 +1912,14 @@ static void CollectVisibleConversions(
// Collect information recursively from any base classes.
for (const auto &I : Record->bases()) {
- const auto *RT = I.getType()->getAs<RecordType>();
- if (!RT) continue;
+ const auto *Base = I.getType()->getAsCXXRecordDecl();
+ if (!Base)
+ continue;
AccessSpecifier BaseAccess
= CXXRecordDecl::MergeAccess(Access, I.getAccessSpecifier());
bool BaseInVirtual = InVirtual || I.isVirtual();
- auto *Base =
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf();
CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess,
*HiddenTypes, Output, VOutput, HiddenVBaseCs);
}
@@ -1951,14 +1954,13 @@ static void CollectVisibleConversions(ASTContext &Context,
// Recursively collect conversions from base classes.
for (const auto &I : Record->bases()) {
- const auto *RT = I.getType()->getAs<RecordType>();
- if (!RT) continue;
+ const auto *Base = I.getType()->getAsCXXRecordDecl();
+ if (!Base)
+ continue;
- CollectVisibleConversions(
- Context,
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf(),
- I.isVirtual(), I.getAccessSpecifier(), HiddenTypes, Output, VBaseCs,
- HiddenVBaseCs);
+ CollectVisibleConversions(Context, Base, I.isVirtual(),
+ I.getAccessSpecifier(), HiddenTypes, Output,
+ VBaseCs, HiddenVBaseCs);
}
// Add any unhidden conversions provided by virtual bases.
@@ -2312,7 +2314,7 @@ bool CXXRecordDecl::mayBeAbstract() const {
for (const auto &B : bases()) {
const auto *BaseDecl = cast<CXXRecordDecl>(
- B.getType()->castAs<RecordType>()->getOriginalDecl());
+ B.getType()->castAsCanonical<RecordType>()->getOriginalDecl());
if (BaseDecl->isAbstract())
return true;
}
@@ -2472,11 +2474,9 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
};
for (const auto &I : RD->bases()) {
- const RecordType *RT = I.getType()->getAs<RecordType>();
- if (!RT)
+ const auto *Base = I.getType()->getAsCXXRecordDecl();
+ if (!Base)
continue;
- const auto *Base =
- cast<CXXRecordDecl>(RT->getOriginalDecl())->getDefinitionOrSelf();
if (CXXMethodDecl *D = this->getCorrespondingMethodInClass(Base))
AddFinalOverrider(D);
}
@@ -3437,13 +3437,12 @@ SourceRange UsingDecl::getSourceRange() const {
void UsingEnumDecl::anchor() {}
UsingEnumDecl *UsingEnumDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation UL,
- SourceLocation EL,
+ SourceLocation UL, SourceLocation EL,
SourceLocation NL,
TypeSourceInfo *EnumType) {
- assert(isa<EnumDecl>(EnumType->getType()->getAsTagDecl()));
return new (C, DC)
- UsingEnumDecl(DC, EnumType->getType()->getAsTagDecl()->getDeclName(), UL, EL, NL, EnumType);
+ UsingEnumDecl(DC, EnumType->getType()->castAsEnumDecl()->getDeclName(),
+ UL, EL, NL, EnumType);
}
UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C,
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index b91b4670c63a..3162857aac5d 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -730,15 +730,15 @@ void TemplateTypeParmDecl::setDefaultArgument(
}
unsigned TemplateTypeParmDecl::getDepth() const {
- return getTypeForDecl()->castAs<TemplateTypeParmType>()->getDepth();
+ return dyn_cast<TemplateTypeParmType>(getTypeForDecl())->getDepth();
}
unsigned TemplateTypeParmDecl::getIndex() const {
- return getTypeForDecl()->castAs<TemplateTypeParmType>()->getIndex();
+ return dyn_cast<TemplateTypeParmType>(getTypeForDecl())->getIndex();
}
bool TemplateTypeParmDecl::isParameterPack() const {
- return getTypeForDecl()->castAs<TemplateTypeParmType>()->isParameterPack();
+ return dyn_cast<TemplateTypeParmType>(getTypeForDecl())->isParameterPack();
}
void TemplateTypeParmDecl::setTypeConstraint(
diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp
index 6c7b995d5756..55f5a994d788 100644
--- a/clang/lib/AST/DeclarationName.cpp
+++ b/clang/lib/AST/DeclarationName.cpp
@@ -113,13 +113,14 @@ static void printCXXConstructorDestructorName(QualType ClassType,
PrintingPolicy Policy) {
// We know we're printing C++ here. Ensure we print types properly.
Policy.adjustForCPlusPlus();
+ Policy.SuppressScope = true;
- if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) {
+ if (const RecordType *ClassRec = ClassType->getAsCanonical<RecordType>()) {
ClassRec->getOriginalDecl()->printName(OS, Policy);
return;
}
if (Policy.SuppressTemplateArgsInCXXConstructors) {
- if (auto *InjTy = ClassType->getAs<InjectedClassNameType>()) {
+ if (auto *InjTy = ClassType->getAsCanonical<InjectedClassNameType>()) {
InjTy->getOriginalDecl()->printName(OS, Policy);
return;
}
diff --git a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp
index 8821cd332e91..6d7925b437b0 100644
--- a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp
+++ b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp
@@ -87,7 +87,7 @@ using namespace clang;
// ends up executing RAV's implementation because we used a qualified
// function call.
//
-// End result: RAV::TraverseCallExpr() is executed,
+// End result: RAV::TraverseCallExpr() is executed.
namespace {
template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> {
DynamicRecursiveASTVisitorBase<Const> &Visitor;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 340de6d4be93..cdff160067fe 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -74,8 +74,7 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const {
if (DerivedType->isDependentType())
return nullptr;
- const RecordType *Ty = DerivedType->castAs<RecordType>();
- return cast<CXXRecordDecl>(Ty->getOriginalDecl())->getDefinitionOrSelf();
+ return DerivedType->castAsCXXRecordDecl();
}
const Expr *Expr::skipRValueSubobjectAdjustments(
@@ -90,10 +89,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments(
CE->getCastKind() == CK_UncheckedDerivedToBase) &&
E->getType()->isRecordType()) {
E = CE->getSubExpr();
- const auto *Derived =
- cast<CXXRecordDecl>(
- E->getType()->castAs<RecordType>()->getOriginalDecl())
- ->getDefinitionOrSelf();
+ const auto *Derived = E->getType()->castAsCXXRecordDecl();
Adjustments.push_back(SubobjectAdjustment(CE, Derived));
continue;
}
@@ -2032,9 +2028,7 @@ CXXBaseSpecifier **CastExpr::path_buffer() {
const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType,
QualType opType) {
- auto RD =
- unionType->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
- return getTargetFieldForToUnionCast(RD, opType);
+ return getTargetFieldForToUnionCast(unionType->castAsRecordDecl(), opType);
}
const FieldDecl *CastExpr::getTargetFieldForToUnionCast(const RecordDecl *RD,
@@ -2401,6 +2395,7 @@ EmbedExpr::EmbedExpr(const ASTContext &Ctx, SourceLocation Loc,
setDependence(ExprDependence::None);
FakeChildNode = IntegerLiteral::Create(
Ctx, llvm::APInt::getZero(Ctx.getTypeSize(getType())), getType(), Loc);
+ assert(getType()->isSignedIntegerType() && "IntTy should be signed");
}
InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
@@ -3396,10 +3391,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
if (ILE->getType()->isRecordType()) {
unsigned ElementNo = 0;
- RecordDecl *RD = ILE->getType()
- ->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ auto *RD = ILE->getType()->castAsRecordDecl();
// In C++17, bases were added to the list of members used by aggregate
// initialization.
@@ -3533,6 +3525,56 @@ bool CallExpr::isBuiltinAssumeFalse(const ASTContext &Ctx) const {
Arg->EvaluateAsBooleanCondition(ArgVal, Ctx) && !ArgVal;
}
+const AllocSizeAttr *CallExpr::getCalleeAllocSizeAttr() const {
+ if (const FunctionDecl *DirectCallee = getDirectCallee())
+ return DirectCallee->getAttr<AllocSizeAttr>();
+ if (const Decl *IndirectCallee = getCalleeDecl())
+ return IndirectCallee->getAttr<AllocSizeAttr>();
+ return nullptr;
+}
+
+std::optional<llvm::APInt>
+CallExpr::evaluateBytesReturnedByAllocSizeCall(const ASTContext &Ctx) const {
+ const AllocSizeAttr *AllocSize = getCalleeAllocSizeAttr();
+
+ assert(AllocSize && AllocSize->getElemSizeParam().isValid());
+ unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex();
+ unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType());
+ if (getNumArgs() <= SizeArgNo)
+ return std::nullopt;
+
+ auto EvaluateAsSizeT = [&](const Expr *E, llvm::APSInt &Into) {
+ Expr::EvalResult ExprResult;
+ if (E->isValueDependent() ||
+ !E->EvaluateAsInt(ExprResult, Ctx, Expr::SE_AllowSideEffects))
+ return false;
+ Into = ExprResult.Val.getInt();
+ if (Into.isNegative() || !Into.isIntN(BitsInSizeT))
+ return false;
+ Into = Into.zext(BitsInSizeT);
+ return true;
+ };
+
+ llvm::APSInt SizeOfElem;
+ if (!EvaluateAsSizeT(getArg(SizeArgNo), SizeOfElem))
+ return std::nullopt;
+
+ if (!AllocSize->getNumElemsParam().isValid())
+ return SizeOfElem;
+
+ llvm::APSInt NumberOfElems;
+ unsigned NumArgNo = AllocSize->getNumElemsParam().getASTIndex();
+ if (!EvaluateAsSizeT(getArg(NumArgNo), NumberOfElems))
+ return std::nullopt;
+
+ bool Overflow;
+ llvm::APInt BytesAvailable = SizeOfElem.umul_ov(NumberOfElems, Overflow);
+ if (Overflow)
+ return std::nullopt;
+
+ return BytesAvailable;
+}
+
bool CallExpr::isCallToStdMove() const {
return getBuiltinCallee() == Builtin::BImove;
}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index a71cb8b0143b..2376e482a19f 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -114,15 +114,6 @@ namespace {
return Ctx.getLValueReferenceType(E->getType());
}
- /// Given a CallExpr, try to get the alloc_size attribute. May return null.
- static const AllocSizeAttr *getAllocSizeAttr(const CallExpr *CE) {
- if (const FunctionDecl *DirectCallee = CE->getDirectCallee())
- return DirectCallee->getAttr<AllocSizeAttr>();
- if (const Decl *IndirectCallee = CE->getCalleeDecl())
- return IndirectCallee->getAttr<AllocSizeAttr>();
- return nullptr;
- }
-
/// Attempts to unwrap a CallExpr (with an alloc_size attribute) from an Expr.
/// This will look through a single cast.
///
@@ -142,7 +133,7 @@ namespace {
E = Cast->getSubExpr()->IgnoreParens();
if (const auto *CE = dyn_cast<CallExpr>(E))
- return getAllocSizeAttr(CE) ? CE : nullptr;
+ return CE->getCalleeAllocSizeAttr() ? CE : nullptr;
return nullptr;
}
@@ -465,49 +456,7 @@ namespace {
void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E,
const APSInt &N);
/// Add N to the address of this subobject.
- void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N) {
- if (Invalid || !N) return;
- uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue();
- if (isMostDerivedAnUnsizedArray()) {
- diagnoseUnsizedArrayPointerArithmetic(Info, E);
- // Can't verify -- trust that the user is doing the right thing (or if
- // not, trust that the caller will catch the bad behavior).
- // FIXME: Should we reject if this overflows, at least?
- Entries.back() = PathEntry::ArrayIndex(
- Entries.back().getAsArrayIndex() + TruncatedN);
- return;
- }
-
- // [expr.add]p4: For the purposes of these operators, a pointer to a
- // nonarray object behaves the same as a pointer to the first element of
- // an array of length one with the type of the object as its element type.
- bool IsArray = MostDerivedPathLength == Entries.size() &&
- MostDerivedIsArrayElement;
- uint64_t ArrayIndex = IsArray ? Entries.back().getAsArrayIndex()
- : (uint64_t)IsOnePastTheEnd;
- uint64_t ArraySize =
- IsArray ? getMostDerivedArraySize() : (uint64_t)1;
-
- if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) {
- // Calculate the actual index in a wide enough type, so we can include
- // it in the note.
- N = N.extend(std::max<unsigned>(N.getBitWidth() + 1, 65));
- (llvm::APInt&)N += ArrayIndex;
- assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index");
- diagnosePointerArithmetic(Info, E, N);
- setInvalid();
- return;
- }
-
- ArrayIndex += TruncatedN;
- assert(ArrayIndex <= ArraySize &&
- "bounds check succeeded for out-of-bounds index");
-
- if (IsArray)
- Entries.back() = PathEntry::ArrayIndex(ArrayIndex);
- else
- IsOnePastTheEnd = (ArrayIndex != 0);
- }
+ void adjustIndex(EvalInfo &Info, const Expr *E, APSInt N, const LValue &LV);
};
/// A scope at the end of which an object can need to be destroyed.
@@ -894,6 +843,11 @@ namespace {
/// declaration whose initializer is being evaluated, if any.
APValue *EvaluatingDeclValue;
+ /// Stack of loops and 'switch' statements which we're currently
+ /// breaking/continuing; null entries are used to mark unlabeled
+ /// break/continue.
+ SmallVector<const Stmt *> BreakContinueStack;
+
/// Set of objects that are currently being constructed.
llvm::DenseMap<ObjectUnderConstruction, ConstructionPhase>
ObjectsUnderConstruction;
@@ -972,19 +926,6 @@ namespace {
/// fold (not just why it's not strictly a constant expression)?
bool HasFoldFailureDiagnostic;
- /// Whether we're checking that an expression is a potential constant
- /// expression. If so, do not fail on constructs that could become constant
- /// later on (such as a use of an undefined global).
- bool CheckingPotentialConstantExpression = false;
-
- /// Whether we're checking for an expression that has undefined behavior.
- /// If so, we will produce warnings if we encounter an operation that is
- /// always undefined.
- ///
- /// Note that we still need to evaluate the expression normally when this
- /// is set; this is used when evaluating ICEs in C.
- bool CheckingForUndefinedBehavior = false;
-
enum EvaluationMode {
/// Evaluate as a constant expression. Stop if we find that the expression
/// is not a constant expression.
@@ -1006,19 +947,6 @@ namespace {
EM_IgnoreSideEffects,
} EvalMode;
- /// Are we checking whether the expression is a potential constant
- /// expression?
- bool checkingPotentialConstantExpression() const override {
- return CheckingPotentialConstantExpression;
- }
-
- /// Are we checking an expression for overflow?
- // FIXME: We should check for any kind of undefined or suspicious behavior
- // in such constructs, not just overflow.
- bool checkingForUndefinedBehavior() const override {
- return CheckingForUndefinedBehavior;
- }
-
EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
: Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr),
CallStackDepth(0), NextCallIndex(1),
@@ -1799,7 +1727,7 @@ namespace {
Offset = CharUnits::fromQuantity(Offset64 + ElemSize64 * Index64);
if (checkNullPointer(Info, E, CSK_ArrayIndex))
- Designator.adjustIndex(Info, E, Index);
+ Designator.adjustIndex(Info, E, Index, *this);
clearIsNullPointer();
}
void adjustOffset(CharUnits N) {
@@ -1907,6 +1835,54 @@ namespace {
}
}
+void SubobjectDesignator::adjustIndex(EvalInfo &Info, const Expr *E, APSInt N,
+ const LValue &LV) {
+ if (Invalid || !N)
+ return;
+ uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue();
+ if (isMostDerivedAnUnsizedArray()) {
+ diagnoseUnsizedArrayPointerArithmetic(Info, E);
+ // Can't verify -- trust that the user is doing the right thing (or if
+ // not, trust that the caller will catch the bad behavior).
+ // FIXME: Should we reject if this overflows, at least?
+ Entries.back() =
+ PathEntry::ArrayIndex(Entries.back().getAsArrayIndex() + TruncatedN);
+ return;
+ }
+
+ // [expr.add]p4: For the purposes of these operators, a pointer to a
+ // nonarray object behaves the same as a pointer to the first element of
+ // an array of length one with the type of the object as its element type.
+ bool IsArray =
+ MostDerivedPathLength == Entries.size() && MostDerivedIsArrayElement;
+ uint64_t ArrayIndex =
+ IsArray ? Entries.back().getAsArrayIndex() : (uint64_t)IsOnePastTheEnd;
+ uint64_t ArraySize = IsArray ? getMostDerivedArraySize() : (uint64_t)1;
+
+ if (N < -(int64_t)ArrayIndex || N > ArraySize - ArrayIndex) {
+ if (!Info.checkingPotentialConstantExpression() ||
+ !LV.AllowConstexprUnknown) {
+ // Calculate the actual index in a wide enough type, so we can include
+ // it in the note.
+ N = N.extend(std::max<unsigned>(N.getBitWidth() + 1, 65));
+ (llvm::APInt &)N += ArrayIndex;
+ assert(N.ugt(ArraySize) && "bounds check failed for in-bounds index");
+ diagnosePointerArithmetic(Info, E, N);
+ }
+ setInvalid();
+ return;
+ }
+
+ ArrayIndex += TruncatedN;
+ assert(ArrayIndex <= ArraySize &&
+ "bounds check succeeded for out-of-bounds index");
+
+ if (IsArray)
+ Entries.back() = PathEntry::ArrayIndex(ArrayIndex);
+ else
+ IsOnePastTheEnd = (ArrayIndex != 0);
+}
+
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
const LValue &This, const Expr *E,
@@ -2623,8 +2599,7 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
Value.getUnionValue(), Kind, Value.getUnionField(), CheckedTemps);
}
if (Value.isStruct()) {
- RecordDecl *RD =
- Type->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
+ auto *RD = Type->castAsRecordDecl();
if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
unsigned BaseIndex = 0;
for (const CXXBaseSpecifier &BS : CD->bases()) {
@@ -4029,10 +4004,12 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
LastField = nullptr;
if (ObjType->isArrayType()) {
// Next subobject is an array element.
- const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType);
- assert(CAT && "vla in literal type?");
+ const ArrayType *AT = Info.Ctx.getAsArrayType(ObjType);
+ assert((isa<ConstantArrayType>(AT) || isa<IncompleteArrayType>(AT)) &&
+ "vla in literal type?");
uint64_t Index = Sub.Entries[I].getAsArrayIndex();
- if (CAT->getSize().ule(Index)) {
+ if (const auto *CAT = dyn_cast<ConstantArrayType>(AT);
+ CAT && CAT->getSize().ule(Index)) {
// Note, it should not be possible to form a pointer with a valid
// designator which points more than one past the end of the array.
if (Info.getLangOpts().CPlusPlus11)
@@ -4043,12 +4020,13 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
return handler.failed();
}
- ObjType = CAT->getElementType();
+ ObjType = AT->getElementType();
if (O->getArrayInitializedElts() > Index)
O = &O->getArrayInitializedElt(Index);
else if (!isRead(handler.AccessKind)) {
- if (!CheckArraySize(Info, CAT, E->getExprLoc()))
+ if (const auto *CAT = dyn_cast<ConstantArrayType>(AT);
+ CAT && !CheckArraySize(Info, CAT, E->getExprLoc()))
return handler.failed();
expandArray(*O, Index);
@@ -4110,7 +4088,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
}
// Next subobject is a class, struct or union field.
- RecordDecl *RD = ObjType->castAs<RecordType>()->getOriginalDecl();
+ RecordDecl *RD =
+ ObjType->castAsCanonical<RecordType>()->getOriginalDecl();
if (RD->isUnion()) {
const FieldDecl *UnionField = O->getUnionField();
if (!UnionField ||
@@ -5148,12 +5127,18 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
if (const PointerType *PT = TargetQT->getAs<PointerType>())
TargetQT = PT->getPointeeType();
- // Check this cast lands within the final derived-to-base subobject path.
- if (D.MostDerivedPathLength + E->path_size() > D.Entries.size()) {
- Info.CCEDiag(E, diag::note_constexpr_invalid_downcast)
- << D.MostDerivedType << TargetQT;
+ auto InvalidCast = [&]() {
+ if (!Info.checkingPotentialConstantExpression() ||
+ !Result.AllowConstexprUnknown) {
+ Info.CCEDiag(E, diag::note_constexpr_invalid_downcast)
+ << D.MostDerivedType << TargetQT;
+ }
return false;
- }
+ };
+
+ // Check this cast lands within the final derived-to-base subobject path.
+ if (D.MostDerivedPathLength + E->path_size() > D.Entries.size())
+ return InvalidCast();
// Check the type of the final cast. We don't need to check the path,
// since a cast can only be formed if the path is unique.
@@ -5164,11 +5149,8 @@ static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
FinalType = D.MostDerivedType->getAsCXXRecordDecl();
else
FinalType = getAsBaseClass(D.Entries[NewEntriesSize - 1]);
- if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) {
- Info.CCEDiag(E, diag::note_constexpr_invalid_downcast)
- << D.MostDerivedType << TargetQT;
- return false;
- }
+ if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl())
+ return InvalidCast();
// Truncate the lvalue to the appropriate derived class.
return CastToDerivedClass(Info, E, Result, TargetType, NewEntriesSize);
@@ -5386,6 +5368,44 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
const Stmt *S,
const SwitchCase *SC = nullptr);
+/// Helper to implement named break/continue. Returns 'true' if the evaluation
+/// result should be propagated up. Otherwise, it sets the evaluation result
+/// to either Continue to continue the current loop, or Succeeded to break it.
+static bool ShouldPropagateBreakContinue(EvalInfo &Info,
+ const Stmt *LoopOrSwitch,
+ ArrayRef<BlockScopeRAII *> Scopes,
+ EvalStmtResult &ESR) {
+ bool IsSwitch = isa<SwitchStmt>(LoopOrSwitch);
+
+ // For loops, map Succeeded to Continue so we don't have to check for both.
+ if (!IsSwitch && ESR == ESR_Succeeded) {
+ ESR = ESR_Continue;
+ return false;
+ }
+
+ if (ESR != ESR_Break && ESR != ESR_Continue)
+ return false;
+
+ // Are we breaking out of or continuing this statement?
+ bool CanBreakOrContinue = !IsSwitch || ESR == ESR_Break;
+ const Stmt *StackTop = Info.BreakContinueStack.back();
+ if (CanBreakOrContinue && (StackTop == nullptr || StackTop == LoopOrSwitch)) {
+ Info.BreakContinueStack.pop_back();
+ if (ESR == ESR_Break)
+ ESR = ESR_Succeeded;
+ return false;
+ }
+
+ // We're not. Propagate the result up.
+ for (BlockScopeRAII *S : Scopes) {
+ if (!S->destroy()) {
+ ESR = ESR_Failed;
+ break;
+ }
+ }
+ return true;
+}
+
/// Evaluate the body of a loop, and translate the result as appropriate.
static EvalStmtResult EvaluateLoopBody(StmtResult &Result, EvalInfo &Info,
const Stmt *Body,
@@ -5396,18 +5416,7 @@ static EvalStmtResult EvaluateLoopBody(StmtResult &Result, EvalInfo &Info,
if (ESR != ESR_Failed && ESR != ESR_CaseNotFound && !Scope.destroy())
ESR = ESR_Failed;
- switch (ESR) {
- case ESR_Break:
- return ESR_Succeeded;
- case ESR_Succeeded:
- case ESR_Continue:
- return ESR_Continue;
- case ESR_Failed:
- case ESR_Returned:
- case ESR_CaseNotFound:
- return ESR;
- }
- llvm_unreachable("Invalid EvalStmtResult!");
+ return ESR;
}
/// Evaluate a switch statement.
@@ -5473,10 +5482,12 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found);
if (ESR != ESR_Failed && ESR != ESR_CaseNotFound && !Scope.destroy())
return ESR_Failed;
+ if (ShouldPropagateBreakContinue(Info, SS, /*Scopes=*/{}, ESR))
+ return ESR;
switch (ESR) {
case ESR_Break:
- return ESR_Succeeded;
+ llvm_unreachable("Should have been converted to Succeeded");
case ESR_Succeeded:
case ESR_Continue:
case ESR_Failed:
@@ -5574,6 +5585,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
case Stmt::WhileStmtClass: {
EvalStmtResult ESR =
EvaluateLoopBody(Result, Info, cast<WhileStmt>(S)->getBody(), Case);
+ if (ShouldPropagateBreakContinue(Info, S, /*Scopes=*/{}, ESR))
+ return ESR;
if (ESR != ESR_Continue)
return ESR;
break;
@@ -5595,6 +5608,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
EvalStmtResult ESR =
EvaluateLoopBody(Result, Info, FS->getBody(), Case);
+ if (ShouldPropagateBreakContinue(Info, FS, /*Scopes=*/{}, ESR))
+ return ESR;
if (ESR != ESR_Continue)
return ESR;
if (const auto *Inc = FS->getInc()) {
@@ -5757,6 +5772,9 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
break;
EvalStmtResult ESR = EvaluateLoopBody(Result, Info, WS->getBody());
+ if (ShouldPropagateBreakContinue(Info, WS, &Scope, ESR))
+ return ESR;
+
if (ESR != ESR_Continue) {
if (ESR != ESR_Failed && !Scope.destroy())
return ESR_Failed;
@@ -5773,6 +5791,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
bool Continue;
do {
EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case);
+ if (ShouldPropagateBreakContinue(Info, DS, /*Scopes=*/{}, ESR))
+ return ESR;
if (ESR != ESR_Continue)
return ESR;
Case = nullptr;
@@ -5815,6 +5835,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
}
EvalStmtResult ESR = EvaluateLoopBody(Result, Info, FS->getBody());
+ if (ShouldPropagateBreakContinue(Info, FS, {&IterScope, &ForScope}, ESR))
+ return ESR;
if (ESR != ESR_Continue) {
if (ESR != ESR_Failed && (!IterScope.destroy() || !ForScope.destroy()))
return ESR_Failed;
@@ -5906,6 +5928,8 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
// Loop body.
ESR = EvaluateLoopBody(Result, Info, FS->getBody());
+ if (ShouldPropagateBreakContinue(Info, FS, {&InnerScope, &Scope}, ESR))
+ return ESR;
if (ESR != ESR_Continue) {
if (ESR != ESR_Failed && (!InnerScope.destroy() || !Scope.destroy()))
return ESR_Failed;
@@ -5931,10 +5955,11 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S));
case Stmt::ContinueStmtClass:
- return ESR_Continue;
-
- case Stmt::BreakStmtClass:
- return ESR_Break;
+ case Stmt::BreakStmtClass: {
+ auto *B = cast<LoopControlStmt>(S);
+ Info.BreakContinueStack.push_back(B->getNamedLoopOrSwitch());
+ return isa<ContinueStmt>(S) ? ESR_Continue : ESR_Break;
+ }
case Stmt::LabelStmtClass:
return EvaluateStmt(Result, Info, cast<LabelStmt>(S)->getSubStmt(), Case);
@@ -6126,12 +6151,15 @@ static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This,
} else if (Polymorphic) {
// Conservatively refuse to perform a polymorphic operation if we would
// not be able to read a notional 'vptr' value.
- APValue Val;
- This.moveInto(Val);
- QualType StarThisType =
- Info.Ctx.getLValueReferenceType(This.Designator.getType(Info.Ctx));
- Info.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
- << AK << Val.getAsString(Info.Ctx, StarThisType);
+ if (!Info.checkingPotentialConstantExpression() ||
+ !This.AllowConstexprUnknown) {
+ APValue Val;
+ This.moveInto(Val);
+ QualType StarThisType =
+ Info.Ctx.getLValueReferenceType(This.Designator.getType(Info.Ctx));
+ Info.FFDiag(E, diag::note_constexpr_polymorphic_unknown_dynamic_type)
+ << AK << Val.getAsString(Info.Ctx, StarThisType);
+ }
return false;
}
return true;
@@ -7984,8 +8012,9 @@ static bool checkBitCastConstexprEligibilityType(SourceLocation Loc,
// so its layout is unspecified. For now, we'll simply treat these cases
// as unsupported (this should only be possible with OpenCL bool vectors
// whose element count isn't a multiple of the byte size).
- Info->FFDiag(Loc, diag::note_constexpr_bit_cast_invalid_vector)
- << QualType(VTy, 0) << EltSize << NElts << Ctx.getCharWidth();
+ if (Info)
+ Info->FFDiag(Loc, diag::note_constexpr_bit_cast_invalid_vector)
+ << QualType(VTy, 0) << EltSize << NElts << Ctx.getCharWidth();
return false;
}
@@ -7994,8 +8023,9 @@ static bool checkBitCastConstexprEligibilityType(SourceLocation Loc,
// The layout for x86_fp80 vectors seems to be handled very inconsistently
// by both clang and LLVM, so for now we won't allow bit_casts involving
// it in a constexpr context.
- Info->FFDiag(Loc, diag::note_constexpr_bit_cast_unsupported_type)
- << EltTy;
+ if (Info)
+ Info->FFDiag(Loc, diag::note_constexpr_bit_cast_unsupported_type)
+ << EltTy;
return false;
}
}
@@ -8591,10 +8621,9 @@ public:
const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
if (!FD) return Error(E);
assert(!FD->getType()->isReferenceType() && "prvalue reference?");
- assert(
- BaseTy->castAs<RecordType>()->getOriginalDecl()->getCanonicalDecl() ==
- FD->getParent()->getCanonicalDecl() &&
- "record / field mismatch");
+ assert(BaseTy->castAsCanonical<RecordType>()->getOriginalDecl() ==
+ FD->getParent()->getCanonicalDecl() &&
+ "record / field mismatch");
// Note: there is no lvalue base here. But this case should only ever
// happen in C or in C++98, where we cannot be evaluating a constexpr
@@ -8821,10 +8850,9 @@ public:
const ValueDecl *MD = E->getMemberDecl();
if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
- assert(
- BaseTy->castAs<RecordType>()->getOriginalDecl()->getCanonicalDecl() ==
- FD->getParent()->getCanonicalDecl() &&
- "record / field mismatch");
+ assert(BaseTy->castAsCanonical<RecordType>()->getOriginalDecl() ==
+ FD->getParent()->getCanonicalDecl() &&
+ "record / field mismatch");
(void)BaseTy;
if (!HandleLValueMember(this->Info, E, Result, FD))
return false;
@@ -9466,57 +9494,6 @@ bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {
// Pointer Evaluation
//===----------------------------------------------------------------------===//
-/// Attempts to compute the number of bytes available at the pointer
-/// returned by a function with the alloc_size attribute. Returns true if we
-/// were successful. Places an unsigned number into `Result`.
-///
-/// This expects the given CallExpr to be a call to a function with an
-/// alloc_size attribute.
-static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
- const CallExpr *Call,
- llvm::APInt &Result) {
- const AllocSizeAttr *AllocSize = getAllocSizeAttr(Call);
-
- assert(AllocSize && AllocSize->getElemSizeParam().isValid());
- unsigned SizeArgNo = AllocSize->getElemSizeParam().getASTIndex();
- unsigned BitsInSizeT = Ctx.getTypeSize(Ctx.getSizeType());
- if (Call->getNumArgs() <= SizeArgNo)
- return false;
-
- auto EvaluateAsSizeT = [&](const Expr *E, APSInt &Into) {
- Expr::EvalResult ExprResult;
- if (!E->EvaluateAsInt(ExprResult, Ctx, Expr::SE_AllowSideEffects))
- return false;
- Into = ExprResult.Val.getInt();
- if (Into.isNegative() || !Into.isIntN(BitsInSizeT))
- return false;
- Into = Into.zext(BitsInSizeT);
- return true;
- };
-
- APSInt SizeOfElem;
- if (!EvaluateAsSizeT(Call->getArg(SizeArgNo), SizeOfElem))
- return false;
-
- if (!AllocSize->getNumElemsParam().isValid()) {
- Result = std::move(SizeOfElem);
- return true;
- }
-
- APSInt NumberOfElems;
- unsigned NumArgNo = AllocSize->getNumElemsParam().getASTIndex();
- if (!EvaluateAsSizeT(Call->getArg(NumArgNo), NumberOfElems))
- return false;
-
- bool Overflow;
- llvm::APInt BytesAvailable = SizeOfElem.umul_ov(NumberOfElems, Overflow);
- if (Overflow)
- return false;
-
- Result = std::move(BytesAvailable);
- return true;
-}
-
/// Convenience function. LVal's base must be a call to an alloc_size
/// function.
static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
@@ -9526,7 +9503,13 @@ static bool getBytesReturnedByAllocSizeCall(const ASTContext &Ctx,
"Can't get the size of a non alloc_size function");
const auto *Base = LVal.getLValueBase().get<const Expr *>();
const CallExpr *CE = tryUnwrapAllocSizeCall(Base);
- return getBytesReturnedByAllocSizeCall(Ctx, CE, Result);
+ std::optional<llvm::APInt> Size =
+ CE->evaluateBytesReturnedByAllocSizeCall(Ctx);
+ if (!Size)
+ return false;
+
+ Result = std::move(*Size);
+ return true;
}
/// Attempts to evaluate the given LValueBase as the result of a call to
@@ -10017,7 +10000,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {
if (ExprEvaluatorBaseTy::VisitCallExpr(E))
return true;
- if (!(InvalidBaseOK && getAllocSizeAttr(E)))
+ if (!(InvalidBaseOK && E->getCalleeAllocSizeAttr()))
return false;
Result.setInvalid(E);
@@ -10824,8 +10807,7 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
}
bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) {
- const RecordDecl *RD =
- T->castAs<RecordType>()->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *RD = T->castAsRecordDecl();
if (RD->isInvalidDecl()) return false;
if (RD->isUnion()) {
// C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the
@@ -10894,10 +10876,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
const Expr *ExprToVisit, ArrayRef<Expr *> Args) {
- const RecordDecl *RD = ExprToVisit->getType()
- ->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ const auto *RD = ExprToVisit->getType()->castAsRecordDecl();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
@@ -11121,10 +11100,7 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
Result = APValue(APValue::UninitStruct(), 0, 2);
Array.moveInto(Result.getStructField(0));
- RecordDecl *Record = E->getType()
- ->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ auto *Record = E->getType()->castAsRecordDecl();
RecordDecl::field_iterator Field = Record->field_begin();
assert(Field != Record->field_end() &&
Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
@@ -11310,6 +11286,24 @@ static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
return VectorExprEvaluator(Info, Result).Visit(E);
}
+static llvm::APInt ConvertBoolVectorToInt(const APValue &Val) {
+ assert(Val.isVector() && "expected vector APValue");
+ unsigned NumElts = Val.getVectorLength();
+
+ // Each element is one bit, so create an integer with NumElts bits.
+ llvm::APInt Result(NumElts, 0);
+
+ for (unsigned I = 0; I < NumElts; ++I) {
+ const APValue &Elt = Val.getVectorElt(I);
+ assert(Elt.isInt() && "expected integer element in bool vector");
+
+ if (Elt.getInt().getBoolValue())
+ Result.setBit(I);
+ }
+
+ return Result;
+}
+
bool VectorExprEvaluator::VisitCastExpr(const CastExpr *E) {
const VectorType *VTy = E->getType()->castAs<VectorType>();
unsigned NElts = VTy->getNumElements();
@@ -11603,6 +11597,38 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (!IsConstantEvaluatedBuiltinCall(E))
return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ auto EvaluateBinOpExpr =
+ [&](llvm::function_ref<APInt(const APSInt &, const APSInt &)> Fn) {
+ APValue SourceLHS, SourceRHS;
+ if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) ||
+ !EvaluateAsRValue(Info, E->getArg(1), SourceRHS))
+ return false;
+
+ auto *DestTy = E->getType()->castAs<VectorType>();
+ QualType DestEltTy = DestTy->getElementType();
+ bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType();
+ unsigned SourceLen = SourceLHS.getVectorLength();
+ SmallVector<APValue, 4> ResultElements;
+ ResultElements.reserve(SourceLen);
+
+ if (SourceRHS.isInt()) {
+ const APSInt &RHS = SourceRHS.getInt();
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt();
+ ResultElements.push_back(
+ APValue(APSInt(Fn(LHS, RHS), DestUnsigned)));
+ }
+ } else {
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt();
+ const APSInt &RHS = SourceRHS.getVectorElt(EltNum).getInt();
+ ResultElements.push_back(
+ APValue(APSInt(Fn(LHS, RHS), DestUnsigned)));
+ }
+ }
+ return Success(APValue(ResultElements.data(), SourceLen), E);
+ };
+
switch (E->getBuiltinCallee()) {
default:
return false;
@@ -11659,99 +11685,108 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
case Builtin::BI__builtin_elementwise_add_sat:
+ return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) {
+ return LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS);
+ });
+
case Builtin::BI__builtin_elementwise_sub_sat:
+ return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) {
+ return LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
+ });
+
+ case clang::X86::BI__builtin_ia32_pavgb128:
+ case clang::X86::BI__builtin_ia32_pavgw128:
+ case clang::X86::BI__builtin_ia32_pavgb256:
+ case clang::X86::BI__builtin_ia32_pavgw256:
+ case clang::X86::BI__builtin_ia32_pavgb512:
+ case clang::X86::BI__builtin_ia32_pavgw512:
+ return EvaluateBinOpExpr(llvm::APIntOps::avgCeilU);
+
case clang::X86::BI__builtin_ia32_pmulhuw128:
case clang::X86::BI__builtin_ia32_pmulhuw256:
case clang::X86::BI__builtin_ia32_pmulhuw512:
+ return EvaluateBinOpExpr(llvm::APIntOps::mulhu);
+
case clang::X86::BI__builtin_ia32_pmulhw128:
case clang::X86::BI__builtin_ia32_pmulhw256:
case clang::X86::BI__builtin_ia32_pmulhw512:
+ return EvaluateBinOpExpr(llvm::APIntOps::mulhs);
+
case clang::X86::BI__builtin_ia32_psllv2di:
case clang::X86::BI__builtin_ia32_psllv4di:
case clang::X86::BI__builtin_ia32_psllv4si:
+ case clang::X86::BI__builtin_ia32_psllv8di:
+ case clang::X86::BI__builtin_ia32_psllv8hi:
case clang::X86::BI__builtin_ia32_psllv8si:
+ case clang::X86::BI__builtin_ia32_psllv16hi:
+ case clang::X86::BI__builtin_ia32_psllv16si:
+ case clang::X86::BI__builtin_ia32_psllv32hi:
+ case clang::X86::BI__builtin_ia32_psllwi128:
+ case clang::X86::BI__builtin_ia32_pslldi128:
+ case clang::X86::BI__builtin_ia32_psllqi128:
+ case clang::X86::BI__builtin_ia32_psllwi256:
+ case clang::X86::BI__builtin_ia32_pslldi256:
+ case clang::X86::BI__builtin_ia32_psllqi256:
+ case clang::X86::BI__builtin_ia32_psllwi512:
+ case clang::X86::BI__builtin_ia32_pslldi512:
+ case clang::X86::BI__builtin_ia32_psllqi512:
+ return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(LHS.getBitWidth())) {
+ return APInt::getZero(LHS.getBitWidth());
+ }
+ return LHS.shl(RHS.getZExtValue());
+ });
+
case clang::X86::BI__builtin_ia32_psrav4si:
+ case clang::X86::BI__builtin_ia32_psrav8di:
+ case clang::X86::BI__builtin_ia32_psrav8hi:
case clang::X86::BI__builtin_ia32_psrav8si:
+ case clang::X86::BI__builtin_ia32_psrav16hi:
+ case clang::X86::BI__builtin_ia32_psrav16si:
+ case clang::X86::BI__builtin_ia32_psrav32hi:
+ case clang::X86::BI__builtin_ia32_psravq128:
+ case clang::X86::BI__builtin_ia32_psravq256:
+ case clang::X86::BI__builtin_ia32_psrawi128:
+ case clang::X86::BI__builtin_ia32_psradi128:
+ case clang::X86::BI__builtin_ia32_psraqi128:
+ case clang::X86::BI__builtin_ia32_psrawi256:
+ case clang::X86::BI__builtin_ia32_psradi256:
+ case clang::X86::BI__builtin_ia32_psraqi256:
+ case clang::X86::BI__builtin_ia32_psrawi512:
+ case clang::X86::BI__builtin_ia32_psradi512:
+ case clang::X86::BI__builtin_ia32_psraqi512:
+ return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(LHS.getBitWidth())) {
+ return LHS.ashr(LHS.getBitWidth() - 1);
+ }
+ return LHS.ashr(RHS.getZExtValue());
+ });
+
case clang::X86::BI__builtin_ia32_psrlv2di:
case clang::X86::BI__builtin_ia32_psrlv4di:
case clang::X86::BI__builtin_ia32_psrlv4si:
- case clang::X86::BI__builtin_ia32_psrlv8si:{
- APValue SourceLHS, SourceRHS;
- if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) ||
- !EvaluateAsRValue(Info, E->getArg(1), SourceRHS))
- return false;
-
- QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
- bool DestUnsigned = DestEltTy->isUnsignedIntegerOrEnumerationType();
- unsigned SourceLen = SourceLHS.getVectorLength();
- SmallVector<APValue, 4> ResultElements;
- ResultElements.reserve(SourceLen);
-
- for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
- APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt();
- APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt();
- switch (E->getBuiltinCallee()) {
- case Builtin::BI__builtin_elementwise_add_sat:
- ResultElements.push_back(APValue(
- APSInt(LHS.isSigned() ? LHS.sadd_sat(RHS) : LHS.uadd_sat(RHS),
- DestUnsigned)));
- break;
- case Builtin::BI__builtin_elementwise_sub_sat:
- ResultElements.push_back(APValue(
- APSInt(LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS),
- DestUnsigned)));
- break;
- case clang::X86::BI__builtin_ia32_pmulhuw128:
- case clang::X86::BI__builtin_ia32_pmulhuw256:
- case clang::X86::BI__builtin_ia32_pmulhuw512:
- ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhu(LHS, RHS),
- /*isUnsigned=*/true)));
- break;
- case clang::X86::BI__builtin_ia32_pmulhw128:
- case clang::X86::BI__builtin_ia32_pmulhw256:
- case clang::X86::BI__builtin_ia32_pmulhw512:
- ResultElements.push_back(APValue(APSInt(llvm::APIntOps::mulhs(LHS, RHS),
- /*isUnsigned=*/false)));
- break;
- case clang::X86::BI__builtin_ia32_psllv2di:
- case clang::X86::BI__builtin_ia32_psllv4di:
- case clang::X86::BI__builtin_ia32_psllv4si:
- case clang::X86::BI__builtin_ia32_psllv8si:
- if (RHS.uge(RHS.getBitWidth())) {
- ResultElements.push_back(
- APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned)));
- break;
- }
- ResultElements.push_back(
- APValue(APSInt(LHS.shl(RHS.getZExtValue()), DestUnsigned)));
- break;
- case clang::X86::BI__builtin_ia32_psrav4si:
- case clang::X86::BI__builtin_ia32_psrav8si:
- if (RHS.uge(RHS.getBitWidth())) {
- ResultElements.push_back(
- APValue(APSInt(LHS.ashr(RHS.getBitWidth() - 1), DestUnsigned)));
- break;
- }
- ResultElements.push_back(
- APValue(APSInt(LHS.ashr(RHS.getZExtValue()), DestUnsigned)));
- break;
- case clang::X86::BI__builtin_ia32_psrlv2di:
- case clang::X86::BI__builtin_ia32_psrlv4di:
- case clang::X86::BI__builtin_ia32_psrlv4si:
- case clang::X86::BI__builtin_ia32_psrlv8si:
- if (RHS.uge(RHS.getBitWidth())) {
- ResultElements.push_back(
- APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned)));
- break;
- }
- ResultElements.push_back(
- APValue(APSInt(LHS.lshr(RHS.getZExtValue()), DestUnsigned)));
- break;
+ case clang::X86::BI__builtin_ia32_psrlv8di:
+ case clang::X86::BI__builtin_ia32_psrlv8hi:
+ case clang::X86::BI__builtin_ia32_psrlv8si:
+ case clang::X86::BI__builtin_ia32_psrlv16hi:
+ case clang::X86::BI__builtin_ia32_psrlv16si:
+ case clang::X86::BI__builtin_ia32_psrlv32hi:
+ case clang::X86::BI__builtin_ia32_psrlwi128:
+ case clang::X86::BI__builtin_ia32_psrldi128:
+ case clang::X86::BI__builtin_ia32_psrlqi128:
+ case clang::X86::BI__builtin_ia32_psrlwi256:
+ case clang::X86::BI__builtin_ia32_psrldi256:
+ case clang::X86::BI__builtin_ia32_psrlqi256:
+ case clang::X86::BI__builtin_ia32_psrlwi512:
+ case clang::X86::BI__builtin_ia32_psrldi512:
+ case clang::X86::BI__builtin_ia32_psrlqi512:
+ return EvaluateBinOpExpr([](const APSInt &LHS, const APSInt &RHS) {
+ if (RHS.uge(LHS.getBitWidth())) {
+ return APInt::getZero(LHS.getBitWidth());
}
- }
+ return LHS.lshr(RHS.getZExtValue());
+ });
- return Success(APValue(ResultElements.data(), ResultElements.size()), E);
- }
case clang::X86::BI__builtin_ia32_pmuldq128:
case clang::X86::BI__builtin_ia32_pmuldq256:
case clang::X86::BI__builtin_ia32_pmuldq512:
@@ -11789,6 +11824,29 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
+
+ case clang::X86::BI__builtin_ia32_vprotbi:
+ case clang::X86::BI__builtin_ia32_vprotdi:
+ case clang::X86::BI__builtin_ia32_vprotqi:
+ case clang::X86::BI__builtin_ia32_vprotwi:
+ case clang::X86::BI__builtin_ia32_prold128:
+ case clang::X86::BI__builtin_ia32_prold256:
+ case clang::X86::BI__builtin_ia32_prold512:
+ case clang::X86::BI__builtin_ia32_prolq128:
+ case clang::X86::BI__builtin_ia32_prolq256:
+ case clang::X86::BI__builtin_ia32_prolq512:
+ return EvaluateBinOpExpr(
+ [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotl(RHS); });
+
+ case clang::X86::BI__builtin_ia32_prord128:
+ case clang::X86::BI__builtin_ia32_prord256:
+ case clang::X86::BI__builtin_ia32_prord512:
+ case clang::X86::BI__builtin_ia32_prorq128:
+ case clang::X86::BI__builtin_ia32_prorq256:
+ case clang::X86::BI__builtin_ia32_prorq512:
+ return EvaluateBinOpExpr(
+ [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotr(RHS); });
+
case Builtin::BI__builtin_elementwise_max:
case Builtin::BI__builtin_elementwise_min: {
APValue SourceLHS, SourceRHS;
@@ -11824,6 +11882,96 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
+ case X86::BI__builtin_ia32_vpshldd128:
+ case X86::BI__builtin_ia32_vpshldd256:
+ case X86::BI__builtin_ia32_vpshldd512:
+ case X86::BI__builtin_ia32_vpshldq128:
+ case X86::BI__builtin_ia32_vpshldq256:
+ case X86::BI__builtin_ia32_vpshldq512:
+ case X86::BI__builtin_ia32_vpshldw128:
+ case X86::BI__builtin_ia32_vpshldw256:
+ case X86::BI__builtin_ia32_vpshldw512: {
+ APValue SourceHi, SourceLo, SourceAmt;
+ if (!EvaluateAsRValue(Info, E->getArg(0), SourceHi) ||
+ !EvaluateAsRValue(Info, E->getArg(1), SourceLo) ||
+ !EvaluateAsRValue(Info, E->getArg(2), SourceAmt))
+ return false;
+
+ QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
+ unsigned SourceLen = SourceHi.getVectorLength();
+ SmallVector<APValue, 32> ResultElements;
+ ResultElements.reserve(SourceLen);
+
+ APInt Amt = SourceAmt.getInt();
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ APInt Hi = SourceHi.getVectorElt(EltNum).getInt();
+ APInt Lo = SourceLo.getVectorElt(EltNum).getInt();
+ APInt R = llvm::APIntOps::fshl(Hi, Lo, Amt);
+ ResultElements.push_back(
+ APValue(APSInt(R, DestEltTy->isUnsignedIntegerOrEnumerationType())));
+ }
+
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ }
+ case X86::BI__builtin_ia32_vpshrdd128:
+ case X86::BI__builtin_ia32_vpshrdd256:
+ case X86::BI__builtin_ia32_vpshrdd512:
+ case X86::BI__builtin_ia32_vpshrdq128:
+ case X86::BI__builtin_ia32_vpshrdq256:
+ case X86::BI__builtin_ia32_vpshrdq512:
+ case X86::BI__builtin_ia32_vpshrdw128:
+ case X86::BI__builtin_ia32_vpshrdw256:
+ case X86::BI__builtin_ia32_vpshrdw512: {
+ // NOTE: Reversed Hi/Lo operands.
+ APValue SourceHi, SourceLo, SourceAmt;
+ if (!EvaluateAsRValue(Info, E->getArg(0), SourceLo) ||
+ !EvaluateAsRValue(Info, E->getArg(1), SourceHi) ||
+ !EvaluateAsRValue(Info, E->getArg(2), SourceAmt))
+ return false;
+
+ QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
+ unsigned SourceLen = SourceHi.getVectorLength();
+ SmallVector<APValue, 32> ResultElements;
+ ResultElements.reserve(SourceLen);
+
+ APInt Amt = SourceAmt.getInt();
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ APInt Hi = SourceHi.getVectorElt(EltNum).getInt();
+ APInt Lo = SourceLo.getVectorElt(EltNum).getInt();
+ APInt R = llvm::APIntOps::fshr(Hi, Lo, Amt);
+ ResultElements.push_back(
+ APValue(APSInt(R, DestEltTy->isUnsignedIntegerOrEnumerationType())));
+ }
+
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ }
+ case X86::BI__builtin_ia32_blendvpd:
+ case X86::BI__builtin_ia32_blendvpd256:
+ case X86::BI__builtin_ia32_blendvps:
+ case X86::BI__builtin_ia32_blendvps256:
+ case X86::BI__builtin_ia32_pblendvb128:
+ case X86::BI__builtin_ia32_pblendvb256: {
+ // SSE blendv by mask signbit: "Result = C[] < 0 ? T[] : F[]".
+ APValue SourceF, SourceT, SourceC;
+ if (!EvaluateAsRValue(Info, E->getArg(0), SourceF) ||
+ !EvaluateAsRValue(Info, E->getArg(1), SourceT) ||
+ !EvaluateAsRValue(Info, E->getArg(2), SourceC))
+ return false;
+
+ unsigned SourceLen = SourceF.getVectorLength();
+ SmallVector<APValue, 32> ResultElements;
+ ResultElements.reserve(SourceLen);
+
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ const APValue &F = SourceF.getVectorElt(EltNum);
+ const APValue &T = SourceT.getVectorElt(EltNum);
+ const APValue &C = SourceC.getVectorElt(EltNum);
+ APInt M = C.isInt() ? (APInt)C.getInt() : C.getFloat().bitcastToAPInt();
+ ResultElements.push_back(M.isNegative() ? T : F);
+ }
+
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ }
case X86::BI__builtin_ia32_selectb_128:
case X86::BI__builtin_ia32_selectb_256:
case X86::BI__builtin_ia32_selectb_512:
@@ -11937,6 +12085,40 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
+
+ case Builtin::BI__builtin_elementwise_fshl:
+ case Builtin::BI__builtin_elementwise_fshr: {
+ APValue SourceHi, SourceLo, SourceShift;
+ if (!EvaluateAsRValue(Info, E->getArg(0), SourceHi) ||
+ !EvaluateAsRValue(Info, E->getArg(1), SourceLo) ||
+ !EvaluateAsRValue(Info, E->getArg(2), SourceShift))
+ return false;
+
+ QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
+ if (!DestEltTy->isIntegerType())
+ return false;
+
+ unsigned SourceLen = SourceHi.getVectorLength();
+ SmallVector<APValue> ResultElements;
+ ResultElements.reserve(SourceLen);
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ const APSInt &Hi = SourceHi.getVectorElt(EltNum).getInt();
+ const APSInt &Lo = SourceLo.getVectorElt(EltNum).getInt();
+ const APSInt &Shift = SourceShift.getVectorElt(EltNum).getInt();
+ switch (E->getBuiltinCallee()) {
+ case Builtin::BI__builtin_elementwise_fshl:
+ ResultElements.push_back(APValue(
+ APSInt(llvm::APIntOps::fshl(Hi, Lo, Shift), Hi.isUnsigned())));
+ break;
+ case Builtin::BI__builtin_elementwise_fshr:
+ ResultElements.push_back(APValue(
+ APSInt(llvm::APIntOps::fshr(Hi, Lo, Shift), Hi.isUnsigned())));
+ break;
+ }
+ }
+
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ }
}
}
@@ -13168,10 +13350,7 @@ static bool convertUnsignedAPIntToCharUnits(const llvm::APInt &Int,
static void addFlexibleArrayMemberInitSize(EvalInfo &Info, const QualType &T,
const LValue &LV, CharUnits &Size) {
if (!T.isNull() && T->isStructureType() &&
- T->getAsStructureType()
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->hasFlexibleArrayMember())
+ T->castAsRecordDecl()->hasFlexibleArrayMember())
if (const auto *V = LV.getLValueBase().dyn_cast<const ValueDecl *>())
if (const auto *VD = dyn_cast<VarDecl>(V))
if (VD->hasInit())
@@ -13497,8 +13676,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__lzcnt:
case Builtin::BI__lzcnt64: {
APSInt Val;
- if (!EvaluateInteger(E->getArg(0), Val, Info))
+ if (E->getArg(0)->getType()->isExtVectorBoolType()) {
+ APValue Vec;
+ if (!EvaluateVector(E->getArg(0), Vec, Info))
+ return false;
+ Val = ConvertBoolVectorToInt(Vec);
+ } else if (!EvaluateInteger(E->getArg(0), Val, Info)) {
return false;
+ }
std::optional<APSInt> Fallback;
if ((BuiltinOp == Builtin::BI__builtin_clzg ||
@@ -13583,8 +13768,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_ctzg:
case Builtin::BI__builtin_elementwise_cttz: {
APSInt Val;
- if (!EvaluateInteger(E->getArg(0), Val, Info))
+ if (E->getArg(0)->getType()->isExtVectorBoolType()) {
+ APValue Vec;
+ if (!EvaluateVector(E->getArg(0), Vec, Info))
+ return false;
+ Val = ConvertBoolVectorToInt(Vec);
+ } else if (!EvaluateInteger(E->getArg(0), Val, Info)) {
return false;
+ }
std::optional<APSInt> Fallback;
if ((BuiltinOp == Builtin::BI__builtin_ctzg ||
@@ -13799,8 +13990,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__popcnt:
case Builtin::BI__popcnt64: {
APSInt Val;
- if (!EvaluateInteger(E->getArg(0), Val, Info))
+ if (E->getArg(0)->getType()->isExtVectorBoolType()) {
+ APValue Vec;
+ if (!EvaluateVector(E->getArg(0), Vec, Info))
+ return false;
+ Val = ConvertBoolVectorToInt(Vec);
+ } else if (!EvaluateInteger(E->getArg(0), Val, Info)) {
return false;
+ }
return Success(Val.popcount(), E);
}
@@ -13875,6 +14072,25 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
APInt Result = std::min(LHS, RHS);
return Success(APSInt(Result, !LHS.isSigned()), E);
}
+ case Builtin::BI__builtin_elementwise_fshl:
+ case Builtin::BI__builtin_elementwise_fshr: {
+ APSInt Hi, Lo, Shift;
+ if (!EvaluateInteger(E->getArg(0), Hi, Info) ||
+ !EvaluateInteger(E->getArg(1), Lo, Info) ||
+ !EvaluateInteger(E->getArg(2), Shift, Info))
+ return false;
+
+ switch (BuiltinOp) {
+ case Builtin::BI__builtin_elementwise_fshl: {
+ APSInt Result(llvm::APIntOps::fshl(Hi, Lo, Shift), Hi.isUnsigned());
+ return Success(Result, E);
+ }
+ case Builtin::BI__builtin_elementwise_fshr: {
+ APSInt Result(llvm::APIntOps::fshr(Hi, Lo, Shift), Hi.isUnsigned());
+ return Success(Result, E);
+ }
+ }
+ }
case Builtin::BIstrlen:
case Builtin::BIwcslen:
// A call to strlen is not a constant expression.
@@ -14910,6 +15126,11 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
// Reject differing bases from the normal codepath; we special-case
// comparisons to null.
if (!HasSameBase(LHSValue, RHSValue)) {
+ // Bail out early if we're checking potential constant expression.
+ // Otherwise, prefer to diagnose other issues.
+ if (Info.checkingPotentialConstantExpression() &&
+ (LHSValue.AllowConstexprUnknown || RHSValue.AllowConstexprUnknown))
+ return false;
auto DiagComparison = [&] (unsigned DiagID, bool Reversed = false) {
std::string LHS = LHSValue.toString(Info.Ctx, E->getLHS()->getType());
std::string RHS = RHSValue.toString(Info.Ctx, E->getRHS()->getType());
@@ -15230,6 +15451,10 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
// Reject differing bases from the normal codepath; we special-case
// comparisons to null.
if (!HasSameBase(LHSValue, RHSValue)) {
+ if (Info.checkingPotentialConstantExpression() &&
+ (LHSValue.AllowConstexprUnknown || RHSValue.AllowConstexprUnknown))
+ return false;
+
const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr *>();
const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr *>();
@@ -15408,6 +15633,13 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
const auto *VAT = Info.Ctx.getAsVariableArrayType(Ty);
assert(VAT);
if (VAT->getElementType()->isArrayType()) {
+ // Variable array size expression could be missing (e.g. int a[*][10]) In
+ // that case, it can't be a constant expression.
+ if (!VAT->getSizeExpr()) {
+ Info.FFDiag(E->getBeginLoc());
+ return false;
+ }
+
std::optional<APSInt> Res =
VAT->getSizeExpr()->getIntegerConstantExpr(Info.Ctx);
if (Res) {
@@ -15455,10 +15687,9 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
case OffsetOfNode::Field: {
FieldDecl *MemberDecl = ON.getField();
- const RecordType *RT = CurrentType->getAs<RecordType>();
- if (!RT)
+ const auto *RD = CurrentType->getAsRecordDecl();
+ if (!RD)
return Error(OOE);
- RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
unsigned i = MemberDecl->getFieldIndex();
@@ -15477,22 +15708,20 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
return Error(OOE);
// Find the layout of the class whose base we are looking into.
- const RecordType *RT = CurrentType->getAs<RecordType>();
- if (!RT)
+ const auto *RD = CurrentType->getAsCXXRecordDecl();
+ if (!RD)
return Error(OOE);
- RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
// Find the base class itself.
CurrentType = BaseSpec->getType();
- const RecordType *BaseRT = CurrentType->getAs<RecordType>();
- if (!BaseRT)
+ const auto *BaseRD = CurrentType->getAsCXXRecordDecl();
+ if (!BaseRD)
return Error(OOE);
// Add the offset to the base.
- Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(
- BaseRT->getOriginalDecl()->getDefinitionOrSelf()));
+ Result += RL.getBaseClassOffset(BaseRD);
break;
}
}
@@ -15670,8 +15899,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
if (Info.Ctx.getLangOpts().CPlusPlus && DestType->isEnumeralType()) {
- const EnumType *ET = dyn_cast<EnumType>(DestType.getCanonicalType());
- const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *ED = DestType->getAsEnumDecl();
// Check that the value is within the range of the enumeration values.
//
// This corressponds to [expr.static.cast]p10 which says:
@@ -17945,7 +18173,10 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
// it is an ICE or not.
const auto *VAT = Ctx.getAsVariableArrayType(ArgTy);
if (VAT->getElementType()->isArrayType())
- return CheckICE(VAT->getSizeExpr(), Ctx);
+ // Variable array size expression could be missing (e.g. int a[*][10])
+ // In that case, it can't be a constant expression.
+ return VAT->getSizeExpr() ? CheckICE(VAT->getSizeExpr(), Ctx)
+ : ICEDiag(IK_NotICE, E->getBeginLoc());
// Otherwise, this is a regular VLA, which is definitely not an ICE.
return ICEDiag(IK_NotICE, E->getBeginLoc());
diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp
index 502a3e6b145e..d4cb89b43ae8 100644
--- a/clang/lib/AST/FormatString.cpp
+++ b/clang/lib/AST/FormatString.cpp
@@ -413,14 +413,13 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
return Match;
case AnyCharTy: {
- if (const auto *ETy = argTy->getAs<EnumType>()) {
+ if (const auto *ED = argTy->getAsEnumDecl()) {
// If the enum is incomplete we know nothing about the underlying type.
// Assume that it's 'int'. Do not use the underlying type for a scoped
// enumeration.
- const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf();
if (!ED->isComplete())
return NoMatch;
- if (ETy->isUnscopedEnumerationType())
+ if (!ED->isScoped())
argTy = ED->getIntegerType();
}
@@ -463,14 +462,13 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
return matchesSizeTPtrdiffT(C, argTy, T);
}
- if (const EnumType *ETy = argTy->getAs<EnumType>()) {
+ if (const auto *ED = argTy->getAsEnumDecl()) {
// If the enum is incomplete we know nothing about the underlying type.
// Assume that it's 'int'. Do not use the underlying type for a scoped
// enumeration as that needs an exact match.
- const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf();
if (!ED->isComplete())
argTy = C.IntTy;
- else if (ETy->isUnscopedEnumerationType())
+ else if (!ED->isScoped())
argTy = ED->getIntegerType();
}
@@ -655,7 +653,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
// to Objective-C objects. Since the compiler doesn't know which
// structs can be toll-free bridged, we just accept them all.
QualType pointee = PT->getPointeeType();
- if (pointee->getAsStructureType() || pointee->isVoidType())
+ if (pointee->isStructureType() || pointee->isVoidType())
return Match;
}
return NoMatch;
diff --git a/clang/lib/AST/InheritViz.cpp b/clang/lib/AST/InheritViz.cpp
index c03492c64b16..3c4a5a8e2c4a 100644
--- a/clang/lib/AST/InheritViz.cpp
+++ b/clang/lib/AST/InheritViz.cpp
@@ -89,8 +89,8 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) {
Out << " \"];\n";
// Display the base classes.
- const auto *Decl = static_cast<const CXXRecordDecl *>(
- Type->castAs<RecordType>()->getOriginalDecl());
+ const auto *Decl = cast<CXXRecordDecl>(
+ Type->castAsCanonical<RecordType>()->getOriginalDecl());
for (const auto &Base : Decl->bases()) {
QualType CanonBaseType = Context.getCanonicalType(Base.getType());
diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp
index 43a8bcd9443f..adef1584fd9b 100644
--- a/clang/lib/AST/ItaniumCXXABI.cpp
+++ b/clang/lib/AST/ItaniumCXXABI.cpp
@@ -42,8 +42,7 @@ namespace {
///
/// Returns the name of anonymous union VarDecl or nullptr if it is not found.
static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) {
- const auto *RT = VD.getType()->castAs<RecordType>();
- const RecordDecl *RD = RT->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *RD = VD.getType()->castAsRecordDecl();
assert(RD->isUnion() && "RecordType is expected to be a union.");
if (const FieldDecl *FD = RD->findFirstNamedDataMember()) {
return FD->getIdentifier();
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 112678fb2714..163cd43abd45 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -1580,10 +1580,7 @@ void CXXNameMangler::mangleUnqualifiedName(
if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
// We must have an anonymous union or struct declaration.
- const RecordDecl *RD = VD->getType()
- ->castAs<RecordType>()
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ const auto *RD = VD->getType()->castAsRecordDecl();
// Itanium C++ ABI 5.1.2:
//
@@ -4729,7 +4726,7 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T,
void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) {
// Ignore member expressions involving anonymous unions.
- while (const auto *RT = Base->getType()->getAs<RecordType>()) {
+ while (const auto *RT = Base->getType()->getAsCanonical<RecordType>()) {
if (!RT->getOriginalDecl()->isAnonymousStructOrUnion())
break;
const auto *ME = dyn_cast<MemberExpr>(Base);
@@ -6029,6 +6026,8 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
// ::= CI2 <type> # base inheriting constructor
//
// In addition, C5 is a comdat name with C1 and C2 in it.
+ // C4 represents a ctor declaration and is used by debuggers to look up
+ // the various ctor variants.
Out << 'C';
if (InheritedFrom)
Out << 'I';
@@ -6039,6 +6038,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
case Ctor_Base:
Out << '2';
break;
+ case Ctor_Unified:
+ Out << '4';
+ break;
case Ctor_Comdat:
Out << '5';
break;
@@ -6056,6 +6058,8 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
// ::= D2 # base object destructor
//
// In addition, D5 is a comdat name with D1, D2 and, if virtual, D0 in it.
+ // D4 represents a dtor declaration and is used by debuggers to look up
+ // the various dtor variants.
switch (T) {
case Dtor_Deleting:
Out << "D0";
@@ -6066,6 +6070,9 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
case Dtor_Base:
Out << "D2";
break;
+ case Dtor_Unified:
+ Out << "D4";
+ break;
case Dtor_Comdat:
Out << "D5";
break;
@@ -6997,8 +7004,8 @@ static bool hasMangledSubstitutionQualifiers(QualType T) {
bool CXXNameMangler::mangleSubstitution(QualType T) {
if (!hasMangledSubstitutionQualifiers(T)) {
- if (const RecordType *RT = T->getAs<RecordType>())
- return mangleSubstitution(RT->getOriginalDecl()->getDefinitionOrSelf());
+ if (const auto *RD = T->getAsCXXRecordDecl())
+ return mangleSubstitution(RD);
}
uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
@@ -7034,7 +7041,7 @@ bool CXXNameMangler::isSpecializedAs(QualType S, llvm::StringRef Name,
if (S.isNull())
return false;
- const RecordType *RT = S->getAs<RecordType>();
+ const RecordType *RT = S->getAsCanonical<RecordType>();
if (!RT)
return false;
@@ -7168,8 +7175,8 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
void CXXNameMangler::addSubstitution(QualType T) {
if (!hasMangledSubstitutionQualifiers(T)) {
- if (const RecordType *RT = T->getAs<RecordType>()) {
- addSubstitution(RT->getOriginalDecl()->getDefinitionOrSelf());
+ if (const auto *RD = T->getAsCXXRecordDecl()) {
+ addSubstitution(RD);
return;
}
}
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index b3f12a1cce2e..2f4aebd0845d 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -396,7 +396,7 @@ llvm::json::Array JSONNodeDumper::createCastPath(const CastExpr *C) {
for (auto I = C->path_begin(), E = C->path_end(); I != E; ++I) {
const CXXBaseSpecifier *Base = *I;
const auto *RD = cast<CXXRecordDecl>(
- Base->getType()->castAs<RecordType>()->getOriginalDecl());
+ Base->getType()->castAsCanonical<RecordType>()->getOriginalDecl());
llvm::json::Object Val{{"name", RD->getName()}};
if (Base->isVirtual())
@@ -1671,6 +1671,13 @@ void JSONNodeDumper::VisitLabelStmt(const LabelStmt *LS) {
JOS.attribute("declId", createPointerRepresentation(LS->getDecl()));
attributeOnlyIfTrue("sideEntry", LS->isSideEntry());
}
+
+void JSONNodeDumper::VisitLoopControlStmt(const LoopControlStmt *LS) {
+ if (LS->hasLabelTarget())
+ JOS.attribute("targetLabelDeclId",
+ createPointerRepresentation(LS->getLabelDecl()));
+}
+
void JSONNodeDumper::VisitGotoStmt(const GotoStmt *GS) {
JOS.attribute("targetLabelDeclId",
createPointerRepresentation(GS->getLabel()));
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 0bfb51c11f0a..780b2c585c81 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -152,6 +152,37 @@ bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
return shouldMangleCXXName(D);
}
+static llvm::StringRef g_lldb_func_call_label_prefix = "$__lldb_func:";
+
+/// Given an LLDB function call label, this function prints the label
+/// into \c Out, together with the structor type of \c GD (if the
+/// decl is a constructor/destructor). LLDB knows how to handle mangled
+/// names with this encoding.
+///
+/// Example input label:
+/// $__lldb_func::123:456:~Foo
+///
+/// Example output:
+/// $__lldb_func:D1:123:456:~Foo
+///
+static void emitLLDBAsmLabel(llvm::StringRef label, GlobalDecl GD,
+ llvm::raw_ostream &Out) {
+ assert(label.starts_with(g_lldb_func_call_label_prefix));
+
+ Out << g_lldb_func_call_label_prefix;
+
+ if (auto *Ctor = llvm::dyn_cast<clang::CXXConstructorDecl>(GD.getDecl())) {
+ Out << "C";
+ if (Ctor->getInheritedConstructor().getConstructor())
+ Out << "I";
+ Out << GD.getCtorType();
+ } else if (llvm::isa<clang::CXXDestructorDecl>(GD.getDecl())) {
+ Out << "D" << GD.getDtorType();
+ }
+
+ Out << label.substr(g_lldb_func_call_label_prefix.size());
+}
+
void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
const ASTContext &ASTContext = getASTContext();
const NamedDecl *D = cast<NamedDecl>(GD.getDecl());
@@ -185,7 +216,11 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
if (!UserLabelPrefix.empty())
Out << '\01'; // LLVM IR Marker for __asm("foo")
- Out << ALA->getLabel();
+ if (ALA->getLabel().starts_with(g_lldb_func_call_label_prefix))
+ emitLLDBAsmLabel(ALA->getLabel(), GD, Out);
+ else
+ Out << ALA->getLabel();
+
return;
}
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index fc79ab1de24f..d96472e393f6 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -1496,6 +1496,8 @@ void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
// it.
case Dtor_Comdat:
llvm_unreachable("not expecting a COMDAT");
+ case Dtor_Unified:
+ llvm_unreachable("not expecting a unified dtor type");
}
llvm_unreachable("Unsupported dtor type?");
}
@@ -3246,13 +3248,17 @@ void MicrosoftCXXNameMangler::mangleTagTypeKind(TagTypeKind TTK) {
}
void MicrosoftCXXNameMangler::mangleType(const EnumType *T, Qualifiers,
SourceRange) {
- mangleType(cast<TagType>(T)->getOriginalDecl()->getDefinitionOrSelf());
+ mangleType(cast<TagType>(T)->getOriginalDecl());
}
void MicrosoftCXXNameMangler::mangleType(const RecordType *T, Qualifiers,
SourceRange) {
- mangleType(cast<TagType>(T)->getOriginalDecl()->getDefinitionOrSelf());
+ mangleType(cast<TagType>(T)->getOriginalDecl());
}
void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) {
+ // MSVC chooses the tag kind of the definition if it exists, otherwise it
+ // always picks the first declaration.
+ const auto *Def = TD->getDefinition();
+ TD = Def ? Def : TD->getFirstDecl();
mangleTagTypeKind(TD->getTagKind());
mangleName(TD);
}
diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp
index 9a9ede467331..6c4bc7c274ea 100644
--- a/clang/lib/AST/OpenACCClause.cpp
+++ b/clang/lib/AST/OpenACCClause.cpp
@@ -317,11 +317,11 @@ OpenACCTileClause *OpenACCTileClause::Create(const ASTContext &C,
OpenACCPrivateClause *
OpenACCPrivateClause::Create(const ASTContext &C, SourceLocation BeginLoc,
SourceLocation LParenLoc, ArrayRef<Expr *> VarList,
- ArrayRef<VarDecl *> InitRecipes,
+ ArrayRef<OpenACCPrivateRecipe> InitRecipes,
SourceLocation EndLoc) {
assert(VarList.size() == InitRecipes.size());
- void *Mem =
- C.Allocate(OpenACCPrivateClause::totalSizeToAlloc<Expr *, VarDecl *>(
+ void *Mem = C.Allocate(
+ OpenACCPrivateClause::totalSizeToAlloc<Expr *, OpenACCPrivateRecipe>(
VarList.size(), InitRecipes.size()));
return new (Mem)
OpenACCPrivateClause(BeginLoc, LParenLoc, VarList, InitRecipes, EndLoc);
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index 588b0dcc6d7b..0930ca27c29f 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -104,6 +104,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
return static_cast<const OMPFilterClause *>(C);
case OMPC_ompx_dyn_cgroup_mem:
return static_cast<const OMPXDynCGroupMemClause *>(C);
+ case OMPC_message:
+ return static_cast<const OMPMessageClause *>(C);
case OMPC_default:
case OMPC_proc_bind:
case OMPC_safelen:
@@ -158,7 +160,6 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_self_maps:
case OMPC_at:
case OMPC_severity:
- case OMPC_message:
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
@@ -1963,8 +1964,10 @@ void OMPClausePrinter::VisitOMPSeverityClause(OMPSeverityClause *Node) {
}
void OMPClausePrinter::VisitOMPMessageClause(OMPMessageClause *Node) {
- OS << "message(\""
- << cast<StringLiteral>(Node->getMessageString())->getString() << "\")";
+ OS << "message(";
+ if (Expr *E = Node->getMessageString())
+ E->printPretty(OS, nullptr, Policy);
+ OS << ")";
}
void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) {
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index 687160c6116b..855550475721 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -793,8 +793,8 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
}
// If it's an enum, get its underlying type.
- if (const EnumType *ETy = QT->getAs<EnumType>())
- QT = ETy->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
+ if (const auto *ED = QT->getAsEnumDecl())
+ QT = ED->getIntegerType();
const BuiltinType *BT = QT->getAs<BuiltinType>();
if (!BT) {
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index f1f21f426f94..43f4e070748b 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -187,6 +187,7 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
// Check the bases.
for (const CXXBaseSpecifier &Base : Class->bases()) {
const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl();
+ assert(BaseDecl != Class && "Class cannot inherit from itself.");
CharUnits EmptySize;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
@@ -204,15 +205,13 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
// Check the fields.
for (const FieldDecl *FD : Class->fields()) {
- const RecordType *RT =
- Context.getBaseElementType(FD->getType())->getAs<RecordType>();
-
- // We only care about record types.
- if (!RT)
+ // We only care about records.
+ const auto *MemberDecl =
+ Context.getBaseElementType(FD->getType())->getAsCXXRecordDecl();
+ if (!MemberDecl)
continue;
CharUnits EmptySize;
- const CXXRecordDecl *MemberDecl = RT->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl);
if (MemberDecl->isEmpty()) {
// If the class decl is empty, get its size.
@@ -433,11 +432,10 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
// If we have an array type we need to look at every element.
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
QualType ElemTy = Context.getBaseElementType(AT);
- const RecordType *RT = ElemTy->getAs<RecordType>();
- if (!RT)
+ const auto *RD = ElemTy->getAsCXXRecordDecl();
+ if (!RD)
return true;
- const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
@@ -533,11 +531,10 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(
// If we have an array type we need to update every element.
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) {
QualType ElemTy = Context.getBaseElementType(AT);
- const RecordType *RT = ElemTy->getAs<RecordType>();
- if (!RT)
+ const auto *RD = ElemTy->getAsCXXRecordDecl();
+ if (!RD)
return;
- const CXXRecordDecl *RD = RT->getAsCXXRecordDecl();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
@@ -2011,7 +2008,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
CTy->getElementType()->castAs<BuiltinType>());
} else if (const BuiltinType *BTy = BaseTy->getAs<BuiltinType>()) {
performBuiltinTypeAlignmentUpgrade(BTy);
- } else if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
+ } else if (const RecordType *RT = BaseTy->getAsCanonical<RecordType>()) {
const RecordDecl *RD = RT->getOriginalDecl();
const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD);
PreferredAlign = FieldRecord.getPreferredAlignment();
@@ -2711,8 +2708,9 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(
// alignment when it is applied to bitfields.
Info.Alignment = std::max(Info.Alignment, FieldRequiredAlignment);
else {
- if (auto RT =
- FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
+ if (const auto *RT = FD->getType()
+ ->getBaseElementTypeUnsafe()
+ ->getAsCanonical<RecordType>()) {
auto const &Layout = Context.getASTRecordLayout(RT->getOriginalDecl());
EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject();
FieldRequiredAlignment = std::max(FieldRequiredAlignment,
@@ -3695,9 +3693,9 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD,
Offset + C.toCharUnitsFromBits(LocalFieldOffsetInBits);
// Recursively dump fields of record type.
- if (auto RT = Field->getType()->getAs<RecordType>()) {
- DumpRecordLayout(OS, RT->getOriginalDecl()->getDefinitionOrSelf(), C,
- FieldOffset, IndentLevel, Field->getName().data(),
+ if (const auto *RD = Field->getType()->getAsRecordDecl()) {
+ DumpRecordLayout(OS, RD, C, FieldOffset, IndentLevel,
+ Field->getName().data(),
/*PrintSizeInfo=*/false,
/*IncludeVirtualBases=*/true);
continue;
diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp
index 31c001d025fe..41cf71a3e042 100644
--- a/clang/lib/AST/ScanfFormatString.cpp
+++ b/clang/lib/AST/ScanfFormatString.cpp
@@ -430,9 +430,8 @@ bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
QualType PT = QT->getPointeeType();
// If it's an enum, get its underlying type.
- if (const EnumType *ETy = PT->getAs<EnumType>()) {
+ if (const auto *ED = PT->getAsEnumDecl()) {
// Don't try to fix incomplete enums.
- const EnumDecl *ED = ETy->getOriginalDecl()->getDefinitionOrSelf();
if (!ED->isComplete())
return false;
PT = ED->getIntegerType();
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 4fc4a99ad240..9ae8aea3ab37 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -1482,3 +1482,16 @@ bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
return false;
}
+
+const Stmt *LabelStmt::getInnermostLabeledStmt() const {
+ const Stmt *S = getSubStmt();
+ while (isa_and_present<LabelStmt>(S))
+ S = cast<LabelStmt>(S)->getSubStmt();
+ return S;
+}
+
+const Stmt *LoopControlStmt::getNamedLoopOrSwitch() const {
+ if (!hasLabelTarget())
+ return nullptr;
+ return getLabelDecl()->getStmt()->getInnermostLabeledStmt();
+}
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index 2eeb5e45ab51..36ecaf6489ef 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -125,12 +125,13 @@ OMPLoopBasedDirective::tryToFindNextInnerLoop(Stmt *CurStmt,
bool OMPLoopBasedDirective::doForAllLoops(
Stmt *CurStmt, bool TryImperfectlyNestedLoops, unsigned NumLoops,
llvm::function_ref<bool(unsigned, Stmt *)> Callback,
- llvm::function_ref<void(OMPLoopTransformationDirective *)>
+ llvm::function_ref<void(OMPCanonicalLoopNestTransformationDirective *)>
OnTransformationCallback) {
CurStmt = CurStmt->IgnoreContainers();
for (unsigned Cnt = 0; Cnt < NumLoops; ++Cnt) {
while (true) {
- auto *Dir = dyn_cast<OMPLoopTransformationDirective>(CurStmt);
+ auto *Dir =
+ dyn_cast<OMPCanonicalLoopNestTransformationDirective>(CurStmt);
if (!Dir)
break;
@@ -369,11 +370,11 @@ OMPForDirective *OMPForDirective::Create(
return Dir;
}
-Stmt *OMPLoopTransformationDirective::getTransformedStmt() const {
+Stmt *OMPCanonicalLoopNestTransformationDirective::getTransformedStmt() const {
switch (getStmtClass()) {
#define STMT(CLASS, PARENT)
#define ABSTRACT_STMT(CLASS)
-#define OMPLOOPTRANSFORMATIONDIRECTIVE(CLASS, PARENT) \
+#define OMPCANONICALLOOPNESTTRANSFORMATIONDIRECTIVE(CLASS, PARENT) \
case Stmt::CLASS##Class: \
return static_cast<const CLASS *>(this)->getTransformedStmt();
#include "clang/AST/StmtNodes.inc"
@@ -382,11 +383,11 @@ Stmt *OMPLoopTransformationDirective::getTransformedStmt() const {
}
}
-Stmt *OMPLoopTransformationDirective::getPreInits() const {
+Stmt *OMPCanonicalLoopNestTransformationDirective::getPreInits() const {
switch (getStmtClass()) {
#define STMT(CLASS, PARENT)
#define ABSTRACT_STMT(CLASS)
-#define OMPLOOPTRANSFORMATIONDIRECTIVE(CLASS, PARENT) \
+#define OMPCANONICALLOOPNESTTRANSFORMATIONDIRECTIVE(CLASS, PARENT) \
case Stmt::CLASS##Class: \
return static_cast<const CLASS *>(this)->getPreInits();
#include "clang/AST/StmtNodes.inc"
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index afccba8778fd..003030052112 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -473,12 +473,21 @@ void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) {
}
void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) {
- Indent() << "continue;";
+ Indent();
+ if (Node->hasLabelTarget())
+ OS << "continue " << Node->getLabelDecl()->getIdentifier()->getName()
+ << ';';
+ else
+ OS << "continue;";
if (Policy.IncludeNewlines) OS << NL;
}
void StmtPrinter::VisitBreakStmt(BreakStmt *Node) {
- Indent() << "break;";
+ Indent();
+ if (Node->hasLabelTarget())
+ OS << "break " << Node->getLabelDecl()->getIdentifier()->getName() << ';';
+ else
+ OS << "break;";
if (Policy.IncludeNewlines) OS << NL;
}
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 2035fa7635f2..37c4d43ec0b2 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -999,30 +999,30 @@ void StmtProfiler::VisitOMPSimdDirective(const OMPSimdDirective *S) {
VisitOMPLoopDirective(S);
}
-void StmtProfiler::VisitOMPLoopTransformationDirective(
- const OMPLoopTransformationDirective *S) {
+void StmtProfiler::VisitOMPCanonicalLoopNestTransformationDirective(
+ const OMPCanonicalLoopNestTransformationDirective *S) {
VisitOMPLoopBasedDirective(S);
}
void StmtProfiler::VisitOMPTileDirective(const OMPTileDirective *S) {
- VisitOMPLoopTransformationDirective(S);
+ VisitOMPCanonicalLoopNestTransformationDirective(S);
}
void StmtProfiler::VisitOMPStripeDirective(const OMPStripeDirective *S) {
- VisitOMPLoopTransformationDirective(S);
+ VisitOMPCanonicalLoopNestTransformationDirective(S);
}
void StmtProfiler::VisitOMPUnrollDirective(const OMPUnrollDirective *S) {
- VisitOMPLoopTransformationDirective(S);
+ VisitOMPCanonicalLoopNestTransformationDirective(S);
}
void StmtProfiler::VisitOMPReverseDirective(const OMPReverseDirective *S) {
- VisitOMPLoopTransformationDirective(S);
+ VisitOMPCanonicalLoopNestTransformationDirective(S);
}
void StmtProfiler::VisitOMPInterchangeDirective(
const OMPInterchangeDirective *S) {
- VisitOMPLoopTransformationDirective(S);
+ VisitOMPCanonicalLoopNestTransformationDirective(S);
}
void StmtProfiler::VisitOMPForDirective(const OMPForDirective *S) {
@@ -2636,8 +2636,11 @@ void OpenACCClauseProfiler::VisitPrivateClause(
const OpenACCPrivateClause &Clause) {
VisitClauseWithVarList(Clause);
- for (auto *VD : Clause.getInitRecipes())
- Profiler.VisitDecl(VD);
+ for (auto &Recipe : Clause.getInitRecipes()) {
+ Profiler.VisitDecl(Recipe.AllocaDecl);
+ if (Recipe.InitExpr)
+ Profiler.VisitExpr(Recipe.InitExpr);
+ }
}
void OpenACCClauseProfiler::VisitFirstPrivateClause(
@@ -2645,7 +2648,9 @@ void OpenACCClauseProfiler::VisitFirstPrivateClause(
VisitClauseWithVarList(Clause);
for (auto &Recipe : Clause.getInitRecipes()) {
- Profiler.VisitDecl(Recipe.RecipeDecl);
+ Profiler.VisitDecl(Recipe.AllocaDecl);
+ if (Recipe.InitExpr)
+ Profiler.VisitExpr(Recipe.InitExpr);
Profiler.VisitDecl(Recipe.InitFromTemporary);
}
}
@@ -2750,11 +2755,13 @@ void OpenACCClauseProfiler::VisitReductionClause(
VisitClauseWithVarList(Clause);
for (auto &Recipe : Clause.getRecipes()) {
- Profiler.VisitDecl(Recipe.RecipeDecl);
+ Profiler.VisitDecl(Recipe.AllocaDecl);
+ if (Recipe.InitExpr)
+ Profiler.VisitExpr(Recipe.InitExpr);
// TODO: OpenACC: Make sure we remember to update this when we figure out
// what we're adding for the operation recipe, in the meantime, a static
// assert will make sure we don't add something.
- static_assert(sizeof(OpenACCReductionRecipe) == sizeof(int *));
+ static_assert(sizeof(OpenACCReductionRecipe) == 2 * sizeof(int *));
}
}
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index 76050ceeb35a..76f96fb8c5dc 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -56,8 +56,8 @@ static void printIntegral(const TemplateArgument &TemplArg, raw_ostream &Out,
const llvm::APSInt &Val = TemplArg.getAsIntegral();
if (Policy.UseEnumerators) {
- if (const EnumType *ET = T->getAs<EnumType>()) {
- for (const EnumConstantDecl *ECD : ET->getOriginalDecl()->enumerators()) {
+ if (const auto *ED = T->getAsEnumDecl()) {
+ for (const EnumConstantDecl *ECD : ED->enumerators()) {
// In Sema::CheckTemplateArugment, enum template arguments value are
// extended to the size of the integer underlying the enum type. This
// may create a size difference between the enum value and template
diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp
index c171516c38c1..f2cb15dbc43d 100644
--- a/clang/lib/AST/TemplateName.cpp
+++ b/clang/lib/AST/TemplateName.cpp
@@ -289,28 +289,23 @@ QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const {
return dyn_cast_if_present<QualifiedTemplateName *>(Storage);
}
-QualifiedTemplateName *
-TemplateName::getAsAdjustedQualifiedTemplateName() const {
- for (std::optional<TemplateName> Cur = *this; Cur;
- Cur = Cur->desugar(/*IgnoreDeduced=*/true))
- if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName())
- return N;
- return nullptr;
-}
-
DependentTemplateName *TemplateName::getAsDependentTemplateName() const {
return Storage.dyn_cast<DependentTemplateName *>();
}
-NestedNameSpecifier TemplateName::getQualifier() const {
+std::tuple<NestedNameSpecifier, bool>
+TemplateName::getQualifierAndTemplateKeyword() const {
for (std::optional<TemplateName> Cur = *this; Cur;
Cur = Cur->desugar(/*IgnoreDeduced=*/true)) {
if (DependentTemplateName *N = Cur->getAsDependentTemplateName())
- return N->getQualifier();
+ return {N->getQualifier(), N->hasTemplateKeyword()};
if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName())
- return N->getQualifier();
+ return {N->getQualifier(), N->hasTemplateKeyword()};
+ if (Cur->getAsSubstTemplateTemplateParm() ||
+ Cur->getAsSubstTemplateTemplateParmPack())
+ break;
}
- return std::nullopt;
+ return {std::nullopt, false};
}
UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const {
@@ -448,8 +443,14 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
Template = cast<TemplateDecl>(Template->getCanonicalDecl());
if (handleAnonymousTTP(Template, OS))
return;
- if (Qual == Qualified::None || Policy.SuppressScope) {
- OS << *Template;
+ if (Qual == Qualified::None || isa<TemplateTemplateParmDecl>(Template) ||
+ Policy.SuppressScope) {
+ if (IdentifierInfo *II = Template->getIdentifier();
+ Policy.CleanUglifiedParameters && II &&
+ isa<TemplateTemplateParmDecl>(Template))
+ OS << II->deuglifiedName();
+ else
+ OS << *Template;
} else {
PrintingPolicy NestedNamePolicy = Policy;
NestedNamePolicy.SuppressUnwrittenScope = true;
@@ -474,12 +475,7 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
if (handleAnonymousTTP(UTD, OS))
return;
- if (IdentifierInfo *II = UTD->getIdentifier();
- Policy.CleanUglifiedParameters && II &&
- isa<TemplateTemplateParmDecl>(UTD))
- OS << II->deuglifiedName();
- else
- OS << *UTD;
+ OS << *UTD;
} else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
DTN->print(OS, Policy);
} else if (SubstTemplateTemplateParmStorage *subst =
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 085616049373..8c59dbd34543 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1401,7 +1401,7 @@ static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
OS << " -> ";
const auto *RD = cast<CXXRecordDecl>(
- Base->getType()->castAs<RecordType>()->getOriginalDecl());
+ Base->getType()->castAsCanonical<RecordType>()->getOriginalDecl());
if (Base->isVirtual())
OS << "virtual ";
@@ -1412,6 +1412,26 @@ static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
OS << ')';
}
+void TextNodeDumper::VisitLoopControlStmt(const LoopControlStmt *Node) {
+ if (!Node->hasLabelTarget())
+ return;
+
+ OS << " '" << Node->getLabelDecl()->getIdentifier()->getName() << "' (";
+
+ auto *Target = Node->getNamedLoopOrSwitch();
+ if (!Target) {
+ ColorScope Color(OS, ShowColors, NullColor);
+ OS << "<<<NULL>>>";
+ } else {
+ {
+ ColorScope Color(OS, ShowColors, StmtColor);
+ OS << Target->getStmtClassName();
+ }
+ dumpPointer(Target);
+ }
+ OS << ")";
+}
+
void TextNodeDumper::VisitIfStmt(const IfStmt *Node) {
if (Node->hasInitStorage())
OS << " has_init";
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index a70bc5424009..86621795d81e 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -113,10 +113,8 @@ const IdentifierInfo *QualType::getBaseTypeIdentifier() const {
return DNT->getIdentifier();
if (ty->isPointerOrReferenceType())
return ty->getPointeeType().getBaseTypeIdentifier();
- if (ty->isRecordType())
- ND = ty->castAs<RecordType>()->getOriginalDecl();
- else if (ty->isEnumeralType())
- ND = ty->castAs<EnumType>()->getOriginalDecl();
+ if (const auto *TT = ty->getAs<TagType>())
+ ND = TT->getOriginalDecl();
else if (ty->getTypeClass() == Type::Typedef)
ND = ty->castAs<TypedefType>()->getDecl();
else if (ty->isArrayType())
@@ -672,63 +670,59 @@ const Type *Type::getUnqualifiedDesugaredType() const {
}
bool Type::isClassType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()->isClass();
return false;
}
bool Type::isStructureType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()->isStruct();
return false;
}
bool Type::isStructureTypeWithFlexibleArrayMember() const {
- const auto *RT = getAs<RecordType>();
+ const auto *RT = getAsCanonical<RecordType>();
if (!RT)
return false;
- const auto *Decl = RT->getOriginalDecl()->getDefinitionOrSelf();
+ const auto *Decl = RT->getOriginalDecl();
if (!Decl->isStruct())
return false;
- return Decl->hasFlexibleArrayMember();
+ return Decl->getDefinitionOrSelf()->hasFlexibleArrayMember();
}
bool Type::isObjCBoxableRecordType() const {
- if (const auto *RT = getAs<RecordType>())
- return RT->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->hasAttr<ObjCBoxableAttr>();
+ if (const auto *RD = getAsRecordDecl())
+ return RD->hasAttr<ObjCBoxableAttr>();
return false;
}
bool Type::isInterfaceType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()->isInterface();
return false;
}
bool Type::isStructureOrClassType() const {
- if (const auto *RT = getAs<RecordType>()) {
- RecordDecl *RD = RT->getOriginalDecl();
- return RD->isStruct() || RD->isClass() || RD->isInterface();
- }
+ if (const auto *RT = getAsCanonical<RecordType>())
+ return RT->getOriginalDecl()->isStructureOrClass();
return false;
}
bool Type::isVoidPointerType() const {
- if (const auto *PT = getAs<PointerType>())
+ if (const auto *PT = getAsCanonical<PointerType>())
return PT->getPointeeType()->isVoidType();
return false;
}
bool Type::isUnionType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()->isUnion();
return false;
}
bool Type::isComplexType() const {
- if (const auto *CT = dyn_cast<ComplexType>(CanonicalType))
+ if (const auto *CT = getAsCanonical<ComplexType>())
return CT->getElementType()->isFloatingType();
return false;
}
@@ -739,7 +733,7 @@ bool Type::isComplexIntegerType() const {
}
bool Type::isScopedEnumeralType() const {
- if (const auto *ET = getAs<EnumType>())
+ if (const auto *ET = getAsCanonical<EnumType>())
return ET->getOriginalDecl()->isScoped();
return false;
}
@@ -1914,41 +1908,13 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const {
const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const {
QualType PointeeType;
- if (const auto *PT = getAs<PointerType>())
+ if (const auto *PT = getAsCanonical<PointerType>())
PointeeType = PT->getPointeeType();
- else if (const auto *RT = getAs<ReferenceType>())
+ else if (const auto *RT = getAsCanonical<ReferenceType>())
PointeeType = RT->getPointeeType();
else
return nullptr;
-
- if (const auto *RT = PointeeType->getAs<RecordType>())
- return dyn_cast<CXXRecordDecl>(
- RT->getOriginalDecl()->getDefinitionOrSelf());
-
- return nullptr;
-}
-
-CXXRecordDecl *Type::getAsCXXRecordDecl() const {
- const auto *TT = dyn_cast<TagType>(CanonicalType);
- if (!isa_and_present<RecordType, InjectedClassNameType>(TT))
- return nullptr;
- auto *TD = TT->getOriginalDecl();
- if (!isa<InjectedClassNameType>(TT) && !isa<CXXRecordDecl>(TD))
- return nullptr;
- return cast<CXXRecordDecl>(TD)->getDefinitionOrSelf();
-}
-
-RecordDecl *Type::getAsRecordDecl() const {
- const auto *TT = dyn_cast<TagType>(CanonicalType);
- if (!isa_and_present<RecordType, InjectedClassNameType>(TT))
- return nullptr;
- return cast<RecordDecl>(TT->getOriginalDecl())->getDefinitionOrSelf();
-}
-
-TagDecl *Type::getAsTagDecl() const {
- if (const auto *TT = dyn_cast<TagType>(CanonicalType))
- return TT->getOriginalDecl()->getDefinitionOrSelf();
- return nullptr;
+ return PointeeType->getAsCXXRecordDecl();
}
const TemplateSpecializationType *
@@ -1963,12 +1929,10 @@ NestedNameSpecifier Type::getPrefix() const {
switch (getTypeClass()) {
case Type::DependentName:
return cast<DependentNameType>(this)->getQualifier();
- case Type::TemplateSpecialization: {
- QualifiedTemplateName *S = cast<TemplateSpecializationType>(this)
- ->getTemplateName()
- .getAsAdjustedQualifiedTemplateName();
- return S ? S->getQualifier() : std::nullopt;
- }
+ case Type::TemplateSpecialization:
+ return cast<TemplateSpecializationType>(this)
+ ->getTemplateName()
+ .getQualifier();
case Type::DependentTemplateSpecialization:
return cast<DependentTemplateSpecializationType>(this)
->getDependentTemplateName()
@@ -2246,10 +2210,9 @@ bool Type::isSignedIntegerType() const {
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->isSignedInteger();
- if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
+ if (const auto *ED = getAsEnumDecl()) {
// Incomplete enum types are not treated as integer types.
// FIXME: In C++, enum types are never integer types.
- const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
if (!ED->isComplete() || ED->isScoped())
return false;
return ED->getIntegerType()->isSignedIntegerType();
@@ -2267,8 +2230,7 @@ bool Type::isSignedIntegerOrEnumerationType() const {
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->isSignedInteger();
- if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) {
- const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ if (const auto *ED = getAsEnumDecl()) {
if (!ED->isComplete())
return false;
return ED->getIntegerType()->isSignedIntegerType();
@@ -2296,10 +2258,9 @@ bool Type::isUnsignedIntegerType() const {
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->isUnsignedInteger();
- if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) {
+ if (const auto *ED = getAsEnumDecl()) {
// Incomplete enum types are not treated as integer types.
// FIXME: In C++, enum types are never integer types.
- const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
if (!ED->isComplete() || ED->isScoped())
return false;
return ED->getIntegerType()->isUnsignedIntegerType();
@@ -2317,8 +2278,7 @@ bool Type::isUnsignedIntegerOrEnumerationType() const {
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->isUnsignedInteger();
- if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) {
- const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ if (const auto *ED = getAsEnumDecl()) {
if (!ED->isComplete())
return false;
return ED->getIntegerType()->isUnsignedIntegerType();
@@ -2398,10 +2358,8 @@ bool Type::isArithmeticType() const {
bool Type::hasBooleanRepresentation() const {
if (const auto *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isBooleanType();
- if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) {
- const auto *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ if (const auto *ED = getAsEnumDecl())
return ED->isComplete() && ED->getIntegerType()->isBooleanType();
- }
if (const auto *IT = dyn_cast<BitIntType>(CanonicalType))
return IT->getNumBits() == 1;
return isBooleanType();
@@ -2432,10 +2390,7 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const {
} else if (isa<MemberPointerType>(T)) {
return STK_MemberPointer;
} else if (isa<EnumType>(T)) {
- assert(cast<EnumType>(T)
- ->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->isComplete());
+ assert(T->castAsEnumDecl()->isComplete());
return STK_Integral;
} else if (const auto *CT = dyn_cast<ComplexType>(T)) {
if (CT->getElementType()->isRealFloatingType())
@@ -2459,8 +2414,8 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const {
/// includes union types.
bool Type::isAggregateType() const {
if (const auto *Record = dyn_cast<RecordType>(CanonicalType)) {
- if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(
- Record->getOriginalDecl()->getDefinitionOrSelf()))
+ if (const auto *ClassDecl =
+ dyn_cast<CXXRecordDecl>(Record->getOriginalDecl()))
return ClassDecl->isAggregate();
return true;
@@ -2494,8 +2449,7 @@ bool Type::isIncompleteType(NamedDecl **Def) const {
// be completed.
return isVoidType();
case Enum: {
- EnumDecl *EnumD =
- cast<EnumType>(CanonicalType)->getOriginalDecl()->getDefinitionOrSelf();
+ auto *EnumD = castAsEnumDecl();
if (Def)
*Def = EnumD;
return !EnumD->isComplete();
@@ -2503,17 +2457,13 @@ bool Type::isIncompleteType(NamedDecl **Def) const {
case Record: {
// A tagged type (struct/union/enum/class) is incomplete if the decl is a
// forward declaration, but not a full definition (C99 6.2.5p22).
- RecordDecl *Rec = cast<RecordType>(CanonicalType)
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ auto *Rec = castAsRecordDecl();
if (Def)
*Def = Rec;
return !Rec->isCompleteDefinition();
}
case InjectedClassName: {
- CXXRecordDecl *Rec = cast<InjectedClassNameType>(CanonicalType)
- ->getOriginalDecl()
- ->getDefinitionOrSelf();
+ auto *Rec = castAsCXXRecordDecl();
if (!Rec->isBeingDefined())
return false;
if (Def)
@@ -2573,7 +2523,7 @@ bool Type::isAlwaysIncompleteType() const {
// Forward declarations of structs, classes, enums, and unions could be later
// completed in a compilation unit by providing a type definition.
- if (getAsTagDecl())
+ if (isa<TagType>(CanonicalType))
return false;
// Other types are incompletable.
@@ -2771,6 +2721,11 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const {
return false;
QualType CanonicalType = getTypePtr()->CanonicalType;
+
+ // Any type that is, or contains, address discriminated data is never POD.
+ if (Context.containsAddressDiscriminatedPointerAuth(CanonicalType))
+ return false;
+
switch (CanonicalType->getTypeClass()) {
// Everything not explicitly mentioned is not POD.
default:
@@ -2797,7 +2752,7 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const {
case Type::Record:
if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(
cast<RecordType>(CanonicalType)->getOriginalDecl()))
- return ClassDecl->getDefinitionOrSelf()->isPOD();
+ return ClassDecl->isPOD();
// C struct/union is POD.
return true;
@@ -2829,6 +2784,11 @@ bool QualType::isTrivialType(const ASTContext &Context) const {
if (CanonicalType->isDependentType())
return false;
+ // Any type that is, or contains, address discriminated data is never a
+ // trivial type.
+ if (Context.containsAddressDiscriminatedPointerAuth(CanonicalType))
+ return false;
+
// C++0x [basic.types]p9:
// Scalar types, trivial class types, arrays of such types, and
// cv-qualified versions of these types are collectively called trivial
@@ -2837,23 +2797,22 @@ bool QualType::isTrivialType(const ASTContext &Context) const {
// As an extension, Clang treats vector types as Scalar types.
if (CanonicalType->isScalarType() || CanonicalType->isVectorType())
return true;
- if (const auto *RT = CanonicalType->getAs<RecordType>()) {
- if (const auto *ClassDecl =
- dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) {
- // C++20 [class]p6:
- // A trivial class is a class that is trivially copyable, and
- // has one or more eligible default constructors such that each is
- // trivial.
- // FIXME: We should merge this definition of triviality into
- // CXXRecordDecl::isTrivial. Currently it computes the wrong thing.
- return ClassDecl->hasTrivialDefaultConstructor() &&
- !ClassDecl->hasNonTrivialDefaultConstructor() &&
- ClassDecl->isTriviallyCopyable();
- }
- return true;
+ if (const auto *ClassDecl = CanonicalType->getAsCXXRecordDecl()) {
+ // C++20 [class]p6:
+ // A trivial class is a class that is trivially copyable, and
+ // has one or more eligible default constructors such that each is
+ // trivial.
+ // FIXME: We should merge this definition of triviality into
+ // CXXRecordDecl::isTrivial. Currently it computes the wrong thing.
+ return ClassDecl->hasTrivialDefaultConstructor() &&
+ !ClassDecl->hasNonTrivialDefaultConstructor() &&
+ ClassDecl->isTriviallyCopyable();
}
+ if (isa<RecordType>(CanonicalType))
+ return true;
+
// No other types can match.
return false;
}
@@ -2897,18 +2856,13 @@ static bool isTriviallyCopyableTypeImpl(const QualType &type,
if (CanonicalType->isMFloat8Type())
return true;
- if (const auto *RT = CanonicalType->getAs<RecordType>()) {
- if (const auto *ClassDecl =
- dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) {
- if (IsCopyConstructible) {
+ if (const auto *RD = CanonicalType->getAsRecordDecl()) {
+ if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
+ if (IsCopyConstructible)
return ClassDecl->isTriviallyCopyConstructible();
- } else {
- return ClassDecl->isTriviallyCopyable();
- }
+ return ClassDecl->isTriviallyCopyable();
}
- return !RT->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->isNonTrivialToPrimitiveCopy();
+ return !RD->isNonTrivialToPrimitiveCopy();
}
// No other types can match.
return false;
@@ -2930,6 +2884,12 @@ bool QualType::isBitwiseCloneableType(const ASTContext &Context) const {
if (CanonicalType->isIncompleteType())
return false;
+
+ // Any type that is, or contains, address discriminated data is never
+ // bitwise clonable.
+ if (Context.containsAddressDiscriminatedPointerAuth(CanonicalType))
+ return false;
+
const auto *RD = CanonicalType->getAsRecordDecl(); // struct/union/class
if (!RD)
return true;
@@ -2996,11 +2956,9 @@ bool QualType::isWebAssemblyFuncrefType() const {
QualType::PrimitiveDefaultInitializeKind
QualType::isNonTrivialToPrimitiveDefaultInitialize() const {
- if (const auto *RT =
- getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>())
- if (RT->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->isNonTrivialToPrimitiveDefaultInitialize())
+ if (const auto *RD =
+ getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl())
+ if (RD->isNonTrivialToPrimitiveDefaultInitialize())
return PDIK_Struct;
switch (getQualifiers().getObjCLifetime()) {
@@ -3014,11 +2972,9 @@ QualType::isNonTrivialToPrimitiveDefaultInitialize() const {
}
QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveCopy() const {
- if (const auto *RT =
- getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>())
- if (RT->getOriginalDecl()
- ->getDefinitionOrSelf()
- ->isNonTrivialToPrimitiveCopy())
+ if (const auto *RD =
+ getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl())
+ if (RD->isNonTrivialToPrimitiveCopy())
return PCK_Struct;
Qualifiers Qs = getQualifiers();
@@ -3075,7 +3031,7 @@ bool Type::isLiteralType(const ASTContext &Ctx) const {
if (BaseTy->isReferenceType())
return true;
// -- a class type that has all of the following properties:
- if (const auto *RT = BaseTy->getAs<RecordType>()) {
+ if (const auto *RD = BaseTy->getAsRecordDecl()) {
// -- a trivial destructor,
// -- every constructor call and full-expression in the
// brace-or-equal-initializers for non-static data members (if any)
@@ -3086,8 +3042,8 @@ bool Type::isLiteralType(const ASTContext &Ctx) const {
// -- all non-static data members and base classes of literal types
//
// We resolve DR1361 by ignoring the second bullet.
- if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getOriginalDecl()))
- return ClassDecl->getDefinitionOrSelf()->isLiteral();
+ if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD))
+ return ClassDecl->isLiteral();
return true;
}
@@ -3139,10 +3095,10 @@ bool Type::isStandardLayoutType() const {
// As an extension, Clang treats vector types as Scalar types.
if (BaseTy->isScalarType() || BaseTy->isVectorType())
return true;
- if (const auto *RT = BaseTy->getAs<RecordType>()) {
- if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getOriginalDecl()))
- if (!ClassDecl->getDefinitionOrSelf()->isStandardLayout())
- return false;
+ if (const auto *RD = BaseTy->getAsRecordDecl()) {
+ if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD);
+ ClassDecl && !ClassDecl->isStandardLayout())
+ return false;
// Default to 'true' for non-C++ class types.
// FIXME: This is a bit dubious, but plain C structs should trivially meet
@@ -3179,13 +3135,15 @@ bool QualType::isCXX11PODType(const ASTContext &Context) const {
if (BaseTy->isIncompleteType())
return false;
+ // Any type that is, or contains, address discriminated data is non-POD.
+ if (Context.containsAddressDiscriminatedPointerAuth(*this))
+ return false;
+
// As an extension, Clang treats vector types as Scalar types.
if (BaseTy->isScalarType() || BaseTy->isVectorType())
return true;
- if (const auto *RT = BaseTy->getAs<RecordType>()) {
- if (const auto *ClassDecl =
- dyn_cast<CXXRecordDecl>(RT->getOriginalDecl())) {
- ClassDecl = ClassDecl->getDefinitionOrSelf();
+ if (const auto *RD = BaseTy->getAsRecordDecl()) {
+ if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
// C++11 [class]p10:
// A POD struct is a non-union class that is both a trivial class [...]
if (!ClassDecl->isTrivial())
@@ -3224,7 +3182,7 @@ bool Type::isNothrowT() const {
}
bool Type::isAlignValT() const {
- if (const auto *ET = getAs<EnumType>()) {
+ if (const auto *ET = getAsCanonical<EnumType>()) {
const auto *ED = ET->getOriginalDecl();
IdentifierInfo *II = ED->getIdentifier();
if (II && II->isStr("align_val_t") && ED->isInStdNamespace())
@@ -3234,7 +3192,7 @@ bool Type::isAlignValT() const {
}
bool Type::isStdByteType() const {
- if (const auto *ET = getAs<EnumType>()) {
+ if (const auto *ET = getAsCanonical<EnumType>()) {
const auto *ED = ET->getOriginalDecl();
IdentifierInfo *II = ED->getIdentifier();
if (II && II->isStr("byte") && ED->isInStdNamespace())
@@ -4405,7 +4363,7 @@ bool RecordType::hasConstFields() const {
if (FieldTy.isConstQualified())
return true;
FieldTy = FieldTy.getCanonicalType();
- if (const auto *FieldRecTy = FieldTy->getAs<RecordType>()) {
+ if (const auto *FieldRecTy = FieldTy->getAsCanonical<RecordType>()) {
if (!llvm::is_contained(RecordTypeList, FieldRecTy))
RecordTypeList.push_back(FieldRecTy);
}
@@ -5409,7 +5367,7 @@ bool Type::isObjCARCBridgableType() const {
/// Determine whether the given type T is a "bridgeable" C type.
bool Type::isCARCBridgableType() const {
- const auto *Pointer = getAs<PointerType>();
+ const auto *Pointer = getAsCanonical<PointerType>();
if (!Pointer)
return false;
@@ -5419,7 +5377,7 @@ bool Type::isCARCBridgableType() const {
/// Check if the specified type is the CUDA device builtin surface type.
bool Type::isCUDADeviceBuiltinSurfaceType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()
->getMostRecentDecl()
->hasAttr<CUDADeviceBuiltinSurfaceTypeAttr>();
@@ -5428,7 +5386,7 @@ bool Type::isCUDADeviceBuiltinSurfaceType() const {
/// Check if the specified type is the CUDA device builtin texture type.
bool Type::isCUDADeviceBuiltinTextureType() const {
- if (const auto *RT = getAs<RecordType>())
+ if (const auto *RT = getAsCanonical<RecordType>())
return RT->getOriginalDecl()
->getMostRecentDecl()
->hasAttr<CUDADeviceBuiltinTextureTypeAttr>();
@@ -5462,7 +5420,7 @@ bool Type::isHLSLResourceRecordArray() const {
const Type *Ty = getUnqualifiedDesugaredType();
if (!Ty->isArrayType())
return false;
- while (isa<ConstantArrayType>(Ty))
+ while (isa<ArrayType>(Ty))
Ty = Ty->getArrayElementTypeNoTypeQual();
return Ty->isHLSLResourceRecord();
}
@@ -5475,7 +5433,7 @@ bool Type::isHLSLIntangibleType() const {
return Ty->isHLSLBuiltinIntangibleType();
// unwrap arrays
- while (isa<ConstantArrayType>(Ty))
+ while (isa<ArrayType>(Ty))
Ty = Ty->getArrayElementTypeNoTypeQual();
const RecordType *RT =
@@ -5503,8 +5461,7 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
return DK_objc_weak_lifetime;
}
- if (const auto *RT = type->getBaseElementTypeUnsafe()->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getOriginalDecl();
+ if (const auto *RD = type->getBaseElementTypeUnsafe()->getAsRecordDecl()) {
if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
/// Check if this is a C++ object with a non-trivial destructor.
if (CXXRD->hasDefinition() && !CXXRD->hasTrivialDestructor())
@@ -5512,7 +5469,7 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
} else {
/// Check if this is a C struct that is non-trivial to destroy or an array
/// that contains such a struct.
- if (RD->getDefinitionOrSelf()->isNonTrivialToPrimitiveDestroy())
+ if (RD->isNonTrivialToPrimitiveDestroy())
return DK_nontrivial_c_struct;
}
}
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index fbe877292446..3e9597fc4d47 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -750,8 +750,9 @@ void TemplateSpecializationTypeLoc::set(SourceLocation ElaboratedKeywordLoc,
void TemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
- QualifiedTemplateName *Name =
- getTypePtr()->getTemplateName().getAsAdjustedQualifiedTemplateName();
+
+ auto [Qualifier, HasTemplateKeyword] =
+ getTypePtr()->getTemplateName().getQualifierAndTemplateKeyword();
SourceLocation ElaboratedKeywordLoc =
getTypePtr()->getKeyword() != ElaboratedTypeKeyword::None
@@ -759,8 +760,7 @@ void TemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
: SourceLocation();
NestedNameSpecifierLoc QualifierLoc;
- if (NestedNameSpecifier Qualifier =
- Name ? Name->getQualifier() : std::nullopt) {
+ if (Qualifier) {
NestedNameSpecifierLocBuilder Builder;
Builder.MakeTrivial(Context, Qualifier, Loc);
QualifierLoc = Builder.getWithLocInContext(Context);
@@ -768,9 +768,7 @@ void TemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
TemplateArgumentListInfo TAL(Loc, Loc);
set(ElaboratedKeywordLoc, QualifierLoc,
- /*TemplateKeywordLoc=*/Name && Name->hasTemplateKeyword()
- ? Loc
- : SourceLocation(),
+ /*TemplateKeywordLoc=*/HasTemplateKeyword ? Loc : SourceLocation(),
/*NameLoc=*/Loc, /*LAngleLoc=*/Loc, /*RAngleLoc=*/Loc);
initializeArgLocs(Context, getTypePtr()->template_arguments(), getArgInfos(),
Loc);
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 52ff0d5b5771..54ca42d2035a 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -2382,7 +2382,7 @@ static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern,
return true;
// A type parameter matches its argument.
- if (auto *TTPT = Pattern->getAs<TemplateTypeParmType>()) {
+ if (auto *TTPT = Pattern->getAsCanonical<TemplateTypeParmType>()) {
if (TTPT->getDepth() == Depth && TTPT->getIndex() < Args.size() &&
Args[TTPT->getIndex()].getKind() == TemplateArgument::Type) {
QualType SubstArg = Ctx.getQualifiedType(
diff --git a/clang/lib/AST/VTTBuilder.cpp b/clang/lib/AST/VTTBuilder.cpp
index 85101aee97e6..89b58b557ddc 100644
--- a/clang/lib/AST/VTTBuilder.cpp
+++ b/clang/lib/AST/VTTBuilder.cpp
@@ -63,11 +63,7 @@ void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
if (I.isVirtual())
continue;
- const auto *BaseDecl =
- cast<CXXRecordDecl>(
- I.getType()->castAs<RecordType>()->getOriginalDecl())
- ->getDefinitionOrSelf();
-
+ const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
CharUnits BaseOffset = Base.getBaseOffset() +
Layout.getBaseClassOffset(BaseDecl);
@@ -91,10 +87,7 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
return;
for (const auto &I : RD->bases()) {
- const auto *BaseDecl =
- cast<CXXRecordDecl>(
- I.getType()->castAs<RecordType>()->getOriginalDecl())
- ->getDefinitionOrSelf();
+ const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();
// Itanium C++ ABI 2.6.2:
// Secondary virtual pointers are present for all bases with either
@@ -157,10 +150,7 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD,
VisitedVirtualBasesSetTy &VBases) {
for (const auto &I : RD->bases()) {
- const auto *BaseDecl =
- cast<CXXRecordDecl>(
- I.getType()->castAs<RecordType>()->getOriginalDecl())
- ->getDefinitionOrSelf();
+ const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();
// Check if this is a virtual base.
if (I.isVirtual()) {