aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST')
-rw-r--r--clang/lib/AST/APValue.cpp2
-rw-r--r--clang/lib/AST/ASTConcept.cpp11
-rw-r--r--clang/lib/AST/ASTContext.cpp1188
-rw-r--r--clang/lib/AST/ASTDiagnostic.cpp49
-rw-r--r--clang/lib/AST/ASTDumper.cpp4
-rw-r--r--clang/lib/AST/ASTImporter.cpp310
-rw-r--r--clang/lib/AST/ASTImporterLookupTable.cpp16
-rw-r--r--clang/lib/AST/ASTStructuralEquivalence.cpp194
-rw-r--r--clang/lib/AST/ASTTypeTraits.cpp36
-rw-r--r--clang/lib/AST/ByteCode/Compiler.cpp339
-rw-r--r--clang/lib/AST/ByteCode/Compiler.h23
-rw-r--r--clang/lib/AST/ByteCode/Context.cpp25
-rw-r--r--clang/lib/AST/ByteCode/Context.h21
-rw-r--r--clang/lib/AST/ByteCode/Descriptor.cpp124
-rw-r--r--clang/lib/AST/ByteCode/Descriptor.h9
-rw-r--r--clang/lib/AST/ByteCode/Disasm.cpp53
-rw-r--r--clang/lib/AST/ByteCode/DynamicAllocator.cpp76
-rw-r--r--clang/lib/AST/ByteCode/DynamicAllocator.h11
-rw-r--r--clang/lib/AST/ByteCode/EvalEmitter.cpp23
-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/Function.h2
-rw-r--r--clang/lib/AST/ByteCode/Integral.h5
-rw-r--r--clang/lib/AST/ByteCode/Interp.cpp288
-rw-r--r--clang/lib/AST/ByteCode/Interp.h110
-rw-r--r--clang/lib/AST/ByteCode/InterpBlock.cpp47
-rw-r--r--clang/lib/AST/ByteCode/InterpBlock.h78
-rw-r--r--clang/lib/AST/ByteCode/InterpBuiltin.cpp843
-rw-r--r--clang/lib/AST/ByteCode/InterpFrame.cpp12
-rw-r--r--clang/lib/AST/ByteCode/InterpFrame.h3
-rw-r--r--clang/lib/AST/ByteCode/InterpStack.cpp57
-rw-r--r--clang/lib/AST/ByteCode/InterpStack.h24
-rw-r--r--clang/lib/AST/ByteCode/InterpState.cpp40
-rw-r--r--clang/lib/AST/ByteCode/InterpState.h5
-rw-r--r--clang/lib/AST/ByteCode/MemberPointer.h6
-rw-r--r--clang/lib/AST/ByteCode/Pointer.cpp223
-rw-r--r--clang/lib/AST/ByteCode/Pointer.h263
-rw-r--r--clang/lib/AST/ByteCode/PrimType.h30
-rw-r--r--clang/lib/AST/ByteCode/Program.cpp61
-rw-r--r--clang/lib/AST/ByteCode/Program.h9
-rw-r--r--clang/lib/AST/ByteCode/Record.cpp4
-rw-r--r--clang/lib/AST/CXXInheritance.cpp34
-rw-r--r--clang/lib/AST/Comment.cpp2
-rw-r--r--clang/lib/AST/CommentLexer.cpp2
-rw-r--r--clang/lib/AST/CommentParser.cpp5
-rw-r--r--clang/lib/AST/CommentSema.cpp21
-rw-r--r--clang/lib/AST/ComparisonCategories.cpp2
-rw-r--r--clang/lib/AST/ComputeDependence.cpp26
-rw-r--r--clang/lib/AST/Decl.cpp137
-rw-r--r--clang/lib/AST/DeclBase.cpp40
-rw-r--r--clang/lib/AST/DeclCXX.cpp129
-rw-r--r--clang/lib/AST/DeclPrinter.cpp60
-rw-r--r--clang/lib/AST/DeclTemplate.cpp91
-rw-r--r--clang/lib/AST/DeclarationName.cpp11
-rw-r--r--clang/lib/AST/DynamicRecursiveASTVisitor.cpp53
-rw-r--r--clang/lib/AST/Expr.cpp142
-rw-r--r--clang/lib/AST/ExprCXX.cpp9
-rw-r--r--clang/lib/AST/ExprConcepts.cpp4
-rw-r--r--clang/lib/AST/ExprConstant.cpp689
-rw-r--r--clang/lib/AST/FormatString.cpp18
-rw-r--r--clang/lib/AST/InheritViz.cpp6
-rw-r--r--clang/lib/AST/ItaniumCXXABI.cpp7
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp214
-rw-r--r--clang/lib/AST/JSONNodeDumper.cpp36
-rw-r--r--clang/lib/AST/MicrosoftMangle.cpp30
-rw-r--r--clang/lib/AST/NestedNameSpecifier.cpp474
-rw-r--r--clang/lib/AST/ODRHash.cpp124
-rw-r--r--clang/lib/AST/OpenACCClause.cpp8
-rw-r--r--clang/lib/AST/OpenMPClause.cpp35
-rw-r--r--clang/lib/AST/ParentMapContext.cpp6
-rw-r--r--clang/lib/AST/PrintfFormatString.cpp4
-rw-r--r--clang/lib/AST/QualTypeNames.cpp368
-rw-r--r--clang/lib/AST/RecordLayoutBuilder.cpp54
-rw-r--r--clang/lib/AST/ScanfFormatString.cpp6
-rw-r--r--clang/lib/AST/StmtPrinter.cpp33
-rw-r--r--clang/lib/AST/StmtProfile.cpp73
-rw-r--r--clang/lib/AST/TemplateBase.cpp34
-rw-r--r--clang/lib/AST/TemplateName.cpp66
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp78
-rw-r--r--clang/lib/AST/Type.cpp644
-rw-r--r--clang/lib/AST/TypeLoc.cpp242
-rw-r--r--clang/lib/AST/TypePrinter.cpp276
-rw-r--r--clang/lib/AST/VTTBuilder.cpp10
-rw-r--r--clang/lib/AST/VTableBuilder.cpp8
84 files changed, 5220 insertions, 3830 deletions
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index ee3dc84..7173c2a 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -902,8 +902,8 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy,
}
case APValue::Struct: {
Out << '{';
- const RecordDecl *RD = Ty->castAs<RecordType>()->getDecl();
bool First = true;
+ 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/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index 2243ac0..d658890 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/ASTConcept.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ExprConcepts.h"
+#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
#include "llvm/ADT/StringExtras.h"
@@ -92,10 +93,16 @@ ConceptReference::Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
FoundDecl, NamedConcept, ArgsAsWritten);
}
+SourceLocation ConceptReference::getBeginLoc() const {
+ // Note that if the qualifier is null the template KW must also be null.
+ if (auto QualifierLoc = getNestedNameSpecifierLoc())
+ return QualifierLoc.getBeginLoc();
+ return getConceptNameInfo().getBeginLoc();
+}
+
void ConceptReference::print(llvm::raw_ostream &OS,
const PrintingPolicy &Policy) const {
- if (NestedNameSpec)
- NestedNameSpec.getNestedNameSpecifier()->print(OS, Policy);
+ NestedNameSpec.getNestedNameSpecifier().print(OS, Policy);
ConceptName.printName(OS, Policy);
if (hasExplicitTemplateArgs()) {
OS << "<";
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 3a16111..dca05b4 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->getDecl())
- 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,9 +1934,8 @@ 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>();
- RT && !RT->getDecl()->isInvalidDecl()) {
- const ASTRecordLayout &layout = getASTRecordLayout(RT->getDecl());
+ if (const auto *RD = T->getAsCXXRecordDecl(); RD && !RD->isInvalidDecl()) {
+ const ASTRecordLayout &layout = getASTRecordLayout(RD);
Info.Width = layout.getDataSize();
}
}
@@ -2002,9 +2002,9 @@ 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>()) {
- if (T->isDependentType() || ET->getDecl()->getPromotionType().isNull() ||
- ET->getDecl()->isScoped())
+ if (const auto *ED = T->getAsEnumDecl()) {
+ if (T->isDependentType() || ED->getPromotionType().isNull() ||
+ ED->isScoped())
return false;
return true;
@@ -2040,8 +2040,8 @@ unsigned ASTContext::getTypeAlignIfKnown(QualType T,
return Align;
// Otherwise, see if the declaration of the type had an attribute.
- if (const auto *TT = T->getAs<TagType>())
- return TT->getDecl()->getMaxAlignment();
+ if (const auto *TD = T->getAsTagDecl())
+ return TD->getMaxAlignment();
return 0;
}
@@ -2472,15 +2472,16 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::Record:
case Type::Enum: {
const auto *TT = cast<TagType>(T);
+ const TagDecl *TD = TT->getOriginalDecl()->getDefinitionOrSelf();
- if (TT->getDecl()->isInvalidDecl()) {
+ if (TD->isInvalidDecl()) {
Width = 8;
Align = 8;
break;
}
- if (const auto *ET = dyn_cast<EnumType>(TT)) {
- const EnumDecl *ED = ET->getDecl();
+ if (isa<EnumType>(TT)) {
+ const EnumDecl *ED = cast<EnumDecl>(TD);
TypeInfo Info =
getTypeInfo(ED->getIntegerType()->getUnqualifiedDesugaredType());
if (unsigned AttrAlign = ED->getMaxAlignment()) {
@@ -2490,8 +2491,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
return Info;
}
- const auto *RT = cast<RecordType>(TT);
- const RecordDecl *RD = RT->getDecl();
+ const auto *RD = cast<RecordDecl>(TD);
const ASTRecordLayout &Layout = getASTRecordLayout(RD);
Width = toBits(Layout.getSize());
Align = toBits(Layout.getAlignment());
@@ -2543,9 +2543,6 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
break;
}
- case Type::Elaborated:
- return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
-
case Type::Attributed:
return getTypeInfo(
cast<AttributedType>(T)->getEquivalentType().getTypePtr());
@@ -2618,11 +2615,10 @@ unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const {
return I->second;
unsigned UnadjustedAlign;
- if (const auto *RT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl();
- const ASTRecordLayout &Layout = getASTRecordLayout(RD);
+ 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 {
@@ -2695,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->getDecl();
-
+ 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
@@ -2718,8 +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->getDecl()->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) ||
@@ -2851,7 +2845,8 @@ static bool unionHasUniqueObjectRepresentations(const ASTContext &Context,
const RecordDecl *RD,
bool CheckIfTriviallyCopyable) {
assert(RD->isUnion() && "Must be union type");
- CharUnits UnionSize = Context.getTypeSizeInChars(RD->getTypeForDecl());
+ CharUnits UnionSize =
+ Context.getTypeSizeInChars(Context.getCanonicalTagType(RD));
for (const auto *Field : RD->fields()) {
if (!Context.hasUniqueObjectRepresentations(Field->getType(),
@@ -2884,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.
@@ -3037,16 +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>()->getDecl();
-
+ if (const auto *Record = Ty->getAsRecordDecl()) {
if (Record->isInvalidDecl())
return false;
@@ -3418,7 +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)->getDecl()->getIntegerType();
+ QualType UnderlyingType = T->castAsEnumDecl()->getIntegerType();
return encodeTypeForFunctionPointerAuth(
Ctx, OS, UnderlyingType.isNull() ? Ctx.IntTy : UnderlyingType);
}
@@ -3456,7 +3447,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
OS << "M";
const auto *MPT = T->castAs<MemberPointerType>();
encodeTypeForFunctionPointerAuth(
- Ctx, OS, QualType(MPT->getQualifier()->getAsType(), 0));
+ Ctx, OS, QualType(MPT->getQualifier().getAsType(), 0));
encodeTypeForFunctionPointerAuth(Ctx, OS, MPT->getPointeeType());
return;
}
@@ -3562,7 +3553,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx,
llvm_unreachable("should never get here");
}
case Type::Record: {
- const RecordDecl *RD = T->castAs<RecordType>()->getDecl();
+ const RecordDecl *RD = T->castAsCanonical<RecordType>()->getOriginalDecl();
const IdentifierInfo *II = RD->getIdentifier();
// In C++, an immediate typedef of an anonymous struct or union
@@ -3740,12 +3731,6 @@ ASTContext::adjustType(QualType Orig,
adjustType(BTFT->getWrappedType(), Adjust));
}
- case Type::Elaborated: {
- const auto *ET = cast<ElaboratedType>(Orig);
- return getElaboratedType(ET->getKeyword(), ET->getQualifier(),
- adjustType(ET->getNamedType(), Adjust));
- }
-
case Type::Paren:
return getParenType(
adjustType(cast<ParenType>(Orig)->getInnerType(), Adjust));
@@ -4163,14 +4148,13 @@ QualType ASTContext::getRValueReferenceType(QualType T) const {
}
QualType ASTContext::getMemberPointerType(QualType T,
- NestedNameSpecifier *Qualifier,
+ NestedNameSpecifier Qualifier,
const CXXRecordDecl *Cls) const {
if (!Qualifier) {
assert(Cls && "At least one of Qualifier or Cls must be provided");
- Qualifier = NestedNameSpecifier::Create(*this, /*Prefix=*/nullptr,
- getTypeDeclType(Cls).getTypePtr());
+ Qualifier = NestedNameSpecifier(getCanonicalTagType(Cls).getTypePtr());
} else if (!Cls) {
- Cls = Qualifier->getAsRecordDecl();
+ Cls = Qualifier.getAsRecordDecl();
}
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
@@ -4182,12 +4166,11 @@ QualType ASTContext::getMemberPointerType(QualType T,
MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(PT, 0);
- NestedNameSpecifier *CanonicalQualifier = [&] {
+ NestedNameSpecifier CanonicalQualifier = [&] {
if (!Cls)
- return getCanonicalNestedNameSpecifier(Qualifier);
- NestedNameSpecifier *R = NestedNameSpecifier::Create(
- *this, /*Prefix=*/nullptr, Cls->getCanonicalDecl()->getTypeForDecl());
- assert(R == getCanonicalNestedNameSpecifier(R));
+ return Qualifier.getCanonical();
+ NestedNameSpecifier R(getCanonicalTagType(Cls).getTypePtr());
+ assert(R.isCanonical());
return R;
}();
// If the pointee or class type isn't canonical, this won't be a canonical
@@ -4306,6 +4289,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
case Type::DependentTemplateSpecialization:
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
+ case Type::SubstBuiltinTemplatePack:
case Type::Auto:
case Type::DeducedTemplateSpecialization:
case Type::PackExpansion:
@@ -5128,10 +5112,12 @@ QualType ASTContext::getFunctionTypeInternal(
EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size());
size_t Size = FunctionProtoType::totalSizeToAlloc<
QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields,
+ FunctionType::FunctionTypeExtraAttributeInfo,
FunctionType::FunctionTypeArmAttributes, FunctionType::ExceptionType,
Expr *, FunctionDecl *, FunctionProtoType::ExtParameterInfo, Qualifiers,
FunctionEffect, EffectConditionExpr>(
NumArgs, EPI.Variadic, EPI.requiresFunctionProtoTypeExtraBitfields(),
+ EPI.requiresFunctionProtoTypeExtraAttributeInfo(),
EPI.requiresFunctionProtoTypeArmAttributes(), ESH.NumExceptionType,
ESH.NumExprPtr, ESH.NumFunctionDeclPtr,
EPI.ExtParameterInfos ? NumArgs : 0,
@@ -5245,7 +5231,6 @@ ASTContext::getPredefinedSugarType(PredefinedSugarType::Kind KD) const {
}
llvm_unreachable("unexpected kind");
};
-
auto *New = new (*this, alignof(PredefinedSugarType))
PredefinedSugarType(KD, &Idents.get(PredefinedSugarType::getName(KD)),
getCanonicalType(*this, static_cast<Kind>(KD)));
@@ -5254,153 +5239,296 @@ ASTContext::getPredefinedSugarType(PredefinedSugarType::Kind KD) const {
return QualType(New, 0);
}
-#ifndef NDEBUG
-static bool NeedsInjectedClassNameType(const RecordDecl *D) {
- if (!isa<CXXRecordDecl>(D)) return false;
- const auto *RD = cast<CXXRecordDecl>(D);
- if (isa<ClassTemplatePartialSpecializationDecl>(RD))
- return true;
- if (RD->getDescribedClassTemplate() &&
- !isa<ClassTemplateSpecializationDecl>(RD))
- return true;
- return false;
-}
-#endif
+QualType ASTContext::getTypeDeclType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const TypeDecl *Decl) const {
+ if (auto *Tag = dyn_cast<TagDecl>(Decl))
+ return getTagType(Keyword, Qualifier, Tag,
+ /*OwnsTag=*/false);
+ if (auto *Typedef = dyn_cast<TypedefNameDecl>(Decl))
+ return getTypedefType(Keyword, Qualifier, Typedef);
+ if (auto *UD = dyn_cast<UnresolvedUsingTypenameDecl>(Decl))
+ return getUnresolvedUsingType(Keyword, Qualifier, UD);
-/// getInjectedClassNameType - Return the unique reference to the
-/// injected class name type for the specified templated declaration.
-QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl,
- QualType TST) const {
- assert(NeedsInjectedClassNameType(Decl));
- if (Decl->TypeForDecl) {
- assert(isa<InjectedClassNameType>(Decl->TypeForDecl));
- } else if (CXXRecordDecl *PrevDecl = Decl->getPreviousDecl()) {
- assert(PrevDecl->TypeForDecl && "previous declaration has no type");
- Decl->TypeForDecl = PrevDecl->TypeForDecl;
- assert(isa<InjectedClassNameType>(Decl->TypeForDecl));
- } else {
- Type *newType = new (*this, alignof(InjectedClassNameType))
- InjectedClassNameType(Decl, TST);
- Decl->TypeForDecl = newType;
- Types.push_back(newType);
- }
+ assert(Keyword == ElaboratedTypeKeyword::None);
+ assert(!Qualifier);
return QualType(Decl->TypeForDecl, 0);
}
-/// getTypeDeclType - Return the unique reference to the type for the
-/// specified type declaration.
-QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
- assert(Decl && "Passed null for Decl param");
- assert(!Decl->TypeForDecl && "TypeForDecl present in slow case");
-
- if (const auto *Typedef = dyn_cast<TypedefNameDecl>(Decl))
- return getTypedefType(Typedef);
-
- assert(!isa<TemplateTypeParmDecl>(Decl) &&
- "Template type parameter types are always available.");
-
- if (const auto *Record = dyn_cast<RecordDecl>(Decl)) {
- assert(Record->isFirstDecl() && "struct/union has previous declaration");
- assert(!NeedsInjectedClassNameType(Record));
- return getRecordType(Record);
- } else if (const auto *Enum = dyn_cast<EnumDecl>(Decl)) {
- assert(Enum->isFirstDecl() && "enum has previous declaration");
- return getEnumType(Enum);
- } else if (const auto *Using = dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) {
- return getUnresolvedUsingType(Using);
- } else
- llvm_unreachable("TypeDecl without a type?");
-
+CanQualType ASTContext::getCanonicalTypeDeclType(const TypeDecl *TD) const {
+ if (auto *Tag = dyn_cast<TagDecl>(TD))
+ return getCanonicalTagType(Tag);
+ if (auto *TN = dyn_cast<TypedefNameDecl>(TD))
+ return getCanonicalType(TN->getUnderlyingType());
+ if (const auto *UD = dyn_cast<UnresolvedUsingTypenameDecl>(TD))
+ return getCanonicalUnresolvedUsingType(UD);
+ assert(TD->TypeForDecl);
+ return TD->TypeForDecl->getCanonicalTypeUnqualified();
+}
+
+QualType ASTContext::getTypeDeclType(const TypeDecl *Decl) const {
+ if (const auto *TD = dyn_cast<TagDecl>(Decl))
+ return getCanonicalTagType(TD);
+ if (const auto *TD = dyn_cast<TypedefNameDecl>(Decl);
+ isa_and_nonnull<TypedefDecl, TypeAliasDecl>(TD))
+ return getTypedefType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, TD);
+ if (const auto *Using = dyn_cast<UnresolvedUsingTypenameDecl>(Decl))
+ return getCanonicalUnresolvedUsingType(Using);
+
+ assert(Decl->TypeForDecl);
return QualType(Decl->TypeForDecl, 0);
}
/// getTypedefType - Return the unique reference to the type for the
/// specified typedef name decl.
-QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl,
- QualType Underlying) const {
- if (!Decl->TypeForDecl) {
- if (Underlying.isNull())
- Underlying = Decl->getUnderlyingType();
- auto *NewType = new (*this, alignof(TypedefType)) TypedefType(
- Type::Typedef, Decl, Underlying, /*HasTypeDifferentFromDecl=*/false);
- Decl->TypeForDecl = NewType;
+QualType
+ASTContext::getTypedefType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const TypedefNameDecl *Decl, QualType UnderlyingType,
+ std::optional<bool> TypeMatchesDeclOrNone) const {
+ if (!TypeMatchesDeclOrNone) {
+ QualType DeclUnderlyingType = Decl->getUnderlyingType();
+ assert(!DeclUnderlyingType.isNull());
+ if (UnderlyingType.isNull())
+ UnderlyingType = DeclUnderlyingType;
+ else
+ assert(hasSameType(UnderlyingType, DeclUnderlyingType));
+ TypeMatchesDeclOrNone = UnderlyingType == DeclUnderlyingType;
+ } else {
+ // FIXME: This is a workaround for a serialization cycle: assume the decl
+ // underlying type is not available; don't touch it.
+ assert(!UnderlyingType.isNull());
+ }
+
+ if (Keyword == ElaboratedTypeKeyword::None && !Qualifier &&
+ *TypeMatchesDeclOrNone) {
+ if (Decl->TypeForDecl)
+ return QualType(Decl->TypeForDecl, 0);
+
+ auto *NewType = new (*this, alignof(TypedefType))
+ TypedefType(Type::Typedef, Keyword, Qualifier, Decl, UnderlyingType,
+ !*TypeMatchesDeclOrNone);
+
Types.push_back(NewType);
+ Decl->TypeForDecl = NewType;
return QualType(NewType, 0);
}
- if (Underlying.isNull() || Decl->getUnderlyingType() == Underlying)
- return QualType(Decl->TypeForDecl, 0);
- assert(hasSameType(Decl->getUnderlyingType(), Underlying));
llvm::FoldingSetNodeID ID;
- TypedefType::Profile(ID, Decl, Underlying);
+ TypedefType::Profile(ID, Keyword, Qualifier, Decl, UnderlyingType);
void *InsertPos = nullptr;
- if (TypedefType *T = TypedefTypes.FindNodeOrInsertPos(ID, InsertPos)) {
- assert(!T->typeMatchesDecl() &&
- "non-divergent case should be handled with TypeDecl");
- return QualType(T, 0);
- }
+ if (FoldingSetPlaceholder<TypedefType> *Placeholder =
+ TypedefTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(Placeholder->getType(), 0);
- void *Mem = Allocate(TypedefType::totalSizeToAlloc<QualType>(true),
- alignof(TypedefType));
- auto *NewType = new (Mem) TypedefType(Type::Typedef, Decl, Underlying,
- /*HasTypeDifferentFromDecl=*/true);
- TypedefTypes.InsertNode(NewType, InsertPos);
+ void *Mem =
+ Allocate(TypedefType::totalSizeToAlloc<FoldingSetPlaceholder<TypedefType>,
+ NestedNameSpecifier, QualType>(
+ 1, !!Qualifier, !*TypeMatchesDeclOrNone),
+ alignof(TypedefType));
+ auto *NewType =
+ new (Mem) TypedefType(Type::Typedef, Keyword, Qualifier, Decl,
+ UnderlyingType, !*TypeMatchesDeclOrNone);
+ auto *Placeholder = new (NewType->getFoldingSetPlaceholder())
+ FoldingSetPlaceholder<TypedefType>();
+ TypedefTypes.InsertNode(Placeholder, InsertPos);
Types.push_back(NewType);
return QualType(NewType, 0);
}
-QualType ASTContext::getUsingType(const UsingShadowDecl *Found,
- QualType Underlying) const {
+QualType ASTContext::getUsingType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const UsingShadowDecl *D,
+ QualType UnderlyingType) const {
+ // FIXME: This is expensive to compute every time!
+ if (UnderlyingType.isNull()) {
+ const auto *UD = cast<UsingDecl>(D->getIntroducer());
+ UnderlyingType =
+ getTypeDeclType(UD->hasTypename() ? ElaboratedTypeKeyword::Typename
+ : ElaboratedTypeKeyword::None,
+ UD->getQualifier(), cast<TypeDecl>(D->getTargetDecl()));
+ }
+
llvm::FoldingSetNodeID ID;
- UsingType::Profile(ID, Found, Underlying);
+ UsingType::Profile(ID, Keyword, Qualifier, D, UnderlyingType);
void *InsertPos = nullptr;
- if (UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos))
+ if (const UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(T, 0);
- const Type *TypeForDecl =
- cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl();
+ assert(!UnderlyingType.hasLocalQualifiers());
- assert(!Underlying.hasLocalQualifiers());
- QualType Canon = Underlying->getCanonicalTypeInternal();
- assert(TypeForDecl->getCanonicalTypeInternal() == Canon);
+ assert(
+ hasSameType(getCanonicalTypeDeclType(cast<TypeDecl>(D->getTargetDecl())),
+ UnderlyingType));
- if (Underlying.getTypePtr() == TypeForDecl)
- Underlying = QualType();
void *Mem =
- Allocate(UsingType::totalSizeToAlloc<QualType>(!Underlying.isNull()),
+ Allocate(UsingType::totalSizeToAlloc<NestedNameSpecifier>(!!Qualifier),
alignof(UsingType));
- UsingType *NewType = new (Mem) UsingType(Found, Underlying, Canon);
- Types.push_back(NewType);
- UsingTypes.InsertNode(NewType, InsertPos);
- return QualType(NewType, 0);
+ UsingType *T = new (Mem) UsingType(Keyword, Qualifier, D, UnderlyingType);
+ Types.push_back(T);
+ UsingTypes.InsertNode(T, InsertPos);
+ return QualType(T, 0);
}
-QualType ASTContext::getRecordType(const RecordDecl *Decl) const {
- if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
+TagType *ASTContext::getTagTypeInternal(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const TagDecl *TD, bool OwnsTag,
+ bool IsInjected,
+ const Type *CanonicalType,
+ bool WithFoldingSetNode) const {
+ auto [TC, Size] = [&] {
+ switch (TD->getDeclKind()) {
+ case Decl::Enum:
+ static_assert(alignof(EnumType) == alignof(TagType));
+ return std::make_tuple(Type::Enum, sizeof(EnumType));
+ case Decl::ClassTemplatePartialSpecialization:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::CXXRecord:
+ static_assert(alignof(RecordType) == alignof(TagType));
+ static_assert(alignof(InjectedClassNameType) == alignof(TagType));
+ if (cast<CXXRecordDecl>(TD)->hasInjectedClassType())
+ return std::make_tuple(Type::InjectedClassName,
+ sizeof(InjectedClassNameType));
+ [[fallthrough]];
+ case Decl::Record:
+ return std::make_tuple(Type::Record, sizeof(RecordType));
+ default:
+ llvm_unreachable("unexpected decl kind");
+ }
+ }();
- if (const RecordDecl *PrevDecl = Decl->getPreviousDecl())
- if (PrevDecl->TypeForDecl)
- return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0);
+ if (Qualifier) {
+ static_assert(alignof(NestedNameSpecifier) <= alignof(TagType));
+ Size = llvm::alignTo(Size, alignof(NestedNameSpecifier)) +
+ sizeof(NestedNameSpecifier);
+ }
+ void *Mem;
+ if (WithFoldingSetNode) {
+ // FIXME: It would be more profitable to tail allocate the folding set node
+ // from the type, instead of the other way around, due to the greater
+ // alignment requirements of the type. But this makes it harder to deal with
+ // the different type node sizes. This would require either uniquing from
+ // different folding sets, or having the folding setaccept a
+ // contextual parameter which is not fixed at construction.
+ Mem = Allocate(
+ sizeof(TagTypeFoldingSetPlaceholder) +
+ TagTypeFoldingSetPlaceholder::getOffset() + Size,
+ std::max(alignof(TagTypeFoldingSetPlaceholder), alignof(TagType)));
+ auto *T = new (Mem) TagTypeFoldingSetPlaceholder();
+ Mem = T->getTagType();
+ } else {
+ Mem = Allocate(Size, alignof(TagType));
+ }
+
+ auto *T = [&, TC = TC]() -> TagType * {
+ switch (TC) {
+ case Type::Enum: {
+ assert(isa<EnumDecl>(TD));
+ auto *T = new (Mem) EnumType(TC, Keyword, Qualifier, TD, OwnsTag,
+ IsInjected, CanonicalType);
+ assert(reinterpret_cast<void *>(T) ==
+ reinterpret_cast<void *>(static_cast<TagType *>(T)) &&
+ "TagType must be the first base of EnumType");
+ return T;
+ }
+ case Type::Record: {
+ assert(isa<RecordDecl>(TD));
+ auto *T = new (Mem) RecordType(TC, Keyword, Qualifier, TD, OwnsTag,
+ IsInjected, CanonicalType);
+ assert(reinterpret_cast<void *>(T) ==
+ reinterpret_cast<void *>(static_cast<TagType *>(T)) &&
+ "TagType must be the first base of RecordType");
+ return T;
+ }
+ case Type::InjectedClassName: {
+ auto *T = new (Mem) InjectedClassNameType(Keyword, Qualifier, TD,
+ IsInjected, CanonicalType);
+ assert(reinterpret_cast<void *>(T) ==
+ reinterpret_cast<void *>(static_cast<TagType *>(T)) &&
+ "TagType must be the first base of InjectedClassNameType");
+ return T;
+ }
+ default:
+ llvm_unreachable("unexpected type class");
+ }
+ }();
+ assert(T->getKeyword() == Keyword);
+ assert(T->getQualifier() == Qualifier);
+ assert(T->getOriginalDecl() == TD);
+ assert(T->isInjected() == IsInjected);
+ assert(T->isTagOwned() == OwnsTag);
+ assert((T->isCanonicalUnqualified()
+ ? QualType()
+ : T->getCanonicalTypeInternal()) == QualType(CanonicalType, 0));
+ Types.push_back(T);
+ return T;
+}
- auto *newType = new (*this, alignof(RecordType)) RecordType(Decl);
- Decl->TypeForDecl = newType;
- Types.push_back(newType);
- return QualType(newType, 0);
+static const TagDecl *getNonInjectedClassName(const TagDecl *TD) {
+ if (const auto *RD = dyn_cast<CXXRecordDecl>(TD);
+ RD && RD->isInjectedClassName())
+ return cast<TagDecl>(RD->getDeclContext());
+ return TD;
}
-QualType ASTContext::getEnumType(const EnumDecl *Decl) const {
- if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
+CanQualType ASTContext::getCanonicalTagType(const TagDecl *TD) const {
+ TD = ::getNonInjectedClassName(TD)->getCanonicalDecl();
+ if (TD->TypeForDecl)
+ return TD->TypeForDecl->getCanonicalTypeUnqualified();
- if (const EnumDecl *PrevDecl = Decl->getPreviousDecl())
- if (PrevDecl->TypeForDecl)
- return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0);
+ const Type *CanonicalType = getTagTypeInternal(
+ ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, TD,
+ /*OwnsTag=*/false, /*IsInjected=*/false, /*CanonicalType=*/nullptr,
+ /*WithFoldingSetNode=*/false);
+ TD->TypeForDecl = CanonicalType;
+ return CanQualType::CreateUnsafe(QualType(CanonicalType, 0));
+}
- auto *newType = new (*this, alignof(EnumType)) EnumType(Decl);
- Decl->TypeForDecl = newType;
- Types.push_back(newType);
- return QualType(newType, 0);
+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(
+ NonInjectedTD->getTagKind());
+
+ if (Keyword == PreferredKeyword && !Qualifier && !OwnsTag) {
+ if (const Type *T = TD->TypeForDecl; T && !T->isCanonicalUnqualified())
+ return QualType(T, 0);
+
+ const Type *CanonicalType = getCanonicalTagType(NonInjectedTD).getTypePtr();
+ const Type *T =
+ getTagTypeInternal(Keyword,
+ /*Qualifier=*/std::nullopt, NonInjectedTD,
+ /*OwnsTag=*/false, IsInjected, CanonicalType,
+ /*WithFoldingSetNode=*/false);
+ TD->TypeForDecl = T;
+ return QualType(T, 0);
+ }
+
+ llvm::FoldingSetNodeID ID;
+ 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(NonInjectedTD).getTypePtr();
+ TagType *T =
+ getTagTypeInternal(Keyword, Qualifier, NonInjectedTD, OwnsTag, IsInjected,
+ CanonicalType, /*WithFoldingSetNode=*/true);
+ TagTypes.InsertNode(TagTypeFoldingSetPlaceholder::fromTagType(T), InsertPos);
+ return QualType(T, 0);
}
bool ASTContext::computeBestEnumTypes(bool IsPacked, unsigned NumNegativeBits,
@@ -5495,21 +5623,69 @@ bool ASTContext::isRepresentableIntegerValue(llvm::APSInt &Value, QualType T) {
return Value.getSignificantBits() <= BitWidth;
}
-QualType ASTContext::getUnresolvedUsingType(
- const UnresolvedUsingTypenameDecl *Decl) const {
- if (Decl->TypeForDecl)
- return QualType(Decl->TypeForDecl, 0);
+UnresolvedUsingType *ASTContext::getUnresolvedUsingTypeInternal(
+ ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier,
+ const UnresolvedUsingTypenameDecl *D, void *InsertPos,
+ const Type *CanonicalType) const {
+ void *Mem = Allocate(
+ UnresolvedUsingType::totalSizeToAlloc<
+ FoldingSetPlaceholder<UnresolvedUsingType>, NestedNameSpecifier>(
+ !!InsertPos, !!Qualifier),
+ alignof(UnresolvedUsingType));
+ auto *T = new (Mem) UnresolvedUsingType(Keyword, Qualifier, D, CanonicalType);
+ if (InsertPos) {
+ auto *Placeholder = new (T->getFoldingSetPlaceholder())
+ FoldingSetPlaceholder<TypedefType>();
+ TypedefTypes.InsertNode(Placeholder, InsertPos);
+ }
+ Types.push_back(T);
+ return T;
+}
- if (const UnresolvedUsingTypenameDecl *CanonicalDecl =
- Decl->getCanonicalDecl())
- if (CanonicalDecl->TypeForDecl)
- return QualType(Decl->TypeForDecl = CanonicalDecl->TypeForDecl, 0);
+CanQualType ASTContext::getCanonicalUnresolvedUsingType(
+ const UnresolvedUsingTypenameDecl *D) const {
+ D = D->getCanonicalDecl();
+ if (D->TypeForDecl)
+ return D->TypeForDecl->getCanonicalTypeUnqualified();
- Type *newType =
- new (*this, alignof(UnresolvedUsingType)) UnresolvedUsingType(Decl);
- Decl->TypeForDecl = newType;
- Types.push_back(newType);
- return QualType(newType, 0);
+ const Type *CanonicalType = getUnresolvedUsingTypeInternal(
+ ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, D,
+ /*InsertPos=*/nullptr, /*CanonicalType=*/nullptr);
+ D->TypeForDecl = CanonicalType;
+ return CanQualType::CreateUnsafe(QualType(CanonicalType, 0));
+}
+
+QualType
+ASTContext::getUnresolvedUsingType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const UnresolvedUsingTypenameDecl *D) const {
+ if (Keyword == ElaboratedTypeKeyword::None && !Qualifier) {
+ if (const Type *T = D->TypeForDecl; T && !T->isCanonicalUnqualified())
+ return QualType(T, 0);
+
+ const Type *CanonicalType = getCanonicalUnresolvedUsingType(D).getTypePtr();
+ const Type *T =
+ getUnresolvedUsingTypeInternal(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, D,
+ /*InsertPos=*/nullptr, CanonicalType);
+ D->TypeForDecl = T;
+ return QualType(T, 0);
+ }
+
+ llvm::FoldingSetNodeID ID;
+ UnresolvedUsingType::Profile(ID, Keyword, Qualifier, D);
+
+ void *InsertPos = nullptr;
+ if (FoldingSetPlaceholder<UnresolvedUsingType> *Placeholder =
+ UnresolvedUsingTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(Placeholder->getType(), 0);
+ assert(InsertPos);
+
+ const Type *CanonicalType = getCanonicalUnresolvedUsingType(D).getTypePtr();
+ const Type *T = getUnresolvedUsingTypeInternal(Keyword, Qualifier, D,
+ InsertPos, CanonicalType);
+ return QualType(T, 0);
}
QualType ASTContext::getAttributedType(attr::Kind attrKind,
@@ -5655,7 +5831,6 @@ QualType ASTContext::getSubstTemplateTypeParmType(QualType Replacement,
return QualType(SubstParm, 0);
}
-/// Retrieve a
QualType
ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
unsigned Index, bool Final,
@@ -5694,6 +5869,34 @@ ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
return QualType(SubstParm, 0);
}
+QualType
+ASTContext::getSubstBuiltinTemplatePack(const TemplateArgument &ArgPack) {
+ assert(llvm::all_of(ArgPack.pack_elements(),
+ [](const auto &P) {
+ return P.getKind() == TemplateArgument::Type;
+ }) &&
+ "Pack contains a non-type");
+
+ llvm::FoldingSetNodeID ID;
+ SubstBuiltinTemplatePackType::Profile(ID, ArgPack);
+
+ void *InsertPos = nullptr;
+ if (auto *T =
+ SubstBuiltinTemplatePackTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(T, 0);
+
+ QualType Canon;
+ TemplateArgument CanonArgPack = getCanonicalTemplateArgument(ArgPack);
+ if (!CanonArgPack.structurallyEquals(ArgPack))
+ Canon = getSubstBuiltinTemplatePack(CanonArgPack);
+
+ auto *PackType = new (*this, alignof(SubstBuiltinTemplatePackType))
+ SubstBuiltinTemplatePackType(Canon, ArgPack);
+ Types.push_back(PackType);
+ SubstBuiltinTemplatePackTypes.InsertNode(PackType, InsertPos);
+ return QualType(PackType, 0);
+}
+
/// Retrieve the template type parameter type for a template
/// parameter or parameter pack with the given depth, index, and (optionally)
/// name.
@@ -5729,34 +5932,32 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
}
TypeSourceInfo *ASTContext::getTemplateSpecializationTypeInfo(
+ ElaboratedTypeKeyword Keyword, SourceLocation ElaboratedKeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKeywordLoc,
TemplateName Name, SourceLocation NameLoc,
const TemplateArgumentListInfo &SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
- QualType TST = getTemplateSpecializationType(Name, SpecifiedArgs.arguments(),
- CanonicalArgs, Underlying);
+ QualType TST = getTemplateSpecializationType(
+ Keyword, Name, SpecifiedArgs.arguments(), CanonicalArgs, Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
- TemplateSpecializationTypeLoc TL =
- DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>();
- TL.setTemplateKeywordLoc(SourceLocation());
- TL.setTemplateNameLoc(NameLoc);
- TL.setLAngleLoc(SpecifiedArgs.getLAngleLoc());
- TL.setRAngleLoc(SpecifiedArgs.getRAngleLoc());
- for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
- TL.setArgLocInfo(i, SpecifiedArgs[i].getLocInfo());
+ DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>().set(
+ ElaboratedKeywordLoc, QualifierLoc, TemplateKeywordLoc, NameLoc,
+ SpecifiedArgs);
return DI;
}
QualType ASTContext::getTemplateSpecializationType(
- TemplateName Template, ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
+ ElaboratedTypeKeyword Keyword, TemplateName Template,
+ ArrayRef<TemplateArgumentLoc> SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
SmallVector<TemplateArgument, 4> SpecifiedArgVec;
SpecifiedArgVec.reserve(SpecifiedArgs.size());
for (const TemplateArgumentLoc &Arg : SpecifiedArgs)
SpecifiedArgVec.push_back(Arg.getArgument());
- return getTemplateSpecializationType(Template, SpecifiedArgVec, CanonicalArgs,
- Underlying);
+ return getTemplateSpecializationType(Keyword, Template, SpecifiedArgVec,
+ CanonicalArgs, Underlying);
}
[[maybe_unused]] static bool
@@ -5787,7 +5988,8 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
sizeof(TemplateArgument) * Args.size(),
alignof(TemplateSpecializationType));
auto *Spec = new (Mem)
- TemplateSpecializationType(Template, /*IsAlias=*/false, Args, QualType());
+ TemplateSpecializationType(ElaboratedTypeKeyword::None, Template,
+ /*IsAlias=*/false, Args, QualType());
assert(Spec->isDependentType() &&
"canonical template specialization must be dependent");
Types.push_back(Spec);
@@ -5796,7 +5998,8 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
}
QualType ASTContext::getTemplateSpecializationType(
- TemplateName Template, ArrayRef<TemplateArgument> SpecifiedArgs,
+ ElaboratedTypeKeyword Keyword, TemplateName Template,
+ ArrayRef<TemplateArgument> SpecifiedArgs,
ArrayRef<TemplateArgument> CanonicalArgs, QualType Underlying) const {
assert(!Template.getUnderlying().getAsDependentTemplateName() &&
"No dependent template names here!");
@@ -5806,7 +6009,8 @@ QualType ASTContext::getTemplateSpecializationType(
if (Underlying.isNull()) {
TemplateName CanonTemplate =
getCanonicalTemplateName(Template, /*IgnoreDeduced=*/true);
- bool NonCanonical = Template != CanonTemplate;
+ bool NonCanonical =
+ Template != CanonTemplate || Keyword != ElaboratedTypeKeyword::None;
SmallVector<TemplateArgument, 4> CanonArgsVec;
if (CanonicalArgs.empty()) {
CanonArgsVec = SmallVector<TemplateArgument, 4>(SpecifiedArgs);
@@ -5837,42 +6041,12 @@ QualType ASTContext::getTemplateSpecializationType(
sizeof(TemplateArgument) * SpecifiedArgs.size() +
(IsTypeAlias ? sizeof(QualType) : 0),
alignof(TemplateSpecializationType));
- auto *Spec = new (Mem) TemplateSpecializationType(Template, IsTypeAlias,
- SpecifiedArgs, Underlying);
+ auto *Spec = new (Mem) TemplateSpecializationType(
+ Keyword, Template, IsTypeAlias, SpecifiedArgs, Underlying);
Types.push_back(Spec);
return QualType(Spec, 0);
}
-QualType ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS,
- QualType NamedType,
- TagDecl *OwnedTagDecl) const {
- llvm::FoldingSetNodeID ID;
- ElaboratedType::Profile(ID, Keyword, NNS, NamedType, OwnedTagDecl);
-
- void *InsertPos = nullptr;
- ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
- if (T)
- return QualType(T, 0);
-
- QualType Canon = NamedType;
- if (!Canon.isCanonical()) {
- Canon = getCanonicalType(NamedType);
- ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(!CheckT && "Elaborated canonical type broken");
- (void)CheckT;
- }
-
- void *Mem =
- Allocate(ElaboratedType::totalSizeToAlloc<TagDecl *>(!!OwnedTagDecl),
- alignof(ElaboratedType));
- T = new (Mem) ElaboratedType(Keyword, NNS, NamedType, Canon, OwnedTagDecl);
-
- Types.push_back(T);
- ElaboratedTypes.InsertNode(T, InsertPos);
- return QualType(T, 0);
-}
-
QualType
ASTContext::getParenType(QualType InnerType) const {
llvm::FoldingSetNodeID ID;
@@ -5935,7 +6109,7 @@ getCanonicalElaboratedTypeKeyword(ElaboratedTypeKeyword Keyword) {
}
QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS,
+ NestedNameSpecifier NNS,
const IdentifierInfo *Name) const {
llvm::FoldingSetNodeID ID;
DependentNameType::Profile(ID, Keyword, NNS, Name);
@@ -5947,7 +6121,7 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
ElaboratedTypeKeyword CanonKeyword =
getCanonicalElaboratedTypeKeyword(Keyword);
- NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
+ NestedNameSpecifier CanonNNS = NNS.getCanonical();
QualType Canon;
if (CanonKeyword != Keyword || CanonNNS != NNS) {
@@ -5985,13 +6159,13 @@ QualType ASTContext::getDependentTemplateSpecializationType(
T_iter != DependentTemplateSpecializationTypes.end())
return QualType(T_iter->getSecond(), 0);
- NestedNameSpecifier *NNS = Name.getQualifier();
+ NestedNameSpecifier NNS = Name.getQualifier();
QualType Canon;
if (!IsCanonical) {
ElaboratedTypeKeyword CanonKeyword =
getCanonicalElaboratedTypeKeyword(Keyword);
- NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
+ NestedNameSpecifier CanonNNS = NNS.getCanonical();
bool AnyNonCanonArgs = false;
auto CanonArgs =
::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs);
@@ -6006,7 +6180,7 @@ QualType ASTContext::getDependentTemplateSpecializationType(
} else {
assert(Keyword == getCanonicalElaboratedTypeKeyword(Keyword));
assert(Name.hasTemplateKeyword());
- assert(NNS == getCanonicalNestedNameSpecifier(NNS));
+ assert(NNS.isCanonical());
#ifndef NDEBUG
for (const auto &Arg : Args)
assert(Arg.structurallyEquals(getCanonicalTemplateArgument(Arg)));
@@ -6062,7 +6236,8 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) const {
} else {
auto *TTP = cast<TemplateTemplateParmDecl>(Param);
TemplateName Name = getQualifiedTemplateName(
- nullptr, /*TemplateKeyword=*/false, TemplateName(TTP));
+ /*Qualifier=*/std::nullopt, /*TemplateKeyword=*/false,
+ TemplateName(TTP));
if (TTP->isParameterPack())
Arg = TemplateArgument(Name, /*NumExpansions=*/std::nullopt);
else
@@ -6334,11 +6509,11 @@ void ASTContext::adjustObjCTypeParamBoundType(const ObjCTypeParamDecl *Orig,
ObjCTypeParamDecl *New) const {
New->setTypeSourceInfo(getTrivialTypeSourceInfo(Orig->getUnderlyingType()));
// Update TypeForDecl after updating TypeSourceInfo.
- auto NewTypeParamTy = cast<ObjCTypeParamType>(New->getTypeForDecl());
+ auto *NewTypeParamTy = cast<ObjCTypeParamType>(New->TypeForDecl);
SmallVector<ObjCProtocolDecl *, 8> protocols;
protocols.append(NewTypeParamTy->qual_begin(), NewTypeParamTy->qual_end());
QualType UpdatedTy = getObjCTypeParamType(New, protocols);
- New->setTypeForDecl(UpdatedTy.getTypePtr());
+ New->TypeForDecl = UpdatedTy.getTypePtr();
}
/// ObjCObjectAdoptsQTypeProtocols - Checks that protocols in IC's
@@ -6737,20 +6912,20 @@ QualType ASTContext::getUnconstrainedType(QualType T) const {
}
QualType ASTContext::getDeducedTemplateSpecializationTypeInternal(
- TemplateName Template, QualType DeducedType, bool IsDependent,
- QualType Canon) const {
+ ElaboratedTypeKeyword Keyword, TemplateName Template, QualType DeducedType,
+ bool IsDependent, QualType Canon) const {
// Look in the folding set for an existing type.
void *InsertPos = nullptr;
llvm::FoldingSetNodeID ID;
- DeducedTemplateSpecializationType::Profile(ID, Template, DeducedType,
+ DeducedTemplateSpecializationType::Profile(ID, Keyword, Template, DeducedType,
IsDependent);
if (DeducedTemplateSpecializationType *DTST =
DeducedTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(DTST, 0);
auto *DTST = new (*this, alignof(DeducedTemplateSpecializationType))
- DeducedTemplateSpecializationType(Template, DeducedType, IsDependent,
- Canon);
+ DeducedTemplateSpecializationType(Keyword, Template, DeducedType,
+ IsDependent, Canon);
#ifndef NDEBUG
llvm::FoldingSetNodeID TempID;
@@ -6766,14 +6941,20 @@ QualType ASTContext::getDeducedTemplateSpecializationTypeInternal(
/// which has been deduced to the given type, or to the canonical undeduced
/// such type, or the canonical deduced-but-dependent such type.
QualType ASTContext::getDeducedTemplateSpecializationType(
- TemplateName Template, QualType DeducedType, bool IsDependent) const {
- QualType Canon = DeducedType.isNull()
- ? getDeducedTemplateSpecializationTypeInternal(
- getCanonicalTemplateName(Template), QualType(),
- IsDependent, QualType())
- : DeducedType.getCanonicalType();
- return getDeducedTemplateSpecializationTypeInternal(Template, DeducedType,
- IsDependent, Canon);
+ ElaboratedTypeKeyword Keyword, TemplateName Template, QualType DeducedType,
+ bool IsDependent) const {
+ // FIXME: This could save an extra hash table lookup if it handled all the
+ // parameters already being canonical.
+ // FIXME: Can this be formed from a DependentTemplateName, such that the
+ // keyword should be part of the canonical type?
+ QualType Canon =
+ DeducedType.isNull()
+ ? getDeducedTemplateSpecializationTypeInternal(
+ ElaboratedTypeKeyword::None, getCanonicalTemplateName(Template),
+ QualType(), IsDependent, QualType())
+ : DeducedType.getCanonicalType();
+ return getDeducedTemplateSpecializationTypeInternal(
+ Keyword, Template, DeducedType, IsDependent, Canon);
}
/// getAtomicType - Return the uniqued reference to the atomic type for
@@ -6823,15 +7004,6 @@ QualType ASTContext::getAutoRRefDeductType() const {
return AutoRRefDeductTy;
}
-/// getTagDeclType - Return the unique reference to the type for the
-/// specified TagDecl (struct/union/class/enum) decl.
-QualType ASTContext::getTagDeclType(const TagDecl *Decl) const {
- assert(Decl);
- // FIXME: What is the design on getTagDeclType when it requires casting
- // away const? mutable?
- return getTypeDeclType(const_cast<TagDecl*>(Decl));
-}
-
/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result
/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and
/// needs to agree with the definition in <stddef.h>.
@@ -7053,8 +7225,8 @@ bool ASTContext::UnwrapSimilarTypes(QualType &T1, QualType &T2,
*RD2 = T2MPType->getMostRecentCXXRecordDecl();
RD1 != RD2 && RD1->getCanonicalDecl() != RD2->getCanonicalDecl())
return false;
- if (getCanonicalNestedNameSpecifier(T1MPType->getQualifier()) !=
- getCanonicalNestedNameSpecifier(T2MPType->getQualifier()))
+ if (T1MPType->getQualifier().getCanonical() !=
+ T2MPType->getQualifier().getCanonical())
return false;
T1 = T1MPType->getPointeeType();
T2 = T2MPType->getPointeeType();
@@ -7211,9 +7383,8 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name,
case TemplateName::DependentTemplate: {
DependentTemplateName *DTN = Name.getAsDependentTemplateName();
assert(DTN && "Non-dependent template names must refer to template decls.");
- NestedNameSpecifier *Qualifier = DTN->getQualifier();
- NestedNameSpecifier *CanonQualifier =
- getCanonicalNestedNameSpecifier(Qualifier);
+ NestedNameSpecifier Qualifier = DTN->getQualifier();
+ NestedNameSpecifier CanonQualifier = Qualifier.getCanonical();
if (Qualifier != CanonQualifier || !DTN->hasTemplateKeyword())
return getDependentTemplateName({CanonQualifier, DTN->getName(),
/*HasTemplateKeyword=*/true});
@@ -7430,38 +7601,40 @@ bool ASTContext::isSameDefaultTemplateArgument(const NamedDecl *X,
return hasSameTemplateName(TAX.getAsTemplate(), TAY.getAsTemplate());
}
-static bool isSameQualifier(const NestedNameSpecifier *X,
- const NestedNameSpecifier *Y) {
- if (X->getKind() != Y->getKind())
+static bool isSameQualifier(const NestedNameSpecifier X,
+ const NestedNameSpecifier Y) {
+ if (X == Y)
+ return true;
+ if (!X || !Y)
+ return false;
+
+ auto Kind = X.getKind();
+ if (Kind != Y.getKind())
return false;
// FIXME: For namespaces and types, we're permitted to check that the entity
// is named via the same tokens. We should probably do so.
- switch (X->getKind()) {
- case NestedNameSpecifier::Identifier:
- if (X->getAsIdentifier() != Y->getAsIdentifier())
- return false;
- break;
- case NestedNameSpecifier::Namespace:
- if (!declaresSameEntity(X->getAsNamespace(), Y->getAsNamespace()))
+ switch (Kind) {
+ case NestedNameSpecifier::Kind::Namespace: {
+ auto [NamespaceX, PrefixX] = X.getAsNamespaceAndPrefix();
+ auto [NamespaceY, PrefixY] = Y.getAsNamespaceAndPrefix();
+ if (!declaresSameEntity(NamespaceX->getNamespace(),
+ NamespaceY->getNamespace()))
return false;
- break;
- case NestedNameSpecifier::TypeSpec:
- if (X->getAsType()->getCanonicalTypeInternal() !=
- Y->getAsType()->getCanonicalTypeInternal())
+ return isSameQualifier(PrefixX, PrefixY);
+ }
+ case NestedNameSpecifier::Kind::Type: {
+ const auto *TX = X.getAsType(), *TY = Y.getAsType();
+ if (TX->getCanonicalTypeInternal() != TY->getCanonicalTypeInternal())
return false;
- break;
- case NestedNameSpecifier::Global:
- case NestedNameSpecifier::Super:
+ return isSameQualifier(TX->getPrefix(), TY->getPrefix());
+ }
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::Global:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
return true;
}
-
- // Recurse into earlier portion of NNS, if any.
- auto *PX = X->getPrefix();
- auto *PY = Y->getPrefix();
- if (PX && PY)
- return isSameQualifier(PX, PY);
- return !PX && !PY;
+ llvm_unreachable("unhandled qualifier kind");
}
static bool hasSameCudaAttrs(const FunctionDecl *A, const FunctionDecl *B) {
@@ -7854,63 +8027,6 @@ bool ASTContext::isSameTemplateArgument(const TemplateArgument &Arg1,
llvm_unreachable("Unhandled template argument kind");
}
-NestedNameSpecifier *
-ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
- if (!NNS)
- return nullptr;
-
- switch (NNS->getKind()) {
- case NestedNameSpecifier::Identifier:
- // Canonicalize the prefix but keep the identifier the same.
- return NestedNameSpecifier::Create(*this,
- getCanonicalNestedNameSpecifier(NNS->getPrefix()),
- NNS->getAsIdentifier());
-
- case NestedNameSpecifier::Namespace:
- // A namespace is canonical; build a nested-name-specifier with
- // this namespace and no prefix.
- return NestedNameSpecifier::Create(
- *this, nullptr, NNS->getAsNamespace()->getNamespace()->getFirstDecl());
-
- // The difference between TypeSpec and TypeSpecWithTemplate is that the
- // latter will have the 'template' keyword when printed.
- case NestedNameSpecifier::TypeSpec: {
- const Type *T = getCanonicalType(NNS->getAsType());
-
- // If we have some kind of dependent-named type (e.g., "typename T::type"),
- // break it apart into its prefix and identifier, then reconsititute those
- // as the canonical nested-name-specifier. This is required to canonicalize
- // a dependent nested-name-specifier involving typedefs of dependent-name
- // types, e.g.,
- // typedef typename T::type T1;
- // typedef typename T1::type T2;
- if (const auto *DNT = T->getAs<DependentNameType>())
- return NestedNameSpecifier::Create(*this, DNT->getQualifier(),
- DNT->getIdentifier());
- if (const auto *DTST = T->getAs<DependentTemplateSpecializationType>()) {
- const DependentTemplateStorage &DTN = DTST->getDependentTemplateName();
- QualType NewT = getDependentTemplateSpecializationType(
- ElaboratedTypeKeyword::None,
- {/*NNS=*/nullptr, DTN.getName(), /*HasTemplateKeyword=*/true},
- DTST->template_arguments(), /*IsCanonical=*/true);
- assert(NewT.isCanonical());
- NestedNameSpecifier *Prefix = DTN.getQualifier();
- if (!Prefix)
- Prefix = getCanonicalNestedNameSpecifier(NNS->getPrefix());
- return NestedNameSpecifier::Create(*this, Prefix, NewT.getTypePtr());
- }
- return NestedNameSpecifier::Create(*this, nullptr, T);
- }
-
- case NestedNameSpecifier::Global:
- case NestedNameSpecifier::Super:
- // The global specifier and __super specifer are canonical and unique.
- return NNS;
- }
-
- llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
-}
-
const ArrayType *ASTContext::getAsArrayType(QualType T) const {
// Handle the non-qualified case efficiently.
if (!T.hasLocalQualifiers()) {
@@ -8228,8 +8344,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->getDecl()->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
@@ -8288,8 +8404,9 @@ Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const {
static const Type *getIntegerTypeForEnum(const EnumType *ET) {
// Incomplete enum types are not treated as integer types.
// FIXME: In C++, enum types are never integer types.
- if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped())
- return ET->getDecl()->getIntegerType().getTypePtr();
+ const EnumDecl *ED = ET->getOriginalDecl()->getDefinitionOrSelf();
+ if (ED->isComplete() && !ED->isScoped())
+ return ED->getIntegerType().getTypePtr();
return nullptr;
}
@@ -8418,7 +8535,7 @@ TypedefDecl *ASTContext::getCFConstantStringDecl() const {
CFConstantStringTagDecl->completeDefinition();
// This type is designed to be compatible with NSConstantString, but cannot
// use the same name, since NSConstantString is an interface.
- auto tagType = getTagDeclType(CFConstantStringTagDecl);
+ CanQualType tagType = getCanonicalTagType(CFConstantStringTagDecl);
CFConstantStringTypeDecl =
buildImplicitTypedef(tagType, "__NSConstantString");
@@ -8433,28 +8550,28 @@ RecordDecl *ASTContext::getCFConstantStringTagDecl() const {
// getCFConstantStringType - Return the type used for constant CFStrings.
QualType ASTContext::getCFConstantStringType() const {
- return getTypedefType(getCFConstantStringDecl());
+ return getTypedefType(ElaboratedTypeKeyword::None, /*Qualifier=*/std::nullopt,
+ getCFConstantStringDecl());
}
QualType ASTContext::getObjCSuperType() const {
if (ObjCSuperType.isNull()) {
RecordDecl *ObjCSuperTypeDecl = buildImplicitRecord("objc_super");
getTranslationUnitDecl()->addDecl(ObjCSuperTypeDecl);
- ObjCSuperType = getTagDeclType(ObjCSuperTypeDecl);
+ ObjCSuperType = getCanonicalTagType(ObjCSuperTypeDecl);
}
return ObjCSuperType;
}
void ASTContext::setCFConstantStringType(QualType T) {
- const auto *TD = T->castAs<TypedefType>();
- CFConstantStringTypeDecl = cast<TypedefDecl>(TD->getDecl());
- const auto *TagType = TD->castAs<RecordType>();
- CFConstantStringTagDecl = TagType->getDecl();
+ const auto *TT = T->castAs<TypedefType>();
+ CFConstantStringTypeDecl = cast<TypedefDecl>(TT->getDecl());
+ CFConstantStringTagDecl = TT->castAsRecordDecl();
}
QualType ASTContext::getBlockDescriptorType() const {
if (BlockDescriptorType)
- return getTagDeclType(BlockDescriptorType);
+ return getCanonicalTagType(BlockDescriptorType);
RecordDecl *RD;
// FIXME: Needs the FlagAppleBlock bit.
@@ -8484,12 +8601,12 @@ QualType ASTContext::getBlockDescriptorType() const {
BlockDescriptorType = RD;
- return getTagDeclType(BlockDescriptorType);
+ return getCanonicalTagType(BlockDescriptorType);
}
QualType ASTContext::getBlockDescriptorExtendedType() const {
if (BlockDescriptorExtendedType)
- return getTagDeclType(BlockDescriptorExtendedType);
+ return getCanonicalTagType(BlockDescriptorExtendedType);
RecordDecl *RD;
// FIXME: Needs the FlagAppleBlock bit.
@@ -8523,7 +8640,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
RD->completeDefinition();
BlockDescriptorExtendedType = RD;
- return getTagDeclType(BlockDescriptorExtendedType);
+ return getCanonicalTagType(BlockDescriptorExtendedType);
}
OpenCLTypeKind ASTContext::getOpenCLTypeKind(const Type *T) const {
@@ -9160,8 +9277,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->getDecl();
+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())
@@ -9204,8 +9321,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);
@@ -9262,7 +9379,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:
@@ -9329,14 +9446,15 @@ 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 (RTy->getDecl()->getIdentifier() == &Idents.get("objc_class")) {
+ if (II == &Idents.get("objc_class")) {
S += '#';
return;
}
// GCC binary compat: Need to convert "struct objc_object *" to "@".
- if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_object")) {
+ if (II == &Idents.get("objc_object")) {
S += '@';
return;
}
@@ -9401,7 +9519,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
return;
case Type::Record: {
- RecordDecl *RDecl = cast<RecordType>(CT)->getDecl();
+ RecordDecl *RDecl = cast<RecordType>(CT)->getOriginalDecl();
S += RDecl->isUnion() ? '(' : '{';
// Anonymous structures print as '?'
if (const IdentifierInfo *II = RDecl->getIdentifier()) {
@@ -9900,7 +10018,7 @@ CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
}
VaListTagDecl->completeDefinition();
Context->VaListTagDecl = VaListTagDecl;
- QualType VaListTagType = Context->getRecordType(VaListTagDecl);
+ CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl);
// } __builtin_va_list;
return Context->buildImplicitTypedef(VaListTagType, "__builtin_va_list");
@@ -9952,14 +10070,15 @@ static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
}
VaListTagDecl->completeDefinition();
Context->VaListTagDecl = VaListTagDecl;
- QualType VaListTagType = Context->getRecordType(VaListTagDecl);
+ CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl);
// } __va_list_tag;
TypedefDecl *VaListTagTypedefDecl =
Context->buildImplicitTypedef(VaListTagType, "__va_list_tag");
QualType VaListTagTypedefType =
- Context->getTypedefType(VaListTagTypedefDecl);
+ Context->getTypedefType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, VaListTagTypedefDecl);
// typedef __va_list_tag __builtin_va_list[1];
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
@@ -10011,7 +10130,7 @@ CreateX86_64ABIBuiltinVaListDecl(const ASTContext *Context) {
}
VaListTagDecl->completeDefinition();
Context->VaListTagDecl = VaListTagDecl;
- QualType VaListTagType = Context->getRecordType(VaListTagDecl);
+ CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl);
// };
@@ -10059,7 +10178,7 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) {
Context->VaListTagDecl = VaListDecl;
// typedef struct __va_list __builtin_va_list;
- QualType T = Context->getRecordType(VaListDecl);
+ CanQualType T = Context->getCanonicalTagType(VaListDecl);
return Context->buildImplicitTypedef(T, "__builtin_va_list");
}
@@ -10106,7 +10225,7 @@ CreateSystemZBuiltinVaListDecl(const ASTContext *Context) {
}
VaListTagDecl->completeDefinition();
Context->VaListTagDecl = VaListTagDecl;
- QualType VaListTagType = Context->getRecordType(VaListTagDecl);
+ CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl);
// };
@@ -10153,13 +10272,15 @@ static TypedefDecl *CreateHexagonBuiltinVaListDecl(const ASTContext *Context) {
}
VaListTagDecl->completeDefinition();
Context->VaListTagDecl = VaListTagDecl;
- QualType VaListTagType = Context->getRecordType(VaListTagDecl);
+ CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl);
// } __va_list_tag;
TypedefDecl *VaListTagTypedefDecl =
Context->buildImplicitTypedef(VaListTagType, "__va_list_tag");
- QualType VaListTagTypedefType = Context->getTypedefType(VaListTagTypedefDecl);
+ QualType VaListTagTypedefType =
+ Context->getTypedefType(ElaboratedTypeKeyword::None,
+ /*Qualifier=*/std::nullopt, VaListTagTypedefDecl);
// typedef __va_list_tag __builtin_va_list[1];
llvm::APInt Size(Context->getTypeSize(Context->getSizeType()), 1);
@@ -10197,7 +10318,7 @@ CreateXtensaABIBuiltinVaListDecl(const ASTContext *Context) {
}
VaListTagDecl->completeDefinition();
Context->VaListTagDecl = VaListTagDecl;
- QualType VaListTagType = Context->getRecordType(VaListTagDecl);
+ CanQualType VaListTagType = Context->getCanonicalTagType(VaListTagDecl);
// } __va_list_tag;
TypedefDecl *VaListTagTypedefDecl =
@@ -10311,22 +10432,28 @@ TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const {
/// Retrieve the template name that represents a qualified
/// template name such as \c std::vector.
-TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
+TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier Qualifier,
bool TemplateKeyword,
TemplateName Template) const {
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, NNS, TemplateKeyword, Template);
+ QualifiedTemplateName::Profile(ID, Qualifier, TemplateKeyword, Template);
void *InsertPos = nullptr;
QualifiedTemplateName *QTN =
- QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+ QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
if (!QTN) {
QTN = new (*this, alignof(QualifiedTemplateName))
- QualifiedTemplateName(NNS, TemplateKeyword, Template);
+ QualifiedTemplateName(Qualifier, TemplateKeyword, Template);
QualifiedTemplateNames.InsertNode(QTN, InsertPos);
}
@@ -11296,7 +11423,7 @@ QualType ASTContext::mergeTransparentUnionType(QualType T, QualType SubType,
bool OfBlockPointer,
bool Unqualified) {
if (const RecordType *UT = T->getAsUnionType()) {
- RecordDecl *UD = UT->getDecl();
+ RecordDecl *UD = UT->getOriginalDecl()->getMostRecentDecl();
if (UD->hasAttr<TransparentUnionAttr>()) {
for (const auto *I : UD->fields()) {
QualType ET = I->getType().getUnqualifiedType();
@@ -11442,6 +11569,11 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lproto->getMethodQuals() != rproto->getMethodQuals())
return {};
+ // Function protos with different 'cfi_salt' values aren't compatible.
+ if (lproto->getExtraAttributeInfo().CFISalt !=
+ rproto->getExtraAttributeInfo().CFISalt)
+ return {};
+
// Function effects are handled similarly to noreturn, see above.
FunctionEffectsRef LHSFX = lproto->getFunctionEffects();
FunctionEffectsRef RHSFX = rproto->getFunctionEffects();
@@ -11527,8 +11659,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->getDecl()->getIntegerType();
+ if (const auto *ED = paramTy->getAsEnumDecl()) {
+ paramTy = ED->getIntegerType();
if (paramTy.isNull())
return {};
}
@@ -11560,7 +11692,8 @@ static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET,
// a signed integer type, or an unsigned integer type.
// Compatibility is based on the underlying type, not the promotion
// type.
- QualType underlyingType = ET->getDecl()->getIntegerType();
+ QualType underlyingType =
+ ET->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
if (underlyingType.isNull())
return {};
if (Context.hasSameType(underlyingType, other))
@@ -11685,10 +11818,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.
@@ -12118,8 +12251,8 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
//===----------------------------------------------------------------------===//
unsigned ASTContext::getIntWidth(QualType T) const {
- if (const auto *ET = T->getAs<EnumType>())
- T = ET->getDecl()->getIntegerType();
+ if (const auto *ED = T->getAsEnumDecl())
+ T = ED->getIntegerType();
if (T->isBooleanType())
return 1;
if (const auto *EIT = T->getAs<BitIntType>())
@@ -12144,8 +12277,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->getDecl()->getIntegerType();
+ if (const auto *ED = T->getAsEnumDecl())
+ T = ED->getIntegerType();
switch (T->castAs<BuiltinType>()->getKind()) {
case BuiltinType::Char_U:
@@ -12218,8 +12351,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->getDecl()->getIntegerType();
+ if (const auto *ED = T->getAsEnumDecl())
+ T = ED->getIntegerType();
switch (T->castAs<BuiltinType>()->getKind()) {
case BuiltinType::Char_S:
@@ -12980,6 +13113,14 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (D->hasAttr<WeakRefAttr>())
return false;
+ // SYCL device compilation requires that functions defined with the
+ // sycl_kernel_entry_point or sycl_external attributes be emitted. All
+ // other entities are emitted only if they are used by a function
+ // defined with one of those attributes.
+ if (LangOpts.SYCLIsDevice)
+ return isa<FunctionDecl>(D) && (D->hasAttr<SYCLKernelEntryPointAttr>() ||
+ D->hasAttr<SYCLExternalAttr>());
+
// Aliases and used decls are required.
if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>())
return true;
@@ -12989,15 +13130,6 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (!FD->doesThisDeclarationHaveABody())
return FD->doesDeclarationForceExternallyVisibleDefinition();
- // Function definitions with the sycl_kernel_entry_point attribute are
- // required during device compilation so that SYCL kernel caller offload
- // entry points are emitted.
- if (LangOpts.SYCLIsDevice && FD->hasAttr<SYCLKernelEntryPointAttr>())
- return true;
-
- // FIXME: Functions declared with SYCL_EXTERNAL are required during
- // device compilation.
-
// Constructors and destructors are required.
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
return true;
@@ -13573,7 +13705,7 @@ static T *getCommonDeclChecked(T *X, T *Y) {
const_cast<Decl *>(cast<Decl>(Y))));
}
-static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X,
+static TemplateName getCommonTemplateName(const ASTContext &Ctx, TemplateName X,
TemplateName Y,
bool IgnoreDeduced = false) {
if (X.getAsVoidPointer() == Y.getAsVoidPointer())
@@ -13588,7 +13720,7 @@ static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X,
return CX;
}
-static TemplateName getCommonTemplateNameChecked(ASTContext &Ctx,
+static TemplateName getCommonTemplateNameChecked(const ASTContext &Ctx,
TemplateName X, TemplateName Y,
bool IgnoreDeduced) {
TemplateName R = getCommonTemplateName(Ctx, X, Y, IgnoreDeduced);
@@ -13596,7 +13728,7 @@ static TemplateName getCommonTemplateNameChecked(ASTContext &Ctx,
return R;
}
-static auto getCommonTypes(ASTContext &Ctx, ArrayRef<QualType> Xs,
+static auto getCommonTypes(const ASTContext &Ctx, ArrayRef<QualType> Xs,
ArrayRef<QualType> Ys, bool Unqualified = false) {
assert(Xs.size() == Ys.size());
SmallVector<QualType, 8> Rs(Xs.size());
@@ -13611,7 +13743,7 @@ static SourceLocation getCommonAttrLoc(const T *X, const T *Y) {
: SourceLocation();
}
-static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx,
+static TemplateArgument getCommonTemplateArgument(const ASTContext &Ctx,
const TemplateArgument &X,
const TemplateArgument &Y) {
if (X.getKind() != Y.getKind())
@@ -13657,7 +13789,7 @@ static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx,
}
}
-static bool getCommonTemplateArguments(ASTContext &Ctx,
+static bool getCommonTemplateArguments(const ASTContext &Ctx,
SmallVectorImpl<TemplateArgument> &R,
ArrayRef<TemplateArgument> Xs,
ArrayRef<TemplateArgument> Ys) {
@@ -13672,7 +13804,7 @@ static bool getCommonTemplateArguments(ASTContext &Ctx,
return false;
}
-static auto getCommonTemplateArguments(ASTContext &Ctx,
+static auto getCommonTemplateArguments(const ASTContext &Ctx,
ArrayRef<TemplateArgument> Xs,
ArrayRef<TemplateArgument> Ys) {
SmallVector<TemplateArgument, 8> R;
@@ -13683,163 +13815,101 @@ static auto getCommonTemplateArguments(ASTContext &Ctx,
}
template <class T>
-static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y) {
- return X->getKeyword() == Y->getKeyword() ? X->getKeyword()
- : ElaboratedTypeKeyword::None;
+static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y,
+ bool IsSame) {
+ ElaboratedTypeKeyword KX = X->getKeyword(), KY = Y->getKeyword();
+ if (KX == KY)
+ return KX;
+ KX = getCanonicalElaboratedTypeKeyword(KX);
+ assert(!IsSame || KX == getCanonicalElaboratedTypeKeyword(KY));
+ return KX;
}
/// Returns a NestedNameSpecifier which has only the common sugar
/// present in both NNS1 and NNS2.
-static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx,
- NestedNameSpecifier *NNS1,
- NestedNameSpecifier *NNS2,
- bool IsSame) {
+static NestedNameSpecifier getCommonNNS(const ASTContext &Ctx,
+ NestedNameSpecifier NNS1,
+ NestedNameSpecifier NNS2, bool IsSame) {
// If they are identical, all sugar is common.
if (NNS1 == NNS2)
return NNS1;
- // IsSame implies both NNSes are equivalent.
- NestedNameSpecifier *Canon = Ctx.getCanonicalNestedNameSpecifier(NNS1);
- if (Canon != Ctx.getCanonicalNestedNameSpecifier(NNS2)) {
+ // IsSame implies both Qualifiers are equivalent.
+ NestedNameSpecifier Canon = NNS1.getCanonical();
+ if (Canon != NNS2.getCanonical()) {
assert(!IsSame && "Should be the same NestedNameSpecifier");
// If they are not the same, there is nothing to unify.
- // FIXME: It would be useful here if we could represent a canonically
- // empty NNS, which is not identical to an empty-as-written NNS.
- return nullptr;
+ return std::nullopt;
}
- NestedNameSpecifier *R = nullptr;
- NestedNameSpecifier::SpecifierKind K1 = NNS1->getKind(), K2 = NNS2->getKind();
- switch (K1) {
- case NestedNameSpecifier::SpecifierKind::Identifier: {
- assert(K2 == NestedNameSpecifier::SpecifierKind::Identifier);
- IdentifierInfo *II = NNS1->getAsIdentifier();
- assert(II == NNS2->getAsIdentifier());
- // For an identifier, the prefixes are significant, so they must be the
- // same.
- NestedNameSpecifier *P = ::getCommonNNS(Ctx, NNS1->getPrefix(),
- NNS2->getPrefix(), /*IsSame=*/true);
- R = NestedNameSpecifier::Create(Ctx, P, II);
- break;
- }
- case NestedNameSpecifier::SpecifierKind::Namespace: {
- assert(K2 == NestedNameSpecifier::SpecifierKind::Namespace);
- // The prefixes for namespaces are not significant, its declaration
- // identifies it uniquely.
- NestedNameSpecifier *P =
- ::getCommonNNS(Ctx, NNS1->getPrefix(), NNS2->getPrefix(),
- /*IsSame=*/false);
- NamespaceBaseDecl *Namespace1 = NNS1->getAsNamespace(),
- *Namespace2 = NNS2->getAsNamespace();
+ NestedNameSpecifier R = std::nullopt;
+ NestedNameSpecifier::Kind Kind = NNS1.getKind();
+ assert(Kind == NNS2.getKind());
+ switch (Kind) {
+ case NestedNameSpecifier::Kind::Namespace: {
+ auto [Namespace1, Prefix1] = NNS1.getAsNamespaceAndPrefix();
+ auto [Namespace2, Prefix2] = NNS2.getAsNamespaceAndPrefix();
auto Kind = Namespace1->getKind();
if (Kind != Namespace2->getKind() ||
(Kind == Decl::NamespaceAlias &&
!declaresSameEntity(Namespace1, Namespace2))) {
- R = NestedNameSpecifier::Create(
- Ctx, P,
+ R = NestedNameSpecifier(
+ Ctx,
::getCommonDeclChecked(Namespace1->getNamespace(),
- Namespace2->getNamespace()));
+ Namespace2->getNamespace()),
+ /*Prefix=*/std::nullopt);
break;
}
- R = NestedNameSpecifier::Create(
- Ctx, P, ::getCommonDeclChecked(Namespace1, Namespace2));
+ // The prefixes for namespaces are not significant, its declaration
+ // identifies it uniquely.
+ NestedNameSpecifier Prefix = ::getCommonNNS(Ctx, Prefix1, Prefix2,
+ /*IsSame=*/false);
+ R = NestedNameSpecifier(Ctx, ::getCommonDeclChecked(Namespace1, Namespace2),
+ Prefix);
break;
}
- case NestedNameSpecifier::SpecifierKind::TypeSpec: {
- // FIXME: See comment below, on Super case.
- if (K2 == NestedNameSpecifier::SpecifierKind::Super)
- return Ctx.getCanonicalNestedNameSpecifier(NNS1);
-
- assert(K2 == NestedNameSpecifier::SpecifierKind::TypeSpec);
-
- const Type *T1 = NNS1->getAsType(), *T2 = NNS2->getAsType();
- if (T1 == T2) {
- // If the types are indentical, then only the prefixes differ.
- // A well-formed NNS never has these types, as they have
- // special normalized forms.
- assert((!isa<DependentNameType, ElaboratedType>(T1)));
- // Only for a DependentTemplateSpecializationType the prefix
- // is actually significant. A DependentName, which would be another
- // plausible case, cannot occur here, as explained above.
- bool IsSame = isa<DependentTemplateSpecializationType>(T1);
- NestedNameSpecifier *P =
- ::getCommonNNS(Ctx, NNS1->getPrefix(), NNS2->getPrefix(), IsSame);
- R = NestedNameSpecifier::Create(Ctx, P, T1);
- break;
- }
- // TODO: Try to salvage the original prefix.
- // If getCommonSugaredType removed any top level sugar, the original prefix
- // is not applicable anymore.
+ case NestedNameSpecifier::Kind::Type: {
+ const Type *T1 = NNS1.getAsType(), *T2 = NNS2.getAsType();
const Type *T = Ctx.getCommonSugaredType(QualType(T1, 0), QualType(T2, 0),
/*Unqualified=*/true)
.getTypePtr();
-
- // A NestedNameSpecifier has special normalization rules for certain types.
- switch (T->getTypeClass()) {
- case Type::Elaborated: {
- // An ElaboratedType is stripped off, it's Qualifier becomes the prefix.
- auto *ET = cast<ElaboratedType>(T);
- R = NestedNameSpecifier::Create(Ctx, ET->getQualifier(),
- ET->getNamedType().getTypePtr());
- break;
- }
- case Type::DependentName: {
- // A DependentName is turned into an Identifier NNS.
- auto *DN = cast<DependentNameType>(T);
- R = NestedNameSpecifier::Create(Ctx, DN->getQualifier(),
- DN->getIdentifier());
- break;
- }
- case Type::DependentTemplateSpecialization: {
- // A DependentTemplateSpecializationType loses it's Qualifier, which
- // is turned into the prefix.
- auto *DTST = cast<DependentTemplateSpecializationType>(T);
- const DependentTemplateStorage &DTN = DTST->getDependentTemplateName();
- DependentTemplateStorage NewDTN(/*Qualifier=*/nullptr, DTN.getName(),
- DTN.hasTemplateKeyword());
- T = Ctx.getDependentTemplateSpecializationType(DTST->getKeyword(), NewDTN,
- DTST->template_arguments())
- .getTypePtr();
- R = NestedNameSpecifier::Create(Ctx, DTN.getQualifier(), T);
- break;
- }
- default:
- R = NestedNameSpecifier::Create(Ctx, /*Prefix=*/nullptr, T);
- break;
- }
+ R = NestedNameSpecifier(T);
break;
}
- case NestedNameSpecifier::SpecifierKind::Super:
+ case NestedNameSpecifier::Kind::MicrosoftSuper: {
// FIXME: Can __super even be used with data members?
// If it's only usable in functions, we will never see it here,
// unless we save the qualifiers used in function types.
// In that case, it might be possible NNS2 is a type,
// in which case we should degrade the result to
// a CXXRecordType.
- return Ctx.getCanonicalNestedNameSpecifier(NNS1);
- case NestedNameSpecifier::SpecifierKind::Global:
- // The global NNS is a singleton.
- assert(K2 == NestedNameSpecifier::SpecifierKind::Global &&
- "Global NNS cannot be equivalent to any other kind");
- llvm_unreachable("Global NestedNameSpecifiers did not compare equal");
- }
- assert(Ctx.getCanonicalNestedNameSpecifier(R) == Canon);
+ R = NestedNameSpecifier(getCommonDeclChecked(NNS1.getAsMicrosoftSuper(),
+ NNS2.getAsMicrosoftSuper()));
+ break;
+ }
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::Global:
+ // These are singletons.
+ llvm_unreachable("singletons did not compare equal");
+ }
+ assert(R.getCanonical() == Canon);
return R;
}
template <class T>
-static NestedNameSpecifier *getCommonQualifier(ASTContext &Ctx, const T *X,
- const T *Y, bool IsSame) {
+static NestedNameSpecifier getCommonQualifier(const ASTContext &Ctx, const T *X,
+ const T *Y, bool IsSame) {
return ::getCommonNNS(Ctx, X->getQualifier(), Y->getQualifier(), IsSame);
}
template <class T>
-static QualType getCommonElementType(ASTContext &Ctx, const T *X, const T *Y) {
+static QualType getCommonElementType(const ASTContext &Ctx, const T *X,
+ const T *Y) {
return Ctx.getCommonSugaredType(X->getElementType(), Y->getElementType());
}
template <class T>
-static QualType getCommonArrayElementType(ASTContext &Ctx, const T *X,
+static QualType getCommonArrayElementType(const ASTContext &Ctx, const T *X,
Qualifiers &QX, const T *Y,
Qualifiers &QY) {
QualType EX = X->getElementType(), EY = Y->getElementType();
@@ -13856,11 +13926,13 @@ static QualType getCommonArrayElementType(ASTContext &Ctx, const T *X,
}
template <class T>
-static QualType getCommonPointeeType(ASTContext &Ctx, const T *X, const T *Y) {
+static QualType getCommonPointeeType(const ASTContext &Ctx, const T *X,
+ const T *Y) {
return Ctx.getCommonSugaredType(X->getPointeeType(), Y->getPointeeType());
}
-template <class T> static auto *getCommonSizeExpr(ASTContext &Ctx, T *X, T *Y) {
+template <class T>
+static auto *getCommonSizeExpr(const ASTContext &Ctx, T *X, T *Y) {
assert(Ctx.hasSameExpr(X->getSizeExpr(), Y->getSizeExpr()));
return X->getSizeExpr();
}
@@ -13880,8 +13952,9 @@ static auto getCommonIndexTypeCVRQualifiers(const ArrayType *X,
// each type (in a canonical sense) only once, in the order they appear
// from X to Y. If they occur in both X and Y, the result will contain
// the common sugared type between them.
-static void mergeTypeLists(ASTContext &Ctx, SmallVectorImpl<QualType> &Out,
- ArrayRef<QualType> X, ArrayRef<QualType> Y) {
+static void mergeTypeLists(const ASTContext &Ctx,
+ SmallVectorImpl<QualType> &Out, ArrayRef<QualType> X,
+ ArrayRef<QualType> Y) {
llvm::DenseMap<QualType, unsigned> Found;
for (auto Ts : {X, Y}) {
for (QualType T : Ts) {
@@ -13900,7 +13973,7 @@ FunctionProtoType::ExceptionSpecInfo
ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1,
FunctionProtoType::ExceptionSpecInfo ESI2,
SmallVectorImpl<QualType> &ExceptionTypeStorage,
- bool AcceptDependent) {
+ bool AcceptDependent) const {
ExceptionSpecificationType EST1 = ESI1.Type, EST2 = ESI2.Type;
// If either of them can throw anything, that is the result.
@@ -13964,7 +14037,7 @@ ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1,
llvm_unreachable("invalid ExceptionSpecificationType");
}
-static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
+static QualType getCommonNonSugarTypeNode(const ASTContext &Ctx, const Type *X,
Qualifiers &QX, const Type *Y,
Qualifiers &QY) {
Type::TypeClass TC = X->getTypeClass();
@@ -13982,11 +14055,10 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
SUGAR_FREE_TYPE(Builtin)
SUGAR_FREE_TYPE(DeducedTemplateSpecialization)
SUGAR_FREE_TYPE(DependentBitInt)
- SUGAR_FREE_TYPE(Enum)
SUGAR_FREE_TYPE(BitInt)
SUGAR_FREE_TYPE(ObjCInterface)
- SUGAR_FREE_TYPE(Record)
SUGAR_FREE_TYPE(SubstTemplateTypeParmPack)
+ SUGAR_FREE_TYPE(SubstBuiltinTemplatePack)
SUGAR_FREE_TYPE(UnresolvedUsing)
SUGAR_FREE_TYPE(HLSLAttributedResource)
SUGAR_FREE_TYPE(HLSLInlineSpirv)
@@ -14203,13 +14275,15 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
getCommonElementType(Ctx, VX, VY), getCommonSizeExpr(Ctx, VX, VY),
getCommonAttrLoc(VX, VY), VX->getVectorKind());
}
+ case Type::Enum:
+ case Type::Record:
case Type::InjectedClassName: {
- const auto *IX = cast<InjectedClassNameType>(X),
- *IY = cast<InjectedClassNameType>(Y);
- return Ctx.getInjectedClassNameType(
- getCommonDeclChecked(IX->getDecl(), IY->getDecl()),
- Ctx.getCommonSugaredType(IX->getInjectedSpecializationType(),
- IY->getInjectedSpecializationType()));
+ const auto *TX = cast<TagType>(X), *TY = cast<TagType>(Y);
+ return Ctx.getTagType(
+ ::getCommonTypeKeyword(TX, TY, /*IsSame=*/false),
+ ::getCommonQualifier(Ctx, TX, TY, /*IsSame=*/false),
+ ::getCommonDeclChecked(TX->getOriginalDecl(), TY->getOriginalDecl()),
+ /*OwnedTag=*/false);
}
case Type::TemplateSpecialization: {
const auto *TX = cast<TemplateSpecializationType>(X),
@@ -14217,6 +14291,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
TY->template_arguments());
return Ctx.getTemplateSpecializationType(
+ getCommonTypeKeyword(TX, TY, /*IsSame=*/false),
::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(),
TY->getTemplateName(),
/*IgnoreDeduced=*/true),
@@ -14244,7 +14319,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
*NY = cast<DependentNameType>(Y);
assert(NX->getIdentifier() == NY->getIdentifier());
return Ctx.getDependentNameType(
- getCommonTypeKeyword(NX, NY),
+ getCommonTypeKeyword(NX, NY, /*IsSame=*/true),
getCommonQualifier(Ctx, NX, NY, /*IsSame=*/true), NX->getIdentifier());
}
case Type::DependentTemplateSpecialization: {
@@ -14260,7 +14335,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
/*IsSame=*/true),
SX.getName(), SX.hasTemplateKeyword() || SY.hasTemplateKeyword());
return Ctx.getDependentTemplateSpecializationType(
- getCommonTypeKeyword(TX, TY), Name, As);
+ getCommonTypeKeyword(TX, TY, /*IsSame=*/true), Name, As);
}
case Type::UnaryTransform: {
const auto *TX = cast<UnaryTransformType>(X),
@@ -14301,7 +14376,7 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
llvm_unreachable("Unknown Type Class");
}
-static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
+static QualType getCommonSugarTypeNode(const ASTContext &Ctx, const Type *X,
const Type *Y,
SplitQualType Underlying) {
Type::TypeClass TC = X->getTypeClass();
@@ -14413,15 +14488,6 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
case Type::DeducedTemplateSpecialization:
// FIXME: Try to merge these.
return QualType();
-
- case Type::Elaborated: {
- const auto *EX = cast<ElaboratedType>(X), *EY = cast<ElaboratedType>(Y);
- return Ctx.getElaboratedType(
- ::getCommonTypeKeyword(EX, EY),
- ::getCommonQualifier(Ctx, EX, EY, /*IsSame=*/false),
- Ctx.getQualifiedType(Underlying),
- ::getCommonDecl(EX->getOwnedTagDecl(), EY->getOwnedTagDecl()));
- }
case Type::MacroQualified: {
const auto *MX = cast<MacroQualifiedType>(X),
*MY = cast<MacroQualifiedType>(Y);
@@ -14465,16 +14531,19 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
if (getCommonTemplateArguments(Ctx, As, TX->template_arguments(),
TY->template_arguments()))
return QualType();
- return Ctx.getTemplateSpecializationType(CTN, As,
- /*CanonicalArgs=*/{},
- Ctx.getQualifiedType(Underlying));
+ return Ctx.getTemplateSpecializationType(
+ getCommonTypeKeyword(TX, TY, /*IsSame=*/false), CTN, As,
+ /*CanonicalArgs=*/{}, Ctx.getQualifiedType(Underlying));
}
case Type::Typedef: {
const auto *TX = cast<TypedefType>(X), *TY = cast<TypedefType>(Y);
const TypedefNameDecl *CD = ::getCommonDecl(TX->getDecl(), TY->getDecl());
if (!CD)
return QualType();
- return Ctx.getTypedefType(CD, Ctx.getQualifiedType(Underlying));
+ return Ctx.getTypedefType(
+ ::getCommonTypeKeyword(TX, TY, /*IsSame=*/false),
+ ::getCommonQualifier(Ctx, TX, TY, /*IsSame=*/false), CD,
+ Ctx.getQualifiedType(Underlying));
}
case Type::TypeOf: {
// The common sugar between two typeof expressions, where one is
@@ -14505,11 +14574,12 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
}
case Type::Using: {
const auto *UX = cast<UsingType>(X), *UY = cast<UsingType>(Y);
- const UsingShadowDecl *CD =
- ::getCommonDecl(UX->getFoundDecl(), UY->getFoundDecl());
+ const UsingShadowDecl *CD = ::getCommonDecl(UX->getDecl(), UY->getDecl());
if (!CD)
return QualType();
- return Ctx.getUsingType(CD, Ctx.getQualifiedType(Underlying));
+ return Ctx.getUsingType(::getCommonTypeKeyword(UX, UY, /*IsSame=*/false),
+ ::getCommonQualifier(Ctx, UX, UY, /*IsSame=*/false),
+ CD, Ctx.getQualifiedType(Underlying));
}
case Type::MemberPointer: {
const auto *PX = cast<MemberPointerType>(X),
@@ -14568,7 +14638,7 @@ static auto unwrapSugar(SplitQualType &T, Qualifiers &QTotal) {
}
QualType ASTContext::getCommonSugaredType(QualType X, QualType Y,
- bool Unqualified) {
+ bool Unqualified) const {
assert(Unqualified ? hasSameUnqualifiedType(X, Y) : hasSameType(X, Y));
if (X == Y)
return X;
@@ -15119,7 +15189,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/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index 2ef0c31..d7fd411 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -36,11 +36,6 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
while (true) {
const Type *Ty = QC.strip(QT);
- // Don't aka just because we saw an elaborated type...
- if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Ty)) {
- QT = ET->desugar();
- continue;
- }
// ... or a using type ...
if (const UsingType *UT = dyn_cast<UsingType>(Ty)) {
QT = UT->desugar();
@@ -130,7 +125,8 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
if (DesugarArgument) {
ShouldAKA = true;
QT = Context.getTemplateSpecializationType(
- TST->getTemplateName(), Args, /*CanonicalArgs=*/{}, QT);
+ TST->getKeyword(), TST->getTemplateName(), Args,
+ /*CanonicalArgs=*/{}, QT);
}
break;
}
@@ -200,7 +196,8 @@ break; \
// Don't desugar through the primary typedef of an anonymous type.
if (const TagType *UTT = Underlying->getAs<TagType>())
if (const TypedefType *QTT = dyn_cast<TypedefType>(QT))
- if (UTT->getDecl()->getTypedefNameForAnonDecl() == QTT->getDecl())
+ if (UTT->getOriginalDecl()->getTypedefNameForAnonDecl() ==
+ QTT->getDecl())
break;
// Record that we actually looked through an opaque type here.
@@ -461,13 +458,12 @@ void clang::FormatASTNodeDiagnosticArgument(
ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), Qualified);
break;
}
- case DiagnosticsEngine::ak_nestednamespec: {
- NestedNameSpecifier *NNS = reinterpret_cast<NestedNameSpecifier*>(Val);
- NNS->print(OS, Context.getPrintingPolicy(),
+ case DiagnosticsEngine::ak_nestednamespec:
+ NestedNameSpecifier::getFromVoidPointer(reinterpret_cast<void *>(Val))
+ .print(OS, Context.getPrintingPolicy(),
/*ResolveTemplateArguments=*/false,
/*PrintFinalScopeResOp=*/false);
break;
- }
case DiagnosticsEngine::ak_declcontext: {
DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
assert(DC && "Should never have a null declaration context");
@@ -484,9 +480,8 @@ void clang::FormatASTNodeDiagnosticArgument(
} else if (isLambdaCallOperator(DC)) {
OS << "lambda expression";
} else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
- OS << ConvertTypeToDiagnosticString(Context,
- Context.getTypeDeclType(Type),
- PrevArgs, QualTypeVals);
+ OS << ConvertTypeToDiagnosticString(
+ Context, Context.getTypeDeclType(Type), PrevArgs, QualTypeVals);
} else {
assert(isa<NamedDecl>(DC) && "Expected a NamedDecl");
NamedDecl *ND = cast<NamedDecl>(DC);
@@ -1158,12 +1153,13 @@ class TemplateDiff {
return nullptr;
const ClassTemplateSpecializationDecl *CTSD =
- dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getOriginalDecl());
if (!CTSD)
return nullptr;
Ty = Context.getTemplateSpecializationType(
+ ElaboratedTypeKeyword::None,
TemplateName(CTSD->getSpecializedTemplate()),
CTSD->getTemplateArgs().asArray(), /*CanonicalArgs=*/{},
Ty.getLocalUnqualifiedType().getCanonicalType());
@@ -1743,25 +1739,10 @@ class TemplateDiff {
std::string FromTypeStr = FromType.isNull() ? "(no argument)"
: FromType.getAsString(Policy);
- std::string ToTypeStr = ToType.isNull() ? "(no argument)"
- : ToType.getAsString(Policy);
- // Print without ElaboratedType sugar if it is better.
+ std::string ToTypeStr =
+ ToType.isNull() ? "(no argument)" : ToType.getAsString(Policy);
// TODO: merge this with other aka printing above.
if (FromTypeStr == ToTypeStr) {
- const auto *FromElTy = dyn_cast<ElaboratedType>(FromType),
- *ToElTy = dyn_cast<ElaboratedType>(ToType);
- if (FromElTy || ToElTy) {
- std::string FromNamedTypeStr =
- FromElTy ? FromElTy->getNamedType().getAsString(Policy)
- : FromTypeStr;
- std::string ToNamedTypeStr =
- ToElTy ? ToElTy->getNamedType().getAsString(Policy) : ToTypeStr;
- if (FromNamedTypeStr != ToNamedTypeStr) {
- FromTypeStr = FromNamedTypeStr;
- ToTypeStr = ToNamedTypeStr;
- goto PrintTypes;
- }
- }
// Switch to canonical typename if it is better.
std::string FromCanTypeStr =
FromType.getCanonicalType().getAsString(Policy);
@@ -1772,8 +1753,8 @@ class TemplateDiff {
}
}
- PrintTypes:
- if (PrintTree) OS << '[';
+ if (PrintTree)
+ OS << '[';
OS << (FromDefault ? "(default) " : "");
Bold();
OS << FromTypeStr;
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index 5e4487e..8e651a0 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -117,7 +117,9 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
// FIXME: The redecls() range sometimes has elements of a less-specific
// type. (In particular, ClassTemplateSpecializationDecl::redecls() gives
// us TagDecls, and should give CXXRecordDecls).
- auto *Redecl = cast<SpecializationDecl>(RedeclWithBadType);
+ auto *Redecl = dyn_cast<SpecializationDecl>(RedeclWithBadType);
+ if (!Redecl)
+ continue;
switch (Redecl->getTemplateSpecializationKind()) {
case TSK_ExplicitInstantiationDeclaration:
case TSK_ExplicitInstantiationDefinition:
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 8e2927b..6299efa 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -949,8 +949,10 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) {
else
return TSIOrErr.takeError();
} else {
- auto ToTemplateQualifierLocOrErr =
- import(FromInfo.getTemplateQualifierLoc());
+ auto ToTemplateKWLocOrErr = import(FromInfo.getTemplateKwLoc());
+ if (!ToTemplateKWLocOrErr)
+ return ToTemplateKWLocOrErr.takeError();
+ auto ToTemplateQualifierLocOrErr = import(TALoc.getTemplateQualifierLoc());
if (!ToTemplateQualifierLocOrErr)
return ToTemplateQualifierLocOrErr.takeError();
auto ToTemplateNameLocOrErr = import(FromInfo.getTemplateNameLoc());
@@ -961,8 +963,9 @@ ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) {
if (!ToTemplateEllipsisLocOrErr)
return ToTemplateEllipsisLocOrErr.takeError();
ToInfo = TemplateArgumentLocInfo(
- Importer.getToContext(), *ToTemplateQualifierLocOrErr,
- *ToTemplateNameLocOrErr, *ToTemplateEllipsisLocOrErr);
+ Importer.getToContext(), *ToTemplateKWLocOrErr,
+ *ToTemplateQualifierLocOrErr, *ToTemplateNameLocOrErr,
+ *ToTemplateEllipsisLocOrErr);
}
return TemplateArgumentLoc(Arg, ToInfo);
@@ -1597,13 +1600,15 @@ ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
ExpectedType ASTNodeImporter::VisitUnresolvedUsingType(
const UnresolvedUsingType *T) {
Error Err = Error::success();
- auto ToD = importChecked(Err, T->getDecl());
- auto ToPrevD = importChecked(Err, T->getDecl()->getPreviousDecl());
+ auto ToQualifier = importChecked(Err, T->getQualifier());
+ auto *ToD = importChecked(Err, T->getDecl());
if (Err)
return std::move(Err);
- return Importer.getToContext().getTypeDeclType(
- ToD, cast_or_null<TypeDecl>(ToPrevD));
+ if (T->isCanonicalUnqualified())
+ return Importer.getToContext().getCanonicalUnresolvedUsingType(ToD);
+ return Importer.getToContext().getUnresolvedUsingType(T->getKeyword(),
+ ToQualifier, ToD);
}
ExpectedType ASTNodeImporter::VisitParenType(const ParenType *T) {
@@ -1631,15 +1636,17 @@ ExpectedType ASTNodeImporter::VisitTypedefType(const TypedefType *T) {
if (!ToDeclOrErr)
return ToDeclOrErr.takeError();
- TypedefNameDecl *ToDecl = *ToDeclOrErr;
- if (ToDecl->getTypeForDecl())
- return QualType(ToDecl->getTypeForDecl(), 0);
+ auto ToQualifierOrErr = import(T->getQualifier());
+ if (!ToQualifierOrErr)
+ return ToQualifierOrErr.takeError();
- ExpectedType ToUnderlyingTypeOrErr = import(T->desugar());
+ ExpectedType ToUnderlyingTypeOrErr =
+ T->typeMatchesDecl() ? QualType() : import(T->desugar());
if (!ToUnderlyingTypeOrErr)
return ToUnderlyingTypeOrErr.takeError();
- return Importer.getToContext().getTypedefType(ToDecl, *ToUnderlyingTypeOrErr);
+ return Importer.getToContext().getTypedefType(
+ T->getKeyword(), *ToQualifierOrErr, *ToDeclOrErr, *ToUnderlyingTypeOrErr);
}
ExpectedType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) {
@@ -1658,14 +1665,14 @@ ExpectedType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) {
}
ExpectedType ASTNodeImporter::VisitUsingType(const UsingType *T) {
- Expected<UsingShadowDecl *> FoundOrErr = import(T->getFoundDecl());
- if (!FoundOrErr)
- return FoundOrErr.takeError();
- Expected<QualType> UnderlyingOrErr = import(T->getUnderlyingType());
- if (!UnderlyingOrErr)
- return UnderlyingOrErr.takeError();
-
- return Importer.getToContext().getUsingType(*FoundOrErr, *UnderlyingOrErr);
+ Error Err = Error::success();
+ auto ToQualifier = importChecked(Err, T->getQualifier());
+ auto *ToD = importChecked(Err, T->getDecl());
+ QualType ToT = importChecked(Err, T->desugar());
+ if (Err)
+ return std::move(Err);
+ return Importer.getToContext().getUsingType(T->getKeyword(), ToQualifier, ToD,
+ ToT);
}
ExpectedType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) {
@@ -1728,36 +1735,37 @@ ExpectedType ASTNodeImporter::VisitDeducedTemplateSpecializationType(
return ToDeducedTypeOrErr.takeError();
return Importer.getToContext().getDeducedTemplateSpecializationType(
- *ToTemplateNameOrErr, *ToDeducedTypeOrErr, T->isDependentType());
+ T->getKeyword(), *ToTemplateNameOrErr, *ToDeducedTypeOrErr,
+ T->isDependentType());
}
-ExpectedType ASTNodeImporter::VisitInjectedClassNameType(
- const InjectedClassNameType *T) {
- Expected<CXXRecordDecl *> ToDeclOrErr = import(T->getDecl());
+ExpectedType ASTNodeImporter::VisitTagType(const TagType *T) {
+ Expected<TagDecl *> ToDeclOrErr = import(T->getOriginalDecl());
if (!ToDeclOrErr)
return ToDeclOrErr.takeError();
- // The InjectedClassNameType is created in VisitRecordDecl when the
- // T->getDecl() is imported. Here we can return the existing type.
- const Type *Ty = (*ToDeclOrErr)->getTypeForDecl();
- assert(isa_and_nonnull<InjectedClassNameType>(Ty));
- return QualType(Ty, 0);
-}
+ if (T->isCanonicalUnqualified())
+ return Importer.getToContext().getCanonicalTagType(*ToDeclOrErr);
-ExpectedType ASTNodeImporter::VisitRecordType(const RecordType *T) {
- Expected<RecordDecl *> ToDeclOrErr = import(T->getDecl());
- if (!ToDeclOrErr)
- return ToDeclOrErr.takeError();
+ auto ToQualifierOrErr = import(T->getQualifier());
+ if (!ToQualifierOrErr)
+ return ToQualifierOrErr.takeError();
- return Importer.getToContext().getTagDeclType(*ToDeclOrErr);
+ return Importer.getToContext().getTagType(T->getKeyword(), *ToQualifierOrErr,
+ *ToDeclOrErr, T->isTagOwned());
}
ExpectedType ASTNodeImporter::VisitEnumType(const EnumType *T) {
- Expected<EnumDecl *> ToDeclOrErr = import(T->getDecl());
- if (!ToDeclOrErr)
- return ToDeclOrErr.takeError();
+ return VisitTagType(T);
+}
- return Importer.getToContext().getTagDeclType(*ToDeclOrErr);
+ExpectedType ASTNodeImporter::VisitRecordType(const RecordType *T) {
+ return VisitTagType(T);
+}
+
+ExpectedType
+ASTNodeImporter::VisitInjectedClassNameType(const InjectedClassNameType *T) {
+ return VisitTagType(T);
}
ExpectedType ASTNodeImporter::VisitAttributedType(const AttributedType *T) {
@@ -1834,6 +1842,14 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
*ReplacedOrErr, T->getIndex(), T->getFinal(), *ToArgumentPack);
}
+ExpectedType ASTNodeImporter::VisitSubstBuiltinTemplatePackType(
+ const SubstBuiltinTemplatePackType *T) {
+ Expected<TemplateArgument> ToArgumentPack = import(T->getArgumentPack());
+ if (!ToArgumentPack)
+ return ToArgumentPack.takeError();
+ return Importer.getToContext().getSubstBuiltinTemplatePack(*ToArgumentPack);
+}
+
ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
const TemplateSpecializationType *T) {
auto ToTemplateOrErr = import(T->getTemplateName());
@@ -1850,27 +1866,8 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
if (!ToUnderlyingOrErr)
return ToUnderlyingOrErr.takeError();
return Importer.getToContext().getTemplateSpecializationType(
- *ToTemplateOrErr, ToTemplateArgs, {}, *ToUnderlyingOrErr);
-}
-
-ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) {
- // Note: the qualifier in an ElaboratedType is optional.
- auto ToQualifierOrErr = import(T->getQualifier());
- if (!ToQualifierOrErr)
- return ToQualifierOrErr.takeError();
-
- ExpectedType ToNamedTypeOrErr = import(T->getNamedType());
- if (!ToNamedTypeOrErr)
- return ToNamedTypeOrErr.takeError();
-
- Expected<TagDecl *> ToOwnedTagDeclOrErr = import(T->getOwnedTagDecl());
- if (!ToOwnedTagDeclOrErr)
- return ToOwnedTagDeclOrErr.takeError();
-
- return Importer.getToContext().getElaboratedType(T->getKeyword(),
- *ToQualifierOrErr,
- *ToNamedTypeOrErr,
- *ToOwnedTagDeclOrErr);
+ T->getKeyword(), *ToTemplateOrErr, ToTemplateArgs, {},
+ *ToUnderlyingOrErr);
}
ExpectedType
@@ -2168,7 +2165,7 @@ Error ASTNodeImporter::ImportDeclParts(
const Type *LeafT =
getLeafPointeeType(P->getType().getCanonicalType().getTypePtr());
auto *RT = dyn_cast<RecordType>(LeafT);
- if (RT && RT->getDecl() == D) {
+ if (RT && RT->getOriginalDecl() == D) {
Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
<< D->getDeclKindName();
return make_error<ASTImportError>(ASTImportError::UnsupportedConstruct);
@@ -2421,8 +2418,8 @@ Error ASTNodeImporter::ImportFieldDeclDefinition(const FieldDecl *From,
const RecordType *RecordTo = ToType->getAs<RecordType>();
if (RecordFrom && RecordTo) {
- FromRecordDecl = RecordFrom->getDecl();
- ToRecordDecl = RecordTo->getDecl();
+ FromRecordDecl = RecordFrom->getOriginalDecl();
+ ToRecordDecl = RecordTo->getOriginalDecl();
}
}
@@ -2643,7 +2640,7 @@ Error ASTNodeImporter::ImportDefinition(
return Err;
ExpectedType ToTypeOrErr =
- import(Importer.getFromContext().getTypeDeclType(From));
+ import(QualType(Importer.getFromContext().getCanonicalTagType(From)));
if (!ToTypeOrErr)
return ToTypeOrErr.takeError();
@@ -3218,7 +3215,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
if (auto *Typedef = dyn_cast<TypedefNameDecl>(FoundDecl)) {
if (const auto *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
- FoundDecl = Tag->getDecl();
+ FoundDecl = Tag->getOriginalDecl();
}
if (auto *FoundEnum = dyn_cast<EnumDecl>(FoundDecl)) {
@@ -3349,7 +3346,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
Decl *Found = FoundDecl;
if (auto *Typedef = dyn_cast<TypedefNameDecl>(Found)) {
if (const auto *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
- Found = Tag->getDecl();
+ Found = Tag->getOriginalDecl();
}
if (auto *FoundRecord = dyn_cast<RecordDecl>(Found)) {
@@ -3428,17 +3425,6 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
return CDeclOrErr.takeError();
Numbering.ContextDecl = *CDeclOrErr;
D2CXX->setLambdaNumbering(Numbering);
- } else if (DCXX->isInjectedClassName()) {
- // We have to be careful to do a similar dance to the one in
- // Sema::ActOnStartCXXMemberDeclarations
- const bool DelayTypeCreation = true;
- if (GetImportedOrCreateDecl(
- D2CXX, D, Importer.getToContext(), D->getTagKind(), DC,
- *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(),
- cast_or_null<CXXRecordDecl>(PrevDecl), DelayTypeCreation))
- return D2CXX;
- Importer.getToContext().getTypeDeclType(
- D2CXX, dyn_cast<CXXRecordDecl>(DC));
} else {
if (GetImportedOrCreateDecl(D2CXX, D, Importer.getToContext(),
D->getTagKind(), DC, *BeginLocOrErr, Loc,
@@ -3458,51 +3444,6 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
if (Error Err = importInto(ToDescribed, FromDescribed))
return std::move(Err);
D2CXX->setDescribedClassTemplate(ToDescribed);
- if (!DCXX->isInjectedClassName() && !IsFriendTemplate) {
- // In a record describing a template the type should be an
- // InjectedClassNameType (see Sema::CheckClassTemplate). Update the
- // previously set type to the correct value here (ToDescribed is not
- // available at record create).
- CXXRecordDecl *Injected = nullptr;
- for (NamedDecl *Found : D2CXX->noload_lookup(Name)) {
- auto *Record = dyn_cast<CXXRecordDecl>(Found);
- if (Record && Record->isInjectedClassName()) {
- Injected = Record;
- break;
- }
- }
- // Create an injected type for the whole redecl chain.
- // The chain may contain an already existing injected type at the start,
- // if yes this should be reused. We must ensure that only one type
- // object exists for the injected type (including the injected record
- // declaration), ASTContext does not check it.
- SmallVector<Decl *, 2> Redecls =
- getCanonicalForwardRedeclChain(D2CXX);
- const Type *FrontTy =
- cast<CXXRecordDecl>(Redecls.front())->getTypeForDecl();
- QualType InjSpec;
- if (auto *InjTy = FrontTy->getAs<InjectedClassNameType>())
- InjSpec = InjTy->getInjectedSpecializationType();
- else
- InjSpec = ToDescribed->getInjectedClassNameSpecialization();
- for (auto *R : Redecls) {
- auto *RI = cast<CXXRecordDecl>(R);
- if (R != Redecls.front() ||
- !isa<InjectedClassNameType>(RI->getTypeForDecl()))
- RI->setTypeForDecl(nullptr);
- // This function tries to get the injected type from getTypeForDecl,
- // then from the previous declaration if possible. If not, it creates
- // a new type.
- Importer.getToContext().getInjectedClassNameType(RI, InjSpec);
- }
- // Set the new type for the injected decl too.
- if (Injected) {
- Injected->setTypeForDecl(nullptr);
- // This function will copy the injected type from D2CXX into Injected.
- // The injected decl does not have a previous decl to copy from.
- Importer.getToContext().getTypeDeclType(Injected, D2CXX);
- }
- }
} else if (MemberSpecializationInfo *MemberInfo =
DCXX->getMemberSpecializationInfo()) {
TemplateSpecializationKind SK =
@@ -3826,11 +3767,12 @@ public:
}
std::optional<bool> VisitTagType(const TagType *T) {
- if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl()))
+ if (auto *Spec =
+ dyn_cast<ClassTemplateSpecializationDecl>(T->getOriginalDecl()))
for (const auto &Arg : Spec->getTemplateArgs().asArray())
if (checkTemplateArgument(Arg))
return true;
- return isAncestorDeclContextOf(ParentDC, T->getDecl());
+ return isAncestorDeclContextOf(ParentDC, T->getOriginalDecl());
}
std::optional<bool> VisitPointerType(const PointerType *T) {
@@ -3842,17 +3784,11 @@ public:
}
std::optional<bool> VisitTypedefType(const TypedefType *T) {
- const TypedefNameDecl *TD = T->getDecl();
- assert(TD);
- return isAncestorDeclContextOf(ParentDC, TD);
+ return isAncestorDeclContextOf(ParentDC, T->getDecl());
}
std::optional<bool> VisitUsingType(const UsingType *T) {
- if (T->getFoundDecl() &&
- isAncestorDeclContextOf(ParentDC, T->getFoundDecl()))
- return true;
-
- return {};
+ return isAncestorDeclContextOf(ParentDC, T->getDecl());
}
std::optional<bool>
@@ -6521,16 +6457,10 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
// Create the specialization.
ClassTemplateSpecializationDecl *D2 = nullptr;
if (PartialSpec) {
- QualType CanonInjType;
- if (Error Err = importInto(
- CanonInjType, PartialSpec->getInjectedSpecializationType()))
- return std::move(Err);
- CanonInjType = CanonInjType.getCanonicalType();
-
if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr,
*IdLocOrErr, ToTPList, ClassTemplate, ArrayRef(TemplateArgs),
- CanonInjType,
+ /*CanonInjectedTST=*/CanQualType(),
cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
return D2;
@@ -10050,46 +9980,34 @@ Expected<Stmt *> ASTImporter::Import(Stmt *FromS) {
return ToSOrErr;
}
-Expected<NestedNameSpecifier *>
-ASTImporter::Import(NestedNameSpecifier *FromNNS) {
- if (!FromNNS)
- return nullptr;
-
- NestedNameSpecifier *Prefix = nullptr;
- if (Error Err = importInto(Prefix, FromNNS->getPrefix()))
- return std::move(Err);
-
- switch (FromNNS->getKind()) {
- case NestedNameSpecifier::Identifier:
- assert(FromNNS->getAsIdentifier() && "NNS should contain identifier.");
- return NestedNameSpecifier::Create(ToContext, Prefix,
- Import(FromNNS->getAsIdentifier()));
-
- case NestedNameSpecifier::Namespace:
- if (ExpectedDecl NSOrErr = Import(FromNNS->getAsNamespace())) {
- return NestedNameSpecifier::Create(ToContext, Prefix,
- cast<NamespaceBaseDecl>(*NSOrErr));
- } else
+Expected<NestedNameSpecifier> ASTImporter::Import(NestedNameSpecifier FromNNS) {
+ switch (FromNNS.getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::Global:
+ return FromNNS;
+ case NestedNameSpecifier::Kind::Namespace: {
+ auto [Namespace, Prefix] = FromNNS.getAsNamespaceAndPrefix();
+ auto NSOrErr = Import(Namespace);
+ if (!NSOrErr)
return NSOrErr.takeError();
-
- case NestedNameSpecifier::Global:
- return NestedNameSpecifier::GlobalSpecifier(ToContext);
-
- case NestedNameSpecifier::Super:
- if (ExpectedDecl RDOrErr = Import(FromNNS->getAsRecordDecl()))
- return NestedNameSpecifier::SuperSpecifier(ToContext,
- cast<CXXRecordDecl>(*RDOrErr));
+ auto PrefixOrErr = Import(Prefix);
+ if (!PrefixOrErr)
+ return PrefixOrErr.takeError();
+ return NestedNameSpecifier(ToContext, cast<NamespaceBaseDecl>(*NSOrErr),
+ *PrefixOrErr);
+ }
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ if (ExpectedDecl RDOrErr = Import(FromNNS.getAsMicrosoftSuper()))
+ return NestedNameSpecifier(cast<CXXRecordDecl>(*RDOrErr));
else
return RDOrErr.takeError();
-
- case NestedNameSpecifier::TypeSpec:
- if (ExpectedTypePtr TyOrErr = Import(FromNNS->getAsType())) {
- return NestedNameSpecifier::Create(ToContext, Prefix, *TyOrErr);
+ case NestedNameSpecifier::Kind::Type:
+ if (ExpectedTypePtr TyOrErr = Import(FromNNS.getAsType())) {
+ return NestedNameSpecifier(*TyOrErr);
} else {
return TyOrErr.takeError();
}
}
-
llvm_unreachable("Invalid nested name specifier kind");
}
@@ -10103,64 +10021,62 @@ ASTImporter::Import(NestedNameSpecifierLoc FromNNS) {
// serialization in reverse order.
while (NNS) {
NestedNames.push_back(NNS);
- NNS = NNS.getPrefix();
+ NNS = NNS.getAsNamespaceAndPrefix().Prefix;
}
NestedNameSpecifierLocBuilder Builder;
while (!NestedNames.empty()) {
NNS = NestedNames.pop_back_val();
- NestedNameSpecifier *Spec = nullptr;
+ NestedNameSpecifier Spec = std::nullopt;
if (Error Err = importInto(Spec, NNS.getNestedNameSpecifier()))
return std::move(Err);
- NestedNameSpecifier::SpecifierKind Kind = Spec->getKind();
+ NestedNameSpecifier::Kind Kind = Spec.getKind();
SourceLocation ToLocalBeginLoc, ToLocalEndLoc;
- if (Kind != NestedNameSpecifier::Super) {
+ if (Kind != NestedNameSpecifier::Kind::MicrosoftSuper) {
if (Error Err = importInto(ToLocalBeginLoc, NNS.getLocalBeginLoc()))
return std::move(Err);
- if (Kind != NestedNameSpecifier::Global)
+ if (Kind != NestedNameSpecifier::Kind::Global)
if (Error Err = importInto(ToLocalEndLoc, NNS.getLocalEndLoc()))
return std::move(Err);
}
switch (Kind) {
- case NestedNameSpecifier::Identifier:
- Builder.Extend(getToContext(), Spec->getAsIdentifier(), ToLocalBeginLoc,
- ToLocalEndLoc);
- break;
-
- case NestedNameSpecifier::Namespace:
- Builder.Extend(getToContext(), Spec->getAsNamespace(), ToLocalBeginLoc,
- ToLocalEndLoc);
+ case NestedNameSpecifier::Kind::Namespace:
+ Builder.Extend(getToContext(), Spec.getAsNamespaceAndPrefix().Namespace,
+ ToLocalBeginLoc, ToLocalEndLoc);
break;
- case NestedNameSpecifier::TypeSpec: {
+ case NestedNameSpecifier::Kind::Type: {
SourceLocation ToTLoc;
- if (Error Err = importInto(ToTLoc, NNS.getTypeLoc().getBeginLoc()))
+ if (Error Err = importInto(ToTLoc, NNS.castAsTypeLoc().getBeginLoc()))
return std::move(Err);
TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo(
- QualType(Spec->getAsType(), 0), ToTLoc);
- Builder.Extend(getToContext(), TSI->getTypeLoc(), ToLocalEndLoc);
+ QualType(Spec.getAsType(), 0), ToTLoc);
+ Builder.Make(getToContext(), TSI->getTypeLoc(), ToLocalEndLoc);
break;
}
- case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Kind::Global:
Builder.MakeGlobal(getToContext(), ToLocalBeginLoc);
break;
- case NestedNameSpecifier::Super: {
+ case NestedNameSpecifier::Kind::MicrosoftSuper: {
auto ToSourceRangeOrErr = Import(NNS.getSourceRange());
if (!ToSourceRangeOrErr)
return ToSourceRangeOrErr.takeError();
- Builder.MakeSuper(getToContext(), Spec->getAsRecordDecl(),
- ToSourceRangeOrErr->getBegin(),
- ToSourceRangeOrErr->getEnd());
+ Builder.MakeMicrosoftSuper(getToContext(), Spec.getAsMicrosoftSuper(),
+ ToSourceRangeOrErr->getBegin(),
+ ToSourceRangeOrErr->getEnd());
+ break;
+ }
+ case NestedNameSpecifier::Kind::Null:
+ llvm_unreachable("unexpected null nested name specifier");
}
- }
}
return Builder.getWithLocInContext(getToContext());
@@ -10740,7 +10656,7 @@ ASTNodeImporter::ImportAPValue(const APValue &FromValue) {
if (Err)
return std::move(Err);
if (auto *RD = dyn_cast<CXXRecordDecl>(FromDecl))
- FromElemTy = Importer.FromContext.getRecordType(RD);
+ FromElemTy = Importer.FromContext.getCanonicalTagType(RD);
else
FromElemTy = cast<ValueDecl>(FromDecl)->getType();
ToPath[LoopIdx] = APValue::LValuePathEntry(APValue::BaseOrMemberType(
diff --git a/clang/lib/AST/ASTImporterLookupTable.cpp b/clang/lib/AST/ASTImporterLookupTable.cpp
index 4ed3198..29c3af1 100644
--- a/clang/lib/AST/ASTImporterLookupTable.cpp
+++ b/clang/lib/AST/ASTImporterLookupTable.cpp
@@ -49,8 +49,6 @@ struct Builder : RecursiveASTVisitor<Builder> {
bool VisitFriendDecl(FriendDecl *D) {
if (D->getFriendType()) {
QualType Ty = D->getFriendType()->getType();
- if (isa<ElaboratedType>(Ty))
- Ty = cast<ElaboratedType>(Ty)->getNamedType();
// A FriendDecl with a dependent type (e.g. ClassTemplateSpecialization)
// always has that decl as child node.
// However, there are non-dependent cases which does not have the
@@ -64,13 +62,15 @@ struct Builder : RecursiveASTVisitor<Builder> {
dyn_cast<SubstTemplateTypeParmType>(Ty)) {
if (SubstTy->getAsCXXRecordDecl())
LT.add(SubstTy->getAsCXXRecordDecl());
- } else if (isa<TypedefType>(Ty)) {
- // We do not put friend typedefs to the lookup table because
- // ASTImporter does not organize typedefs into redecl chains.
- } else if (isa<UsingType>(Ty)) {
- // Similar to TypedefType, not putting into lookup table.
} else {
- llvm_unreachable("Unhandled type of friend class");
+ if (isa<TypedefType>(Ty)) {
+ // We do not put friend typedefs to the lookup table because
+ // ASTImporter does not organize typedefs into redecl chains.
+ } else if (isa<UsingType>(Ty)) {
+ // Similar to TypedefType, not putting into lookup table.
+ } else {
+ llvm_unreachable("Unhandled type of friend class");
+ }
}
}
}
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 0e2023f..1292c30 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -110,8 +110,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const TemplateArgumentLoc &Arg1,
const TemplateArgumentLoc &Arg2);
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- NestedNameSpecifier *NNS1,
- NestedNameSpecifier *NNS2);
+ NestedNameSpecifier NNS1,
+ NestedNameSpecifier NNS2);
static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
const IdentifierInfo *Name2);
@@ -579,35 +579,30 @@ static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
/// Determine whether two nested-name-specifiers are equivalent.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
- NestedNameSpecifier *NNS1,
- NestedNameSpecifier *NNS2) {
- if (NNS1->getKind() != NNS2->getKind())
- return false;
-
- NestedNameSpecifier *Prefix1 = NNS1->getPrefix(),
- *Prefix2 = NNS2->getPrefix();
- if ((bool)Prefix1 != (bool)Prefix2)
- return false;
-
- if (Prefix1)
- if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2))
- return false;
-
- switch (NNS1->getKind()) {
- case NestedNameSpecifier::Identifier:
- return IsStructurallyEquivalent(NNS1->getAsIdentifier(),
- NNS2->getAsIdentifier());
- case NestedNameSpecifier::Namespace:
- return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(),
- NNS2->getAsNamespace());
- case NestedNameSpecifier::TypeSpec:
- return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0),
- QualType(NNS2->getAsType(), 0));
- case NestedNameSpecifier::Global:
+ NestedNameSpecifier NNS1,
+ NestedNameSpecifier NNS2) {
+ auto Kind = NNS1.getKind();
+ if (Kind != NNS2.getKind())
+ return false;
+ switch (Kind) {
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::Global:
return true;
- case NestedNameSpecifier::Super:
- return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(),
- NNS2->getAsRecordDecl());
+ case NestedNameSpecifier::Kind::Namespace: {
+ auto [Namespace1, Prefix1] = NNS1.getAsNamespaceAndPrefix();
+ auto [Namespace2, Prefix2] = NNS2.getAsNamespaceAndPrefix();
+ if (!IsStructurallyEquivalent(Context,
+ const_cast<NamespaceBaseDecl *>(Namespace1),
+ const_cast<NamespaceBaseDecl *>(Namespace2)))
+ return false;
+ return IsStructurallyEquivalent(Context, Prefix1, Prefix2);
+ }
+ case NestedNameSpecifier::Kind::Type:
+ return IsStructurallyEquivalent(Context, QualType(NNS1.getAsType(), 0),
+ QualType(NNS2.getAsType(), 0));
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ return IsStructurallyEquivalent(Context, NNS1.getAsMicrosoftSuper(),
+ NNS2.getAsMicrosoftSuper());
}
return false;
}
@@ -615,9 +610,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const DependentTemplateStorage &S1,
const DependentTemplateStorage &S2) {
- if (NestedNameSpecifier *NNS1 = S1.getQualifier(), *NNS2 = S2.getQualifier();
- !NNS1 != !NNS2 ||
- (NNS1 && !IsStructurallyEquivalent(Context, NNS1, NNS2)))
+ if (!IsStructurallyEquivalent(Context, S1.getQualifier(), S2.getQualifier()))
return false;
IdentifierOrOverloadedOperator IO1 = S1.getName(), IO2 = S2.getName();
@@ -885,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>()->getDecl()->getIntegerType();
+ T1 = cast<EnumType>(T1)->getOriginalDecl()->getIntegerType();
assert(T2->isBuiltinType() && !T1.isNull()); // Sanity check
} else if (T2->getTypeClass() == Type::Enum) {
- T2 = T2->getAs<EnumType>()->getDecl()->getIntegerType();
+ T2 = cast<EnumType>(T2)->getOriginalDecl()->getIntegerType();
assert(T1->isBuiltinType() && !T2.isNull()); // Sanity check
}
TC = Type::Builtin;
@@ -1206,23 +1199,35 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
- case Type::Using:
- if (!IsStructurallyEquivalent(Context, cast<UsingType>(T1)->getFoundDecl(),
- cast<UsingType>(T2)->getFoundDecl()))
+ case Type::Using: {
+ auto *U1 = cast<UsingType>(T1), *U2 = cast<UsingType>(T2);
+ if (U1->getKeyword() != U2->getKeyword())
return false;
- if (!IsStructurallyEquivalent(Context,
- cast<UsingType>(T1)->getUnderlyingType(),
- cast<UsingType>(T2)->getUnderlyingType()))
+ if (!IsStructurallyEquivalent(Context, U1->getQualifier(),
+ U2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, U1->getDecl(), U2->getDecl()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, U1->desugar(), U2->desugar()))
return false;
break;
-
- case Type::Typedef:
- if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
- cast<TypedefType>(T2)->getDecl()) ||
- !IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->desugar(),
- cast<TypedefType>(T2)->desugar()))
+ }
+ case Type::Typedef: {
+ auto *U1 = cast<TypedefType>(T1), *U2 = cast<TypedefType>(T2);
+ if (U1->getKeyword() != U2->getKeyword())
+ return false;
+ if (!IsStructurallyEquivalent(Context, U1->getQualifier(),
+ U2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, U1->getDecl(), U2->getDecl()))
+ return false;
+ if (U1->typeMatchesDecl() != U2->typeMatchesDecl())
+ return false;
+ if (!U1->typeMatchesDecl() &&
+ !IsStructurallyEquivalent(Context, U1->desugar(), U2->desugar()))
return false;
break;
+ }
case Type::TypeOfExpr:
if (!IsStructurallyEquivalent(
@@ -1286,10 +1291,20 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
case Type::Record:
case Type::Enum:
- if (!IsStructurallyEquivalent(Context, cast<TagType>(T1)->getDecl(),
- cast<TagType>(T2)->getDecl()))
+ case Type::InjectedClassName: {
+ const auto *TT1 = cast<TagType>(T1), *TT2 = cast<TagType>(T2);
+ if (TT1->getKeyword() != TT2->getKeyword())
+ return false;
+ if (TT1->isTagOwned() != TT2->isTagOwned())
+ return false;
+ if (!IsStructurallyEquivalent(Context, TT1->getQualifier(),
+ TT2->getQualifier()))
+ return false;
+ if (!IsStructurallyEquivalent(Context, TT1->getOriginalDecl(),
+ TT2->getOriginalDecl()))
return false;
break;
+ }
case Type::TemplateTypeParm: {
const auto *Parm1 = cast<TemplateTypeParmType>(T1);
@@ -1322,6 +1337,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
break;
}
+ case Type::SubstBuiltinTemplatePack: {
+ const auto *Subst1 = cast<SubstBuiltinTemplatePackType>(T1);
+ const auto *Subst2 = cast<SubstBuiltinTemplatePackType>(T2);
+ if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
+ Subst2->getArgumentPack()))
+ return false;
+ break;
+ }
case Type::SubstTemplateTypeParmPack: {
const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1);
const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2);
@@ -1348,33 +1371,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
break;
}
- case Type::Elaborated: {
- const auto *Elab1 = cast<ElaboratedType>(T1);
- const auto *Elab2 = cast<ElaboratedType>(T2);
- // CHECKME: what if a keyword is ElaboratedTypeKeyword::None or
- // ElaboratedTypeKeyword::Typename
- // ?
- if (Elab1->getKeyword() != Elab2->getKeyword())
- return false;
- if (!IsStructurallyEquivalent(Context, Elab1->getQualifier(),
- Elab2->getQualifier()))
- return false;
- if (!IsStructurallyEquivalent(Context, Elab1->getNamedType(),
- Elab2->getNamedType()))
- return false;
- break;
- }
-
- case Type::InjectedClassName: {
- const auto *Inj1 = cast<InjectedClassNameType>(T1);
- const auto *Inj2 = cast<InjectedClassNameType>(T2);
- if (!IsStructurallyEquivalent(Context,
- Inj1->getInjectedSpecializationType(),
- Inj2->getInjectedSpecializationType()))
- return false;
- break;
- }
-
case Type::DependentName: {
const auto *Typename1 = cast<DependentNameType>(T1);
const auto *Typename2 = cast<DependentNameType>(T2);
@@ -1549,8 +1545,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
// types
if (Field1->isAnonymousStructOrUnion() &&
Field2->isAnonymousStructOrUnion()) {
- RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
- RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getOriginalDecl();
+ RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getOriginalDecl();
return IsStructurallyEquivalent(Context, D1, D2);
}
@@ -1628,7 +1624,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
FieldDecl *Field1, FieldDecl *Field2) {
const auto *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
return IsStructurallyEquivalent(Context, Field1, Field2,
- Context.ToCtx.getTypeDeclType(Owner2));
+ Context.ToCtx.getCanonicalTagType(Owner2));
}
/// Determine structural equivalence of two methods.
@@ -1801,7 +1797,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Context.Complain) {
Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here)
<< D1->getDeclName() << (unsigned)D1->getTagKind();
@@ -1903,7 +1899,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
<< D2CXX->getNumBases();
@@ -1924,7 +1920,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base)
<< Base2->getType() << Base2->getSourceRange();
@@ -1940,7 +1936,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base)
<< Base2->isVirtual() << Base2->getSourceRange();
@@ -1962,7 +1958,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2CXX)
+ << Context.ToCtx.getCanonicalTagType(D2CXX)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend);
@@ -1975,7 +1971,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2CXX)
+ << Context.ToCtx.getCanonicalTagType(D2CXX)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
@@ -1989,7 +1985,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend);
@@ -2001,7 +1997,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
const CXXBaseSpecifier *Base1 = D1CXX->bases_begin();
Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base)
@@ -2013,7 +2009,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
}
// Check the fields for consistency.
- QualType D2Type = Context.ToCtx.getTypeDeclType(D2);
+ CanQualType D2Type = Context.ToCtx.getCanonicalTagType(D2);
RecordDecl::field_iterator Field2 = D2->field_begin(),
Field2End = D2->field_end();
for (RecordDecl::field_iterator Field1 = D1->field_begin(),
@@ -2024,7 +2020,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag1(Field1->getLocation(), diag::note_odr_field)
<< Field1->getDeclName() << Field1->getType();
@@ -2041,7 +2037,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Context.Complain) {
Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag2(Field2->getLocation(), diag::note_odr_field)
<< Field2->getDeclName() << Field2->getType();
@@ -2101,7 +2097,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag1(D1->getLocation(),
D1->isFixed()
@@ -2124,7 +2120,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag2(D2->getLocation(),
diag::note_odr_incompatible_fixed_underlying_type)
@@ -2162,7 +2158,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag1((*EC1)->getLocation(), diag::note_odr_enumerator)
<< (*EC1)->getDeclName() << toString((*EC1)->getInitVal(), 10);
@@ -2180,7 +2176,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Context.Diag2(D2->getLocation(),
Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag2((*EC2)->getLocation(), diag::note_odr_enumerator)
<< (*EC2)->getDeclName() << toString((*EC2)->getInitVal(), 10);
@@ -2198,7 +2194,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Context.Complain) {
Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic(
diag::err_odr_tag_type_inconsistent))
- << Context.ToCtx.getTypeDeclType(D2)
+ << Context.ToCtx.getCanonicalTagType(D2)
<< (&Context.FromCtx != &Context.ToCtx);
Context.Diag2((*EC2)->getLocation(), diag::note_odr_enumerator)
<< (*EC2)->getDeclName() << toString((*EC2)->getInitVal(), 10);
@@ -2595,7 +2591,7 @@ DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc,
UnsignedOrNone
StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
ASTContext &Context = Anon->getASTContext();
- QualType AnonTy = Context.getRecordType(Anon);
+ CanQualType AnonTy = Context.getCanonicalTagType(Anon);
const auto *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
if (!Owner)
@@ -2617,12 +2613,8 @@ StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
// If the field looks like this:
// struct { ... } A;
QualType FieldType = F->getType();
- // In case of nested structs.
- while (const auto *ElabType = dyn_cast<ElaboratedType>(FieldType))
- FieldType = ElabType->getNamedType();
-
if (const auto *RecType = dyn_cast<RecordType>(FieldType)) {
- const RecordDecl *RecDecl = RecType->getDecl();
+ const RecordDecl *RecDecl = RecType->getOriginalDecl();
if (RecDecl->getDeclContext() == Owner && !RecDecl->getIdentifier()) {
if (Context.hasSameType(FieldType, AnonTy))
break;
diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp
index 99916f5..d2f7fdb 100644
--- a/clang/lib/AST/ASTTypeTraits.cpp
+++ b/clang/lib/AST/ASTTypeTraits.cpp
@@ -194,8 +194,8 @@ void DynTypedNode::print(llvm::raw_ostream &OS,
else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>())
NNS->print(OS, PP);
else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) {
- if (const NestedNameSpecifier *NNS = NNSL->getNestedNameSpecifier())
- NNS->print(OS, PP);
+ if (NestedNameSpecifier NNS = NNSL->getNestedNameSpecifier())
+ NNS.print(OS, PP);
else
OS << "(empty NestedNameSpecifierLoc)";
} else if (const QualType *QT = get<QualType>())
@@ -234,13 +234,39 @@ void DynTypedNode::dump(llvm::raw_ostream &OS,
OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n";
}
-SourceRange DynTypedNode::getSourceRange() const {
+SourceRange DynTypedNode::getSourceRange(bool IncludeQualifier) const {
if (const CXXCtorInitializer *CCI = get<CXXCtorInitializer>())
return CCI->getSourceRange();
if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
return NNSL->getSourceRange();
- if (const TypeLoc *TL = get<TypeLoc>())
- return TL->getSourceRange();
+ if (const TypeLoc *TL = get<TypeLoc>()) {
+ if (IncludeQualifier)
+ return TL->getSourceRange();
+ switch (TL->getTypeLocClass()) {
+ case TypeLoc::DependentName:
+ return TL->castAs<DependentNameTypeLoc>().getNameLoc();
+ case TypeLoc::TemplateSpecialization: {
+ auto T = TL->castAs<TemplateSpecializationTypeLoc>();
+ return SourceRange(T.getTemplateNameLoc(), T.getEndLoc());
+ }
+ case TypeLoc::DependentTemplateSpecialization: {
+ auto T = TL->castAs<DependentTemplateSpecializationTypeLoc>();
+ return SourceRange(T.getTemplateNameLoc(), T.getEndLoc());
+ }
+ case TypeLoc::Enum:
+ case TypeLoc::Record:
+ case TypeLoc::InjectedClassName:
+ return TL->castAs<TagTypeLoc>().getNameLoc();
+ case TypeLoc::Typedef:
+ return TL->castAs<TypedefTypeLoc>().getNameLoc();
+ case TypeLoc::UnresolvedUsing:
+ return TL->castAs<UnresolvedUsingTypeLoc>().getNameLoc();
+ case TypeLoc::Using:
+ return TL->castAs<UsingTypeLoc>().getNameLoc();
+ default:
+ return TL->getSourceRange();
+ }
+ }
if (const Decl *D = get<Decl>())
return D->getSourceRange();
if (const Stmt *S = get<Stmt>())
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index cc99efa..56552f3 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -60,16 +60,18 @@ template <class Emitter> class OptionScope final {
public:
/// Root constructor, compiling or discarding primitives.
OptionScope(Compiler<Emitter> *Ctx, bool NewDiscardResult,
- bool NewInitializing)
+ bool NewInitializing, bool NewToLValue)
: Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
- OldInitializing(Ctx->Initializing) {
+ OldInitializing(Ctx->Initializing), OldToLValue(Ctx->ToLValue) {
Ctx->DiscardResult = NewDiscardResult;
Ctx->Initializing = NewInitializing;
+ Ctx->ToLValue = NewToLValue;
}
~OptionScope() {
Ctx->DiscardResult = OldDiscardResult;
Ctx->Initializing = OldInitializing;
+ Ctx->ToLValue = OldToLValue;
}
private:
@@ -78,6 +80,7 @@ private:
/// Old discard flag to restore.
bool OldDiscardResult;
bool OldInitializing;
+ bool OldToLValue;
};
template <class Emitter>
@@ -222,6 +225,9 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
switch (CE->getCastKind()) {
case CK_LValueToRValue: {
+ if (ToLValue && CE->getType()->isPointerType())
+ return this->delegate(SubExpr);
+
if (SubExpr->getType().isVolatileQualified())
return this->emitInvalidCast(CastKind::Volatile, /*Fatal=*/true, CE);
@@ -250,7 +256,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
// Prepare storage for the result.
if (!Initializing && !SubExprT) {
- std::optional<unsigned> LocalIndex = allocateLocal(SubExpr);
+ UnsignedOrNone LocalIndex = allocateLocal(SubExpr);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, CE))
@@ -553,9 +559,9 @@ 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()) {
- if (const auto *ET = CE->getType().getCanonicalType()->castAs<EnumType>();
- !ET->getDecl()->isFixed()) {
- if (!this->emitCheckEnumValue(*FromT, ET->getDecl(), CE))
+ const auto *ED = CE->getType()->castAsEnumDecl();
+ if (!ED->isFixed()) {
+ if (!this->emitCheckEnumValue(*FromT, ED, CE))
return false;
}
}
@@ -602,7 +608,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
// We're creating a complex value here, so we need to
// allocate storage for it.
if (!Initializing) {
- std::optional<unsigned> LocalIndex = allocateTemporary(CE);
+ UnsignedOrNone LocalIndex = allocateTemporary(CE);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, CE))
@@ -626,7 +632,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
assert(CE->getType()->isAnyComplexType());
assert(SubExpr->getType()->isAnyComplexType());
if (!Initializing) {
- std::optional<unsigned> LocalIndex = allocateLocal(CE);
+ UnsignedOrNone LocalIndex = allocateLocal(CE);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, CE))
@@ -666,12 +672,12 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
}
case CK_VectorSplat: {
- assert(!classify(CE->getType()));
- assert(classify(SubExpr->getType()));
+ assert(!canClassify(CE->getType()));
+ assert(canClassify(SubExpr->getType()));
assert(CE->getType()->isVectorType());
if (!Initializing) {
- std::optional<unsigned> LocalIndex = allocateLocal(CE);
+ UnsignedOrNone LocalIndex = allocateLocal(CE);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, CE))
@@ -715,7 +721,7 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
assert(CE->getType()->isVectorType());
if (!Initializing) {
- std::optional<unsigned> LocalIndex = allocateTemporary(CE);
+ UnsignedOrNone LocalIndex = allocateTemporary(CE);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, CE))
@@ -803,7 +809,7 @@ bool Compiler<Emitter>::VisitImaginaryLiteral(const ImaginaryLiteral *E) {
return true;
if (!Initializing) {
- std::optional<unsigned> LocalIndex = allocateTemporary(E);
+ UnsignedOrNone LocalIndex = allocateTemporary(E);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
@@ -904,7 +910,7 @@ bool Compiler<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
// We need a temporary variable holding our return value.
if (!Initializing) {
- std::optional<unsigned> ResultIndex = this->allocateLocal(BO);
+ UnsignedOrNone ResultIndex = this->allocateLocal(BO);
if (!this->emitGetPtrLocal(*ResultIndex, BO))
return false;
}
@@ -936,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;
@@ -1144,7 +1150,7 @@ template <class Emitter>
bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
// Prepare storage for result.
if (!Initializing) {
- std::optional<unsigned> LocalIndex = allocateTemporary(E);
+ UnsignedOrNone LocalIndex = allocateTemporary(E);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
@@ -1203,7 +1209,7 @@ bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
if (!LHSIsComplex) {
// This is using the RHS type for the fake-complex LHS.
- std::optional<unsigned> LocalIndex = allocateTemporary(RHS);
+ UnsignedOrNone LocalIndex = allocateTemporary(RHS);
if (!LocalIndex)
return false;
LHSOffset = *LocalIndex;
@@ -1370,23 +1376,27 @@ 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()) {
- std::optional<unsigned> LocalIndex = allocateTemporary(E);
+ if (!Initializing && !E->isCompoundAssignmentOp() && !E->isAssignmentOp()) {
+ UnsignedOrNone LocalIndex = allocateTemporary(E);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, 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())
@@ -1396,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);
@@ -1931,15 +1956,19 @@ bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
dyn_cast<EmbedExpr>(Init->IgnoreParenImpCasts())) {
PrimType TargetT = classifyPrim(Init->getType());
- auto Eval = [&](const Expr *Init, unsigned ElemIndex) {
- PrimType InitT = classifyPrim(Init->getType());
- if (!this->visit(Init))
- return false;
- if (InitT != TargetT) {
- if (!this->emitCast(InitT, TargetT, E))
+ auto Eval = [&](const IntegerLiteral *IL, unsigned ElemIndex) {
+ if (TargetT == PT_Float) {
+ if (!this->emitConst(IL->getValue(), classifyPrim(IL), Init))
+ return false;
+ const auto *Sem = &Ctx.getFloatSemantics(CAT->getElementType());
+ if (!this->emitCastIntegralFloating(classifyPrim(IL), Sem,
+ getFPOptions(E), E))
+ return false;
+ } else {
+ if (!this->emitConst(IL->getValue(), TargetT, Init))
return false;
}
- return this->emitInitElem(TargetT, ElemIndex, Init);
+ return this->emitInitElem(TargetT, ElemIndex, IL);
};
if (!EmbedS->doForEachDataElement(Eval, ElementIndex))
return false;
@@ -2061,24 +2090,36 @@ bool Compiler<Emitter>::visitArrayElemInit(unsigned ElemIndex, const Expr *Init,
template <class Emitter>
bool Compiler<Emitter>::visitCallArgs(ArrayRef<const Expr *> Args,
const FunctionDecl *FuncDecl,
- bool Activate) {
+ bool Activate, bool IsOperatorCall) {
assert(VarScope->getKind() == ScopeKind::Call);
- bool HasNonNullAttr = false;
llvm::BitVector NonNullArgs;
- if (FuncDecl && FuncDecl->hasAttr<NonNullAttr>()) {
- HasNonNullAttr = true;
+ if (FuncDecl && FuncDecl->hasAttr<NonNullAttr>())
NonNullArgs = collectNonNullArgs(FuncDecl, Args);
- }
+
+ bool ExplicitMemberFn = false;
+ if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(FuncDecl))
+ ExplicitMemberFn = MD->isExplicitObjectMemberFunction();
unsigned ArgIndex = 0;
for (const Expr *Arg : Args) {
- if (OptPrimType T = classify(Arg)) {
+ if (canClassify(Arg)) {
if (!this->visit(Arg))
return false;
} else {
- std::optional<unsigned> LocalIndex = allocateLocal(
- Arg, Arg->getType(), /*ExtendingDecl=*/nullptr, ScopeKind::Call);
+ DeclTy Source = Arg;
+ if (FuncDecl) {
+ // Try to use the parameter declaration instead of the argument
+ // expression as a source.
+ unsigned DeclIndex = ArgIndex - IsOperatorCall + ExplicitMemberFn;
+ if (DeclIndex < FuncDecl->getNumParams())
+ Source = FuncDecl->getParamDecl(ArgIndex - IsOperatorCall +
+ ExplicitMemberFn);
+ }
+
+ UnsignedOrNone LocalIndex =
+ allocateLocal(std::move(Source), Arg->getType(),
+ /*ExtendingDecl=*/nullptr, ScopeKind::Call);
if (!LocalIndex)
return false;
@@ -2094,7 +2135,7 @@ bool Compiler<Emitter>::visitCallArgs(ArrayRef<const Expr *> Args,
return false;
}
- if (HasNonNullAttr && NonNullArgs[ArgIndex]) {
+ if (!NonNullArgs.empty() && NonNullArgs[ArgIndex]) {
PrimType ArgT = classify(Arg).value_or(PT_Ptr);
if (ArgT == PT_Ptr) {
if (!this->emitCheckNonNullArg(ArgT, Arg))
@@ -2225,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;
@@ -2919,7 +2962,7 @@ bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
return false;
const Expr *Inner = E->getSubExpr()->skipRValueSubobjectAdjustments();
- if (std::optional<unsigned> LocalIndex =
+ if (UnsignedOrNone LocalIndex =
allocateLocal(E, Inner->getType(), E->getExtendingDecl())) {
InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalIndex));
if (!this->emitGetPtrLocal(*LocalIndex, E))
@@ -2966,20 +3009,25 @@ bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
if (T && !E->isLValue())
return this->delegate(Init);
- if (std::optional<unsigned> GlobalIndex = P.createGlobal(E)) {
- if (!this->emitGetPtrGlobal(*GlobalIndex, E))
- return false;
+ std::optional<unsigned> GlobalIndex = P.createGlobal(E);
+ if (!GlobalIndex)
+ return false;
- if (T) {
- if (!this->visit(Init))
- return false;
- return this->emitInitGlobal(*T, *GlobalIndex, E);
- }
+ if (!this->emitGetPtrGlobal(*GlobalIndex, E))
+ return false;
+
+ // Since this is a global variable, we might've already seen,
+ // don't do it again.
+ if (P.isGlobalInitialized(*GlobalIndex))
+ return true;
- return this->visitInitializer(Init) && this->emitFinishInit(E);
+ if (T) {
+ if (!this->visit(Init))
+ return false;
+ return this->emitInitGlobal(*T, *GlobalIndex, E);
}
- return false;
+ return this->visitInitializer(Init) && this->emitFinishInit(E);
}
// Otherwise, use a local variable.
@@ -2991,7 +3039,7 @@ bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
unsigned LocalIndex;
if (T)
LocalIndex = this->allocateLocalPrimitive(Init, *T, /*IsConst=*/false);
- else if (std::optional<unsigned> MaybeIndex = this->allocateLocal(Init))
+ else if (UnsignedOrNone MaybeIndex = this->allocateLocal(Init))
LocalIndex = *MaybeIndex;
else
return false;
@@ -3157,25 +3205,18 @@ bool Compiler<Emitter>::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
template <class Emitter>
bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) {
QualType T = E->getType();
- assert(!classify(T));
+ assert(!canClassify(T));
if (T->isRecordType()) {
const CXXConstructorDecl *Ctor = E->getConstructor();
- // Trivial copy/move constructor. Avoid copy.
- if (Ctor->isDefaulted() && Ctor->isCopyOrMoveConstructor() &&
- Ctor->isTrivial() &&
- E->getArg(0)->isTemporaryObject(Ctx.getASTContext(),
- T->getAsCXXRecordDecl()))
- return this->visitInitializer(E->getArg(0));
-
// If we're discarding a construct expression, we still need
// to allocate a variable and call the constructor and destructor.
if (DiscardResult) {
if (Ctor->isTrivial())
return true;
assert(!Initializing);
- std::optional<unsigned> LocalIndex = allocateLocal(E);
+ UnsignedOrNone LocalIndex = allocateLocal(E);
if (!LocalIndex)
return false;
@@ -3184,6 +3225,13 @@ bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) {
return false;
}
+ // Trivial copy/move constructor. Avoid copy.
+ if (Ctor->isDefaulted() && Ctor->isCopyOrMoveConstructor() &&
+ Ctor->isTrivial() &&
+ E->getArg(0)->isTemporaryObject(Ctx.getASTContext(),
+ T->getAsCXXRecordDecl()))
+ return this->visitInitializer(E->getArg(0));
+
// Zero initialization.
if (E->requiresZeroInitialization()) {
const Record *R = getRecord(E->getType());
@@ -3378,7 +3426,7 @@ bool Compiler<Emitter>::VisitCXXScalarValueInitExpr(
if (const auto *CT = Ty->getAs<ComplexType>()) {
if (!Initializing) {
- std::optional<unsigned> LocalIndex = allocateLocal(E);
+ UnsignedOrNone LocalIndex = allocateLocal(E);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
@@ -3401,7 +3449,7 @@ bool Compiler<Emitter>::VisitCXXScalarValueInitExpr(
if (const auto *VT = Ty->getAs<VectorType>()) {
// FIXME: Code duplication with the _Complex case above.
if (!Initializing) {
- std::optional<unsigned> LocalIndex = allocateLocal(E);
+ UnsignedOrNone LocalIndex = allocateLocal(E);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
@@ -3851,6 +3899,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);
@@ -4027,8 +4077,7 @@ bool Compiler<Emitter>::VisitExtVectorElementExpr(
// Now the vector variable for the return value.
if (!Initializing) {
- std::optional<unsigned> ResultIndex;
- ResultIndex = allocateLocal(E);
+ UnsignedOrNone ResultIndex = allocateLocal(E);
if (!ResultIndex)
return false;
if (!this->emitGetPtrLocal(*ResultIndex, E))
@@ -4089,8 +4138,7 @@ bool Compiler<Emitter>::VisitCXXStdInitializerListExpr(
PrimType SecondFieldT = classifyPrim(R->getField(1u)->Decl->getType());
if (isIntegralType(SecondFieldT)) {
- if (!this->emitConst(static_cast<APSInt>(ArrayType->getSize()),
- SecondFieldT, E))
+ if (!this->emitConst(ArrayType->getSize(), SecondFieldT, E))
return false;
return this->emitInitField(SecondFieldT, R->getField(1u)->Offset, E);
}
@@ -4100,7 +4148,7 @@ bool Compiler<Emitter>::VisitCXXStdInitializerListExpr(
return false;
if (!this->emitExpandPtr(E))
return false;
- if (!this->emitConst(static_cast<APSInt>(ArrayType->getSize()), PT_Uint64, E))
+ if (!this->emitConst(ArrayType->getSize(), PT_Uint64, E))
return false;
if (!this->emitArrayElemPtrPop(PT_Uint64, E))
return false;
@@ -4132,13 +4180,13 @@ bool Compiler<Emitter>::VisitStmtExpr(const StmtExpr *E) {
template <class Emitter> bool Compiler<Emitter>::discard(const Expr *E) {
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true,
- /*NewInitializing=*/false);
+ /*NewInitializing=*/false, /*ToLValue=*/false);
return this->Visit(E);
}
template <class Emitter> bool Compiler<Emitter>::delegate(const Expr *E) {
// We're basically doing:
- // OptionScope<Emitter> Scope(this, DicardResult, Initializing);
+ // OptionScope<Emitter> Scope(this, DicardResult, Initializing, ToLValue);
// but that's unnecessary of course.
return this->Visit(E);
}
@@ -4152,8 +4200,8 @@ template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) {
// Create local variable to hold the return value.
if (!E->isGLValue() && !E->getType()->isAnyComplexType() &&
- !classify(E->getType())) {
- std::optional<unsigned> LocalIndex = allocateLocal(E);
+ !canClassify(E->getType())) {
+ UnsignedOrNone LocalIndex = allocateLocal(E);
if (!LocalIndex)
return false;
@@ -4166,16 +4214,22 @@ template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) {
// Otherwise,we have a primitive return value, produce the value directly
// and push it on the stack.
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false,
- /*NewInitializing=*/false);
+ /*NewInitializing=*/false, /*ToLValue=*/ToLValue);
return this->Visit(E);
}
template <class Emitter>
bool Compiler<Emitter>::visitInitializer(const Expr *E) {
- assert(!classify(E->getType()));
+ assert(!canClassify(E->getType()));
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false,
- /*NewInitializing=*/true);
+ /*NewInitializing=*/true, /*ToLValue=*/false);
+ return this->Visit(E);
+}
+
+template <class Emitter> bool Compiler<Emitter>::visitAsLValue(const Expr *E) {
+ OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/false,
+ /*NewInitializing=*/false, /*ToLValue=*/true);
return this->Visit(E);
}
@@ -4379,7 +4433,7 @@ bool Compiler<Emitter>::visitZeroArrayInitializer(QualType T, const Expr *E) {
template <class Emitter>
bool Compiler<Emitter>::visitAssignment(const Expr *LHS, const Expr *RHS,
const Expr *E) {
- if (!classify(E->getType()))
+ if (!canClassify(E->getType()))
return false;
if (!this->visit(RHS))
@@ -4472,12 +4526,18 @@ bool Compiler<Emitter>::emitConst(T Value, const Expr *E) {
template <class Emitter>
bool Compiler<Emitter>::emitConst(const APSInt &Value, PrimType Ty,
const Expr *E) {
+ return this->emitConst(static_cast<const APInt &>(Value), Ty, E);
+}
+
+template <class Emitter>
+bool Compiler<Emitter>::emitConst(const APInt &Value, PrimType Ty,
+ const Expr *E) {
if (Ty == PT_IntAPS)
return this->emitConstIntAPS(Value, E);
if (Ty == PT_IntAP)
return this->emitConstIntAP(Value, E);
- if (Value.isSigned())
+ if (isSignedType(Ty))
return this->emitConst(Value.getSExtValue(), Ty, E);
return this->emitConst(Value.getZExtValue(), Ty, E);
}
@@ -4491,14 +4551,6 @@ template <class Emitter>
unsigned Compiler<Emitter>::allocateLocalPrimitive(
DeclTy &&Src, PrimType Ty, bool IsConst, const ValueDecl *ExtendingDecl,
ScopeKind SC, bool IsConstexprUnknown) {
- // Make sure we don't accidentally register the same decl twice.
- if (const auto *VD =
- dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
- assert(!P.getGlobal(VD));
- assert(!Locals.contains(VD));
- (void)VD;
- }
-
// FIXME: There are cases where Src.is<Expr*>() is wrong, e.g.
// (int){12} in C. Consider using Expr::isTemporaryObject() instead
// or isa<MaterializeTemporaryExpr>().
@@ -4516,23 +4568,15 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive(
}
template <class Emitter>
-std::optional<unsigned>
-Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty,
- const ValueDecl *ExtendingDecl, ScopeKind SC,
- bool IsConstexprUnknown) {
- // Make sure we don't accidentally register the same decl twice.
- if ([[maybe_unused]] const auto *VD =
- dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
- assert(!P.getGlobal(VD));
- assert(!Locals.contains(VD));
- }
-
+UnsignedOrNone Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty,
+ const ValueDecl *ExtendingDecl,
+ ScopeKind SC,
+ bool IsConstexprUnknown) {
const ValueDecl *Key = nullptr;
const Expr *Init = nullptr;
bool IsTemporary = false;
if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
Key = VD;
- Ty = VD->getType();
if (const auto *VarD = dyn_cast<VarDecl>(VD))
Init = VarD->getInit();
@@ -4561,7 +4605,7 @@ Compiler<Emitter>::allocateLocal(DeclTy &&Src, QualType Ty,
}
template <class Emitter>
-std::optional<unsigned> Compiler<Emitter>::allocateTemporary(const Expr *E) {
+UnsignedOrNone Compiler<Emitter>::allocateTemporary(const Expr *E) {
QualType Ty = E->getType();
assert(!Ty->isRecordType());
@@ -4586,13 +4630,13 @@ std::optional<unsigned> 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) {
if (const auto *RecordTy = getRecordTy(Ty))
- return getRecord(RecordTy->getDecl());
+ return getRecord(RecordTy->getOriginalDecl()->getDefinitionOrSelf());
return nullptr;
}
@@ -4640,7 +4684,7 @@ bool Compiler<Emitter>::visitExpr(const Expr *E, bool DestroyToplevelScope) {
// Expressions with a composite return type.
// For us, that means everything we don't
// have a PrimType for.
- if (std::optional<unsigned> LocalOffset = this->allocateLocal(E)) {
+ if (UnsignedOrNone LocalOffset = this->allocateLocal(E)) {
InitLinkScope<Emitter> ILS(this, InitLink::Temp(*LocalOffset));
if (!this->emitGetPtrLocal(*LocalOffset, E))
return false;
@@ -4837,7 +4881,7 @@ VarCreationState Compiler<Emitter>::visitVarDecl(const VarDecl *VD,
return this->emitSetLocal(*VarT, Offset, VD);
}
} else {
- if (std::optional<unsigned> Offset = this->allocateLocal(
+ if (UnsignedOrNone Offset = this->allocateLocal(
VD, VD->getType(), nullptr, ScopeKind::Block, IsConstexprUnknown)) {
if (!Init)
return true;
@@ -4952,7 +4996,6 @@ bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
template <class Emitter>
bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinID) {
-
if (BuiltinID == Builtin::BI__builtin_constant_p) {
// Void argument is always invalid and harder to handle later.
if (E->getArg(0)->getType()->isVoidType()) {
@@ -4990,18 +5033,38 @@ bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E,
// Non-primitive return type. Prepare storage.
if (!Initializing && !ReturnT && !ReturnType->isVoidType()) {
- std::optional<unsigned> LocalIndex = allocateLocal(E);
+ UnsignedOrNone LocalIndex = allocateLocal(E);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}
- if (!Context::isUnevaluatedBuiltin(BuiltinID)) {
- // Put arguments on the stack.
- for (const auto *Arg : E->arguments()) {
- if (!this->visit(Arg))
+ // Prepare function arguments including special cases.
+ switch (BuiltinID) {
+ case Builtin::BI__builtin_object_size:
+ case Builtin::BI__builtin_dynamic_object_size: {
+ assert(E->getNumArgs() == 2);
+ const Expr *Arg0 = E->getArg(0);
+ if (Arg0->isGLValue()) {
+ if (!this->visit(Arg0))
return false;
+
+ } else {
+ if (!this->visitAsLValue(Arg0))
+ return false;
+ }
+ if (!this->visit(E->getArg(1)))
+ return false;
+
+ } break;
+ default:
+ if (!Context::isUnevaluatedBuiltin(BuiltinID)) {
+ // Put arguments on the stack.
+ for (const auto *Arg : E->arguments()) {
+ if (!this->visit(Arg))
+ return false;
+ }
}
}
@@ -5066,7 +5129,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
// If we need to discard the return value but the function returns its
// value via an RVO pointer, we need to create one such pointer just
// for this call.
- if (std::optional<unsigned> LocalIndex = allocateLocal(E)) {
+ if (UnsignedOrNone LocalIndex = allocateLocal(E)) {
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}
@@ -5074,7 +5137,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
// We need the result. Prepare a pointer to return or
// dup the current one.
if (!Initializing) {
- if (std::optional<unsigned> LocalIndex = allocateLocal(E)) {
+ if (UnsignedOrNone LocalIndex = allocateLocal(E)) {
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}
@@ -5110,7 +5173,7 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
}
bool Devirtualized = false;
- std::optional<unsigned> CalleeOffset;
+ UnsignedOrNone CalleeOffset = std::nullopt;
// Add the (optional, implicit) This pointer.
if (const auto *MC = dyn_cast<CXXMemberCallExpr>(E)) {
if (!FuncDecl && classifyPrim(E->getCallee()) == PT_MemberPtr) {
@@ -5154,7 +5217,8 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
if (!this->emitCheckPseudoDtor(E))
return false;
const Expr *Base = PD->getBase();
- if (!Base->isGLValue())
+ // E.g. `using T = int; 0.~T();`.
+ if (OptPrimType BaseT = classify(Base); !BaseT || BaseT != PT_Ptr)
return this->discard(Base);
if (!this->visit(Base))
return false;
@@ -5169,7 +5233,8 @@ bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
return false;
}
- if (!this->visitCallArgs(Args, FuncDecl, IsAssignmentOperatorCall))
+ if (!this->visitCallArgs(Args, FuncDecl, IsAssignmentOperatorCall,
+ isa<CXXOperatorCallExpr>(E)))
return false;
// Undo the argument reversal we did earlier.
@@ -5185,6 +5250,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;
@@ -6516,7 +6587,7 @@ bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) {
OptPrimType ResT = classify(E);
auto prepareResult = [=]() -> bool {
if (!ResT && !Initializing) {
- std::optional<unsigned> LocalIndex = allocateLocal(SubExpr);
+ UnsignedOrNone LocalIndex = allocateLocal(SubExpr);
if (!LocalIndex)
return false;
return this->emitGetPtrLocal(*LocalIndex, E);
@@ -6634,7 +6705,7 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
return this->delegate(SubExpr);
if (!Initializing) {
- std::optional<unsigned> LocalIndex = allocateLocal(SubExpr);
+ UnsignedOrNone LocalIndex = allocateLocal(SubExpr);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
@@ -6752,6 +6823,22 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
// value.
bool IsReference = D->getType()->isReferenceType();
+ // Function parameters.
+ // Note that it's important to check them first since we might have a local
+ // variable created for a ParmVarDecl as well.
+ if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
+ if (Ctx.getLangOpts().CPlusPlus && !Ctx.getLangOpts().CPlusPlus11 &&
+ !D->getType()->isIntegralOrEnumerationType()) {
+ return this->emitInvalidDeclRef(cast<DeclRefExpr>(E),
+ /*InitializerFailed=*/false, E);
+ }
+ if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+ if (IsReference || !It->second.IsPtr)
+ return this->emitGetParam(classifyPrim(E), It->second.Offset, E);
+
+ return this->emitGetPtrParam(It->second.Offset, E);
+ }
+ }
// Local variables.
if (auto It = Locals.find(D); It != Locals.end()) {
const unsigned Offset = It->second.Offset;
@@ -6769,20 +6856,6 @@ bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
return this->emitGetPtrGlobal(*GlobalIndex, E);
}
- // Function parameters.
- if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) {
- if (Ctx.getLangOpts().CPlusPlus && !Ctx.getLangOpts().CPlusPlus11 &&
- !D->getType()->isIntegralOrEnumerationType()) {
- return this->emitInvalidDeclRef(cast<DeclRefExpr>(E),
- /*InitializerFailed=*/false, E);
- }
- if (auto It = this->Params.find(PVD); It != this->Params.end()) {
- if (IsReference || !It->second.IsPtr)
- return this->emitGetParam(classifyPrim(E), It->second.Offset, E);
-
- return this->emitGetPtrParam(It->second.Offset, E);
- }
- }
// In case we need to re-visit a declaration.
auto revisit = [&](const VarDecl *VD) -> bool {
@@ -7142,10 +7215,6 @@ bool Compiler<Emitter>::emitDestruction(const Descriptor *Desc,
assert(!Desc->isPrimitive());
assert(!Desc->isPrimitiveArray());
- // Can happen if the decl is invalid.
- if (Desc->isDummy())
- return true;
-
// Arrays.
if (Desc->isArray()) {
const Descriptor *ElemDesc = Desc->ElemDesc;
@@ -7240,7 +7309,7 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
// Prepare storage for the result in case we discard.
if (DiscardResult && !Initializing && !ToT) {
- std::optional<unsigned> LocalIndex = allocateLocal(E);
+ UnsignedOrNone LocalIndex = allocateLocal(E);
if (!LocalIndex)
return false;
if (!this->emitGetPtrLocal(*LocalIndex, E))
diff --git a/clang/lib/AST/ByteCode/Compiler.h b/clang/lib/AST/ByteCode/Compiler.h
index ee8327d..475faee 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -256,6 +256,8 @@ protected:
OptPrimType classify(const Expr *E) const { return Ctx.classify(E); }
OptPrimType classify(QualType Ty) const { return Ctx.classify(Ty); }
+ bool canClassify(const Expr *E) const { return Ctx.canClassify(E); }
+ bool canClassify(QualType T) const { return Ctx.canClassify(T); }
/// Classifies a known primitive type.
PrimType classifyPrim(QualType Ty) const {
@@ -280,6 +282,7 @@ protected:
/// been created. visitInitializer() then relies on a pointer to this
/// variable being on top of the stack.
bool visitInitializer(const Expr *E);
+ bool visitAsLValue(const Expr *E);
/// Evaluates an expression for side effects and discards the result.
bool discard(const Expr *E);
/// Just pass evaluation on to \p E. This leaves all the parsing flags
@@ -304,7 +307,7 @@ protected:
bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init,
OptPrimType InitT);
bool visitCallArgs(ArrayRef<const Expr *> Args, const FunctionDecl *FuncDecl,
- bool Activate);
+ bool Activate, bool IsOperatorCall);
/// Creates a local primitive value.
unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,
@@ -313,11 +316,11 @@ protected:
bool IsConstexprUnknown = false);
/// Allocates a space storing a local given its type.
- std::optional<unsigned>
- allocateLocal(DeclTy &&Decl, QualType Ty = QualType(),
- const ValueDecl *ExtendingDecl = nullptr,
- ScopeKind = ScopeKind::Block, bool IsConstexprUnknown = false);
- std::optional<unsigned> allocateTemporary(const Expr *E);
+ UnsignedOrNone allocateLocal(DeclTy &&Decl, QualType Ty = QualType(),
+ const ValueDecl *ExtendingDecl = nullptr,
+ ScopeKind = ScopeKind::Block,
+ bool IsConstexprUnknown = false);
+ UnsignedOrNone allocateTemporary(const Expr *E);
private:
friend class VariableScope<Emitter>;
@@ -344,9 +347,10 @@ private:
/// Emits an APSInt constant.
bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);
+ bool emitConst(const llvm::APInt &Value, PrimType Ty, const Expr *E);
bool emitConst(const llvm::APSInt &Value, const Expr *E);
bool emitConst(const llvm::APInt &Value, const Expr *E) {
- return emitConst(static_cast<llvm::APSInt>(Value), E);
+ return emitConst(Value, classifyPrim(E), E);
}
/// Emits an integer constant.
@@ -424,6 +428,7 @@ protected:
bool DiscardResult = false;
bool InStmtExpr = false;
+ bool ToLValue = false;
/// Flag inidicating if we're initializing an already created
/// variable. This is set in visitInitializer().
@@ -563,7 +568,7 @@ public:
void addLocal(const Scope::Local &Local) override {
if (!Idx) {
- Idx = this->Ctx->Descriptors.size();
+ Idx = static_cast<unsigned>(this->Ctx->Descriptors.size());
this->Ctx->Descriptors.emplace_back();
this->Ctx->emitInitScope(*Idx, {});
}
@@ -611,7 +616,7 @@ public:
}
/// Index of the scope in the chain.
- std::optional<unsigned> Idx;
+ UnsignedOrNone Idx = std::nullopt;
};
/// Scope for storage declared in a compound statement.
diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp
index f7f528c..8598996 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->getDecl();
+ if (const auto *D = T->getAsEnumDecl()) {
if (!D->isComplete())
return std::nullopt;
return classify(D->getIntegerType());
@@ -398,17 +397,11 @@ const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {
}
bool Context::Run(State &Parent, const Function *Func) {
-
- {
- InterpState State(Parent, *P, Stk, *this, Func);
- if (Interpret(State)) {
- assert(Stk.empty());
- return true;
- }
- // State gets destroyed here, so the Stk.clear() below doesn't accidentally
- // remove values the State's destructor might access.
+ InterpState State(Parent, *P, Stk, *this, Func);
+ if (Interpret(State)) {
+ assert(Stk.empty());
+ return true;
}
-
Stk.clear();
return false;
}
@@ -501,7 +494,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) {
// elsewhere in the code.
QualType Ty = FuncDecl->getReturnType();
bool HasRVO = false;
- if (!Ty->isVoidType() && !classify(Ty)) {
+ if (!Ty->isVoidType() && !canClassify(Ty)) {
HasRVO = true;
ParamTypes.push_back(PT_Ptr);
ParamOffsets.push_back(ParamOffset);
diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h
index 1c084ac..fa98498 100644
--- a/clang/lib/AST/ByteCode/Context.h
+++ b/clang/lib/AST/ByteCode/Context.h
@@ -30,7 +30,7 @@ namespace interp {
class Function;
class Program;
class State;
-enum PrimType : unsigned;
+enum PrimType : uint8_t;
struct ParamOffset {
unsigned Offset;
@@ -93,6 +93,25 @@ public:
return classify(E->getType());
}
+ bool canClassify(QualType T) {
+ if (const auto *BT = dyn_cast<BuiltinType>(T)) {
+ if (BT->isInteger() || BT->isFloatingPoint())
+ return true;
+ if (BT->getKind() == BuiltinType::Bool)
+ return true;
+ }
+
+ if (T->isArrayType() || T->isRecordType() || T->isAnyComplexType() ||
+ T->isVectorType())
+ return false;
+ return classify(T) != std::nullopt;
+ }
+ bool canClassify(const Expr *E) {
+ if (E->isGLValue())
+ return true;
+ return canClassify(E->getType());
+ }
+
const CXXMethodDecl *
getOverridingFunction(const CXXRecordDecl *DynamicDecl,
const CXXRecordDecl *StaticDecl,
diff --git a/clang/lib/AST/ByteCode/Descriptor.cpp b/clang/lib/AST/ByteCode/Descriptor.cpp
index 629c1ff..647de56 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");
}
@@ -367,7 +364,7 @@ Descriptor::Descriptor(const DeclTy &D, const Record *R, MetadataSize MD,
Descriptor::Descriptor(const DeclTy &D, MetadataSize MD)
: Source(D), ElemSize(1), Size(1), MDSize(MD.value_or(0)),
AllocSize(MDSize), ElemRecord(nullptr), IsConst(true), IsMutable(false),
- IsTemporary(false), IsDummy(true) {
+ IsTemporary(false) {
assert(Source && "Missing source");
}
@@ -377,12 +374,14 @@ QualType Descriptor::getType() const {
if (const auto *D = asValueDecl())
return D->getType();
if (const auto *T = dyn_cast_if_present<TypeDecl>(asDecl()))
- return QualType(T->getTypeForDecl(), 0);
+ return T->getASTContext().getTypeDeclType(T);
// The Source sometimes has a different type than the once
// we really save. Try to consult the Record first.
- if (isRecord())
- return QualType(ElemRecord->getDecl()->getTypeForDecl(), 0);
+ if (isRecord()) {
+ const RecordDecl *RD = ElemRecord->getDecl();
+ return RD->getASTContext().getCanonicalTagType(RD);
+ }
if (const auto *E = asExpr())
return E->getType();
llvm_unreachable("Invalid descriptor type");
@@ -453,7 +452,7 @@ SourceInfo Descriptor::getLoc() const {
}
bool Descriptor::hasTrivialDtor() const {
- if (isPrimitive() || isPrimitiveArray() || isDummy())
+ if (isPrimitive() || isPrimitiveArray())
return true;
if (isRecord()) {
@@ -462,17 +461,16 @@ bool Descriptor::hasTrivialDtor() const {
return !Dtor || Dtor->isTrivial();
}
+ if (!ElemDesc)
+ return true;
// Composite arrays.
- assert(ElemDesc);
return ElemDesc->hasTrivialDtor();
}
bool Descriptor::isUnion() const { return isRecord() && ElemRecord->isUnion(); }
InitMap::InitMap(unsigned N)
- : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {
- std::fill_n(data(), numFields(N), 0);
-}
+ : UninitFields(N), Data(std::make_unique<T[]>(numFields(N))) {}
bool InitMap::initializeElement(unsigned I) {
unsigned Bucket = I / PER_FIELD;
diff --git a/clang/lib/AST/ByteCode/Descriptor.h b/clang/lib/AST/ByteCode/Descriptor.h
index cd34e11..90dc2b4 100644
--- a/clang/lib/AST/ByteCode/Descriptor.h
+++ b/clang/lib/AST/ByteCode/Descriptor.h
@@ -24,7 +24,7 @@ class Record;
class SourceInfo;
struct InitMap;
struct Descriptor;
-enum PrimType : unsigned;
+enum PrimType : uint8_t;
using DeclTy = llvm::PointerUnion<const Decl *, const Expr *>;
using InitMapPtr = std::optional<std::pair<bool, std::shared_ptr<InitMap>>>;
@@ -166,8 +166,6 @@ public:
const bool IsVolatile = false;
/// Flag indicating if the block is an array.
const bool IsArray = false;
- /// Flag indicating if this is a dummy descriptor.
- bool IsDummy = false;
bool IsConstexprUnknown = false;
/// Storage management methods.
@@ -203,9 +201,6 @@ public:
/// Allocates a dummy descriptor.
Descriptor(const DeclTy &D, MetadataSize MD = std::nullopt);
- /// Make this descriptor a dummy descriptor.
- void makeDummy() { IsDummy = true; }
-
QualType getType() const;
QualType getElemQualType() const;
QualType getDataType(const ASTContext &Ctx) const;
@@ -273,8 +268,6 @@ public:
bool isRecord() const { return !IsArray && ElemRecord; }
/// Checks if the descriptor is of a union.
bool isUnion() const;
- /// Checks if this is a dummy descriptor.
- bool isDummy() const { return IsDummy; }
/// Whether variables of this descriptor need their destructor called or not.
bool hasTrivialDtor() const;
diff --git a/clang/lib/AST/ByteCode/Disasm.cpp b/clang/lib/AST/ByteCode/Disasm.cpp
index 5049a65..ac904d3 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -338,7 +338,7 @@ LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
}
OS << "\n";
- if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) {
+ if (GP.isInitialized() && Desc->isPrimitive() && !G->block()->isDummy()) {
OS << " ";
{
ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false});
@@ -394,8 +394,6 @@ LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const {
else if (isUnknownSizeArray())
OS << " unknown-size-array";
- if (isDummy())
- OS << " dummy";
if (IsConstexprUnknown)
OS << " constexpr-unknown";
}
@@ -541,50 +539,27 @@ LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
else
OS << "-\n";
OS << " Pointers: " << NPointers << "\n";
- OS << " Dead: " << IsDead << "\n";
+ OS << " Dead: " << isDead() << "\n";
OS << " Static: " << IsStatic << "\n";
- OS << " Extern: " << IsExtern << "\n";
+ OS << " Extern: " << isExtern() << "\n";
OS << " Initialized: " << IsInitialized << "\n";
- OS << " Weak: " << IsWeak << "\n";
- OS << " Dynamic: " << IsDynamic << "\n";
+ OS << " Weak: " << isWeak() << "\n";
+ OS << " Dummy: " << isDummy() << '\n';
+ OS << " Dynamic: " << isDynamic() << "\n";
}
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/DynamicAllocator.cpp b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
index 9b8b664..4fedac6 100644
--- a/clang/lib/AST/ByteCode/DynamicAllocator.cpp
+++ b/clang/lib/AST/ByteCode/DynamicAllocator.cpp
@@ -13,25 +13,6 @@
using namespace clang;
using namespace clang::interp;
-// FIXME: There is a peculiar problem with the way we track pointers
-// to blocks and the way we allocate dynamic memory.
-//
-// When we have code like this:
-// while (true) {
-// char *buffer = new char[1024];
-// delete[] buffer;
-// }
-//
-// We have a local variable 'buffer' pointing to the heap allocated memory.
-// When deallocating the memory via delete[], that local variable still
-// points to the memory, which means we will create a DeadBlock for it and move
-// it over to that block, essentially duplicating the allocation. Moving
-// the data is also slow.
-//
-// However, when we actually try to access the allocation after it has been
-// freed, we need the block to still exist (alive or dead) so we can tell
-// that it's a dynamic allocation.
-
DynamicAllocator::~DynamicAllocator() { cleanup(); }
void DynamicAllocator::cleanup() {
@@ -42,12 +23,15 @@ void DynamicAllocator::cleanup() {
for (auto &Iter : AllocationSites) {
auto &AllocSite = Iter.second;
for (auto &Alloc : AllocSite.Allocations) {
- Block *B = reinterpret_cast<Block *>(Alloc.Memory.get());
+ Block *B = Alloc.block();
+ assert(!B->isDead());
+ assert(B->isInitialized());
B->invokeDtor();
+
if (B->hasPointers()) {
while (B->Pointers) {
Pointer *Next = B->Pointers->asBlockPointer().Next;
- B->Pointers->PointeeStorage.BS.Pointee = nullptr;
+ B->Pointers->BS.Pointee = nullptr;
B->Pointers = Next;
}
B->Pointers = nullptr;
@@ -89,6 +73,12 @@ Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID,
assert(D);
assert(D->asExpr());
+ // Garbage collection. Remove all dead allocations that don't have pointers to
+ // them anymore.
+ llvm::erase_if(DeadAllocations, [](Allocation &Alloc) -> bool {
+ return !Alloc.block()->hasPointers();
+ });
+
auto Memory =
std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize());
auto *B = new (Memory.get()) Block(EvalID, D, /*isStatic=*/false);
@@ -111,13 +101,17 @@ Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID,
ID->LifeState =
AllocForm == Form::Operator ? Lifetime::Ended : Lifetime::Started;
- B->IsDynamic = true;
-
- if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end())
+ if (auto It = AllocationSites.find(D->asExpr());
+ It != AllocationSites.end()) {
It->second.Allocations.emplace_back(std::move(Memory));
- else
+ B->setDynAllocId(It->second.NumAllocs);
+ ++It->second.NumAllocs;
+ } else {
AllocationSites.insert(
{D->asExpr(), AllocationSite(std::move(Memory), AllocForm)});
+ B->setDynAllocId(0);
+ }
+ assert(B->isDynamic());
return B;
}
@@ -128,23 +122,39 @@ bool DynamicAllocator::deallocate(const Expr *Source,
return false;
auto &Site = It->second;
- assert(Site.size() > 0);
+ assert(!Site.empty());
// Find the Block to delete.
- auto AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
- const Block *B = reinterpret_cast<const Block *>(A.Memory.get());
- return BlockToDelete == B;
+ auto *AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
+ return BlockToDelete == A.block();
});
assert(AllocIt != Site.Allocations.end());
- Block *B = reinterpret_cast<Block *>(AllocIt->Memory.get());
+ Block *B = AllocIt->block();
+ assert(B->isInitialized());
+ assert(!B->isDead());
B->invokeDtor();
- S.deallocate(B);
- Site.Allocations.erase(AllocIt);
+ // Almost all our dynamic allocations have a pointer pointing to them
+ // when we deallocate them, since otherwise we can't call delete() at all.
+ // This means that we would usually need to create DeadBlocks for all of them.
+ // To work around that, we instead mark them as dead without moving the data
+ // over to a DeadBlock and simply keep the block in a separate DeadAllocations
+ // list.
+ if (B->hasPointers()) {
+ B->AccessFlags |= Block::DeadFlag;
+ DeadAllocations.push_back(std::move(*AllocIt));
+ Site.Allocations.erase(AllocIt);
+
+ if (Site.size() == 0)
+ AllocationSites.erase(It);
+ return true;
+ }
- if (Site.size() == 0)
+ // Get rid of the allocation altogether.
+ Site.Allocations.erase(AllocIt);
+ if (Site.empty())
AllocationSites.erase(It);
return true;
diff --git a/clang/lib/AST/ByteCode/DynamicAllocator.h b/clang/lib/AST/ByteCode/DynamicAllocator.h
index cff09bf..ab1058b 100644
--- a/clang/lib/AST/ByteCode/DynamicAllocator.h
+++ b/clang/lib/AST/ByteCode/DynamicAllocator.h
@@ -43,18 +43,22 @@ private:
std::unique_ptr<std::byte[]> Memory;
Allocation(std::unique_ptr<std::byte[]> Memory)
: Memory(std::move(Memory)) {}
+ Block *block() const { return reinterpret_cast<Block *>(Memory.get()); }
};
struct AllocationSite {
llvm::SmallVector<Allocation> Allocations;
+ unsigned NumAllocs = 0;
Form AllocForm;
AllocationSite(std::unique_ptr<std::byte[]> Memory, Form AllocForm)
: AllocForm(AllocForm) {
Allocations.push_back({std::move(Memory)});
+ ++NumAllocs;
}
size_t size() const { return Allocations.size(); }
+ bool empty() const { return Allocations.empty(); }
};
public:
@@ -65,8 +69,6 @@ public:
void cleanup();
- unsigned getNumAllocations() const { return AllocationSites.size(); }
-
/// Allocate ONE element of the given descriptor.
Block *allocate(const Descriptor *D, unsigned EvalID, Form AllocForm);
/// Allocate \p NumElements primitive elements of the given type.
@@ -96,8 +98,13 @@ public:
return llvm::make_range(AllocationSites.begin(), AllocationSites.end());
}
+ bool hasAllocations() const { return !AllocationSites.empty(); }
+
private:
llvm::DenseMap<const Expr *, AllocationSite> AllocationSites;
+ // Allocations that have already been deallocated but had pointers
+ // to them.
+ llvm::SmallVector<Allocation> DeadAllocations;
using PoolAllocTy = llvm::BumpPtrAllocator;
PoolAllocTy DescAllocator;
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp
index 976b7c0..2860a09 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.cpp
+++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp
@@ -98,10 +98,7 @@ bool EvalEmitter::interpretCall(const FunctionDecl *FD, const Expr *E) {
this->Params.insert({PD, {0, false}});
}
- if (!this->visit(E))
- return false;
- PrimType T = Ctx.classify(E).value_or(PT_Ptr);
- return this->emitPop(T, E);
+ return this->visitExpr(E, /*DestroyToplevelScope=*/false);
}
void EvalEmitter::emitLabel(LabelTy Label) { CurrentLabel = Label; }
@@ -187,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;
}
@@ -198,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;
}
@@ -216,10 +213,8 @@ template <> bool EvalEmitter::emitRet<PT_Ptr>(const SourceInfo &Info) {
if (!Ptr.isZero() && !Ptr.isDereferencable())
return false;
- if (S.getLangOpts().CPlusPlus11 && Ptr.isBlockPointer() &&
- !CheckFinalLoad(S, OpPC, Ptr)) {
+ if (!Ptr.isZero() && !CheckFinalLoad(S, OpPC, Ptr))
return false;
- }
// Never allow reading from a non-const pointer, unless the memory
// has been created in this evaluation.
@@ -229,7 +224,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;
}
@@ -238,14 +233,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;
@@ -266,7 +261,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;
}
@@ -292,7 +287,7 @@ bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
Block *B = getLocal(I);
- if (!CheckLocalLoad(S, OpPC, Pointer(B)))
+ if (!CheckLocalLoad(S, OpPC, B))
return false;
S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));
diff --git a/clang/lib/AST/ByteCode/EvaluationResult.cpp b/clang/lib/AST/ByteCode/EvaluationResult.cpp
index b11531f..ba81878 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 3b6c65ef..c296cc9 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/Function.h b/clang/lib/AST/ByteCode/Function.h
index 92363b6..af429b7 100644
--- a/clang/lib/AST/ByteCode/Function.h
+++ b/clang/lib/AST/ByteCode/Function.h
@@ -28,7 +28,7 @@ namespace interp {
class Program;
class ByteCodeEmitter;
class Pointer;
-enum PrimType : uint32_t;
+enum PrimType : uint8_t;
/// Describes a scope block.
///
diff --git a/clang/lib/AST/ByteCode/Integral.h b/clang/lib/AST/ByteCode/Integral.h
index af5cd2d..1318024 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 eb4e480..06b2bdc 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -211,25 +211,26 @@ static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
S.Note(VD->getLocation(), diag::note_declared_at);
}
-static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B,
AccessKinds AK) {
- if (auto ID = Ptr.getDeclID()) {
- if (!Ptr.isStaticTemporary())
+ if (B->getDeclID()) {
+ if (!(B->isStatic() && B->isTemporary()))
return true;
const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(
- Ptr.getDeclDesc()->asExpr());
+ B->getDescriptor()->asExpr());
if (!MTE)
return true;
// FIXME(perf): Since we do this check on every Load from a static
// temporary, it might make sense to cache the value of the
// isUsableInConstantExpressions call.
- if (!MTE->isUsableInConstantExpressions(S.getASTContext()) &&
- Ptr.block()->getEvalID() != S.Ctx.getEvalID()) {
+ if (B->getEvalID() != S.Ctx.getEvalID() &&
+ !MTE->isUsableInConstantExpressions(S.getASTContext())) {
const SourceInfo &E = S.Current->getSource(OpPC);
S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
- S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
+ S.Note(B->getDescriptor()->getLocation(),
+ diag::note_constexpr_temporary_here);
return false;
}
}
@@ -517,7 +518,7 @@ bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
- if (!Ptr.isOnePastEnd())
+ if (!Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray())
return true;
if (S.getLangOpts().CPlusPlus) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
@@ -529,7 +530,7 @@ bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
CheckSubobjectKind CSK) {
- if (!Ptr.isElementPastEnd())
+ if (!Ptr.isElementPastEnd() && !Ptr.isZeroSizeArray())
return true;
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_past_end_subobject)
@@ -658,17 +659,19 @@ static bool CheckVolatile(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}
-bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK) {
+bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK) {
assert(Ptr.isLive());
+ assert(!Ptr.isInitialized());
+ return DiagnoseUninitialized(S, OpPC, Ptr.isExtern(), Ptr.getDeclDesc(), AK);
+}
- if (Ptr.isInitialized())
- return true;
-
- if (Ptr.isExtern() && S.checkingPotentialConstantExpression())
+bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,
+ const Descriptor *Desc, AccessKinds AK) {
+ if (Extern && S.checkingPotentialConstantExpression())
return false;
- if (const auto *VD = Ptr.getDeclDesc()->asVarDecl();
+ if (const auto *VD = Desc->asVarDecl();
VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {
if (VD == S.EvaluatingDecl &&
@@ -703,9 +706,9 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}
-static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+static bool CheckLifetime(InterpState &S, CodePtr OpPC, Lifetime LT,
AccessKinds AK) {
- if (Ptr.getLifetime() == Lifetime::Started)
+ if (LT == Lifetime::Started)
return true;
if (!S.checkingPotentialConstantExpression()) {
@@ -715,11 +718,11 @@ static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
return false;
}
-static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- if (!Ptr.isWeak())
+static bool CheckWeak(InterpState &S, CodePtr OpPC, const Block *B) {
+ if (!B->isWeak())
return true;
- const auto *VD = Ptr.getDeclDesc()->asVarDecl();
+ const auto *VD = B->getDescriptor()->asVarDecl();
assert(VD);
S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_var_init_weak)
<< VD;
@@ -732,57 +735,100 @@ static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
// ones removed that are impossible on primitive global values.
// For example, since those can't be members of structs, they also can't
// be mutable.
-bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- if (!CheckExtern(S, OpPC, Ptr))
- return false;
- if (!CheckConstant(S, OpPC, Ptr))
- return false;
- if (!CheckDummy(S, OpPC, Ptr, AK_Read))
- return false;
- if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
- return false;
- if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
+bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
+ const auto &Desc =
+ *reinterpret_cast<const GlobalInlineDescriptor *>(B->rawData());
+ if (!B->isAccessible()) {
+ if (!CheckExtern(S, OpPC, Pointer(const_cast<Block *>(B))))
+ return false;
+ if (!CheckDummy(S, OpPC, B, AK_Read))
+ return false;
+ return CheckWeak(S, OpPC, B);
+ }
+
+ if (!CheckConstant(S, OpPC, B->getDescriptor()))
return false;
- if (!CheckWeak(S, OpPC, Ptr))
+ if (Desc.InitState != GlobalInitState::Initialized)
+ return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(),
+ AK_Read);
+ if (!CheckTemporary(S, OpPC, B, AK_Read))
return false;
- if (!CheckVolatile(S, OpPC, Ptr, AK_Read))
+ if (B->getDescriptor()->IsVolatile) {
+ if (!S.getLangOpts().CPlusPlus)
+ return Invalid(S, OpPC);
+
+ const ValueDecl *D = B->getDescriptor()->asValueDecl();
+ S.FFDiag(S.Current->getLocation(OpPC),
+ diag::note_constexpr_access_volatile_obj, 1)
+ << AK_Read << 1 << D;
+ S.Note(D->getLocation(), diag::note_constexpr_volatile_here) << 1;
return false;
+ }
return true;
}
// Similarly, for local loads.
-bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- if (!CheckLifetime(S, OpPC, Ptr, AK_Read))
- return false;
- if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
- return false;
- if (!CheckVolatile(S, OpPC, Ptr, AK_Read))
+bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
+ assert(!B->isExtern());
+ const auto &Desc = *reinterpret_cast<const InlineDescriptor *>(B->rawData());
+ if (!CheckLifetime(S, OpPC, Desc.LifeState, AK_Read))
+ return false;
+ if (!Desc.IsInitialized)
+ return DiagnoseUninitialized(S, OpPC, /*Extern=*/false, B->getDescriptor(),
+ AK_Read);
+ if (B->getDescriptor()->IsVolatile) {
+ if (!S.getLangOpts().CPlusPlus)
+ return Invalid(S, OpPC);
+
+ const ValueDecl *D = B->getDescriptor()->asValueDecl();
+ S.FFDiag(S.Current->getLocation(OpPC),
+ diag::note_constexpr_access_volatile_obj, 1)
+ << AK_Read << 1 << D;
+ S.Note(D->getLocation(), diag::note_constexpr_volatile_here) << 1;
return false;
+ }
return true;
}
bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
- if (!CheckLive(S, OpPC, Ptr, AK))
- return false;
- if (!CheckExtern(S, OpPC, Ptr))
+ if (!Ptr.isBlockPointer()) {
+ if (Ptr.isZero()) {
+ const auto &Src = S.Current->getSource(OpPC);
+
+ if (Ptr.isField())
+ S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
+ else
+ S.FFDiag(Src, diag::note_constexpr_access_null) << AK;
+ }
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;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckDummy(S, OpPC, Ptr.block(), AK))
+ return false;
+ if (!CheckWeak(S, OpPC, Ptr.block()))
+ return false;
+ }
+
if (!CheckConstant(S, OpPC, Ptr))
return false;
- if (!CheckDummy(S, OpPC, Ptr, AK))
- return false;
if (!CheckRange(S, OpPC, Ptr, AK))
return false;
if (!CheckActive(S, OpPC, Ptr, AK))
return false;
- if (!CheckLifetime(S, OpPC, Ptr, AK))
- return false;
- if (!CheckInitialized(S, OpPC, Ptr, AK))
- return false;
- if (!CheckTemporary(S, OpPC, Ptr, AK))
+ if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK))
return false;
- if (!CheckWeak(S, OpPC, Ptr))
+ if (!Ptr.isInitialized())
+ return DiagnoseUninitialized(S, OpPC, Ptr, AK);
+ if (!CheckTemporary(S, OpPC, Ptr.block(), AK))
return false;
+
if (!CheckMutable(S, OpPC, Ptr))
return false;
if (!CheckVolatile(S, OpPC, Ptr, AK))
@@ -793,26 +839,30 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
/// This is not used by any of the opcodes directly. It's used by
/// EvalEmitter to do the final lvalue-to-rvalue conversion.
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- if (!CheckLive(S, OpPC, Ptr, AK_Read))
+ assert(!Ptr.isZero());
+ if (!Ptr.isBlockPointer())
return false;
+
+ if (!Ptr.block()->isAccessible()) {
+ if (!CheckLive(S, OpPC, Ptr, AK_Read))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckDummy(S, OpPC, Ptr.block(), AK_Read))
+ return false;
+ return CheckWeak(S, OpPC, Ptr.block());
+ }
+
if (!CheckConstant(S, OpPC, Ptr))
return false;
- if (!CheckDummy(S, OpPC, Ptr, AK_Read))
- return false;
- if (!CheckExtern(S, OpPC, Ptr))
- return false;
- if (!CheckRange(S, OpPC, Ptr, AK_Read))
- return false;
if (!CheckActive(S, OpPC, Ptr, AK_Read))
return false;
- if (!CheckLifetime(S, OpPC, Ptr, AK_Read))
+ if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Read))
return false;
- if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
- return false;
- if (!CheckTemporary(S, OpPC, Ptr, AK_Read))
- return false;
- if (!CheckWeak(S, OpPC, Ptr))
+ if (!Ptr.isInitialized())
+ return DiagnoseUninitialized(S, OpPC, Ptr, AK_Read);
+ if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Read))
return false;
if (!CheckMutable(S, OpPC, Ptr))
return false;
@@ -820,13 +870,17 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
}
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
- if (!CheckLive(S, OpPC, Ptr, AK_Assign))
- return false;
- if (!CheckDummy(S, OpPC, Ptr, AK_Assign))
- return false;
- if (!CheckLifetime(S, OpPC, Ptr, AK_Assign))
+ if (!Ptr.isBlockPointer())
return false;
- if (!CheckExtern(S, OpPC, Ptr))
+
+ if (!Ptr.block()->isAccessible()) {
+ if (!CheckLive(S, OpPC, Ptr, AK_Assign))
+ return false;
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ return CheckDummy(S, OpPC, Ptr.block(), AK_Assign);
+ }
+ if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Assign))
return false;
if (!CheckRange(S, OpPC, Ptr, AK_Assign))
return false;
@@ -1098,13 +1152,11 @@ bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
return diagnoseUnknownDecl(S, OpPC, D);
}
-bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK) {
- if (!Ptr.isDummy())
+bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK) {
+ if (!B->isDummy())
return true;
- const Descriptor *Desc = Ptr.getDeclDesc();
- const ValueDecl *D = Desc->asValueDecl();
+ const ValueDecl *D = B->getDescriptor()->asValueDecl();
if (!D)
return false;
@@ -1155,17 +1207,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) {
@@ -1177,6 +1227,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)
@@ -1251,7 +1304,7 @@ bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,
return false;
}
- if (!Ptr.isRoot() || Ptr.isOnePastEnd() ||
+ if (!Ptr.isRoot() || (Ptr.isOnePastEnd() && !Ptr.isZeroSizeArray()) ||
(Ptr.isArrayElement() && Ptr.getIndex() != 0)) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_delete_subobject)
@@ -1426,7 +1479,7 @@ static bool checkConstructor(InterpState &S, CodePtr OpPC, const Function *Func,
bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
if (!CheckLive(S, OpPC, Ptr, AK_Destroy))
return false;
- if (!CheckTemporary(S, OpPC, Ptr, AK_Destroy))
+ if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Destroy))
return false;
if (!CheckRange(S, OpPC, Ptr, AK_Destroy))
return false;
@@ -1620,8 +1673,17 @@ bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());
const auto *InitialFunction = cast<CXXMethodDecl>(Callee);
- const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(
- DynamicDecl, StaticDecl, InitialFunction);
+ const CXXMethodDecl *Overrider;
+
+ if (StaticDecl != DynamicDecl) {
+ if (!DynamicDecl->isDerivedFrom(StaticDecl))
+ return false;
+ Overrider = S.getContext().getOverridingFunction(DynamicDecl, StaticDecl,
+ InitialFunction);
+
+ } else {
+ Overrider = InitialFunction;
+ }
if (Overrider != InitialFunction) {
// DR1872: An instantiated virtual constexpr function can't be called in a
@@ -1749,7 +1811,7 @@ static void startLifetimeRecurse(const Pointer &Ptr) {
bool StartLifetime(InterpState &S, CodePtr OpPC) {
const auto &Ptr = S.Stk.peek<Pointer>();
- if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
+ if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))
return false;
startLifetimeRecurse(Ptr.narrow());
return true;
@@ -1780,8 +1842,13 @@ static void endLifetimeRecurse(const Pointer &Ptr) {
/// Ends the lifetime of the peek'd pointer.
bool EndLifetime(InterpState &S, CodePtr OpPC) {
const auto &Ptr = S.Stk.peek<Pointer>();
- if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
+ if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))
return false;
+
+ // FIXME: We need per-element lifetime information for primitive arrays.
+ if (Ptr.isArrayElement())
+ return true;
+
endLifetimeRecurse(Ptr.narrow());
return true;
}
@@ -1789,8 +1856,13 @@ bool EndLifetime(InterpState &S, CodePtr OpPC) {
/// Ends the lifetime of the pop'd pointer.
bool EndLifetimePop(InterpState &S, CodePtr OpPC) {
const auto &Ptr = S.Stk.pop<Pointer>();
- if (!CheckDummy(S, OpPC, Ptr, AK_Destroy))
+ if (Ptr.isBlockPointer() && !CheckDummy(S, OpPC, Ptr.block(), AK_Destroy))
return false;
+
+ // FIXME: We need per-element lifetime information for primitive arrays.
+ if (Ptr.isArrayElement())
+ return true;
+
endLifetimeRecurse(Ptr.narrow());
return true;
}
@@ -1802,26 +1874,32 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,
if (Ptr.inUnion() && Ptr.getBase().getRecord()->isUnion())
Ptr.activate();
+ if (!Ptr.isBlockPointer())
+ return false;
+
// Similar to CheckStore(), but with the additional CheckTemporary() call and
// the AccessKinds are different.
- if (!CheckTemporary(S, OpPC, Ptr, AK_Construct))
- return false;
- if (!CheckLive(S, OpPC, Ptr, AK_Construct))
- return false;
- if (!CheckDummy(S, OpPC, Ptr, AK_Construct))
+
+ if (!Ptr.block()->isAccessible()) {
+ if (!CheckExtern(S, OpPC, Ptr))
+ return false;
+ if (!CheckLive(S, OpPC, Ptr, AK_Construct))
+ return false;
+ return CheckDummy(S, OpPC, Ptr.block(), AK_Construct);
+ }
+ if (!CheckTemporary(S, OpPC, Ptr.block(), AK_Construct))
return false;
// CheckLifetime for this and all base pointers.
for (Pointer P = Ptr;;) {
- if (!CheckLifetime(S, OpPC, P, AK_Construct))
+ if (!CheckLifetime(S, OpPC, P.getLifetime(), AK_Construct))
return false;
if (P.isRoot())
break;
P = P.getBase();
}
- if (!CheckExtern(S, OpPC, Ptr))
- return false;
+
if (!CheckRange(S, OpPC, Ptr, AK_Construct))
return false;
if (!CheckGlobal(S, OpPC, Ptr))
@@ -2011,7 +2089,7 @@ bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
return false;
// Pick the most-derived type.
- const Type *T = P.getDeclPtr().getType().getTypePtr();
+ CanQualType T = P.getDeclPtr().getType()->getCanonicalTypeUnqualified();
// ... unless we're currently constructing this object.
// FIXME: We have a similar check to this in more places.
if (S.Current->getFunction()) {
@@ -2019,14 +2097,14 @@ bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType) {
if (const Function *Func = Frame->getFunction();
Func && (Func->isConstructor() || Func->isDestructor()) &&
P.block() == Frame->getThis().block()) {
- T = Func->getParentDecl()->getTypeForDecl();
+ T = S.getContext().getASTContext().getCanonicalTagType(
+ Func->getParentDecl());
break;
}
}
}
- S.Stk.push<Pointer>(T->getCanonicalTypeUnqualified().getTypePtr(),
- TypeInfoType);
+ S.Stk.push<Pointer>(T->getTypePtr(), TypeInfoType);
return true;
}
@@ -2040,8 +2118,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 8a28106..2da2202 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -51,8 +51,7 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK);
/// Checks if a pointer is a dummy pointer.
-bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK);
+bool CheckDummy(InterpState &S, CodePtr OpPC, const Block *B, AccessKinds AK);
/// Checks if a pointer is null.
bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
@@ -89,11 +88,14 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK = AK_Read);
bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
-bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
- AccessKinds AK);
+bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+ AccessKinds AK);
+bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,
+ const Descriptor *Desc, AccessKinds AK);
+
/// Checks a direct load of a primitive value from a global or local variable.
-bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
-bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
+bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B);
+bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B);
/// Checks if a value can be stored in a block.
bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
@@ -1351,10 +1353,10 @@ inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
- const Pointer &Ptr = S.Current->getLocalPointer(I);
- if (!CheckLocalLoad(S, OpPC, Ptr))
+ const Block *B = S.Current->getLocalBlock(I);
+ if (!CheckLocalLoad(S, OpPC, B))
return false;
- S.Stk.push<T>(Ptr.deref<T>());
+ S.Stk.push<T>(B->deref<T>());
return true;
}
@@ -1465,22 +1467,26 @@ bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
- const Pointer &Ptr = S.P.getPtrGlobal(I);
+ const Block *B = S.P.getGlobal(I);
- if (!CheckGlobalLoad(S, OpPC, Ptr))
+ if (!CheckGlobalLoad(S, OpPC, B))
return false;
- S.Stk.push<T>(Ptr.deref<T>());
+ S.Stk.push<T>(B->deref<T>());
return true;
}
/// Same as GetGlobal, but without the checks.
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {
- const Pointer &Ptr = S.P.getPtrGlobal(I);
- if (!CheckInitialized(S, OpPC, Ptr, AK_Read))
- return false;
- S.Stk.push<T>(Ptr.deref<T>());
+ const Block *B = S.P.getGlobal(I);
+ const auto &Desc =
+ *reinterpret_cast<const GlobalInlineDescriptor *>(B->rawData());
+ if (Desc.InitState != GlobalInitState::Initialized)
+ return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(),
+ AK_Read);
+
+ S.Stk.push<T>(B->deref<T>());
return true;
}
@@ -1634,6 +1640,9 @@ bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
return false;
+ if (!CheckArray(S, OpPC, Ptr))
+ return false;
+
const Pointer &Field = Ptr.atField(I);
Field.deref<T>() = Value;
Field.initialize();
@@ -1646,6 +1655,9 @@ bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckRange(S, OpPC, Ptr, CSK_Field))
return false;
+ if (!CheckArray(S, OpPC, Ptr))
+ return false;
+
const Pointer &Field = Ptr.atField(I);
Field.deref<T>() = Value;
Field.activate();
@@ -1657,7 +1669,13 @@ template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
assert(F->isBitField());
const T &Value = S.Stk.pop<T>();
- const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ if (!CheckRange(S, OpPC, Ptr, CSK_Field))
+ return false;
+ if (!CheckArray(S, OpPC, Ptr))
+ return false;
+
+ const Pointer &Field = Ptr.atField(F->Offset);
if constexpr (needsAlloc<T>()) {
T Result = S.allocAP<T>(Value.bitWidth());
@@ -1683,7 +1701,13 @@ bool InitBitFieldActivate(InterpState &S, CodePtr OpPC,
const Record::Field *F) {
assert(F->isBitField());
const T &Value = S.Stk.pop<T>();
- const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);
+ const Pointer &Ptr = S.Stk.peek<Pointer>();
+ if (!CheckRange(S, OpPC, Ptr, CSK_Field))
+ return false;
+ if (!CheckArray(S, OpPC, Ptr))
+ return false;
+
+ const Pointer &Field = Ptr.atField(F->Offset);
if constexpr (needsAlloc<T>()) {
T Result = S.allocAP<T>(Value.bitWidth());
@@ -1764,10 +1788,7 @@ inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,
const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord();
assert(TargetRecord);
- if (TargetRecord->getDecl()
- ->getTypeForDecl()
- ->getAsCXXRecordDecl()
- ->getCanonicalDecl() !=
+ if (TargetRecord->getDecl()->getCanonicalDecl() !=
TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) {
QualType MostDerivedType = Ptr.getDeclDesc()->getType();
S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast)
@@ -1785,6 +1806,8 @@ inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
return false;
if (!Ptr.isBlockPointer()) {
+ if (!Ptr.isIntegralPointer())
+ return false;
S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
return true;
}
@@ -1806,6 +1829,8 @@ inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off,
return false;
if (!Ptr.isBlockPointer()) {
+ if (!Ptr.isIntegralPointer())
+ return false;
S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));
return true;
}
@@ -2351,8 +2376,8 @@ static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,
static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))
- return false;
+ if (!Ptr.isInitialized())
+ return DiagnoseUninitialized(S, OpPC, Ptr, AK_Increment);
return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);
}
@@ -2360,8 +2385,8 @@ static inline bool IncPtr(InterpState &S, CodePtr OpPC) {
static inline bool DecPtr(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))
- return false;
+ if (!Ptr.isInitialized())
+ return DiagnoseUninitialized(S, OpPC, Ptr, AK_Decrement);
return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);
}
@@ -2434,9 +2459,17 @@ inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
const Pointer &Ptr = S.Current->getLocalPointer(Local.Offset);
if (Ptr.getLifetime() == Lifetime::Ended) {
- auto *D = cast<NamedDecl>(Ptr.getFieldDesc()->asDecl());
- S.FFDiag(D->getLocation(), diag::note_constexpr_destroy_out_of_lifetime)
- << D->getNameAsString();
+ // Try to use the declaration for better diagnostics
+ if (const Decl *D = Ptr.getDeclDesc()->asDecl()) {
+ auto *ND = cast<NamedDecl>(D);
+ S.FFDiag(ND->getLocation(),
+ diag::note_constexpr_destroy_out_of_lifetime)
+ << ND->getNameAsString();
+ } else {
+ S.FFDiag(Ptr.getDeclDesc()->getLocation(),
+ diag::note_constexpr_destroy_out_of_lifetime)
+ << Ptr.toDiagnosticString(S.getASTContext());
+ }
return false;
}
}
@@ -3155,8 +3188,10 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
return true;
}
- if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
- return false;
+ if (!Ptr.isZeroSizeArray()) {
+ if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
+ return false;
+ }
if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {
S.Stk.push<Pointer>(Ptr.atIndex(0));
@@ -3195,6 +3230,9 @@ inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {
inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {
const auto &MP = S.Stk.pop<MemberPointer>();
+ if (!MP.isBaseCastPossible())
+ return false;
+
S.Stk.push<Pointer>(MP.getBase());
return true;
}
@@ -3452,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/InterpBlock.cpp b/clang/lib/AST/ByteCode/InterpBlock.cpp
index 963b54e..ac6f01f 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.cpp
+++ b/clang/lib/AST/ByteCode/InterpBlock.cpp
@@ -18,18 +18,14 @@ using namespace clang::interp;
void Block::addPointer(Pointer *P) {
assert(P);
- if (IsStatic) {
- assert(!Pointers);
- return;
- }
#ifndef NDEBUG
assert(!hasPointer(P));
#endif
if (Pointers)
- Pointers->PointeeStorage.BS.Prev = P;
- P->PointeeStorage.BS.Next = Pointers;
- P->PointeeStorage.BS.Prev = nullptr;
+ Pointers->BS.Prev = P;
+ P->BS.Next = Pointers;
+ P->BS.Prev = nullptr;
Pointers = P;
#ifndef NDEBUG
assert(hasPointer(P));
@@ -39,32 +35,28 @@ void Block::addPointer(Pointer *P) {
void Block::removePointer(Pointer *P) {
assert(P->isBlockPointer());
assert(P);
- if (IsStatic) {
- assert(!Pointers);
- return;
- }
#ifndef NDEBUG
assert(hasPointer(P));
#endif
- BlockPointer &BP = P->PointeeStorage.BS;
+ BlockPointer &BP = P->BS;
if (Pointers == P)
Pointers = BP.Next;
if (BP.Prev)
- BP.Prev->PointeeStorage.BS.Next = BP.Next;
+ BP.Prev->BS.Next = BP.Next;
if (BP.Next)
- BP.Next->PointeeStorage.BS.Prev = BP.Prev;
- P->PointeeStorage.BS.Pointee = nullptr;
+ BP.Next->BS.Prev = BP.Prev;
+ P->BS.Pointee = nullptr;
#ifndef NDEBUG
assert(!hasPointer(P));
#endif
}
void Block::cleanup() {
- if (Pointers == nullptr && IsDead)
+ if (Pointers == nullptr && !isDynamic() && isDead())
(reinterpret_cast<DeadBlock *>(this + 1) - 1)->free();
}
@@ -74,21 +66,17 @@ void Block::replacePointer(Pointer *Old, Pointer *New) {
assert(New);
assert(New->isBlockPointer());
assert(Old != New);
- if (IsStatic) {
- assert(!Pointers);
- return;
- }
#ifndef NDEBUG
assert(hasPointer(Old));
#endif
- BlockPointer &OldBP = Old->PointeeStorage.BS;
- BlockPointer &NewBP = New->PointeeStorage.BS;
+ BlockPointer &OldBP = Old->BS;
+ BlockPointer &NewBP = New->BS;
if (OldBP.Prev)
- OldBP.Prev->PointeeStorage.BS.Next = New;
+ OldBP.Prev->BS.Next = New;
if (OldBP.Next)
- OldBP.Next->PointeeStorage.BS.Prev = New;
+ OldBP.Next->BS.Prev = New;
NewBP.Prev = OldBP.Prev;
NewBP.Next = OldBP.Next;
if (Pointers == Old)
@@ -113,8 +101,8 @@ bool Block::hasPointer(const Pointer *P) const {
#endif
DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
- : Root(Root), B(~0u, Blk->Desc, Blk->IsStatic, Blk->IsExtern, Blk->IsWeak,
- /*isDead=*/true) {
+ : Root(Root), B(~0u, Blk->Desc, Blk->isExtern(), Blk->IsStatic,
+ Blk->isWeak(), Blk->isDummy(), /*IsDead=*/true) {
// Add the block to the chain of dead blocks.
if (Root)
Root->Prev = this;
@@ -123,18 +111,17 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
Prev = nullptr;
Root = this;
- B.IsDynamic = Blk->IsDynamic;
+ B.DynAllocId = Blk->DynAllocId;
// Transfer pointers.
B.Pointers = Blk->Pointers;
for (Pointer *P = Blk->Pointers; P; P = P->asBlockPointer().Next)
- P->PointeeStorage.BS.Pointee = &B;
+ P->BS.Pointee = &B;
Blk->Pointers = nullptr;
}
void DeadBlock::free() {
- if (B.IsInitialized)
- B.invokeDtor();
+ assert(!B.isInitialized());
if (Prev)
Prev->Next = Next;
diff --git a/clang/lib/AST/ByteCode/InterpBlock.h b/clang/lib/AST/ByteCode/InterpBlock.h
index 5162223..ea9f44c 100644
--- a/clang/lib/AST/ByteCode/InterpBlock.h
+++ b/clang/lib/AST/ByteCode/InterpBlock.h
@@ -22,7 +22,7 @@ class Block;
class DeadBlock;
class InterpState;
class Pointer;
-enum PrimType : unsigned;
+enum PrimType : uint8_t;
/// A memory block, either on the stack or in the heap.
///
@@ -42,21 +42,31 @@ enum PrimType : unsigned;
/// the data size and the metadata size.
///
class Block final {
+private:
+ static constexpr uint8_t ExternFlag = 1 << 0;
+ static constexpr uint8_t DeadFlag = 1 << 1;
+ static constexpr uint8_t WeakFlag = 1 << 2;
+ static constexpr uint8_t DummyFlag = 1 << 3;
+
public:
/// Creates a new block.
- Block(unsigned EvalID, const std::optional<unsigned> &DeclID,
- const Descriptor *Desc, bool IsStatic = false, bool IsExtern = false,
- bool IsWeak = false)
- : EvalID(EvalID), DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern),
- IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
+ Block(unsigned EvalID, UnsignedOrNone DeclID, const Descriptor *Desc,
+ bool IsStatic = false, bool IsExtern = false, bool IsWeak = false,
+ bool IsDummy = false)
+ : Desc(Desc), DeclID(DeclID), EvalID(EvalID), IsStatic(IsStatic) {
assert(Desc);
+ AccessFlags |= (ExternFlag * IsExtern);
+ AccessFlags |= (WeakFlag * IsWeak);
+ AccessFlags |= (DummyFlag * IsDummy);
}
Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false,
- bool IsExtern = false, bool IsWeak = false)
- : EvalID(EvalID), DeclID((unsigned)-1), IsStatic(IsStatic),
- IsExtern(IsExtern), IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
+ bool IsExtern = false, bool IsWeak = false, bool IsDummy = false)
+ : Desc(Desc), EvalID(EvalID), IsStatic(IsStatic) {
assert(Desc);
+ AccessFlags |= (ExternFlag * IsExtern);
+ AccessFlags |= (WeakFlag * IsWeak);
+ AccessFlags |= (DummyFlag * IsDummy);
}
/// Returns the block's descriptor.
@@ -64,17 +74,19 @@ public:
/// Checks if the block has any live pointers.
bool hasPointers() const { return Pointers; }
/// Checks if the block is extern.
- bool isExtern() const { return IsExtern; }
+ bool isExtern() const { return AccessFlags & ExternFlag; }
/// Checks if the block has static storage duration.
bool isStatic() const { return IsStatic; }
/// Checks if the block is temporary.
bool isTemporary() const { return Desc->IsTemporary; }
- bool isWeak() const { return IsWeak; }
- bool isDynamic() const { return IsDynamic; }
+ bool isWeak() const { return AccessFlags & WeakFlag; }
+ bool isDynamic() const { return (DynAllocId != std::nullopt); }
+ bool isDummy() const { return AccessFlags & DummyFlag; }
+ bool isDead() const { return AccessFlags & DeadFlag; }
/// Returns the size of the block.
unsigned getSize() const { return Desc->getAllocSize(); }
/// Returns the declaration ID.
- std::optional<unsigned> getDeclID() const { return DeclID; }
+ UnsignedOrNone getDeclID() const { return DeclID; }
/// Returns whether the data of this block has been initialized via
/// invoking the Ctor func.
bool isInitialized() const { return IsInitialized; }
@@ -103,6 +115,10 @@ public:
return reinterpret_cast<const std::byte *>(this) + sizeof(Block);
}
+ template <typename T> T deref() const {
+ return *reinterpret_cast<const T *>(data());
+ }
+
/// Invokes the constructor.
void invokeCtor() {
assert(!IsInitialized);
@@ -126,19 +142,28 @@ public:
void dump() const { dump(llvm::errs()); }
void dump(llvm::raw_ostream &OS) const;
+ bool isAccessible() const { return AccessFlags == 0; }
+
private:
friend class Pointer;
friend class DeadBlock;
friend class InterpState;
friend class DynamicAllocator;
+ friend class Program;
Block(unsigned EvalID, const Descriptor *Desc, bool IsExtern, bool IsStatic,
- bool IsWeak, bool IsDead)
- : EvalID(EvalID), IsStatic(IsStatic), IsExtern(IsExtern), IsDead(true),
- IsDynamic(false), IsWeak(IsWeak), Desc(Desc) {
+ bool IsWeak, bool IsDummy, bool IsDead)
+ : Desc(Desc), EvalID(EvalID), IsStatic(IsStatic) {
assert(Desc);
+ AccessFlags |= (ExternFlag * IsExtern);
+ AccessFlags |= (DeadFlag * IsDead);
+ AccessFlags |= (WeakFlag * IsWeak);
+ AccessFlags |= (DummyFlag * IsDummy);
}
+ /// To be called by DynamicAllocator.
+ void setDynAllocId(unsigned ID) { DynAllocId = ID; }
+
/// Deletes a dead block at the end of its lifetime.
void cleanup();
@@ -150,27 +175,22 @@ private:
bool hasPointer(const Pointer *P) const;
#endif
- const unsigned EvalID = ~0u;
+ /// Pointer to the stack slot descriptor.
+ const Descriptor *Desc;
/// Start of the chain of pointers.
Pointer *Pointers = nullptr;
/// Unique identifier of the declaration.
- std::optional<unsigned> DeclID;
+ UnsignedOrNone DeclID = std::nullopt;
+ const unsigned EvalID = ~0u;
/// Flag indicating if the block has static storage duration.
bool IsStatic = false;
- /// Flag indicating if the block is an extern.
- bool IsExtern = false;
- /// Flag indicating if the pointer is dead. This is only ever
- /// set once, when converting the Block to a DeadBlock.
- bool IsDead = false;
/// Flag indicating if the block contents have been initialized
/// via invokeCtor.
bool IsInitialized = false;
- /// Flag indicating if this block has been allocated via dynamic
- /// memory allocation (e.g. malloc).
- bool IsDynamic = false;
- bool IsWeak = false;
- /// Pointer to the stack slot descriptor.
- const Descriptor *Desc;
+ /// Allocation ID for this dynamic allocation, if it is one.
+ UnsignedOrNone DynAllocId = std::nullopt;
+ /// AccessFlags containing IsExtern, IsDead, IsWeak, and IsDummy bits.
+ uint8_t AccessFlags = 0;
};
/// Descriptor for a dead block.
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index f908d02..e05b1a8 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) {
@@ -205,6 +221,8 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
if (A.isDummy() || B.isDummy())
return false;
+ if (!A.isBlockPointer() || !B.isBlockPointer())
+ return false;
bool IsWide = ID == Builtin::BIwcscmp || ID == Builtin::BIwcsncmp ||
ID == Builtin::BI__builtin_wcscmp ||
@@ -212,7 +230,10 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
assert(A.getFieldDesc()->isPrimitiveArray());
assert(B.getFieldDesc()->isPrimitiveArray());
- assert(getElemType(A).getTypePtr() == getElemType(B).getTypePtr());
+ // Different element types shouldn't happen, but with casts they can.
+ if (!S.getASTContext().hasSameUnqualifiedType(getElemType(A), getElemType(B)))
+ return false;
+
PrimType ElemT = *S.getContext().classify(getElemType(A));
auto returnResult = [&](int V) -> bool {
@@ -276,7 +297,7 @@ static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
if (!CheckLive(S, OpPC, StrPtr, AK_Read))
return false;
- if (!CheckDummy(S, OpPC, StrPtr, AK_Read))
+ if (!CheckDummy(S, OpPC, StrPtr.block(), AK_Read))
return false;
assert(StrPtr.getFieldDesc()->isPrimitiveArray());
@@ -459,12 +480,13 @@ static bool interp__builtin_isinf(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, bool CheckSign,
const CallExpr *Call) {
const Floating &Arg = S.Stk.pop<Floating>();
- bool IsInf = Arg.isInf();
+ APFloat F = Arg.getAPFloat();
+ bool IsInf = F.isInfinity();
if (CheckSign)
- pushInteger(S, IsInf ? (Arg.isNegative() ? -1 : 1) : 0, Call->getType());
+ pushInteger(S, IsInf ? (F.isNegative() ? -1 : 1) : 0, Call->getType());
else
- pushInteger(S, Arg.isInf(), Call->getType());
+ pushInteger(S, IsInf, Call->getType());
return true;
}
@@ -597,6 +619,17 @@ static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC,
return true;
}
+static inline Floating abs(InterpState &S, const Floating &In) {
+ if (!In.isNegative())
+ return In;
+
+ Floating Output = S.allocFloat(In.getSemantics());
+ APFloat New = In.getAPFloat();
+ New.changeSign();
+ Output.copy(New);
+ return Output;
+}
+
// The C standard says "fabs raises no floating-point exceptions,
// even if x is a signaling NaN. The returned value is independent of
// the current rounding direction mode." Therefore constant folding can
@@ -605,16 +638,7 @@ static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC,
static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame) {
const Floating &Val = S.Stk.pop<Floating>();
- APFloat F = Val.getAPFloat();
- if (!F.isNegative()) {
- S.Stk.push<Floating>(Val);
- return true;
- }
-
- Floating Result = S.allocFloat(Val.getSemantics());
- F.changeSign();
- Result.copy(F);
- S.Stk.push<Floating>(Result);
+ S.Stk.push<Floating>(abs(S, Val));
return true;
}
@@ -635,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;
}
@@ -932,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.
@@ -963,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) {
@@ -1544,8 +1586,7 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
// Composite arrays
if (IsArray) {
const Descriptor *Desc =
- S.P.createDescriptor(NewCall, ElemType.getTypePtr(),
- IsArray ? std::nullopt : Descriptor::InlineDescMD);
+ S.P.createDescriptor(NewCall, ElemType.getTypePtr(), std::nullopt);
Block *B =
Allocator.allocate(Desc, NumElems.getZExtValue(), S.Ctx.getEvalID(),
DynamicAllocator::Form::Operator);
@@ -1558,9 +1599,8 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
QualType AllocType = S.getASTContext().getConstantArrayType(
ElemType, NumElems, nullptr, ArraySizeModifier::Normal, 0);
- const Descriptor *Desc =
- S.P.createDescriptor(NewCall, AllocType.getTypePtr(),
- IsArray ? std::nullopt : Descriptor::InlineDescMD);
+ const Descriptor *Desc = S.P.createDescriptor(NewCall, AllocType.getTypePtr(),
+ Descriptor::InlineDescMD);
Block *B = Allocator.allocate(Desc, S.getContext().getEvalID(),
DynamicAllocator::Form::Operator);
assert(B);
@@ -1687,6 +1727,57 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
return true;
}
+static bool interp__builtin_elementwise_abs(InterpState &S, CodePtr OpPC,
+ const InterpFrame *Frame,
+ const CallExpr *Call,
+ unsigned BuiltinID) {
+ assert(Call->getNumArgs() == 1);
+ QualType Ty = Call->getArg(0)->getType();
+ if (Ty->isIntegerType()) {
+ PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
+ APSInt Val = popToAPSInt(S.Stk, ArgT);
+
+ pushInteger(S, Val.abs(), Call->getType());
+ return true;
+ }
+
+ if (Ty->isFloatingType()) {
+ Floating Val = S.Stk.pop<Floating>();
+ Floating Result = abs(S, Val);
+ S.Stk.push<Floating>(Result);
+ return true;
+ }
+
+ // Otherwise, the argument must be a vector.
+ assert(Call->getArg(0)->getType()->isVectorType());
+ const Pointer &Arg = S.Stk.pop<Pointer>();
+ assert(Arg.getFieldDesc()->isPrimitiveArray());
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+ assert(Dst.getFieldDesc()->isPrimitiveArray());
+ assert(Arg.getFieldDesc()->getNumElems() ==
+ Dst.getFieldDesc()->getNumElems());
+
+ QualType ElemType = Arg.getFieldDesc()->getElemQualType();
+ PrimType ElemT = *S.getContext().classify(ElemType);
+ unsigned NumElems = Arg.getNumElems();
+ // we can either have a vector of integer or a vector of floating point
+ for (unsigned I = 0; I != NumElems; ++I) {
+ if (ElemType->isIntegerType()) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, {
+ Dst.elem<T>(I) = T::from(static_cast<T>(
+ APSInt(Arg.elem<T>(I).toAPSInt().abs(),
+ ElemType->isUnsignedIntegerOrEnumerationType())));
+ });
+ } else {
+ Floating Val = Arg.elem<Floating>(I);
+ Dst.elem<Floating>(I) = abs(S, Val);
+ }
+ }
+ Dst.initializeAllElements();
+
+ return true;
+}
+
/// Can be called with an integer or vector as the first and only parameter.
static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
@@ -1733,6 +1824,94 @@ static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
return true;
}
+/// Can be called with an integer or vector as the first and only parameter.
+static bool interp__builtin_elementwise_countzeroes(InterpState &S,
+ CodePtr OpPC,
+ const InterpFrame *Frame,
+ const CallExpr *Call,
+ unsigned BuiltinID) {
+ const bool HasZeroArg = Call->getNumArgs() == 2;
+ const bool IsCTTZ = BuiltinID == Builtin::BI__builtin_elementwise_cttz;
+ assert(Call->getNumArgs() == 1 || HasZeroArg);
+ if (Call->getArg(0)->getType()->isIntegerType()) {
+ PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
+ APSInt Val = popToAPSInt(S.Stk, ArgT);
+ std::optional<APSInt> ZeroVal;
+ if (HasZeroArg) {
+ ZeroVal = Val;
+ Val = popToAPSInt(S.Stk, ArgT);
+ }
+
+ if (Val.isZero()) {
+ if (ZeroVal) {
+ pushInteger(S, *ZeroVal, Call->getType());
+ return true;
+ }
+ // If we haven't been provided the second argument, the result is
+ // undefined
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_countzeroes_zero)
+ << /*IsTrailing=*/IsCTTZ;
+ return false;
+ }
+
+ if (BuiltinID == Builtin::BI__builtin_elementwise_ctlz) {
+ pushInteger(S, Val.countLeadingZeros(), Call->getType());
+ } else {
+ pushInteger(S, Val.countTrailingZeros(), Call->getType());
+ }
+ return true;
+ }
+ // Otherwise, the argument must be a vector.
+ const ASTContext &ASTCtx = S.getASTContext();
+ Pointer ZeroArg;
+ if (HasZeroArg) {
+ assert(Call->getArg(1)->getType()->isVectorType() &&
+ ASTCtx.hasSameUnqualifiedType(Call->getArg(0)->getType(),
+ Call->getArg(1)->getType()));
+ (void)ASTCtx;
+ ZeroArg = S.Stk.pop<Pointer>();
+ assert(ZeroArg.getFieldDesc()->isPrimitiveArray());
+ }
+ assert(Call->getArg(0)->getType()->isVectorType());
+ const Pointer &Arg = S.Stk.pop<Pointer>();
+ assert(Arg.getFieldDesc()->isPrimitiveArray());
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+ assert(Dst.getFieldDesc()->isPrimitiveArray());
+ assert(Arg.getFieldDesc()->getNumElems() ==
+ Dst.getFieldDesc()->getNumElems());
+
+ QualType ElemType = Arg.getFieldDesc()->getElemQualType();
+ PrimType ElemT = *S.getContext().classify(ElemType);
+ unsigned NumElems = Arg.getNumElems();
+
+ // FIXME: Reading from uninitialized vector elements?
+ for (unsigned I = 0; I != NumElems; ++I) {
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, {
+ APInt EltVal = Arg.atIndex(I).deref<T>().toAPSInt();
+ if (EltVal.isZero()) {
+ if (HasZeroArg) {
+ Dst.atIndex(I).deref<T>() = ZeroArg.atIndex(I).deref<T>();
+ } else {
+ // If we haven't been provided the second argument, the result is
+ // undefined
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_countzeroes_zero)
+ << /*IsTrailing=*/IsCTTZ;
+ return false;
+ }
+ } else if (IsCTTZ) {
+ Dst.atIndex(I).deref<T>() = T::from(EltVal.countTrailingZeros());
+ } else {
+ Dst.atIndex(I).deref<T>() = T::from(EltVal.countLeadingZeros());
+ }
+ Dst.atIndex(I).initialize();
+ });
+ }
+
+ return true;
+}
+
static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call, unsigned ID) {
@@ -1784,7 +1963,27 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
if (DestPtr.isDummy() || SrcPtr.isDummy())
return false;
+ if (DestPtr.getType()->isIncompleteType()) {
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_memcpy_incomplete_type)
+ << Move << DestPtr.getType();
+ return false;
+ }
+ if (SrcPtr.getType()->isIncompleteType()) {
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_memcpy_incomplete_type)
+ << Move << SrcPtr.getType();
+ return false;
+ }
+
QualType DestElemType = getElemType(DestPtr);
+ if (DestElemType->isIncompleteType()) {
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_memcpy_incomplete_type)
+ << Move << DestElemType;
+ return false;
+ }
+
size_t RemainingDestElems;
if (DestPtr.getFieldDesc()->isArray()) {
RemainingDestElems = DestPtr.isUnknownSizeArray()
@@ -1826,16 +2025,6 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
return false;
}
- if (DestElemType->isIncompleteType() ||
- DestPtr.getType()->isIncompleteType()) {
- QualType DiagType =
- DestElemType->isIncompleteType() ? DestElemType : DestPtr.getType();
- S.FFDiag(S.Current->getSource(OpPC),
- diag::note_constexpr_memcpy_incomplete_type)
- << Move << DiagType;
- return false;
- }
-
if (!DestElemType.isTriviallyCopyableType(ASTCtx)) {
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_nontrivial)
<< Move << DestElemType;
@@ -2024,8 +2213,13 @@ static bool interp__builtin_memchr(InterpState &S, CodePtr OpPC,
return true;
}
- if (Ptr.isDummy())
+ if (Ptr.isDummy()) {
+ if (Ptr.getType()->isIncompleteType())
+ S.FFDiag(S.Current->getSource(OpPC),
+ diag::note_constexpr_ltor_incomplete_type)
+ << Ptr.getType();
return false;
+ }
// Null is only okay if the given size is 0.
if (Ptr.isZero()) {
@@ -2103,29 +2297,32 @@ static bool interp__builtin_memchr(InterpState &S, CodePtr OpPC,
return true;
}
-static unsigned computeFullDescSize(const ASTContext &ASTCtx,
- const Descriptor *Desc) {
-
+static std::optional<unsigned> computeFullDescSize(const ASTContext &ASTCtx,
+ const Descriptor *Desc) {
if (Desc->isPrimitive())
return ASTCtx.getTypeSizeInChars(Desc->getType()).getQuantity();
-
if (Desc->isArray())
return ASTCtx.getTypeSizeInChars(Desc->getElemQualType()).getQuantity() *
Desc->getNumElems();
+ if (Desc->isRecord()) {
+ // Can't use Descriptor::getType() as that may return a pointer type. Look
+ // at the decl directly.
+ return ASTCtx
+ .getTypeSizeInChars(
+ ASTCtx.getCanonicalTagType(Desc->ElemRecord->getDecl()))
+ .getQuantity();
+ }
- if (Desc->isRecord())
- return ASTCtx.getTypeSizeInChars(Desc->getType()).getQuantity();
-
- llvm_unreachable("Unhandled descriptor type");
- return 0;
+ return std::nullopt;
}
+/// Compute the byte offset of \p Ptr in the full declaration.
static unsigned computePointerOffset(const ASTContext &ASTCtx,
const Pointer &Ptr) {
unsigned Result = 0;
Pointer P = Ptr;
- while (P.isArrayElement() || P.isField()) {
+ while (P.isField() || P.isArrayElement()) {
P = P.expand();
const Descriptor *D = P.getFieldDesc();
@@ -2138,7 +2335,6 @@ static unsigned computePointerOffset(const ASTContext &ASTCtx,
Result += ElemSize * P.getIndex();
P = P.expand().getArray();
} else if (P.isBaseClass()) {
-
const auto *RD = cast<CXXRecordDecl>(D->asDecl());
bool IsVirtual = Ptr.isVirtualBaseClass();
P = P.getBase();
@@ -2167,30 +2363,136 @@ static unsigned computePointerOffset(const ASTContext &ASTCtx,
return Result;
}
+/// Does Ptr point to the last subobject?
+static bool pointsToLastObject(const Pointer &Ptr) {
+ Pointer P = Ptr;
+ while (!P.isRoot()) {
+
+ if (P.isArrayElement()) {
+ P = P.expand().getArray();
+ continue;
+ }
+ if (P.isBaseClass()) {
+ if (P.getRecord()->getNumFields() > 0)
+ return false;
+ P = P.getBase();
+ continue;
+ }
+
+ Pointer Base = P.getBase();
+ if (const Record *R = Base.getRecord()) {
+ assert(P.getField());
+ if (P.getField()->getFieldIndex() != R->getNumFields() - 1)
+ return false;
+ }
+ P = Base;
+ }
+
+ return true;
+}
+
+/// Does Ptr point to the last object AND to a flexible array member?
+static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const Pointer &Ptr) {
+ auto isFlexibleArrayMember = [&](const Descriptor *FieldDesc) {
+ using FAMKind = LangOptions::StrictFlexArraysLevelKind;
+ FAMKind StrictFlexArraysLevel =
+ Ctx.getLangOpts().getStrictFlexArraysLevel();
+
+ if (StrictFlexArraysLevel == FAMKind::Default)
+ return true;
+
+ unsigned NumElems = FieldDesc->getNumElems();
+ if (NumElems == 0 && StrictFlexArraysLevel != FAMKind::IncompleteOnly)
+ return true;
+
+ if (NumElems == 1 && StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete)
+ return true;
+ return false;
+ };
+
+ const Descriptor *FieldDesc = Ptr.getFieldDesc();
+ if (!FieldDesc->isArray())
+ return false;
+
+ return Ptr.isDummy() && pointsToLastObject(Ptr) &&
+ isFlexibleArrayMember(FieldDesc);
+}
+
static bool interp__builtin_object_size(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
+ const ASTContext &ASTCtx = S.getASTContext();
PrimType KindT = *S.getContext().classify(Call->getArg(1));
- [[maybe_unused]] unsigned Kind = popToAPSInt(S.Stk, KindT).getZExtValue();
-
+ // From the GCC docs:
+ // Kind is an integer constant from 0 to 3. If the least significant bit is
+ // clear, objects are whole variables. If it is set, a closest surrounding
+ // subobject is considered the object a pointer points to. The second bit
+ // determines if maximum or minimum of remaining bytes is computed.
+ unsigned Kind = popToAPSInt(S.Stk, KindT).getZExtValue();
assert(Kind <= 3 && "unexpected kind");
-
+ bool UseFieldDesc = (Kind & 1u);
+ bool ReportMinimum = (Kind & 2u);
const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (Ptr.isZero())
+ if (Call->getArg(0)->HasSideEffects(ASTCtx)) {
+ // "If there are any side effects in them, it returns (size_t) -1
+ // for type 0 or 1 and (size_t) 0 for type 2 or 3."
+ pushInteger(S, Kind <= 1 ? -1 : 0, Call->getType());
+ return true;
+ }
+
+ if (Ptr.isZero() || !Ptr.isBlockPointer())
return false;
- const Descriptor *DeclDesc = Ptr.getDeclDesc();
- if (!DeclDesc)
+ // We can't load through pointers.
+ if (Ptr.isDummy() && Ptr.getType()->isPointerType())
return false;
- const ASTContext &ASTCtx = S.getASTContext();
+ bool DetermineForCompleteObject = Ptr.getFieldDesc() == Ptr.getDeclDesc();
+ const Descriptor *DeclDesc = Ptr.getDeclDesc();
+ assert(DeclDesc);
+
+ if (!UseFieldDesc || DetermineForCompleteObject) {
+ // Lower bound, so we can't fall back to this.
+ if (ReportMinimum && !DetermineForCompleteObject)
+ return false;
- unsigned ByteOffset = computePointerOffset(ASTCtx, Ptr);
- unsigned FullSize = computeFullDescSize(ASTCtx, DeclDesc);
+ // Can't read beyond the pointer decl desc.
+ if (!UseFieldDesc && !ReportMinimum && DeclDesc->getType()->isPointerType())
+ return false;
+ } else {
+ if (isUserWritingOffTheEnd(ASTCtx, Ptr.expand())) {
+ // If we cannot determine the size of the initial allocation, then we
+ // can't given an accurate upper-bound. However, we are still able to give
+ // conservative lower-bounds for Type=3.
+ if (Kind == 1)
+ return false;
+ }
+ }
- pushInteger(S, FullSize - ByteOffset, Call->getType());
+ const Descriptor *Desc = UseFieldDesc ? Ptr.getFieldDesc() : DeclDesc;
+ assert(Desc);
+ std::optional<unsigned> FullSize = computeFullDescSize(ASTCtx, Desc);
+ if (!FullSize)
+ return false;
+
+ unsigned ByteOffset;
+ if (UseFieldDesc) {
+ if (Ptr.isBaseClass())
+ ByteOffset = computePointerOffset(ASTCtx, Ptr.getBase()) -
+ computePointerOffset(ASTCtx, Ptr);
+ else
+ ByteOffset =
+ computePointerOffset(ASTCtx, Ptr) -
+ computePointerOffset(ASTCtx, Ptr.expand().atIndex(0).narrow());
+ } else
+ ByteOffset = computePointerOffset(ASTCtx, Ptr);
+
+ assert(ByteOffset <= *FullSize);
+ unsigned Result = *FullSize - ByteOffset;
+
+ pushInteger(S, Result, Call->getType());
return true;
}
@@ -2232,17 +2534,13 @@ static bool interp__builtin_is_within_lifetime(InterpState &S, CodePtr OpPC,
return false;
if (!CheckMutable(S, OpPC, Ptr))
return false;
- if (!CheckDummy(S, OpPC, Ptr, AK_Read))
+ if (!CheckDummy(S, OpPC, Ptr.block(), AK_Read))
return false;
}
// 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);
@@ -2250,10 +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) {
- Call->dumpColor();
+static bool interp__builtin_elementwise_int_binop(
+ InterpState &S, CodePtr OpPC, const CallExpr *Call, unsigned BuiltinID,
+ llvm::function_ref<APInt(const APSInt &, const APSInt &)> Fn) {
assert(Call->getNumArgs() == 2);
// Single integer case.
@@ -2263,11 +2560,84 @@ 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 = 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());
+ assert(VT->getElementType() ==
+ Call->getArg(1)->getType()->castAs<VectorType>()->getElementType());
+ assert(VT->getNumElements() ==
+ Call->getArg(1)->getType()->castAs<VectorType>()->getNumElements());
+ assert(VT->getElementType()->isIntegralOrEnumerationType());
+
+ const Pointer &RHS = S.Stk.pop<Pointer>();
+ 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, {
+ 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));
+ });
+ }
+ Dst.initializeAllElements();
+
+ return true;
+}
+
+static bool interp__builtin_elementwise_maxmin(InterpState &S, CodePtr OpPC,
+ const CallExpr *Call,
+ unsigned BuiltinID) {
+ assert(Call->getNumArgs() == 2);
+
+ QualType Arg0Type = Call->getArg(0)->getType();
+
+ // TODO: Support floating-point types.
+ if (!(Arg0Type->isIntegerType() ||
+ (Arg0Type->isVectorType() &&
+ Arg0Type->castAs<VectorType>()->getElementType()->isIntegerType())))
+ return false;
+
+ if (!Arg0Type->isVectorType()) {
+ assert(!Call->getArg(1)->getType()->isVectorType());
+ APSInt RHS = popToAPSInt(
+ 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);
+ if (BuiltinID == Builtin::BI__builtin_elementwise_max) {
+ Result = std::max(LHS, RHS);
+ } else if (BuiltinID == Builtin::BI__builtin_elementwise_min) {
+ Result = std::min(LHS, RHS);
} else {
llvm_unreachable("Wrong builtin ID");
}
@@ -2300,13 +2670,11 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
});
APSInt Result;
- if (BuiltinID == Builtin::BI__builtin_elementwise_add_sat) {
- Result = APSInt(Elem1.isSigned() ? Elem1.sadd_sat(Elem2)
- : Elem1.uadd_sat(Elem2),
+ if (BuiltinID == Builtin::BI__builtin_elementwise_max) {
+ Result = APSInt(std::max(Elem1, Elem2),
Call->getType()->isUnsignedIntegerOrEnumerationType());
- } else if (BuiltinID == Builtin::BI__builtin_elementwise_sub_sat) {
- Result = APSInt(Elem1.isSigned() ? Elem1.ssub_sat(Elem2)
- : Elem1.usub_sat(Elem2),
+ } else if (BuiltinID == Builtin::BI__builtin_elementwise_min) {
+ Result = APSInt(std::min(Elem1, Elem2),
Call->getType()->isUnsignedIntegerOrEnumerationType());
} else {
llvm_unreachable("Wrong builtin ID");
@@ -2320,6 +2688,147 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
return true;
}
+static bool interp__builtin_ia32_pmul(InterpState &S, CodePtr OpPC,
+ const CallExpr *Call,
+ unsigned BuiltinID) {
+ assert(Call->getArg(0)->getType()->isVectorType() &&
+ Call->getArg(1)->getType()->isVectorType());
+ const Pointer &RHS = S.Stk.pop<Pointer>();
+ const Pointer &LHS = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+
+ const auto *VT = Call->getArg(0)->getType()->castAs<VectorType>();
+ PrimType ElemT = *S.getContext().classify(VT->getElementType());
+ unsigned SourceLen = VT->getNumElements();
+
+ PrimType DstElemT = *S.getContext().classify(
+ Call->getType()->castAs<VectorType>()->getElementType());
+ unsigned DstElem = 0;
+ for (unsigned I = 0; I != SourceLen; I += 2) {
+ APSInt Elem1;
+ APSInt Elem2;
+ INT_TYPE_SWITCH_NO_BOOL(ElemT, {
+ Elem1 = LHS.elem<T>(I).toAPSInt();
+ Elem2 = RHS.elem<T>(I).toAPSInt();
+ });
+
+ APSInt Result;
+ switch (BuiltinID) {
+ case clang::X86::BI__builtin_ia32_pmuludq128:
+ case clang::X86::BI__builtin_ia32_pmuludq256:
+ case clang::X86::BI__builtin_ia32_pmuludq512:
+ Result = APSInt(llvm::APIntOps::muluExtended(Elem1, Elem2),
+ /*IsUnsigned=*/true);
+ break;
+ case clang::X86::BI__builtin_ia32_pmuldq128:
+ case clang::X86::BI__builtin_ia32_pmuldq256:
+ case clang::X86::BI__builtin_ia32_pmuldq512:
+ Result = APSInt(llvm::APIntOps::mulsExtended(Elem1, Elem2),
+ /*IsUnsigned=*/false);
+ break;
+ }
+ INT_TYPE_SWITCH_NO_BOOL(DstElemT,
+ { Dst.elem<T>(DstElem) = static_cast<T>(Result); });
+ ++DstElem;
+ }
+
+ Dst.initializeAllElements();
+ return true;
+}
+
+static bool interp__builtin_elementwise_fma(InterpState &S, CodePtr OpPC,
+ const CallExpr *Call) {
+ assert(Call->getNumArgs() == 3);
+
+ FPOptions FPO = Call->getFPFeaturesInEffect(S.Ctx.getLangOpts());
+ llvm::RoundingMode RM = getRoundingMode(FPO);
+ const QualType Arg1Type = Call->getArg(0)->getType();
+ const QualType Arg2Type = Call->getArg(1)->getType();
+ const QualType Arg3Type = Call->getArg(2)->getType();
+
+ // Non-vector floating point types.
+ if (!Arg1Type->isVectorType()) {
+ assert(!Arg2Type->isVectorType());
+ assert(!Arg3Type->isVectorType());
+ (void)Arg2Type;
+ (void)Arg3Type;
+
+ 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);
+ Floating Result = S.allocFloat(X.getSemantics());
+ Result.copy(F);
+ S.Stk.push<Floating>(Result);
+ return true;
+ }
+
+ // Vector type.
+ assert(Arg1Type->isVectorType() && Arg2Type->isVectorType() &&
+ Arg3Type->isVectorType());
+
+ const VectorType *VecT = Arg1Type->castAs<VectorType>();
+ const QualType ElemT = VecT->getElementType();
+ unsigned NumElems = VecT->getNumElements();
+
+ assert(ElemT == Arg2Type->castAs<VectorType>()->getElementType() &&
+ ElemT == Arg3Type->castAs<VectorType>()->getElementType());
+ assert(NumElems == Arg2Type->castAs<VectorType>()->getNumElements() &&
+ NumElems == Arg3Type->castAs<VectorType>()->getNumElements());
+ assert(ElemT->isRealFloatingType());
+ (void)ElemT;
+
+ const Pointer &VZ = S.Stk.pop<Pointer>();
+ const Pointer &VY = S.Stk.pop<Pointer>();
+ const Pointer &VX = S.Stk.pop<Pointer>();
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+ for (unsigned I = 0; I != NumElems; ++I) {
+ using T = PrimConv<PT_Float>::T;
+ 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);
+ }
+ Dst.initializeAllElements();
+ return true;
+}
+
+/// AVX512 predicated move: "Result = Mask[] ? LHS[] : RHS[]".
+static bool interp__builtin_select(InterpState &S, CodePtr OpPC,
+ const CallExpr *Call) {
+ const Pointer &RHS = S.Stk.pop<Pointer>();
+ const Pointer &LHS = S.Stk.pop<Pointer>();
+ PrimType MaskT = *S.getContext().classify(Call->getArg(0));
+ APSInt Mask = popToAPSInt(S.Stk, MaskT);
+ const Pointer &Dst = S.Stk.peek<Pointer>();
+
+ assert(LHS.getNumElems() == RHS.getNumElems());
+ assert(LHS.getNumElems() == Dst.getNumElems());
+ unsigned NumElems = LHS.getNumElems();
+ PrimType ElemT = LHS.getFieldDesc()->getPrimType();
+ PrimType DstElemT = Dst.getFieldDesc()->getPrimType();
+
+ for (unsigned I = 0; I != NumElems; ++I) {
+ if (ElemT == PT_Float) {
+ assert(DstElemT == PT_Float);
+ Dst.elem<Floating>(I) =
+ Mask[I] ? LHS.elem<Floating>(I) : RHS.elem<Floating>(I);
+ } else {
+ APSInt Elem;
+ INT_TYPE_SWITCH(ElemT, {
+ Elem = Mask[I] ? LHS.elem<T>(I).toAPSInt() : RHS.elem<T>(I).toAPSInt();
+ });
+ INT_TYPE_SWITCH_NO_BOOL(DstElemT,
+ { Dst.elem<T>(I) = static_cast<T>(Elem); });
+ }
+ }
+ Dst.initializeAllElements();
+
+ return true;
+}
+
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
uint32_t BuiltinID) {
if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID))
@@ -2596,6 +3105,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
case Builtin::BI__builtin_ctzg:
return interp__builtin_ctz(S, OpPC, Frame, Call, BuiltinID);
+ case Builtin::BI__builtin_elementwise_ctlz:
+ case Builtin::BI__builtin_elementwise_cttz:
+ return interp__builtin_elementwise_countzeroes(S, OpPC, Frame, Call,
+ BuiltinID);
+
case Builtin::BI__builtin_bswap16:
case Builtin::BI__builtin_bswap32:
case Builtin::BI__builtin_bswap64:
@@ -2687,6 +3201,9 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
return interp__builtin_elementwise_popcount(S, OpPC, Frame, Call,
BuiltinID);
+ case Builtin::BI__builtin_elementwise_abs:
+ return interp__builtin_elementwise_abs(S, OpPC, Frame, Call, BuiltinID);
+
case Builtin::BI__builtin_memcpy:
case Builtin::BImemcpy:
case Builtin::BI__builtin_wmemcpy:
@@ -2724,8 +3241,154 @@ 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, BuiltinID, [](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_sat(S, OpPC, Call, BuiltinID);
+ return interp__builtin_elementwise_int_binop(
+ S, OpPC, Call, BuiltinID, [](const APSInt &LHS, const APSInt &RHS) {
+ return LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
+ });
+
+ 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, BuiltinID,
+ 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_int_binop(S, OpPC, Call, BuiltinID,
+ 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_psllv8si:
+ 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, BuiltinID, [](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_psrav8si:
+ 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, BuiltinID, [](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:
+ 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, BuiltinID, [](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, BuiltinID,
+ [](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, BuiltinID,
+ [](const APSInt &LHS, const APSInt &RHS) { return LHS.rotr(RHS); });
+
+ case Builtin::BI__builtin_elementwise_max:
+ case Builtin::BI__builtin_elementwise_min:
+ return interp__builtin_elementwise_maxmin(S, OpPC, Call, BuiltinID);
+
+ case clang::X86::BI__builtin_ia32_pmuldq128:
+ case clang::X86::BI__builtin_ia32_pmuldq256:
+ case clang::X86::BI__builtin_ia32_pmuldq512:
+ case clang::X86::BI__builtin_ia32_pmuludq128:
+ case clang::X86::BI__builtin_ia32_pmuludq256:
+ case clang::X86::BI__builtin_ia32_pmuludq512:
+ return interp__builtin_ia32_pmul(S, OpPC, Call, BuiltinID);
+
+ case Builtin::BI__builtin_elementwise_fma:
+ return interp__builtin_elementwise_fma(S, OpPC, Call);
+
+ case X86::BI__builtin_ia32_selectb_128:
+ case X86::BI__builtin_ia32_selectb_256:
+ case X86::BI__builtin_ia32_selectb_512:
+ case X86::BI__builtin_ia32_selectw_128:
+ case X86::BI__builtin_ia32_selectw_256:
+ case X86::BI__builtin_ia32_selectw_512:
+ case X86::BI__builtin_ia32_selectd_128:
+ case X86::BI__builtin_ia32_selectd_256:
+ case X86::BI__builtin_ia32_selectd_512:
+ case X86::BI__builtin_ia32_selectq_128:
+ case X86::BI__builtin_ia32_selectq_256:
+ case X86::BI__builtin_ia32_selectq_512:
+ case X86::BI__builtin_ia32_selectph_128:
+ case X86::BI__builtin_ia32_selectph_256:
+ case X86::BI__builtin_ia32_selectph_512:
+ case X86::BI__builtin_ia32_selectpbf_128:
+ case X86::BI__builtin_ia32_selectpbf_256:
+ case X86::BI__builtin_ia32_selectpbf_512:
+ case X86::BI__builtin_ia32_selectps_128:
+ case X86::BI__builtin_ia32_selectps_256:
+ case X86::BI__builtin_ia32_selectps_512:
+ case X86::BI__builtin_ia32_selectpd_128:
+ case X86::BI__builtin_ia32_selectpd_256:
+ case X86::BI__builtin_ia32_selectpd_512:
+ return interp__builtin_select(S, OpPC, Call);
default:
S.FFDiag(S.Current->getLocation(OpPC),
@@ -2751,11 +3414,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->getDecl();
- 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();
@@ -2784,22 +3444,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->getDecl();
- 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->getDecl()));
+ 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 9342192..b9dc2ae 100644
--- a/clang/lib/AST/ByteCode/InterpFrame.cpp
+++ b/clang/lib/AST/ByteCode/InterpFrame.cpp
@@ -169,7 +169,7 @@ void InterpFrame::describe(llvm::raw_ostream &OS) const {
} else if (const auto *M = dyn_cast<CXXMethodDecl>(F)) {
print(OS, This, S.getASTContext(),
S.getASTContext().getLValueReferenceType(
- S.getASTContext().getRecordType(M->getParent())));
+ S.getASTContext().getCanonicalTagType(M->getParent())));
OS << ".";
}
}
@@ -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())
@@ -231,6 +225,10 @@ Pointer InterpFrame::getLocalPointer(unsigned Offset) const {
return Pointer(localBlock(Offset));
}
+Block *InterpFrame::getLocalBlock(unsigned Offset) const {
+ return localBlock(Offset);
+}
+
Pointer InterpFrame::getParamPointer(unsigned Off) {
// Return the block if it was created previously.
if (auto Pt = Params.find(Off); Pt != Params.end())
diff --git a/clang/lib/AST/ByteCode/InterpFrame.h b/clang/lib/AST/ByteCode/InterpFrame.h
index cfebe93..cf4d27d 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;
@@ -86,6 +86,7 @@ public:
/// Returns a pointer to a local variables.
Pointer getLocalPointer(unsigned Offset) const;
+ Block *getLocalBlock(unsigned Offset) const;
/// Returns the value of an argument.
template <typename T> const T &getParam(unsigned Offset) const {
diff --git a/clang/lib/AST/ByteCode/InterpStack.cpp b/clang/lib/AST/ByteCode/InterpStack.cpp
index 6b748d6..7920378 100644
--- a/clang/lib/AST/ByteCode/InterpStack.cpp
+++ b/clang/lib/AST/ByteCode/InterpStack.cpp
@@ -26,33 +26,33 @@ InterpStack::~InterpStack() {
std::free(Chunk);
Chunk = nullptr;
StackSize = 0;
-#ifndef NDEBUG
ItemTypes.clear();
-#endif
}
// We keep the last chunk around to reuse.
void InterpStack::clear() {
- if (!Chunk)
- return;
-
- if (Chunk->Next)
- std::free(Chunk->Next);
-
- assert(Chunk);
- StackSize = 0;
-#ifndef NDEBUG
- ItemTypes.clear();
-#endif
+ for (PrimType Item : llvm::reverse(ItemTypes)) {
+ TYPE_SWITCH(Item, { this->discard<T>(); });
+ }
+ assert(ItemTypes.empty());
+ assert(empty());
}
void InterpStack::clearTo(size_t NewSize) {
- assert(NewSize <= size());
- size_t ToShrink = size() - NewSize;
- if (ToShrink == 0)
+ if (NewSize == 0)
+ return clear();
+ if (NewSize == size())
return;
- shrink(ToShrink);
+ assert(NewSize <= size());
+ for (PrimType Item : llvm::reverse(ItemTypes)) {
+ TYPE_SWITCH(Item, { this->discard<T>(); });
+
+ if (size() == NewSize)
+ break;
+ }
+
+ // Note: discard() above already removed the types from ItemTypes.
assert(size() == NewSize);
}
@@ -105,25 +105,9 @@ void InterpStack::shrink(size_t Size) {
Chunk->End -= Size;
StackSize -= Size;
-
-#ifndef NDEBUG
- size_t TypesSize = 0;
- for (PrimType T : ItemTypes)
- TYPE_SWITCH(T, { TypesSize += aligned_size<T>(); });
-
- size_t StackSize = size();
- while (TypesSize > StackSize) {
- TYPE_SWITCH(ItemTypes.back(), {
- TypesSize -= aligned_size<T>();
- ItemTypes.pop_back();
- });
- }
- assert(TypesSize == StackSize);
-#endif
}
void InterpStack::dump() const {
-#ifndef NDEBUG
llvm::errs() << "Items: " << ItemTypes.size() << ". Size: " << size() << '\n';
if (ItemTypes.empty())
return;
@@ -133,11 +117,11 @@ void InterpStack::dump() const {
// The type of the item on the top of the stack is inserted to the back
// of the vector, so the iteration has to happen backwards.
- for (auto TyIt = ItemTypes.rbegin(); TyIt != ItemTypes.rend(); ++TyIt) {
- Offset += align(primSize(*TyIt));
+ for (PrimType Item : llvm::reverse(ItemTypes)) {
+ Offset += align(primSize(Item));
llvm::errs() << Index << '/' << Offset << ": ";
- TYPE_SWITCH(*TyIt, {
+ TYPE_SWITCH(Item, {
const T &V = peek<T>(Offset);
llvm::errs() << V;
});
@@ -145,5 +129,4 @@ void InterpStack::dump() const {
++Index;
}
-#endif
}
diff --git a/clang/lib/AST/ByteCode/InterpStack.h b/clang/lib/AST/ByteCode/InterpStack.h
index 580494e..b0f9f6e 100644
--- a/clang/lib/AST/ByteCode/InterpStack.h
+++ b/clang/lib/AST/ByteCode/InterpStack.h
@@ -17,7 +17,6 @@
#include "IntegralAP.h"
#include "MemberPointer.h"
#include "PrimType.h"
-#include <vector>
namespace clang {
namespace interp {
@@ -33,18 +32,14 @@ public:
/// Constructs a value in place on the top of the stack.
template <typename T, typename... Tys> void push(Tys &&...Args) {
new (grow(aligned_size<T>())) T(std::forward<Tys>(Args)...);
-#ifndef NDEBUG
ItemTypes.push_back(toPrimType<T>());
-#endif
}
/// Returns the value from the top of the stack and removes it.
template <typename T> T pop() {
-#ifndef NDEBUG
assert(!ItemTypes.empty());
assert(ItemTypes.back() == toPrimType<T>());
ItemTypes.pop_back();
-#endif
T *Ptr = &peekInternal<T>();
T Value = std::move(*Ptr);
shrink(aligned_size<T>());
@@ -53,22 +48,20 @@ public:
/// Discards the top value from the stack.
template <typename T> void discard() {
-#ifndef NDEBUG
assert(!ItemTypes.empty());
assert(ItemTypes.back() == toPrimType<T>());
ItemTypes.pop_back();
-#endif
T *Ptr = &peekInternal<T>();
- Ptr->~T();
+ if constexpr (!std::is_trivially_destructible_v<T>) {
+ Ptr->~T();
+ }
shrink(aligned_size<T>());
}
/// Returns a reference to the value on the top of the stack.
template <typename T> T &peek() const {
-#ifndef NDEBUG
assert(!ItemTypes.empty());
assert(ItemTypes.back() == toPrimType<T>());
-#endif
return peekInternal<T>();
}
@@ -83,7 +76,7 @@ public:
/// Returns the size of the stack in bytes.
size_t size() const { return StackSize; }
- /// Clears the stack without calling any destructors.
+ /// Clears the stack.
void clear();
void clearTo(size_t NewSize);
@@ -146,9 +139,11 @@ private:
/// Total size of the stack.
size_t StackSize = 0;
-#ifndef NDEBUG
- /// vector recording the type of data we pushed into the stack.
- std::vector<PrimType> ItemTypes;
+ /// SmallVector recording the type of data we pushed into the stack.
+ /// We don't usually need this during normal code interpretation but
+ /// when aborting, we need type information to call the destructors
+ /// for what's left on the stack.
+ llvm::SmallVector<PrimType> ItemTypes;
template <typename T> static constexpr PrimType toPrimType() {
if constexpr (std::is_same_v<T, Pointer>)
@@ -192,7 +187,6 @@ private:
llvm_unreachable("unknown type push()'ed into InterpStack");
}
-#endif
};
} // namespace interp
diff --git a/clang/lib/AST/ByteCode/InterpState.cpp b/clang/lib/AST/ByteCode/InterpState.cpp
index a06b125..a2a1e58 100644
--- a/clang/lib/AST/ByteCode/InterpState.cpp
+++ b/clang/lib/AST/ByteCode/InterpState.cpp
@@ -45,6 +45,12 @@ InterpState::~InterpState() {
while (DeadBlocks) {
DeadBlock *Next = DeadBlocks->Next;
+
+ // There might be a pointer in a global structure pointing to the dead
+ // block.
+ for (Pointer *P = DeadBlocks->B.Pointers; P; P = P->asBlockPointer().Next)
+ DeadBlocks->B.removePointer(P);
+
std::free(DeadBlocks);
DeadBlocks = Next;
}
@@ -53,20 +59,10 @@ 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.
- for (DeadBlock *DB = DeadBlocks; DB; DB = DB->Next) {
- for (Pointer *P = DB->B.Pointers; P; P = P->asBlockPointer().Next) {
- P->PointeeStorage.BS.Pointee = nullptr;
- }
- }
-
Alloc.cleanup();
}
-Frame *InterpState::getCurrentFrame() {
- if (Current && Current->Caller)
- return Current;
- return Parent.getCurrentFrame();
-}
+Frame *InterpState::getCurrentFrame() { return Current; }
bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) {
QualType Type = E->getType();
@@ -76,8 +72,9 @@ bool InterpState::reportOverflow(const Expr *E, const llvm::APSInt &Value) {
void InterpState::deallocate(Block *B) {
assert(B);
- const Descriptor *Desc = B->getDescriptor();
- assert(Desc);
+ assert(!B->isDynamic());
+ assert(!B->isStatic());
+ assert(!B->isDead());
// The block might have a pointer saved in a field in its data
// that points to the block itself. We call the dtor first,
@@ -87,6 +84,7 @@ void InterpState::deallocate(Block *B) {
if (B->IsInitialized)
B->invokeDtor();
+ assert(!B->isInitialized());
if (B->hasPointers()) {
size_t Size = B->getSize();
// Allocate a new block, transferring over pointers.
@@ -95,24 +93,20 @@ void InterpState::deallocate(Block *B) {
auto *D = new (Memory) DeadBlock(DeadBlocks, B);
// Since the block doesn't hold any actual data anymore, we can just
// memcpy() everything over.
- std::memcpy(D->rawData(), B->rawData(), Desc->getAllocSize());
- D->B.IsInitialized = B->IsInitialized;
-
- // We moved the contents over to the DeadBlock.
- B->IsInitialized = false;
+ std::memcpy(D->rawData(), B->rawData(), Size);
+ D->B.IsInitialized = false;
}
}
bool InterpState::maybeDiagnoseDanglingAllocations() {
- bool NoAllocationsLeft = (Alloc.getNumAllocations() == 0);
+ bool NoAllocationsLeft = !Alloc.hasAllocations();
if (!checkingPotentialConstantExpression()) {
- for (const auto &It : Alloc.allocation_sites()) {
- assert(It.second.size() > 0);
+ for (const auto &[Source, Site] : Alloc.allocation_sites()) {
+ assert(!Site.empty());
- const Expr *Source = It.first;
CCEDiag(Source->getExprLoc(), diag::note_constexpr_memory_leak)
- << (It.second.size() - 1) << Source->getSourceRange();
+ << (Site.size() - 1) << Source->getSourceRange();
}
}
// Keep evaluating before C++20, since the CXXNewExpr wasn't valid there
diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h
index 861e4c3..f123a1f 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 {
diff --git a/clang/lib/AST/ByteCode/MemberPointer.h b/clang/lib/AST/ByteCode/MemberPointer.h
index b17ce25..8dd75ca 100644
--- a/clang/lib/AST/ByteCode/MemberPointer.h
+++ b/clang/lib/AST/ByteCode/MemberPointer.h
@@ -51,6 +51,12 @@ public:
FunctionPointer toFunctionPointer(const Context &Ctx) const;
+ bool isBaseCastPossible() const {
+ if (PtrOffset < 0)
+ return true;
+ return static_cast<uint64_t>(PtrOffset) <= Base.getByteOffset();
+ }
+
Pointer getBase() const {
if (PtrOffset < 0)
return Base.atField(-PtrOffset);
diff --git a/clang/lib/AST/ByteCode/Pointer.cpp b/clang/lib/AST/ByteCode/Pointer.cpp
index dec2088..973bc7c 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -30,39 +30,62 @@ Pointer::Pointer(Block *Pointee)
Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
: Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
-Pointer::Pointer(const Pointer &P)
- : Offset(P.Offset), StorageKind(P.StorageKind),
- PointeeStorage(P.PointeeStorage) {
-
- if (isBlockPointer() && PointeeStorage.BS.Pointee)
- PointeeStorage.BS.Pointee->addPointer(this);
-}
-
Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)
: Offset(Offset), StorageKind(Storage::Block) {
assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
- PointeeStorage.BS = {Pointee, Base, nullptr, nullptr};
+ BS = {Pointee, Base, nullptr, nullptr};
if (Pointee)
Pointee->addPointer(this);
}
-Pointer::Pointer(Pointer &&P)
- : Offset(P.Offset), StorageKind(P.StorageKind),
- PointeeStorage(P.PointeeStorage) {
+Pointer::Pointer(const Pointer &P)
+ : Offset(P.Offset), StorageKind(P.StorageKind) {
+ switch (StorageKind) {
+ case Storage::Int:
+ Int = P.Int;
+ break;
+ case Storage::Block:
+ BS = P.BS;
+ if (BS.Pointee)
+ BS.Pointee->addPointer(this);
+ break;
+ case Storage::Fn:
+ Fn = P.Fn;
+ break;
+ case Storage::Typeid:
+ Typeid = P.Typeid;
+ break;
+ }
+}
- if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee)
- PointeeStorage.BS.Pointee->replacePointer(&P, this);
+Pointer::Pointer(Pointer &&P) : Offset(P.Offset), StorageKind(P.StorageKind) {
+ switch (StorageKind) {
+ case Storage::Int:
+ Int = P.Int;
+ break;
+ case Storage::Block:
+ BS = P.BS;
+ if (BS.Pointee)
+ BS.Pointee->replacePointer(&P, this);
+ break;
+ case Storage::Fn:
+ Fn = P.Fn;
+ break;
+ case Storage::Typeid:
+ Typeid = P.Typeid;
+ break;
+ }
}
Pointer::~Pointer() {
if (!isBlockPointer())
return;
- if (Block *Pointee = PointeeStorage.BS.Pointee) {
+ if (Block *Pointee = BS.Pointee) {
Pointee->removePointer(this);
- PointeeStorage.BS.Pointee = nullptr;
+ BS.Pointee = nullptr;
Pointee->cleanup();
}
}
@@ -73,13 +96,13 @@ Pointer &Pointer::operator=(const Pointer &P) {
if (isBlockPointer()) {
if (P.isBlockPointer() && this->block() == P.block()) {
Offset = P.Offset;
- PointeeStorage.BS.Base = P.PointeeStorage.BS.Base;
+ BS.Base = P.BS.Base;
return *this;
}
- if (Block *Pointee = PointeeStorage.BS.Pointee) {
+ if (Block *Pointee = BS.Pointee) {
Pointee->removePointer(this);
- PointeeStorage.BS.Pointee = nullptr;
+ BS.Pointee = nullptr;
Pointee->cleanup();
}
}
@@ -88,16 +111,16 @@ Pointer &Pointer::operator=(const Pointer &P) {
Offset = P.Offset;
if (P.isBlockPointer()) {
- PointeeStorage.BS = P.PointeeStorage.BS;
+ BS = P.BS;
- if (PointeeStorage.BS.Pointee)
- PointeeStorage.BS.Pointee->addPointer(this);
+ if (BS.Pointee)
+ BS.Pointee->addPointer(this);
} else if (P.isIntegralPointer()) {
- PointeeStorage.Int = P.PointeeStorage.Int;
+ Int = P.Int;
} else if (P.isFunctionPointer()) {
- PointeeStorage.Fn = P.PointeeStorage.Fn;
+ Fn = P.Fn;
} else if (P.isTypeidPointer()) {
- PointeeStorage.Typeid = P.PointeeStorage.Typeid;
+ Typeid = P.Typeid;
} else {
assert(false && "Unhandled storage kind");
}
@@ -110,13 +133,13 @@ Pointer &Pointer::operator=(Pointer &&P) {
if (isBlockPointer()) {
if (P.isBlockPointer() && this->block() == P.block()) {
Offset = P.Offset;
- PointeeStorage.BS.Base = P.PointeeStorage.BS.Base;
+ BS.Base = P.BS.Base;
return *this;
}
- if (Block *Pointee = PointeeStorage.BS.Pointee) {
+ if (Block *Pointee = BS.Pointee) {
Pointee->removePointer(this);
- PointeeStorage.BS.Pointee = nullptr;
+ BS.Pointee = nullptr;
Pointee->cleanup();
}
}
@@ -125,16 +148,16 @@ Pointer &Pointer::operator=(Pointer &&P) {
Offset = P.Offset;
if (P.isBlockPointer()) {
- PointeeStorage.BS = P.PointeeStorage.BS;
+ BS = P.BS;
- if (PointeeStorage.BS.Pointee)
- PointeeStorage.BS.Pointee->addPointer(this);
+ if (BS.Pointee)
+ BS.Pointee->addPointer(this);
} else if (P.isIntegralPointer()) {
- PointeeStorage.Int = P.PointeeStorage.Int;
+ Int = P.Int;
} else if (P.isFunctionPointer()) {
- PointeeStorage.Fn = P.PointeeStorage.Fn;
+ Fn = P.Fn;
} else if (P.isTypeidPointer()) {
- PointeeStorage.Typeid = P.PointeeStorage.Typeid;
+ Typeid = P.Typeid;
} else {
assert(false && "Unhandled storage kind");
}
@@ -163,12 +186,11 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
}
if (isTypeidPointer()) {
- TypeInfoLValue TypeInfo(PointeeStorage.Typeid.TypePtr);
- return APValue(
- APValue::LValueBase::getTypeInfo(
- TypeInfo, QualType(PointeeStorage.Typeid.TypeInfoType, 0)),
- CharUnits::Zero(), {},
- /*OnePastTheEnd=*/false, /*IsNull=*/false);
+ TypeInfoLValue TypeInfo(Typeid.TypePtr);
+ return APValue(APValue::LValueBase::getTypeInfo(
+ TypeInfo, QualType(Typeid.TypeInfoType, 0)),
+ CharUnits::Zero(), {},
+ /*OnePastTheEnd=*/false, /*IsNull=*/false);
}
// Build the lvalue base from the block.
@@ -179,10 +201,7 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
else if (const auto *E = Desc->asExpr()) {
if (block()->isDynamic()) {
QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx);
- // FIXME: Suboptimal counting of dynamic allocations. Move this to Context
- // or InterpState?
- static int ReportedDynamicAllocs = 0;
- DynamicAllocLValue DA(ReportedDynamicAllocs++);
+ DynamicAllocLValue DA(*block()->DynAllocId);
Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
} else {
Base = E;
@@ -212,7 +231,7 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
UsePath = false;
// Build the path into the object.
- bool OnePastEnd = isOnePastEnd();
+ bool OnePastEnd = isOnePastEnd() && !isZeroSizeArray();
Pointer Ptr = *this;
while (Ptr.isField() || Ptr.isArrayElement()) {
@@ -259,10 +278,10 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
Ptr = Ptr.getArray();
} else {
const Descriptor *Desc = Ptr.getFieldDesc();
- bool IsVirtual = false;
// Create a path entry for the field.
if (const auto *BaseOrMember = Desc->asDecl()) {
+ bool IsVirtual = false;
if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
Ptr = Ptr.getBase();
Offset += getFieldOffset(FD);
@@ -303,13 +322,13 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
void Pointer::print(llvm::raw_ostream &OS) const {
switch (StorageKind) {
case Storage::Block: {
- const Block *B = PointeeStorage.BS.Pointee;
+ const Block *B = BS.Pointee;
OS << "(Block) " << B << " {";
if (isRoot())
- OS << "rootptr(" << PointeeStorage.BS.Base << "), ";
+ OS << "rootptr(" << BS.Base << "), ";
else
- OS << PointeeStorage.BS.Base << ", ";
+ OS << BS.Base << ", ";
if (isElementPastEnd())
OS << "pastend, ";
@@ -324,8 +343,7 @@ void Pointer::print(llvm::raw_ostream &OS) const {
} break;
case Storage::Int:
OS << "(Int) {";
- OS << PointeeStorage.Int.Value << " + " << Offset << ", "
- << PointeeStorage.Int.Desc;
+ OS << Int.Value << " + " << Offset << ", " << Int.Desc;
OS << "}";
break;
case Storage::Fn:
@@ -378,6 +396,8 @@ size_t Pointer::computeOffsetForComparison() const {
}
if (const Record *R = P.getBase().getRecord(); R && R->isUnion()) {
+ if (P.isOnePastEnd())
+ ++Result;
// Direct child of a union - all have offset 0.
P = P.getBase();
continue;
@@ -413,45 +433,60 @@ bool Pointer::isInitialized() const {
if (!isBlockPointer())
return true;
- if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
const GlobalInlineDescriptor &GD =
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
return GD.InitState == GlobalInitState::Initialized;
}
- assert(PointeeStorage.BS.Pointee &&
- "Cannot check if null pointer was initialized");
+ assert(BS.Pointee && "Cannot check if null pointer was initialized");
const Descriptor *Desc = getFieldDesc();
assert(Desc);
- if (Desc->isPrimitiveArray()) {
- if (isStatic() && PointeeStorage.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 {
if (!isBlockPointer())
return;
- assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
+ assert(BS.Pointee && "Cannot initialize null pointer");
- if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
asBlockPointer().Pointee->rawData());
GD.InitState = GlobalInitState::Initialized;
@@ -462,7 +497,7 @@ void Pointer::initialize() const {
assert(Desc);
if (Desc->isPrimitiveArray()) {
// Primitive global arrays don't have an initmap.
- if (isStatic() && PointeeStorage.BS.Base == 0)
+ if (isStatic() && BS.Base == 0)
return;
// Nothing to do for these.
@@ -488,8 +523,7 @@ void Pointer::initialize() const {
}
// Field has its bit in an inline descriptor.
- assert(PointeeStorage.BS.Base != 0 &&
- "Only composite fields can be initialised");
+ assert(BS.Base != 0 && "Only composite fields can be initialised");
getInlineDesc()->IsInitialized = true;
}
@@ -506,12 +540,28 @@ 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(PointeeStorage.BS.Base != 0 &&
- "Only composite fields can be activated");
+ assert(BS.Base != 0 && "Only composite fields can be activated");
- if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor))
+ if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor))
return;
if (!getInlineDesc()->InUnion)
return;
@@ -593,8 +643,7 @@ bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
}
bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
- return hasSameBase(A, B) &&
- A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
+ return hasSameBase(A, B) && A.BS.Base == B.BS.Base &&
A.getFieldDesc()->IsArray;
}
@@ -684,12 +733,12 @@ 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");
bool Ok = true;
- if (RT->getDecl()->isUnion()) {
+ if (RT->getOriginalDecl()->isUnion()) {
const FieldDecl *ActiveField = nullptr;
APValue Value;
for (const auto &F : Record->fields()) {
@@ -728,14 +777,15 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx,
for (unsigned I = 0; I < NB; ++I) {
const Record::Base *BD = Record->getBase(I);
- QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
+ QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl);
const Pointer &BP = Ptr.atField(BD->Offset);
Ok &= Composite(BaseTy, BP, R.getStructBase(I));
}
for (unsigned I = 0; I < NV; ++I) {
const Record::Base *VD = Record->getVirtualBase(I);
- QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
+ QualType VirtBaseTy =
+ Ctx.getASTContext().getCanonicalTagType(VD->Decl);
const Pointer &VP = Ptr.atField(VD->Offset);
Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
}
@@ -754,13 +804,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;
@@ -768,8 +818,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 5bafc5b..49d701c 100644
--- a/clang/lib/AST/ByteCode/Pointer.h
+++ b/clang/lib/AST/ByteCode/Pointer.h
@@ -28,8 +28,6 @@ class Block;
class DeadBlock;
class Pointer;
class Context;
-template <unsigned A, bool B> class Integral;
-enum PrimType : unsigned;
class Pointer;
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P);
@@ -95,31 +93,21 @@ private:
static constexpr unsigned RootPtrMark = ~0u;
public:
- Pointer() {
- StorageKind = Storage::Int;
- PointeeStorage.Int.Value = 0;
- PointeeStorage.Int.Desc = nullptr;
- }
- Pointer(IntPointer &&IntPtr) : StorageKind(Storage::Int) {
- PointeeStorage.Int = std::move(IntPtr);
- }
+ Pointer() : StorageKind(Storage::Int), Int{nullptr, 0} {}
+ Pointer(IntPointer &&IntPtr)
+ : StorageKind(Storage::Int), Int(std::move(IntPtr)) {}
Pointer(Block *B);
Pointer(Block *B, uint64_t BaseAndOffset);
Pointer(const Pointer &P);
Pointer(Pointer &&P);
Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0)
- : Offset(Offset), StorageKind(Storage::Int) {
- PointeeStorage.Int.Value = Address;
- PointeeStorage.Int.Desc = Desc;
- }
+ : Offset(Offset), StorageKind(Storage::Int), Int{Desc, Address} {}
Pointer(const Function *F, uint64_t Offset = 0)
- : Offset(Offset), StorageKind(Storage::Fn) {
- PointeeStorage.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) {
- PointeeStorage.Typeid.TypePtr = TypePtr;
- PointeeStorage.Typeid.TypeInfoType = TypeInfoType;
+ Typeid.TypePtr = TypePtr;
+ Typeid.TypeInfoType = TypeInfoType;
}
Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
~Pointer();
@@ -132,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;
}
@@ -156,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.
@@ -169,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
@@ -197,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.
@@ -209,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.
@@ -225,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
@@ -236,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.
@@ -245,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()
@@ -270,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 {
@@ -295,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(); }
@@ -310,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();
@@ -350,9 +331,11 @@ public:
/// Returns the type of the innermost field.
QualType getType() const {
if (isTypeidPointer())
- return QualType(PointeeStorage.Typeid.TypeInfoType, 0);
+ return QualType(Typeid.TypeInfoType, 0);
+ if (isFunctionPointer())
+ 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())
@@ -365,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();
}
@@ -391,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 {
@@ -417,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;
};
@@ -439,7 +418,7 @@ public:
if (!isBlockPointer())
return false;
- const BlockPointer &BP = asBlockPointer();
+ const BlockPointer &BP = BS;
if (inArray() && BP.Base != Offset)
return true;
@@ -454,33 +433,32 @@ 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 {
assert(isBlockPointer());
- return PointeeStorage.BS;
+ return BS;
}
[[nodiscard]] const IntPointer &asIntPointer() const {
assert(isIntegralPointer());
- return PointeeStorage.Int;
+ return Int;
}
[[nodiscard]] const FunctionPointer &asFunctionPointer() const {
assert(isFunctionPointer());
- return PointeeStorage.Fn;
+ return Fn;
}
[[nodiscard]] const TypeidPointer &asTypeidPointer() const {
assert(isTypeidPointer());
- return PointeeStorage.Typeid;
+ return Typeid;
}
bool isBlockPointer() const { return StorageKind == Storage::Block; }
@@ -505,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;
}
@@ -543,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())
@@ -568,10 +544,9 @@ public:
if (!isBlockPointer())
return false;
- if (!asBlockPointer().Pointee)
- return false;
-
- return getDeclDesc()->isDummy();
+ if (const Block *Pointee = BS.Pointee)
+ return Pointee->isDummy();
+ return false;
}
/// Checks if an object or a subfield is mutable.
@@ -594,10 +569,10 @@ public:
}
/// Returns the declaration ID.
- std::optional<unsigned> getDeclID() const {
+ UnsignedOrNone getDeclID() const {
if (isBlockPointer()) {
- assert(asBlockPointer().Pointee);
- return asBlockPointer().Pointee->getDeclID();
+ assert(BS.Pointee);
+ return BS.Pointee->getDeclID();
}
return std::nullopt;
}
@@ -605,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;
@@ -620,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.
@@ -638,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())
@@ -652,13 +626,13 @@ public:
if (!isBlockPointer())
return false;
- if (!asBlockPointer().Pointee)
+ if (!BS.Pointee)
return false;
if (isUnknownSizeArray())
return false;
- return isPastEnd() || (getSize() == getOffset() && !isZeroSizeArray());
+ return isPastEnd() || (getSize() == getOffset());
}
/// Checks if the pointer points past the end of the object.
@@ -666,7 +640,7 @@ public:
if (isIntegralPointer())
return false;
- return !isZero() && Offset > PointeeStorage.BS.Pointee->getSize();
+ return !isZero() && Offset > BS.Pointee->getSize();
}
/// Checks if the pointer is an out-of-bounds element pointer.
@@ -685,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.
@@ -702,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
@@ -733,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.
@@ -741,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;
}
@@ -749,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;
}
@@ -757,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;
}
@@ -805,14 +782,15 @@ private:
friend class InterpState;
friend struct InitMap;
friend class DynamicAllocator;
+ friend class Program;
/// 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.
@@ -820,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;
}
@@ -829,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.
@@ -842,7 +819,7 @@ private:
BlockPointer BS;
FunctionPointer Fn;
TypeidPointer Typeid;
- } PointeeStorage;
+ };
};
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {
diff --git a/clang/lib/AST/ByteCode/PrimType.h b/clang/lib/AST/ByteCode/PrimType.h
index 724da93..54fd39a 100644
--- a/clang/lib/AST/ByteCode/PrimType.h
+++ b/clang/lib/AST/ByteCode/PrimType.h
@@ -31,7 +31,7 @@ template <bool Signed> class IntegralAP;
template <unsigned Bits, bool Signed> class Integral;
/// Enumeration of the primitive types of the VM.
-enum PrimType : unsigned {
+enum PrimType : uint8_t {
PT_Sint8 = 0,
PT_Uint8 = 1,
PT_Sint16 = 2,
@@ -51,14 +51,15 @@ enum PrimType : unsigned {
// Like std::optional<PrimType>, but only sizeof(PrimType).
class OptPrimType final {
- unsigned V = ~0u;
+ static constexpr uint8_t None = 0xFF;
+ uint8_t V = None;
public:
OptPrimType() = default;
OptPrimType(std::nullopt_t) {}
OptPrimType(PrimType T) : V(static_cast<unsigned>(T)) {}
- explicit constexpr operator bool() const { return V != ~0u; }
+ explicit constexpr operator bool() const { return V != None; }
PrimType operator*() const {
assert(operator bool());
return static_cast<PrimType>(V);
@@ -85,6 +86,19 @@ inline constexpr bool isPtrType(PrimType T) {
return T == PT_Ptr || T == PT_MemberPtr;
}
+inline constexpr bool isSignedType(PrimType T) {
+ switch (T) {
+ case PT_Sint8:
+ case PT_Sint16:
+ case PT_Sint32:
+ case PT_Sint64:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
enum class CastKind : uint8_t {
Reinterpret,
Volatile,
@@ -258,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 4daa4ab..0be017e 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;
}
@@ -164,8 +164,8 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) {
const auto *VD = cast<ValueDecl>(cast<const Decl *>(D));
IsWeak = VD->isWeak();
QT = VD->getType();
- if (const auto *RT = QT->getAs<ReferenceType>())
- QT = RT->getPointeeType();
+ if (QT->isPointerOrReferenceType())
+ QT = QT->getPointeeType();
}
assert(!QT.isNull());
@@ -180,17 +180,15 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) {
Desc = allocateDescriptor(D);
assert(Desc);
- Desc->makeDummy();
-
- assert(Desc->isDummy());
// Allocate a block for storage.
unsigned I = Globals.size();
auto *G = new (Allocator, Desc->getAllocSize())
Global(Ctx.getEvalID(), getCurrentDecl(), Desc, /*IsStatic=*/true,
- /*IsExtern=*/false, IsWeak);
+ /*IsExtern=*/false, IsWeak, /*IsDummy=*/true);
G->block()->invokeCtor();
+ assert(G->block()->isDummy());
Globals.push_back(G);
DummyVariables[D.getOpaqueValue()] = I;
@@ -215,19 +213,31 @@ 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.
- if (auto Idx =
- createGlobal(VD, VD->getType(), IsStatic, IsExtern, IsWeak, Init)) {
- for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
- unsigned &PIdx = GlobalIndices[P];
- if (P != VD) {
- if (Globals[PIdx]->block()->isExtern())
- Globals[PIdx] = Globals[*Idx];
+ std::optional<unsigned> Idx =
+ createGlobal(VD, VD->getType(), IsStatic, IsExtern, IsWeak, Init);
+ if (!Idx)
+ return std::nullopt;
+
+ Global *NewGlobal = Globals[*Idx];
+ for (const Decl *Redecl : VD->redecls()) {
+ unsigned &PIdx = GlobalIndices[Redecl];
+ if (Redecl != VD) {
+ if (Block *RedeclBlock = Globals[PIdx]->block();
+ RedeclBlock->isExtern()) {
+ Globals[PIdx] = NewGlobal;
+ // All pointers pointing to the previous extern decl now point to the
+ // new decl.
+ for (Pointer *Ptr = RedeclBlock->Pointers; Ptr; Ptr = Ptr->BS.Next) {
+ RedeclBlock->removePointer(Ptr);
+ Ptr->BS.Pointee = NewGlobal->block();
+ NewGlobal->block()->addPointer(Ptr);
+ }
}
- PIdx = *Idx;
}
- return *Idx;
+ PIdx = *Idx;
}
- return std::nullopt;
+
+ return *Idx;
}
std::optional<unsigned> Program::createGlobal(const Expr *E) {
@@ -266,7 +276,7 @@ std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
Ctx.getEvalID(), getCurrentDecl(), Desc, IsStatic, IsExtern, IsWeak);
G->block()->invokeCtor();
- // Initialize InlineDescriptor fields.
+ // Initialize GlobalInlineDescriptor fields.
auto *GD = new (G->block()->rawData()) GlobalInlineDescriptor();
if (!Init)
GD->InitState = GlobalInitState::NoInitializer;
@@ -322,10 +332,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->getDecl();
const Record *BR = getOrCreateRecord(BD);
const Descriptor *Desc = GetBaseDesc(BD, BR);
@@ -338,11 +347,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->getDecl();
+ const auto *BD = Spec.getType()->castAsCXXRecordDecl();
const Record *BR = getOrCreateRecord(BD);
const Descriptor *Desc = GetBaseDesc(BD, BR);
@@ -398,8 +403,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->getDecl()))
+ 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 207ceef..90b48ee5 100644
--- a/clang/lib/AST/ByteCode/Program.h
+++ b/clang/lib/AST/ByteCode/Program.h
@@ -73,6 +73,10 @@ public:
return Globals[Idx]->block();
}
+ bool isGlobalInitialized(unsigned Index) const {
+ return getPtrGlobal(Index).isInitialized();
+ }
+
/// Finds a global's index.
std::optional<unsigned> getGlobal(const ValueDecl *VD);
std::optional<unsigned> getGlobal(const Expr *E);
@@ -152,7 +156,7 @@ public:
};
/// Returns the current declaration ID.
- std::optional<unsigned> getCurrentDecl() const {
+ UnsignedOrNone getCurrentDecl() const {
if (CurrentDeclaration == NoDeclaration)
return std::nullopt;
return CurrentDeclaration;
@@ -172,9 +176,6 @@ private:
/// List of anonymous functions.
std::vector<std::unique_ptr<Function>> AnonFuncs;
- /// Function relocation locations.
- llvm::DenseMap<const FunctionDecl *, std::vector<unsigned>> Relocs;
-
/// Native pointers referenced by bytecode.
std::vector<const void *> NativePointers;
/// Cached native pointer indices.
diff --git a/clang/lib/AST/ByteCode/Record.cpp b/clang/lib/AST/ByteCode/Record.cpp
index 1d4ac71..c20ec18 100644
--- a/clang/lib/AST/ByteCode/Record.cpp
+++ b/clang/lib/AST/ByteCode/Record.cpp
@@ -50,10 +50,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->getDecl();
+ if (auto *RD = T->getAsCXXRecordDecl())
return BaseMap.lookup(RD);
- }
return nullptr;
}
diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp
index f037616..7a3e7ea 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->getDecl()->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,8 +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->getDecl());
+ BaseRecord = BaseSpec.getType()->getAsCXXRecordDecl();
} else {
TemplateName TN = TST->getTemplateName();
if (auto *TD =
@@ -270,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)) {
@@ -334,9 +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->getDecl());
+ auto *VBase = PE.Base->getType()->getAsCXXRecordDecl();
if (!VBase)
break;
@@ -345,10 +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->getDecl());
+ auto *HidingClass =
+ HidingP.back().Base->getType()->getAsCXXRecordDecl();
if (!HidingClass)
break;
@@ -404,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);
@@ -467,8 +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->getDecl());
+ if (const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl()) {
if (!BaseDecl->isPolymorphic())
continue;
diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp
index cd73d27..37e21c3 100644
--- a/clang/lib/AST/Comment.cpp
+++ b/clang/lib/AST/Comment.cpp
@@ -147,8 +147,6 @@ static TypeLoc lookThroughTypedefOrTypeAliasLocs(TypeLoc &SrcTL) {
return BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
if (MemberPointerTypeLoc MemberPointerTL = TL.getAs<MemberPointerTypeLoc>())
return MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
- if (ElaboratedTypeLoc ETL = TL.getAs<ElaboratedTypeLoc>())
- return ETL.getNamedTypeLoc();
return TL;
}
diff --git a/clang/lib/AST/CommentLexer.cpp b/clang/lib/AST/CommentLexer.cpp
index e19c232..a0903d0 100644
--- a/clang/lib/AST/CommentLexer.cpp
+++ b/clang/lib/AST/CommentLexer.cpp
@@ -214,7 +214,7 @@ bool isCommandNameStartCharacter(char C) {
}
bool isCommandNameCharacter(char C) {
- return isAlphanumeric(C);
+ return isAsciiIdentifierContinue(C, false);
}
const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) {
diff --git a/clang/lib/AST/CommentParser.cpp b/clang/lib/AST/CommentParser.cpp
index e61846d..2e5821a 100644
--- a/clang/lib/AST/CommentParser.cpp
+++ b/clang/lib/AST/CommentParser.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CommentParser.h"
+#include "clang/AST/Comment.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/CommentSema.h"
#include "clang/Basic/CharInfo.h"
@@ -569,6 +570,8 @@ BlockCommandComment *Parser::parseBlockCommand() {
InlineCommandComment *Parser::parseInlineCommand() {
assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
+ CommandMarkerKind CMK =
+ Tok.is(tok::backslash_command) ? CMK_Backslash : CMK_At;
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
const Token CommandTok = Tok;
@@ -580,7 +583,7 @@ InlineCommandComment *Parser::parseInlineCommand() {
InlineCommandComment *IC = S.actOnInlineCommand(
CommandTok.getLocation(), CommandTok.getEndLocation(),
- CommandTok.getCommandID(), Args);
+ CommandTok.getCommandID(), CMK, Args);
if (Args.size() < Info->NumArgs) {
Diag(CommandTok.getEndLocation().getLocWithOffset(1),
diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp
index 88520d7..649fba9 100644
--- a/clang/lib/AST/CommentSema.cpp
+++ b/clang/lib/AST/CommentSema.cpp
@@ -363,12 +363,13 @@ void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
InlineCommandComment *
Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
SourceLocation CommandLocEnd, unsigned CommandID,
+ CommandMarkerKind CommandMarker,
ArrayRef<Comment::Argument> Args) {
StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
- return new (Allocator)
- InlineCommandComment(CommandLocBegin, CommandLocEnd, CommandID,
- getInlineCommandRenderKind(CommandName), Args);
+ return new (Allocator) InlineCommandComment(
+ CommandLocBegin, CommandLocEnd, CommandID,
+ getInlineCommandRenderKind(CommandName), CommandMarker, Args);
}
InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
@@ -905,17 +906,9 @@ bool Sema::isClassOrStructOrTagTypedefDecl() {
if (isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl))
return true;
- if (auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->CurrentDecl)) {
- auto UnderlyingType = ThisTypedefDecl->getUnderlyingType();
- if (auto ThisElaboratedType = dyn_cast<ElaboratedType>(UnderlyingType)) {
- auto DesugaredType = ThisElaboratedType->desugar();
- if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) {
- if (auto *ThisRecordType = dyn_cast<RecordType>(DesugaredTypePtr)) {
- return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl());
- }
- }
- }
- }
+ if (auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->CurrentDecl))
+ if (auto *D = ThisTypedefDecl->getUnderlyingType()->getAsRecordDecl())
+ return isClassOrStructDeclImpl(D);
return false;
}
diff --git a/clang/lib/AST/ComparisonCategories.cpp b/clang/lib/AST/ComparisonCategories.cpp
index 2824410..0c7a7f4 100644
--- a/clang/lib/AST/ComparisonCategories.cpp
+++ b/clang/lib/AST/ComparisonCategories.cpp
@@ -166,7 +166,7 @@ const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty)
QualType ComparisonCategoryInfo::getType() const {
assert(Record);
- return QualType(Record->getTypeForDecl(), 0);
+ return Record->getASTContext().getCanonicalTagType(Record);
}
StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) {
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 87334d9..e0cf0de 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -500,9 +500,8 @@ ExprDependence clang::computeDependence(OMPIteratorExpr *E) {
ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) {
auto Deps = ExprDependence::None;
- if (auto *NNS = E->getQualifier())
- Deps |= toExprDependence(NNS->getDependence() &
- ~NestedNameSpecifierDependence::Dependent);
+ Deps |= toExprDependence(E->getQualifier().getDependence() &
+ ~NestedNameSpecifierDependence::Dependent);
if (auto *FirstArg = E->getTemplateArgs()) {
unsigned NumArgs = E->getNumTemplateArgs();
@@ -673,9 +672,8 @@ ExprDependence clang::computeDependence(MemberExpr *E) {
auto D = E->getBase()->getDependence();
D |= getDependenceInExpr(E->getMemberNameInfo());
- if (auto *NNS = E->getQualifier())
- D |= toExprDependence(NNS->getDependence() &
- ~NestedNameSpecifierDependence::Dependent);
+ D |= toExprDependence(E->getQualifier().getDependence() &
+ ~NestedNameSpecifierDependence::Dependent);
for (const auto &A : E->template_arguments())
D |= toExprDependence(A.getArgument().getDependence());
@@ -783,9 +781,8 @@ ExprDependence clang::computeDependence(CXXPseudoDestructorExpr *E) {
if (auto *ST = E->getScopeTypeInfo())
D |= turnTypeToValueDependence(
toExprDependenceAsWritten(ST->getType()->getDependence()));
- if (auto *Q = E->getQualifier())
- D |= toExprDependence(Q->getDependence() &
- ~NestedNameSpecifierDependence::Dependent);
+ D |= toExprDependence(E->getQualifier().getDependence() &
+ ~NestedNameSpecifierDependence::Dependent);
return D;
}
@@ -801,9 +798,8 @@ clang::computeDependence(OverloadExpr *E, bool KnownDependent,
if (KnownContainsUnexpandedParameterPack)
Deps |= ExprDependence::UnexpandedPack;
Deps |= getDependenceInExpr(E->getNameInfo());
- if (auto *Q = E->getQualifier())
- Deps |= toExprDependence(Q->getDependence() &
- ~NestedNameSpecifierDependence::Dependent);
+ Deps |= toExprDependence(E->getQualifier().getDependence() &
+ ~NestedNameSpecifierDependence::Dependent);
for (auto *D : E->decls()) {
if (D->getDeclContext()->isDependentContext() ||
isa<UnresolvedUsingValueDecl>(D) || isa<TemplateTemplateParmDecl>(D))
@@ -820,8 +816,7 @@ clang::computeDependence(OverloadExpr *E, bool KnownDependent,
ExprDependence clang::computeDependence(DependentScopeDeclRefExpr *E) {
auto D = ExprDependence::TypeValue;
D |= getDependenceInExpr(E->getNameInfo());
- if (auto *Q = E->getQualifier())
- D |= toExprDependence(Q->getDependence());
+ D |= toExprDependence(E->getQualifier().getDependence());
for (const auto &A : E->template_arguments())
D |= toExprDependence(A.getArgument().getDependence());
return D;
@@ -872,8 +867,7 @@ ExprDependence clang::computeDependence(CXXDependentScopeMemberExpr *E) {
auto D = ExprDependence::TypeValueInstantiation;
if (!E->isImplicitAccess())
D |= E->getBase()->getDependence();
- if (auto *Q = E->getQualifier())
- D |= toExprDependence(Q->getDependence());
+ D |= toExprDependence(E->getQualifier().getDependence());
D |= getDependenceInExpr(E->getMemberNameInfo());
for (const auto &A : E->template_arguments())
D |= toExprDependence(A.getArgument().getDependence());
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 5471f31..34367306 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -1604,17 +1604,20 @@ LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D,
// We have just computed the linkage for this decl. By induction we know
// that all other computed linkages match, check that the one we just
// computed also does.
- NamedDecl *Old = nullptr;
- for (auto *I : D->redecls()) {
- auto *T = cast<NamedDecl>(I);
- if (T == D)
+ // We can't assume the redecl chain is well formed at this point,
+ // so keep track of already visited declarations.
+ for (llvm::SmallPtrSet<const Decl *, 4> AlreadyVisited{D}; /**/; /**/) {
+ D = cast<NamedDecl>(const_cast<NamedDecl *>(D)->getNextRedeclarationImpl());
+ if (!AlreadyVisited.insert(D).second)
+ break;
+ if (D->isInvalidDecl())
continue;
- if (!T->isInvalidDecl() && T->hasCachedLinkage()) {
- Old = T;
+ if (auto OldLinkage = D->getCachedLinkage();
+ OldLinkage != Linkage::Invalid) {
+ assert(LV.getLinkage() == OldLinkage);
break;
}
}
- assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage());
#endif
return LV;
@@ -1693,9 +1696,9 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
return;
}
printNestedNameSpecifier(OS, P);
- if (getDeclName())
- OS << *this;
- else {
+ if (getDeclName()) {
+ printName(OS, P);
+ } else {
// Give the printName override a chance to pick a different name before we
// fall back to "(anonymous)".
SmallString<64> NameBuffer;
@@ -1883,18 +1886,13 @@ bool NamedDecl::declarationReplaces(const NamedDecl *OldD,
// Using declarations can be replaced if they import the same name from the
// same context.
- if (const auto *UD = dyn_cast<UsingDecl>(this)) {
- ASTContext &Context = getASTContext();
- return Context.getCanonicalNestedNameSpecifier(UD->getQualifier()) ==
- Context.getCanonicalNestedNameSpecifier(
- cast<UsingDecl>(OldD)->getQualifier());
- }
- if (const auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(this)) {
- ASTContext &Context = getASTContext();
- return Context.getCanonicalNestedNameSpecifier(UUVD->getQualifier()) ==
- Context.getCanonicalNestedNameSpecifier(
- cast<UnresolvedUsingValueDecl>(OldD)->getQualifier());
- }
+ if (const auto *UD = dyn_cast<UsingDecl>(this))
+ return UD->getQualifier().getCanonical() ==
+
+ cast<UsingDecl>(OldD)->getQualifier().getCanonical();
+ if (const auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(this))
+ return UUVD->getQualifier().getCanonical() ==
+ cast<UnresolvedUsingValueDecl>(OldD)->getQualifier().getCanonical();
if (isRedeclarable(getKind())) {
if (getCanonicalDecl() != OldD->getCanonicalDecl())
@@ -2863,8 +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->getDecl()->hasFlexibleArrayMember())
+ auto *D = getType()->getAsRecordDecl();
+ if (!D || !D->hasFlexibleArrayMember())
return false;
auto *List = dyn_cast<InitListExpr>(getInit()->IgnoreParens());
if (!List)
@@ -2878,8 +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 || !Ty->getDecl()->hasFlexibleArrayMember())
+ auto *RD = getType()->getAsRecordDecl();
+ if (!RD || !RD->hasFlexibleArrayMember())
return CharUnits::Zero();
auto *List = dyn_cast<InitListExpr>(getInit()->IgnoreParens());
if (!List || List->getNumInits() == 0)
@@ -2889,7 +2887,7 @@ CharUnits VarDecl::getFlexibleArrayInitChars(const ASTContext &Ctx) const {
if (!InitTy)
return CharUnits::Zero();
CharUnits FlexibleArraySize = Ctx.getTypeSizeInChars(InitTy);
- const ASTRecordLayout &RL = Ctx.getASTRecordLayout(Ty->getDecl());
+ const ASTRecordLayout &RL = Ctx.getASTRecordLayout(RD);
CharUnits FlexibleArrayOffset =
Ctx.toCharUnitsFromBits(RL.getFieldOffset(RL.getFieldCount() - 1));
if (FlexibleArrayOffset + FlexibleArraySize < RL.getSize())
@@ -2990,8 +2988,11 @@ bool ParmVarDecl::isDestroyedInCallee() const {
// FIXME: isParamDestroyedInCallee() should probably imply
// isDestructedType()
- const auto *RT = getType()->getAs<RecordType>();
- if (RT && RT->getDecl()->isParamDestroyedInCallee() &&
+ const auto *RT = getType()->getAsCanonical<RecordType>();
+ if (RT &&
+ RT->getOriginalDecl()
+ ->getDefinitionOrSelf()
+ ->isParamDestroyedInCallee() &&
getType().isDestructedType())
return true;
@@ -3502,7 +3503,7 @@ bool FunctionDecl::isUsableAsGlobalAllocationFunctionInConstantEvaluation(
while (const auto *TD = T->getAs<TypedefType>())
T = TD->getDecl()->getUnderlyingType();
const IdentifierInfo *II =
- T->castAs<EnumType>()->getDecl()->getIdentifier();
+ T->castAsCanonical<EnumType>()->getOriginalDecl()->getIdentifier();
if (II && II->isStr("__hot_cold_t"))
Consume();
}
@@ -4652,8 +4653,8 @@ bool FieldDecl::isAnonymousStructOrUnion() const {
if (!isImplicit() || getDeclName())
return false;
- if (const auto *Record = getType()->getAs<RecordType>())
- return Record->getDecl()->isAnonymousStructOrUnion();
+ if (const auto *Record = getType()->getAsCanonical<RecordType>())
+ return Record->getOriginalDecl()->isAnonymousStructOrUnion();
return false;
}
@@ -4710,10 +4711,10 @@ 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->getDecl()->getDefinition();
+ const RecordDecl *RD = RT->getOriginalDecl()->getDefinition();
if (!RD) {
assert(isInvalidDecl() && "valid field has incomplete type");
return false;
@@ -4733,7 +4734,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();
});
}
@@ -4836,10 +4837,6 @@ TagDecl *TagDecl::getCanonicalDecl() { return getFirstDecl(); }
void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
TypedefNameDeclOrQualifier = TDD;
- if (const Type *T = getTypeForDecl()) {
- (void)T;
- assert(T->isLinkageValid());
- }
assert(isLinkageValid());
}
@@ -4867,25 +4864,16 @@ void TagDecl::completeDefinition() {
}
TagDecl *TagDecl::getDefinition() const {
- if (isCompleteDefinition())
+ if (isCompleteDefinition() || isBeingDefined())
return const_cast<TagDecl *>(this);
- // If it's possible for us to have an out-of-date definition, check now.
- if (mayHaveOutOfDateDef()) {
- if (IdentifierInfo *II = getIdentifier()) {
- if (II->isOutOfDate()) {
- updateOutOfDate(*II);
- }
- }
- }
-
if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(this))
return CXXRD->getDefinition();
- for (auto *R : redecls())
- if (R->isCompleteDefinition())
+ for (TagDecl *R :
+ redecl_range(redecl_iterator(getNextRedeclaration()), redecl_iterator()))
+ if (R->isCompleteDefinition() || R->isBeingDefined())
return R;
-
return nullptr;
}
@@ -4919,7 +4907,7 @@ void TagDecl::printName(raw_ostream &OS, const PrintingPolicy &Policy) const {
// is already printed as part of the type.
PrintingPolicy Copy(Policy);
Copy.SuppressScope = true;
- getASTContext().getTagDeclType(this).print(OS, Copy);
+ QualType(getASTContext().getCanonicalTagType(this)).print(OS, Copy);
return;
}
// Otherwise, do the normal printing.
@@ -4963,19 +4951,13 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
EnumDecl *PrevDecl, bool IsScoped,
bool IsScopedUsingClassTag, bool IsFixed) {
- auto *Enum = new (C, DC) EnumDecl(C, DC, StartLoc, IdLoc, Id, PrevDecl,
- IsScoped, IsScopedUsingClassTag, IsFixed);
- Enum->setMayHaveOutOfDateDef(C.getLangOpts().Modules);
- C.getTypeDeclType(Enum, PrevDecl);
- return Enum;
+ return new (C, DC) EnumDecl(C, DC, StartLoc, IdLoc, Id, PrevDecl, IsScoped,
+ IsScopedUsingClassTag, IsFixed);
}
EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
- EnumDecl *Enum =
- new (C, ID) EnumDecl(C, nullptr, SourceLocation(), SourceLocation(),
- nullptr, nullptr, false, false, false);
- Enum->setMayHaveOutOfDateDef(C.getLangOpts().Modules);
- return Enum;
+ return new (C, ID) EnumDecl(C, nullptr, SourceLocation(), SourceLocation(),
+ nullptr, nullptr, false, false, false);
}
SourceRange EnumDecl::getIntegerTypeRange() const {
@@ -5035,7 +5017,7 @@ EnumDecl *EnumDecl::getTemplateInstantiationPattern() const {
EnumDecl *ED = getInstantiatedFromMemberEnum();
while (auto *NewED = ED->getInstantiatedFromMemberEnum())
ED = NewED;
- return getDefinitionOrSelf(ED);
+ return ::getDefinitionOrSelf(ED);
}
}
@@ -5125,21 +5107,15 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C,
RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, RecordDecl* PrevDecl) {
- RecordDecl *R = new (C, DC) RecordDecl(Record, TK, C, DC,
- StartLoc, IdLoc, Id, PrevDecl);
- R->setMayHaveOutOfDateDef(C.getLangOpts().Modules);
-
- C.getTypeDeclType(R, PrevDecl);
- return R;
+ return new (C, DC)
+ RecordDecl(Record, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl);
}
RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C,
GlobalDeclID ID) {
- RecordDecl *R = new (C, ID)
+ return new (C, ID)
RecordDecl(Record, TagTypeKind::Struct, C, nullptr, SourceLocation(),
SourceLocation(), nullptr, nullptr);
- R->setMayHaveOutOfDateDef(C.getLangOpts().Modules);
- return R;
}
bool RecordDecl::isLambda() const {
@@ -5162,8 +5138,8 @@ bool RecordDecl::isOrContainsUnion() const {
if (const RecordDecl *Def = getDefinition()) {
for (const FieldDecl *FD : Def->fields()) {
- const RecordType *RT = FD->getType()->getAs<RecordType>();
- if (RT && RT->getDecl()->isOrContainsUnion())
+ const RecordType *RT = FD->getType()->getAsCanonical<RecordType>();
+ if (RT && RT->getOriginalDecl()->isOrContainsUnion())
return true;
}
}
@@ -5294,9 +5270,8 @@ const FieldDecl *RecordDecl::findFirstNamedDataMember() const {
if (I->getIdentifier())
return I;
- if (const auto *RT = I->getType()->getAs<RecordType>())
- if (const FieldDecl *NamedDataMember =
- RT->getDecl()->findFirstNamedDataMember())
+ if (const auto *RD = I->getType()->getAsRecordDecl())
+ if (const FieldDecl *NamedDataMember = RD->findFirstNamedDataMember())
return NamedDataMember;
}
@@ -5658,14 +5633,14 @@ void TypedefNameDecl::anchor() {}
TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName(bool AnyRedecl) const {
if (auto *TT = getTypeSourceInfo()->getType()->getAs<TagType>()) {
- auto *OwningTypedef = TT->getDecl()->getTypedefNameForAnonDecl();
+ auto *OwningTypedef = TT->getOriginalDecl()->getTypedefNameForAnonDecl();
auto *ThisTypedef = this;
if (AnyRedecl && OwningTypedef) {
OwningTypedef = OwningTypedef->getCanonicalDecl();
ThisTypedef = ThisTypedef->getCanonicalDecl();
}
if (OwningTypedef == ThisTypedef)
- return TT->getDecl();
+ return TT->getOriginalDecl()->getDefinitionOrSelf();
}
return nullptr;
@@ -5674,7 +5649,7 @@ TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName(bool AnyRedecl) const {
bool TypedefNameDecl::isTransparentTagSlow() const {
auto determineIsTransparent = [&]() {
if (auto *TT = getUnderlyingType()->getAs<TagType>()) {
- if (auto *TD = TT->getDecl()) {
+ if (auto *TD = TT->getOriginalDecl()) {
if (TD->getName() != getName())
return false;
SourceLocation TTLoc = getLocation();
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index 13c46fd..680a4d7 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -58,10 +58,6 @@ using namespace clang;
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
-void Decl::updateOutOfDate(IdentifierInfo &II) const {
- getASTContext().getExternalSource()->updateOutOfDateIdentifier(II);
-}
-
#define DECL(DERIVED, BASE) \
static_assert(alignof(Decl) >= alignof(DERIVED##Decl), \
"Alignment sufficient after objects prepended to " #DERIVED);
@@ -489,8 +485,7 @@ bool Decl::isFlexibleArrayMemberLike(
// Look through typedefs.
if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) {
- const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
- TInfo = TDL->getTypeSourceInfo();
+ TInfo = TTL.getDecl()->getTypeSourceInfo();
continue;
}
@@ -1512,30 +1507,19 @@ DeclContext *DeclContext::getPrimaryContext() {
case Decl::ObjCCategoryImpl:
return this;
- default:
- if (getDeclKind() >= Decl::firstTag && getDeclKind() <= Decl::lastTag) {
- // If this is a tag type that has a definition or is currently
- // being defined, that definition is our primary context.
- auto *Tag = cast<TagDecl>(this);
-
- if (TagDecl *Def = Tag->getDefinition())
- return Def;
-
- if (const auto *TagTy = dyn_cast<TagType>(Tag->getTypeForDecl())) {
- // Note, TagType::getDecl returns the (partial) definition one exists.
- TagDecl *PossiblePartialDef = TagTy->getDecl();
- if (PossiblePartialDef->isBeingDefined())
- return PossiblePartialDef;
- } else {
- assert(isa<InjectedClassNameType>(Tag->getTypeForDecl()));
- }
-
- return Tag;
- }
+ // If this is a tag type that has a definition or is currently
+ // being defined, that definition is our primary context.
+ case Decl::ClassTemplatePartialSpecialization:
+ case Decl::ClassTemplateSpecialization:
+ case Decl::CXXRecord:
+ return cast<CXXRecordDecl>(this)->getDefinitionOrSelf();
+ case Decl::Record:
+ case Decl::Enum:
+ return cast<TagDecl>(this)->getDefinitionOrSelf();
+ default:
assert(getDeclKind() >= Decl::firstFunction &&
- getDeclKind() <= Decl::lastFunction &&
- "Unknown DeclContext kind");
+ getDeclKind() <= Decl::lastFunction && "Unknown DeclContext kind");
return this;
}
}
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index 037a28c4..aa1f5a1 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -132,16 +132,9 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, const ASTContext &C,
CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
- CXXRecordDecl *PrevDecl,
- bool DelayTypeCreation) {
- auto *R = new (C, DC) CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc, IdLoc, Id,
- PrevDecl);
- R->setMayHaveOutOfDateDef(C.getLangOpts().Modules);
-
- // FIXME: DelayTypeCreation seems like such a hack
- if (!DelayTypeCreation)
- C.getTypeDeclType(R, PrevDecl);
- return R;
+ CXXRecordDecl *PrevDecl) {
+ return new (C, DC)
+ CXXRecordDecl(CXXRecord, TK, C, DC, StartLoc, IdLoc, Id, PrevDecl);
}
CXXRecordDecl *
@@ -154,10 +147,7 @@ CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
R->setBeingDefined(true);
R->DefinitionData = new (C) struct LambdaDefinitionData(
R, Info, DependencyKind, IsGeneric, CaptureDefault);
- R->setMayHaveOutOfDateDef(false);
R->setImplicit(true);
-
- C.getTypeDeclType(R, /*PrevDecl=*/nullptr);
return R;
}
@@ -166,7 +156,6 @@ CXXRecordDecl *CXXRecordDecl::CreateDeserialized(const ASTContext &C,
auto *R = new (C, ID)
CXXRecordDecl(CXXRecord, TagTypeKind::Struct, C, nullptr,
SourceLocation(), SourceLocation(), nullptr, nullptr);
- R->setMayHaveOutOfDateDef(false);
return R;
}
@@ -178,7 +167,7 @@ static bool hasRepeatedBaseClass(const CXXRecordDecl *StartRD) {
SmallVector<const CXXRecordDecl*, 8> WorkList = {StartRD};
while (!WorkList.empty()) {
const CXXRecordDecl *RD = WorkList.pop_back_val();
- if (RD->getTypeForDecl()->isDependentType())
+ if (RD->isDependentType())
continue;
for (const CXXBaseSpecifier &BaseSpec : RD->bases()) {
if (const CXXRecordDecl *B = BaseSpec.getType()->getAsCXXRecordDecl()) {
@@ -227,8 +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>()->getDecl());
+ auto *BaseClassDecl = BaseType->castAsCXXRecordDecl();
// C++2a [class]p7:
// A standard-layout class is a class that:
@@ -1217,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->getDecl());
- 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
@@ -1448,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
@@ -1918,14 +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->getDecl());
CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess,
*HiddenTypes, Output, VOutput, HiddenVBaseCs);
}
@@ -1960,12 +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->getDecl()),
- 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.
@@ -2125,11 +2120,10 @@ const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const {
CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
ASTContext &Context = getASTContext();
- QualType ClassType = Context.getTypeDeclType(this);
+ CanQualType ClassType = Context.getCanonicalTagType(this);
- DeclarationName Name
- = Context.DeclarationNames.getCXXDestructorName(
- Context.getCanonicalType(ClassType));
+ DeclarationName Name =
+ Context.DeclarationNames.getCXXDestructorName(ClassType);
DeclContext::lookup_result R = lookup(Name);
@@ -2159,6 +2153,29 @@ bool CXXRecordDecl::isInjectedClassName() const {
return false;
}
+bool CXXRecordDecl::hasInjectedClassType() const {
+ switch (getDeclKind()) {
+ case Decl::ClassTemplatePartialSpecialization:
+ return true;
+ case Decl::ClassTemplateSpecialization:
+ return false;
+ case Decl::CXXRecord:
+ return getDescribedClassTemplate() != nullptr;
+ default:
+ llvm_unreachable("unexpected decl kind");
+ }
+}
+
+CanQualType CXXRecordDecl::getCanonicalTemplateSpecializationType(
+ const ASTContext &Ctx) const {
+ if (auto *RD = dyn_cast<ClassTemplatePartialSpecializationDecl>(this))
+ return RD->getCanonicalInjectedSpecializationType(Ctx);
+ if (const ClassTemplateDecl *TD = getDescribedClassTemplate();
+ TD && !isa<ClassTemplateSpecializationDecl>(this))
+ return TD->getCanonicalInjectedSpecializationType(Ctx);
+ return CanQualType();
+}
+
static bool isDeclContextInNamespace(const DeclContext *DC) {
while (!DC->isTranslationUnit()) {
if (DC->isNamespace())
@@ -2272,7 +2289,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
Context.getDiagnostics().Report(
AT->getLocation(),
diag::warn_cxx20_compat_requires_explicit_init_non_aggregate)
- << AT << FD << Context.getRecordType(this);
+ << AT << FD << Context.getCanonicalTagType(this);
}
}
@@ -2284,7 +2301,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
if (const auto *AT = FD->getAttr<ExplicitInitAttr>())
Context.getDiagnostics().Report(AT->getLocation(),
diag::warn_attribute_needs_aggregate)
- << AT << Context.getRecordType(this);
+ << AT << Context.getCanonicalTagType(this);
}
setHasUninitializedExplicitInitFields(false);
}
@@ -2296,8 +2313,8 @@ bool CXXRecordDecl::mayBeAbstract() const {
return false;
for (const auto &B : bases()) {
- const auto *BaseDecl =
- cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl());
+ const auto *BaseDecl = cast<CXXRecordDecl>(
+ B.getType()->castAsCanonical<RecordType>()->getOriginalDecl());
if (BaseDecl->isAbstract())
return true;
}
@@ -2457,10 +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->getDecl());
if (CXXMethodDecl *D = this->getCorrespondingMethodInClass(Base))
AddFinalOverrider(D);
}
@@ -2712,8 +2728,7 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const {
ParamType = Ref->getPointeeType();
ASTContext &Context = getASTContext();
- QualType ClassType
- = Context.getCanonicalType(Context.getTypeDeclType(getParent()));
+ CanQualType ClassType = Context.getCanonicalTagType(getParent());
return Context.hasSameUnqualifiedType(ClassType, ParamType);
}
@@ -2733,8 +2748,7 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const {
ParamType = ParamType->getPointeeType();
ASTContext &Context = getASTContext();
- QualType ClassType
- = Context.getCanonicalType(Context.getTypeDeclType(getParent()));
+ CanQualType ClassType = Context.getCanonicalTagType(getParent());
return Context.hasSameUnqualifiedType(ClassType, ParamType);
}
@@ -2769,7 +2783,7 @@ CXXMethodDecl::overridden_methods() const {
static QualType getThisObjectType(ASTContext &C, const FunctionProtoType *FPT,
const CXXRecordDecl *Decl) {
- QualType ClassTy = C.getTypeDeclType(Decl);
+ CanQualType ClassTy = C.getCanonicalTagType(Decl);
return C.getQualifiedType(ClassTy, FPT->getMethodQuals());
}
@@ -3027,11 +3041,9 @@ bool CXXConstructorDecl::isCopyOrMoveConstructor(unsigned &TypeQuals) const {
// Is it a reference to our class type?
ASTContext &Context = getASTContext();
- CanQualType PointeeType
- = Context.getCanonicalType(ParamRefType->getPointeeType());
- CanQualType ClassTy
- = Context.getCanonicalType(Context.getTagDeclType(getParent()));
- if (PointeeType.getUnqualifiedType() != ClassTy)
+ QualType PointeeType = ParamRefType->getPointeeType();
+ CanQualType ClassTy = Context.getCanonicalTagType(getParent());
+ if (!Context.hasSameUnqualifiedType(PointeeType, ClassTy))
return false;
// FIXME: other qualifiers?
@@ -3066,15 +3078,11 @@ bool CXXConstructorDecl::isSpecializationCopyingObject() const {
const ParmVarDecl *Param = getParamDecl(0);
ASTContext &Context = getASTContext();
- CanQualType ParamType = Context.getCanonicalType(Param->getType());
+ CanQualType ParamType = Param->getType()->getCanonicalTypeUnqualified();
// Is it the same as our class type?
- CanQualType ClassTy
- = Context.getCanonicalType(Context.getTagDeclType(getParent()));
- if (ParamType.getUnqualifiedType() != ClassTy)
- return false;
-
- return true;
+ CanQualType ClassTy = Context.getCanonicalTagType(getParent());
+ return ParamType == ClassTy;
}
void CXXDestructorDecl::anchor() {}
@@ -3371,7 +3379,7 @@ ConstructorUsingShadowDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) {
}
CXXRecordDecl *ConstructorUsingShadowDecl::getNominatedBaseClass() const {
- return getIntroducer()->getQualifier()->getAsRecordDecl();
+ return getIntroducer()->getQualifier().getAsRecordDecl();
}
void BaseUsingDecl::anchor() {}
@@ -3429,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/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index f4265dd0..196057f 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -202,8 +202,7 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls,
}
Decl** End = Begin + NumDecls;
- TagDecl* TD = dyn_cast<TagDecl>(*Begin);
- if (TD)
+ if (isa<TagDecl>(*Begin))
++Begin;
PrintingPolicy SubPolicy(Policy);
@@ -211,13 +210,9 @@ void Decl::printGroup(Decl** Begin, unsigned NumDecls,
bool isFirst = true;
for ( ; Begin != End; ++Begin) {
if (isFirst) {
- if(TD)
- SubPolicy.IncludeTagDefinition = true;
- SubPolicy.SuppressSpecifiers = false;
isFirst = false;
} else {
- if (!isFirst) Out << ", ";
- SubPolicy.IncludeTagDefinition = false;
+ Out << ", ";
SubPolicy.SuppressSpecifiers = true;
}
@@ -487,10 +482,12 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
QualType CurDeclType = getDeclType(*D);
if (!Decls.empty() && !CurDeclType.isNull()) {
QualType BaseType = GetBaseType(CurDeclType);
- if (!BaseType.isNull() && isa<ElaboratedType>(BaseType) &&
- cast<ElaboratedType>(BaseType)->getOwnedTagDecl() == Decls[0]) {
- Decls.push_back(*D);
- continue;
+ if (const auto *TT = dyn_cast_or_null<TagType>(BaseType);
+ TT && TT->isTagOwned()) {
+ if (TT->getOriginalDecl() == Decls[0]) {
+ Decls.push_back(*D);
+ continue;
+ }
}
}
@@ -662,16 +659,6 @@ static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out,
Out << Proto;
}
-static void MaybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy,
- QualType T,
- llvm::raw_ostream &Out) {
- StringRef prefix = T->isClassType() ? "class "
- : T->isStructureType() ? "struct "
- : T->isUnionType() ? "union "
- : "";
- Out << prefix;
-}
-
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (!D->getDescribedFunctionTemplate() &&
!D->isFunctionTemplateSpecialization()) {
@@ -721,11 +708,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Proto += D->getQualifiedNameAsString();
} else {
llvm::raw_string_ostream OS(Proto);
- if (!Policy.SuppressScope) {
- if (const NestedNameSpecifier *NS = D->getQualifier()) {
- NS->print(OS, Policy);
- }
- }
+ if (!Policy.SuppressScope)
+ D->getQualifier().print(OS, Policy);
D->getNameInfo().printName(OS, Policy);
}
@@ -833,10 +817,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Out << Proto << " -> ";
Proto.clear();
}
- if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
- !Policy.SuppressUnwrittenScope)
- MaybePrintTagKeywordIfSupressingScopes(Policy, AFT->getReturnType(),
- Out);
AFT->getReturnType().print(Out, Policy, Proto);
Proto.clear();
}
@@ -995,10 +975,6 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
}
}
- if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
- !Policy.SuppressUnwrittenScope)
- MaybePrintTagKeywordIfSupressingScopes(Policy, T, Out);
-
printDeclType(T, (isa<ParmVarDecl>(D) && Policy.CleanUglifiedParameters &&
D->getIdentifier())
? D->getIdentifier()->deuglifiedName()
@@ -1028,7 +1004,6 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
}
PrintingPolicy SubPolicy(Policy);
SubPolicy.SuppressSpecifiers = false;
- SubPolicy.IncludeTagDefinition = false;
Init->printPretty(Out, nullptr, SubPolicy, Indentation, "\n", &Context);
if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
Out << ")";
@@ -1086,15 +1061,13 @@ void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) {
void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
Out << "using namespace ";
- if (D->getQualifier())
- D->getQualifier()->print(Out, Policy);
+ D->getQualifier().print(Out, Policy);
Out << *D->getNominatedNamespaceAsWritten();
}
void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
Out << "namespace " << *D << " = ";
- if (D->getQualifier())
- D->getQualifier()->print(Out, Policy);
+ D->getQualifier().print(Out, Policy);
Out << *D->getAliasedNamespace();
}
@@ -1115,8 +1088,7 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
Out << ' ';
if (D->getIdentifier()) {
- if (auto *NNS = D->getQualifier())
- NNS->print(Out, Policy);
+ D->getQualifier().print(Out, Policy);
Out << *D;
if (auto *S = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
@@ -1746,7 +1718,7 @@ void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
Out << "using ";
if (D->hasTypename())
Out << "typename ";
- D->getQualifier()->print(Out, Policy);
+ D->getQualifier().print(Out, Policy);
// Use the correct record name when the using declaration is used for
// inheriting constructors.
@@ -1768,14 +1740,14 @@ void DeclPrinter::VisitUsingEnumDecl(UsingEnumDecl *D) {
void
DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
Out << "using typename ";
- D->getQualifier()->print(Out, Policy);
+ D->getQualifier().print(Out, Policy);
Out << D->getDeclName();
}
void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
if (!D->isAccessDeclaration())
Out << "using ";
- D->getQualifier()->print(Out, Policy);
+ D->getQualifier().print(Out, Policy);
Out << D->getDeclName();
}
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index bc4a299..3162857 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -307,8 +307,9 @@ bool TemplateDecl::hasAssociatedConstraints() const {
bool TemplateDecl::isTypeAlias() const {
switch (getKind()) {
case TemplateDecl::TypeAliasTemplate:
- case TemplateDecl::BuiltinTemplate:
return true;
+ case TemplateDecl::BuiltinTemplate:
+ return !cast<BuiltinTemplateDecl>(this)->isPackProducingBuiltinTemplate();
default:
return false;
};
@@ -632,7 +633,8 @@ ClassTemplateDecl::findPartialSpecialization(QualType T) {
ASTContext &Context = getASTContext();
for (ClassTemplatePartialSpecializationDecl &P :
getPartialSpecializations()) {
- if (Context.hasSameType(P.getInjectedSpecializationType(), T))
+ if (Context.hasSameType(P.getCanonicalInjectedSpecializationType(Context),
+ T))
return P.getMostRecentDecl();
}
@@ -651,28 +653,20 @@ ClassTemplateDecl::findPartialSpecInstantiatedFromMember(
return nullptr;
}
-QualType
-ClassTemplateDecl::getInjectedClassNameSpecialization() {
+CanQualType ClassTemplateDecl::getCanonicalInjectedSpecializationType(
+ const ASTContext &Ctx) const {
Common *CommonPtr = getCommonPtr();
- if (!CommonPtr->InjectedClassNameType.isNull())
- return CommonPtr->InjectedClassNameType;
-
- // C++0x [temp.dep.type]p2:
- // The template argument list of a primary template is a template argument
- // list in which the nth template argument has the value of the nth template
- // parameter of the class template. If the nth template parameter is a
- // template parameter pack (14.5.3), the nth template argument is a pack
- // expansion (14.5.3) whose pattern is the name of the template parameter
- // pack.
- ASTContext &Context = getASTContext();
- TemplateName Name = Context.getQualifiedTemplateName(
- /*NNS=*/nullptr, /*TemplateKeyword=*/false, TemplateName(this));
- auto TemplateArgs = getTemplateParameters()->getInjectedTemplateArgs(Context);
- CommonPtr->InjectedClassNameType =
- Context.getTemplateSpecializationType(Name,
- /*SpecifiedArgs=*/TemplateArgs,
- /*CanonicalArgs=*/{});
- return CommonPtr->InjectedClassNameType;
+
+ if (CommonPtr->CanonInjectedTST.isNull()) {
+ SmallVector<TemplateArgument> CanonicalArgs(
+ getTemplateParameters()->getInjectedTemplateArgs(Ctx));
+ Ctx.canonicalizeTemplateArguments(CanonicalArgs);
+ CommonPtr->CanonInjectedTST =
+ CanQualType::CreateUnsafe(Ctx.getCanonicalTemplateSpecializationType(
+ TemplateName(const_cast<ClassTemplateDecl *>(getCanonicalDecl())),
+ CanonicalArgs));
+ }
+ return CommonPtr->CanonInjectedTST;
}
//===----------------------------------------------------------------------===//
@@ -736,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(
@@ -998,7 +992,6 @@ ClassTemplateSpecializationDecl *ClassTemplateSpecializationDecl::Create(
auto *Result = new (Context, DC) ClassTemplateSpecializationDecl(
Context, ClassTemplateSpecialization, TK, DC, StartLoc, IdLoc,
SpecializedTemplate, Args, StrictPackMatch, PrevDecl);
- Result->setMayHaveOutOfDateDef(false);
// If the template decl is incomplete, copy the external lexical storage from
// the base template. This allows instantiations of incomplete types to
@@ -1008,17 +1001,14 @@ ClassTemplateSpecializationDecl *ClassTemplateSpecializationDecl::Create(
Result->setHasExternalLexicalStorage(
SpecializedTemplate->getTemplatedDecl()->hasExternalLexicalStorage());
- Context.getTypeDeclType(Result, PrevDecl);
return Result;
}
ClassTemplateSpecializationDecl *
ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C,
GlobalDeclID ID) {
- auto *Result =
- new (C, ID) ClassTemplateSpecializationDecl(C, ClassTemplateSpecialization);
- Result->setMayHaveOutOfDateDef(false);
- return Result;
+ return new (C, ID)
+ ClassTemplateSpecializationDecl(C, ClassTemplateSpecialization);
}
void ClassTemplateSpecializationDecl::getNameForDiagnostic(
@@ -1180,13 +1170,15 @@ ClassTemplatePartialSpecializationDecl::ClassTemplatePartialSpecializationDecl(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
+ CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl)
: ClassTemplateSpecializationDecl(
Context, ClassTemplatePartialSpecialization, TK, DC, StartLoc, IdLoc,
// Tracking StrictPackMatch for Partial
// Specializations is not needed.
SpecializedTemplate, Args, /*StrictPackMatch=*/false, PrevDecl),
- TemplateParams(Params), InstantiatedFromMember(nullptr, false) {
+ TemplateParams(Params), InstantiatedFromMember(nullptr, false),
+ CanonInjectedTST(CanonInjectedTST) {
if (AdoptTemplateParameterList(Params, this))
setInvalidDecl();
}
@@ -1196,24 +1188,31 @@ ClassTemplatePartialSpecializationDecl::Create(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
- QualType CanonInjectedType,
+ CanQualType CanonInjectedTST,
ClassTemplatePartialSpecializationDecl *PrevDecl) {
auto *Result = new (Context, DC) ClassTemplatePartialSpecializationDecl(
Context, TK, DC, StartLoc, IdLoc, Params, SpecializedTemplate, Args,
- PrevDecl);
+ CanonInjectedTST, PrevDecl);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
- Result->setMayHaveOutOfDateDef(false);
-
- Context.getInjectedClassNameType(Result, CanonInjectedType);
return Result;
}
ClassTemplatePartialSpecializationDecl *
ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
GlobalDeclID ID) {
- auto *Result = new (C, ID) ClassTemplatePartialSpecializationDecl(C);
- Result->setMayHaveOutOfDateDef(false);
- return Result;
+ return new (C, ID) ClassTemplatePartialSpecializationDecl(C);
+}
+
+CanQualType
+ClassTemplatePartialSpecializationDecl::getCanonicalInjectedSpecializationType(
+ const ASTContext &Ctx) const {
+ if (CanonInjectedTST.isNull()) {
+ CanonInjectedTST =
+ CanQualType::CreateUnsafe(Ctx.getCanonicalTemplateSpecializationType(
+ TemplateName(getSpecializedTemplate()->getCanonicalDecl()),
+ getTemplateArgs().asArray()));
+ }
+ return CanonInjectedTST;
}
SourceRange ClassTemplatePartialSpecializationDecl::getSourceRange() const {
@@ -1600,6 +1599,16 @@ BuiltinTemplateDecl::BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC,
createBuiltinTemplateParameterList(C, DC, BTK)),
BTK(BTK) {}
+bool BuiltinTemplateDecl::isPackProducingBuiltinTemplate() const {
+ return getBuiltinTemplateKind() == clang::BTK__builtin_dedup_pack;
+}
+
+bool clang::isPackProducingBuiltinTemplateName(TemplateName N) {
+ auto *T = dyn_cast_or_null<BuiltinTemplateDecl>(
+ N.getAsTemplateDecl(/*IgnoreDeduced=*/true));
+ return T && T->isPackProducingBuiltinTemplate();
+}
+
TemplateParamObjectDecl *TemplateParamObjectDecl::Create(const ASTContext &C,
QualType T,
const APValue &V) {
diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp
index ae5fcf6..55f5a99 100644
--- a/clang/lib/AST/DeclarationName.cpp
+++ b/clang/lib/AST/DeclarationName.cpp
@@ -113,14 +113,15 @@ 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>()) {
- ClassRec->getDecl()->printName(OS, Policy);
+ if (const RecordType *ClassRec = ClassType->getAsCanonical<RecordType>()) {
+ ClassRec->getOriginalDecl()->printName(OS, Policy);
return;
}
if (Policy.SuppressTemplateArgsInCXXConstructors) {
- if (auto *InjTy = ClassType->getAs<InjectedClassNameType>()) {
- InjTy->getDecl()->printName(OS, Policy);
+ if (auto *InjTy = ClassType->getAsCanonical<InjectedClassNameType>()) {
+ InjTy->getOriginalDecl()->printName(OS, Policy);
return;
}
}
@@ -184,7 +185,7 @@ void DeclarationName::print(raw_ostream &OS,
OS << "operator ";
QualType Type = getCXXNameType();
if (const RecordType *Rec = Type->getAs<RecordType>()) {
- OS << *Rec->getDecl();
+ OS << *Rec->getOriginalDecl();
return;
}
// We know we're printing C++ here, ensure we print 'bool' properly.
diff --git a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp
index b478e7a..8821cd3 100644
--- a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp
+++ b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp
@@ -115,8 +115,12 @@ template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> {
bool TraverseAST(ASTContext &AST) { return Visitor.TraverseAST(AST); }
bool TraverseAttr(Attr *At) { return Visitor.TraverseAttr(At); }
bool TraverseDecl(Decl *D) { return Visitor.TraverseDecl(D); }
- bool TraverseType(QualType T) { return Visitor.TraverseType(T); }
- bool TraverseTypeLoc(TypeLoc TL) { return Visitor.TraverseTypeLoc(TL); }
+ bool TraverseType(QualType T, bool TraverseQualifier = true) {
+ return Visitor.TraverseType(T, TraverseQualifier);
+ }
+ bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) {
+ return Visitor.TraverseTypeLoc(TL, TraverseQualifier);
+ }
bool TraverseStmt(Stmt *S) { return Visitor.TraverseStmt(S); }
bool TraverseConstructorInitializer(CXXCtorInitializer *Init) {
@@ -172,7 +176,7 @@ template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> {
return Visitor.TraverseLambdaCapture(LE, C, Init);
}
- bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
+ bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS) {
return Visitor.TraverseNestedNameSpecifier(NNS);
}
@@ -241,8 +245,8 @@ template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> {
// Types.
#define ABSTRACT_TYPE(CLASS, BASE)
#define TYPE(CLASS, BASE) \
- bool Traverse##CLASS##Type(CLASS##Type *T) { \
- return Visitor.Traverse##CLASS##Type(T); \
+ bool Traverse##CLASS##Type(CLASS##Type *T, bool TraverseQualifier) { \
+ return Visitor.Traverse##CLASS##Type(T, TraverseQualifier); \
}
#include "clang/AST/TypeNodes.inc"
@@ -255,8 +259,8 @@ template <bool Const> struct Impl : RecursiveASTVisitor<Impl<Const>> {
// TypeLocs.
#define ABSTRACT_TYPELOC(CLASS, BASE)
#define TYPELOC(CLASS, BASE) \
- bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL) { \
- return Visitor.Traverse##CLASS##TypeLoc(TL); \
+ bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL, bool TraverseQualifier) { \
+ return Visitor.Traverse##CLASS##TypeLoc(TL, TraverseQualifier); \
}
#include "clang/AST/TypeLocNodes.def"
@@ -297,7 +301,6 @@ FORWARD_TO_BASE(TraverseAttr, Attr, *)
FORWARD_TO_BASE(TraverseConstructorInitializer, CXXCtorInitializer, *)
FORWARD_TO_BASE(TraverseDecl, Decl, *)
FORWARD_TO_BASE(TraverseStmt, Stmt, *)
-FORWARD_TO_BASE(TraverseNestedNameSpecifier, NestedNameSpecifier, *)
FORWARD_TO_BASE(TraverseTemplateInstantiations, ClassTemplateDecl, *)
FORWARD_TO_BASE(TraverseTemplateInstantiations, VarTemplateDecl, *)
FORWARD_TO_BASE(TraverseTemplateInstantiations, FunctionTemplateDecl, *)
@@ -314,8 +317,22 @@ FORWARD_TO_BASE_EXACT(TraverseTemplateArgument, const TemplateArgument &)
FORWARD_TO_BASE_EXACT(TraverseTemplateArguments, ArrayRef<TemplateArgument>)
FORWARD_TO_BASE_EXACT(TraverseTemplateArgumentLoc, const TemplateArgumentLoc &)
FORWARD_TO_BASE_EXACT(TraverseTemplateName, TemplateName)
-FORWARD_TO_BASE_EXACT(TraverseType, QualType)
-FORWARD_TO_BASE_EXACT(TraverseTypeLoc, TypeLoc)
+FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifier, NestedNameSpecifier)
+
+template <bool Const>
+bool DynamicRecursiveASTVisitorBase<Const>::TraverseType(
+ QualType T, bool TraverseQualifier) {
+ return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::TraverseType(
+ T, TraverseQualifier);
+}
+
+template <bool Const>
+bool DynamicRecursiveASTVisitorBase<Const>::TraverseTypeLoc(
+ TypeLoc TL, bool TraverseQualifier) {
+ return Impl<Const>(*this).RecursiveASTVisitor<Impl<Const>>::TraverseTypeLoc(
+ TL, TraverseQualifier);
+}
+
FORWARD_TO_BASE_EXACT(TraverseTypeConstraint, const TypeConstraint *)
FORWARD_TO_BASE_EXACT(TraverseObjCProtocolLoc, ObjCProtocolLoc)
FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifierLoc, NestedNameSpecifierLoc)
@@ -354,13 +371,25 @@ bool DynamicRecursiveASTVisitorBase<Const>::dataTraverseNode(
// Declare Traverse*() and friends for all concrete Type classes.
#define ABSTRACT_TYPE(CLASS, BASE)
#define TYPE(CLASS, BASE) \
- FORWARD_TO_BASE(Traverse##CLASS##Type, CLASS##Type, *) \
+ template <bool Const> \
+ bool DynamicRecursiveASTVisitorBase<Const>::Traverse##CLASS##Type( \
+ MaybeConst<CLASS##Type> *T, bool TraverseQualifier) { \
+ return Impl<Const>(*this) \
+ .RecursiveASTVisitor<Impl<Const>>::Traverse##CLASS##Type( \
+ const_cast<CLASS##Type *>(T), TraverseQualifier); \
+ } \
FORWARD_TO_BASE(WalkUpFrom##CLASS##Type, CLASS##Type, *)
#include "clang/AST/TypeNodes.inc"
#define ABSTRACT_TYPELOC(CLASS, BASE)
#define TYPELOC(CLASS, BASE) \
- FORWARD_TO_BASE_EXACT(Traverse##CLASS##TypeLoc, CLASS##TypeLoc)
+ template <bool Const> \
+ bool DynamicRecursiveASTVisitorBase<Const>::Traverse##CLASS##TypeLoc( \
+ CLASS##TypeLoc TL, bool TraverseQualifier) { \
+ return Impl<Const>(*this) \
+ .RecursiveASTVisitor<Impl<Const>>::Traverse##CLASS##TypeLoc( \
+ TL, TraverseQualifier); \
+ }
#include "clang/AST/TypeLocNodes.def"
#define TYPELOC(CLASS, BASE) \
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index cd9672d..cdff160 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -74,9 +74,7 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const {
if (DerivedType->isDependentType())
return nullptr;
- const RecordType *Ty = DerivedType->castAs<RecordType>();
- Decl *D = Ty->getDecl();
- return cast<CXXRecordDecl>(D);
+ return DerivedType->castAsCXXRecordDecl();
}
const Expr *Expr::skipRValueSubobjectAdjustments(
@@ -91,8 +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>()->getDecl());
+ const auto *Derived = E->getType()->castAsCXXRecordDecl();
Adjustments.push_back(SubobjectAdjustment(CE, Derived));
continue;
}
@@ -268,7 +265,7 @@ QualType Expr::getEnumCoercedType(const ASTContext &Ctx) const {
if (const auto *ECD = getEnumConstantDecl()) {
const auto *ED = cast<EnumDecl>(ECD->getDeclContext());
if (ED->isCompleteDefinition())
- return Ctx.getTypeDeclType(ED);
+ return Ctx.getCanonicalTagType(ED);
}
return getType();
}
@@ -2031,8 +2028,7 @@ CXXBaseSpecifier **CastExpr::path_buffer() {
const FieldDecl *CastExpr::getTargetFieldForToUnionCast(QualType unionType,
QualType opType) {
- auto RD = unionType->castAs<RecordType>()->getDecl();
- return getTargetFieldForToUnionCast(RD, opType);
+ return getTargetFieldForToUnionCast(unionType->castAsRecordDecl(), opType);
}
const FieldDecl *CastExpr::getTargetFieldForToUnionCast(const RecordDecl *RD,
@@ -2399,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,
@@ -2774,23 +2771,22 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case UserDefinedLiteralClass: {
// If this is a direct call, get the callee.
const CallExpr *CE = cast<CallExpr>(this);
- if (const Decl *FD = CE->getCalleeDecl()) {
- // If the callee has attribute pure, const, or warn_unused_result, warn
- // about it. void foo() { strlen("bar"); } should warn.
- //
- // Note: If new cases are added here, DiagnoseUnusedExprResult should be
- // updated to match for QoI.
- if (CE->hasUnusedResultAttr(Ctx) ||
- FD->hasAttr<PureAttr>() || FD->hasAttr<ConstAttr>()) {
- WarnE = this;
- Loc = CE->getCallee()->getBeginLoc();
- R1 = CE->getCallee()->getSourceRange();
-
- if (unsigned NumArgs = CE->getNumArgs())
- R2 = SourceRange(CE->getArg(0)->getBeginLoc(),
- CE->getArg(NumArgs - 1)->getEndLoc());
- return true;
- }
+ // If the callee has attribute pure, const, or warn_unused_result, warn
+ // about it. void foo() { strlen("bar"); } should warn.
+ // Note: If new cases are added here, DiagnoseUnusedExprResult should be
+ // updated to match for QoI.
+ const Decl *FD = CE->getCalleeDecl();
+ bool PureOrConst =
+ FD && (FD->hasAttr<PureAttr>() || FD->hasAttr<ConstAttr>());
+ if (CE->hasUnusedResultAttr(Ctx) || PureOrConst) {
+ WarnE = this;
+ Loc = getBeginLoc();
+ R1 = getSourceRange();
+
+ if (unsigned NumArgs = CE->getNumArgs())
+ R2 = SourceRange(CE->getArg(0)->getBeginLoc(),
+ CE->getArg(NumArgs - 1)->getEndLoc());
+ return true;
}
return false;
}
@@ -2803,32 +2799,20 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case CXXTemporaryObjectExprClass:
case CXXConstructExprClass: {
- if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) {
- const auto *WarnURAttr = Type->getAttr<WarnUnusedResultAttr>();
- if (Type->hasAttr<WarnUnusedAttr>() ||
- (WarnURAttr && WarnURAttr->IsCXX11NoDiscard())) {
- WarnE = this;
- Loc = getBeginLoc();
- R1 = getSourceRange();
- return true;
- }
- }
-
const auto *CE = cast<CXXConstructExpr>(this);
- if (const CXXConstructorDecl *Ctor = CE->getConstructor()) {
- const auto *WarnURAttr = Ctor->getAttr<WarnUnusedResultAttr>();
- if (WarnURAttr && WarnURAttr->IsCXX11NoDiscard()) {
- WarnE = this;
- Loc = getBeginLoc();
- R1 = getSourceRange();
-
- if (unsigned NumArgs = CE->getNumArgs())
- R2 = SourceRange(CE->getArg(0)->getBeginLoc(),
- CE->getArg(NumArgs - 1)->getEndLoc());
- return true;
- }
- }
+ const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl();
+ if ((Type && Type->hasAttr<WarnUnusedAttr>()) ||
+ CE->hasUnusedResultAttr(Ctx)) {
+ WarnE = this;
+ Loc = getBeginLoc();
+ R1 = getSourceRange();
+
+ if (unsigned NumArgs = CE->getNumArgs())
+ R2 = SourceRange(CE->getArg(0)->getBeginLoc(),
+ CE->getArg(NumArgs - 1)->getEndLoc());
+ return true;
+ }
return false;
}
@@ -3221,7 +3205,7 @@ static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) {
/// isTemporaryObject - Determines if this expression produces a
/// temporary of the given class type.
bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const {
- if (!C.hasSameUnqualifiedType(getType(), C.getTypeDeclType(TempTy)))
+ if (!C.hasSameUnqualifiedType(getType(), C.getCanonicalTagType(TempTy)))
return false;
const Expr *E = skipTemporaryBindingsNoOpCastsAndParens(this);
@@ -3407,7 +3391,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
if (ILE->getType()->isRecordType()) {
unsigned ElementNo = 0;
- RecordDecl *RD = ILE->getType()->castAs<RecordType>()->getDecl();
+ auto *RD = ILE->getType()->castAsRecordDecl();
// In C++17, bases were added to the list of members used by aggregate
// initialization.
@@ -3541,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;
}
@@ -4050,8 +4084,10 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return NPCK_CXX11_nullptr;
if (const RecordType *UT = getType()->getAsUnionType())
- if (!Ctx.getLangOpts().CPlusPlus11 &&
- UT && UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ if (!Ctx.getLangOpts().CPlusPlus11 && UT &&
+ UT->getOriginalDecl()
+ ->getMostRecentDecl()
+ ->hasAttr<TransparentUnionAttr>())
if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(this)){
const Expr *InitExpr = CLE->getInitializer();
if (const InitListExpr *ILE = dyn_cast<InitListExpr>(InitExpr))
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index a099e97..97ae4a0 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -1319,7 +1319,7 @@ LambdaExpr *LambdaExpr::Create(const ASTContext &Context, CXXRecordDecl *Class,
bool ContainsUnexpandedParameterPack) {
// Determine the type of the expression (i.e., the type of the
// function object we're creating).
- QualType T = Context.getTypeDeclType(Class);
+ CanQualType T = Context.getCanonicalTagType(Class);
unsigned Size = totalSizeToAlloc<Stmt *>(CaptureInits.size() + 1);
void *Mem = Context.Allocate(Size);
@@ -1687,10 +1687,9 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() {
// It can't be dependent: after all, we were actually able to do the
// lookup.
CXXRecordDecl *Record = nullptr;
- auto *NNS = getQualifier();
- if (NNS && NNS->getKind() != NestedNameSpecifier::Super) {
- const Type *T = getQualifier()->getAsType();
- assert(T && "qualifier in member expression does not name type");
+ if (NestedNameSpecifier Qualifier = getQualifier();
+ Qualifier.getKind() == NestedNameSpecifier::Kind::Type) {
+ const Type *T = getQualifier().getAsType();
Record = T->getAsCXXRecordDecl();
assert(Record && "qualifier in member expression does not name record");
}
diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp
index ac0e566..36f910d 100644
--- a/clang/lib/AST/ExprConcepts.cpp
+++ b/clang/lib/AST/ExprConcepts.cpp
@@ -41,10 +41,10 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
assert(!Loc->getNestedNameSpecifierLoc() ||
(!Loc->getNestedNameSpecifierLoc()
.getNestedNameSpecifier()
- ->isInstantiationDependent() &&
+ .isInstantiationDependent() &&
!Loc->getNestedNameSpecifierLoc()
.getNestedNameSpecifier()
- ->containsUnexpandedParameterPack()));
+ .containsUnexpandedParameterPack()));
assert((!isValueDependent() || isInstantiationDependent()) &&
"should not be value-dependent");
}
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 3679327..b4f1e76 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;
}
@@ -401,7 +392,7 @@ namespace {
assert(!Invalid && "invalid designator has no subobject type");
return MostDerivedPathLength == Entries.size()
? MostDerivedType
- : Ctx.getRecordType(getAsBaseClass(Entries.back()));
+ : Ctx.getCanonicalTagType(getAsBaseClass(Entries.back()));
}
/// Update this designator to refer to the first element within this array.
@@ -2623,7 +2614,7 @@ static bool CheckEvaluationResult(CheckEvaluationResultKind CERK,
Value.getUnionValue(), Kind, Value.getUnionField(), CheckedTemps);
}
if (Value.isStruct()) {
- RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
+ auto *RD = Type->castAsRecordDecl();
if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
unsigned BaseIndex = 0;
for (const CXXBaseSpecifier &BS : CD->bases()) {
@@ -4109,7 +4100,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
}
// Next subobject is a class, struct or union field.
- RecordDecl *RD = ObjType->castAs<RecordType>()->getDecl();
+ RecordDecl *RD =
+ ObjType->castAsCanonical<RecordType>()->getOriginalDecl();
if (RD->isUnion()) {
const FieldDecl *UnionField = O->getUnionField();
if (!UnionField ||
@@ -4144,7 +4136,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
const CXXRecordDecl *Base = getAsBaseClass(Sub.Entries[I]);
O = &O->getStructBase(getBaseIndex(Derived, Base));
- ObjType = getSubobjectType(ObjType, Info.Ctx.getRecordType(Base));
+ ObjType = getSubobjectType(ObjType, Info.Ctx.getCanonicalTagType(Base));
}
}
}
@@ -6363,7 +6355,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E,
const CXXRecordDecl *C = E->getTypeAsWritten()->getPointeeCXXRecordDecl();
assert(C && "dynamic_cast target is not void pointer nor class");
- CanQualType CQT = Info.Ctx.getCanonicalType(Info.Ctx.getRecordType(C));
+ CanQualType CQT = Info.Ctx.getCanonicalTagType(C);
auto RuntimeCheckFailed = [&] (CXXBasePaths *Paths) {
// C++ [expr.dynamic.cast]p9:
@@ -6389,7 +6381,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E,
}
Info.FFDiag(E, diag::note_constexpr_dynamic_cast_to_reference_failed)
<< DiagKind << Ptr.Designator.getType(Info.Ctx)
- << Info.Ctx.getRecordType(DynType->Type)
+ << Info.Ctx.getCanonicalTagType(DynType->Type)
<< E->getType().getUnqualifiedType();
return false;
};
@@ -6886,8 +6878,8 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
// FIXME: This immediately starts the lifetime of all members of
// an anonymous struct. It would be preferable to strictly start
// member lifetime in initialization order.
- Success &=
- handleDefaultInitValue(Info.Ctx.getRecordType(CD), *Value);
+ Success &= handleDefaultInitValue(Info.Ctx.getCanonicalTagType(CD),
+ *Value);
}
// Store Subobject as its parent before updating it for the last element
// in the chain.
@@ -7794,7 +7786,8 @@ class BufferToAPValueConverter {
}
std::optional<APValue> visit(const EnumType *Ty, CharUnits Offset) {
- QualType RepresentationType = Ty->getDecl()->getIntegerType();
+ QualType RepresentationType =
+ Ty->getOriginalDecl()->getDefinitionOrSelf()->getIntegerType();
assert(!RepresentationType.isNull() &&
"enum forward decl should be caught by Sema");
const auto *AsBuiltin =
@@ -7982,8 +7975,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;
}
@@ -7992,8 +7986,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;
}
}
@@ -8528,7 +8523,7 @@ public:
if (auto *DD = dyn_cast<CXXDestructorDecl>(FD)) {
assert(This && "no 'this' pointer for destructor call");
return HandleDestruction(Info, E, *This,
- Info.Ctx.getRecordType(DD->getParent())) &&
+ Info.Ctx.getCanonicalTagType(DD->getParent())) &&
CallScope.destroy();
}
@@ -8589,8 +8584,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>()->getDecl()->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
@@ -8817,8 +8813,9 @@ public:
const ValueDecl *MD = E->getMemberDecl();
if (const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
- assert(BaseTy->castAs<RecordType>()->getDecl()->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;
@@ -9257,8 +9254,8 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
if (!DynType)
return false;
- TypeInfo =
- TypeInfoLValue(Info.Ctx.getRecordType(DynType->Type).getTypePtr());
+ TypeInfo = TypeInfoLValue(
+ Info.Ctx.getCanonicalTagType(DynType->Type).getTypePtr());
}
return Success(APValue::LValueBase::getTypeInfo(TypeInfo, E->getType()));
@@ -9460,57 +9457,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,
@@ -9520,7 +9466,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
@@ -10011,7 +9963,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);
@@ -10818,7 +10770,7 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
}
bool RecordExprEvaluator::ZeroInitialization(const Expr *E, QualType T) {
- const RecordDecl *RD = T->castAs<RecordType>()->getDecl();
+ 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
@@ -10887,8 +10839,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
const Expr *ExprToVisit, ArrayRef<Expr *> Args) {
- const RecordDecl *RD =
- ExprToVisit->getType()->castAs<RecordType>()->getDecl();
+ const auto *RD = ExprToVisit->getType()->castAsRecordDecl();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
@@ -11036,10 +10987,6 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
bool ZeroInit = E->requiresZeroInitialization();
if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
- // If we've already performed zero-initialization, we're already done.
- if (Result.hasValue())
- return true;
-
if (ZeroInit)
return ZeroInitialization(E, T);
@@ -11116,7 +11063,7 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
Result = APValue(APValue::UninitStruct(), 0, 2);
Array.moveInto(Result.getStructField(0));
- RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
+ auto *Record = E->getType()->castAsRecordDecl();
RecordDecl::field_iterator Field = Record->field_begin();
assert(Field != Record->field_end() &&
Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
@@ -11302,6 +11249,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();
@@ -11627,30 +11592,424 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
+ case Builtin::BI__builtin_elementwise_abs: {
+ APValue Source;
+ if (!EvaluateAsRValue(Info, E->getArg(0), Source))
+ return false;
+
+ QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
+ unsigned SourceLen = Source.getVectorLength();
+ SmallVector<APValue, 4> ResultElements;
+ ResultElements.reserve(SourceLen);
+
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ APValue CurrentEle = Source.getVectorElt(EltNum);
+ APValue Val = DestEltTy->isFloatingType()
+ ? APValue(llvm::abs(CurrentEle.getFloat()))
+ : APValue(APSInt(
+ CurrentEle.getInt().abs(),
+ DestEltTy->isUnsignedIntegerOrEnumerationType()));
+ ResultElements.push_back(Val);
+ }
+
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ }
+
case Builtin::BI__builtin_elementwise_add_sat:
- case Builtin::BI__builtin_elementwise_sub_sat: {
+ case Builtin::BI__builtin_elementwise_sub_sat:
+ case clang::X86::BI__builtin_ia32_pmulhuw128:
+ case clang::X86::BI__builtin_ia32_pmulhuw256:
+ case clang::X86::BI__builtin_ia32_pmulhuw512:
+ case clang::X86::BI__builtin_ia32_pmulhw128:
+ case clang::X86::BI__builtin_ia32_pmulhw256:
+ case clang::X86::BI__builtin_ia32_pmulhw512:
+ 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:
+ case clang::X86::BI__builtin_ia32_psrav4si:
+ case clang::X86::BI__builtin_ia32_psrav8si:
+ 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:
+
+ 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:
+
+ 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:
+
+ 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: {
+
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();
+
+ if (SourceRHS.isInt()) {
+ const unsigned LaneBitWidth = LHS.getBitWidth();
+ const unsigned ShiftAmount = SourceRHS.getInt().getZExtValue();
+
+ switch (E->getBuiltinCallee()) {
+ 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:
+ if (ShiftAmount >= LaneBitWidth) {
+ ResultElements.push_back(
+ APValue(APSInt(APInt::getZero(LaneBitWidth), DestUnsigned)));
+ } else {
+ ResultElements.push_back(
+ APValue(APSInt(LHS.shl(ShiftAmount), DestUnsigned)));
+ }
+ break;
+ 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:
+ if (ShiftAmount >= LaneBitWidth) {
+ ResultElements.push_back(
+ APValue(APSInt(APInt::getZero(LaneBitWidth), DestUnsigned)));
+ } else {
+ ResultElements.push_back(
+ APValue(APSInt(LHS.lshr(ShiftAmount), DestUnsigned)));
+ }
+ break;
+ 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:
+ ResultElements.push_back(
+ APValue(APSInt(LHS.ashr(std::min(ShiftAmount, LaneBitWidth - 1)),
+ DestUnsigned)));
+ break;
+ default:
+ llvm_unreachable("Unexpected builtin callee");
+ }
+ continue;
+ }
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),
- DestEltTy->isUnsignedIntegerOrEnumerationType())));
+ 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;
+ }
+ }
+
+ 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:
+ case clang::X86::BI__builtin_ia32_pmuludq128:
+ case clang::X86::BI__builtin_ia32_pmuludq256:
+ case clang::X86::BI__builtin_ia32_pmuludq512: {
+ APValue SourceLHS, SourceRHS;
+ if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS) ||
+ !EvaluateAsRValue(Info, E->getArg(1), SourceRHS))
+ return false;
+
+ unsigned SourceLen = SourceLHS.getVectorLength();
+ SmallVector<APValue, 4> ResultElements;
+ ResultElements.reserve(SourceLen / 2);
+
+ for (unsigned EltNum = 0; EltNum < SourceLen; EltNum += 2) {
+ APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt();
+ APSInt RHS = SourceRHS.getVectorElt(EltNum).getInt();
+
+ switch (E->getBuiltinCallee()) {
+ case clang::X86::BI__builtin_ia32_pmuludq128:
+ case clang::X86::BI__builtin_ia32_pmuludq256:
+ case clang::X86::BI__builtin_ia32_pmuludq512:
+ ResultElements.push_back(
+ APValue(APSInt(llvm::APIntOps::muluExtended(LHS, RHS), true)));
+ break;
+ case clang::X86::BI__builtin_ia32_pmuldq128:
+ case clang::X86::BI__builtin_ia32_pmuldq256:
+ case clang::X86::BI__builtin_ia32_pmuldq512:
+ ResultElements.push_back(
+ APValue(APSInt(llvm::APIntOps::mulsExtended(LHS, RHS), false)));
+ break;
+ }
+ }
+
+ 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: {
+ 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);
+
+ APSInt RHS = SourceRHS.getInt();
+
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt();
+ ResultElements.push_back(APValue(APSInt(LHS.rotl(RHS), DestUnsigned)));
+ }
+
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ }
+ 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: {
+ 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);
+
+ APSInt RHS = SourceRHS.getInt();
+
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ const APSInt &LHS = SourceLHS.getVectorElt(EltNum).getInt();
+ ResultElements.push_back(APValue(APSInt(LHS.rotr(RHS), DestUnsigned)));
+ }
+
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ }
+ case Builtin::BI__builtin_elementwise_max:
+ case Builtin::BI__builtin_elementwise_min: {
+ 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();
+
+ if (!DestEltTy->isIntegerType())
+ return false;
+
+ 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_max:
+ ResultElements.push_back(
+ APValue(APSInt(std::max(LHS, RHS),
+ DestEltTy->isUnsignedIntegerOrEnumerationType())));
+ break;
+ case Builtin::BI__builtin_elementwise_min:
+ ResultElements.push_back(
+ APValue(APSInt(std::min(LHS, RHS),
+ DestEltTy->isUnsignedIntegerOrEnumerationType())));
+ break;
+ }
+ }
+
+ 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:
+ case X86::BI__builtin_ia32_selectw_128:
+ case X86::BI__builtin_ia32_selectw_256:
+ case X86::BI__builtin_ia32_selectw_512:
+ case X86::BI__builtin_ia32_selectd_128:
+ case X86::BI__builtin_ia32_selectd_256:
+ case X86::BI__builtin_ia32_selectd_512:
+ case X86::BI__builtin_ia32_selectq_128:
+ case X86::BI__builtin_ia32_selectq_256:
+ case X86::BI__builtin_ia32_selectq_512:
+ case X86::BI__builtin_ia32_selectph_128:
+ case X86::BI__builtin_ia32_selectph_256:
+ case X86::BI__builtin_ia32_selectph_512:
+ case X86::BI__builtin_ia32_selectpbf_128:
+ case X86::BI__builtin_ia32_selectpbf_256:
+ case X86::BI__builtin_ia32_selectpbf_512:
+ case X86::BI__builtin_ia32_selectps_128:
+ case X86::BI__builtin_ia32_selectps_256:
+ case X86::BI__builtin_ia32_selectps_512:
+ case X86::BI__builtin_ia32_selectpd_128:
+ case X86::BI__builtin_ia32_selectpd_256:
+ case X86::BI__builtin_ia32_selectpd_512: {
+ // AVX512 predicated move: "Result = Mask[] ? LHS[] : RHS[]".
+ APValue SourceMask, SourceLHS, SourceRHS;
+ if (!EvaluateAsRValue(Info, E->getArg(0), SourceMask) ||
+ !EvaluateAsRValue(Info, E->getArg(1), SourceLHS) ||
+ !EvaluateAsRValue(Info, E->getArg(2), SourceRHS))
+ return false;
+
+ APSInt Mask = SourceMask.getInt();
+ unsigned SourceLen = SourceLHS.getVectorLength();
+ SmallVector<APValue, 4> ResultElements;
+ ResultElements.reserve(SourceLen);
+
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ const APValue &LHS = SourceLHS.getVectorElt(EltNum);
+ const APValue &RHS = SourceRHS.getVectorElt(EltNum);
+ ResultElements.push_back(Mask[EltNum] ? LHS : RHS);
+ }
+
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ }
+ case Builtin::BI__builtin_elementwise_ctlz:
+ case Builtin::BI__builtin_elementwise_cttz: {
+ APValue SourceLHS;
+ std::optional<APValue> Fallback;
+ if (!EvaluateAsRValue(Info, E->getArg(0), SourceLHS))
+ return false;
+ if (E->getNumArgs() > 1) {
+ APValue FallbackTmp;
+ if (!EvaluateAsRValue(Info, E->getArg(1), FallbackTmp))
+ return false;
+ Fallback = FallbackTmp;
+ }
+
+ QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
+ unsigned SourceLen = SourceLHS.getVectorLength();
+ SmallVector<APValue, 4> ResultElements;
+ ResultElements.reserve(SourceLen);
+
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ APSInt LHS = SourceLHS.getVectorElt(EltNum).getInt();
+ if (!LHS) {
+ // Without a fallback, a zero element is undefined
+ if (!Fallback) {
+ Info.FFDiag(E, diag::note_constexpr_countzeroes_zero)
+ << /*IsTrailing=*/(E->getBuiltinCallee() ==
+ Builtin::BI__builtin_elementwise_cttz);
+ return false;
+ }
+ ResultElements.push_back(Fallback->getVectorElt(EltNum));
+ continue;
+ }
+ switch (E->getBuiltinCallee()) {
+ case Builtin::BI__builtin_elementwise_ctlz:
+ ResultElements.push_back(APValue(
+ APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), LHS.countl_zero()),
+ DestEltTy->isUnsignedIntegerOrEnumerationType())));
+ break;
+ case Builtin::BI__builtin_elementwise_cttz:
+ ResultElements.push_back(APValue(
+ APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), LHS.countr_zero()),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
break;
}
@@ -11658,6 +12017,28 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
+
+ case Builtin::BI__builtin_elementwise_fma: {
+ APValue SourceX, SourceY, SourceZ;
+ if (!EvaluateAsRValue(Info, E->getArg(0), SourceX) ||
+ !EvaluateAsRValue(Info, E->getArg(1), SourceY) ||
+ !EvaluateAsRValue(Info, E->getArg(2), SourceZ))
+ return false;
+
+ unsigned SourceLen = SourceX.getVectorLength();
+ SmallVector<APValue> ResultElements;
+ ResultElements.reserve(SourceLen);
+ llvm::RoundingMode RM = getActiveRoundingMode(getEvalInfo(), E);
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
+ const APFloat &X = SourceX.getVectorElt(EltNum).getFloat();
+ const APFloat &Y = SourceY.getVectorElt(EltNum).getFloat();
+ const APFloat &Z = SourceZ.getVectorElt(EltNum).getFloat();
+ APFloat Result(X);
+ (void)Result.fusedMultiplyAdd(Y, Z, RM);
+ ResultElements.push_back(APValue(Result));
+ }
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E);
+ }
}
}
@@ -12889,7 +13270,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()->getDecl()->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())
@@ -13210,15 +13591,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_clzll:
case Builtin::BI__builtin_clzs:
case Builtin::BI__builtin_clzg:
+ case Builtin::BI__builtin_elementwise_ctlz:
case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes
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 && E->getNumArgs() > 1) {
+ if ((BuiltinOp == Builtin::BI__builtin_clzg ||
+ BuiltinOp == Builtin::BI__builtin_elementwise_ctlz) &&
+ E->getNumArgs() > 1) {
APSInt FallbackTemp;
if (!EvaluateInteger(E->getArg(1), FallbackTemp, Info))
return false;
@@ -13236,6 +13626,11 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
BuiltinOp != Builtin::BI__lzcnt &&
BuiltinOp != Builtin::BI__lzcnt64;
+ if (BuiltinOp == Builtin::BI__builtin_elementwise_ctlz) {
+ Info.FFDiag(E, diag::note_constexpr_countzeroes_zero)
+ << /*IsTrailing=*/false;
+ }
+
if (ZeroIsUndefined)
return Error(E);
}
@@ -13290,13 +13685,22 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_ctzl:
case Builtin::BI__builtin_ctzll:
case Builtin::BI__builtin_ctzs:
- case Builtin::BI__builtin_ctzg: {
+ 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 && E->getNumArgs() > 1) {
+ if ((BuiltinOp == Builtin::BI__builtin_ctzg ||
+ BuiltinOp == Builtin::BI__builtin_elementwise_cttz) &&
+ E->getNumArgs() > 1) {
APSInt FallbackTemp;
if (!EvaluateInteger(E->getArg(1), FallbackTemp, Info))
return false;
@@ -13307,6 +13711,10 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
if (Fallback)
return Success(*Fallback, E);
+ if (BuiltinOp == Builtin::BI__builtin_elementwise_cttz) {
+ Info.FFDiag(E, diag::note_constexpr_countzeroes_zero)
+ << /*IsTrailing=*/true;
+ }
return Error(E);
}
@@ -13319,6 +13727,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
return Success(Operand, E);
}
+ case Builtin::BI__builtin_elementwise_abs: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+
+ return Success(Val.abs(), E);
+ }
+
case Builtin::BI__builtin_expect:
case Builtin::BI__builtin_expect_with_probability:
return Visit(E->getArg(0));
@@ -13494,8 +13910,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);
}
@@ -13552,7 +13974,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
APInt Result = LHS.isSigned() ? LHS.ssub_sat(RHS) : LHS.usub_sat(RHS);
return Success(APSInt(Result, !LHS.isSigned()), E);
}
+ case Builtin::BI__builtin_elementwise_max: {
+ APSInt LHS, RHS;
+ if (!EvaluateInteger(E->getArg(0), LHS, Info) ||
+ !EvaluateInteger(E->getArg(1), RHS, Info))
+ return false;
+
+ APInt Result = std::max(LHS, RHS);
+ return Success(APSInt(Result, !LHS.isSigned()), E);
+ }
+ case Builtin::BI__builtin_elementwise_min: {
+ APSInt LHS, RHS;
+ if (!EvaluateInteger(E->getArg(0), LHS, Info) ||
+ !EvaluateInteger(E->getArg(1), RHS, Info))
+ return false;
+ APInt Result = std::min(LHS, RHS);
+ return Success(APSInt(Result, !LHS.isSigned()), E);
+ }
case Builtin::BIstrlen:
case Builtin::BIwcslen:
// A call to strlen is not a constant expression.
@@ -15086,6 +15525,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) {
@@ -15133,10 +15579,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->getDecl();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
unsigned i = MemberDecl->getFieldIndex();
@@ -15155,21 +15600,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->getDecl();
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->getDecl()));
+ Result += RL.getBaseClassOffset(BaseRD);
break;
}
}
@@ -15347,8 +15791,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->getDecl();
+ 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:
@@ -15792,6 +16235,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
return Error(E);
return true;
+ case Builtin::BI__builtin_elementwise_abs:
case Builtin::BI__builtin_fabs:
case Builtin::BI__builtin_fabsf:
case Builtin::BI__builtin_fabsl:
@@ -15878,6 +16322,21 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
Result = minimumnum(Result, RHS);
return true;
}
+
+ case Builtin::BI__builtin_elementwise_fma: {
+ if (!E->getArg(0)->isPRValue() || !E->getArg(1)->isPRValue() ||
+ !E->getArg(2)->isPRValue()) {
+ return false;
+ }
+ APFloat SourceY(0.), SourceZ(0.);
+ if (!EvaluateFloat(E->getArg(0), Result, Info) ||
+ !EvaluateFloat(E->getArg(1), SourceY, Info) ||
+ !EvaluateFloat(E->getArg(2), SourceZ, Info))
+ return false;
+ llvm::RoundingMode RM = getActiveRoundingMode(getEvalInfo(), E);
+ (void)Result.fusedMultiplyAdd(SourceY, SourceZ, RM);
+ return true;
+ }
}
}
@@ -17606,7 +18065,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());
@@ -18010,7 +18472,8 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
// Fabricate an arbitrary expression on the stack and pretend that it
// is a temporary being used as the 'this' pointer.
LValue This;
- ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy);
+ ImplicitValueInitExpr VIE(RD ? Info.Ctx.getCanonicalTagType(RD)
+ : Info.Ctx.IntTy);
This.set({&VIE, Info.CurrentCall->Index});
ArrayRef<const Expr*> Args;
diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp
index 112b756d..d4cb89b 100644
--- a/clang/lib/AST/FormatString.cpp
+++ b/clang/lib/AST/FormatString.cpp
@@ -413,14 +413,14 @@ 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.
- if (!ETy->getDecl()->isComplete())
+ if (!ED->isComplete())
return NoMatch;
- if (ETy->isUnscopedEnumerationType())
- argTy = ETy->getDecl()->getIntegerType();
+ if (!ED->isScoped())
+ argTy = ED->getIntegerType();
}
if (const auto *BT = argTy->getAs<BuiltinType>()) {
@@ -462,14 +462,14 @@ 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.
- if (!ETy->getDecl()->isComplete())
+ if (!ED->isComplete())
argTy = C.IntTy;
- else if (ETy->isUnscopedEnumerationType())
- argTy = ETy->getDecl()->getIntegerType();
+ else if (!ED->isScoped())
+ argTy = ED->getIntegerType();
}
if (argTy->isSaturatedFixedPointType())
@@ -653,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 1dafed8..3c4a5a8 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>()->getDecl());
+ const auto *Decl = cast<CXXRecordDecl>(
+ Type->castAsCanonical<RecordType>()->getOriginalDecl());
for (const auto &Base : Decl->bases()) {
QualType CanonBaseType = Context.getCanonicalType(Base.getType());
@@ -133,7 +133,7 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
/// viewInheritance - Display the inheritance hierarchy of this C++
/// class using GraphViz.
void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
- QualType Self = Context.getTypeDeclType(this);
+ QualType Self = Context.getCanonicalTagType(this);
int FD;
SmallString<128> Filename;
diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp
index 6ceedd6..adef158 100644
--- a/clang/lib/AST/ItaniumCXXABI.cpp
+++ b/clang/lib/AST/ItaniumCXXABI.cpp
@@ -42,10 +42,9 @@ namespace {
///
/// Returns the name of anonymous union VarDecl or nullptr if it is not found.
static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) {
- const RecordType *RT = VD.getType()->getAs<RecordType>();
- assert(RT && "type of VarDecl is expected to be RecordType.");
- assert(RT->getDecl()->isUnion() && "RecordType is expected to be a union.");
- if (const FieldDecl *FD = RT->getDecl()->findFirstNamedDataMember()) {
+ 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 5233648..ffadfce 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -463,9 +463,7 @@ public:
void mangleVendorType(StringRef Name);
private:
-
bool mangleSubstitution(const NamedDecl *ND);
- bool mangleSubstitution(NestedNameSpecifier *NNS);
bool mangleSubstitution(QualType T);
bool mangleSubstitution(TemplateName Template);
bool mangleSubstitution(uintptr_t Ptr);
@@ -479,21 +477,15 @@ private:
addSubstitution(reinterpret_cast<uintptr_t>(ND));
}
- void addSubstitution(NestedNameSpecifier *NNS) {
- NNS = Context.getASTContext().getCanonicalNestedNameSpecifier(NNS);
-
- addSubstitution(reinterpret_cast<uintptr_t>(NNS));
- }
void addSubstitution(QualType T);
void addSubstitution(TemplateName Template);
void addSubstitution(uintptr_t Ptr);
// Destructive copy substitutions from other mangler.
void extendSubstitutions(CXXNameMangler* Other);
- void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
+ void mangleUnresolvedPrefix(NestedNameSpecifier Qualifier,
bool recursive = false);
- void mangleUnresolvedName(NestedNameSpecifier *qualifier,
- DeclarationName name,
+ void mangleUnresolvedName(NestedNameSpecifier Qualifier, DeclarationName name,
const TemplateArgumentLoc *TemplateArgs,
unsigned NumTemplateArgs,
unsigned KnownArity = UnknownArity);
@@ -542,7 +534,7 @@ private:
void mangleNestedNameWithClosurePrefix(GlobalDecl GD,
const NamedDecl *PrefixND,
const AbiTagList *AdditionalAbiTags);
- void manglePrefix(NestedNameSpecifier *qualifier);
+ void manglePrefix(NestedNameSpecifier Qualifier);
void manglePrefix(const DeclContext *DC, bool NoFunction=false);
void manglePrefix(QualType type);
void mangleTemplatePrefix(GlobalDecl GD, bool NoFunction=false);
@@ -588,12 +580,10 @@ private:
void mangleMemberExprBase(const Expr *base, bool isArrow);
void mangleMemberExpr(const Expr *base, bool isArrow,
- NestedNameSpecifier *qualifier,
- NamedDecl *firstQualifierLookup,
- DeclarationName name,
+ NestedNameSpecifier Qualifier,
+ NamedDecl *firstQualifierLookup, DeclarationName name,
const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- unsigned knownArity);
+ unsigned NumTemplateArgs, unsigned knownArity);
void mangleCastExpression(const Expr *E, StringRef CastEncoding);
void mangleInitListElements(const InitListExpr *InitList);
void mangleRequirement(SourceLocation RequiresExprLoc,
@@ -1334,6 +1324,21 @@ void CXXNameMangler::manglePrefix(QualType type) {
mangleTemplateArgs(Template, DTST->template_arguments());
addSubstitution(QualType(DTST, 0));
}
+ } else if (const auto *DNT = type->getAs<DependentNameType>()) {
+ // Clang 14 and before did not consider this substitutable.
+ bool Clang14Compat = isCompatibleWith(LangOptions::ClangABI::Ver14);
+ if (!Clang14Compat && mangleSubstitution(QualType(DNT, 0)))
+ return;
+
+ // Member expressions can have these without prefixes, but that
+ // should end up in mangleUnresolvedPrefix instead.
+ assert(DNT->getQualifier());
+ manglePrefix(DNT->getQualifier());
+
+ mangleSourceName(DNT->getIdentifier());
+
+ if (!Clang14Compat)
+ addSubstitution(QualType(DNT, 0));
} else {
// We use the QualType mangle type variant here because it handles
// substitutions.
@@ -1345,7 +1350,7 @@ void CXXNameMangler::manglePrefix(QualType type) {
///
/// \param recursive - true if this is being called recursively,
/// i.e. if there is more prefix "to the right".
-void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
+void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier Qualifier,
bool recursive) {
// x, ::x
@@ -1362,8 +1367,11 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
// <unresolved-name> ::= [gs] sr <unresolved-qualifier-level>+ E
// <base-unresolved-name>
- switch (qualifier->getKind()) {
- case NestedNameSpecifier::Global:
+ switch (Qualifier.getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ llvm_unreachable("unexpected null nested name specifier");
+
+ case NestedNameSpecifier::Kind::Global:
Out << "gs";
// We want an 'sr' unless this is the entire NNS.
@@ -1373,27 +1381,29 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
// We never want an 'E' here.
return;
- case NestedNameSpecifier::Super:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
llvm_unreachable("Can't mangle __super specifier");
- case NestedNameSpecifier::Namespace:
- if (qualifier->getPrefix())
- mangleUnresolvedPrefix(qualifier->getPrefix(),
+ case NestedNameSpecifier::Kind::Namespace: {
+ auto [Namespace, Prefix] = Qualifier.getAsNamespaceAndPrefix();
+ if (Prefix)
+ mangleUnresolvedPrefix(Prefix,
/*recursive*/ true);
else
Out << "sr";
- mangleSourceNameWithAbiTags(qualifier->getAsNamespace());
+ mangleSourceNameWithAbiTags(Namespace);
break;
+ }
- case NestedNameSpecifier::TypeSpec: {
- const Type *type = qualifier->getAsType();
+ case NestedNameSpecifier::Kind::Type: {
+ const Type *type = Qualifier.getAsType();
// We only want to use an unresolved-type encoding if this is one of:
// - a decltype
// - a template type parameter
// - a template template parameter with arguments
// In all of these cases, we should have no prefix.
- if (NestedNameSpecifier *Prefix = qualifier->getPrefix()) {
+ if (NestedNameSpecifier Prefix = type->getPrefix()) {
mangleUnresolvedPrefix(Prefix,
/*recursive=*/true);
} else {
@@ -1406,18 +1416,6 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
break;
}
-
- case NestedNameSpecifier::Identifier:
- // Member expressions can have these without prefixes.
- if (qualifier->getPrefix())
- mangleUnresolvedPrefix(qualifier->getPrefix(),
- /*recursive*/ true);
- else
- Out << "sr";
-
- mangleSourceName(qualifier->getAsIdentifier());
- // An Identifier has no type information, so we can't emit abi tags for it.
- break;
}
// If this was the innermost part of the NNS, and we fell out to
@@ -1429,10 +1427,11 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
/// Mangle an unresolved-name, which is generally used for names which
/// weren't resolved to specific entities.
void CXXNameMangler::mangleUnresolvedName(
- NestedNameSpecifier *qualifier, DeclarationName name,
+ NestedNameSpecifier Qualifier, DeclarationName name,
const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs,
unsigned knownArity) {
- if (qualifier) mangleUnresolvedPrefix(qualifier);
+ if (Qualifier)
+ mangleUnresolvedPrefix(Qualifier);
switch (name.getNameKind()) {
// <base-unresolved-name> ::= <simple-id>
case DeclarationName::Identifier:
@@ -1581,7 +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>()->getDecl();
+ const auto *RD = VD->getType()->castAsRecordDecl();
// Itanium C++ ABI 5.1.2:
//
@@ -2167,49 +2166,22 @@ void CXXNameMangler::mangleLambdaSig(const CXXRecordDecl *Lambda) {
Lambda->getLambdaStaticInvoker());
}
-void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
- switch (qualifier->getKind()) {
- case NestedNameSpecifier::Global:
+void CXXNameMangler::manglePrefix(NestedNameSpecifier Qualifier) {
+ switch (Qualifier.getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::Global:
// nothing
return;
- case NestedNameSpecifier::Super:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
llvm_unreachable("Can't mangle __super specifier");
- case NestedNameSpecifier::Namespace:
- mangleName(qualifier->getAsNamespace()->getNamespace());
- return;
-
- case NestedNameSpecifier::TypeSpec:
- if (NestedNameSpecifier *Prefix = qualifier->getPrefix()) {
- const auto *DTST =
- cast<DependentTemplateSpecializationType>(qualifier->getAsType());
- QualType NewT = getASTContext().getDependentTemplateSpecializationType(
- DTST->getKeyword(),
- {Prefix, DTST->getDependentTemplateName().getName(),
- /*HasTemplateKeyword=*/true},
- DTST->template_arguments(), /*IsCanonical=*/true);
- manglePrefix(NewT);
- return;
- }
- manglePrefix(QualType(qualifier->getAsType(), 0));
+ case NestedNameSpecifier::Kind::Namespace:
+ mangleName(Qualifier.getAsNamespaceAndPrefix().Namespace->getNamespace());
return;
- case NestedNameSpecifier::Identifier:
- // Clang 14 and before did not consider this substitutable.
- bool Clang14Compat = isCompatibleWith(LangOptions::ClangABI::Ver14);
- if (!Clang14Compat && mangleSubstitution(qualifier))
- return;
-
- // Member expressions can have these without prefixes, but that
- // should end up in mangleUnresolvedPrefix instead.
- assert(qualifier->getPrefix());
- manglePrefix(qualifier->getPrefix());
-
- mangleSourceName(qualifier->getAsIdentifier());
-
- if (!Clang14Compat)
- addSubstitution(qualifier);
+ case NestedNameSpecifier::Kind::Type:
+ manglePrefix(QualType(Qualifier.getAsType(), 0));
return;
}
@@ -2269,8 +2241,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
if (!Clang11Compat && mangleSubstitution(Template))
return;
- if (NestedNameSpecifier *Qualifier = Dependent->getQualifier())
- manglePrefix(Qualifier);
+ manglePrefix(Dependent->getQualifier());
if (Clang11Compat && mangleSubstitution(Template))
return;
@@ -2470,6 +2441,13 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::CountAttributed:
llvm_unreachable("type is illegal as a nested name specifier");
+ case Type::SubstBuiltinTemplatePack:
+ // FIXME: not clear how to mangle this!
+ // template <class T...> class A {
+ // template <class U...> void foo(__builtin_dedup_pack<T...>(*)(U) x...);
+ // };
+ Out << "_SUBSTBUILTINPACK_";
+ break;
case Type::SubstTemplateTypeParmPack:
// FIXME: not clear how to mangle this!
// template <class T...> class A {
@@ -2525,7 +2503,8 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::Enum:
case Type::Record:
- mangleSourceNameWithAbiTags(cast<TagType>(Ty)->getDecl());
+ mangleSourceNameWithAbiTags(
+ cast<TagType>(Ty)->getOriginalDecl()->getDefinitionOrSelf());
break;
case Type::TemplateSpecialization: {
@@ -2586,8 +2565,9 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
}
case Type::InjectedClassName:
- mangleSourceNameWithAbiTags(
- cast<InjectedClassNameType>(Ty)->getDecl());
+ mangleSourceNameWithAbiTags(cast<InjectedClassNameType>(Ty)
+ ->getOriginalDecl()
+ ->getDefinitionOrSelf());
break;
case Type::DependentName:
@@ -2608,9 +2588,6 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
case Type::Using:
return mangleUnresolvedTypeOrSimpleId(cast<UsingType>(Ty)->desugar(),
Prefix);
- case Type::Elaborated:
- return mangleUnresolvedTypeOrSimpleId(
- cast<ElaboratedType>(Ty)->getNamedType(), Prefix);
}
return false;
@@ -3838,7 +3815,7 @@ void CXXNameMangler::mangleType(const RecordType *T) {
mangleType(static_cast<const TagType*>(T));
}
void CXXNameMangler::mangleType(const TagType *T) {
- mangleName(T->getDecl());
+ mangleName(T->getOriginalDecl()->getDefinitionOrSelf());
}
// <type> ::= <array-type>
@@ -3875,16 +3852,10 @@ void CXXNameMangler::mangleType(const IncompleteArrayType *T) {
// <pointer-to-member-type> ::= M <class type> <member type>
void CXXNameMangler::mangleType(const MemberPointerType *T) {
Out << 'M';
- if (auto *RD = T->getMostRecentCXXRecordDecl()) {
+ if (auto *RD = T->getMostRecentCXXRecordDecl())
mangleCXXRecordDecl(RD);
- } else {
- NestedNameSpecifier *NNS = T->getQualifier();
- if (auto *II = NNS->getAsIdentifier())
- mangleType(getASTContext().getDependentNameType(
- ElaboratedTypeKeyword::None, NNS->getPrefix(), II));
- else
- manglePrefix(NNS);
- }
+ else
+ mangleType(QualType(T->getQualifier().getAsType(), 0));
QualType PointeeType = T->getPointeeType();
if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) {
mangleType(FPT);
@@ -3924,6 +3895,14 @@ void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) {
Out << "_SUBSTPACK_";
}
+void CXXNameMangler::mangleType(const SubstBuiltinTemplatePackType *T) {
+ // FIXME: not clear how to mangle this!
+ // template <class T...> class A {
+ // template <class U...> void foo(__builtin_dedup_pack<T...>(*)(U) x...);
+ // };
+ Out << "_SUBSTBUILTINPACK_";
+}
+
// <type> ::= P <type> # pointer-to
void CXXNameMangler::mangleType(const PointerType *T) {
Out << 'P';
@@ -4471,7 +4450,8 @@ void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
// Mangle injected class name types as if the user had written the
// specialization out fully. It may not actually be possible to see
// this mangling, though.
- mangleType(T->getInjectedSpecializationType());
+ mangleType(T->getOriginalDecl()->getCanonicalTemplateSpecializationType(
+ getASTContext()));
}
void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
@@ -4746,8 +4726,8 @@ 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>()) {
- if (!RT->getDecl()->isAnonymousStructOrUnion())
+ while (const auto *RT = Base->getType()->getAsCanonical<RecordType>()) {
+ if (!RT->getOriginalDecl()->isAnonymousStructOrUnion())
break;
const auto *ME = dyn_cast<MemberExpr>(Base);
if (!ME)
@@ -4768,9 +4748,8 @@ void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) {
}
/// Mangles a member expression.
-void CXXNameMangler::mangleMemberExpr(const Expr *base,
- bool isArrow,
- NestedNameSpecifier *qualifier,
+void CXXNameMangler::mangleMemberExpr(const Expr *base, bool isArrow,
+ NestedNameSpecifier Qualifier,
NamedDecl *firstQualifierLookup,
DeclarationName member,
const TemplateArgumentLoc *TemplateArgs,
@@ -4780,7 +4759,7 @@ void CXXNameMangler::mangleMemberExpr(const Expr *base,
// ::= pt <expression> <unresolved-name>
if (base)
mangleMemberExprBase(base, isArrow);
- mangleUnresolvedName(qualifier, member, TemplateArgs, NumTemplateArgs, arity);
+ mangleUnresolvedName(Qualifier, member, TemplateArgs, NumTemplateArgs, arity);
}
/// Look at the callee of the given call expression and determine if
@@ -5230,7 +5209,7 @@ recurse:
const auto *PDE = cast<CXXPseudoDestructorExpr>(E);
if (const Expr *Base = PDE->getBase())
mangleMemberExprBase(Base, PDE->isArrow());
- NestedNameSpecifier *Qualifier = PDE->getQualifier();
+ NestedNameSpecifier Qualifier = PDE->getQualifier();
if (TypeSourceInfo *ScopeInfo = PDE->getScopeTypeInfo()) {
if (Qualifier) {
mangleUnresolvedPrefix(Qualifier,
@@ -5855,7 +5834,8 @@ recurse:
// externally-visible declaration, so there's no standard mangling for
// this, but mangling as a literal of the closure type seems reasonable.
Out << "L";
- mangleType(Context.getASTContext().getRecordType(cast<LambdaExpr>(E)->getLambdaClass()));
+ mangleType(Context.getASTContext().getCanonicalTagType(
+ cast<LambdaExpr>(E)->getLambdaClass()));
Out << "E";
break;
}
@@ -6528,7 +6508,7 @@ static QualType getLValueType(ASTContext &Ctx, const APValue &LV) {
dyn_cast<FieldDecl>(E.getAsBaseOrMember().getPointer()))
T = FD->getType();
else
- T = Ctx.getRecordType(
+ T = Ctx.getCanonicalTagType(
cast<CXXRecordDecl>(E.getAsBaseOrMember().getPointer()));
}
return T;
@@ -6895,7 +6875,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V,
}
TypeSoFar = FD->getType();
} else {
- TypeSoFar = Ctx.getRecordType(cast<CXXRecordDecl>(D));
+ TypeSoFar = Ctx.getCanonicalTagType(cast<CXXRecordDecl>(D));
}
}
}
@@ -7005,14 +6985,6 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
}
-bool CXXNameMangler::mangleSubstitution(NestedNameSpecifier *NNS) {
- assert(NNS->getKind() == NestedNameSpecifier::Identifier &&
- "mangleSubstitution(NestedNameSpecifier *) is only used for "
- "identifier nested name specifiers.");
- NNS = Context.getASTContext().getCanonicalNestedNameSpecifier(NNS);
- return mangleSubstitution(reinterpret_cast<uintptr_t>(NNS));
-}
-
/// Determine whether the given type has any qualifiers that are relevant for
/// substitutions.
static bool hasMangledSubstitutionQualifiers(QualType T) {
@@ -7022,8 +6994,8 @@ static bool hasMangledSubstitutionQualifiers(QualType T) {
bool CXXNameMangler::mangleSubstitution(QualType T) {
if (!hasMangledSubstitutionQualifiers(T)) {
- if (const RecordType *RT = T->getAs<RecordType>())
- return mangleSubstitution(RT->getDecl());
+ if (const auto *RD = T->getAsCXXRecordDecl())
+ return mangleSubstitution(RD);
}
uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
@@ -7059,12 +7031,12 @@ 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;
const ClassTemplateSpecializationDecl *SD =
- dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getOriginalDecl());
if (!SD || !SD->getIdentifier()->isStr(Name))
return false;
@@ -7193,8 +7165,8 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
void CXXNameMangler::addSubstitution(QualType T) {
if (!hasMangledSubstitutionQualifiers(T)) {
- if (const RecordType *RT = T->getAs<RecordType>()) {
- addSubstitution(RT->getDecl());
+ if (const auto *RD = T->getAsCXXRecordDecl()) {
+ addSubstitution(RD);
return;
}
}
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 64ddb1e..ca8e2af 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -395,8 +395,8 @@ 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>()->getDecl());
+ const auto *RD = cast<CXXRecordDecl>(
+ Base->getType()->castAsCanonical<RecordType>()->getOriginalDecl());
llvm::json::Object Val{{"name", RD->getName()}};
if (Base->isVirtual())
@@ -606,9 +606,8 @@ void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) {
}
void JSONNodeDumper::VisitUsingType(const UsingType *TT) {
- JOS.attribute("decl", createBareDeclRef(TT->getFoundDecl()));
- if (!TT->typeMatchesDecl())
- JOS.attribute("type", createQualType(TT->desugar()));
+ JOS.attribute("decl", createBareDeclRef(TT->getDecl()));
+ JOS.attribute("type", createQualType(TT->desugar()));
}
void JSONNodeDumper::VisitFunctionType(const FunctionType *T) {
@@ -759,7 +758,15 @@ void JSONNodeDumper::VisitUnaryTransformType(const UnaryTransformType *UTT) {
}
void JSONNodeDumper::VisitTagType(const TagType *TT) {
- JOS.attribute("decl", createBareDeclRef(TT->getDecl()));
+ if (NestedNameSpecifier Qualifier = TT->getQualifier()) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ Qualifier.print(OS, PrintPolicy, /*ResolveTemplateArguments=*/true);
+ JOS.attribute("qualifier", Str);
+ }
+ JOS.attribute("decl", createBareDeclRef(TT->getOriginalDecl()));
+ if (TT->isTagOwned())
+ JOS.attribute("isTagOwned", true);
}
void JSONNodeDumper::VisitTemplateTypeParmType(
@@ -809,7 +816,7 @@ void JSONNodeDumper::VisitTemplateSpecializationType(
void JSONNodeDumper::VisitInjectedClassNameType(
const InjectedClassNameType *ICNT) {
- JOS.attribute("decl", createBareDeclRef(ICNT->getDecl()));
+ JOS.attribute("decl", createBareDeclRef(ICNT->getOriginalDecl()));
}
void JSONNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *OIT) {
@@ -821,17 +828,6 @@ void JSONNodeDumper::VisitPackExpansionType(const PackExpansionType *PET) {
JOS.attribute("numExpansions", *N);
}
-void JSONNodeDumper::VisitElaboratedType(const ElaboratedType *ET) {
- if (const NestedNameSpecifier *NNS = ET->getQualifier()) {
- std::string Str;
- llvm::raw_string_ostream OS(Str);
- NNS->print(OS, PrintPolicy, /*ResolveTemplateArgs*/ true);
- JOS.attribute("qualifier", Str);
- }
- if (const TagDecl *TD = ET->getOwnedTagDecl())
- JOS.attribute("ownedTagDecl", createBareDeclRef(TD));
-}
-
void JSONNodeDumper::VisitMacroQualifiedType(const MacroQualifiedType *MQT) {
JOS.attribute("macroName", MQT->getMacroIdentifier()->getName());
}
@@ -902,9 +898,9 @@ void JSONNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD) {
void JSONNodeDumper::VisitUsingDecl(const UsingDecl *UD) {
std::string Name;
- if (const NestedNameSpecifier *NNS = UD->getQualifier()) {
+ if (NestedNameSpecifier Qualifier = UD->getQualifier()) {
llvm::raw_string_ostream SOS(Name);
- NNS->print(SOS, UD->getASTContext().getPrintingPolicy());
+ Qualifier.print(SOS, UD->getASTContext().getPrintingPolicy());
}
Name += UD->getNameAsString();
JOS.attribute("name", Name);
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index e6ea0ad..2ac38a2 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -1805,17 +1805,16 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
case TemplateArgument::Declaration: {
const NamedDecl *ND = TA.getAsDecl();
if (isa<FieldDecl>(ND) || isa<IndirectFieldDecl>(ND)) {
- mangleMemberDataPointer(cast<CXXRecordDecl>(ND->getDeclContext())
- ->getMostRecentNonInjectedDecl(),
- cast<ValueDecl>(ND),
- cast<NonTypeTemplateParmDecl>(Parm),
- TA.getParamTypeForDecl());
+ mangleMemberDataPointer(
+ cast<CXXRecordDecl>(ND->getDeclContext())->getMostRecentDecl(),
+ cast<ValueDecl>(ND), cast<NonTypeTemplateParmDecl>(Parm),
+ TA.getParamTypeForDecl());
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
if (MD && MD->isInstance()) {
- mangleMemberFunctionPointer(
- MD->getParent()->getMostRecentNonInjectedDecl(), MD,
- cast<NonTypeTemplateParmDecl>(Parm), TA.getParamTypeForDecl());
+ mangleMemberFunctionPointer(MD->getParent()->getMostRecentDecl(), MD,
+ cast<NonTypeTemplateParmDecl>(Parm),
+ TA.getParamTypeForDecl());
} else {
mangleFunctionPointer(FD, cast<NonTypeTemplateParmDecl>(Parm),
TA.getParamTypeForDecl());
@@ -2021,7 +2020,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArgValue(QualType T,
if (RD->isAnonymousStructOrUnion())
continue;
} else {
- ET = getASTContext().getRecordType(cast<CXXRecordDecl>(D));
+ ET = getASTContext().getCanonicalTagType(cast<CXXRecordDecl>(D));
// Bug in MSVC: fully qualified name of base class should be used for
// mangling to prevent collisions e.g. on base classes with same names
// in different namespaces.
@@ -3247,13 +3246,17 @@ void MicrosoftCXXNameMangler::mangleTagTypeKind(TagTypeKind TTK) {
}
void MicrosoftCXXNameMangler::mangleType(const EnumType *T, Qualifiers,
SourceRange) {
- mangleType(cast<TagType>(T)->getDecl());
+ mangleType(cast<TagType>(T)->getOriginalDecl());
}
void MicrosoftCXXNameMangler::mangleType(const RecordType *T, Qualifiers,
SourceRange) {
- mangleType(cast<TagType>(T)->getDecl());
+ 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);
}
@@ -3384,6 +3387,11 @@ void MicrosoftCXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T,
Error(Range.getBegin(), "substituted parameter pack") << Range;
}
+void MicrosoftCXXNameMangler::mangleType(const SubstBuiltinTemplatePackType *T,
+ Qualifiers, SourceRange Range) {
+ Error(Range.getBegin(), "substituted builtin template pack") << Range;
+}
+
// <type> ::= <pointer-type>
// <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
// # the E is required for 64-bit non-static pointers
diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp
index 56f74b9..c6af91f 100644
--- a/clang/lib/AST/NestedNameSpecifier.cpp
+++ b/clang/lib/AST/NestedNameSpecifier.cpp
@@ -15,7 +15,6 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DependenceFlags.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TemplateName.h"
@@ -35,250 +34,67 @@
using namespace clang;
-NestedNameSpecifier *
-NestedNameSpecifier::FindOrInsert(const ASTContext &Context,
- const NestedNameSpecifier &Mockup) {
+const NamespaceAndPrefixStorage *
+NestedNameSpecifier::MakeNamespaceAndPrefixStorage(
+ const ASTContext &Ctx, const NamespaceBaseDecl *Namespace,
+ NestedNameSpecifier Prefix) {
llvm::FoldingSetNodeID ID;
- Mockup.Profile(ID);
+ NamespaceAndPrefixStorage::Profile(ID, Namespace, Prefix);
void *InsertPos = nullptr;
- NestedNameSpecifier *NNS
- = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos);
- if (!NNS) {
- NNS =
- new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier(Mockup);
- Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos);
+ NamespaceAndPrefixStorage *S =
+ Ctx.NamespaceAndPrefixStorages.FindNodeOrInsertPos(ID, InsertPos);
+ if (!S) {
+ S = new (Ctx, alignof(NamespaceAndPrefixStorage))
+ NamespaceAndPrefixStorage(Namespace, Prefix);
+ Ctx.NamespaceAndPrefixStorages.InsertNode(S, InsertPos);
}
-
- return NNS;
-}
-
-NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context,
- NestedNameSpecifier *Prefix,
- const IdentifierInfo *II) {
- assert(II && "Identifier cannot be NULL");
- assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent");
-
- NestedNameSpecifier Mockup;
- Mockup.Prefix.setPointer(Prefix);
- Mockup.Prefix.setInt(StoredIdentifier);
- Mockup.Specifier = const_cast<IdentifierInfo *>(II);
- return FindOrInsert(Context, Mockup);
-}
-
-NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context,
- NestedNameSpecifier *Prefix,
- const NamespaceBaseDecl *NS) {
- assert(NS && "Namespace cannot be NULL");
- assert((!Prefix ||
- (Prefix->getAsType() == nullptr &&
- Prefix->getAsIdentifier() == nullptr)) &&
- "Broken nested name specifier");
- NestedNameSpecifier Mockup;
- Mockup.Prefix.setPointer(Prefix);
- Mockup.Prefix.setInt(StoredDecl);
- Mockup.Specifier = const_cast<NamespaceBaseDecl *>(NS);
- return FindOrInsert(Context, Mockup);
-}
-
-NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context,
- NestedNameSpecifier *Prefix,
- const Type *T) {
- assert(T && "Type cannot be NULL");
- NestedNameSpecifier Mockup;
- Mockup.Prefix.setPointer(Prefix);
- Mockup.Prefix.setInt(StoredTypeSpec);
- Mockup.Specifier = const_cast<Type*>(T);
- return FindOrInsert(Context, Mockup);
-}
-
-NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context,
- const IdentifierInfo *II) {
- assert(II && "Identifier cannot be NULL");
- NestedNameSpecifier Mockup;
- Mockup.Prefix.setPointer(nullptr);
- Mockup.Prefix.setInt(StoredIdentifier);
- Mockup.Specifier = const_cast<IdentifierInfo *>(II);
- return FindOrInsert(Context, Mockup);
-}
-
-NestedNameSpecifier *
-NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) {
- if (!Context.GlobalNestedNameSpecifier)
- Context.GlobalNestedNameSpecifier =
- new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier();
- return Context.GlobalNestedNameSpecifier;
-}
-
-NestedNameSpecifier *
-NestedNameSpecifier::SuperSpecifier(const ASTContext &Context,
- CXXRecordDecl *RD) {
- NestedNameSpecifier Mockup;
- Mockup.Prefix.setPointer(nullptr);
- Mockup.Prefix.setInt(StoredDecl);
- Mockup.Specifier = RD;
- return FindOrInsert(Context, Mockup);
+ return S;
}
-NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const {
- if (!Specifier)
- return Global;
-
- switch (Prefix.getInt()) {
- case StoredIdentifier:
- return Identifier;
-
- case StoredDecl: {
- NamedDecl *ND = static_cast<NamedDecl *>(Specifier);
- return isa<CXXRecordDecl>(ND) ? Super : Namespace;
- }
-
- case StoredTypeSpec:
- return TypeSpec;
- }
-
- llvm_unreachable("Invalid NNS Kind!");
-}
-
-/// Retrieve the namespace or namespace alias stored in this nested name
-/// specifier.
-NamespaceBaseDecl *NestedNameSpecifier::getAsNamespace() const {
- if (Prefix.getInt() == StoredDecl)
- return dyn_cast<NamespaceBaseDecl>(static_cast<NamedDecl *>(Specifier));
-
- return nullptr;
-}
-
-/// Retrieve the record declaration stored in this nested name specifier.
-CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const {
- switch (Prefix.getInt()) {
- case StoredIdentifier:
- return nullptr;
-
- case StoredDecl:
- return dyn_cast<CXXRecordDecl>(static_cast<NamedDecl *>(Specifier));
-
- case StoredTypeSpec:
- return getAsType()->getAsCXXRecordDecl();
+bool NestedNameSpecifier::isFullyQualified() const {
+ switch (getKind()) {
+ case NestedNameSpecifier::Kind::Global:
+ return true;
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ return false;
+ case NestedNameSpecifier::Kind::Namespace:
+ return getAsNamespaceAndPrefix().Prefix.isFullyQualified();
+ case NestedNameSpecifier::Kind::Type:
+ return getAsType()->getPrefix().isFullyQualified();
}
-
llvm_unreachable("Invalid NNS Kind!");
}
NestedNameSpecifierDependence NestedNameSpecifier::getDependence() const {
switch (getKind()) {
- case Identifier: {
- // Identifier specifiers always represent dependent types
- auto F = NestedNameSpecifierDependence::Dependent |
- NestedNameSpecifierDependence::Instantiation;
- // Prefix can contain unexpanded template parameters.
- if (getPrefix())
- return F | getPrefix()->getDependence();
- return F;
- }
-
- case Namespace:
- case Global:
- return NestedNameSpecifierDependence::None;
-
- case Super: {
- CXXRecordDecl *RD = static_cast<CXXRecordDecl *>(Specifier);
- for (const auto &Base : RD->bases())
- if (Base.getType()->isDependentType())
- // FIXME: must also be instantiation-dependent.
- return NestedNameSpecifierDependence::Dependent;
+ case Kind::Null:
+ case Kind::Global:
+ case Kind::Namespace:
return NestedNameSpecifierDependence::None;
+ case Kind::MicrosoftSuper: {
+ CXXRecordDecl *RD = getAsMicrosoftSuper();
+ return RD->isDependentContext()
+ ? NestedNameSpecifierDependence::DependentInstantiation |
+ NestedNameSpecifierDependence::Dependent
+ : NestedNameSpecifierDependence::None;
}
-
- case TypeSpec: {
- NestedNameSpecifierDependence Dep =
- toNestedNameSpecifierDependendence(getAsType()->getDependence());
- if (NestedNameSpecifier *Prefix = getPrefix())
- Dep |=
- Prefix->getDependence() & ~NestedNameSpecifierDependence::Dependent;
- return Dep;
- }
+ case Kind::Type:
+ return toNestedNameSpecifierDependence(getAsType()->getDependence());
}
llvm_unreachable("Invalid NNS Kind!");
}
-bool NestedNameSpecifier::isDependent() const {
- return getDependence() & NestedNameSpecifierDependence::Dependent;
-}
-
-bool NestedNameSpecifier::isInstantiationDependent() const {
- return getDependence() & NestedNameSpecifierDependence::Instantiation;
-}
-
-bool NestedNameSpecifier::containsUnexpandedParameterPack() const {
- return getDependence() & NestedNameSpecifierDependence::UnexpandedPack;
-}
-
-bool NestedNameSpecifier::containsErrors() const {
- return getDependence() & NestedNameSpecifierDependence::Error;
-}
-
-const Type *
-NestedNameSpecifier::translateToType(const ASTContext &Context) const {
- NestedNameSpecifier *Prefix = getPrefix();
- switch (getKind()) {
- case SpecifierKind::Identifier:
- return Context
- .getDependentNameType(ElaboratedTypeKeyword::None, Prefix,
- getAsIdentifier())
- .getTypePtr();
- case SpecifierKind::TypeSpec: {
- const Type *T = getAsType();
- switch (T->getTypeClass()) {
- case Type::DependentTemplateSpecialization: {
- const auto *DT = cast<DependentTemplateSpecializationType>(T);
- const DependentTemplateStorage &DTN = DT->getDependentTemplateName();
- return Context
- .getDependentTemplateSpecializationType(
- ElaboratedTypeKeyword::None,
- {Prefix, DTN.getName(), DTN.hasTemplateKeyword()},
- DT->template_arguments())
- .getTypePtr();
- }
- case Type::Record:
- case Type::TemplateSpecialization:
- case Type::Using:
- case Type::Enum:
- case Type::Typedef:
- case Type::UnresolvedUsing:
- return Context
- .getElaboratedType(ElaboratedTypeKeyword::None, Prefix,
- QualType(T, 0))
- .getTypePtr();
- default:
- assert(Prefix == nullptr && "unexpected type with elaboration");
- return T;
- }
- }
- case SpecifierKind::Global:
- case SpecifierKind::Namespace:
- case SpecifierKind::Super:
- // These are not representable as types.
- return nullptr;
- }
- llvm_unreachable("Unhandled SpecifierKind enum");
-}
-
/// Print this nested name specifier to the given output
/// stream.
void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
bool ResolveTemplateArguments,
bool PrintFinalScopeResOp) const {
- if (getPrefix())
- getPrefix()->print(OS, Policy);
-
switch (getKind()) {
- case Identifier:
- OS << getAsIdentifier()->getName();
- break;
-
- case Namespace: {
- NamespaceBaseDecl *Namespace = getAsNamespace();
+ case Kind::Namespace: {
+ auto [Namespace, Prefix] = getAsNamespaceAndPrefix();
+ Prefix.print(OS, Policy);
if (const auto *NS = dyn_cast<NamespaceDecl>(Namespace)) {
assert(!NS->isAnonymousNamespace());
OS << NS->getName();
@@ -287,134 +103,49 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
}
break;
}
-
- case Global:
+ case Kind::Global:
OS << "::";
return;
-
- case Super:
+ case Kind::MicrosoftSuper:
OS << "__super";
break;
-
- case TypeSpec: {
+ case Kind::Type: {
PrintingPolicy InnerPolicy(Policy);
- InnerPolicy.SuppressScope = true;
InnerPolicy.SuppressTagKeyword = true;
QualType(getAsType(), 0).print(OS, InnerPolicy);
break;
}
+ case Kind::Null:
+ return;
}
-
if (PrintFinalScopeResOp)
OS << "::";
}
-LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const {
- dump(llvm::errs(), LO);
+LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream *OS,
+ const LangOptions *LO) const {
+ print(OS ? *OS : llvm::errs(), LO ? *LO : LangOptions());
}
-LLVM_DUMP_METHOD void NestedNameSpecifier::dump() const { dump(llvm::errs()); }
-
+LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const {
+ dump(/*OS=*/nullptr, &LO);
+}
LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS) const {
- LangOptions LO;
- dump(OS, LO);
+ dump(&OS);
}
-
LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS,
const LangOptions &LO) const {
- print(OS, PrintingPolicy(LO));
-}
-
-unsigned
-NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) {
- assert(Qualifier && "Expected a non-NULL qualifier");
-
- // Location of the trailing '::'.
- unsigned Length = sizeof(SourceLocation::UIntTy);
-
- switch (Qualifier->getKind()) {
- case NestedNameSpecifier::Global:
- // Nothing more to add.
- break;
-
- case NestedNameSpecifier::Identifier:
- case NestedNameSpecifier::Namespace:
- case NestedNameSpecifier::Super:
- // The location of the identifier or namespace name.
- Length += sizeof(SourceLocation::UIntTy);
- break;
-
- case NestedNameSpecifier::TypeSpec:
- // The "void*" that points at the TypeLoc data.
- // Note: the 'template' keyword is part of the TypeLoc.
- Length += sizeof(void *);
- break;
- }
-
- return Length;
-}
-
-unsigned
-NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) {
- unsigned Length = 0;
- for (; Qualifier; Qualifier = Qualifier->getPrefix())
- Length += getLocalDataLength(Qualifier);
- return Length;
-}
-
-/// Load a (possibly unaligned) source location from a given address
-/// and offset.
-static SourceLocation LoadSourceLocation(void *Data, unsigned Offset) {
- SourceLocation::UIntTy Raw;
- memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(Raw));
- return SourceLocation::getFromRawEncoding(Raw);
+ dump(&OS, &LO);
}
-/// Load a (possibly unaligned) pointer from a given address and
-/// offset.
-static void *LoadPointer(void *Data, unsigned Offset) {
- void *Result;
- memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void*));
- return Result;
-}
-
-SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const {
+SourceLocation NestedNameSpecifierLoc::getBeginLoc() const {
if (!Qualifier)
- return SourceRange();
-
- unsigned Offset = getDataLength(Qualifier->getPrefix());
- switch (Qualifier->getKind()) {
- case NestedNameSpecifier::Global:
- return LoadSourceLocation(Data, Offset);
-
- case NestedNameSpecifier::Identifier:
- case NestedNameSpecifier::Namespace:
- case NestedNameSpecifier::Super:
- return SourceRange(
- LoadSourceLocation(Data, Offset),
- LoadSourceLocation(Data, Offset + sizeof(SourceLocation::UIntTy)));
-
- case NestedNameSpecifier::TypeSpec: {
- // The "void*" that points at the TypeLoc data.
- // Note: the 'template' keyword is part of the TypeLoc.
- void *TypeData = LoadPointer(Data, Offset);
- TypeLoc TL(Qualifier->getAsType(), TypeData);
- return SourceRange(TL.getBeginLoc(),
- LoadSourceLocation(Data, Offset + sizeof(void*)));
- }
- }
+ return SourceLocation();
- llvm_unreachable("Invalid NNS Kind!");
-}
-
-TypeLoc NestedNameSpecifierLoc::getTypeLoc() const {
- if (Qualifier->getKind() != NestedNameSpecifier::TypeSpec)
- return TypeLoc();
-
- // The "void*" that points at the TypeLoc data.
- unsigned Offset = getDataLength(Qualifier->getPrefix());
- void *TypeData = LoadPointer(Data, Offset);
- return TypeLoc(Qualifier->getAsType(), TypeData);
+ NestedNameSpecifierLoc First = *this;
+ while (NestedNameSpecifierLoc Prefix = First.getAsNamespaceAndPrefix().Prefix)
+ First = Prefix;
+ return First.getLocalSourceRange().getBegin();
}
static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize,
@@ -516,10 +247,10 @@ operator=(const NestedNameSpecifierLocBuilder &Other) {
return *this;
}
-void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, TypeLoc TL,
- SourceLocation ColonColonLoc) {
- Representation =
- NestedNameSpecifier::Create(Context, Representation, TL.getTypePtr());
+void NestedNameSpecifierLocBuilder::Make(ASTContext &Context, TypeLoc TL,
+ SourceLocation ColonColonLoc) {
+ assert(!Representation);
+ Representation = NestedNameSpecifier(TL.getTypePtr());
// Push source-location info into the buffer.
SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity);
@@ -527,23 +258,10 @@ void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, TypeLoc TL,
}
void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
- IdentifierInfo *Identifier,
- SourceLocation IdentifierLoc,
- SourceLocation ColonColonLoc) {
- Representation = NestedNameSpecifier::Create(Context, Representation,
- Identifier);
-
- // Push source-location info into the buffer.
- SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity);
- SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
-}
-
-void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
- NamespaceBaseDecl *Namespace,
+ const NamespaceBaseDecl *Namespace,
SourceLocation NamespaceLoc,
SourceLocation ColonColonLoc) {
- Representation = NestedNameSpecifier::Create(Context, Representation,
- Namespace);
+ Representation = NestedNameSpecifier(Context, Namespace, Representation);
// Push source-location info into the buffer.
SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity);
@@ -553,60 +271,48 @@ void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context,
void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context,
SourceLocation ColonColonLoc) {
assert(!Representation && "Already have a nested-name-specifier!?");
- Representation = NestedNameSpecifier::GlobalSpecifier(Context);
+ Representation = NestedNameSpecifier::getGlobal();
// Push source-location info into the buffer.
SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
}
-void NestedNameSpecifierLocBuilder::MakeSuper(ASTContext &Context,
- CXXRecordDecl *RD,
- SourceLocation SuperLoc,
- SourceLocation ColonColonLoc) {
- Representation = NestedNameSpecifier::SuperSpecifier(Context, RD);
+void NestedNameSpecifierLocBuilder::MakeMicrosoftSuper(
+ ASTContext &Context, CXXRecordDecl *RD, SourceLocation SuperLoc,
+ SourceLocation ColonColonLoc) {
+ Representation = NestedNameSpecifier(RD);
// Push source-location info into the buffer.
SaveSourceLocation(SuperLoc, Buffer, BufferSize, BufferCapacity);
SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity);
}
-void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context,
- NestedNameSpecifier *Qualifier,
+void NestedNameSpecifierLocBuilder::PushTrivial(ASTContext &Context,
+ NestedNameSpecifier Qualifier,
SourceRange R) {
- Representation = Qualifier;
-
// Construct bogus (but well-formed) source information for the
// nested-name-specifier.
- BufferSize = 0;
- SmallVector<NestedNameSpecifier *, 4> Stack;
- for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix())
- Stack.push_back(NNS);
- while (!Stack.empty()) {
- NestedNameSpecifier *NNS = Stack.pop_back_val();
- switch (NNS->getKind()) {
- case NestedNameSpecifier::Identifier:
- case NestedNameSpecifier::Namespace:
- SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity);
- break;
-
- case NestedNameSpecifier::TypeSpec: {
- TypeSourceInfo *TSInfo
- = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0),
- R.getBegin());
- SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize,
- BufferCapacity);
- break;
- }
-
- case NestedNameSpecifier::Global:
- case NestedNameSpecifier::Super:
- break;
- }
-
- // Save the location of the '::'.
- SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(),
- Buffer, BufferSize, BufferCapacity);
+ switch (Qualifier.getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ return;
+ case NestedNameSpecifier::Kind::Namespace: {
+ auto [_1, Prefix] = Qualifier.getAsNamespaceAndPrefix();
+ PushTrivial(Context, Prefix, R.getBegin());
+ SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity);
+ break;
+ }
+ case NestedNameSpecifier::Kind::Type: {
+ TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(
+ QualType(Qualifier.getAsType(), 0), R.getBegin());
+ SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize,
+ BufferCapacity);
+ break;
+ }
+ case NestedNameSpecifier::Kind::Global:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ break;
}
+ SaveSourceLocation(R.getEnd(), Buffer, BufferSize, BufferCapacity);
}
void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) {
@@ -614,7 +320,7 @@ void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) {
free(Buffer);
if (!Other) {
- Representation = nullptr;
+ Representation = std::nullopt;
BufferSize = 0;
return;
}
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index bd87d44..fb95f58 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -111,34 +111,28 @@ void ODRHash::AddDeclarationNameInfoImpl(DeclarationNameInfo NameInfo) {
}
}
-void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
- assert(NNS && "Expecting non-null pointer.");
- const auto *Prefix = NNS->getPrefix();
- AddBoolean(Prefix);
- if (Prefix) {
- AddNestedNameSpecifier(Prefix);
- }
- auto Kind = NNS->getKind();
- ID.AddInteger(Kind);
+void ODRHash::AddNestedNameSpecifier(NestedNameSpecifier NNS) {
+ auto Kind = NNS.getKind();
+ ID.AddInteger(llvm::to_underlying(Kind));
switch (Kind) {
- case NestedNameSpecifier::Identifier:
- AddIdentifierInfo(NNS->getAsIdentifier());
- break;
- case NestedNameSpecifier::Namespace:
- AddDecl(NNS->getAsNamespace());
+ case NestedNameSpecifier::Kind::Namespace: {
+ auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix();
+ AddDecl(Namespace);
+ AddNestedNameSpecifier(Prefix);
break;
- case NestedNameSpecifier::TypeSpec:
- AddType(NNS->getAsType());
+ }
+ case NestedNameSpecifier::Kind::Type:
+ AddType(NNS.getAsType());
break;
- case NestedNameSpecifier::Global:
- case NestedNameSpecifier::Super:
+ case NestedNameSpecifier::Kind::Null:
+ case NestedNameSpecifier::Kind::Global:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
break;
}
}
void ODRHash::AddDependentTemplateName(const DependentTemplateStorage &Name) {
- if (NestedNameSpecifier *NNS = Name.getQualifier())
- AddNestedNameSpecifier(NNS);
+ AddNestedNameSpecifier(Name.getQualifier());
if (IdentifierOrOverloadedOperator IO = Name.getName();
const IdentifierInfo *II = IO.getIdentifier())
AddIdentifierInfo(II);
@@ -156,8 +150,7 @@ void ODRHash::AddTemplateName(TemplateName Name) {
break;
case TemplateName::QualifiedTemplate: {
QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName();
- if (NestedNameSpecifier *NNS = QTN->getQualifier())
- AddNestedNameSpecifier(NNS);
+ AddNestedNameSpecifier(QTN->getQualifier());
AddBoolean(QTN->hasTemplateKeyword());
AddTemplateName(QTN->getUnderlyingTemplate());
break;
@@ -889,11 +882,8 @@ public:
}
}
- void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
- Hash.AddBoolean(NNS);
- if (NNS) {
- Hash.AddNestedNameSpecifier(NNS);
- }
+ void AddNestedNameSpecifier(NestedNameSpecifier NNS) {
+ Hash.AddNestedNameSpecifier(NNS);
}
void AddIdentifierInfo(const IdentifierInfo *II) {
@@ -907,52 +897,33 @@ public:
ID.AddInteger(Quals.getAsOpaqueValue());
}
- // Return the RecordType if the typedef only strips away a keyword.
- // Otherwise, return the original type.
- static const Type *RemoveTypedef(const Type *T) {
+ // Handle typedefs which only strip away a keyword.
+ bool handleTypedef(const Type *T) {
const auto *TypedefT = dyn_cast<TypedefType>(T);
- if (!TypedefT) {
- return T;
- }
-
- const TypedefNameDecl *D = TypedefT->getDecl();
- QualType UnderlyingType = D->getUnderlyingType();
-
- if (UnderlyingType.hasLocalQualifiers()) {
- return T;
- }
-
- const auto *ElaboratedT = dyn_cast<ElaboratedType>(UnderlyingType);
- if (!ElaboratedT) {
- return T;
- }
+ if (!TypedefT)
+ return false;
- if (ElaboratedT->getQualifier() != nullptr) {
- return T;
- }
+ QualType UnderlyingType = TypedefT->desugar();
- QualType NamedType = ElaboratedT->getNamedType();
- if (NamedType.hasLocalQualifiers()) {
- return T;
- }
+ if (UnderlyingType.hasLocalQualifiers())
+ return false;
- const auto *RecordT = dyn_cast<RecordType>(NamedType);
- if (!RecordT) {
- return T;
- }
+ const auto *TagT = dyn_cast<TagType>(UnderlyingType);
+ if (!TagT || TagT->getQualifier())
+ return false;
- const IdentifierInfo *TypedefII = TypedefT->getDecl()->getIdentifier();
- const IdentifierInfo *RecordII = RecordT->getDecl()->getIdentifier();
- if (!TypedefII || !RecordII ||
- TypedefII->getName() != RecordII->getName()) {
- return T;
- }
+ if (TypedefT->getDecl()->getIdentifier() !=
+ TagT->getOriginalDecl()->getIdentifier())
+ return false;
- return RecordT;
+ ID.AddInteger(TagT->getTypeClass());
+ VisitTagType(TagT, /*ElaboratedOverride=*/TypedefT);
+ return true;
}
void Visit(const Type *T) {
- T = RemoveTypedef(T);
+ if (handleTypedef(T))
+ return;
ID.AddInteger(T->getTypeClass());
Inherited::Visit(T);
}
@@ -1088,7 +1059,7 @@ public:
}
void VisitInjectedClassNameType(const InjectedClassNameType *T) {
- AddDecl(T->getDecl());
+ AddDecl(T->getOriginalDecl()->getDefinitionOrSelf());
VisitType(T);
}
@@ -1186,14 +1157,17 @@ public:
VisitType(T);
}
- void VisitTagType(const TagType *T) {
- AddDecl(T->getDecl());
+ void VisitTagType(const TagType *T,
+ const TypedefType *ElaboratedOverride = nullptr) {
+ ID.AddInteger(llvm::to_underlying(
+ ElaboratedOverride ? ElaboratedTypeKeyword::None : T->getKeyword()));
+ AddNestedNameSpecifier(ElaboratedOverride
+ ? ElaboratedOverride->getQualifier()
+ : T->getQualifier());
+ AddDecl(T->getOriginalDecl()->getDefinitionOrSelf());
VisitType(T);
}
- void VisitRecordType(const RecordType *T) { VisitTagType(T); }
- void VisitEnumType(const EnumType *T) { VisitTagType(T); }
-
void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
ID.AddInteger(T->template_arguments().size());
for (const auto &TA : T->template_arguments()) {
@@ -1211,6 +1185,8 @@ public:
}
void VisitTypedefType(const TypedefType *T) {
+ ID.AddInteger(llvm::to_underlying(T->getKeyword()));
+ AddNestedNameSpecifier(T->getQualifier());
AddDecl(T->getDecl());
VisitType(T);
}
@@ -1247,12 +1223,6 @@ public:
VisitTypeWithKeyword(T);
}
- void VisitElaboratedType(const ElaboratedType *T) {
- AddNestedNameSpecifier(T->getQualifier());
- AddQualType(T->getNamedType());
- VisitTypeWithKeyword(T);
- }
-
void VisitUnaryTransformType(const UnaryTransformType *T) {
AddQualType(T->getUnderlyingType());
AddQualType(T->getBaseType());
@@ -1330,7 +1300,7 @@ void ODRHash::AddStructuralValue(const APValue &Value) {
TypeSoFar = FD->getType();
} else {
TypeSoFar =
- D->getASTContext().getRecordType(cast<CXXRecordDecl>(D));
+ D->getASTContext().getCanonicalTagType(cast<CXXRecordDecl>(D));
}
}
}
diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp
index fe20004..9a9ede4 100644
--- a/clang/lib/AST/OpenACCClause.cpp
+++ b/clang/lib/AST/OpenACCClause.cpp
@@ -506,11 +506,13 @@ OpenACCDeviceTypeClause *OpenACCDeviceTypeClause::Create(
OpenACCReductionClause *OpenACCReductionClause::Create(
const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
OpenACCReductionOperator Operator, ArrayRef<Expr *> VarList,
+ ArrayRef<OpenACCReductionRecipe> Recipes,
SourceLocation EndLoc) {
void *Mem = C.Allocate(
- OpenACCReductionClause::totalSizeToAlloc<Expr *>(VarList.size()));
- return new (Mem)
- OpenACCReductionClause(BeginLoc, LParenLoc, Operator, VarList, EndLoc);
+ OpenACCReductionClause::totalSizeToAlloc<Expr *, OpenACCReductionRecipe>(
+ VarList.size(), Recipes.size()));
+ return new (Mem) OpenACCReductionClause(BeginLoc, LParenLoc, Operator,
+ VarList, Recipes, EndLoc);
}
OpenACCAutoClause *OpenACCAutoClause::Create(const ASTContext &C,
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index de8b599..0930ca2 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) {
@@ -2350,17 +2353,16 @@ void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) {
if (Node->getModifierLoc().isValid())
OS << getOpenMPSimpleClauseTypeName(OMPC_reduction, Node->getModifier())
<< ", ";
- NestedNameSpecifier *QualifierLoc =
+ NestedNameSpecifier Qualifier =
Node->getQualifierLoc().getNestedNameSpecifier();
OverloadedOperatorKind OOK =
Node->getNameInfo().getName().getCXXOverloadedOperator();
- if (QualifierLoc == nullptr && OOK != OO_None) {
+ if (!Qualifier && OOK != OO_None) {
// Print reduction identifier in C format
OS << getOperatorSpelling(OOK);
} else {
// Use C++ format
- if (QualifierLoc != nullptr)
- QualifierLoc->print(OS, Policy);
+ Qualifier.print(OS, Policy);
OS << Node->getNameInfo();
}
OS << ":";
@@ -2373,17 +2375,16 @@ void OMPClausePrinter::VisitOMPTaskReductionClause(
OMPTaskReductionClause *Node) {
if (!Node->varlist_empty()) {
OS << "task_reduction(";
- NestedNameSpecifier *QualifierLoc =
+ NestedNameSpecifier Qualifier =
Node->getQualifierLoc().getNestedNameSpecifier();
OverloadedOperatorKind OOK =
Node->getNameInfo().getName().getCXXOverloadedOperator();
- if (QualifierLoc == nullptr && OOK != OO_None) {
+ if (!Qualifier && OOK != OO_None) {
// Print reduction identifier in C format
OS << getOperatorSpelling(OOK);
} else {
// Use C++ format
- if (QualifierLoc != nullptr)
- QualifierLoc->print(OS, Policy);
+ Qualifier.print(OS, Policy);
OS << Node->getNameInfo();
}
OS << ":";
@@ -2395,17 +2396,16 @@ void OMPClausePrinter::VisitOMPTaskReductionClause(
void OMPClausePrinter::VisitOMPInReductionClause(OMPInReductionClause *Node) {
if (!Node->varlist_empty()) {
OS << "in_reduction(";
- NestedNameSpecifier *QualifierLoc =
+ NestedNameSpecifier Qualifier =
Node->getQualifierLoc().getNestedNameSpecifier();
OverloadedOperatorKind OOK =
Node->getNameInfo().getName().getCXXOverloadedOperator();
- if (QualifierLoc == nullptr && OOK != OO_None) {
+ if (!Qualifier && OOK != OO_None) {
// Print reduction identifier in C format
OS << getOperatorSpelling(OOK);
} else {
// Use C++ format
- if (QualifierLoc != nullptr)
- QualifierLoc->print(OS, Policy);
+ Qualifier.print(OS, Policy);
OS << Node->getNameInfo();
}
OS << ":";
@@ -2508,10 +2508,9 @@ template <typename T>
static void PrintMapper(raw_ostream &OS, T *Node,
const PrintingPolicy &Policy) {
OS << '(';
- NestedNameSpecifier *MapperNNS =
+ NestedNameSpecifier MapperNNS =
Node->getMapperQualifierLoc().getNestedNameSpecifier();
- if (MapperNNS)
- MapperNNS->print(OS, Policy);
+ MapperNNS.print(OS, Policy);
OS << Node->getMapperIdInfo() << ')';
}
diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp
index 68dfe4d..acc011c 100644
--- a/clang/lib/AST/ParentMapContext.cpp
+++ b/clang/lib/AST/ParentMapContext.cpp
@@ -438,10 +438,12 @@ private:
DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); },
&Map.PointerParents);
}
- bool TraverseTypeLoc(TypeLoc TypeLocNode) {
+ bool TraverseTypeLoc(TypeLoc TypeLocNode, bool TraverseQualifier = true) {
return TraverseNode(
TypeLocNode, DynTypedNode::create(TypeLocNode),
- [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); },
+ [&] {
+ return VisitorBase::TraverseTypeLoc(TypeLocNode, TraverseQualifier);
+ },
&Map.OtherParents);
}
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) {
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index bcd44f0..8555504 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->getDecl()->getIntegerType();
+ if (const auto *ED = QT->getAsEnumDecl())
+ QT = ED->getIntegerType();
const BuiltinType *BT = QT->getAs<BuiltinType>();
if (!BT) {
diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp
index 9731b3a..ee7fec3 100644
--- a/clang/lib/AST/QualTypeNames.cpp
+++ b/clang/lib/AST/QualTypeNames.cpp
@@ -24,10 +24,9 @@ namespace TypeName {
/// is requested.
/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
/// specifier "::" should be prepended or not.
-static NestedNameSpecifier *createNestedNameSpecifier(
- const ASTContext &Ctx,
- const NamespaceDecl *Namesp,
- bool WithGlobalNsPrefix);
+static NestedNameSpecifier
+createNestedNameSpecifier(const ASTContext &Ctx, const NamespaceDecl *Namesp,
+ bool WithGlobalNsPrefix);
/// Create a NestedNameSpecifier for TagDecl and its enclosing
/// scopes.
@@ -39,22 +38,24 @@ static NestedNameSpecifier *createNestedNameSpecifier(
/// qualified names.
/// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace
/// specifier "::" should be prepended or not.
-static NestedNameSpecifier *createNestedNameSpecifier(
- const ASTContext &Ctx, const TypeDecl *TD,
- bool FullyQualify, bool WithGlobalNsPrefix);
+static NestedNameSpecifier createNestedNameSpecifier(const ASTContext &Ctx,
+ const TypeDecl *TD,
+ bool FullyQualify,
+ bool WithGlobalNsPrefix);
-static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
- const ASTContext &Ctx, const Decl *decl,
- bool FullyQualified, bool WithGlobalNsPrefix);
+static NestedNameSpecifier
+createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *decl,
+ bool FullyQualified,
+ bool WithGlobalNsPrefix);
-static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
- const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix);
+static NestedNameSpecifier getFullyQualifiedNestedNameSpecifier(
+ const ASTContext &Ctx, NestedNameSpecifier NNS, bool WithGlobalNsPrefix);
static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
TemplateName &TName,
bool WithGlobalNsPrefix) {
bool Changed = false;
- NestedNameSpecifier *NNS = nullptr;
+ NestedNameSpecifier NNS = std::nullopt;
TemplateDecl *ArgTDecl = TName.getAsTemplateDecl();
// ArgTDecl won't be NULL because we asserted that this isn't a
@@ -65,13 +66,13 @@ static bool getFullyQualifiedTemplateName(const ASTContext &Ctx,
if (QTName &&
!QTName->hasTemplateKeyword() &&
(NNS = QTName->getQualifier())) {
- NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier(
- Ctx, NNS, WithGlobalNsPrefix);
+ NestedNameSpecifier QNNS =
+ getFullyQualifiedNestedNameSpecifier(Ctx, NNS, WithGlobalNsPrefix);
if (QNNS != NNS) {
Changed = true;
NNS = QNNS;
} else {
- NNS = nullptr;
+ NNS = std::nullopt;
}
} else {
NNS = createNestedNameSpecifierForScopeOf(
@@ -116,76 +117,81 @@ static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx,
}
static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
- const Type *TypePtr,
+ const TagType *TSTRecord,
+ ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
bool WithGlobalNsPrefix) {
- // DependentTemplateTypes exist within template declarations and
- // definitions. Therefore we shouldn't encounter them at the end of
- // a translation unit. If we do, the caller has made an error.
- assert(!isa<DependentTemplateSpecializationType>(TypePtr));
- // In case of template specializations, iterate over the arguments
- // and fully qualify them as well.
- if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) {
- bool MightHaveChanged = false;
- SmallVector<TemplateArgument, 4> FQArgs;
- // Cheap to copy and potentially modified by
- // getFullyQualifedTemplateArgument.
- for (TemplateArgument Arg : TST->template_arguments()) {
- MightHaveChanged |= getFullyQualifiedTemplateArgument(
- Ctx, Arg, WithGlobalNsPrefix);
- FQArgs.push_back(Arg);
- }
+ // We are asked to fully qualify and we have a Record Type,
+ // which can point to a template instantiation with no sugar in any of
+ // its template argument, however we still need to fully qualify them.
+
+ const auto *TD = TSTRecord->getOriginalDecl();
+ const auto *TSTDecl = dyn_cast<ClassTemplateSpecializationDecl>(TD);
+ if (!TSTDecl)
+ return Ctx.getTagType(Keyword, Qualifier, TD, /*OwnsTag=*/false)
+ .getTypePtr();
+
+ const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();
+
+ bool MightHaveChanged = false;
+ SmallVector<TemplateArgument, 4> FQArgs;
+ for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {
+ // cheap to copy and potentially modified by
+ // getFullyQualifedTemplateArgument
+ TemplateArgument Arg(TemplateArgs[I]);
+ MightHaveChanged |=
+ getFullyQualifiedTemplateArgument(Ctx, Arg, WithGlobalNsPrefix);
+ FQArgs.push_back(Arg);
+ }
- // If a fully qualified arg is different from the unqualified arg,
- // allocate new type in the AST.
- if (MightHaveChanged) {
- QualType QT = Ctx.getTemplateSpecializationType(
- TST->getTemplateName(), FQArgs,
- /*CanonicalArgs=*/{}, TST->desugar());
- // getTemplateSpecializationType returns a fully qualified
- // version of the specialization itself, so no need to qualify
- // it.
- return QT.getTypePtr();
- }
- } else if (const auto *TSTRecord = dyn_cast<const RecordType>(TypePtr)) {
- // We are asked to fully qualify and we have a Record Type,
- // which can point to a template instantiation with no sugar in any of
- // its template argument, however we still need to fully qualify them.
-
- if (const auto *TSTDecl =
- dyn_cast<ClassTemplateSpecializationDecl>(TSTRecord->getDecl())) {
- const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs();
-
- bool MightHaveChanged = false;
- SmallVector<TemplateArgument, 4> FQArgs;
- for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) {
- // cheap to copy and potentially modified by
- // getFullyQualifedTemplateArgument
- TemplateArgument Arg(TemplateArgs[I]);
- MightHaveChanged |= getFullyQualifiedTemplateArgument(
- Ctx, Arg, WithGlobalNsPrefix);
- FQArgs.push_back(Arg);
- }
+ if (!MightHaveChanged)
+ return Ctx.getTagType(Keyword, Qualifier, TD, /*OwnsTag=*/false)
+ .getTypePtr();
+ // If a fully qualified arg is different from the unqualified arg,
+ // allocate new type in the AST.
+ TemplateName TN = Ctx.getQualifiedTemplateName(
+ Qualifier, /*TemplateKeyword=*/false,
+ TemplateName(TSTDecl->getSpecializedTemplate()));
+ QualType QT = Ctx.getTemplateSpecializationType(
+ Keyword, TN, FQArgs,
+ /*CanonicalArgs=*/{}, TSTRecord->getCanonicalTypeInternal());
+ // getTemplateSpecializationType returns a fully qualified
+ // version of the specialization itself, so no need to qualify
+ // it.
+ return QT.getTypePtr();
+}
- // If a fully qualified arg is different from the unqualified arg,
- // allocate new type in the AST.
- if (MightHaveChanged) {
- TemplateName TN(TSTDecl->getSpecializedTemplate());
- QualType QT = Ctx.getTemplateSpecializationType(
- TN, FQArgs,
- /*CanonicalArgs=*/{}, TSTRecord->getCanonicalTypeInternal());
- // getTemplateSpecializationType returns a fully qualified
- // version of the specialization itself, so no need to qualify
- // it.
- return QT.getTypePtr();
- }
- }
+static const Type *
+getFullyQualifiedTemplateType(const ASTContext &Ctx,
+ const TemplateSpecializationType *TST,
+ bool WithGlobalNsPrefix) {
+ TemplateName TName = TST->getTemplateName();
+ bool MightHaveChanged =
+ getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix);
+ SmallVector<TemplateArgument, 4> FQArgs;
+ // Cheap to copy and potentially modified by
+ // getFullyQualifedTemplateArgument.
+ for (TemplateArgument Arg : TST->template_arguments()) {
+ MightHaveChanged |=
+ getFullyQualifiedTemplateArgument(Ctx, Arg, WithGlobalNsPrefix);
+ FQArgs.push_back(Arg);
}
- return TypePtr;
+
+ if (!MightHaveChanged)
+ return TST;
+
+ QualType NewQT =
+ Ctx.getTemplateSpecializationType(TST->getKeyword(), TName, FQArgs,
+ /*CanonicalArgs=*/{}, TST->desugar());
+ // getTemplateSpecializationType returns a fully qualified
+ // version of the specialization itself, so no need to qualify
+ // it.
+ return NewQT.getTypePtr();
}
-static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
- bool FullyQualify,
- bool WithGlobalNsPrefix) {
+static NestedNameSpecifier createOuterNNS(const ASTContext &Ctx, const Decl *D,
+ bool FullyQualify,
+ bool WithGlobalNsPrefix) {
const DeclContext *DC = D->getDeclContext();
if (const auto *NS = dyn_cast<NamespaceDecl>(DC)) {
while (NS && NS->isInline()) {
@@ -195,71 +201,63 @@ static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D,
if (NS && NS->getDeclName()) {
return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix);
}
- return nullptr; // no starting '::', no anonymous
- } else if (const auto *TD = dyn_cast<TagDecl>(DC)) {
- return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
- } else if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC)) {
- return createNestedNameSpecifier(
- Ctx, TDD, FullyQualify, WithGlobalNsPrefix);
- } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
- return NestedNameSpecifier::GlobalSpecifier(Ctx);
+ return std::nullopt; // no starting '::', no anonymous
}
- return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false
+ if (const auto *TD = dyn_cast<TagDecl>(DC))
+ return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix);
+ if (const auto *TDD = dyn_cast<TypedefNameDecl>(DC))
+ return createNestedNameSpecifier(Ctx, TDD, FullyQualify,
+ WithGlobalNsPrefix);
+ if (WithGlobalNsPrefix && DC->isTranslationUnit())
+ return NestedNameSpecifier::getGlobal();
+ return std::nullopt; // no starting '::' if |WithGlobalNsPrefix| is false
}
/// Return a fully qualified version of this name specifier.
-static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier(
- const ASTContext &Ctx, NestedNameSpecifier *Scope,
- bool WithGlobalNsPrefix) {
- switch (Scope->getKind()) {
- case NestedNameSpecifier::Global:
- case NestedNameSpecifier::Super:
- // Already fully qualified
- return Scope;
- case NestedNameSpecifier::Namespace:
- return TypeName::createNestedNameSpecifier(
- Ctx, Scope->getAsNamespace()->getNamespace(), WithGlobalNsPrefix);
- case NestedNameSpecifier::Identifier:
- // A function or some other construct that makes it un-namable
- // at the end of the TU. Skip the current component of the name,
- // but use the name of it's prefix.
- return getFullyQualifiedNestedNameSpecifier(
- Ctx, Scope->getPrefix(), WithGlobalNsPrefix);
- case NestedNameSpecifier::TypeSpec: {
- const Type *Type = Scope->getAsType();
- // Find decl context.
- const TagDecl *TD = nullptr;
- if (const TagType *TagDeclType = Type->getAs<TagType>()) {
- TD = TagDeclType->getDecl();
- } else {
- TD = Type->getAsCXXRecordDecl();
- }
- if (TD) {
- return TypeName::createNestedNameSpecifier(Ctx, TD,
- true /*FullyQualified*/,
- WithGlobalNsPrefix);
- } else if (const auto *TDD = dyn_cast<TypedefType>(Type)) {
- return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(),
- true /*FullyQualified*/,
- WithGlobalNsPrefix);
- }
+static NestedNameSpecifier getFullyQualifiedNestedNameSpecifier(
+ const ASTContext &Ctx, NestedNameSpecifier Scope, bool WithGlobalNsPrefix) {
+ switch (Scope.getKind()) {
+ case NestedNameSpecifier::Kind::Null:
+ llvm_unreachable("can't fully qualify the empty nested name specifier");
+ case NestedNameSpecifier::Kind::Global:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
+ // Already fully qualified
+ return Scope;
+ case NestedNameSpecifier::Kind::Namespace:
+ return TypeName::createNestedNameSpecifier(
+ Ctx, Scope.getAsNamespaceAndPrefix().Namespace->getNamespace(),
+ WithGlobalNsPrefix);
+ case NestedNameSpecifier::Kind::Type: {
+ const Type *Type = Scope.getAsType();
+ // Find decl context.
+ const TypeDecl *TD;
+ if (const TagType *TagDeclType = Type->getAs<TagType>())
+ TD = TagDeclType->getOriginalDecl();
+ else if (const auto *D = dyn_cast<TypedefType>(Type))
+ TD = D->getDecl();
+ else
return Scope;
- }
+ return TypeName::createNestedNameSpecifier(Ctx, TD, /*FullyQualify=*/true,
+ WithGlobalNsPrefix);
+ }
}
llvm_unreachable("bad NNS kind");
}
/// Create a nested name specifier for the declaring context of
/// the type.
-static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
- const ASTContext &Ctx, const Decl *Decl,
- bool FullyQualified, bool WithGlobalNsPrefix) {
+static NestedNameSpecifier
+createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *Decl,
+ bool FullyQualified,
+ bool WithGlobalNsPrefix) {
assert(Decl);
const DeclContext *DC = Decl->getDeclContext()->getRedeclContext();
const auto *Outer = dyn_cast<NamedDecl>(DC);
const auto *OuterNS = dyn_cast<NamespaceDecl>(DC);
- if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) {
+ if (OuterNS && OuterNS->isAnonymousNamespace())
+ OuterNS = dyn_cast<NamespaceDecl>(OuterNS->getParent());
+ if (Outer) {
if (const auto *CxxDecl = dyn_cast<CXXRecordDecl>(DC)) {
if (ClassTemplateDecl *ClassTempl =
CxxDecl->getDescribedClassTemplate()) {
@@ -288,76 +286,80 @@ static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
Ctx, TD, FullyQualified, WithGlobalNsPrefix);
} else if (isa<TranslationUnitDecl>(Outer)) {
// Context is the TU. Nothing needs to be done.
- return nullptr;
+ return std::nullopt;
} else {
// Decl's context was neither the TU, a namespace, nor a
// TagDecl, which means it is a type local to a scope, and not
// accessible at the end of the TU.
- return nullptr;
+ return std::nullopt;
}
} else if (WithGlobalNsPrefix && DC->isTranslationUnit()) {
- return NestedNameSpecifier::GlobalSpecifier(Ctx);
+ return NestedNameSpecifier::getGlobal();
}
- return nullptr;
+ return std::nullopt;
}
/// Create a nested name specifier for the declaring context of
/// the type.
-static NestedNameSpecifier *createNestedNameSpecifierForScopeOf(
- const ASTContext &Ctx, const Type *TypePtr,
- bool FullyQualified, bool WithGlobalNsPrefix) {
- if (!TypePtr) return nullptr;
+static NestedNameSpecifier
+createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Type *TypePtr,
+ bool FullyQualified,
+ bool WithGlobalNsPrefix) {
+ if (!TypePtr)
+ return std::nullopt;
Decl *Decl = nullptr;
// There are probably other cases ...
if (const auto *TDT = dyn_cast<TypedefType>(TypePtr)) {
Decl = TDT->getDecl();
} else if (const auto *TagDeclType = dyn_cast<TagType>(TypePtr)) {
- Decl = TagDeclType->getDecl();
+ Decl = TagDeclType->getOriginalDecl();
} else if (const auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {
Decl = TST->getTemplateName().getAsTemplateDecl();
} else {
Decl = TypePtr->getAsCXXRecordDecl();
}
- if (!Decl) return nullptr;
+ if (!Decl)
+ return std::nullopt;
return createNestedNameSpecifierForScopeOf(
Ctx, Decl, FullyQualified, WithGlobalNsPrefix);
}
-NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
- const NamespaceDecl *Namespace,
- bool WithGlobalNsPrefix) {
+static NestedNameSpecifier
+createNestedNameSpecifier(const ASTContext &Ctx, const NamespaceDecl *Namespace,
+ bool WithGlobalNsPrefix) {
while (Namespace && Namespace->isInline()) {
// Ignore inline namespace;
Namespace = dyn_cast<NamespaceDecl>(Namespace->getDeclContext());
}
- if (!Namespace) return nullptr;
+ if (!Namespace)
+ return std::nullopt;
- bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces
- return NestedNameSpecifier::Create(
- Ctx,
- createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix),
- Namespace);
+ bool FullyQualify = true; // doesn't matter, DeclContexts are namespaces
+ return NestedNameSpecifier(
+ Ctx, Namespace,
+ createOuterNNS(Ctx, Namespace, FullyQualify, WithGlobalNsPrefix));
}
-NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx,
- const TypeDecl *TD,
- bool FullyQualify,
- bool WithGlobalNsPrefix) {
- const Type *TypePtr = TD->getTypeForDecl();
- if (isa<const TemplateSpecializationType>(TypePtr) ||
- isa<const RecordType>(TypePtr)) {
+NestedNameSpecifier createNestedNameSpecifier(const ASTContext &Ctx,
+ const TypeDecl *TD,
+ bool FullyQualify,
+ bool WithGlobalNsPrefix) {
+ const Type *TypePtr = Ctx.getTypeDeclType(TD).getTypePtr();
+ if (auto *RD = dyn_cast<TagType>(TypePtr)) {
// We are asked to fully qualify and we have a Record Type (which
// may point to a template specialization) or Template
// Specialization Type. We need to fully qualify their arguments.
-
- TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix);
+ TypePtr = getFullyQualifiedTemplateType(
+ Ctx, RD, ElaboratedTypeKeyword::None,
+ createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix),
+ WithGlobalNsPrefix);
+ } else if (auto *TST = dyn_cast<TemplateSpecializationType>(TypePtr)) {
+ TypePtr = getFullyQualifiedTemplateType(Ctx, TST, WithGlobalNsPrefix);
}
-
- return NestedNameSpecifier::Create(
- Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), TypePtr);
+ return NestedNameSpecifier(TypePtr);
}
/// Return the fully qualified type, including fully-qualified
@@ -381,7 +383,7 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
Qualifiers Quals = QT.getQualifiers();
// Fully qualify the pointee and class types.
QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix);
- NestedNameSpecifier *Qualifier = getFullyQualifiedNestedNameSpecifier(
+ NestedNameSpecifier Qualifier = getFullyQualifiedNestedNameSpecifier(
Ctx, MPT->getQualifier(), WithGlobalNsPrefix);
QT = Ctx.getMemberPointerType(QT, Qualifier,
MPT->getMostRecentCXXRecordDecl());
@@ -434,45 +436,48 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
QT = Ctx.getQualifiedType(QT, Quals);
}
- NestedNameSpecifier *Prefix = nullptr;
+ if (const auto *TST =
+ dyn_cast<const TemplateSpecializationType>(QT.getTypePtr())) {
+
+ const Type *T = getFullyQualifiedTemplateType(Ctx, TST, WithGlobalNsPrefix);
+ if (T == TST)
+ return QT;
+ return Ctx.getQualifiedType(T, QT.getQualifiers());
+ }
+
// Local qualifiers are attached to the QualType outside of the
// elaborated type. Retrieve them before descending into the
// elaborated type.
Qualifiers PrefixQualifiers = QT.getLocalQualifiers();
QT = QualType(QT.getTypePtr(), 0);
- ElaboratedTypeKeyword Keyword = ElaboratedTypeKeyword::None;
- if (const auto *ETypeInput = dyn_cast<ElaboratedType>(QT.getTypePtr())) {
- QT = ETypeInput->getNamedType();
- assert(!QT.hasLocalQualifiers());
- Keyword = ETypeInput->getKeyword();
- }
// We don't consider the alias introduced by `using a::X` as a new type.
// The qualified name is still a::X.
if (const auto *UT = QT->getAs<UsingType>()) {
- QT = Ctx.getQualifiedType(UT->getUnderlyingType(), PrefixQualifiers);
+ QT = Ctx.getQualifiedType(UT->desugar(), PrefixQualifiers);
return getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
}
// Create a nested name specifier if needed.
- Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
- true /*FullyQualified*/,
- WithGlobalNsPrefix);
+ NestedNameSpecifier Prefix = createNestedNameSpecifierForScopeOf(
+ Ctx, QT.getTypePtr(), true /*FullyQualified*/, WithGlobalNsPrefix);
// In case of template specializations iterate over the arguments and
// fully qualify them as well.
- if (isa<const TemplateSpecializationType>(QT.getTypePtr()) ||
- isa<const RecordType>(QT.getTypePtr())) {
+ if (const auto *TT = dyn_cast<TagType>(QT.getTypePtr())) {
// We are asked to fully qualify and we have a Record Type (which
// may point to a template specialization) or Template
// Specialization Type. We need to fully qualify their arguments.
const Type *TypePtr = getFullyQualifiedTemplateType(
- Ctx, QT.getTypePtr(), WithGlobalNsPrefix);
+ Ctx, TT, TT->getKeyword(), Prefix, WithGlobalNsPrefix);
QT = QualType(TypePtr, 0);
- }
- if (Prefix || Keyword != ElaboratedTypeKeyword::None) {
- QT = Ctx.getElaboratedType(Keyword, Prefix, QT);
+ } else if (const auto *TT = dyn_cast<TypedefType>(QT.getTypePtr())) {
+ QT = Ctx.getTypedefType(
+ TT->getKeyword(), Prefix, TT->getDecl(),
+ getFullyQualifiedType(TT->desugar(), Ctx, WithGlobalNsPrefix));
+ } else {
+ assert(!Prefix && "Unhandled type node");
}
QT = Ctx.getQualifiedType(QT, PrefixQualifiers);
return QT;
@@ -486,5 +491,12 @@ std::string getFullyQualifiedName(QualType QT,
return FQQT.getAsString(Policy);
}
+NestedNameSpecifier getFullyQualifiedDeclaredContext(const ASTContext &Ctx,
+ const Decl *Decl,
+ bool WithGlobalNsPrefix) {
+ return createNestedNameSpecifierForScopeOf(Ctx, Decl, /*FullyQualified=*/true,
+ WithGlobalNsPrefix);
+}
+
} // end namespace TypeName
} // end namespace clang
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 760b2fc..4b312c5 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -204,15 +204,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 +431,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 +530,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,9 +2007,8 @@ 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>()) {
- const RecordDecl *RD = RT->getDecl();
- assert(RD && "Expected non-null RecordDecl.");
+ } else if (const RecordType *RT = BaseTy->getAsCanonical<RecordType>()) {
+ const RecordDecl *RD = RT->getOriginalDecl();
const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD);
PreferredAlign = FieldRecord.getPreferredAlignment();
}
@@ -2128,7 +2123,8 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
// TODO: Takes no account the alignment of the outer struct
if (FieldOffset % OriginalFieldAlign != 0)
Diag(D->getLocation(), diag::warn_unaligned_access)
- << Context.getTypeDeclType(RD) << D->getName() << D->getType();
+ << Context.getCanonicalTagType(RD) << D->getName()
+ << D->getType();
}
}
@@ -2193,8 +2189,7 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
InBits = false;
}
Diag(RD->getLocation(), diag::warn_padded_struct_size)
- << Context.getTypeDeclType(RD)
- << PadSize
+ << Context.getCanonicalTagType(RD) << PadSize
<< (InBits ? 1 : 0); // (byte|bit)
}
@@ -2212,7 +2207,7 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
Context.getLangOpts().getClangABICompat() <=
LangOptions::ClangABI::Ver15))
Diag(D->getLocation(), diag::warn_unnecessary_packed)
- << Context.getTypeDeclType(RD);
+ << Context.getCanonicalTagType(RD);
}
}
@@ -2306,7 +2301,7 @@ static void CheckFieldPadding(const ASTContext &Context, bool IsUnion,
Context.getDiagnostics().Report(D->getLocation(),
Diagnostic)
<< getPaddingDiagFromTagKind(D->getParent()->getTagKind())
- << Context.getTypeDeclType(D->getParent()) << PadSize
+ << Context.getCanonicalTagType(D->getParent()) << PadSize
<< (InBits ? 1 : 0) // (byte|bit)
<< D->getIdentifier();
} else {
@@ -2315,7 +2310,7 @@ static void CheckFieldPadding(const ASTContext &Context, bool IsUnion,
Context.getDiagnostics().Report(D->getLocation(),
Diagnostic)
<< getPaddingDiagFromTagKind(D->getParent()->getTagKind())
- << Context.getTypeDeclType(D->getParent()) << PadSize
+ << Context.getCanonicalTagType(D->getParent()) << PadSize
<< (InBits ? 1 : 0); // (byte|bit)
}
}
@@ -2712,9 +2707,10 @@ 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>()) {
- auto const &Layout = Context.getASTRecordLayout(RT->getDecl());
+ if (const auto *RT = FD->getType()
+ ->getBaseElementTypeUnsafe()
+ ->getAsCanonical<RecordType>()) {
+ auto const &Layout = Context.getASTRecordLayout(RT->getOriginalDecl());
EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject();
FieldRequiredAlignment = std::max(FieldRequiredAlignment,
Layout.getRequiredAlignment());
@@ -3273,7 +3269,7 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) {
Context.getDiagnostics().Report(RD->getLocation(),
diag::warn_padded_struct_size)
- << Context.getTypeDeclType(RD) << PadSize
+ << Context.getCanonicalTagType(RD) << PadSize
<< (InBits ? 1 : 0); // (byte|bit)
}
}
@@ -3631,7 +3627,7 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD,
auto CXXRD = dyn_cast<CXXRecordDecl>(RD);
PrintOffset(OS, Offset, IndentLevel);
- OS << C.getTypeDeclType(const_cast<RecordDecl *>(RD));
+ OS << C.getCanonicalTagType(const_cast<RecordDecl *>(RD));
if (Description)
OS << ' ' << Description;
if (CXXRD && CXXRD->isEmpty())
@@ -3696,8 +3692,8 @@ 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->getDecl(), C, FieldOffset, IndentLevel,
+ if (const auto *RD = Field->getType()->getAsRecordDecl()) {
+ DumpRecordLayout(OS, RD, C, FieldOffset, IndentLevel,
Field->getName().data(),
/*PrintSizeInfo=*/false,
/*IncludeVirtualBases=*/true);
@@ -3781,7 +3777,7 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS,
// in libFrontend.
const ASTRecordLayout &Info = getASTRecordLayout(RD);
- OS << "Type: " << getTypeDeclType(RD) << "\n";
+ OS << "Type: " << getCanonicalTagType(RD) << "\n";
OS << "\nLayout: ";
OS << "<ASTRecordLayout\n";
OS << " Size:" << toBits(Info.getSize()) << "\n";
diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp
index 1227edd..41cf71a 100644
--- a/clang/lib/AST/ScanfFormatString.cpp
+++ b/clang/lib/AST/ScanfFormatString.cpp
@@ -430,11 +430,11 @@ 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.
- if (!ETy->getDecl()->isComplete())
+ if (!ED->isComplete())
return false;
- PT = ETy->getDecl()->getIntegerType();
+ PT = ED->getIntegerType();
}
const BuiltinType *BT = PT->getAs<BuiltinType>();
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 6ba5ec8..afccba8 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -454,10 +454,7 @@ void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) {
else
OS << "__if_not_exists (";
- if (NestedNameSpecifier *Qualifier
- = Node->getQualifierLoc().getNestedNameSpecifier())
- Qualifier->print(OS, Policy);
-
+ Node->getQualifierLoc().getNestedNameSpecifier().print(OS, Policy);
OS << Node->getNameInfo() << ") ";
PrintRawCompoundStmt(Node->getSubStmt());
@@ -1309,8 +1306,7 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
TPOD->printAsExpr(OS, Policy);
return;
}
- if (NestedNameSpecifier *Qualifier = Node->getQualifier())
- Qualifier->print(OS, Policy);
+ Node->getQualifier().print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
@@ -1359,8 +1355,7 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
void StmtPrinter::VisitDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr *Node) {
- if (NestedNameSpecifier *Qualifier = Node->getQualifier())
- Qualifier->print(OS, Policy);
+ Node->getQualifier().print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getNameInfo();
@@ -1369,8 +1364,7 @@ void StmtPrinter::VisitDependentScopeDeclRefExpr(
}
void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
- if (Node->getQualifier())
- Node->getQualifier()->print(OS, Policy);
+ Node->getQualifier().print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getNameInfo();
@@ -1778,8 +1772,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
if (FD->isAnonymousStructOrUnion())
return;
- if (NestedNameSpecifier *Qualifier = Node->getQualifier())
- Qualifier->print(OS, Policy);
+ Node->getQualifier().print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
@@ -2177,9 +2170,7 @@ void StmtPrinter::VisitMSPropertyRefExpr(MSPropertyRefExpr *Node) {
OS << "->";
else
OS << ".";
- if (NestedNameSpecifier *Qualifier =
- Node->getQualifierLoc().getNestedNameSpecifier())
- Qualifier->print(OS, Policy);
+ Node->getQualifierLoc().getNestedNameSpecifier().print(OS, Policy);
OS << Node->getPropertyDecl()->getDeclName();
}
@@ -2509,8 +2500,7 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
OS << "->";
else
OS << '.';
- if (E->getQualifier())
- E->getQualifier()->print(OS, Policy);
+ E->getQualifier().print(OS, Policy);
OS << "~";
if (const IdentifierInfo *II = E->getDestroyedTypeIdentifier())
@@ -2572,8 +2562,7 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr(
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
}
- if (NestedNameSpecifier *Qualifier = Node->getQualifier())
- Qualifier->print(OS, Policy);
+ Node->getQualifier().print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
@@ -2586,8 +2575,7 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
}
- if (NestedNameSpecifier *Qualifier = Node->getQualifier())
- Qualifier->print(OS, Policy);
+ Node->getQualifier().print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
@@ -2678,8 +2666,7 @@ void StmtPrinter::VisitCXXParenListInitExpr(CXXParenListInitExpr *Node) {
void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc();
- if (NNS)
- NNS.getNestedNameSpecifier()->print(OS, Policy);
+ NNS.getNestedNameSpecifier().print(OS, Policy);
if (E->getTemplateKWLoc().isValid())
OS << "template ";
OS << E->getFoundDecl()->getName();
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 0297f9c..2035fa7 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -65,7 +65,7 @@ namespace {
/// Visit a nested-name-specifier that occurs within an expression
/// or statement.
- virtual void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) = 0;
+ virtual void VisitNestedNameSpecifier(NestedNameSpecifier NNS) = 0;
/// Visit a template name that occurs within an expression or
/// statement.
@@ -167,10 +167,10 @@ namespace {
ID.AddPointer(II);
}
- void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override {
+ void VisitNestedNameSpecifier(NestedNameSpecifier NNS) override {
if (Canonical)
- NNS = Context.getCanonicalNestedNameSpecifier(NNS);
- ID.AddPointer(NNS);
+ NNS = NNS.getCanonical();
+ NNS.Profile(ID);
}
void VisitTemplateName(TemplateName Name) override {
@@ -226,11 +226,10 @@ namespace {
void VisitTemplateName(TemplateName Name) override {
Hash.AddTemplateName(Name);
}
- void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override {
- ID.AddBoolean(NNS);
- if (NNS) {
+ void VisitNestedNameSpecifier(NestedNameSpecifier NNS) override {
+ ID.AddBoolean(bool(NNS));
+ if (NNS)
Hash.AddNestedNameSpecifier(NNS);
- }
}
};
}
@@ -441,37 +440,37 @@ public:
#define GEN_CLANG_CLAUSE_CLASS
#define CLAUSE_CLASS(Enum, Str, Class) void Visit##Class(const Class *C);
#include "llvm/Frontend/OpenMP/OMP.inc"
- void VistOMPClauseWithPreInit(const OMPClauseWithPreInit *C);
- void VistOMPClauseWithPostUpdate(const OMPClauseWithPostUpdate *C);
+ void VisitOMPClauseWithPreInit(const OMPClauseWithPreInit *C);
+ void VisitOMPClauseWithPostUpdate(const OMPClauseWithPostUpdate *C);
};
-void OMPClauseProfiler::VistOMPClauseWithPreInit(
+void OMPClauseProfiler::VisitOMPClauseWithPreInit(
const OMPClauseWithPreInit *C) {
if (auto *S = C->getPreInitStmt())
Profiler->VisitStmt(S);
}
-void OMPClauseProfiler::VistOMPClauseWithPostUpdate(
+void OMPClauseProfiler::VisitOMPClauseWithPostUpdate(
const OMPClauseWithPostUpdate *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (auto *E = C->getPostUpdateExpr())
Profiler->VisitStmt(E);
}
void OMPClauseProfiler::VisitOMPIfClause(const OMPIfClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (C->getCondition())
Profiler->VisitStmt(C->getCondition());
}
void OMPClauseProfiler::VisitOMPFinalClause(const OMPFinalClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (C->getCondition())
Profiler->VisitStmt(C->getCondition());
}
void OMPClauseProfiler::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (C->getNumThreads())
Profiler->VisitStmt(C->getNumThreads());
}
@@ -527,13 +526,13 @@ void OMPClauseProfiler::VisitOMPDetachClause(const OMPDetachClause *C) {
}
void OMPClauseProfiler::VisitOMPNovariantsClause(const OMPNovariantsClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (C->getCondition())
Profiler->VisitStmt(C->getCondition());
}
void OMPClauseProfiler::VisitOMPNocontextClause(const OMPNocontextClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (C->getCondition())
Profiler->VisitStmt(C->getCondition());
}
@@ -569,7 +568,7 @@ void OMPClauseProfiler::VisitOMPMessageClause(const OMPMessageClause *C) {
}
void OMPClauseProfiler::VisitOMPScheduleClause(const OMPScheduleClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (auto *S = C->getChunkSize())
Profiler->VisitStmt(S);
}
@@ -647,7 +646,7 @@ void OMPClauseProfiler::VisitOMPDestroyClause(const OMPDestroyClause *C) {
}
void OMPClauseProfiler::VisitOMPFilterClause(const OMPFilterClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (C->getThreadID())
Profiler->VisitStmt(C->getThreadID());
}
@@ -670,7 +669,7 @@ void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
void
OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) {
VisitOMPClauseList(C);
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
for (auto *E : C->private_copies()) {
if (E)
Profiler->VisitStmt(E);
@@ -683,7 +682,7 @@ OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) {
void
OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) {
VisitOMPClauseList(C);
- VistOMPClauseWithPostUpdate(C);
+ VisitOMPClauseWithPostUpdate(C);
for (auto *E : C->source_exprs()) {
if (E)
Profiler->VisitStmt(E);
@@ -706,7 +705,7 @@ void OMPClauseProfiler::VisitOMPReductionClause(
C->getQualifierLoc().getNestedNameSpecifier());
Profiler->VisitName(C->getNameInfo().getName());
VisitOMPClauseList(C);
- VistOMPClauseWithPostUpdate(C);
+ VisitOMPClauseWithPostUpdate(C);
for (auto *E : C->privates()) {
if (E)
Profiler->VisitStmt(E);
@@ -744,7 +743,7 @@ void OMPClauseProfiler::VisitOMPTaskReductionClause(
C->getQualifierLoc().getNestedNameSpecifier());
Profiler->VisitName(C->getNameInfo().getName());
VisitOMPClauseList(C);
- VistOMPClauseWithPostUpdate(C);
+ VisitOMPClauseWithPostUpdate(C);
for (auto *E : C->privates()) {
if (E)
Profiler->VisitStmt(E);
@@ -768,7 +767,7 @@ void OMPClauseProfiler::VisitOMPInReductionClause(
C->getQualifierLoc().getNestedNameSpecifier());
Profiler->VisitName(C->getNameInfo().getName());
VisitOMPClauseList(C);
- VistOMPClauseWithPostUpdate(C);
+ VisitOMPClauseWithPostUpdate(C);
for (auto *E : C->privates()) {
if (E)
Profiler->VisitStmt(E);
@@ -792,7 +791,7 @@ void OMPClauseProfiler::VisitOMPInReductionClause(
}
void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) {
VisitOMPClauseList(C);
- VistOMPClauseWithPostUpdate(C);
+ VisitOMPClauseWithPostUpdate(C);
for (auto *E : C->privates()) {
if (E)
Profiler->VisitStmt(E);
@@ -874,25 +873,25 @@ void OMPClauseProfiler::VisitOMPAllocateClause(const OMPAllocateClause *C) {
}
void OMPClauseProfiler::VisitOMPNumTeamsClause(const OMPNumTeamsClause *C) {
VisitOMPClauseList(C);
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
}
void OMPClauseProfiler::VisitOMPThreadLimitClause(
const OMPThreadLimitClause *C) {
VisitOMPClauseList(C);
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
}
void OMPClauseProfiler::VisitOMPPriorityClause(const OMPPriorityClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (C->getPriority())
Profiler->VisitStmt(C->getPriority());
}
void OMPClauseProfiler::VisitOMPGrainsizeClause(const OMPGrainsizeClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (C->getGrainsize())
Profiler->VisitStmt(C->getGrainsize());
}
void OMPClauseProfiler::VisitOMPNumTasksClause(const OMPNumTasksClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (C->getNumTasks())
Profiler->VisitStmt(C->getNumTasks());
}
@@ -953,7 +952,7 @@ void OMPClauseProfiler::VisitOMPOrderClause(const OMPOrderClause *C) {}
void OMPClauseProfiler::VisitOMPBindClause(const OMPBindClause *C) {}
void OMPClauseProfiler::VisitOMPXDynCGroupMemClause(
const OMPXDynCGroupMemClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (Expr *Size = C->getSize())
Profiler->VisitStmt(Size);
}
@@ -1230,7 +1229,7 @@ void StmtProfiler::VisitOMPDistributeDirective(
void OMPClauseProfiler::VisitOMPDistScheduleClause(
const OMPDistScheduleClause *C) {
- VistOMPClauseWithPreInit(C);
+ VisitOMPClauseWithPreInit(C);
if (auto *S = C->getChunkSize())
Profiler->VisitStmt(S);
}
@@ -2749,6 +2748,14 @@ void OpenACCClauseProfiler::VisitGangClause(const OpenACCGangClause &Clause) {
void OpenACCClauseProfiler::VisitReductionClause(
const OpenACCReductionClause &Clause) {
VisitClauseWithVarList(Clause);
+
+ for (auto &Recipe : Clause.getRecipes()) {
+ Profiler.VisitDecl(Recipe.RecipeDecl);
+ // 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 *));
+ }
}
void OpenACCClauseProfiler::VisitBindClause(const OpenACCBindClause &Clause) {
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index 7a0f740..76f96fb 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->getDecl()->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
@@ -596,6 +596,29 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out,
// TemplateArgumentLoc Implementation
//===----------------------------------------------------------------------===//
+TemplateArgumentLoc::TemplateArgumentLoc(ASTContext &Ctx,
+ const TemplateArgument &Argument,
+ SourceLocation TemplateKWLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateNameLoc,
+ SourceLocation EllipsisLoc)
+ : Argument(Argument),
+ LocInfo(Ctx, TemplateKWLoc, QualifierLoc, TemplateNameLoc, EllipsisLoc) {
+ assert(Argument.getKind() == TemplateArgument::Template ||
+ Argument.getKind() == TemplateArgument::TemplateExpansion);
+ assert(QualifierLoc.getNestedNameSpecifier() ==
+ Argument.getAsTemplateOrTemplatePattern().getQualifier());
+}
+
+NestedNameSpecifierLoc TemplateArgumentLoc::getTemplateQualifierLoc() const {
+ if (Argument.getKind() != TemplateArgument::Template &&
+ Argument.getKind() != TemplateArgument::TemplateExpansion)
+ return NestedNameSpecifierLoc();
+ return NestedNameSpecifierLoc(
+ Argument.getAsTemplateOrTemplatePattern().getQualifier(),
+ LocInfo.getTemplate()->QualifierLocData);
+}
+
SourceRange TemplateArgumentLoc::getSourceRange() const {
switch (Argument.getKind()) {
case TemplateArgument::Expression:
@@ -702,10 +725,11 @@ const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
}
clang::TemplateArgumentLocInfo::TemplateArgumentLocInfo(
- ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc,
- SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc) {
+ ASTContext &Ctx, SourceLocation TemplateKWLoc,
+ NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc,
+ SourceLocation EllipsisLoc) {
TemplateTemplateArgLocInfo *Template = new (Ctx) TemplateTemplateArgLocInfo;
- Template->Qualifier = QualifierLoc.getNestedNameSpecifier();
+ Template->TemplateKwLoc = TemplateKWLoc;
Template->QualifierLocData = QualifierLoc.getOpaqueData();
Template->TemplateNameLoc = TemplateNameLoc;
Template->EllipsisLoc = EllipsisLoc;
diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp
index 5b7abc4..f2cb15d 100644
--- a/clang/lib/AST/TemplateName.cpp
+++ b/clang/lib/AST/TemplateName.cpp
@@ -293,6 +293,21 @@ DependentTemplateName *TemplateName::getAsDependentTemplateName() const {
return Storage.dyn_cast<DependentTemplateName *>();
}
+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(), N->hasTemplateKeyword()};
+ if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName())
+ return {N->getQualifier(), N->hasTemplateKeyword()};
+ if (Cur->getAsSubstTemplateTemplateParm() ||
+ Cur->getAsSubstTemplateTemplateParmPack())
+ break;
+ }
+ return {std::nullopt, false};
+}
+
UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const {
if (Decl *D = Storage.dyn_cast<Decl *>())
if (UsingShadowDecl *USD = dyn_cast<UsingShadowDecl>(D))
@@ -303,24 +318,21 @@ UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const {
}
DependentTemplateStorage::DependentTemplateStorage(
- NestedNameSpecifier *Qualifier, IdentifierOrOverloadedOperator Name,
+ NestedNameSpecifier Qualifier, IdentifierOrOverloadedOperator Name,
bool HasTemplateKeyword)
: Qualifier(Qualifier, HasTemplateKeyword), Name(Name) {
- assert((!Qualifier || Qualifier->isDependent()) &&
+ assert((!Qualifier || Qualifier.isDependent()) &&
"Qualifier must be dependent");
}
TemplateNameDependence DependentTemplateStorage::getDependence() const {
- auto D = TemplateNameDependence::DependentInstantiation;
- if (NestedNameSpecifier *Qualifier = getQualifier())
- D |= toTemplateNameDependence(Qualifier->getDependence());
- return D;
+ return toTemplateNameDependence(getQualifier().getDependence()) |
+ TemplateNameDependence::DependentInstantiation;
}
void DependentTemplateStorage::print(raw_ostream &OS,
const PrintingPolicy &Policy) const {
- if (NestedNameSpecifier *NNS = getQualifier())
- NNS->print(OS, Policy);
+ getQualifier().print(OS, Policy);
if (hasTemplateKeyword())
OS << "template ";
@@ -363,16 +375,13 @@ TemplateNameDependence TemplateName::getDependence() const {
case NameKind::QualifiedTemplate: {
QualifiedTemplateName *S = getAsQualifiedTemplateName();
TemplateNameDependence D = S->getUnderlyingTemplate().getDependence();
- if (NestedNameSpecifier *NNS = S->getQualifier())
- D |= toTemplateNameDependence(NNS->getDependence());
+ D |= toTemplateNameDependence(S->getQualifier().getDependence());
return D;
}
case NameKind::DependentTemplate: {
DependentTemplateName *S = getAsDependentTemplateName();
- auto D = TemplateNameDependence::DependentInstantiation;
- if (NestedNameSpecifier *Qualifier = S->getQualifier())
- D |= toTemplateNameDependence(Qualifier->getDependence());
- return D;
+ return toTemplateNameDependence(S->getQualifier().getDependence()) |
+ TemplateNameDependence::DependentInstantiation;
}
case NameKind::SubstTemplateTemplateParm: {
auto *S = getAsSubstTemplateTemplateParm();
@@ -434,18 +443,26 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
Template = cast<TemplateDecl>(Template->getCanonicalDecl());
if (handleAnonymousTTP(Template, OS))
return;
- if (Qual == Qualified::None)
- OS << *Template;
- else
- Template->printQualifiedName(OS, Policy);
+ 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;
+ Template->printQualifiedName(OS, NestedNamePolicy);
+ }
} else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
if (Policy.PrintAsCanonical) {
QTN->getUnderlyingTemplate().print(OS, Policy, Qual);
return;
}
- if (NestedNameSpecifier *NNS = QTN->getQualifier();
- Qual != Qualified::None && NNS)
- NNS->print(OS, Policy);
+ if (Qual != Qualified::None)
+ QTN->getQualifier().print(OS, Policy);
if (QTN->hasTemplateKeyword())
OS << "template ";
@@ -458,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 6b524cf..9dca5cf 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1037,35 +1037,34 @@ void clang::TextNodeDumper::dumpTemplateSpecializationKind(
}
}
-void clang::TextNodeDumper::dumpNestedNameSpecifier(const NestedNameSpecifier *NNS) {
+void clang::TextNodeDumper::dumpNestedNameSpecifier(NestedNameSpecifier NNS) {
if (!NNS)
return;
AddChild([=] {
OS << "NestedNameSpecifier";
- switch (NNS->getKind()) {
- case NestedNameSpecifier::Identifier:
- OS << " Identifier";
- OS << " '" << NNS->getAsIdentifier()->getName() << "'";
- break;
- case NestedNameSpecifier::Namespace:
+ switch (NNS.getKind()) {
+ case NestedNameSpecifier::Kind::Namespace: {
+ auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix();
OS << " "; // "Namespace" is printed as the decl kind.
- dumpBareDeclRef(NNS->getAsNamespace());
+ dumpBareDeclRef(Namespace);
+ dumpNestedNameSpecifier(Prefix);
break;
- case NestedNameSpecifier::TypeSpec:
+ }
+ case NestedNameSpecifier::Kind::Type:
OS << " TypeSpec";
- dumpType(QualType(NNS->getAsType(), 0));
+ dumpType(QualType(NNS.getAsType(), 0));
break;
- case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Kind::Global:
OS << " Global";
break;
- case NestedNameSpecifier::Super:
+ case NestedNameSpecifier::Kind::MicrosoftSuper:
OS << " Super";
break;
+ case NestedNameSpecifier::Kind::Null:
+ llvm_unreachable("unexpected null nested name specifier");
}
-
- dumpNestedNameSpecifier(NNS->getPrefix());
});
}
@@ -1401,8 +1400,8 @@ static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
if (!First)
OS << " -> ";
- const auto *RD =
- cast<CXXRecordDecl>(Base->getType()->castAs<RecordType>()->getDecl());
+ const auto *RD = cast<CXXRecordDecl>(
+ Base->getType()->castAsCanonical<RecordType>()->getOriginalDecl());
if (Base->isVirtual())
OS << "virtual ";
@@ -2112,19 +2111,32 @@ void TextNodeDumper::VisitFunctionProtoType(const FunctionProtoType *T) {
}
void TextNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
+ if (ElaboratedTypeKeyword K = T->getKeyword();
+ K != ElaboratedTypeKeyword::None)
+ OS << ' ' << TypeWithKeyword::getKeywordName(K);
+ dumpNestedNameSpecifier(T->getQualifier());
dumpDeclRef(T->getDecl());
}
void TextNodeDumper::VisitUsingType(const UsingType *T) {
- dumpDeclRef(T->getFoundDecl());
- if (!T->typeMatchesDecl())
- OS << " divergent";
+ if (ElaboratedTypeKeyword K = T->getKeyword();
+ K != ElaboratedTypeKeyword::None)
+ OS << ' ' << TypeWithKeyword::getKeywordName(K);
+ dumpNestedNameSpecifier(T->getQualifier());
+ dumpDeclRef(T->getDecl());
+ dumpType(T->desugar());
}
void TextNodeDumper::VisitTypedefType(const TypedefType *T) {
+ if (ElaboratedTypeKeyword K = T->getKeyword();
+ K != ElaboratedTypeKeyword::None)
+ OS << ' ' << TypeWithKeyword::getKeywordName(K);
+ dumpNestedNameSpecifier(T->getQualifier());
dumpDeclRef(T->getDecl());
- if (!T->typeMatchesDecl())
+ if (!T->typeMatchesDecl()) {
OS << " divergent";
+ dumpType(T->desugar());
+ }
}
void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) {
@@ -2138,7 +2150,17 @@ void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) {
}
void TextNodeDumper::VisitTagType(const TagType *T) {
- dumpDeclRef(T->getDecl());
+ if (T->isCanonicalUnqualified())
+ OS << " canonical";
+ if (T->isTagOwned())
+ OS << " owns_tag";
+ if (T->isInjected())
+ OS << " injected";
+ if (ElaboratedTypeKeyword K = T->getKeyword();
+ K != ElaboratedTypeKeyword::None)
+ OS << ' ' << TypeWithKeyword::getKeywordName(K);
+ dumpNestedNameSpecifier(T->getQualifier());
+ dumpDeclRef(T->getOriginalDecl());
}
void TextNodeDumper::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
@@ -2182,12 +2204,15 @@ void TextNodeDumper::VisitTemplateSpecializationType(
const TemplateSpecializationType *T) {
if (T->isTypeAlias())
OS << " alias";
+ if (ElaboratedTypeKeyword K = T->getKeyword();
+ K != ElaboratedTypeKeyword::None)
+ OS << ' ' << TypeWithKeyword::getKeywordName(K);
dumpTemplateName(T->getTemplateName(), "name");
}
void TextNodeDumper::VisitInjectedClassNameType(
const InjectedClassNameType *T) {
- dumpDeclRef(T->getDecl());
+ dumpDeclRef(T->getOriginalDecl());
}
void TextNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
@@ -2778,8 +2803,7 @@ void TextNodeDumper::VisitTemplateTemplateParmDecl(
void TextNodeDumper::VisitUsingDecl(const UsingDecl *D) {
OS << ' ';
- if (D->getQualifier())
- D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ D->getQualifier().print(OS, D->getASTContext().getPrintingPolicy());
OS << D->getDeclName();
dumpNestedNameSpecifier(D->getQualifier());
}
@@ -2792,16 +2816,14 @@ void TextNodeDumper::VisitUsingEnumDecl(const UsingEnumDecl *D) {
void TextNodeDumper::VisitUnresolvedUsingTypenameDecl(
const UnresolvedUsingTypenameDecl *D) {
OS << ' ';
- if (D->getQualifier())
- D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ D->getQualifier().print(OS, D->getASTContext().getPrintingPolicy());
OS << D->getDeclName();
}
void TextNodeDumper::VisitUnresolvedUsingValueDecl(
const UnresolvedUsingValueDecl *D) {
OS << ' ';
- if (D->getQualifier())
- D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ D->getQualifier().print(OS, D->getASTContext().getPrintingPolicy());
OS << D->getDeclName();
dumpType(D->getType());
}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 141edc8..3432810 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -109,12 +109,12 @@ bool Qualifiers::isTargetAddressSpaceSupersetOf(LangAS A, LangAS B,
const IdentifierInfo *QualType::getBaseTypeIdentifier() const {
const Type *ty = getTypePtr();
NamedDecl *ND = nullptr;
+ if (const auto *DNT = ty->getAs<DependentNameType>())
+ return DNT->getIdentifier();
if (ty->isPointerOrReferenceType())
return ty->getPointeeType().getBaseTypeIdentifier();
- else if (ty->isRecordType())
- ND = ty->castAs<RecordType>()->getDecl();
- else if (ty->isEnumeralType())
- ND = ty->castAs<EnumType>()->getDecl();
+ 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())
@@ -670,61 +670,59 @@ const Type *Type::getUnqualifiedDesugaredType() const {
}
bool Type::isClassType() const {
- if (const auto *RT = getAs<RecordType>())
- return RT->getDecl()->isClass();
+ if (const auto *RT = getAsCanonical<RecordType>())
+ return RT->getOriginalDecl()->isClass();
return false;
}
bool Type::isStructureType() const {
- if (const auto *RT = getAs<RecordType>())
- return RT->getDecl()->isStruct();
+ 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->getDecl();
+ 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->getDecl()->hasAttr<ObjCBoxableAttr>();
+ if (const auto *RD = getAsRecordDecl())
+ return RD->hasAttr<ObjCBoxableAttr>();
return false;
}
bool Type::isInterfaceType() const {
- if (const auto *RT = getAs<RecordType>())
- return RT->getDecl()->isInterface();
+ 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->getDecl();
- 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>())
- return RT->getDecl()->isUnion();
+ 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;
}
@@ -735,8 +733,8 @@ bool Type::isComplexIntegerType() const {
}
bool Type::isScopedEnumeralType() const {
- if (const auto *ET = getAs<EnumType>())
- return ET->getDecl()->isScoped();
+ if (const auto *ET = getAsCanonical<EnumType>())
+ return ET->getOriginalDecl()->isScoped();
return false;
}
@@ -770,13 +768,13 @@ QualType Type::getPointeeType() const {
const RecordType *Type::getAsStructureType() const {
// If this is directly a structure type, return it.
if (const auto *RT = dyn_cast<RecordType>(this)) {
- if (RT->getDecl()->isStruct())
+ if (RT->getOriginalDecl()->isStruct())
return RT;
}
// If the canonical form of this type isn't the right kind, reject it.
if (const auto *RT = dyn_cast<RecordType>(CanonicalType)) {
- if (!RT->getDecl()->isStruct())
+ if (!RT->getOriginalDecl()->isStruct())
return nullptr;
// If this is a typedef for a structure type, strip the typedef off without
@@ -789,13 +787,13 @@ const RecordType *Type::getAsStructureType() const {
const RecordType *Type::getAsUnionType() const {
// If this is directly a union type, return it.
if (const auto *RT = dyn_cast<RecordType>(this)) {
- if (RT->getDecl()->isUnion())
+ if (RT->getOriginalDecl()->isUnion())
return RT;
}
// If the canonical form of this type isn't the right kind, reject it.
if (const auto *RT = dyn_cast<RecordType>(CanonicalType)) {
- if (!RT->getDecl()->isUnion())
+ if (!RT->getOriginalDecl()->isUnion())
return nullptr;
// If this is a typedef for a union type, strip the typedef off without
@@ -1272,9 +1270,6 @@ public:
TRIVIAL_TYPE_CLASS(Record)
TRIVIAL_TYPE_CLASS(Enum)
- // FIXME: Non-trivial to implement, but important for C++
- SUGARED_TYPE_CLASS(Elaborated)
-
QualType VisitAttributedType(const AttributedType *T) {
QualType modifiedType = recurse(T->getModifiedType());
if (modifiedType.isNull())
@@ -1626,7 +1621,7 @@ bool QualType::UseExcessPrecision(const ASTContext &Ctx) {
switch (BT->getKind()) {
case BuiltinType::Kind::Float16: {
const TargetInfo &TI = Ctx.getTargetInfo();
- if (TI.hasFloat16Type() && !TI.hasLegalHalfType() &&
+ if (TI.hasFloat16Type() && !TI.hasFastHalfType() &&
Ctx.getLangOpts().getFloat16ExcessPrecision() !=
Ctx.getLangOpts().ExcessPrecisionKind::FPP_None)
return true;
@@ -1913,34 +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->getDecl());
-
- return nullptr;
-}
-
-CXXRecordDecl *Type::getAsCXXRecordDecl() const {
- return dyn_cast_or_null<CXXRecordDecl>(getAsTagDecl());
-}
-
-RecordDecl *Type::getAsRecordDecl() const {
- return dyn_cast_or_null<RecordDecl>(getAsTagDecl());
-}
-
-TagDecl *Type::getAsTagDecl() const {
- if (const auto *TT = getAs<TagType>())
- return TT->getDecl();
- if (const auto *Injected = getAs<InjectedClassNameType>())
- return Injected->getDecl();
-
- return nullptr;
+ return PointeeType->getAsCXXRecordDecl();
}
const TemplateSpecializationType *
@@ -1951,6 +1925,33 @@ Type::getAsNonAliasTemplateSpecializationType() const {
return TST;
}
+NestedNameSpecifier Type::getPrefix() const {
+ switch (getTypeClass()) {
+ case Type::DependentName:
+ return cast<DependentNameType>(this)->getQualifier();
+ case Type::TemplateSpecialization:
+ return cast<TemplateSpecializationType>(this)
+ ->getTemplateName()
+ .getQualifier();
+ case Type::DependentTemplateSpecialization:
+ return cast<DependentTemplateSpecializationType>(this)
+ ->getDependentTemplateName()
+ .getQualifier();
+ case Type::Enum:
+ case Type::Record:
+ case Type::InjectedClassName:
+ return cast<TagType>(this)->getQualifier();
+ case Type::Typedef:
+ return cast<TypedefType>(this)->getQualifier();
+ case Type::UnresolvedUsing:
+ return cast<UnresolvedUsingType>(this)->getQualifier();
+ case Type::Using:
+ return cast<UsingType>(this)->getQualifier();
+ default:
+ return std::nullopt;
+ }
+}
+
bool Type::hasAttr(attr::Kind AK) const {
const Type *Cur = this;
while (const auto *AT = Cur->getAs<AttributedType>()) {
@@ -1989,10 +1990,6 @@ public:
return Visit(T->getReplacementType());
}
- Type *VisitElaboratedType(const ElaboratedType *T) {
- return Visit(T->getNamedType());
- }
-
Type *VisitPointerType(const PointerType *T) {
return Visit(T->getPointeeType());
}
@@ -2114,7 +2111,7 @@ bool Type::isIntegralType(const ASTContext &Ctx) const {
// Complete enum types are integral in C.
if (!Ctx.getLangOpts().CPlusPlus)
if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
- return ET->getDecl()->isComplete();
+ return IsEnumDeclComplete(ET->getOriginalDecl());
return isBitIntType();
}
@@ -2131,7 +2128,7 @@ bool Type::isIntegralOrUnscopedEnumerationType() const {
bool Type::isUnscopedEnumerationType() const {
if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
- return !ET->getDecl()->isScoped();
+ return !ET->getOriginalDecl()->isScoped();
return false;
}
@@ -2213,11 +2210,12 @@ 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.
- if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped())
- return ET->getDecl()->getIntegerType()->isSignedIntegerType();
+ if (!ED->isComplete() || ED->isScoped())
+ return false;
+ return ED->getIntegerType()->isSignedIntegerType();
}
if (const auto *IT = dyn_cast<BitIntType>(CanonicalType))
@@ -2232,9 +2230,11 @@ bool Type::isSignedIntegerOrEnumerationType() const {
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->isSignedInteger();
- if (const auto *ET = dyn_cast<EnumType>(CanonicalType);
- ET && ET->getDecl()->isComplete())
- return ET->getDecl()->getIntegerType()->isSignedIntegerType();
+ if (const auto *ED = getAsEnumDecl()) {
+ if (!ED->isComplete())
+ return false;
+ return ED->getIntegerType()->isSignedIntegerType();
+ }
if (const auto *IT = dyn_cast<BitIntType>(CanonicalType))
return IT->isSigned();
@@ -2258,11 +2258,12 @@ 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.
- if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped())
- return ET->getDecl()->getIntegerType()->isUnsignedIntegerType();
+ if (!ED->isComplete() || ED->isScoped())
+ return false;
+ return ED->getIntegerType()->isUnsignedIntegerType();
}
if (const auto *IT = dyn_cast<BitIntType>(CanonicalType))
@@ -2277,9 +2278,11 @@ bool Type::isUnsignedIntegerOrEnumerationType() const {
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->isUnsignedInteger();
- if (const auto *ET = dyn_cast<EnumType>(CanonicalType);
- ET && ET->getDecl()->isComplete())
- return ET->getDecl()->getIntegerType()->isUnsignedIntegerType();
+ if (const auto *ED = getAsEnumDecl()) {
+ if (!ED->isComplete())
+ return false;
+ return ED->getIntegerType()->isUnsignedIntegerType();
+ }
if (const auto *IT = dyn_cast<BitIntType>(CanonicalType))
return IT->isUnsigned();
@@ -2328,8 +2331,10 @@ bool Type::isRealType() const {
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::Ibm128;
- if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
- return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
+ if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) {
+ const auto *ED = ET->getOriginalDecl();
+ return !ED->isScoped() && ED->getDefinitionOrSelf()->isComplete();
+ }
return isBitIntType();
}
@@ -2337,24 +2342,24 @@ bool Type::isArithmeticType() const {
if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::Ibm128;
- if (const auto *ET = dyn_cast<EnumType>(CanonicalType))
+ if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) {
// GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2).
// If a body isn't seen by the time we get here, return false.
//
// C++0x: Enumerations are not arithmetic types. For now, just return
// false for scoped enumerations since that will disable any
// unwanted implicit conversions.
- return !ET->getDecl()->isScoped() && ET->getDecl()->isComplete();
+ const auto *ED = ET->getOriginalDecl();
+ return !ED->isScoped() && ED->getDefinitionOrSelf()->isComplete();
+ }
return isa<ComplexType>(CanonicalType) || isBitIntType();
}
bool Type::hasBooleanRepresentation() const {
if (const auto *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isBooleanType();
- if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) {
- return ET->getDecl()->isComplete() &&
- ET->getDecl()->getIntegerType()->isBooleanType();
- }
+ 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();
@@ -2385,7 +2390,7 @@ Type::ScalarTypeKind Type::getScalarTypeKind() const {
} else if (isa<MemberPointerType>(T)) {
return STK_MemberPointer;
} else if (isa<EnumType>(T)) {
- assert(cast<EnumType>(T)->getDecl()->isComplete());
+ assert(T->castAsEnumDecl()->isComplete());
return STK_Integral;
} else if (const auto *CT = dyn_cast<ComplexType>(T)) {
if (CT->getElementType()->isRealFloatingType())
@@ -2409,7 +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->getDecl()))
+ if (const auto *ClassDecl =
+ dyn_cast<CXXRecordDecl>(Record->getOriginalDecl()))
return ClassDecl->isAggregate();
return true;
@@ -2443,7 +2449,7 @@ bool Type::isIncompleteType(NamedDecl **Def) const {
// be completed.
return isVoidType();
case Enum: {
- EnumDecl *EnumD = cast<EnumType>(CanonicalType)->getDecl();
+ auto *EnumD = castAsEnumDecl();
if (Def)
*Def = EnumD;
return !EnumD->isComplete();
@@ -2451,13 +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)->getDecl();
+ auto *Rec = castAsRecordDecl();
if (Def)
*Def = Rec;
return !Rec->isCompleteDefinition();
}
case InjectedClassName: {
- CXXRecordDecl *Rec = cast<InjectedClassNameType>(CanonicalType)->getDecl();
+ auto *Rec = castAsCXXRecordDecl();
if (!Rec->isBeingDefined())
return false;
if (Def)
@@ -2517,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.
@@ -2715,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:
@@ -2739,8 +2750,8 @@ bool QualType::isCXX98PODType(const ASTContext &Context) const {
return true;
case Type::Record:
- if (const auto *ClassDecl =
- dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl()))
+ if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(
+ cast<RecordType>(CanonicalType)->getOriginalDecl()))
return ClassDecl->isPOD();
// C struct/union is POD.
@@ -2773,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
@@ -2781,22 +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->getDecl())) {
- // 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;
}
@@ -2840,15 +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->getDecl())) {
- 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->getDecl()->isNonTrivialToPrimitiveCopy();
+ return !RD->isNonTrivialToPrimitiveCopy();
}
// No other types can match.
return false;
@@ -2870,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;
@@ -2936,9 +2956,9 @@ bool QualType::isWebAssemblyFuncrefType() const {
QualType::PrimitiveDefaultInitializeKind
QualType::isNonTrivialToPrimitiveDefaultInitialize() const {
- if (const auto *RT =
- getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>())
- if (RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize())
+ if (const auto *RD =
+ getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl())
+ if (RD->isNonTrivialToPrimitiveDefaultInitialize())
return PDIK_Struct;
switch (getQualifiers().getObjCLifetime()) {
@@ -2952,9 +2972,9 @@ QualType::isNonTrivialToPrimitiveDefaultInitialize() const {
}
QualType::PrimitiveCopyKind QualType::isNonTrivialToPrimitiveCopy() const {
- if (const auto *RT =
- getTypePtr()->getBaseElementTypeUnsafe()->getAs<RecordType>())
- if (RT->getDecl()->isNonTrivialToPrimitiveCopy())
+ if (const auto *RD =
+ getTypePtr()->getBaseElementTypeUnsafe()->getAsRecordDecl())
+ if (RD->isNonTrivialToPrimitiveCopy())
return PCK_Struct;
Qualifiers Qs = getQualifiers();
@@ -3011,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)
@@ -3022,7 +3042,7 @@ 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->getDecl()))
+ if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD))
return ClassDecl->isLiteral();
return true;
@@ -3075,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->getDecl()))
- if (!ClassDecl->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
@@ -3115,11 +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->getDecl())) {
+ 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())
@@ -3158,18 +3182,20 @@ bool Type::isNothrowT() const {
}
bool Type::isAlignValT() const {
- if (const auto *ET = getAs<EnumType>()) {
- IdentifierInfo *II = ET->getDecl()->getIdentifier();
- if (II && II->isStr("align_val_t") && ET->getDecl()->isInStdNamespace())
+ if (const auto *ET = getAsCanonical<EnumType>()) {
+ const auto *ED = ET->getOriginalDecl();
+ IdentifierInfo *II = ED->getIdentifier();
+ if (II && II->isStr("align_val_t") && ED->isInStdNamespace())
return true;
}
return false;
}
bool Type::isStdByteType() const {
- if (const auto *ET = getAs<EnumType>()) {
- IdentifierInfo *II = ET->getDecl()->getIdentifier();
- if (II && II->isStr("byte") && ET->getDecl()->isInStdNamespace())
+ if (const auto *ET = getAsCanonical<EnumType>()) {
+ const auto *ED = ET->getOriginalDecl();
+ IdentifierInfo *II = ED->getIdentifier();
+ if (II && II->isStr("byte") && ED->isInStdNamespace())
return true;
}
return false;
@@ -3188,7 +3214,6 @@ bool Type::isSpecifierType() const {
case TemplateTypeParm:
case SubstTemplateTypeParm:
case TemplateSpecialization:
- case Elaborated:
case DependentName:
case DependentTemplateSpecialization:
case ObjCInterface:
@@ -3199,8 +3224,7 @@ bool Type::isSpecifierType() const {
}
}
-ElaboratedTypeKeyword
-TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) {
+ElaboratedTypeKeyword KeywordHelpers::getKeywordForTypeSpec(unsigned TypeSpec) {
switch (TypeSpec) {
default:
return ElaboratedTypeKeyword::None;
@@ -3219,7 +3243,7 @@ TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) {
}
}
-TagTypeKind TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) {
+TagTypeKind KeywordHelpers::getTagTypeKindForTypeSpec(unsigned TypeSpec) {
switch (TypeSpec) {
case TST_class:
return TagTypeKind::Class;
@@ -3237,7 +3261,7 @@ TagTypeKind TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) {
}
ElaboratedTypeKeyword
-TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) {
+KeywordHelpers::getKeywordForTagTypeKind(TagTypeKind Kind) {
switch (Kind) {
case TagTypeKind::Class:
return ElaboratedTypeKeyword::Class;
@@ -3254,7 +3278,7 @@ TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) {
}
TagTypeKind
-TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) {
+KeywordHelpers::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) {
switch (Keyword) {
case ElaboratedTypeKeyword::Class:
return TagTypeKind::Class;
@@ -3273,7 +3297,7 @@ TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) {
llvm_unreachable("Unknown elaborated type keyword.");
}
-bool TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) {
+bool KeywordHelpers::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) {
switch (Keyword) {
case ElaboratedTypeKeyword::None:
case ElaboratedTypeKeyword::Typename:
@@ -3288,7 +3312,7 @@ bool TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) {
llvm_unreachable("Unknown elaborated type keyword.");
}
-StringRef TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) {
+StringRef KeywordHelpers::getKeywordName(ElaboratedTypeKeyword Keyword) {
switch (Keyword) {
case ElaboratedTypeKeyword::None:
return {};
@@ -3338,13 +3362,21 @@ void DependentTemplateSpecializationType::Profile(
bool Type::isElaboratedTypeSpecifier() const {
ElaboratedTypeKeyword Keyword;
- if (const auto *Elab = dyn_cast<ElaboratedType>(this))
- Keyword = Elab->getKeyword();
+ if (const auto *TST = dyn_cast<TemplateSpecializationType>(this))
+ Keyword = TST->getKeyword();
else if (const auto *DepName = dyn_cast<DependentNameType>(this))
Keyword = DepName->getKeyword();
else if (const auto *DepTST =
dyn_cast<DependentTemplateSpecializationType>(this))
Keyword = DepTST->getKeyword();
+ else if (const auto *T = dyn_cast<TagType>(this))
+ Keyword = T->getKeyword();
+ else if (const auto *T = dyn_cast<TypedefType>(this))
+ Keyword = T->getKeyword();
+ else if (const auto *T = dyn_cast<UnresolvedUsingType>(this))
+ Keyword = T->getKeyword();
+ else if (const auto *T = dyn_cast<UsingType>(this))
+ Keyword = T->getKeyword();
else
return false;
@@ -3677,6 +3709,16 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params,
FunctionTypeBits.HasExtraBitfields = false;
}
+ // Propagate any extra attribute information.
+ if (epi.requiresFunctionProtoTypeExtraAttributeInfo()) {
+ auto &ExtraAttrInfo = *getTrailingObjects<FunctionTypeExtraAttributeInfo>();
+ ExtraAttrInfo.CFISalt = epi.ExtraAttributeInfo.CFISalt;
+
+ // Also set the bit in FunctionTypeExtraBitfields.
+ auto &ExtraBits = *getTrailingObjects<FunctionTypeExtraBitfields>();
+ ExtraBits.HasExtraAttributeInfo = true;
+ }
+
if (epi.requiresFunctionProtoTypeArmAttributes()) {
auto &ArmTypeAttrs = *getTrailingObjects<FunctionTypeArmAttributes>();
ArmTypeAttrs = FunctionTypeArmAttributes();
@@ -3894,7 +3936,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
// This is followed by the ext info:
// int
// Finally we have a trailing return type flag (bool)
- // combined with AArch64 SME Attributes, to save space:
+ // combined with AArch64 SME Attributes and extra attribute info, to save
+ // space:
// int
// combined with any FunctionEffects
//
@@ -3929,6 +3972,7 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
}
epi.ExtInfo.Profile(ID);
+ epi.ExtraAttributeInfo.Profile(ID);
unsigned EffectCount = epi.FunctionEffects.size();
bool HasConds = !epi.FunctionEffects.Conditions.empty();
@@ -4011,34 +4055,53 @@ StringRef CountAttributedType::getAttributeName(bool WithMacroPrefix) const {
#undef ENUMERATE_ATTRS
}
-TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D,
- QualType UnderlyingType, bool HasTypeDifferentFromDecl)
- : Type(tc, UnderlyingType.getCanonicalType(),
- toSemanticDependence(UnderlyingType->getDependence())),
+TypedefType::TypedefType(TypeClass TC, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const TypedefNameDecl *D, QualType UnderlyingType,
+ bool HasTypeDifferentFromDecl)
+ : TypeWithKeyword(
+ Keyword, TC, UnderlyingType.getCanonicalType(),
+ toSemanticDependence(UnderlyingType->getDependence()) |
+ (Qualifier
+ ? toTypeDependence(Qualifier.getDependence() &
+ ~NestedNameSpecifierDependence::Dependent)
+ : TypeDependence{})),
Decl(const_cast<TypedefNameDecl *>(D)) {
- TypedefBits.hasTypeDifferentFromDecl = HasTypeDifferentFromDecl;
- if (!typeMatchesDecl())
- *getTrailingObjects() = UnderlyingType;
+ if ((TypedefBits.hasQualifier = !!Qualifier))
+ *getTrailingObjects<NestedNameSpecifier>() = Qualifier;
+ if ((TypedefBits.hasTypeDifferentFromDecl = HasTypeDifferentFromDecl))
+ *getTrailingObjects<QualType>() = UnderlyingType;
}
QualType TypedefType::desugar() const {
- return typeMatchesDecl() ? Decl->getUnderlyingType() : *getTrailingObjects();
-}
-
-UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying,
- QualType Canon)
- : Type(Using, Canon, toSemanticDependence(Canon->getDependence())),
- Found(const_cast<UsingShadowDecl *>(Found)) {
- UsingBits.hasTypeDifferentFromDecl = !Underlying.isNull();
- if (!typeMatchesDecl())
- *getTrailingObjects() = Underlying;
-}
-
-QualType UsingType::getUnderlyingType() const {
- return typeMatchesDecl()
- ? QualType(
- cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(), 0)
- : *getTrailingObjects();
+ return typeMatchesDecl() ? Decl->getUnderlyingType()
+ : *getTrailingObjects<QualType>();
+}
+
+UnresolvedUsingType::UnresolvedUsingType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const UnresolvedUsingTypenameDecl *D,
+ const Type *CanonicalType)
+ : TypeWithKeyword(
+ Keyword, UnresolvedUsing, QualType(CanonicalType, 0),
+ TypeDependence::DependentInstantiation |
+ (Qualifier
+ ? toTypeDependence(Qualifier.getDependence() &
+ ~NestedNameSpecifierDependence::Dependent)
+ : TypeDependence{})),
+ Decl(const_cast<UnresolvedUsingTypenameDecl *>(D)) {
+ if ((UnresolvedUsingBits.hasQualifier = !!Qualifier))
+ *getTrailingObjects<NestedNameSpecifier>() = Qualifier;
+}
+
+UsingType::UsingType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier, const UsingShadowDecl *D,
+ QualType UnderlyingType)
+ : TypeWithKeyword(Keyword, Using, UnderlyingType.getCanonicalType(),
+ toSemanticDependence(UnderlyingType->getDependence())),
+ D(const_cast<UsingShadowDecl *>(D)), UnderlyingType(UnderlyingType) {
+ if ((UsingBits.hasQualifier = !!Qualifier))
+ *getTrailingObjects() = Qualifier;
}
QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); }
@@ -4212,24 +4275,79 @@ UnaryTransformType::UnaryTransformType(QualType BaseType,
: Type(UnaryTransform, CanonicalType, BaseType->getDependence()),
BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) {}
-TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
- : Type(TC, can,
- D->isDependentType() ? TypeDependence::DependentInstantiation
- : TypeDependence::None),
- decl(const_cast<TagDecl *>(D)) {}
-
-static TagDecl *getInterestingTagDecl(TagDecl *decl) {
- for (auto *I : decl->redecls()) {
- if (I->isCompleteDefinition() || I->isBeingDefined())
- return I;
+TagType::TagType(TypeClass TC, ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier, const TagDecl *Tag,
+ bool OwnsTag, bool ISInjected, const Type *CanonicalType)
+ : TypeWithKeyword(
+ Keyword, TC, QualType(CanonicalType, 0),
+ (Tag->isDependentType() ? TypeDependence::DependentInstantiation
+ : TypeDependence::None) |
+ (Qualifier
+ ? toTypeDependence(Qualifier.getDependence() &
+ ~NestedNameSpecifierDependence::Dependent)
+ : TypeDependence{})),
+ decl(const_cast<TagDecl *>(Tag)) {
+ if ((TagTypeBits.HasQualifier = !!Qualifier))
+ getTrailingQualifier() = Qualifier;
+ TagTypeBits.OwnsTag = !!OwnsTag;
+ TagTypeBits.IsInjected = ISInjected;
+}
+
+void *TagType::getTrailingPointer() const {
+ switch (getTypeClass()) {
+ case Type::Enum:
+ return const_cast<EnumType *>(cast<EnumType>(this) + 1);
+ case Type::Record:
+ return const_cast<RecordType *>(cast<RecordType>(this) + 1);
+ case Type::InjectedClassName:
+ return const_cast<InjectedClassNameType *>(
+ cast<InjectedClassNameType>(this) + 1);
+ default:
+ llvm_unreachable("unexpected type class");
}
- // If there's no definition (not even in progress), return what we have.
- return decl;
}
-TagDecl *TagType::getDecl() const { return getInterestingTagDecl(decl); }
+NestedNameSpecifier &TagType::getTrailingQualifier() const {
+ assert(TagTypeBits.HasQualifier);
+ return *reinterpret_cast<NestedNameSpecifier *>(llvm::alignAddr(
+ getTrailingPointer(), llvm::Align::Of<NestedNameSpecifier *>()));
+}
-bool TagType::isBeingDefined() const { return getDecl()->isBeingDefined(); }
+NestedNameSpecifier TagType::getQualifier() const {
+ return TagTypeBits.HasQualifier ? getTrailingQualifier() : std::nullopt;
+}
+
+ClassTemplateDecl *TagType::getTemplateDecl() const {
+ auto *Decl = dyn_cast<CXXRecordDecl>(decl);
+ if (!Decl)
+ return nullptr;
+ if (auto *RD = dyn_cast<ClassTemplateSpecializationDecl>(Decl))
+ return RD->getSpecializedTemplate();
+ return Decl->getDescribedClassTemplate();
+}
+
+TemplateName TagType::getTemplateName(const ASTContext &Ctx) const {
+ auto *TD = getTemplateDecl();
+ if (!TD)
+ return TemplateName();
+ if (isCanonicalUnqualified())
+ return TemplateName(TD);
+ return Ctx.getQualifiedTemplateName(getQualifier(), /*TemplateKeyword=*/false,
+ TemplateName(TD));
+}
+
+ArrayRef<TemplateArgument>
+TagType::getTemplateArgs(const ASTContext &Ctx) const {
+ auto *Decl = dyn_cast<CXXRecordDecl>(decl);
+ if (!Decl)
+ return {};
+
+ if (auto *RD = dyn_cast<ClassTemplateSpecializationDecl>(Decl))
+ return RD->getTemplateArgs().asArray();
+ if (ClassTemplateDecl *TD = Decl->getDescribedClassTemplate())
+ return TD->getTemplateParameters()->getInjectedTemplateArgs(Ctx);
+ return {};
+}
bool RecordType::hasConstFields() const {
std::vector<const RecordType *> RecordTypeList;
@@ -4237,13 +4355,15 @@ bool RecordType::hasConstFields() const {
unsigned NextToCheckIndex = 0;
while (RecordTypeList.size() > NextToCheckIndex) {
- for (FieldDecl *FD :
- RecordTypeList[NextToCheckIndex]->getDecl()->fields()) {
+ for (FieldDecl *FD : RecordTypeList[NextToCheckIndex]
+ ->getOriginalDecl()
+ ->getDefinitionOrSelf()
+ ->fields()) {
QualType FieldTy = FD->getType();
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);
}
@@ -4253,6 +4373,13 @@ bool RecordType::hasConstFields() const {
return false;
}
+InjectedClassNameType::InjectedClassNameType(ElaboratedTypeKeyword Keyword,
+ NestedNameSpecifier Qualifier,
+ const TagDecl *TD, bool IsInjected,
+ const Type *CanonicalType)
+ : TagType(TypeClass::InjectedClassName, Keyword, Qualifier, TD,
+ /*OwnsTag=*/false, IsInjected, CanonicalType) {}
+
AttributedType::AttributedType(QualType canon, const Attr *attr,
QualType modified, QualType equivalent)
: AttributedType(canon, attr->getKind(), attr, modified, equivalent) {}
@@ -4340,10 +4467,6 @@ bool AttributedType::isCallingConv() const {
llvm_unreachable("invalid attr kind");
}
-CXXRecordDecl *InjectedClassNameType::getDecl() const {
- return cast<CXXRecordDecl>(getInterestingTagDecl(Decl));
-}
-
IdentifierInfo *TemplateTypeParmType::getIdentifier() const {
return isCanonicalUnqualified() ? nullptr : getDecl()->getIdentifier();
}
@@ -4393,17 +4516,45 @@ void SubstTemplateTypeParmType::Profile(llvm::FoldingSetNodeID &ID,
ID.AddBoolean(Final);
}
+SubstPackType::SubstPackType(TypeClass Derived, QualType Canon,
+ const TemplateArgument &ArgPack)
+ : Type(Derived, Canon,
+ TypeDependence::DependentInstantiation |
+ TypeDependence::UnexpandedPack),
+ Arguments(ArgPack.pack_begin()) {
+ assert(llvm::all_of(
+ ArgPack.pack_elements(),
+ [](auto &P) { return P.getKind() == TemplateArgument::Type; }) &&
+ "non-type argument to SubstPackType?");
+ SubstPackTypeBits.NumArgs = ArgPack.pack_size();
+}
+
+TemplateArgument SubstPackType::getArgumentPack() const {
+ return TemplateArgument(llvm::ArrayRef(Arguments, getNumArgs()));
+}
+
+void SubstPackType::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getArgumentPack());
+}
+
+void SubstPackType::Profile(llvm::FoldingSetNodeID &ID,
+ const TemplateArgument &ArgPack) {
+ ID.AddInteger(ArgPack.pack_size());
+ for (const auto &P : ArgPack.pack_elements())
+ ID.AddPointer(P.getAsType().getAsOpaquePtr());
+}
+
SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType(
QualType Canon, Decl *AssociatedDecl, unsigned Index, bool Final,
const TemplateArgument &ArgPack)
- : Type(SubstTemplateTypeParmPack, Canon,
- TypeDependence::DependentInstantiation |
- TypeDependence::UnexpandedPack),
- Arguments(ArgPack.pack_begin()),
+ : SubstPackType(SubstTemplateTypeParmPack, Canon, ArgPack),
AssociatedDeclAndFinal(AssociatedDecl, Final) {
- SubstTemplateTypeParmPackTypeBits.Index = Index;
- SubstTemplateTypeParmPackTypeBits.NumArgs = ArgPack.pack_size();
assert(AssociatedDecl != nullptr);
+
+ SubstPackTypeBits.SubstTemplTypeParmPackIndex = Index;
+ assert(getNumArgs() == ArgPack.pack_size() &&
+ "Parent bitfields in SubstPackType were overwritten."
+ "Check NumSubstPackTypeBits.");
}
Decl *SubstTemplateTypeParmPackType::getAssociatedDecl() const {
@@ -4423,10 +4574,6 @@ IdentifierInfo *SubstTemplateTypeParmPackType::getIdentifier() const {
return getReplacedParameter()->getIdentifier();
}
-TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const {
- return TemplateArgument(llvm::ArrayRef(Arguments, getNumArgs()));
-}
-
void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getAssociatedDecl(), getIndex(), getFinal(), getArgumentPack());
}
@@ -4438,11 +4585,13 @@ void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID,
ID.AddPointer(AssociatedDecl);
ID.AddInteger(Index);
ID.AddBoolean(Final);
- ID.AddInteger(ArgPack.pack_size());
- for (const auto &P : ArgPack.pack_elements())
- ID.AddPointer(P.getAsType().getAsOpaquePtr());
+ SubstPackType::Profile(ID, ArgPack);
}
+SubstBuiltinTemplatePackType::SubstBuiltinTemplatePackType(
+ QualType Canon, const TemplateArgument &ArgPack)
+ : SubstPackType(SubstBuiltinTemplatePack, Canon, ArgPack) {}
+
bool TemplateSpecializationType::anyDependentTemplateArguments(
const TemplateArgumentListInfo &Args,
ArrayRef<TemplateArgument> Converted) {
@@ -4466,17 +4615,28 @@ bool TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
return false;
}
+static TypeDependence
+getTemplateSpecializationTypeDependence(QualType Underlying, TemplateName T) {
+ TypeDependence D = Underlying.isNull()
+ ? TypeDependence::DependentInstantiation
+ : toSemanticDependence(Underlying->getDependence());
+ D |= toTypeDependence(T.getDependence()) & TypeDependence::UnexpandedPack;
+ if (isPackProducingBuiltinTemplateName(T)) {
+ if (Underlying.isNull()) // Dependent, will produce a pack on substitution.
+ D |= TypeDependence::UnexpandedPack;
+ else
+ D |= (Underlying->getDependence() & TypeDependence::UnexpandedPack);
+ }
+ return D;
+}
+
TemplateSpecializationType::TemplateSpecializationType(
- TemplateName T, bool IsAlias, ArrayRef<TemplateArgument> Args,
- QualType Underlying)
- : Type(TemplateSpecialization,
- Underlying.isNull() ? QualType(this, 0)
- : Underlying.getCanonicalType(),
- (Underlying.isNull()
- ? TypeDependence::DependentInstantiation
- : toSemanticDependence(Underlying->getDependence())) |
- (toTypeDependence(T.getDependence()) &
- TypeDependence::UnexpandedPack)),
+ ElaboratedTypeKeyword Keyword, TemplateName T, bool IsAlias,
+ ArrayRef<TemplateArgument> Args, QualType Underlying)
+ : TypeWithKeyword(Keyword, TemplateSpecialization,
+ Underlying.isNull() ? QualType(this, 0)
+ : Underlying.getCanonicalType(),
+ getTemplateSpecializationTypeDependence(Underlying, T)),
Template(T) {
TemplateSpecializationTypeBits.NumArgs = Args.size();
TemplateSpecializationTypeBits.TypeAlias = IsAlias;
@@ -4522,6 +4682,12 @@ QualType TemplateSpecializationType::getAliasedType() const {
return *reinterpret_cast<const QualType *>(template_arguments().end());
}
+bool clang::TemplateSpecializationType::isSugared() const {
+ return !isDependentType() || isCurrentInstantiation() || isTypeAlias() ||
+ (isPackProducingBuiltinTemplateName(Template) &&
+ isa<SubstBuiltinTemplatePackType>(*getCanonicalTypeInternal()));
+}
+
void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Ctx) {
Profile(ID, Template, template_arguments(),
@@ -4699,7 +4865,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
case Type::Record:
case Type::Enum: {
- const TagDecl *Tag = cast<TagType>(T)->getDecl();
+ const TagDecl *Tag =
+ cast<TagType>(T)->getOriginalDecl()->getDefinitionOrSelf();
// C++ [basic.link]p8:
// - it is a class or enumeration type that is named (or has a name
@@ -4726,12 +4893,9 @@ static CachedProperties computeCachedProperties(const Type *T) {
case Type::MemberPointer: {
const auto *MPT = cast<MemberPointerType>(T);
CachedProperties Cls = [&] {
- if (auto *RD = MPT->getMostRecentCXXRecordDecl())
- return Cache::get(QualType(RD->getTypeForDecl(), 0));
- if (const Type *T = MPT->getQualifier()->getAsType())
- return Cache::get(T);
- // Treat as a dependent type.
- return CachedProperties(Linkage::External, false);
+ if (MPT->isSugared())
+ MPT = cast<MemberPointerType>(MPT->getCanonicalTypeInternal());
+ return Cache::get(MPT->getQualifier().getAsType());
}();
return merge(Cls, Cache::get(MPT->getPointeeType()));
}
@@ -4811,7 +4975,8 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
case Type::Record:
case Type::Enum:
- return getDeclLinkageAndVisibility(cast<TagType>(T)->getDecl());
+ return getDeclLinkageAndVisibility(
+ cast<TagType>(T)->getOriginalDecl()->getDefinitionOrSelf());
case Type::Complex:
return computeTypeLinkageInfo(cast<ComplexType>(T)->getElementType());
@@ -4827,8 +4992,8 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
LinkageInfo LV;
if (auto *D = MPT->getMostRecentCXXRecordDecl()) {
LV.merge(getDeclLinkageAndVisibility(D));
- } else if (auto *Ty = MPT->getQualifier()->getAsType()) {
- LV.merge(computeTypeLinkageInfo(Ty));
+ } else {
+ LV.merge(computeTypeLinkageInfo(MPT->getQualifier().getAsType()));
}
LV.merge(computeTypeLinkageInfo(MPT->getPointeeType()));
return LV;
@@ -4938,6 +5103,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
case Type::UnaryTransform:
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
+ case Type::SubstBuiltinTemplatePack:
case Type::DependentName:
case Type::DependentTemplateSpecialization:
case Type::Auto:
@@ -5014,7 +5180,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
llvm_unreachable("unknown builtin type");
case Type::Record: {
- const RecordDecl *RD = cast<RecordType>(type)->getDecl();
+ const RecordDecl *RD = cast<RecordType>(type)->getOriginalDecl();
// For template specializations, look only at primary template attributes.
// This is a consistent regardless of whether the instantiation is known.
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
@@ -5201,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;
@@ -5211,15 +5377,19 @@ 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>())
- return RT->getDecl()->hasAttr<CUDADeviceBuiltinSurfaceTypeAttr>();
+ if (const auto *RT = getAsCanonical<RecordType>())
+ return RT->getOriginalDecl()
+ ->getMostRecentDecl()
+ ->hasAttr<CUDADeviceBuiltinSurfaceTypeAttr>();
return false;
}
/// Check if the specified type is the CUDA device builtin texture type.
bool Type::isCUDADeviceBuiltinTextureType() const {
- if (const auto *RT = getAs<RecordType>())
- return RT->getDecl()->hasAttr<CUDADeviceBuiltinTextureTypeAttr>();
+ if (const auto *RT = getAsCanonical<RecordType>())
+ return RT->getOriginalDecl()
+ ->getMostRecentDecl()
+ ->hasAttr<CUDADeviceBuiltinTextureTypeAttr>();
return false;
}
@@ -5246,6 +5416,15 @@ bool Type::isHLSLResourceRecord() const {
return HLSLAttributedResourceType::findHandleTypeOnResource(this) != nullptr;
}
+bool Type::isHLSLResourceRecordArray() const {
+ const Type *Ty = getUnqualifiedDesugaredType();
+ if (!Ty->isArrayType())
+ return false;
+ while (isa<ConstantArrayType>(Ty))
+ Ty = Ty->getArrayElementTypeNoTypeQual();
+ return Ty->isHLSLResourceRecord();
+}
+
bool Type::isHLSLIntangibleType() const {
const Type *Ty = getUnqualifiedDesugaredType();
@@ -5282,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->getDecl();
+ 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())
@@ -5301,16 +5479,16 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
bool MemberPointerType::isSugared() const {
CXXRecordDecl *D1 = getMostRecentCXXRecordDecl(),
- *D2 = getQualifier()->getAsRecordDecl();
+ *D2 = getQualifier().getAsRecordDecl();
assert(!D1 == !D2);
return D1 != D2 && D1->getCanonicalDecl() != D2->getCanonicalDecl();
}
void MemberPointerType::Profile(llvm::FoldingSetNodeID &ID, QualType Pointee,
- const NestedNameSpecifier *Qualifier,
+ const NestedNameSpecifier Qualifier,
const CXXRecordDecl *Cls) {
ID.AddPointer(Pointee.getAsOpaquePtr());
- ID.AddPointer(Qualifier);
+ Qualifier.Profile(ID);
if (Cls)
ID.AddPointer(Cls->getCanonicalDecl());
}
@@ -5318,14 +5496,14 @@ void MemberPointerType::Profile(llvm::FoldingSetNodeID &ID, QualType Pointee,
CXXRecordDecl *MemberPointerType::getCXXRecordDecl() const {
return dyn_cast<MemberPointerType>(getCanonicalTypeInternal())
->getQualifier()
- ->getAsRecordDecl();
+ .getAsRecordDecl();
}
CXXRecordDecl *MemberPointerType::getMostRecentCXXRecordDecl() const {
auto *RD = getCXXRecordDecl();
if (!RD)
return nullptr;
- return RD->getMostRecentNonInjectedDecl();
+ return RD->getMostRecentDecl();
}
void clang::FixedPointValueToString(SmallVectorImpl<char> &Str,
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index 5c45c59..3e9597f 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -195,15 +195,6 @@ SourceLocation TypeLoc::getBeginLoc() const {
TypeLoc LeftMost = Cur;
while (true) {
switch (Cur.getTypeLocClass()) {
- case Elaborated:
- if (Cur.getLocalSourceRange().getBegin().isValid()) {
- LeftMost = Cur;
- break;
- }
- Cur = Cur.getNextTypeLoc();
- if (Cur.isNull())
- break;
- continue;
case FunctionProto:
if (Cur.castAs<FunctionProtoTypeLoc>().getTypePtr()
->hasTrailingReturn()) {
@@ -275,7 +266,6 @@ SourceLocation TypeLoc::getEndLoc() const {
Last = Cur;
break;
case Qualified:
- case Elaborated:
break;
}
Cur = Cur.getNextTypeLoc();
@@ -313,9 +303,8 @@ bool TypeSpecTypeLoc::isKind(const TypeLoc &TL) {
}
bool TagTypeLoc::isDefinition() const {
- TagDecl *D = getDecl();
- return D->isCompleteDefinition() &&
- (D->getIdentifier() == nullptr || D->getLocation() == getNameLoc());
+ return getTypePtr()->isTagOwned() &&
+ getOriginalDecl()->isCompleteDefinition();
}
// Reimplemented to account for GNU/C++ extension
@@ -482,6 +471,134 @@ TypeLoc TypeLoc::findExplicitQualifierLoc() const {
return {};
}
+NestedNameSpecifierLoc TypeLoc::getPrefix() const {
+ switch (getTypeLocClass()) {
+ case TypeLoc::DependentName:
+ return castAs<DependentNameTypeLoc>().getQualifierLoc();
+ case TypeLoc::TemplateSpecialization:
+ return castAs<TemplateSpecializationTypeLoc>().getQualifierLoc();
+ case TypeLoc::DependentTemplateSpecialization:
+ return castAs<DependentTemplateSpecializationTypeLoc>().getQualifierLoc();
+ case TypeLoc::DeducedTemplateSpecialization:
+ return castAs<DeducedTemplateSpecializationTypeLoc>().getQualifierLoc();
+ case TypeLoc::Enum:
+ case TypeLoc::Record:
+ case TypeLoc::InjectedClassName:
+ return castAs<TagTypeLoc>().getQualifierLoc();
+ case TypeLoc::Typedef:
+ return castAs<TypedefTypeLoc>().getQualifierLoc();
+ case TypeLoc::UnresolvedUsing:
+ return castAs<UnresolvedUsingTypeLoc>().getQualifierLoc();
+ case TypeLoc::Using:
+ return castAs<UsingTypeLoc>().getQualifierLoc();
+ default:
+ return NestedNameSpecifierLoc();
+ }
+}
+
+SourceLocation TypeLoc::getNonPrefixBeginLoc() const {
+ switch (getTypeLocClass()) {
+ case TypeLoc::TemplateSpecialization: {
+ auto TL = castAs<TemplateSpecializationTypeLoc>();
+ SourceLocation Loc = TL.getTemplateKeywordLoc();
+ if (!Loc.isValid())
+ Loc = TL.getTemplateNameLoc();
+ return Loc;
+ }
+ case TypeLoc::DependentTemplateSpecialization: {
+ auto TL = castAs<DependentTemplateSpecializationTypeLoc>();
+ SourceLocation Loc = TL.getTemplateKeywordLoc();
+ if (!Loc.isValid())
+ Loc = TL.getTemplateNameLoc();
+ return Loc;
+ }
+ case TypeLoc::DeducedTemplateSpecialization: {
+ auto TL = castAs<DeducedTemplateSpecializationTypeLoc>();
+ SourceLocation Loc = TL.getTemplateKeywordLoc();
+ if (!Loc.isValid())
+ Loc = TL.getTemplateNameLoc();
+ return Loc;
+ }
+ case TypeLoc::DependentName:
+ return castAs<DependentNameTypeLoc>().getNameLoc();
+ case TypeLoc::Enum:
+ case TypeLoc::Record:
+ case TypeLoc::InjectedClassName:
+ return castAs<TagTypeLoc>().getNameLoc();
+ case TypeLoc::Typedef:
+ return castAs<TypedefTypeLoc>().getNameLoc();
+ case TypeLoc::UnresolvedUsing:
+ return castAs<UnresolvedUsingTypeLoc>().getNameLoc();
+ case TypeLoc::Using:
+ return castAs<UsingTypeLoc>().getNameLoc();
+ default:
+ return getBeginLoc();
+ }
+}
+
+SourceLocation TypeLoc::getNonElaboratedBeginLoc() const {
+ // For elaborated types (e.g. `struct a::A`) we want the portion after the
+ // `struct` but including the namespace qualifier, `a::`.
+ switch (getTypeLocClass()) {
+ case TypeLoc::Qualified:
+ return castAs<QualifiedTypeLoc>()
+ .getUnqualifiedLoc()
+ .getNonElaboratedBeginLoc();
+ case TypeLoc::TemplateSpecialization: {
+ auto T = castAs<TemplateSpecializationTypeLoc>();
+ if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc())
+ return QualifierLoc.getBeginLoc();
+ return T.getTemplateNameLoc();
+ }
+ case TypeLoc::DependentTemplateSpecialization: {
+ auto T = castAs<DependentTemplateSpecializationTypeLoc>();
+ if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc())
+ return QualifierLoc.getBeginLoc();
+ return T.getTemplateNameLoc();
+ }
+ case TypeLoc::DeducedTemplateSpecialization: {
+ auto T = castAs<DeducedTemplateSpecializationTypeLoc>();
+ if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc())
+ return QualifierLoc.getBeginLoc();
+ return T.getTemplateNameLoc();
+ }
+ case TypeLoc::DependentName: {
+ auto T = castAs<DependentNameTypeLoc>();
+ if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc())
+ return QualifierLoc.getBeginLoc();
+ return T.getNameLoc();
+ }
+ case TypeLoc::Enum:
+ case TypeLoc::Record:
+ case TypeLoc::InjectedClassName: {
+ auto T = castAs<TagTypeLoc>();
+ if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc())
+ return QualifierLoc.getBeginLoc();
+ return T.getNameLoc();
+ }
+ case TypeLoc::Typedef: {
+ auto T = castAs<TypedefTypeLoc>();
+ if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc())
+ return QualifierLoc.getBeginLoc();
+ return T.getNameLoc();
+ }
+ case TypeLoc::UnresolvedUsing: {
+ auto T = castAs<UnresolvedUsingTypeLoc>();
+ if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc())
+ return QualifierLoc.getBeginLoc();
+ return T.getNameLoc();
+ }
+ case TypeLoc::Using: {
+ auto T = castAs<UsingTypeLoc>();
+ if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc())
+ return QualifierLoc.getBeginLoc();
+ return T.getNameLoc();
+ }
+ default:
+ return getBeginLoc();
+ }
+}
+
void ObjCTypeParamTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
setNameLoc(Loc);
@@ -555,9 +672,9 @@ static void initializeElaboratedKeyword(TL T, SourceLocation Loc) {
: SourceLocation());
}
-static NestedNameSpecifierLoc
-initializeQualifier(ASTContext &Context, NestedNameSpecifier *Qualifier,
- SourceLocation Loc) {
+static NestedNameSpecifierLoc initializeQualifier(ASTContext &Context,
+ NestedNameSpecifier Qualifier,
+ SourceLocation Loc) {
if (!Qualifier)
return NestedNameSpecifierLoc();
NestedNameSpecifierLocBuilder Builder;
@@ -565,15 +682,6 @@ initializeQualifier(ASTContext &Context, NestedNameSpecifier *Qualifier,
return Builder.getWithLocInContext(Context);
}
-void ElaboratedTypeLoc::initializeLocal(ASTContext &Context,
- SourceLocation Loc) {
- if (isEmpty())
- return;
- initializeElaboratedKeyword(*this, Loc);
- setQualifierLoc(
- initializeQualifier(Context, getTypePtr()->getQualifier(), Loc));
-}
-
void DependentNameTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
initializeElaboratedKeyword(*this, Loc);
@@ -596,6 +704,76 @@ DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
Context, getTypePtr()->template_arguments(), getArgInfos(), Loc);
}
+void TemplateSpecializationTypeLoc::set(SourceLocation ElaboratedKeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKeywordLoc,
+ SourceLocation NameLoc,
+ SourceLocation LAngleLoc,
+ SourceLocation RAngleLoc) {
+ TemplateSpecializationLocInfo &Data = *getLocalData();
+
+ Data.ElaboratedKWLoc = ElaboratedKeywordLoc;
+ SourceLocation BeginLoc = ElaboratedKeywordLoc;
+
+ getLocalData()->QualifierData = QualifierLoc.getOpaqueData();
+
+ assert(QualifierLoc.getNestedNameSpecifier() ==
+ getTypePtr()->getTemplateName().getQualifier());
+ Data.QualifierData = QualifierLoc ? QualifierLoc.getOpaqueData() : nullptr;
+ if (QualifierLoc && !BeginLoc.isValid())
+ BeginLoc = QualifierLoc.getBeginLoc();
+
+ Data.TemplateKWLoc = TemplateKeywordLoc;
+ if (!BeginLoc.isValid())
+ BeginLoc = TemplateKeywordLoc;
+
+ Data.NameLoc = NameLoc;
+ if (!BeginLoc.isValid())
+ BeginLoc = NameLoc;
+
+ Data.LAngleLoc = LAngleLoc;
+ Data.SR = SourceRange(BeginLoc, RAngleLoc);
+}
+
+void TemplateSpecializationTypeLoc::set(SourceLocation ElaboratedKeywordLoc,
+ NestedNameSpecifierLoc QualifierLoc,
+ SourceLocation TemplateKeywordLoc,
+ SourceLocation NameLoc,
+ const TemplateArgumentListInfo &TAL) {
+ set(ElaboratedKeywordLoc, QualifierLoc, TemplateKeywordLoc, NameLoc,
+ TAL.getLAngleLoc(), TAL.getRAngleLoc());
+ MutableArrayRef<TemplateArgumentLocInfo> ArgInfos = getArgLocInfos();
+ assert(TAL.size() == ArgInfos.size());
+ for (unsigned I = 0, N = TAL.size(); I != N; ++I)
+ ArgInfos[I] = TAL[I].getLocInfo();
+}
+
+void TemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+
+ auto [Qualifier, HasTemplateKeyword] =
+ getTypePtr()->getTemplateName().getQualifierAndTemplateKeyword();
+
+ SourceLocation ElaboratedKeywordLoc =
+ getTypePtr()->getKeyword() != ElaboratedTypeKeyword::None
+ ? Loc
+ : SourceLocation();
+
+ NestedNameSpecifierLoc QualifierLoc;
+ if (Qualifier) {
+ NestedNameSpecifierLocBuilder Builder;
+ Builder.MakeTrivial(Context, Qualifier, Loc);
+ QualifierLoc = Builder.getWithLocInContext(Context);
+ }
+
+ TemplateArgumentListInfo TAL(Loc, Loc);
+ set(ElaboratedKeywordLoc, QualifierLoc,
+ /*TemplateKeywordLoc=*/HasTemplateKeyword ? Loc : SourceLocation(),
+ /*NameLoc=*/Loc, /*LAngleLoc=*/Loc, /*RAngleLoc=*/Loc);
+ initializeArgLocs(Context, getTypePtr()->template_arguments(), getArgInfos(),
+ Loc);
+}
+
void TemplateSpecializationTypeLoc::initializeArgLocs(
ASTContext &Context, ArrayRef<TemplateArgument> Args,
TemplateArgumentLocInfo *ArgInfos, SourceLocation Loc) {
@@ -631,7 +809,7 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(
Builder.MakeTrivial(Context, QTN->getQualifier(), Loc);
ArgInfos[i] = TemplateArgumentLocInfo(
- Context, Builder.getWithLocInContext(Context), Loc,
+ Context, Loc, Builder.getWithLocInContext(Context), Loc,
Args[i].getKind() == TemplateArgument::Template ? SourceLocation()
: Loc);
break;
@@ -680,6 +858,14 @@ void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) {
}
}
+void DeducedTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
+ SourceLocation Loc) {
+ initializeElaboratedKeyword(*this, Loc);
+ setQualifierLoc(initializeQualifier(
+ Context, getTypePtr()->getTemplateName().getQualifier(), Loc));
+ setTemplateNameLoc(Loc);
+}
+
namespace {
class GetContainedAutoTypeLocVisitor :
@@ -693,10 +879,6 @@ namespace {
// Only these types can contain the desired 'auto' type.
- TypeLoc VisitElaboratedTypeLoc(ElaboratedTypeLoc T) {
- return Visit(T.getNamedTypeLoc());
- }
-
TypeLoc VisitQualifiedTypeLoc(QualifiedTypeLoc T) {
return Visit(T.getUnqualifiedLoc());
}
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index deb453f..54ca42d 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -133,7 +133,7 @@ public:
void printAfter(QualType T, raw_ostream &OS);
void AppendScope(DeclContext *DC, raw_ostream &OS,
DeclarationName NameInScope);
- void printTag(TagDecl *T, raw_ostream &OS);
+ void printTagType(const TagType *T, raw_ostream &OS);
void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS);
#define ABSTRACT_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) \
@@ -230,9 +230,9 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::UnaryTransform:
case Type::Record:
case Type::Enum:
- case Type::Elaborated:
case Type::TemplateTypeParm:
case Type::SubstTemplateTypeParmPack:
+ case Type::SubstBuiltinTemplatePack:
case Type::DeducedTemplateSpecialization:
case Type::TemplateSpecialization:
case Type::InjectedClassName:
@@ -504,11 +504,7 @@ void TypePrinter::printMemberPointerBefore(const MemberPointerType *T,
// FIXME: this should include vectors, but vectors use attributes I guess.
if (isa<ArrayType>(T->getPointeeType()))
OS << '(';
-
- PrintingPolicy InnerPolicy(Policy);
- InnerPolicy.IncludeTagDefinition = false;
- T->getQualifier()->print(OS, InnerPolicy);
-
+ T->getQualifier().print(OS, Policy);
OS << "*";
}
@@ -1211,29 +1207,50 @@ void TypePrinter::printTypeSpec(NamedDecl *D, raw_ostream &OS) {
void TypePrinter::printUnresolvedUsingBefore(const UnresolvedUsingType *T,
raw_ostream &OS) {
- printTypeSpec(T->getDecl(), OS);
+ OS << TypeWithKeyword::getKeywordName(T->getKeyword());
+ if (T->getKeyword() != ElaboratedTypeKeyword::None)
+ OS << ' ';
+ auto *D = T->getDecl();
+ if (Policy.FullyQualifiedName || T->isCanonicalUnqualified()) {
+ AppendScope(D->getDeclContext(), OS, D->getDeclName());
+ } else {
+ T->getQualifier().print(OS, Policy);
+ }
+ OS << D->getIdentifier()->getName();
+ spaceBeforePlaceHolder(OS);
}
void TypePrinter::printUnresolvedUsingAfter(const UnresolvedUsingType *T,
raw_ostream &OS) {}
void TypePrinter::printUsingBefore(const UsingType *T, raw_ostream &OS) {
- // After `namespace b { using a::X }`, is the type X within B a::X or b::X?
- //
- // - b::X is more formally correct given the UsingType model
- // - b::X makes sense if "re-exporting" a symbol in a new namespace
- // - a::X makes sense if "importing" a symbol for convenience
- //
- // The "importing" use seems much more common, so we print a::X.
- // This could be a policy option, but the right choice seems to rest more
- // with the intent of the code than the caller.
- printTypeSpec(T->getFoundDecl()->getUnderlyingDecl(), OS);
+ OS << TypeWithKeyword::getKeywordName(T->getKeyword());
+ if (T->getKeyword() != ElaboratedTypeKeyword::None)
+ OS << ' ';
+ auto *D = T->getDecl();
+ if (Policy.FullyQualifiedName) {
+ AppendScope(D->getDeclContext(), OS, D->getDeclName());
+ } else {
+ T->getQualifier().print(OS, Policy);
+ }
+ OS << D->getIdentifier()->getName();
+ spaceBeforePlaceHolder(OS);
}
void TypePrinter::printUsingAfter(const UsingType *T, raw_ostream &OS) {}
void TypePrinter::printTypedefBefore(const TypedefType *T, raw_ostream &OS) {
- printTypeSpec(T->getDecl(), OS);
+ OS << TypeWithKeyword::getKeywordName(T->getKeyword());
+ if (T->getKeyword() != ElaboratedTypeKeyword::None)
+ OS << ' ';
+ auto *D = T->getDecl();
+ if (Policy.FullyQualifiedName) {
+ AppendScope(D->getDeclContext(), OS, D->getDeclName());
+ } else {
+ T->getQualifier().print(OS, Policy);
+ }
+ OS << D->getIdentifier()->getName();
+ spaceBeforePlaceHolder(OS);
}
void TypePrinter::printMacroQualifiedBefore(const MacroQualifiedType *T,
@@ -1354,14 +1371,53 @@ void TypePrinter::printAutoAfter(const AutoType *T, raw_ostream &OS) {
void TypePrinter::printDeducedTemplateSpecializationBefore(
const DeducedTemplateSpecializationType *T, raw_ostream &OS) {
- // If the type has been deduced, print the deduced type.
+ if (ElaboratedTypeKeyword Keyword = T->getKeyword();
+ T->getKeyword() != ElaboratedTypeKeyword::None)
+ OS << KeywordHelpers::getKeywordName(Keyword) << ' ';
+
+ TemplateName Name = T->getTemplateName();
+
+ // If the type has been deduced, print the template arguments, as if this was
+ // printing the deduced type, but including elaboration and template name
+ // qualification.
+ // FIXME: There should probably be a policy which controls this.
+ // We would probably want to do this on diagnostics, but not on -ast-print.
+ ArrayRef<TemplateArgument> Args;
+ TemplateDecl *DeducedTD = nullptr;
if (!T->getDeducedType().isNull()) {
- printBefore(T->getDeducedType(), OS);
- } else {
+ if (const auto *TST =
+ dyn_cast<TemplateSpecializationType>(T->getDeducedType())) {
+ DeducedTD = TST->getTemplateName().getAsTemplateDecl(
+ /*IgnoreDeduced=*/true);
+ Args = TST->template_arguments();
+ } else {
+ // Should only get here for canonical types.
+ const auto *CD = cast<ClassTemplateSpecializationDecl>(
+ cast<RecordType>(T->getDeducedType())->getOriginalDecl());
+ DeducedTD = CD->getSpecializedTemplate();
+ Args = CD->getTemplateArgs().asArray();
+ }
+
+ // FIXME: Workaround for alias template CTAD not producing guides which
+ // include the alias template specialization type.
+ // Purposefully disregard qualification when building this TemplateName;
+ // any qualification we might have, might not make sense in the
+ // context this was deduced.
+ if (!declaresSameEntity(DeducedTD, Name.getAsTemplateDecl(
+ /*IgnoreDeduced=*/true)))
+ Name = TemplateName(DeducedTD);
+ }
+
+ {
IncludeStrongLifetimeRAII Strong(Policy);
- T->getTemplateName().print(OS, Policy);
- spaceBeforePlaceHolder(OS);
+ Name.print(OS, Policy);
}
+ if (DeducedTD) {
+ printTemplateArgumentList(OS, Args, Policy,
+ DeducedTD->getTemplateParameters());
+ }
+
+ spaceBeforePlaceHolder(OS);
}
void TypePrinter::printDeducedTemplateSpecializationAfter(
@@ -1480,30 +1536,37 @@ void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS,
}
}
-void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
- if (Policy.IncludeTagDefinition) {
- PrintingPolicy SubPolicy = Policy;
- SubPolicy.IncludeTagDefinition = false;
- D->print(OS, SubPolicy, Indentation);
+void TypePrinter::printTagType(const TagType *T, raw_ostream &OS) {
+ TagDecl *D = T->getOriginalDecl();
+
+ if (Policy.IncludeTagDefinition && T->isTagOwned()) {
+ D->print(OS, Policy, Indentation);
spaceBeforePlaceHolder(OS);
return;
}
bool HasKindDecoration = false;
- // We don't print tags unless this is an elaborated type.
- // In C, we just assume every RecordType is an elaborated type.
- if (!Policy.SuppressTagKeyword && !D->getTypedefNameForAnonDecl()) {
- HasKindDecoration = true;
- OS << D->getKindName();
- OS << ' ';
+ if (T->isCanonicalUnqualified()) {
+ if (!Policy.SuppressTagKeyword && !D->getTypedefNameForAnonDecl()) {
+ HasKindDecoration = true;
+ OS << D->getKindName();
+ OS << ' ';
+ }
+ } else {
+ OS << TypeWithKeyword::getKeywordName(T->getKeyword());
+ if (T->getKeyword() != ElaboratedTypeKeyword::None)
+ OS << ' ';
}
- // Compute the full nested-name-specifier for this type.
- // In C, this will always be empty except when the type
- // being printed is anonymous within other Record.
- if (!Policy.SuppressScope)
+ if (!Policy.FullyQualifiedName && !T->isCanonicalUnqualified()) {
+ T->getQualifier().print(OS, Policy);
+ } else if (!Policy.SuppressScope) {
+ // Compute the full nested-name-specifier for this type.
+ // In C, this will always be empty except when the type
+ // being printed is anonymous within other Record.
AppendScope(D->getDeclContext(), OS, D->getDeclName());
+ }
if (const IdentifierInfo *II = D->getIdentifier())
OS << II->getName();
@@ -1578,9 +1641,11 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) {
void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) {
// Print the preferred name if we have one for this type.
if (Policy.UsePreferredNames) {
- for (const auto *PNA : T->getDecl()->specific_attrs<PreferredNameAttr>()) {
+ for (const auto *PNA : T->getOriginalDecl()
+ ->getMostRecentDecl()
+ ->specific_attrs<PreferredNameAttr>()) {
if (!declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(),
- T->getDecl()))
+ T->getOriginalDecl()))
continue;
// Find the outermost typedef or alias template.
QualType T = PNA->getTypedefType();
@@ -1594,17 +1659,44 @@ void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) {
}
}
- printTag(T->getDecl(), OS);
+ printTagType(T, OS);
}
void TypePrinter::printRecordAfter(const RecordType *T, raw_ostream &OS) {}
void TypePrinter::printEnumBefore(const EnumType *T, raw_ostream &OS) {
- printTag(T->getDecl(), OS);
+ printTagType(T, OS);
}
void TypePrinter::printEnumAfter(const EnumType *T, raw_ostream &OS) {}
+void TypePrinter::printInjectedClassNameBefore(const InjectedClassNameType *T,
+ raw_ostream &OS) {
+ const ASTContext &Ctx = T->getOriginalDecl()->getASTContext();
+ IncludeStrongLifetimeRAII Strong(Policy);
+ T->getTemplateName(Ctx).print(OS, Policy);
+ if (Policy.PrintInjectedClassNameWithArguments) {
+ auto *Decl = T->getOriginalDecl();
+ // FIXME: Use T->getTemplateArgs(Ctx) when that supports as-written
+ // arguments.
+ if (auto *RD = dyn_cast<ClassTemplateSpecializationDecl>(Decl)) {
+ printTemplateArgumentList(OS, RD->getTemplateArgsAsWritten()->arguments(),
+ Policy,
+ T->getTemplateDecl()->getTemplateParameters());
+ } else {
+ ClassTemplateDecl *TD = Decl->getDescribedClassTemplate();
+ assert(TD);
+ printTemplateArgumentList(
+ OS, TD->getTemplateParameters()->getInjectedTemplateArgs(Ctx), Policy,
+ T->getTemplateDecl()->getTemplateParameters());
+ }
+ }
+ spaceBeforePlaceHolder(OS);
+}
+
+void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T,
+ raw_ostream &OS) {}
+
void TypePrinter::printTemplateTypeParmBefore(const TemplateTypeParmType *T,
raw_ostream &OS) {
TemplateTypeParmDecl *D = T->getDecl();
@@ -1640,6 +1732,15 @@ void TypePrinter::printSubstTemplateTypeParmAfter(
printAfter(T->getReplacementType(), OS);
}
+void TypePrinter::printSubstBuiltinTemplatePackBefore(
+ const SubstBuiltinTemplatePackType *T, raw_ostream &OS) {
+ IncludeStrongLifetimeRAII Strong(Policy);
+ OS << "type-pack";
+}
+
+void TypePrinter::printSubstBuiltinTemplatePackAfter(
+ const SubstBuiltinTemplatePackType *T, raw_ostream &OS) {}
+
void TypePrinter::printSubstTemplateTypeParmPackBefore(
const SubstTemplateTypeParmPackType *T,
raw_ostream &OS) {
@@ -1671,6 +1772,10 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
raw_ostream &OS, bool FullyQualify) {
IncludeStrongLifetimeRAII Strong(Policy);
+ if (ElaboratedTypeKeyword K = T->getKeyword();
+ K != ElaboratedTypeKeyword::None)
+ OS << TypeWithKeyword::getKeywordName(K) << ' ';
+
TemplateDecl *TD =
T->getTemplateName().getAsTemplateDecl(/*IgnoreDeduced=*/true);
// FIXME: Null TD never exercised in test suite.
@@ -1680,7 +1785,10 @@ void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
OS << TD->getName();
} else {
- T->getTemplateName().print(OS, Policy, TemplateName::Qualified::None);
+ T->getTemplateName().print(OS, Policy,
+ !Policy.SuppressScope
+ ? TemplateName::Qualified::AsWritten
+ : TemplateName::Qualified::None);
}
DefaultTemplateArgsPolicyRAII TemplateArgs(Policy);
@@ -1699,77 +1807,6 @@ void TypePrinter::printTemplateSpecializationAfter(
const TemplateSpecializationType *T,
raw_ostream &OS) {}
-void TypePrinter::printInjectedClassNameBefore(const InjectedClassNameType *T,
- raw_ostream &OS) {
- if (Policy.PrintInjectedClassNameWithArguments)
- return printTemplateSpecializationBefore(T->getInjectedTST(), OS);
-
- IncludeStrongLifetimeRAII Strong(Policy);
- T->getTemplateName().print(OS, Policy);
- spaceBeforePlaceHolder(OS);
-}
-
-void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T,
- raw_ostream &OS) {}
-
-void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
- raw_ostream &OS) {
- if (Policy.IncludeTagDefinition && T->getOwnedTagDecl()) {
- TagDecl *OwnedTagDecl = T->getOwnedTagDecl();
- assert(OwnedTagDecl->getTypeForDecl() == T->getNamedType().getTypePtr() &&
- "OwnedTagDecl expected to be a declaration for the type");
- PrintingPolicy SubPolicy = Policy;
- SubPolicy.IncludeTagDefinition = false;
- OwnedTagDecl->print(OS, SubPolicy, Indentation);
- spaceBeforePlaceHolder(OS);
- return;
- }
-
- if (Policy.SuppressElaboration) {
- printBefore(T->getNamedType(), OS);
- return;
- }
-
- // The tag definition will take care of these.
- if (!Policy.IncludeTagDefinition)
- {
- OS << TypeWithKeyword::getKeywordName(T->getKeyword());
- if (T->getKeyword() != ElaboratedTypeKeyword::None)
- OS << " ";
- NestedNameSpecifier *Qualifier = T->getQualifier();
- if (!Policy.SuppressTagKeyword && Policy.SuppressScope &&
- !Policy.SuppressUnwrittenScope) {
- bool OldTagKeyword = Policy.SuppressTagKeyword;
- bool OldSupressScope = Policy.SuppressScope;
- Policy.SuppressTagKeyword = true;
- Policy.SuppressScope = false;
- printBefore(T->getNamedType(), OS);
- Policy.SuppressTagKeyword = OldTagKeyword;
- Policy.SuppressScope = OldSupressScope;
- return;
- }
- if (Qualifier)
- Qualifier->print(OS, Policy);
- }
-
- ElaboratedTypePolicyRAII PolicyRAII(Policy);
- printBefore(T->getNamedType(), OS);
-}
-
-void TypePrinter::printElaboratedAfter(const ElaboratedType *T,
- raw_ostream &OS) {
- if (Policy.IncludeTagDefinition && T->getOwnedTagDecl())
- return;
-
- if (Policy.SuppressElaboration) {
- printAfter(T->getNamedType(), OS);
- return;
- }
-
- ElaboratedTypePolicyRAII PolicyRAII(Policy);
- printAfter(T->getNamedType(), OS);
-}
-
void TypePrinter::printParenBefore(const ParenType *T, raw_ostream &OS) {
if (!HasEmptyPlaceHolder && !isa<FunctionType>(T->getInnerType())) {
printBefore(T->getInnerType(), OS);
@@ -1791,9 +1828,7 @@ void TypePrinter::printDependentNameBefore(const DependentNameType *T,
OS << TypeWithKeyword::getKeywordName(T->getKeyword());
if (T->getKeyword() != ElaboratedTypeKeyword::None)
OS << " ";
-
- T->getQualifier()->print(OS, Policy);
-
+ T->getQualifier().print(OS, Policy);
OS << T->getIdentifier()->getName();
spaceBeforePlaceHolder(OS);
}
@@ -2129,6 +2164,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::ExtVectorType:
OS << "ext_vector_type";
break;
+ case attr::CFISalt:
+ OS << "cfi_salt(\"" << cast<CFISaltAttr>(T->getAttr())->getSalt() << "\")";
+ break;
}
OS << "))";
}
@@ -2344,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 de01184..89b58b5 100644
--- a/clang/lib/AST/VTTBuilder.cpp
+++ b/clang/lib/AST/VTTBuilder.cpp
@@ -63,9 +63,7 @@ void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) {
if (I.isVirtual())
continue;
- const auto *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
-
+ const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
CharUnits BaseOffset = Base.getBaseOffset() +
Layout.getBaseClassOffset(BaseDecl);
@@ -89,8 +87,7 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base,
return;
for (const auto &I : RD->bases()) {
- const auto *BaseDecl =
- cast<CXXRecordDecl>(I.getType()->castAs<RecordType>()->getDecl());
+ const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();
// Itanium C++ ABI 2.6.2:
// Secondary virtual pointers are present for all bases with either
@@ -153,8 +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>()->getDecl());
+ const auto *BaseDecl = I.getType()->castAsCXXRecordDecl();
// Check if this is a virtual base.
if (I.isVirtual()) {
diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp
index 0001745..6cec526 100644
--- a/clang/lib/AST/VTableBuilder.cpp
+++ b/clang/lib/AST/VTableBuilder.cpp
@@ -313,10 +313,12 @@ ComputeReturnAdjustmentBaseOffset(ASTContext &Context,
}
const CXXRecordDecl *DerivedRD =
- cast<CXXRecordDecl>(cast<RecordType>(CanDerivedReturnType)->getDecl());
+ cast<CXXRecordDecl>(
+ cast<RecordType>(CanDerivedReturnType)->getOriginalDecl())
+ ->getDefinitionOrSelf();
- const CXXRecordDecl *BaseRD =
- cast<CXXRecordDecl>(cast<RecordType>(CanBaseReturnType)->getDecl());
+ const CXXRecordDecl *BaseRD = cast<CXXRecordDecl>(
+ cast<RecordType>(CanBaseReturnType)->getOriginalDecl());
return ComputeBaseOffset(Context, BaseRD, DerivedRD);
}