aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/AST')
-rw-r--r--clang/lib/AST/APValue.cpp18
-rw-r--r--clang/lib/AST/ASTConcept.cpp72
-rw-r--r--clang/lib/AST/ASTContext.cpp1683
-rw-r--r--clang/lib/AST/ASTDiagnostic.cpp39
-rw-r--r--clang/lib/AST/ASTDumper.cpp55
-rw-r--r--clang/lib/AST/ASTImporter.cpp496
-rw-r--r--clang/lib/AST/ASTStructuralEquivalence.cpp159
-rw-r--r--clang/lib/AST/AttrDocTable.cpp2
-rw-r--r--clang/lib/AST/AttrImpl.cpp41
-rw-r--r--clang/lib/AST/CXXInheritance.cpp1
-rw-r--r--clang/lib/AST/Comment.cpp6
-rw-r--r--clang/lib/AST/CommentCommandTraits.cpp8
-rw-r--r--clang/lib/AST/CommentLexer.cpp2
-rw-r--r--clang/lib/AST/CommentParser.cpp31
-rw-r--r--clang/lib/AST/CommentSema.cpp6
-rw-r--r--clang/lib/AST/ComparisonCategories.cpp5
-rw-r--r--clang/lib/AST/ComputeDependence.cpp20
-rw-r--r--clang/lib/AST/Decl.cpp258
-rw-r--r--clang/lib/AST/DeclBase.cpp47
-rw-r--r--clang/lib/AST/DeclCXX.cpp188
-rw-r--r--clang/lib/AST/DeclObjC.cpp100
-rw-r--r--clang/lib/AST/DeclOpenMP.cpp2
-rw-r--r--clang/lib/AST/DeclPrinter.cpp35
-rw-r--r--clang/lib/AST/DeclTemplate.cpp191
-rw-r--r--clang/lib/AST/DeclarationName.cpp12
-rw-r--r--clang/lib/AST/Expr.cpp101
-rw-r--r--clang/lib/AST/ExprCXX.cpp148
-rw-r--r--clang/lib/AST/ExprClassification.cpp10
-rw-r--r--clang/lib/AST/ExprConcepts.cpp77
-rw-r--r--clang/lib/AST/ExprConstant.cpp688
-rw-r--r--clang/lib/AST/ExternalASTSource.cpp6
-rw-r--r--clang/lib/AST/FormatString.cpp134
-rw-r--r--clang/lib/AST/Interp/Boolean.h27
-rw-r--r--clang/lib/AST/Interp/ByteCodeEmitter.cpp135
-rw-r--r--clang/lib/AST/Interp/ByteCodeEmitter.h4
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.cpp1138
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.h171
-rw-r--r--clang/lib/AST/Interp/ByteCodeGenError.h12
-rw-r--r--clang/lib/AST/Interp/ByteCodeStmtGen.cpp203
-rw-r--r--clang/lib/AST/Interp/ByteCodeStmtGen.h16
-rw-r--r--clang/lib/AST/Interp/Context.cpp39
-rw-r--r--clang/lib/AST/Interp/Context.h6
-rw-r--r--clang/lib/AST/Interp/Descriptor.cpp93
-rw-r--r--clang/lib/AST/Interp/Descriptor.h92
-rw-r--r--clang/lib/AST/Interp/Disasm.cpp28
-rw-r--r--clang/lib/AST/Interp/EvalEmitter.cpp29
-rw-r--r--clang/lib/AST/Interp/EvalEmitter.h12
-rw-r--r--clang/lib/AST/Interp/Function.cpp15
-rw-r--r--clang/lib/AST/Interp/Function.h74
-rw-r--r--clang/lib/AST/Interp/Integral.h126
-rw-r--r--clang/lib/AST/Interp/Interp.cpp93
-rw-r--r--clang/lib/AST/Interp/Interp.h547
-rw-r--r--clang/lib/AST/Interp/InterpBlock.h53
-rw-r--r--clang/lib/AST/Interp/InterpFrame.cpp90
-rw-r--r--clang/lib/AST/Interp/InterpFrame.h42
-rw-r--r--clang/lib/AST/Interp/InterpStack.cpp2
-rw-r--r--clang/lib/AST/Interp/InterpStack.h67
-rw-r--r--clang/lib/AST/Interp/InterpState.h3
-rw-r--r--clang/lib/AST/Interp/Opcodes.td118
-rw-r--r--clang/lib/AST/Interp/Pointer.cpp26
-rw-r--r--clang/lib/AST/Interp/Pointer.h49
-rw-r--r--clang/lib/AST/Interp/PrimType.cpp4
-rw-r--r--clang/lib/AST/Interp/PrimType.h14
-rw-r--r--clang/lib/AST/Interp/Program.cpp123
-rw-r--r--clang/lib/AST/Interp/Program.h54
-rw-r--r--clang/lib/AST/Interp/Record.h22
-rw-r--r--clang/lib/AST/Interp/Source.cpp4
-rw-r--r--clang/lib/AST/Interp/Source.h16
-rw-r--r--clang/lib/AST/Interp/State.h5
-rw-r--r--clang/lib/AST/ItaniumCXXABI.cpp17
-rw-r--r--clang/lib/AST/ItaniumMangle.cpp101
-rw-r--r--clang/lib/AST/JSONNodeDumper.cpp40
-rw-r--r--clang/lib/AST/Linkage.h8
-rw-r--r--clang/lib/AST/Mangle.cpp8
-rw-r--r--clang/lib/AST/MicrosoftCXXABI.cpp4
-rw-r--r--clang/lib/AST/MicrosoftMangle.cpp51
-rw-r--r--clang/lib/AST/NSAPI.cpp25
-rw-r--r--clang/lib/AST/NestedNameSpecifier.cpp4
-rw-r--r--clang/lib/AST/ODRDiagsEmitter.cpp2206
-rw-r--r--clang/lib/AST/ODRHash.cpp186
-rw-r--r--clang/lib/AST/OSLog.cpp11
-rw-r--r--clang/lib/AST/OpenMPClause.cpp109
-rw-r--r--clang/lib/AST/ParentMap.cpp4
-rw-r--r--clang/lib/AST/ParentMapContext.cpp23
-rw-r--r--clang/lib/AST/PrintfFormatString.cpp37
-rw-r--r--clang/lib/AST/QualTypeNames.cpp23
-rw-r--r--clang/lib/AST/RecordLayoutBuilder.cpp72
-rw-r--r--clang/lib/AST/ScanfFormatString.cpp8
-rw-r--r--clang/lib/AST/Stmt.cpp11
-rw-r--r--clang/lib/AST/StmtOpenMP.cpp21
-rw-r--r--clang/lib/AST/StmtPrinter.cpp26
-rw-r--r--clang/lib/AST/StmtProfile.cpp28
-rw-r--r--clang/lib/AST/TemplateBase.cpp32
-rw-r--r--clang/lib/AST/TemplateName.cpp65
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp36
-rw-r--r--clang/lib/AST/Type.cpp276
-rw-r--r--clang/lib/AST/TypeLoc.cpp40
-rw-r--r--clang/lib/AST/TypePrinter.cpp294
-rw-r--r--clang/lib/AST/VTableBuilder.cpp5
99 files changed, 9415 insertions, 2549 deletions
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index a22031142c7c..5b0a5e256e41 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -156,10 +156,10 @@ void APValue::LValuePathEntry::Profile(llvm::FoldingSetNodeID &ID) const {
APValue::LValuePathSerializationHelper::LValuePathSerializationHelper(
ArrayRef<LValuePathEntry> Path, QualType ElemTy)
- : ElemTy((const void *)ElemTy.getTypePtrOrNull()), Path(Path) {}
+ : Ty((const void *)ElemTy.getTypePtrOrNull()), Path(Path) {}
QualType APValue::LValuePathSerializationHelper::getType() {
- return QualType::getFromOpaquePtr(ElemTy);
+ return QualType::getFromOpaquePtr(Ty);
}
namespace {
@@ -637,10 +637,10 @@ static bool TryPrintAsStringLiteral(raw_ostream &Out,
return false;
// Nothing we can do about a sequence that is not null-terminated
- if (!Inits.back().getInt().isZero())
+ if (!Inits.back().isInt() || !Inits.back().getInt().isZero())
return false;
- else
- Inits = Inits.drop_back();
+
+ Inits = Inits.drop_back();
llvm::SmallString<40> Buf;
Buf.push_back('"');
@@ -655,6 +655,8 @@ static bool TryPrintAsStringLiteral(raw_ostream &Out,
}
for (auto &Val : Inits) {
+ if (!Val.isInt())
+ return false;
int64_t Char64 = Val.getInt().getExtValue();
if (!isASCII(Char64))
return false; // Bye bye, see you in integers.
@@ -871,7 +873,7 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy,
Out << "...}";
return;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
getArrayInitializedElt(I).printPretty(Out, Policy, ElemTy, Ctx);
}
@@ -982,7 +984,7 @@ bool APValue::hasLValuePath() const {
ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
assert(isLValue() && hasLValuePath() && "Invalid accessor");
const LV &LVal = *((const LV *)(const char *)&Data);
- return llvm::makeArrayRef(LVal.getPath(), LVal.PathLength);
+ return llvm::ArrayRef(LVal.getPath(), LVal.PathLength);
}
unsigned APValue::getLValueCallIndex() const {
@@ -1060,7 +1062,7 @@ ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
assert(isMemberPointer() && "Invalid accessor");
const MemberPointerData &MPD =
*((const MemberPointerData *)(const char *)&Data);
- return llvm::makeArrayRef(MPD.getPath(), MPD.PathLength);
+ return llvm::ArrayRef(MPD.getPath(), MPD.PathLength);
}
void APValue::MakeLValue() {
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index 18582782888c..8f2d94572184 100644
--- a/clang/lib/AST/ASTConcept.cpp
+++ b/clang/lib/AST/ASTConcept.cpp
@@ -19,33 +19,49 @@
#include "llvm/ADT/FoldingSet.h"
using namespace clang;
-ASTConstraintSatisfaction::ASTConstraintSatisfaction(const ASTContext &C,
- const ConstraintSatisfaction &Satisfaction):
- NumRecords{Satisfaction.Details.size()},
- IsSatisfied{Satisfaction.IsSatisfied} {
- for (unsigned I = 0; I < NumRecords; ++I) {
- auto &Detail = Satisfaction.Details[I];
- if (Detail.second.is<Expr *>())
- new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I)
- UnsatisfiedConstraintRecord{Detail.first,
- UnsatisfiedConstraintRecord::second_type(
- Detail.second.get<Expr *>())};
- else {
- auto &SubstitutionDiagnostic =
- *Detail.second.get<std::pair<SourceLocation, StringRef> *>();
- unsigned MessageSize = SubstitutionDiagnostic.second.size();
- char *Mem = new (C) char[MessageSize];
- memcpy(Mem, SubstitutionDiagnostic.second.data(), MessageSize);
- auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>(
- SubstitutionDiagnostic.first, StringRef(Mem, MessageSize));
- new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I)
- UnsatisfiedConstraintRecord{Detail.first,
- UnsatisfiedConstraintRecord::second_type(
- NewSubstDiag)};
- }
+namespace {
+void CreatUnsatisfiedConstraintRecord(
+ const ASTContext &C, const UnsatisfiedConstraintRecord &Detail,
+ UnsatisfiedConstraintRecord *TrailingObject) {
+ if (Detail.second.is<Expr *>())
+ new (TrailingObject) UnsatisfiedConstraintRecord{
+ Detail.first,
+ UnsatisfiedConstraintRecord::second_type(Detail.second.get<Expr *>())};
+ else {
+ auto &SubstitutionDiagnostic =
+ *Detail.second.get<std::pair<SourceLocation, StringRef> *>();
+ unsigned MessageSize = SubstitutionDiagnostic.second.size();
+ char *Mem = new (C) char[MessageSize];
+ memcpy(Mem, SubstitutionDiagnostic.second.data(), MessageSize);
+ auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>(
+ SubstitutionDiagnostic.first, StringRef(Mem, MessageSize));
+ new (TrailingObject) UnsatisfiedConstraintRecord{
+ Detail.first, UnsatisfiedConstraintRecord::second_type(NewSubstDiag)};
}
}
+} // namespace
+ASTConstraintSatisfaction::ASTConstraintSatisfaction(
+ const ASTContext &C, const ConstraintSatisfaction &Satisfaction)
+ : NumRecords{Satisfaction.Details.size()},
+ IsSatisfied{Satisfaction.IsSatisfied}, ContainsErrors{
+ Satisfaction.ContainsErrors} {
+ for (unsigned I = 0; I < NumRecords; ++I)
+ CreatUnsatisfiedConstraintRecord(
+ C, Satisfaction.Details[I],
+ getTrailingObjects<UnsatisfiedConstraintRecord>() + I);
+}
+
+ASTConstraintSatisfaction::ASTConstraintSatisfaction(
+ const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction)
+ : NumRecords{Satisfaction.NumRecords},
+ IsSatisfied{Satisfaction.IsSatisfied},
+ ContainsErrors{Satisfaction.ContainsErrors} {
+ for (unsigned I = 0; I < NumRecords; ++I)
+ CreatUnsatisfiedConstraintRecord(
+ C, *(Satisfaction.begin() + I),
+ getTrailingObjects<UnsatisfiedConstraintRecord>() + I);
+}
ASTConstraintSatisfaction *
ASTConstraintSatisfaction::Create(const ASTContext &C,
@@ -57,6 +73,14 @@ ASTConstraintSatisfaction::Create(const ASTContext &C,
return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
}
+ASTConstraintSatisfaction *ASTConstraintSatisfaction::Rebuild(
+ const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction) {
+ std::size_t size =
+ totalSizeToAlloc<UnsatisfiedConstraintRecord>(Satisfaction.NumRecords);
+ void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction));
+ return new (Mem) ASTConstraintSatisfaction(C, Satisfaction);
+}
+
void ConstraintSatisfaction::Profile(
llvm::FoldingSetNodeID &ID, const ASTContext &C,
const NamedDecl *ConstraintOwner, ArrayRef<TemplateArgument> TemplateArgs) {
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index cfd7bf604542..2884fe660422 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -71,8 +71,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -94,6 +92,7 @@
#include <cstdlib>
#include <map>
#include <memory>
+#include <optional>
#include <string>
#include <tuple>
#include <utility>
@@ -298,6 +297,9 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
return nullptr;
const FileID File = SourceMgr.getDecomposedLoc(DeclLoc).first;
+ if (!File.isValid()) {
+ return nullptr;
+ }
const auto CommentsInThisFile = Comments.getCommentsInFile(File);
if (!CommentsInThisFile || CommentsInThisFile->empty())
return nullptr;
@@ -693,7 +695,11 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
ID.AddInteger(1);
ID.AddBoolean(NTTP->isParameterPack());
+ const Expr *TC = NTTP->getPlaceholderTypeConstraint();
+ ID.AddBoolean(TC != nullptr);
ID.AddPointer(NTTP->getType().getCanonicalType().getAsOpaquePtr());
+ if (TC)
+ TC->Profile(ID, C, /*Canonical=*/true);
if (NTTP->isExpandedParameterPack()) {
ID.AddBoolean(true);
ID.AddInteger(NTTP->getNumExpansionTypes());
@@ -754,15 +760,19 @@ canonicalizeImmediatelyDeclaredConstraint(const ASTContext &C, Expr *IDC,
NewConverted.push_back(ConstrainedType);
llvm::append_range(NewConverted, OldConverted.drop_front(1));
}
+ auto *CSD = ImplicitConceptSpecializationDecl::Create(
+ C, CSE->getNamedConcept()->getDeclContext(),
+ CSE->getNamedConcept()->getLocation(), NewConverted);
+
Expr *NewIDC = ConceptSpecializationExpr::Create(
- C, CSE->getNamedConcept(), NewConverted, nullptr,
- CSE->isInstantiationDependent(), CSE->containsUnexpandedParameterPack());
+ C, CSE->getNamedConcept(), CSD, nullptr, CSE->isInstantiationDependent(),
+ CSE->containsUnexpandedParameterPack());
if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC))
NewIDC = new (C) CXXFoldExpr(
- OrigFold->getType(), /*Callee*/nullptr, SourceLocation(), NewIDC,
+ OrigFold->getType(), /*Callee*/ nullptr, SourceLocation(), NewIDC,
BinaryOperatorKind::BO_LAnd, SourceLocation(), /*RHS=*/nullptr,
- SourceLocation(), /*NumExpansions=*/None);
+ SourceLocation(), /*NumExpansions=*/std::nullopt);
return NewIDC;
}
@@ -786,23 +796,18 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
PEnd = Params->end();
P != PEnd; ++P) {
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {
- TemplateTypeParmDecl *NewTTP = TemplateTypeParmDecl::Create(*this,
- getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
+ TemplateTypeParmDecl *NewTTP = TemplateTypeParmDecl::Create(
+ *this, getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
TTP->getDepth(), TTP->getIndex(), nullptr, false,
TTP->isParameterPack(), TTP->hasTypeConstraint(),
- TTP->isExpandedParameterPack() ?
- llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None);
+ TTP->isExpandedParameterPack()
+ ? std::optional<unsigned>(TTP->getNumExpansionParameters())
+ : std::nullopt);
if (const auto *TC = TTP->getTypeConstraint()) {
QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0);
Expr *NewIDC = canonicalizeImmediatelyDeclaredConstraint(
*this, TC->getImmediatelyDeclaredConstraint(),
ParamAsArgument);
- TemplateArgumentListInfo CanonArgsAsWritten;
- if (auto *Args = TC->getTemplateArgsAsWritten())
- for (const auto &ArgLoc : Args->arguments())
- CanonArgsAsWritten.addArgument(
- TemplateArgumentLoc(ArgLoc.getArgument(),
- TemplateArgumentLocInfo()));
NewTTP->setTypeConstraint(
NestedNameSpecifierLoc(),
DeclarationNameInfo(TC->getNamedConcept()->getDeclName(),
@@ -924,38 +929,6 @@ ParentMapContext &ASTContext::getParentMapContext() {
return *ParentMapCtx.get();
}
-static const LangASMap *getAddressSpaceMap(const TargetInfo &T,
- const LangOptions &LOpts) {
- if (LOpts.FakeAddressSpaceMap) {
- // The fake address space map must have a distinct entry for each
- // language-specific address space.
- static const unsigned FakeAddrSpaceMap[] = {
- 0, // Default
- 1, // opencl_global
- 3, // opencl_local
- 2, // opencl_constant
- 0, // opencl_private
- 4, // opencl_generic
- 5, // opencl_global_device
- 6, // opencl_global_host
- 7, // cuda_device
- 8, // cuda_constant
- 9, // cuda_shared
- 1, // sycl_global
- 5, // sycl_global_device
- 6, // sycl_global_host
- 3, // sycl_local
- 0, // sycl_private
- 10, // ptr32_sptr
- 11, // ptr32_uptr
- 12 // ptr64
- };
- return &FakeAddrSpaceMap;
- } else {
- return &T.getAddressSpaceMap();
- }
-}
-
static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI,
const LangOptions &LangOpts) {
switch (LangOpts.getAddressSpaceMapMangling()) {
@@ -1133,7 +1106,7 @@ ASTContext::getModulesWithMergedDefinition(const NamedDecl *Def) {
auto MergedIt =
MergedDefModules.find(cast<NamedDecl>(Def->getCanonicalDecl()));
if (MergedIt == MergedDefModules.end())
- return None;
+ return std::nullopt;
return MergedIt->second;
}
@@ -1191,7 +1164,7 @@ void ASTContext::addLazyModuleInitializers(Module *M, ArrayRef<uint32_t> IDs) {
ArrayRef<Decl *> ASTContext::getModuleInitializers(Module *M) {
auto It = ModuleInitializers.find(M);
if (It == ModuleInitializers.end())
- return None;
+ return std::nullopt;
auto *Inits = It->second;
Inits->resolve(*this);
@@ -1286,7 +1259,6 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target,
this->AuxTarget = AuxTarget;
ABI.reset(createCXXABI(Target));
- AddrSpaceMap = getAddressSpaceMap(Target, LangOpts);
AddrSpaceMapMangling = isAddrSpaceMapManglingEnabled(Target, LangOpts);
// C99 6.2.5p19.
@@ -1873,7 +1845,7 @@ static getConstantArrayInfoInChars(const ASTContext &Context,
uint64_t Width = EltInfo.Width.getQuantity() * Size;
unsigned Align = EltInfo.Align.getQuantity();
if (!Context.getTargetInfo().getCXXABI().isMicrosoft() ||
- Context.getTargetInfo().getPointerWidth(0) == 64)
+ Context.getTargetInfo().getPointerWidth(LangAS::Default) == 64)
Width = llvm::alignTo(Width, Align);
return TypeInfoChars(CharUnits::fromQuantity(Width),
CharUnits::fromQuantity(Align),
@@ -1892,6 +1864,44 @@ TypeInfoChars ASTContext::getTypeInfoInChars(QualType T) const {
return getTypeInfoInChars(T.getTypePtr());
}
+bool ASTContext::isPromotableIntegerType(QualType T) const {
+ // HLSL doesn't promote all small integer types to int, it
+ // just uses the rank-based promotion rules for all types.
+ if (getLangOpts().HLSL)
+ return false;
+
+ if (const auto *BT = T->getAs<BuiltinType>())
+ switch (BT->getKind()) {
+ case BuiltinType::Bool:
+ case BuiltinType::Char_S:
+ case BuiltinType::Char_U:
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char8:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ return true;
+ default:
+ return false;
+ }
+
+ // 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())
+ return false;
+
+ return true;
+ }
+
+ return false;
+}
+
bool ASTContext::isAlignmentRequired(const Type *T) const {
return getTypeInfo(T).AlignRequirement != AlignRequirementKind::None;
}
@@ -1946,7 +1956,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
uint64_t Width = 0;
unsigned Align = 8;
AlignRequirementKind AlignRequirement = AlignRequirementKind::None;
- unsigned AS = 0;
+ LangAS AS = LangAS::Default;
switch (T->getTypeClass()) {
#define TYPE(Class, Base)
#define ABSTRACT_TYPE(Class, Base)
@@ -1981,7 +1991,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
Align = EltInfo.Align;
AlignRequirement = EltInfo.AlignRequirement;
if (!getTargetInfo().getCXXABI().isMicrosoft() ||
- getTargetInfo().getPointerWidth(0) == 64)
+ getTargetInfo().getPointerWidth(LangAS::Default) == 64)
Width = llvm::alignTo(Width, Align);
break;
}
@@ -2082,7 +2092,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
case BuiltinType::Int128:
case BuiltinType::UInt128:
Width = 128;
- Align = 128; // int128_t is 128-bit aligned on all targets.
+ Align = Target->getInt128Align();
break;
case BuiltinType::ShortAccum:
case BuiltinType::UShortAccum:
@@ -2181,14 +2191,15 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
}
break;
case BuiltinType::NullPtr:
- Width = Target->getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t)
- Align = Target->getPointerAlign(0); // == sizeof(void*)
+ // C++ 3.9.1p11: sizeof(nullptr_t) == sizeof(void*)
+ Width = Target->getPointerWidth(LangAS::Default);
+ Align = Target->getPointerAlign(LangAS::Default);
break;
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
- Width = Target->getPointerWidth(0);
- Align = Target->getPointerAlign(0);
+ Width = Target->getPointerWidth(LangAS::Default);
+ Align = Target->getPointerAlign(LangAS::Default);
break;
case BuiltinType::OCLSampler:
case BuiltinType::OCLEvent:
@@ -2201,8 +2212,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
case BuiltinType::Id:
#include "clang/Basic/OpenCLExtensionTypes.def"
- AS = getTargetAddressSpace(
- Target->getOpenCLTypeAddrSpace(getOpenCLTypeKind(T)));
+ AS = Target->getOpenCLTypeAddrSpace(getOpenCLTypeKind(T));
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
@@ -2247,11 +2257,11 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
}
break;
case Type::ObjCObjectPointer:
- Width = Target->getPointerWidth(0);
- Align = Target->getPointerAlign(0);
+ Width = Target->getPointerWidth(LangAS::Default);
+ Align = Target->getPointerAlign(LangAS::Default);
break;
case Type::BlockPointer:
- AS = getTargetAddressSpace(cast<BlockPointerType>(T)->getPointeeType());
+ AS = cast<BlockPointerType>(T)->getPointeeType().getAddressSpace();
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
@@ -2259,12 +2269,12 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
case Type::RValueReference:
// alignof and sizeof should never enter this code path here, so we go
// the pointer route.
- AS = getTargetAddressSpace(cast<ReferenceType>(T)->getPointeeType());
+ AS = cast<ReferenceType>(T)->getPointeeType().getAddressSpace();
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
case Type::Pointer:
- AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType());
+ AS = cast<PointerType>(T)->getPointeeType().getAddressSpace();
Width = Target->getPointerWidth(AS);
Align = Target->getPointerAlign(AS);
break;
@@ -2367,12 +2377,12 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
return getTypeInfo(cast<UsingType>(T)->desugar().getTypePtr());
case Type::Typedef: {
- const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl();
- TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
+ const auto *TT = cast<TypedefType>(T);
+ TypeInfo Info = getTypeInfo(TT->desugar().getTypePtr());
// If the typedef has an aligned attribute on it, it overrides any computed
// alignment we have. This violates the GCC documentation (which says that
// attribute(aligned) can only round up) but matches its implementation.
- if (unsigned AttrAlign = Typedef->getMaxAlignment()) {
+ if (unsigned AttrAlign = TT->getDecl()->getMaxAlignment()) {
Align = AttrAlign;
AlignRequirement = AlignRequirementKind::RequiredByTypedef;
} else {
@@ -2421,8 +2431,8 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
break;
case Type::Pipe:
- Width = Target->getPointerWidth(getTargetAddressSpace(LangAS::opencl_global));
- Align = Target->getPointerAlign(getTargetAddressSpace(LangAS::opencl_global));
+ Width = Target->getPointerWidth(LangAS::opencl_global);
+ Align = Target->getPointerAlign(LangAS::opencl_global);
break;
}
@@ -2485,7 +2495,7 @@ CharUnits ASTContext::getTypeAlignInChars(const Type *T) const {
}
/// getTypeUnadjustedAlignInChars - Return the ABI-specified alignment of a
-/// type, in characters, before alignment adustments. This method does
+/// type, in characters, before alignment adjustments. This method does
/// not work on incomplete types.
CharUnits ASTContext::getTypeUnadjustedAlignInChars(QualType T) const {
return toCharUnitsFromBits(getTypeUnadjustedAlign(T));
@@ -2682,11 +2692,11 @@ static int64_t getSubobjectOffset(const CXXRecordDecl *RD,
return Context.toBits(Layout.getBaseClassOffset(RD));
}
-static llvm::Optional<int64_t>
+static std::optional<int64_t>
structHasUniqueObjectRepresentations(const ASTContext &Context,
const RecordDecl *RD);
-static llvm::Optional<int64_t>
+static std::optional<int64_t>
getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context) {
if (Field->getType()->isRecordType()) {
const RecordDecl *RD = Field->getType()->getAsRecordDecl();
@@ -2699,7 +2709,7 @@ getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context) {
bool IsBitIntType = Field->getType()->isBitIntType();
if (!Field->getType()->isReferenceType() && !IsBitIntType &&
!Context.hasUniqueObjectRepresentations(Field->getType()))
- return llvm::None;
+ return std::nullopt;
int64_t FieldSizeInBits =
Context.toBits(Context.getTypeSizeInChars(Field->getType()));
@@ -2708,43 +2718,43 @@ getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context) {
if (IsBitIntType) {
if ((unsigned)BitfieldSize >
cast<BitIntType>(Field->getType())->getNumBits())
- return llvm::None;
+ return std::nullopt;
} else if (BitfieldSize > FieldSizeInBits) {
- return llvm::None;
+ return std::nullopt;
}
FieldSizeInBits = BitfieldSize;
} else if (IsBitIntType &&
!Context.hasUniqueObjectRepresentations(Field->getType())) {
- return llvm::None;
+ return std::nullopt;
}
return FieldSizeInBits;
}
-static llvm::Optional<int64_t>
+static std::optional<int64_t>
getSubobjectSizeInBits(const CXXRecordDecl *RD, const ASTContext &Context) {
return structHasUniqueObjectRepresentations(Context, RD);
}
template <typename RangeT>
-static llvm::Optional<int64_t> structSubobjectsHaveUniqueObjectRepresentations(
+static std::optional<int64_t> structSubobjectsHaveUniqueObjectRepresentations(
const RangeT &Subobjects, int64_t CurOffsetInBits,
const ASTContext &Context, const clang::ASTRecordLayout &Layout) {
for (const auto *Subobject : Subobjects) {
- llvm::Optional<int64_t> SizeInBits =
+ std::optional<int64_t> SizeInBits =
getSubobjectSizeInBits(Subobject, Context);
if (!SizeInBits)
- return llvm::None;
+ return std::nullopt;
if (*SizeInBits != 0) {
int64_t Offset = getSubobjectOffset(Subobject, Context, Layout);
if (Offset != CurOffsetInBits)
- return llvm::None;
+ return std::nullopt;
CurOffsetInBits += *SizeInBits;
}
}
return CurOffsetInBits;
}
-static llvm::Optional<int64_t>
+static std::optional<int64_t>
structHasUniqueObjectRepresentations(const ASTContext &Context,
const RecordDecl *RD) {
assert(!RD->isUnion() && "Must be struct/class type");
@@ -2753,7 +2763,7 @@ structHasUniqueObjectRepresentations(const ASTContext &Context,
int64_t CurOffsetInBits = 0;
if (const auto *ClassDecl = dyn_cast<CXXRecordDecl>(RD)) {
if (ClassDecl->isDynamicClass())
- return llvm::None;
+ return std::nullopt;
SmallVector<CXXRecordDecl *, 4> Bases;
for (const auto &Base : ClassDecl->bases()) {
@@ -2766,19 +2776,19 @@ structHasUniqueObjectRepresentations(const ASTContext &Context,
return Layout.getBaseClassOffset(L) < Layout.getBaseClassOffset(R);
});
- llvm::Optional<int64_t> OffsetAfterBases =
+ std::optional<int64_t> OffsetAfterBases =
structSubobjectsHaveUniqueObjectRepresentations(Bases, CurOffsetInBits,
Context, Layout);
if (!OffsetAfterBases)
- return llvm::None;
+ return std::nullopt;
CurOffsetInBits = *OffsetAfterBases;
}
- llvm::Optional<int64_t> OffsetAfterFields =
+ std::optional<int64_t> OffsetAfterFields =
structSubobjectsHaveUniqueObjectRepresentations(
RD->fields(), CurOffsetInBits, Context, Layout);
if (!OffsetAfterFields)
- return llvm::None;
+ return std::nullopt;
CurOffsetInBits = *OffsetAfterFields;
return CurOffsetInBits;
@@ -2839,7 +2849,7 @@ bool ASTContext::hasUniqueObjectRepresentations(QualType Ty) const {
if (Record->isUnion())
return unionHasUniqueObjectRepresentations(*this, Record);
- Optional<int64_t> StructSize =
+ std::optional<int64_t> StructSize =
structHasUniqueObjectRepresentations(*this, Record);
return StructSize && *StructSize == static_cast<int64_t>(getTypeSize(Ty));
@@ -3001,6 +3011,18 @@ ASTContext::getASTObjCImplementationLayout(
return getObjCLayout(D->getClassInterface(), D);
}
+static auto getCanonicalTemplateArguments(const ASTContext &C,
+ ArrayRef<TemplateArgument> Args,
+ bool &AnyNonCanonArgs) {
+ SmallVector<TemplateArgument, 16> CanonArgs(Args);
+ for (auto &Arg : CanonArgs) {
+ TemplateArgument OrigArg = Arg;
+ Arg = C.getCanonicalTemplateArgument(Arg);
+ AnyNonCanonArgs |= !Arg.structurallyEquals(OrigArg);
+ }
+ return CanonArgs;
+}
+
//===----------------------------------------------------------------------===//
// Type creation/memoization methods
//===----------------------------------------------------------------------===//
@@ -3204,9 +3226,9 @@ bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T,
QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) {
if (const auto *Proto = T->getAs<FunctionProtoType>()) {
QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType());
- SmallVector<QualType, 16> Args(Proto->param_types());
+ SmallVector<QualType, 16> Args(Proto->param_types().size());
for (unsigned i = 0, n = Args.size(); i != n; ++i)
- Args[i] = removePtrSizeAddrSpace(Args[i]);
+ Args[i] = removePtrSizeAddrSpace(Proto->param_types()[i]);
return getFunctionType(RetTy, Args, Proto->getExtProtoInfo());
}
@@ -3329,6 +3351,26 @@ QualType ASTContext::getAdjustedType(QualType Orig, QualType New) const {
return QualType(AT, 0);
}
+QualType ASTContext::getDecayedType(QualType Orig, QualType Decayed) const {
+ llvm::FoldingSetNodeID ID;
+ AdjustedType::Profile(ID, Orig, Decayed);
+ void *InsertPos = nullptr;
+ AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (AT)
+ return QualType(AT, 0);
+
+ QualType Canonical = getCanonicalType(Decayed);
+
+ // Get the new insert position for the node we care about.
+ AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!AT && "Shouldn't be in the map!");
+
+ AT = new (*this, TypeAlignment) DecayedType(Orig, Decayed, Canonical);
+ Types.push_back(AT);
+ AdjustedTypes.InsertNode(AT, InsertPos);
+ return QualType(AT, 0);
+}
+
QualType ASTContext::getDecayedType(QualType T) const {
assert((T->isArrayType() || T->isFunctionType()) && "T does not decay");
@@ -3349,23 +3391,7 @@ QualType ASTContext::getDecayedType(QualType T) const {
if (T->isFunctionType())
Decayed = getPointerType(T);
- llvm::FoldingSetNodeID ID;
- AdjustedType::Profile(ID, T, Decayed);
- void *InsertPos = nullptr;
- AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
- if (AT)
- return QualType(AT, 0);
-
- QualType Canonical = getCanonicalType(Decayed);
-
- // Get the new insert position for the node we care about.
- AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(!AT && "Shouldn't be in the map!");
-
- AT = new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical);
- Types.push_back(AT);
- AdjustedTypes.InsertNode(AT, InsertPos);
- return QualType(AT, 0);
+ return getDecayedType(T, Decayed);
}
/// getBlockPointerType - Return the uniqued reference to the type for
@@ -3541,6 +3567,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
// is instantiation-dependent, this won't be a canonical type either, so fill
// in the canonical type field.
QualType Canon;
+ // FIXME: Check below should look for qualifiers behind sugar.
if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers() || SizeExpr) {
SplitQualType canonSplit = getCanonicalType(EltTy).split();
Canon = getConstantArrayType(QualType(canonSplit.Ty, 0), ArySize, nullptr,
@@ -3716,6 +3743,7 @@ QualType ASTContext::getVariableArrayType(QualType EltTy,
QualType Canon;
// Be sure to pull qualifiers off the element type.
+ // FIXME: Check below should look for qualifiers behind sugar.
if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
SplitQualType canonSplit = getCanonicalType(EltTy).split();
Canon = getVariableArrayType(QualType(canonSplit.Ty, 0), NumElts, ASM,
@@ -3818,6 +3846,7 @@ QualType ASTContext::getIncompleteArrayType(QualType elementType,
// qualifiers off the element type.
QualType canon;
+ // FIXME: Check below should look for qualifiers behind sugar.
if (!elementType.isCanonical() || elementType.hasLocalQualifiers()) {
SplitQualType canonSplit = getCanonicalType(elementType).split();
canon = getIncompleteArrayType(QualType(canonSplit.Ty, 0),
@@ -4009,7 +4038,11 @@ QualType ASTContext::getScalableVectorType(QualType EltTy,
/// the specified element type and size. VectorType must be a built-in type.
QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
VectorType::VectorKind VecKind) const {
- assert(vecType->isBuiltinType());
+ assert(vecType->isBuiltinType() ||
+ (vecType->isBitIntType() &&
+ // Only support _BitInt elements with byte-sized power of 2 NumBits.
+ llvm::isPowerOf2_32(vecType->getAs<BitIntType>()->getNumBits()) &&
+ vecType->getAs<BitIntType>()->getNumBits() >= 8));
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
@@ -4077,9 +4110,13 @@ ASTContext::getDependentVectorType(QualType VecType, Expr *SizeExpr,
/// getExtVectorType - Return the unique reference to an extended vector type of
/// the specified element type and size. VectorType must be a built-in type.
-QualType
-ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const {
- assert(vecType->isBuiltinType() || vecType->isDependentType());
+QualType ASTContext::getExtVectorType(QualType vecType,
+ unsigned NumElts) const {
+ assert(vecType->isBuiltinType() || vecType->isDependentType() ||
+ (vecType->isBitIntType() &&
+ // Only support _BitInt elements with byte-sized power of 2 NumBits.
+ llvm::isPowerOf2_32(vecType->getAs<BitIntType>()->getNumBits()) &&
+ vecType->getAs<BitIntType>()->getNumBits() >= 8));
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
@@ -4420,7 +4457,7 @@ QualType ASTContext::getFunctionTypeInternal(
case EST_Unparsed: case EST_Unevaluated: case EST_Uninstantiated:
// We don't know yet. It shouldn't matter what we pick here; no-one
// should ever look at this.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case EST_None: case EST_MSAny: case EST_NoexceptFalse:
CanonicalEPI.ExceptionSpec.Type = EST_None;
break;
@@ -4626,34 +4663,60 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
/// specified typedef name decl.
QualType ASTContext::getTypedefType(const TypedefNameDecl *Decl,
QualType Underlying) const {
- if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
+ if (!Decl->TypeForDecl) {
+ if (Underlying.isNull())
+ Underlying = Decl->getUnderlyingType();
+ auto *NewType = new (*this, TypeAlignment) TypedefType(
+ Type::Typedef, Decl, QualType(), getCanonicalType(Underlying));
+ Decl->TypeForDecl = NewType;
+ Types.push_back(NewType);
+ return QualType(NewType, 0);
+ }
+ if (Underlying.isNull() || Decl->getUnderlyingType() == Underlying)
+ return QualType(Decl->TypeForDecl, 0);
+ assert(hasSameType(Decl->getUnderlyingType(), Underlying));
- if (Underlying.isNull())
- Underlying = Decl->getUnderlyingType();
- QualType Canonical = getCanonicalType(Underlying);
- auto *newType = new (*this, TypeAlignment)
- TypedefType(Type::Typedef, Decl, Underlying, Canonical);
- Decl->TypeForDecl = newType;
- Types.push_back(newType);
- return QualType(newType, 0);
+ llvm::FoldingSetNodeID ID;
+ TypedefType::Profile(ID, Decl, Underlying);
+
+ 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);
+ }
+
+ void *Mem =
+ Allocate(TypedefType::totalSizeToAlloc<QualType>(true), TypeAlignment);
+ auto *NewType = new (Mem) TypedefType(Type::Typedef, Decl, Underlying,
+ getCanonicalType(Underlying));
+ TypedefTypes.InsertNode(NewType, InsertPos);
+ Types.push_back(NewType);
+ return QualType(NewType, 0);
}
QualType ASTContext::getUsingType(const UsingShadowDecl *Found,
QualType Underlying) const {
llvm::FoldingSetNodeID ID;
- UsingType::Profile(ID, Found);
+ UsingType::Profile(ID, Found, Underlying);
void *InsertPos = nullptr;
- UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos);
- if (T)
+ if (UsingType *T = UsingTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(T, 0);
- assert(!Underlying.hasLocalQualifiers());
- assert(Underlying == getTypeDeclType(cast<TypeDecl>(Found->getTargetDecl())));
- QualType Canon = Underlying.getCanonicalType();
+ const Type *TypeForDecl =
+ cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl();
- UsingType *NewType =
- new (*this, TypeAlignment) UsingType(Found, Underlying, Canon);
+ assert(!Underlying.hasLocalQualifiers());
+ QualType Canon = Underlying->getCanonicalTypeInternal();
+ assert(TypeForDecl->getCanonicalTypeInternal() == Canon);
+
+ if (Underlying.getTypePtr() == TypeForDecl)
+ Underlying = QualType();
+ void *Mem =
+ Allocate(UsingType::totalSizeToAlloc<QualType>(!Underlying.isNull()),
+ TypeAlignment);
+ UsingType *NewType = new (Mem) UsingType(Found, Underlying, Canon);
Types.push_back(NewType);
UsingTypes.InsertNode(NewType, InsertPos);
return QualType(NewType, 0);
@@ -4742,21 +4805,22 @@ QualType ASTContext::getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
}
/// Retrieve a substitution-result type.
-QualType
-ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
- QualType Replacement) const {
- assert(Replacement.isCanonical()
- && "replacement types must always be canonical");
-
+QualType ASTContext::getSubstTemplateTypeParmType(
+ QualType Replacement, Decl *AssociatedDecl, unsigned Index,
+ std::optional<unsigned> PackIndex) const {
llvm::FoldingSetNodeID ID;
- SubstTemplateTypeParmType::Profile(ID, Parm, Replacement);
+ SubstTemplateTypeParmType::Profile(ID, Replacement, AssociatedDecl, Index,
+ PackIndex);
void *InsertPos = nullptr;
- SubstTemplateTypeParmType *SubstParm
- = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
+ SubstTemplateTypeParmType *SubstParm =
+ SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos);
if (!SubstParm) {
- SubstParm = new (*this, TypeAlignment)
- SubstTemplateTypeParmType(Parm, Replacement);
+ void *Mem = Allocate(SubstTemplateTypeParmType::totalSizeToAlloc<QualType>(
+ !Replacement.isCanonical()),
+ TypeAlignment);
+ SubstParm = new (Mem) SubstTemplateTypeParmType(Replacement, AssociatedDecl,
+ Index, PackIndex);
Types.push_back(SubstParm);
SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
}
@@ -4765,34 +4829,38 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
}
/// Retrieve a
-QualType ASTContext::getSubstTemplateTypeParmPackType(
- const TemplateTypeParmType *Parm,
- const TemplateArgument &ArgPack) {
+QualType
+ASTContext::getSubstTemplateTypeParmPackType(Decl *AssociatedDecl,
+ unsigned Index, bool Final,
+ const TemplateArgument &ArgPack) {
#ifndef NDEBUG
- for (const auto &P : ArgPack.pack_elements()) {
- assert(P.getKind() == TemplateArgument::Type &&"Pack contains a non-type");
- assert(P.getAsType().isCanonical() && "Pack contains non-canonical type");
- }
+ for (const auto &P : ArgPack.pack_elements())
+ assert(P.getKind() == TemplateArgument::Type && "Pack contains a non-type");
#endif
llvm::FoldingSetNodeID ID;
- SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack);
+ SubstTemplateTypeParmPackType::Profile(ID, AssociatedDecl, Index, Final,
+ ArgPack);
void *InsertPos = nullptr;
- if (SubstTemplateTypeParmPackType *SubstParm
- = SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos))
+ if (SubstTemplateTypeParmPackType *SubstParm =
+ SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(SubstParm, 0);
QualType Canon;
- if (!Parm->isCanonicalUnqualified()) {
- Canon = getCanonicalType(QualType(Parm, 0));
- Canon = getSubstTemplateTypeParmPackType(cast<TemplateTypeParmType>(Canon),
- ArgPack);
- SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos);
+ {
+ TemplateArgument CanonArgPack = getCanonicalTemplateArgument(ArgPack);
+ if (!AssociatedDecl->isCanonicalDecl() ||
+ !CanonArgPack.structurallyEquals(ArgPack)) {
+ Canon = getSubstTemplateTypeParmPackType(
+ AssociatedDecl->getCanonicalDecl(), Index, Final, CanonArgPack);
+ [[maybe_unused]] const auto *Nothing =
+ SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!Nothing);
+ }
}
- auto *SubstParm
- = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon,
- ArgPack);
+ auto *SubstParm = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(
+ Canon, AssociatedDecl, Index, Final, ArgPack);
Types.push_back(SubstParm);
SubstTemplateTypeParmPackTypes.InsertNode(SubstParm, InsertPos);
return QualType(SubstParm, 0);
@@ -4838,7 +4906,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType Underlying) const {
assert(!Name.getAsDependentTemplateName() &&
"No dependent template names here!");
- QualType TST = getTemplateSpecializationType(Name, Args, Underlying);
+ QualType TST =
+ getTemplateSpecializationType(Name, Args.arguments(), Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
TemplateSpecializationTypeLoc TL =
@@ -4854,14 +4923,14 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
- const TemplateArgumentListInfo &Args,
+ ArrayRef<TemplateArgumentLoc> Args,
QualType Underlying) const {
assert(!Template.getAsDependentTemplateName() &&
"No dependent template names here!");
SmallVector<TemplateArgument, 4> ArgVec;
ArgVec.reserve(Args.size());
- for (const TemplateArgumentLoc &Arg : Args.arguments())
+ for (const TemplateArgumentLoc &Arg : Args)
ArgVec.push_back(Arg.getArgument());
return getTemplateSpecializationType(Template, ArgVec, Underlying);
@@ -4887,8 +4956,8 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Template = QTN->getUnderlyingTemplate();
- bool IsTypeAlias =
- isa_and_nonnull<TypeAliasTemplateDecl>(Template.getAsTemplateDecl());
+ const auto *TD = Template.getAsTemplateDecl();
+ bool IsTypeAlias = TD && TD->isTypeAlias();
QualType CanonType;
if (!Underlying.isNull())
CanonType = getCanonicalType(Underlying);
@@ -4916,23 +4985,6 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
return QualType(Spec, 0);
}
-static bool
-getCanonicalTemplateArguments(const ASTContext &C,
- ArrayRef<TemplateArgument> OrigArgs,
- SmallVectorImpl<TemplateArgument> &CanonArgs) {
- bool AnyNonCanonArgs = false;
- unsigned NumArgs = OrigArgs.size();
- CanonArgs.resize(NumArgs);
- for (unsigned I = 0; I != NumArgs; ++I) {
- const TemplateArgument &OrigArg = OrigArgs[I];
- TemplateArgument &CanonArg = CanonArgs[I];
- CanonArg = C.getCanonicalTemplateArgument(OrigArg);
- if (!CanonArg.structurallyEquals(OrigArg))
- AnyNonCanonArgs = true;
- }
- return AnyNonCanonArgs;
-}
-
QualType ASTContext::getCanonicalTemplateSpecializationType(
TemplateName Template, ArrayRef<TemplateArgument> Args) const {
assert(!Template.getAsDependentTemplateName() &&
@@ -4944,8 +4996,9 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(
// Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
- SmallVector<TemplateArgument, 4> CanonArgs;
- ::getCanonicalTemplateArguments(*this, Args, CanonArgs);
+ bool AnyNonCanonArgs = false;
+ auto CanonArgs =
+ ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs);
// Determine whether this canonical template specialization type already
// exists.
@@ -5065,12 +5118,9 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
return QualType(T, 0);
}
-QualType
-ASTContext::getDependentTemplateSpecializationType(
- ElaboratedTypeKeyword Keyword,
- NestedNameSpecifier *NNS,
- const IdentifierInfo *Name,
- const TemplateArgumentListInfo &Args) const {
+QualType ASTContext::getDependentTemplateSpecializationType(
+ ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name, ArrayRef<TemplateArgumentLoc> Args) const {
// TODO: avoid this copy
SmallVector<TemplateArgument, 16> ArgCopy;
for (unsigned I = 0, E = Args.size(); I != E; ++I)
@@ -5102,9 +5152,9 @@ ASTContext::getDependentTemplateSpecializationType(
ElaboratedTypeKeyword CanonKeyword = Keyword;
if (Keyword == ETK_None) CanonKeyword = ETK_Typename;
- SmallVector<TemplateArgument, 16> CanonArgs;
- bool AnyNonCanonArgs =
- ::getCanonicalTemplateArguments(*this, Args, CanonArgs);
+ bool AnyNonCanonArgs = false;
+ auto CanonArgs =
+ ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs);
QualType Canon;
if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) {
@@ -5113,7 +5163,9 @@ ASTContext::getDependentTemplateSpecializationType(
CanonArgs);
// Find the insert position again.
- DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
+ [[maybe_unused]] auto *Nothing =
+ DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!Nothing && "canonical type broken");
}
void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) +
@@ -5131,7 +5183,7 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) {
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
QualType ArgType = getTypeDeclType(TTP);
if (TTP->isParameterPack())
- ArgType = getPackExpansionType(ArgType, None);
+ ArgType = getPackExpansionType(ArgType, std::nullopt);
Arg = TemplateArgument(ArgType);
} else if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
@@ -5144,17 +5196,17 @@ TemplateArgument ASTContext::getInjectedTemplateArg(NamedDecl *Param) {
if (T->isRecordType())
T.addConst();
Expr *E = new (*this) DeclRefExpr(
- *this, NTTP, /*enclosing*/ false, T,
+ *this, NTTP, /*RefersToEnclosingVariableOrCapture*/ false, T,
Expr::getValueKindForType(NTTP->getType()), NTTP->getLocation());
if (NTTP->isParameterPack())
- E = new (*this) PackExpansionExpr(DependentTy, E, NTTP->getLocation(),
- None);
+ E = new (*this)
+ PackExpansionExpr(DependentTy, E, NTTP->getLocation(), std::nullopt);
Arg = TemplateArgument(E);
} else {
auto *TTP = cast<TemplateTemplateParmDecl>(Param);
if (TTP->isParameterPack())
- Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>());
+ Arg = TemplateArgument(TemplateName(TTP), std::optional<unsigned>());
else
Arg = TemplateArgument(TemplateName(TTP));
}
@@ -5175,7 +5227,7 @@ ASTContext::getInjectedTemplateArgs(const TemplateParameterList *Params,
}
QualType ASTContext::getPackExpansionType(QualType Pattern,
- Optional<unsigned> NumExpansions,
+ std::optional<unsigned> NumExpansions,
bool ExpectPackInType) {
assert((!ExpectPackInType || Pattern->containsUnexpandedParameterPack()) &&
"Pack expansions must expand one or more parameter packs");
@@ -5243,7 +5295,7 @@ QualType ASTContext::getObjCObjectType(QualType BaseType,
ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols) const {
return getObjCObjectType(BaseType, {},
- llvm::makeArrayRef(Protocols, NumProtocols),
+ llvm::ArrayRef(Protocols, NumProtocols),
/*isKindOf=*/false);
}
@@ -5565,30 +5617,31 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
/// multiple declarations that refer to "typeof(x)" all contain different
/// DeclRefExpr's. This doesn't effect the type checker, since it operates
/// on canonical type's (which are always unique).
-QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const {
+QualType ASTContext::getTypeOfExprType(Expr *tofExpr, TypeOfKind Kind) const {
TypeOfExprType *toe;
if (tofExpr->isTypeDependent()) {
llvm::FoldingSetNodeID ID;
- DependentTypeOfExprType::Profile(ID, *this, tofExpr);
+ DependentTypeOfExprType::Profile(ID, *this, tofExpr,
+ Kind == TypeOfKind::Unqualified);
void *InsertPos = nullptr;
- DependentTypeOfExprType *Canon
- = DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentTypeOfExprType *Canon =
+ DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos);
if (Canon) {
// We already have a "canonical" version of an identical, dependent
// typeof(expr) type. Use that as our canonical type.
- toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr,
- QualType((TypeOfExprType*)Canon, 0));
+ toe = new (*this, TypeAlignment)
+ TypeOfExprType(tofExpr, Kind, QualType((TypeOfExprType *)Canon, 0));
} else {
// Build a new, canonical typeof(expr) type.
- Canon
- = new (*this, TypeAlignment) DependentTypeOfExprType(*this, tofExpr);
+ Canon = new (*this, TypeAlignment)
+ DependentTypeOfExprType(*this, tofExpr, Kind);
DependentTypeOfExprTypes.InsertNode(Canon, InsertPos);
toe = Canon;
}
} else {
QualType Canonical = getCanonicalType(tofExpr->getType());
- toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, Canonical);
+ toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, Kind, Canonical);
}
Types.push_back(toe);
return QualType(toe, 0);
@@ -5599,9 +5652,10 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const {
/// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be
/// an issue. This doesn't affect the type checker, since it operates
/// on canonical types (which are always unique).
-QualType ASTContext::getTypeOfType(QualType tofType) const {
+QualType ASTContext::getTypeOfType(QualType tofType, TypeOfKind Kind) const {
QualType Canonical = getCanonicalType(tofType);
- auto *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical);
+ auto *tot =
+ new (*this, TypeAlignment) TypeOfType(tofType, Canonical, Kind);
Types.push_back(tot);
return QualType(tot, 0);
}
@@ -5707,9 +5761,6 @@ QualType ASTContext::getAutoTypeInternal(
!TypeConstraintConcept && !IsDependent)
return getAutoDeductType();
- if (TypeConstraintConcept)
- TypeConstraintConcept = TypeConstraintConcept->getCanonicalDecl();
-
// Look in the folding set for an existing type.
void *InsertPos = nullptr;
llvm::FoldingSetNodeID ID;
@@ -5720,18 +5771,15 @@ QualType ASTContext::getAutoTypeInternal(
QualType Canon;
if (!IsCanon) {
- if (DeducedType.isNull()) {
- SmallVector<TemplateArgument, 4> CanonArgs;
- bool AnyNonCanonArgs =
- ::getCanonicalTemplateArguments(*this, TypeConstraintArgs, CanonArgs);
- if (AnyNonCanonArgs) {
- Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
- TypeConstraintConcept, CanonArgs, true);
- // Find the insert position again.
- AutoTypes.FindNodeOrInsertPos(ID, InsertPos);
- }
- } else {
+ if (!DeducedType.isNull()) {
Canon = DeducedType.getCanonicalType();
+ } else if (TypeConstraintConcept) {
+ Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack,
+ nullptr, {}, true);
+ // Find the insert position again.
+ [[maybe_unused]] auto *Nothing =
+ AutoTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!Nothing && "canonical type broken");
}
}
@@ -5892,14 +5940,14 @@ QualType ASTContext::getUIntPtrType() const {
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType ASTContext::getPointerDiffType() const {
- return getFromTargetType(Target->getPtrDiffType(0));
+ return getFromTargetType(Target->getPtrDiffType(LangAS::Default));
}
/// Return the unique unsigned counterpart of "ptrdiff_t"
/// integer type. The standard (C11 7.21.6.1p7) refers to this type
/// in the definition of %tu format specifier.
QualType ASTContext::getUnsignedPointerDiffType() const {
- return getFromTargetType(Target->getUnsignedPtrDiffType(0));
+ return getFromTargetType(Target->getUnsignedPtrDiffType(LangAS::Default));
}
/// Return the unique type for "pid_t" defined in
@@ -6199,13 +6247,13 @@ ASTContext::getCanonicalTemplateName(const TemplateName &Name) const {
}
case TemplateName::SubstTemplateTemplateParmPack: {
- SubstTemplateTemplateParmPackStorage *subst
- = Name.getAsSubstTemplateTemplateParmPack();
- TemplateTemplateParmDecl *canonParameter
- = getCanonicalTemplateTemplateParmDecl(subst->getParameterPack());
- TemplateArgument canonArgPack
- = getCanonicalTemplateArgument(subst->getArgumentPack());
- return getSubstTemplateTemplateParmPack(canonParameter, canonArgPack);
+ SubstTemplateTemplateParmPackStorage *subst =
+ Name.getAsSubstTemplateTemplateParmPack();
+ TemplateArgument canonArgPack =
+ getCanonicalTemplateArgument(subst->getArgumentPack());
+ return getSubstTemplateTemplateParmPack(
+ canonArgPack, subst->getAssociatedDecl()->getCanonicalDecl(),
+ subst->getFinal(), subst->getIndex());
}
}
@@ -6287,7 +6335,9 @@ bool ASTContext::isSameTemplateParameter(const NamedDecl *X,
if (auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
auto *TY = cast<NonTypeTemplateParmDecl>(Y);
return TX->isParameterPack() == TY->isParameterPack() &&
- TX->getASTContext().hasSameType(TX->getType(), TY->getType());
+ TX->getASTContext().hasSameType(TX->getType(), TY->getType()) &&
+ isSameConstraintExpr(TX->getPlaceholderTypeConstraint(),
+ TY->getPlaceholderTypeConstraint());
}
auto *TX = cast<TemplateTemplateParmDecl>(X);
@@ -6407,8 +6457,8 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A,
auto BEnableIfAttrs = B->specific_attrs<EnableIfAttr>();
for (auto Pair : zip_longest(AEnableIfAttrs, BEnableIfAttrs)) {
- Optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
- Optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
+ std::optional<EnableIfAttr *> Cand1A = std::get<0>(Pair);
+ std::optional<EnableIfAttr *> Cand2A = std::get<1>(Pair);
// Return false if the number of enable_if attributes is different.
if (!Cand1A || !Cand2A)
@@ -6428,6 +6478,31 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A,
return true;
}
+bool ASTContext::FriendsDifferByConstraints(const FunctionDecl *X,
+ const FunctionDecl *Y) const {
+ // If these aren't friends, then they aren't friends that differ by
+ // constraints.
+ if (!X->getFriendObjectKind() || !Y->getFriendObjectKind())
+ return false;
+
+ // If the two functions share lexical declaration context, they are not in
+ // separate instantations, and thus in the same scope.
+ if (X->getLexicalDeclContext() == Y->getLexicalDeclContext())
+ return false;
+
+ if (!X->getDescribedFunctionTemplate()) {
+ assert(!Y->getDescribedFunctionTemplate() &&
+ "How would these be the same if they aren't both templates?");
+
+ // If these friends don't have constraints, they aren't constrained, and
+ // thus don't fall under temp.friend p9. Else the simple presence of a
+ // constraint makes them unique.
+ return X->getTrailingRequiresClause();
+ }
+
+ return X->FriendConstraintRefersToEnclosingTemplate();
+}
+
bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
if (X == Y)
return true;
@@ -6508,6 +6583,10 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
FuncY->getTrailingRequiresClause()))
return false;
+ // Constrained friends are different in certain cases, see: [temp.friend]p9.
+ if (FriendsDifferByConstraints(FuncX, FuncY))
+ return false;
+
auto GetTypeAsWritten = [](const FunctionDecl *FD) {
// Map to the first declaration that we've already merged into this one.
// The TSI of redeclarations might not match (due to calling conventions
@@ -6660,7 +6739,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
case TemplateArgument::Declaration: {
auto *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl());
- return TemplateArgument(D, Arg.getParamTypeForDecl());
+ return TemplateArgument(D, getCanonicalType(Arg.getParamTypeForDecl()));
}
case TemplateArgument::NullPtr:
@@ -6682,17 +6761,13 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
return TemplateArgument(getCanonicalType(Arg.getAsType()));
case TemplateArgument::Pack: {
- if (Arg.pack_size() == 0)
+ bool AnyNonCanonArgs = false;
+ auto CanonArgs = ::getCanonicalTemplateArguments(
+ *this, Arg.pack_elements(), AnyNonCanonArgs);
+ if (!AnyNonCanonArgs)
return Arg;
-
- auto *CanonArgs = new (*this) TemplateArgument[Arg.pack_size()];
- unsigned Idx = 0;
- for (TemplateArgument::pack_iterator A = Arg.pack_begin(),
- AEnd = Arg.pack_end();
- A != AEnd; (void)++A, ++Idx)
- CanonArgs[Idx] = getCanonicalTemplateArgument(*A);
-
- return TemplateArgument(llvm::makeArrayRef(CanonArgs, Arg.pack_size()));
+ return TemplateArgument::CreatePackCopy(const_cast<ASTContext &>(*this),
+ CanonArgs);
}
}
@@ -6864,7 +6939,7 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) const {
PrettyArrayType->getIndexTypeQualifiers());
// int x[_Nullable] -> int * _Nullable
- if (auto Nullability = Ty->getNullability(*this)) {
+ if (auto Nullability = Ty->getNullability()) {
Result = const_cast<ASTContext *>(this)->getAttributedType(
AttributedType::getNullabilityAttrKind(*Nullability), Result, Result);
}
@@ -6901,6 +6976,21 @@ ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const {
return ElementCount;
}
+uint64_t ASTContext::getArrayInitLoopExprElementCount(
+ const ArrayInitLoopExpr *AILE) const {
+ if (!AILE)
+ return 0;
+
+ uint64_t ElementCount = 1;
+
+ do {
+ ElementCount *= AILE->getArraySize().getZExtValue();
+ AILE = dyn_cast<ArrayInitLoopExpr>(AILE->getSubExpr());
+ } while (AILE);
+
+ return ElementCount;
+}
+
/// getFloatingRank - Return a relative rank for floating point types.
/// This routine will assert if passed a built-in type that isn't a float.
static FloatingRank getFloatingRank(QualType T) {
@@ -6976,6 +7066,21 @@ unsigned ASTContext::getIntegerRank(const Type *T) const {
case BuiltinType::Int128:
case BuiltinType::UInt128:
return 7 + (getIntWidth(Int128Ty) << 3);
+
+ // "The ranks of char8_t, char16_t, char32_t, and wchar_t equal the ranks of
+ // their underlying types" [c++20 conv.rank]
+ case BuiltinType::Char8:
+ return getIntegerRank(UnsignedCharTy.getTypePtr());
+ case BuiltinType::Char16:
+ return getIntegerRank(
+ getFromTargetType(Target->getChar16Type()).getTypePtr());
+ case BuiltinType::Char32:
+ return getIntegerRank(
+ getFromTargetType(Target->getChar32Type()).getTypePtr());
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ return getIntegerRank(
+ getFromTargetType(Target->getWCharType()).getTypePtr());
}
}
@@ -7041,7 +7146,7 @@ QualType ASTContext::isPromotableBitField(Expr *E) const {
/// integer type.
QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
assert(!Promotable.isNull());
- assert(Promotable->isPromotableIntegerType());
+ assert(isPromotableIntegerType(Promotable));
if (const auto *ET = Promotable->getAs<EnumType>())
return ET->getDecl()->getPromotionType();
@@ -7061,12 +7166,11 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
uint64_t FromSize = getTypeSize(BT);
QualType PromoteTypes[] = { IntTy, UnsignedIntTy, LongTy, UnsignedLongTy,
LongLongTy, UnsignedLongLongTy };
- for (size_t Idx = 0; Idx < llvm::array_lengthof(PromoteTypes); ++Idx) {
- uint64_t ToSize = getTypeSize(PromoteTypes[Idx]);
+ for (const auto &PT : PromoteTypes) {
+ uint64_t ToSize = getTypeSize(PT);
if (FromSize < ToSize ||
- (FromSize == ToSize &&
- FromIsSigned == PromoteTypes[Idx]->isSignedIntegerType()))
- return PromoteTypes[Idx];
+ (FromSize == ToSize && FromIsSigned == PT->isSignedIntegerType()))
+ return PT;
}
llvm_unreachable("char type should fit into long long");
}
@@ -7551,7 +7655,7 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
// FIXME: There might(should) be a better way of doing this computation!
CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
CharUnits ParmOffset = PtrSize;
- for (auto PI : Decl->parameters()) {
+ for (auto *PI : Decl->parameters()) {
QualType PType = PI->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
if (sz.isZero())
@@ -7566,7 +7670,7 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
// Argument types.
ParmOffset = PtrSize;
- for (auto PVDecl : Decl->parameters()) {
+ for (auto *PVDecl : Decl->parameters()) {
QualType PType = PVDecl->getOriginalType();
if (const auto *AT =
dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
@@ -7595,7 +7699,7 @@ ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl) const {
getObjCEncodingForType(Decl->getReturnType(), S);
CharUnits ParmOffset;
// Compute size of all parameters.
- for (auto PI : Decl->parameters()) {
+ for (auto *PI : Decl->parameters()) {
QualType PType = PI->getType();
CharUnits sz = getObjCEncodingTypeSize(PType);
if (sz.isZero())
@@ -7609,7 +7713,7 @@ ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl) const {
ParmOffset = CharUnits::Zero();
// Argument types.
- for (auto PVDecl : Decl->parameters()) {
+ for (auto *PVDecl : Decl->parameters()) {
QualType PType = PVDecl->getOriginalType();
if (const auto *AT =
dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
@@ -7816,7 +7920,7 @@ ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
/// 'l' or 'L' , but not always. For typedefs, we need to use
/// 'i' or 'I' instead if encoding a struct field, or a pointer!
void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const {
- if (isa<TypedefType>(PointeeTy.getTypePtr())) {
+ if (PointeeTy->getAs<TypedefType>()) {
if (const auto *BT = PointeeTy->getAs<BuiltinType>()) {
if (BT->getKind() == BuiltinType::ULong && getIntWidth(PointeeTy) == 32)
PointeeTy = UnsignedIntTy;
@@ -8104,7 +8208,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
// pointee gets emitted _before_ the '^'. The read-only qualifier of
// the pointer itself gets ignored, _unless_ we are looking at a typedef!
// Also, do not emit the 'r' for anything but the outermost type!
- if (isa<TypedefType>(T.getTypePtr())) {
+ if (T->getAs<TypedefType>()) {
if (Options.IsOutermostType() && T.isConstQualified()) {
isReadOnly = true;
S += 'r';
@@ -8286,7 +8390,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S,
return;
}
// TODO: Double check to make sure this intentionally falls through.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case Type::ObjCInterface: {
@@ -8641,9 +8745,9 @@ CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
// namespace std { struct __va_list {
auto *NS = NamespaceDecl::Create(
const_cast<ASTContext &>(*Context), Context->getTranslationUnitDecl(),
- /*Inline*/ false, SourceLocation(), SourceLocation(),
+ /*Inline=*/false, SourceLocation(), SourceLocation(),
&Context->Idents.get("std"),
- /*PrevDecl*/ nullptr);
+ /*PrevDecl=*/nullptr, /*Nested=*/false);
NS->setImplicit();
VaListTagDecl->setDeclContext(NS);
}
@@ -8830,9 +8934,9 @@ CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) {
NamespaceDecl *NS;
NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context),
Context->getTranslationUnitDecl(),
- /*Inline*/false, SourceLocation(),
+ /*Inline=*/false, SourceLocation(),
SourceLocation(), &Context->Idents.get("std"),
- /*PrevDecl*/ nullptr);
+ /*PrevDecl=*/nullptr, /*Nested=*/false);
NS->setImplicit();
VaListDecl->setDeclContext(NS);
}
@@ -9020,6 +9124,10 @@ TypedefDecl *ASTContext::getBuiltinMSVaListDecl() const {
}
bool ASTContext::canBuiltinBeRedeclared(const FunctionDecl *FD) const {
+ // Allow redecl custom type checking builtin for HLSL.
+ if (LangOpts.HLSL && FD->getBuiltinID() != Builtin::NotBuiltin &&
+ BuiltinInfo.hasCustomTypechecking(FD->getBuiltinID()))
+ return true;
return BuiltinInfo.canBeRedeclared(FD->getBuiltinID());
}
@@ -9158,18 +9266,20 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
return TemplateName(QTN);
}
-TemplateName
-ASTContext::getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param,
- TemplateName replacement) const {
+TemplateName ASTContext::getSubstTemplateTemplateParm(
+ TemplateName Replacement, Decl *AssociatedDecl, unsigned Index,
+ std::optional<unsigned> PackIndex) const {
llvm::FoldingSetNodeID ID;
- SubstTemplateTemplateParmStorage::Profile(ID, param, replacement);
+ SubstTemplateTemplateParmStorage::Profile(ID, Replacement, AssociatedDecl,
+ Index, PackIndex);
void *insertPos = nullptr;
SubstTemplateTemplateParmStorage *subst
= SubstTemplateTemplateParms.FindNodeOrInsertPos(ID, insertPos);
if (!subst) {
- subst = new (*this) SubstTemplateTemplateParmStorage(param, replacement);
+ subst = new (*this) SubstTemplateTemplateParmStorage(
+ Replacement, AssociatedDecl, Index, PackIndex);
SubstTemplateTemplateParms.InsertNode(subst, insertPos);
}
@@ -9177,20 +9287,21 @@ ASTContext::getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param,
}
TemplateName
-ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param,
- const TemplateArgument &ArgPack) const {
+ASTContext::getSubstTemplateTemplateParmPack(const TemplateArgument &ArgPack,
+ Decl *AssociatedDecl,
+ unsigned Index, bool Final) const {
auto &Self = const_cast<ASTContext &>(*this);
llvm::FoldingSetNodeID ID;
- SubstTemplateTemplateParmPackStorage::Profile(ID, Self, Param, ArgPack);
+ SubstTemplateTemplateParmPackStorage::Profile(ID, Self, ArgPack,
+ AssociatedDecl, Index, Final);
void *InsertPos = nullptr;
SubstTemplateTemplateParmPackStorage *Subst
= SubstTemplateTemplateParmPacks.FindNodeOrInsertPos(ID, InsertPos);
if (!Subst) {
- Subst = new (*this) SubstTemplateTemplateParmPackStorage(Param,
- ArgPack.pack_size(),
- ArgPack.pack_begin());
+ Subst = new (*this) SubstTemplateTemplateParmPackStorage(
+ ArgPack.pack_elements(), AssociatedDecl, Index, Final);
SubstTemplateTemplateParmPacks.InsertNode(Subst, InsertPos);
}
@@ -9707,7 +9818,7 @@ void getIntersectionOfProtocols(ASTContext &Context,
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSProtocolSet;
// Start with the protocol qualifiers.
- for (auto proto : LHS->quals()) {
+ for (auto *proto : LHS->quals()) {
Context.CollectInheritedProtocols(proto, LHSProtocolSet);
}
@@ -9718,7 +9829,7 @@ void getIntersectionOfProtocols(ASTContext &Context,
llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSProtocolSet;
// Start with the protocol qualifiers.
- for (auto proto : RHS->quals()) {
+ for (auto *proto : RHS->quals()) {
Context.CollectInheritedProtocols(proto, RHSProtocolSet);
}
@@ -9726,7 +9837,7 @@ void getIntersectionOfProtocols(ASTContext &Context,
Context.CollectInheritedProtocols(RHS->getInterface(), RHSProtocolSet);
// Compute the intersection of the collected protocol sets.
- for (auto proto : LHSProtocolSet) {
+ for (auto *proto : LHSProtocolSet) {
if (RHSProtocolSet.count(proto))
IntersectionSet.push_back(proto);
}
@@ -10077,7 +10188,8 @@ QualType ASTContext::mergeFunctionParameterTypes(QualType lhs, QualType rhs,
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
bool OfBlockPointer, bool Unqualified,
- bool AllowCXX) {
+ bool AllowCXX,
+ bool IsConditionalOperator) {
const auto *lbase = lhs->castAs<FunctionType>();
const auto *rbase = rhs->castAs<FunctionType>();
const auto *lproto = dyn_cast<FunctionProtoType>(lbase);
@@ -10140,9 +10252,27 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lbaseInfo.getNoCfCheck() != rbaseInfo.getNoCfCheck())
return {};
- // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
- bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
-
+ // When merging declarations, it's common for supplemental information like
+ // attributes to only be present in one of the declarations, and we generally
+ // want type merging to preserve the union of information. So a merged
+ // function type should be noreturn if it was noreturn in *either* operand
+ // type.
+ //
+ // But for the conditional operator, this is backwards. The result of the
+ // operator could be either operand, and its type should conservatively
+ // reflect that. So a function type in a composite type is noreturn only
+ // if it's noreturn in *both* operand types.
+ //
+ // Arguably, noreturn is a kind of subtype, and the conditional operator
+ // ought to produce the most specific common supertype of its operand types.
+ // That would differ from this rule in contravariant positions. However,
+ // neither C nor C++ generally uses this kind of subtype reasoning. Also,
+ // as a practical matter, it would only affect C code that does abstraction of
+ // higher-order functions (taking noreturn callbacks!), which is uncommon to
+ // say the least. So we use the simpler rule.
+ bool NoReturn = IsConditionalOperator
+ ? lbaseInfo.getNoReturn() && rbaseInfo.getNoReturn()
+ : lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
if (lbaseInfo.getNoReturn() != NoReturn)
allLTypes = false;
if (rbaseInfo.getNoReturn() != NoReturn)
@@ -10235,7 +10365,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
return {};
}
- if (paramTy->isPromotableIntegerType() ||
+ if (isPromotableIntegerType(paramTy) ||
getCanonicalType(paramTy).getUnqualifiedType() == FloatTy)
return {};
}
@@ -10275,9 +10405,9 @@ static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET,
return {};
}
-QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
- bool OfBlockPointer,
- bool Unqualified, bool BlockReturnType) {
+QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer,
+ bool Unqualified, bool BlockReturnType,
+ bool IsConditionalOperator) {
// For C++ we will not reach this code with reference types (see below),
// for OpenMP variant call overloading we might.
//
@@ -10517,7 +10647,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
const ConstantArrayType* CAT)
-> std::pair<bool,llvm::APInt> {
if (VAT) {
- Optional<llvm::APSInt> TheInt;
+ std::optional<llvm::APSInt> TheInt;
Expr *E = VAT->getSizeExpr();
if (E && (TheInt = E->getIntegerConstantExpr(*this)))
return std::make_pair(true, *TheInt);
@@ -10570,7 +10700,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
ArrayType::ArraySizeModifier(), 0);
}
case Type::FunctionNoProto:
- return mergeFunctionTypes(LHS, RHS, OfBlockPointer, Unqualified);
+ return mergeFunctionTypes(LHS, RHS, OfBlockPointer, Unqualified,
+ /*AllowCXX=*/false, IsConditionalOperator);
case Type::Record:
case Type::Enum:
return {};
@@ -10778,7 +10909,8 @@ unsigned ASTContext::getIntWidth(QualType T) const {
}
QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
- assert((T->hasSignedIntegerRepresentation() || T->isSignedFixedPointType()) &&
+ assert((T->hasIntegerRepresentation() || T->isEnumeralType() ||
+ T->isFixedPointType()) &&
"Unexpected type");
// Turn <4 x signed int> -> <4 x unsigned int>
@@ -10796,8 +10928,11 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
T = ETy->getDecl()->getIntegerType();
switch (T->castAs<BuiltinType>()->getKind()) {
+ case BuiltinType::Char_U:
+ // Plain `char` is mapped to `unsigned char` even if it's already unsigned
case BuiltinType::Char_S:
case BuiltinType::SChar:
+ case BuiltinType::Char8:
return UnsignedCharTy;
case BuiltinType::Short:
return UnsignedShortTy;
@@ -10811,7 +10946,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
return UnsignedInt128Ty;
// wchar_t is special. It is either signed or not, but when it's signed,
// there's no matching "unsigned wchar_t". Therefore we return the unsigned
- // version of it's underlying type instead.
+ // version of its underlying type instead.
case BuiltinType::WChar_S:
return getUnsignedWCharType();
@@ -10840,13 +10975,16 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
case BuiltinType::SatLongFract:
return SatUnsignedLongFractTy;
default:
- llvm_unreachable("Unexpected signed integer or fixed point type");
+ assert((T->hasUnsignedIntegerRepresentation() ||
+ T->isUnsignedFixedPointType()) &&
+ "Unexpected signed integer or fixed point type");
+ return T;
}
}
QualType ASTContext::getCorrespondingSignedType(QualType T) const {
- assert((T->hasUnsignedIntegerRepresentation() ||
- T->isUnsignedFixedPointType()) &&
+ assert((T->hasIntegerRepresentation() || T->isEnumeralType() ||
+ T->isFixedPointType()) &&
"Unexpected type");
// Turn <4 x unsigned int> -> <4 x signed int>
@@ -10864,8 +11002,11 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const {
T = ETy->getDecl()->getIntegerType();
switch (T->castAs<BuiltinType>()->getKind()) {
+ case BuiltinType::Char_S:
+ // Plain `char` is mapped to `signed char` even if it's already signed
case BuiltinType::Char_U:
case BuiltinType::UChar:
+ case BuiltinType::Char8:
return SignedCharTy;
case BuiltinType::UShort:
return ShortTy;
@@ -10879,7 +11020,7 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const {
return Int128Ty;
// wchar_t is special. It is either unsigned or not, but when it's unsigned,
// there's no matching "signed wchar_t". Therefore we return the signed
- // version of it's underlying type instead.
+ // version of its underlying type instead.
case BuiltinType::WChar_U:
return getSignedWCharType();
@@ -10908,7 +11049,10 @@ QualType ASTContext::getCorrespondingSignedType(QualType T) const {
case BuiltinType::SatULongFract:
return SatLongFractTy;
default:
- llvm_unreachable("Unexpected unsigned integer or fixed point type");
+ assert(
+ (T->hasSignedIntegerRepresentation() || T->isSignedFixedPointType()) &&
+ "Unexpected signed integer or fixed point type");
+ return T;
}
}
@@ -11673,7 +11817,7 @@ void ASTContext::forEachMultiversionedFunctionVersion(
FD->getDeclContext()->getRedeclContext()->lookup(FD->getDeclName())) {
FunctionDecl *CurFD = CurDecl->getAsFunction()->getMostRecentDecl();
if (CurFD && hasSameType(CurFD->getType(), FD->getType()) &&
- std::end(SeenDecls) == llvm::find(SeenDecls, CurFD)) {
+ !llvm::is_contained(SeenDecls, CurFD)) {
SeenDecls.insert(CurFD);
Pred(CurFD);
}
@@ -11775,10 +11919,10 @@ MangleContext *ASTContext::createDeviceMangleContext(const TargetInfo &T) {
case TargetCXXABI::XL:
return ItaniumMangleContext::create(
*this, getDiagnostics(),
- [](ASTContext &, const NamedDecl *ND) -> llvm::Optional<unsigned> {
+ [](ASTContext &, const NamedDecl *ND) -> std::optional<unsigned> {
if (const auto *RD = dyn_cast<CXXRecordDecl>(ND))
return RD->getDeviceLambdaManglingNumber();
- return llvm::None;
+ return std::nullopt;
},
/*IsAux=*/true);
case TargetCXXABI::Microsoft:
@@ -12082,25 +12226,885 @@ uint64_t ASTContext::getTargetNullPointerValue(QualType QT) const {
return getTargetInfo().getNullPointerValue(AS);
}
-unsigned ASTContext::getTargetAddressSpace(QualType T) const {
- // Return the address space for the type. If the type is a
- // function type without an address space qualifier, the
- // program address space is used. Otherwise, the target picks
- // the best address space based on the type information
- return T->isFunctionType() && !T.hasAddressSpace()
- ? getTargetInfo().getProgramAddressSpace()
- : getTargetAddressSpace(T.getQualifiers());
+unsigned ASTContext::getTargetAddressSpace(LangAS AS) const {
+ return getTargetInfo().getTargetAddressSpace(AS);
}
-unsigned ASTContext::getTargetAddressSpace(Qualifiers Q) const {
- return getTargetAddressSpace(Q.getAddressSpace());
+bool ASTContext::hasSameExpr(const Expr *X, const Expr *Y) const {
+ if (X == Y)
+ return true;
+ if (!X || !Y)
+ return false;
+ llvm::FoldingSetNodeID IDX, IDY;
+ X->Profile(IDX, *this, /*Canonical=*/true);
+ Y->Profile(IDY, *this, /*Canonical=*/true);
+ return IDX == IDY;
}
-unsigned ASTContext::getTargetAddressSpace(LangAS AS) const {
- if (isTargetAddressSpace(AS))
- return toTargetAddressSpace(AS);
+// The getCommon* helpers return, for given 'same' X and Y entities given as
+// inputs, another entity which is also the 'same' as the inputs, but which
+// is closer to the canonical form of the inputs, each according to a given
+// criteria.
+// The getCommon*Checked variants are 'null inputs not-allowed' equivalents of
+// the regular ones.
+
+static Decl *getCommonDecl(Decl *X, Decl *Y) {
+ if (!declaresSameEntity(X, Y))
+ return nullptr;
+ for (const Decl *DX : X->redecls()) {
+ // If we reach Y before reaching the first decl, that means X is older.
+ if (DX == Y)
+ return X;
+ // If we reach the first decl, then Y is older.
+ if (DX->isFirstDecl())
+ return Y;
+ }
+ llvm_unreachable("Corrupt redecls chain");
+}
+
+template <class T, std::enable_if_t<std::is_base_of_v<Decl, T>, bool> = true>
+static T *getCommonDecl(T *X, T *Y) {
+ return cast_or_null<T>(
+ getCommonDecl(const_cast<Decl *>(cast_or_null<Decl>(X)),
+ const_cast<Decl *>(cast_or_null<Decl>(Y))));
+}
+
+template <class T, std::enable_if_t<std::is_base_of_v<Decl, T>, bool> = true>
+static T *getCommonDeclChecked(T *X, T *Y) {
+ return cast<T>(getCommonDecl(const_cast<Decl *>(cast<Decl>(X)),
+ const_cast<Decl *>(cast<Decl>(Y))));
+}
+
+static TemplateName getCommonTemplateName(ASTContext &Ctx, TemplateName X,
+ TemplateName Y) {
+ if (X.getAsVoidPointer() == Y.getAsVoidPointer())
+ return X;
+ // FIXME: There are cases here where we could find a common template name
+ // with more sugar. For example one could be a SubstTemplateTemplate*
+ // replacing the other.
+ TemplateName CX = Ctx.getCanonicalTemplateName(X);
+ if (CX.getAsVoidPointer() !=
+ Ctx.getCanonicalTemplateName(Y).getAsVoidPointer())
+ return TemplateName();
+ return CX;
+}
+
+static TemplateName
+getCommonTemplateNameChecked(ASTContext &Ctx, TemplateName X, TemplateName Y) {
+ TemplateName R = getCommonTemplateName(Ctx, X, Y);
+ assert(R.getAsVoidPointer() != nullptr);
+ return R;
+}
+
+static auto getCommonTypes(ASTContext &Ctx, ArrayRef<QualType> Xs,
+ ArrayRef<QualType> Ys, bool Unqualified = false) {
+ assert(Xs.size() == Ys.size());
+ SmallVector<QualType, 8> Rs(Xs.size());
+ for (size_t I = 0; I < Rs.size(); ++I)
+ Rs[I] = Ctx.getCommonSugaredType(Xs[I], Ys[I], Unqualified);
+ return Rs;
+}
+
+template <class T>
+static SourceLocation getCommonAttrLoc(const T *X, const T *Y) {
+ return X->getAttributeLoc() == Y->getAttributeLoc() ? X->getAttributeLoc()
+ : SourceLocation();
+}
+
+static TemplateArgument getCommonTemplateArgument(ASTContext &Ctx,
+ const TemplateArgument &X,
+ const TemplateArgument &Y) {
+ if (X.getKind() != Y.getKind())
+ return TemplateArgument();
+
+ switch (X.getKind()) {
+ case TemplateArgument::ArgKind::Type:
+ if (!Ctx.hasSameType(X.getAsType(), Y.getAsType()))
+ return TemplateArgument();
+ return TemplateArgument(
+ Ctx.getCommonSugaredType(X.getAsType(), Y.getAsType()));
+ case TemplateArgument::ArgKind::NullPtr:
+ if (!Ctx.hasSameType(X.getNullPtrType(), Y.getNullPtrType()))
+ return TemplateArgument();
+ return TemplateArgument(
+ Ctx.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()),
+ /*Unqualified=*/true);
+ case TemplateArgument::ArgKind::Expression:
+ if (!Ctx.hasSameType(X.getAsExpr()->getType(), Y.getAsExpr()->getType()))
+ return TemplateArgument();
+ // FIXME: Try to keep the common sugar.
+ return X;
+ case TemplateArgument::ArgKind::Template: {
+ TemplateName TX = X.getAsTemplate(), TY = Y.getAsTemplate();
+ TemplateName CTN = ::getCommonTemplateName(Ctx, TX, TY);
+ if (!CTN.getAsVoidPointer())
+ return TemplateArgument();
+ return TemplateArgument(CTN);
+ }
+ case TemplateArgument::ArgKind::TemplateExpansion: {
+ TemplateName TX = X.getAsTemplateOrTemplatePattern(),
+ TY = Y.getAsTemplateOrTemplatePattern();
+ TemplateName CTN = ::getCommonTemplateName(Ctx, TX, TY);
+ if (!CTN.getAsVoidPointer())
+ return TemplateName();
+ auto NExpX = X.getNumTemplateExpansions();
+ assert(NExpX == Y.getNumTemplateExpansions());
+ return TemplateArgument(CTN, NExpX);
+ }
+ default:
+ // FIXME: Handle the other argument kinds.
+ return X;
+ }
+}
+
+static bool getCommonTemplateArguments(ASTContext &Ctx,
+ SmallVectorImpl<TemplateArgument> &R,
+ ArrayRef<TemplateArgument> Xs,
+ ArrayRef<TemplateArgument> Ys) {
+ if (Xs.size() != Ys.size())
+ return true;
+ R.resize(Xs.size());
+ for (size_t I = 0; I < R.size(); ++I) {
+ R[I] = getCommonTemplateArgument(Ctx, Xs[I], Ys[I]);
+ if (R[I].isNull())
+ return true;
+ }
+ return false;
+}
+
+static auto getCommonTemplateArguments(ASTContext &Ctx,
+ ArrayRef<TemplateArgument> Xs,
+ ArrayRef<TemplateArgument> Ys) {
+ SmallVector<TemplateArgument, 8> R;
+ bool Different = getCommonTemplateArguments(Ctx, R, Xs, Ys);
+ assert(!Different);
+ (void)Different;
+ return R;
+}
+
+template <class T>
+static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y) {
+ return X->getKeyword() == Y->getKeyword() ? X->getKeyword()
+ : ElaboratedTypeKeyword::ETK_None;
+}
+
+template <class T>
+static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx, const T *X,
+ const T *Y) {
+ // FIXME: Try to keep the common NNS sugar.
+ return X->getQualifier() == Y->getQualifier()
+ ? X->getQualifier()
+ : Ctx.getCanonicalNestedNameSpecifier(X->getQualifier());
+}
+
+template <class T>
+static QualType getCommonElementType(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,
+ Qualifiers &QX, const T *Y,
+ Qualifiers &QY) {
+ QualType EX = X->getElementType(), EY = Y->getElementType();
+ QualType R = Ctx.getCommonSugaredType(EX, EY,
+ /*Unqualified=*/true);
+ Qualifiers RQ = R.getQualifiers();
+ QX += EX.getQualifiers() - RQ;
+ QY += EY.getQualifiers() - RQ;
+ return R;
+}
+
+template <class T>
+static QualType getCommonPointeeType(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) {
+ assert(Ctx.hasSameExpr(X->getSizeExpr(), Y->getSizeExpr()));
+ return X->getSizeExpr();
+}
+
+static auto getCommonSizeModifier(const ArrayType *X, const ArrayType *Y) {
+ assert(X->getSizeModifier() == Y->getSizeModifier());
+ return X->getSizeModifier();
+}
+
+static auto getCommonIndexTypeCVRQualifiers(const ArrayType *X,
+ const ArrayType *Y) {
+ assert(X->getIndexTypeCVRQualifiers() == Y->getIndexTypeCVRQualifiers());
+ return X->getIndexTypeCVRQualifiers();
+}
+
+// Merges two type lists such that the resulting vector will contain
+// 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) {
+ llvm::DenseMap<QualType, unsigned> Found;
+ for (auto Ts : {X, Y}) {
+ for (QualType T : Ts) {
+ auto Res = Found.try_emplace(Ctx.getCanonicalType(T), Out.size());
+ if (!Res.second) {
+ QualType &U = Out[Res.first->second];
+ U = Ctx.getCommonSugaredType(U, T);
+ } else {
+ Out.emplace_back(T);
+ }
+ }
+ }
+}
+
+FunctionProtoType::ExceptionSpecInfo
+ASTContext::mergeExceptionSpecs(FunctionProtoType::ExceptionSpecInfo ESI1,
+ FunctionProtoType::ExceptionSpecInfo ESI2,
+ SmallVectorImpl<QualType> &ExceptionTypeStorage,
+ bool AcceptDependent) {
+ ExceptionSpecificationType EST1 = ESI1.Type, EST2 = ESI2.Type;
+
+ // If either of them can throw anything, that is the result.
+ for (auto I : {EST_None, EST_MSAny, EST_NoexceptFalse}) {
+ if (EST1 == I)
+ return ESI1;
+ if (EST2 == I)
+ return ESI2;
+ }
+
+ // If either of them is non-throwing, the result is the other.
+ for (auto I :
+ {EST_NoThrow, EST_DynamicNone, EST_BasicNoexcept, EST_NoexceptTrue}) {
+ if (EST1 == I)
+ return ESI2;
+ if (EST2 == I)
+ return ESI1;
+ }
+
+ // If we're left with value-dependent computed noexcept expressions, we're
+ // stuck. Before C++17, we can just drop the exception specification entirely,
+ // since it's not actually part of the canonical type. And this should never
+ // happen in C++17, because it would mean we were computing the composite
+ // pointer type of dependent types, which should never happen.
+ if (EST1 == EST_DependentNoexcept || EST2 == EST_DependentNoexcept) {
+ assert(AcceptDependent &&
+ "computing composite pointer type of dependent types");
+ return FunctionProtoType::ExceptionSpecInfo();
+ }
+
+ // Switch over the possibilities so that people adding new values know to
+ // update this function.
+ switch (EST1) {
+ case EST_None:
+ case EST_DynamicNone:
+ case EST_MSAny:
+ case EST_BasicNoexcept:
+ case EST_DependentNoexcept:
+ case EST_NoexceptFalse:
+ case EST_NoexceptTrue:
+ case EST_NoThrow:
+ llvm_unreachable("These ESTs should be handled above");
+
+ case EST_Dynamic: {
+ // This is the fun case: both exception specifications are dynamic. Form
+ // the union of the two lists.
+ assert(EST2 == EST_Dynamic && "other cases should already be handled");
+ mergeTypeLists(*this, ExceptionTypeStorage, ESI1.Exceptions,
+ ESI2.Exceptions);
+ FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic);
+ Result.Exceptions = ExceptionTypeStorage;
+ return Result;
+ }
+
+ case EST_Unevaluated:
+ case EST_Uninstantiated:
+ case EST_Unparsed:
+ llvm_unreachable("shouldn't see unresolved exception specifications here");
+ }
+
+ llvm_unreachable("invalid ExceptionSpecificationType");
+}
+
+static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X,
+ Qualifiers &QX, const Type *Y,
+ Qualifiers &QY) {
+ Type::TypeClass TC = X->getTypeClass();
+ assert(TC == Y->getTypeClass());
+ switch (TC) {
+#define UNEXPECTED_TYPE(Class, Kind) \
+ case Type::Class: \
+ llvm_unreachable("Unexpected " Kind ": " #Class);
+
+#define NON_CANONICAL_TYPE(Class, Base) UNEXPECTED_TYPE(Class, "non-canonical")
+#define TYPE(Class, Base)
+#include "clang/AST/TypeNodes.inc"
+
+#define SUGAR_FREE_TYPE(Class) UNEXPECTED_TYPE(Class, "sugar-free")
+ SUGAR_FREE_TYPE(Builtin)
+ SUGAR_FREE_TYPE(Decltype)
+ 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(UnresolvedUsing)
+#undef SUGAR_FREE_TYPE
+#define NON_UNIQUE_TYPE(Class) UNEXPECTED_TYPE(Class, "non-unique")
+ NON_UNIQUE_TYPE(TypeOfExpr)
+ NON_UNIQUE_TYPE(VariableArray)
+#undef NON_UNIQUE_TYPE
+
+ UNEXPECTED_TYPE(TypeOf, "sugar")
+
+#undef UNEXPECTED_TYPE
+
+ case Type::Auto: {
+ const auto *AX = cast<AutoType>(X), *AY = cast<AutoType>(Y);
+ assert(AX->getDeducedType().isNull());
+ assert(AY->getDeducedType().isNull());
+ assert(AX->getKeyword() == AY->getKeyword());
+ assert(AX->isInstantiationDependentType() ==
+ AY->isInstantiationDependentType());
+ auto As = getCommonTemplateArguments(Ctx, AX->getTypeConstraintArguments(),
+ AY->getTypeConstraintArguments());
+ return Ctx.getAutoType(QualType(), AX->getKeyword(),
+ AX->isInstantiationDependentType(),
+ AX->containsUnexpandedParameterPack(),
+ getCommonDeclChecked(AX->getTypeConstraintConcept(),
+ AY->getTypeConstraintConcept()),
+ As);
+ }
+ case Type::IncompleteArray: {
+ const auto *AX = cast<IncompleteArrayType>(X),
+ *AY = cast<IncompleteArrayType>(Y);
+ return Ctx.getIncompleteArrayType(
+ getCommonArrayElementType(Ctx, AX, QX, AY, QY),
+ getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY));
+ }
+ case Type::DependentSizedArray: {
+ const auto *AX = cast<DependentSizedArrayType>(X),
+ *AY = cast<DependentSizedArrayType>(Y);
+ return Ctx.getDependentSizedArrayType(
+ getCommonArrayElementType(Ctx, AX, QX, AY, QY),
+ getCommonSizeExpr(Ctx, AX, AY), getCommonSizeModifier(AX, AY),
+ getCommonIndexTypeCVRQualifiers(AX, AY),
+ AX->getBracketsRange() == AY->getBracketsRange()
+ ? AX->getBracketsRange()
+ : SourceRange());
+ }
+ case Type::ConstantArray: {
+ const auto *AX = cast<ConstantArrayType>(X),
+ *AY = cast<ConstantArrayType>(Y);
+ assert(AX->getSize() == AY->getSize());
+ const Expr *SizeExpr = Ctx.hasSameExpr(AX->getSizeExpr(), AY->getSizeExpr())
+ ? AX->getSizeExpr()
+ : nullptr;
+ return Ctx.getConstantArrayType(
+ getCommonArrayElementType(Ctx, AX, QX, AY, QY), AX->getSize(), SizeExpr,
+ getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY));
+ }
+ case Type::Atomic: {
+ const auto *AX = cast<AtomicType>(X), *AY = cast<AtomicType>(Y);
+ return Ctx.getAtomicType(
+ Ctx.getCommonSugaredType(AX->getValueType(), AY->getValueType()));
+ }
+ case Type::Complex: {
+ const auto *CX = cast<ComplexType>(X), *CY = cast<ComplexType>(Y);
+ return Ctx.getComplexType(getCommonArrayElementType(Ctx, CX, QX, CY, QY));
+ }
+ case Type::Pointer: {
+ const auto *PX = cast<PointerType>(X), *PY = cast<PointerType>(Y);
+ return Ctx.getPointerType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::BlockPointer: {
+ const auto *PX = cast<BlockPointerType>(X), *PY = cast<BlockPointerType>(Y);
+ return Ctx.getBlockPointerType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::ObjCObjectPointer: {
+ const auto *PX = cast<ObjCObjectPointerType>(X),
+ *PY = cast<ObjCObjectPointerType>(Y);
+ return Ctx.getObjCObjectPointerType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::MemberPointer: {
+ const auto *PX = cast<MemberPointerType>(X),
+ *PY = cast<MemberPointerType>(Y);
+ return Ctx.getMemberPointerType(
+ getCommonPointeeType(Ctx, PX, PY),
+ Ctx.getCommonSugaredType(QualType(PX->getClass(), 0),
+ QualType(PY->getClass(), 0))
+ .getTypePtr());
+ }
+ case Type::LValueReference: {
+ const auto *PX = cast<LValueReferenceType>(X),
+ *PY = cast<LValueReferenceType>(Y);
+ // FIXME: Preserve PointeeTypeAsWritten.
+ return Ctx.getLValueReferenceType(getCommonPointeeType(Ctx, PX, PY),
+ PX->isSpelledAsLValue() ||
+ PY->isSpelledAsLValue());
+ }
+ case Type::RValueReference: {
+ const auto *PX = cast<RValueReferenceType>(X),
+ *PY = cast<RValueReferenceType>(Y);
+ // FIXME: Preserve PointeeTypeAsWritten.
+ return Ctx.getRValueReferenceType(getCommonPointeeType(Ctx, PX, PY));
+ }
+ case Type::DependentAddressSpace: {
+ const auto *PX = cast<DependentAddressSpaceType>(X),
+ *PY = cast<DependentAddressSpaceType>(Y);
+ assert(Ctx.hasSameExpr(PX->getAddrSpaceExpr(), PY->getAddrSpaceExpr()));
+ return Ctx.getDependentAddressSpaceType(getCommonPointeeType(Ctx, PX, PY),
+ PX->getAddrSpaceExpr(),
+ getCommonAttrLoc(PX, PY));
+ }
+ case Type::FunctionNoProto: {
+ const auto *FX = cast<FunctionNoProtoType>(X),
+ *FY = cast<FunctionNoProtoType>(Y);
+ assert(FX->getExtInfo() == FY->getExtInfo());
+ return Ctx.getFunctionNoProtoType(
+ Ctx.getCommonSugaredType(FX->getReturnType(), FY->getReturnType()),
+ FX->getExtInfo());
+ }
+ case Type::FunctionProto: {
+ const auto *FX = cast<FunctionProtoType>(X),
+ *FY = cast<FunctionProtoType>(Y);
+ FunctionProtoType::ExtProtoInfo EPIX = FX->getExtProtoInfo(),
+ EPIY = FY->getExtProtoInfo();
+ assert(EPIX.ExtInfo == EPIY.ExtInfo);
+ assert(EPIX.ExtParameterInfos == EPIY.ExtParameterInfos);
+ assert(EPIX.RefQualifier == EPIY.RefQualifier);
+ assert(EPIX.TypeQuals == EPIY.TypeQuals);
+ assert(EPIX.Variadic == EPIY.Variadic);
+
+ // FIXME: Can we handle an empty EllipsisLoc?
+ // Use emtpy EllipsisLoc if X and Y differ.
+
+ EPIX.HasTrailingReturn = EPIX.HasTrailingReturn && EPIY.HasTrailingReturn;
+
+ QualType R =
+ Ctx.getCommonSugaredType(FX->getReturnType(), FY->getReturnType());
+ auto P = getCommonTypes(Ctx, FX->param_types(), FY->param_types(),
+ /*Unqualified=*/true);
+
+ SmallVector<QualType, 8> Exceptions;
+ EPIX.ExceptionSpec = Ctx.mergeExceptionSpecs(
+ EPIX.ExceptionSpec, EPIY.ExceptionSpec, Exceptions, true);
+ return Ctx.getFunctionType(R, P, EPIX);
+ }
+ case Type::ObjCObject: {
+ const auto *OX = cast<ObjCObjectType>(X), *OY = cast<ObjCObjectType>(Y);
+ assert(
+ std::equal(OX->getProtocols().begin(), OX->getProtocols().end(),
+ OY->getProtocols().begin(), OY->getProtocols().end(),
+ [](const ObjCProtocolDecl *P0, const ObjCProtocolDecl *P1) {
+ return P0->getCanonicalDecl() == P1->getCanonicalDecl();
+ }) &&
+ "protocol lists must be the same");
+ auto TAs = getCommonTypes(Ctx, OX->getTypeArgsAsWritten(),
+ OY->getTypeArgsAsWritten());
+ return Ctx.getObjCObjectType(
+ Ctx.getCommonSugaredType(OX->getBaseType(), OY->getBaseType()), TAs,
+ OX->getProtocols(),
+ OX->isKindOfTypeAsWritten() && OY->isKindOfTypeAsWritten());
+ }
+ case Type::ConstantMatrix: {
+ const auto *MX = cast<ConstantMatrixType>(X),
+ *MY = cast<ConstantMatrixType>(Y);
+ assert(MX->getNumRows() == MY->getNumRows());
+ assert(MX->getNumColumns() == MY->getNumColumns());
+ return Ctx.getConstantMatrixType(getCommonElementType(Ctx, MX, MY),
+ MX->getNumRows(), MX->getNumColumns());
+ }
+ case Type::DependentSizedMatrix: {
+ const auto *MX = cast<DependentSizedMatrixType>(X),
+ *MY = cast<DependentSizedMatrixType>(Y);
+ assert(Ctx.hasSameExpr(MX->getRowExpr(), MY->getRowExpr()));
+ assert(Ctx.hasSameExpr(MX->getColumnExpr(), MY->getColumnExpr()));
+ return Ctx.getDependentSizedMatrixType(
+ getCommonElementType(Ctx, MX, MY), MX->getRowExpr(),
+ MX->getColumnExpr(), getCommonAttrLoc(MX, MY));
+ }
+ case Type::Vector: {
+ const auto *VX = cast<VectorType>(X), *VY = cast<VectorType>(Y);
+ assert(VX->getNumElements() == VY->getNumElements());
+ assert(VX->getVectorKind() == VY->getVectorKind());
+ return Ctx.getVectorType(getCommonElementType(Ctx, VX, VY),
+ VX->getNumElements(), VX->getVectorKind());
+ }
+ case Type::ExtVector: {
+ const auto *VX = cast<ExtVectorType>(X), *VY = cast<ExtVectorType>(Y);
+ assert(VX->getNumElements() == VY->getNumElements());
+ return Ctx.getExtVectorType(getCommonElementType(Ctx, VX, VY),
+ VX->getNumElements());
+ }
+ case Type::DependentSizedExtVector: {
+ const auto *VX = cast<DependentSizedExtVectorType>(X),
+ *VY = cast<DependentSizedExtVectorType>(Y);
+ return Ctx.getDependentSizedExtVectorType(getCommonElementType(Ctx, VX, VY),
+ getCommonSizeExpr(Ctx, VX, VY),
+ getCommonAttrLoc(VX, VY));
+ }
+ case Type::DependentVector: {
+ const auto *VX = cast<DependentVectorType>(X),
+ *VY = cast<DependentVectorType>(Y);
+ assert(VX->getVectorKind() == VY->getVectorKind());
+ return Ctx.getDependentVectorType(
+ getCommonElementType(Ctx, VX, VY), getCommonSizeExpr(Ctx, VX, VY),
+ getCommonAttrLoc(VX, VY), VX->getVectorKind());
+ }
+ 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()));
+ }
+ case Type::TemplateSpecialization: {
+ const auto *TX = cast<TemplateSpecializationType>(X),
+ *TY = cast<TemplateSpecializationType>(Y);
+ auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
+ TY->template_arguments());
+ return Ctx.getTemplateSpecializationType(
+ ::getCommonTemplateNameChecked(Ctx, TX->getTemplateName(),
+ TY->getTemplateName()),
+ As, X->getCanonicalTypeInternal());
+ }
+ case Type::DependentName: {
+ const auto *NX = cast<DependentNameType>(X),
+ *NY = cast<DependentNameType>(Y);
+ assert(NX->getIdentifier() == NY->getIdentifier());
+ return Ctx.getDependentNameType(
+ getCommonTypeKeyword(NX, NY), getCommonNNS(Ctx, NX, NY),
+ NX->getIdentifier(), NX->getCanonicalTypeInternal());
+ }
+ case Type::DependentTemplateSpecialization: {
+ const auto *TX = cast<DependentTemplateSpecializationType>(X),
+ *TY = cast<DependentTemplateSpecializationType>(Y);
+ assert(TX->getIdentifier() == TY->getIdentifier());
+ auto As = getCommonTemplateArguments(Ctx, TX->template_arguments(),
+ TY->template_arguments());
+ return Ctx.getDependentTemplateSpecializationType(
+ getCommonTypeKeyword(TX, TY), getCommonNNS(Ctx, TX, TY),
+ TX->getIdentifier(), As);
+ }
+ case Type::UnaryTransform: {
+ const auto *TX = cast<UnaryTransformType>(X),
+ *TY = cast<UnaryTransformType>(Y);
+ assert(TX->getUTTKind() == TY->getUTTKind());
+ return Ctx.getUnaryTransformType(
+ Ctx.getCommonSugaredType(TX->getBaseType(), TY->getBaseType()),
+ Ctx.getCommonSugaredType(TX->getUnderlyingType(),
+ TY->getUnderlyingType()),
+ TX->getUTTKind());
+ }
+ case Type::PackExpansion: {
+ const auto *PX = cast<PackExpansionType>(X),
+ *PY = cast<PackExpansionType>(Y);
+ assert(PX->getNumExpansions() == PY->getNumExpansions());
+ return Ctx.getPackExpansionType(
+ Ctx.getCommonSugaredType(PX->getPattern(), PY->getPattern()),
+ PX->getNumExpansions(), false);
+ }
+ case Type::Pipe: {
+ const auto *PX = cast<PipeType>(X), *PY = cast<PipeType>(Y);
+ assert(PX->isReadOnly() == PY->isReadOnly());
+ auto MP = PX->isReadOnly() ? &ASTContext::getReadPipeType
+ : &ASTContext::getWritePipeType;
+ return (Ctx.*MP)(getCommonElementType(Ctx, PX, PY));
+ }
+ case Type::TemplateTypeParm: {
+ const auto *TX = cast<TemplateTypeParmType>(X),
+ *TY = cast<TemplateTypeParmType>(Y);
+ assert(TX->getDepth() == TY->getDepth());
+ assert(TX->getIndex() == TY->getIndex());
+ assert(TX->isParameterPack() == TY->isParameterPack());
+ return Ctx.getTemplateTypeParmType(
+ TX->getDepth(), TX->getIndex(), TX->isParameterPack(),
+ getCommonDecl(TX->getDecl(), TY->getDecl()));
+ }
+ }
+ llvm_unreachable("Unknown Type Class");
+}
+
+static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X,
+ const Type *Y,
+ SplitQualType Underlying) {
+ Type::TypeClass TC = X->getTypeClass();
+ if (TC != Y->getTypeClass())
+ return QualType();
+ switch (TC) {
+#define UNEXPECTED_TYPE(Class, Kind) \
+ case Type::Class: \
+ llvm_unreachable("Unexpected " Kind ": " #Class);
+#define TYPE(Class, Base)
+#define DEPENDENT_TYPE(Class, Base) UNEXPECTED_TYPE(Class, "dependent")
+#include "clang/AST/TypeNodes.inc"
+
+#define CANONICAL_TYPE(Class) UNEXPECTED_TYPE(Class, "canonical")
+ CANONICAL_TYPE(Atomic)
+ CANONICAL_TYPE(BitInt)
+ CANONICAL_TYPE(BlockPointer)
+ CANONICAL_TYPE(Builtin)
+ CANONICAL_TYPE(Complex)
+ CANONICAL_TYPE(ConstantArray)
+ CANONICAL_TYPE(ConstantMatrix)
+ CANONICAL_TYPE(Enum)
+ CANONICAL_TYPE(ExtVector)
+ CANONICAL_TYPE(FunctionNoProto)
+ CANONICAL_TYPE(FunctionProto)
+ CANONICAL_TYPE(IncompleteArray)
+ CANONICAL_TYPE(LValueReference)
+ CANONICAL_TYPE(MemberPointer)
+ CANONICAL_TYPE(ObjCInterface)
+ CANONICAL_TYPE(ObjCObject)
+ CANONICAL_TYPE(ObjCObjectPointer)
+ CANONICAL_TYPE(Pipe)
+ CANONICAL_TYPE(Pointer)
+ CANONICAL_TYPE(Record)
+ CANONICAL_TYPE(RValueReference)
+ CANONICAL_TYPE(VariableArray)
+ CANONICAL_TYPE(Vector)
+#undef CANONICAL_TYPE
+
+#undef UNEXPECTED_TYPE
+
+ case Type::Adjusted: {
+ const auto *AX = cast<AdjustedType>(X), *AY = cast<AdjustedType>(Y);
+ QualType OX = AX->getOriginalType(), OY = AY->getOriginalType();
+ if (!Ctx.hasSameType(OX, OY))
+ return QualType();
+ // FIXME: It's inefficient to have to unify the original types.
+ return Ctx.getAdjustedType(Ctx.getCommonSugaredType(OX, OY),
+ Ctx.getQualifiedType(Underlying));
+ }
+ case Type::Decayed: {
+ const auto *DX = cast<DecayedType>(X), *DY = cast<DecayedType>(Y);
+ QualType OX = DX->getOriginalType(), OY = DY->getOriginalType();
+ if (!Ctx.hasSameType(OX, OY))
+ return QualType();
+ // FIXME: It's inefficient to have to unify the original types.
+ return Ctx.getDecayedType(Ctx.getCommonSugaredType(OX, OY),
+ Ctx.getQualifiedType(Underlying));
+ }
+ case Type::Attributed: {
+ const auto *AX = cast<AttributedType>(X), *AY = cast<AttributedType>(Y);
+ AttributedType::Kind Kind = AX->getAttrKind();
+ if (Kind != AY->getAttrKind())
+ return QualType();
+ QualType MX = AX->getModifiedType(), MY = AY->getModifiedType();
+ if (!Ctx.hasSameType(MX, MY))
+ return QualType();
+ // FIXME: It's inefficient to have to unify the modified types.
+ return Ctx.getAttributedType(Kind, Ctx.getCommonSugaredType(MX, MY),
+ Ctx.getQualifiedType(Underlying));
+ }
+ case Type::BTFTagAttributed: {
+ const auto *BX = cast<BTFTagAttributedType>(X);
+ const BTFTypeTagAttr *AX = BX->getAttr();
+ // The attribute is not uniqued, so just compare the tag.
+ if (AX->getBTFTypeTag() !=
+ cast<BTFTagAttributedType>(Y)->getAttr()->getBTFTypeTag())
+ return QualType();
+ return Ctx.getBTFTagAttributedType(AX, Ctx.getQualifiedType(Underlying));
+ }
+ case Type::Auto: {
+ const auto *AX = cast<AutoType>(X), *AY = cast<AutoType>(Y);
+
+ AutoTypeKeyword KW = AX->getKeyword();
+ if (KW != AY->getKeyword())
+ return QualType();
+
+ ConceptDecl *CD = ::getCommonDecl(AX->getTypeConstraintConcept(),
+ AY->getTypeConstraintConcept());
+ SmallVector<TemplateArgument, 8> As;
+ if (CD &&
+ getCommonTemplateArguments(Ctx, As, AX->getTypeConstraintArguments(),
+ AY->getTypeConstraintArguments()))
+ CD = nullptr; // The arguments differ, so make it unconstrained.
+
+ // Both auto types can't be dependent, otherwise they wouldn't have been
+ // sugar. This implies they can't contain unexpanded packs either.
+ return Ctx.getAutoType(Ctx.getQualifiedType(Underlying), AX->getKeyword(),
+ /*IsDependent=*/false, /*IsPack=*/false, CD, As);
+ }
+ case Type::Decltype:
+ return QualType();
+ 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), ::getCommonNNS(Ctx, EX, EY),
+ Ctx.getQualifiedType(Underlying),
+ ::getCommonDecl(EX->getOwnedTagDecl(), EY->getOwnedTagDecl()));
+ }
+ case Type::MacroQualified: {
+ const auto *MX = cast<MacroQualifiedType>(X),
+ *MY = cast<MacroQualifiedType>(Y);
+ const IdentifierInfo *IX = MX->getMacroIdentifier();
+ if (IX != MY->getMacroIdentifier())
+ return QualType();
+ return Ctx.getMacroQualifiedType(Ctx.getQualifiedType(Underlying), IX);
+ }
+ case Type::SubstTemplateTypeParm: {
+ const auto *SX = cast<SubstTemplateTypeParmType>(X),
+ *SY = cast<SubstTemplateTypeParmType>(Y);
+ Decl *CD =
+ ::getCommonDecl(SX->getAssociatedDecl(), SY->getAssociatedDecl());
+ if (!CD)
+ return QualType();
+ unsigned Index = SX->getIndex();
+ if (Index != SY->getIndex())
+ return QualType();
+ auto PackIndex = SX->getPackIndex();
+ if (PackIndex != SY->getPackIndex())
+ return QualType();
+ return Ctx.getSubstTemplateTypeParmType(Ctx.getQualifiedType(Underlying),
+ CD, Index, PackIndex);
+ }
+ case Type::ObjCTypeParam:
+ // FIXME: Try to merge these.
+ return QualType();
+ case Type::Paren:
+ return Ctx.getParenType(Ctx.getQualifiedType(Underlying));
+
+ case Type::TemplateSpecialization: {
+ const auto *TX = cast<TemplateSpecializationType>(X),
+ *TY = cast<TemplateSpecializationType>(Y);
+ TemplateName CTN = ::getCommonTemplateName(Ctx, TX->getTemplateName(),
+ TY->getTemplateName());
+ if (!CTN.getAsVoidPointer())
+ return QualType();
+ SmallVector<TemplateArgument, 8> Args;
+ if (getCommonTemplateArguments(Ctx, Args, TX->template_arguments(),
+ TY->template_arguments()))
+ return QualType();
+ return Ctx.getTemplateSpecializationType(CTN, Args,
+ 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));
+ }
+ case Type::TypeOf: {
+ // The common sugar between two typeof expressions, where one is
+ // potentially a typeof_unqual and the other is not, we unify to the
+ // qualified type as that retains the most information along with the type.
+ // We only return a typeof_unqual type when both types are unqual types.
+ TypeOfKind Kind = TypeOfKind::Qualified;
+ if (cast<TypeOfType>(X)->getKind() == cast<TypeOfType>(Y)->getKind() &&
+ cast<TypeOfType>(X)->getKind() == TypeOfKind::Unqualified)
+ Kind = TypeOfKind::Unqualified;
+ return Ctx.getTypeOfType(Ctx.getQualifiedType(Underlying), Kind);
+ }
+ case Type::TypeOfExpr:
+ return QualType();
+
+ case Type::UnaryTransform: {
+ const auto *UX = cast<UnaryTransformType>(X),
+ *UY = cast<UnaryTransformType>(Y);
+ UnaryTransformType::UTTKind KX = UX->getUTTKind();
+ if (KX != UY->getUTTKind())
+ return QualType();
+ QualType BX = UX->getBaseType(), BY = UY->getBaseType();
+ if (!Ctx.hasSameType(BX, BY))
+ return QualType();
+ // FIXME: It's inefficient to have to unify the base types.
+ return Ctx.getUnaryTransformType(Ctx.getCommonSugaredType(BX, BY),
+ Ctx.getQualifiedType(Underlying), KX);
+ }
+ case Type::Using: {
+ const auto *UX = cast<UsingType>(X), *UY = cast<UsingType>(Y);
+ const UsingShadowDecl *CD =
+ ::getCommonDecl(UX->getFoundDecl(), UY->getFoundDecl());
+ if (!CD)
+ return QualType();
+ return Ctx.getUsingType(CD, Ctx.getQualifiedType(Underlying));
+ }
+ }
+ llvm_unreachable("Unhandled Type Class");
+}
+
+static auto unwrapSugar(SplitQualType &T, Qualifiers &QTotal) {
+ SmallVector<SplitQualType, 8> R;
+ while (true) {
+ QTotal += T.Quals;
+ QualType NT = T.Ty->getLocallyUnqualifiedSingleStepDesugaredType();
+ if (NT == QualType(T.Ty, 0))
+ break;
+ R.push_back(T);
+ T = NT.split();
+ }
+ return R;
+}
+
+QualType ASTContext::getCommonSugaredType(QualType X, QualType Y,
+ bool Unqualified) {
+ assert(Unqualified ? hasSameUnqualifiedType(X, Y) : hasSameType(X, Y));
+ if (X == Y)
+ return X;
+ if (!Unqualified) {
+ if (X.isCanonical())
+ return X;
+ if (Y.isCanonical())
+ return Y;
+ }
+
+ SplitQualType SX = X.split(), SY = Y.split();
+ Qualifiers QX, QY;
+ // Desugar SX and SY, setting the sugar and qualifiers aside into Xs and Ys,
+ // until we reach their underlying "canonical nodes". Note these are not
+ // necessarily canonical types, as they may still have sugared properties.
+ // QX and QY will store the sum of all qualifiers in Xs and Ys respectively.
+ auto Xs = ::unwrapSugar(SX, QX), Ys = ::unwrapSugar(SY, QY);
+ if (SX.Ty != SY.Ty) {
+ // The canonical nodes differ. Build a common canonical node out of the two,
+ // unifying their sugar. This may recurse back here.
+ SX.Ty =
+ ::getCommonNonSugarTypeNode(*this, SX.Ty, QX, SY.Ty, QY).getTypePtr();
+ } else {
+ // The canonical nodes were identical: We may have desugared too much.
+ // Add any common sugar back in.
+ while (!Xs.empty() && !Ys.empty() && Xs.back().Ty == Ys.back().Ty) {
+ QX -= SX.Quals;
+ QY -= SY.Quals;
+ SX = Xs.pop_back_val();
+ SY = Ys.pop_back_val();
+ }
+ }
+ if (Unqualified)
+ QX = Qualifiers::removeCommonQualifiers(QX, QY);
else
- return (*AddrSpaceMap)[(unsigned)AS];
+ assert(QX == QY);
+
+ // Even though the remaining sugar nodes in Xs and Ys differ, some may be
+ // related. Walk up these nodes, unifying them and adding the result.
+ while (!Xs.empty() && !Ys.empty()) {
+ auto Underlying = SplitQualType(
+ SX.Ty, Qualifiers::removeCommonQualifiers(SX.Quals, SY.Quals));
+ SX = Xs.pop_back_val();
+ SY = Ys.pop_back_val();
+ SX.Ty = ::getCommonSugarTypeNode(*this, SX.Ty, SY.Ty, Underlying)
+ .getTypePtrOrNull();
+ // Stop at the first pair which is unrelated.
+ if (!SX.Ty) {
+ SX.Ty = Underlying.Ty;
+ break;
+ }
+ QX -= Underlying.Quals;
+ };
+
+ // Add back the missing accumulated qualifiers, which were stripped off
+ // with the sugar nodes we could not unify.
+ QualType R = getQualifiedType(SX.Ty, QX);
+ assert(Unqualified ? hasSameUnqualifiedType(R, X) : hasSameType(R, X));
+ return R;
}
QualType ASTContext::getCorrespondingSaturatedType(QualType Ty) const {
@@ -12304,10 +13308,22 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const {
}
}
+std::vector<std::string> ASTContext::filterFunctionTargetVersionAttrs(
+ const TargetVersionAttr *TV) const {
+ assert(TV != nullptr);
+ llvm::SmallVector<StringRef, 8> Feats;
+ std::vector<std::string> ResFeats;
+ TV->getFeatures(Feats);
+ for (auto &Feature : Feats)
+ if (Target->validateCpuSupports(Feature.str()))
+ ResFeats.push_back("?" + Feature.str());
+ return ResFeats;
+}
+
ParsedTargetAttr
ASTContext::filterFunctionTargetAttrs(const TargetAttr *TD) const {
assert(TD != nullptr);
- ParsedTargetAttr ParsedAttr = TD->parse();
+ ParsedTargetAttr ParsedAttr = Target->parseTargetAttr(TD->getFeaturesStr());
llvm::erase_if(ParsedAttr.Features, [&](const std::string &Feat) {
return !Target->isValidFeatureName(StringRef{Feat}.substr(1));
@@ -12341,9 +13357,8 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
Target->getTargetOpts().FeaturesAsWritten.begin(),
Target->getTargetOpts().FeaturesAsWritten.end());
- if (ParsedAttr.Architecture != "" &&
- Target->isValidCPUName(ParsedAttr.Architecture))
- TargetCPU = ParsedAttr.Architecture;
+ if (ParsedAttr.CPU != "" && Target->isValidCPUName(ParsedAttr.CPU))
+ TargetCPU = ParsedAttr.CPU;
// Now populate the feature map, first with the TargetCPU which is either
// the default or a new one from the target attribute string. Then we'll use
@@ -12363,12 +13378,32 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
} else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) {
std::vector<std::string> Features;
StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
- if (VersionStr.startswith("arch="))
- TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1);
- else if (VersionStr != "default")
- Features.push_back((StringRef{"+"} + VersionStr).str());
-
+ if (Target->getTriple().isAArch64()) {
+ // TargetClones for AArch64
+ if (VersionStr != "default") {
+ SmallVector<StringRef, 1> VersionFeatures;
+ VersionStr.split(VersionFeatures, "+");
+ for (auto &VFeature : VersionFeatures) {
+ VFeature = VFeature.trim();
+ Features.push_back((StringRef{"?"} + VFeature).str());
+ }
+ }
+ Features.insert(Features.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.end());
+ } else {
+ if (VersionStr.startswith("arch="))
+ TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1);
+ else if (VersionStr != "default")
+ Features.push_back((StringRef{"+"} + VersionStr).str());
+ }
Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
+ } else if (const auto *TV = FD->getAttr<TargetVersionAttr>()) {
+ std::vector<std::string> Feats = filterFunctionTargetVersionAttrs(TV);
+ Feats.insert(Feats.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.begin(),
+ Target->getTargetOpts().FeaturesAsWritten.end());
+ Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Feats);
} else {
FeatureMap = Target->getTargetOpts().FeatureMap;
}
diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp
index 28269ec219e4..08877aa12c02 100644
--- a/clang/lib/AST/ASTDiagnostic.cpp
+++ b/clang/lib/AST/ASTDiagnostic.cpp
@@ -118,8 +118,7 @@ QualType clang::desugarForDiagnostic(ASTContext &Context, QualType QT,
if (!TST->isTypeAlias()) {
bool DesugarArgument = false;
SmallVector<TemplateArgument, 4> Args;
- for (unsigned I = 0, N = TST->getNumArgs(); I != N; ++I) {
- const TemplateArgument &Arg = TST->getArg(I);
+ for (const TemplateArgument &Arg : TST->template_arguments()) {
if (Arg.getKind() == TemplateArgument::Type)
Args.push_back(desugarForDiagnostic(Context, Arg.getAsType(),
DesugarArgument));
@@ -228,7 +227,7 @@ break; \
desugarForDiagnostic(Context, Ty->getBaseType(), ShouldAKA);
QT = Context.getObjCObjectType(
BaseType, Ty->getTypeArgsAsWritten(),
- llvm::makeArrayRef(Ty->qual_begin(), Ty->getNumProtocols()),
+ llvm::ArrayRef(Ty->qual_begin(), Ty->getNumProtocols()),
Ty->isKindOfTypeAsWritten());
}
}
@@ -425,7 +424,7 @@ void clang::FormatASTNodeDiagnosticArgument(
Modifier = StringRef();
Argument = StringRef();
// Fall through
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case DiagnosticsEngine::ak_qualtype: {
assert(Modifier.empty() && Argument.empty() &&
@@ -539,7 +538,7 @@ class TemplateDiff {
bool ShowColor;
/// FromTemplateType - When single type printing is selected, this is the
- /// type to be be printed. When tree printing is selected, this type will
+ /// type to be printed. When tree printing is selected, this type will
/// show up first in the tree.
QualType FromTemplateType;
@@ -986,7 +985,7 @@ class TemplateDiff {
if (isEnd()) return;
// Set to first template argument. If not a parameter pack, done.
- TemplateArgument TA = TST->getArg(0);
+ TemplateArgument TA = TST->template_arguments()[0];
if (TA.getKind() != TemplateArgument::Pack) return;
// Start looking into the parameter pack.
@@ -1007,7 +1006,7 @@ class TemplateDiff {
/// isEnd - Returns true if the iterator is one past the end.
bool isEnd() const {
assert(TST && "InternalIterator is invalid with a null TST.");
- return Index >= TST->getNumArgs();
+ return Index >= TST->template_arguments().size();
}
/// &operator++ - Increment the iterator to the next template argument.
@@ -1027,11 +1026,11 @@ class TemplateDiff {
// Loop until a template argument is found, or the end is reached.
while (true) {
// Advance to the next template argument. Break if reached the end.
- if (++Index == TST->getNumArgs())
+ if (++Index == TST->template_arguments().size())
break;
// If the TemplateArgument is not a parameter pack, done.
- TemplateArgument TA = TST->getArg(Index);
+ TemplateArgument TA = TST->template_arguments()[Index];
if (TA.getKind() != TemplateArgument::Pack)
break;
@@ -1051,7 +1050,7 @@ class TemplateDiff {
assert(TST && "InternalIterator is invalid with a null TST.");
assert(!isEnd() && "Index exceeds number of arguments.");
if (CurrentTA == EndTA)
- return TST->getArg(Index);
+ return TST->template_arguments()[Index];
else
return *CurrentTA;
}
@@ -1684,9 +1683,24 @@ class TemplateDiff {
: FromType.getAsString(Policy);
std::string ToTypeStr = ToType.isNull() ? "(no argument)"
: ToType.getAsString(Policy);
- // Switch to canonical typename if it is better.
+ // Print without ElaboratedType sugar if it is better.
// 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);
std::string ToCanTypeStr = ToType.getCanonicalType().getAsString(Policy);
@@ -1696,6 +1710,7 @@ class TemplateDiff {
}
}
+ PrintTypes:
if (PrintTree) OS << '[';
OS << (FromDefault ? "(default) " : "");
Bold();
@@ -1877,7 +1892,7 @@ class TemplateDiff {
TPO->printAsInit(OS, Policy);
return;
}
- VD->printName(OS);
+ VD->printName(OS, Policy);
return;
}
diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp
index c6df61f79e2e..9900efb5a48d 100644
--- a/clang/lib/AST/ASTDumper.cpp
+++ b/clang/lib/AST/ASTDumper.cpp
@@ -19,9 +19,37 @@
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/raw_ostream.h"
+
using namespace clang;
using namespace clang::comments;
+void ASTDumper::dumpInvalidDeclContext(const DeclContext *DC) {
+ NodeDumper.AddChild([=] {
+ if (!DC) {
+ ColorScope Color(OS, ShowColors, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+ // An invalid DeclContext is one for which a dyn_cast() from a DeclContext
+ // pointer to a Decl pointer would fail an assertion or otherwise fall prey
+ // to undefined behavior as a result of an invalid associated DeclKind.
+ // Such invalidity is not supposed to happen of course, but, when it does,
+ // the information provided below is intended to provide some hints about
+ // what might have gone awry.
+ {
+ ColorScope Color(OS, ShowColors, DeclKindNameColor);
+ OS << "DeclContext";
+ }
+ NodeDumper.dumpPointer(DC);
+ OS << " <";
+ {
+ ColorScope Color(OS, ShowColors, DeclNameColor);
+ OS << "unrecognized Decl kind " << (unsigned)DC->getDeclKind();
+ }
+ OS << ">";
+ });
+}
+
void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) {
NodeDumper.AddChild([=] {
OS << "StoredDeclsMap ";
@@ -96,7 +124,7 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D,
case TSK_ExplicitInstantiationDefinition:
if (!DumpExplicitInst)
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case TSK_Undeclared:
case TSK_ImplicitInstantiation:
if (DumpRefOnly)
@@ -200,6 +228,31 @@ LLVM_DUMP_METHOD void Decl::dumpColor() const {
P.Visit(this);
}
+LLVM_DUMP_METHOD void DeclContext::dumpAsDecl() const {
+ dumpAsDecl(nullptr);
+}
+
+LLVM_DUMP_METHOD void DeclContext::dumpAsDecl(const ASTContext *Ctx) const {
+ // By design, DeclContext is required to be a base class of some class that
+ // derives from Decl. Thus, it should always be possible to dyn_cast() from
+ // a DeclContext pointer to a Decl pointer and Decl::castFromDeclContext()
+ // asserts that to be the case. Since this function is intended for use in a
+ // debugger, it performs an additional check in order to prevent a failed
+ // cast and assertion. If that check fails, then the (invalid) DeclContext
+ // is dumped with an indication of its invalidity.
+ if (hasValidDeclKind()) {
+ const auto *D = cast<Decl>(this);
+ D->dump();
+ } else {
+ // If an ASTContext is not available, a less capable ASTDumper is
+ // constructed for which color diagnostics are, regrettably, disabled.
+ ASTDumper P = Ctx ? ASTDumper(llvm::errs(), *Ctx,
+ Ctx->getDiagnostics().getShowColors())
+ : ASTDumper(llvm::errs(), /*ShowColors*/ false);
+ P.dumpInvalidDeclContext(this);
+ }
+}
+
LLVM_DUMP_METHOD void DeclContext::dumpLookups() const {
dumpLookups(llvm::errs());
}
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index 0273e5068371..6f367ef053d2 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -34,7 +34,6 @@
#include "clang/AST/LambdaCapture.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/OperationKinds.h"
-#include "clang/AST/ParentMapContext.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@@ -57,8 +56,6 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/SmallVector.h"
@@ -69,6 +66,7 @@
#include <cassert>
#include <cstddef>
#include <memory>
+#include <optional>
#include <type_traits>
#include <utility>
@@ -184,13 +182,13 @@ namespace clang {
// Use this instead of Importer.importInto .
template <typename ImportT>
- LLVM_NODISCARD Error importInto(ImportT &To, const ImportT &From) {
+ [[nodiscard]] Error importInto(ImportT &To, const ImportT &From) {
return Importer.importInto(To, From);
}
// Use this to import pointers of specific type.
template <typename ImportT>
- LLVM_NODISCARD Error importInto(ImportT *&To, ImportT *From) {
+ [[nodiscard]] Error importInto(ImportT *&To, ImportT *From) {
auto ToOrErr = Importer.Import(From);
if (ToOrErr)
To = cast_or_null<ImportT>(*ToOrErr);
@@ -201,8 +199,8 @@ namespace clang {
// cast the return value to `T`.
template <typename T>
auto import(T *From)
- -> std::conditional_t<std::is_base_of<Type, T>::value,
- Expected<const T *>, Expected<T *>> {
+ -> std::conditional_t<std::is_base_of_v<Type, T>, Expected<const T *>,
+ Expected<T *>> {
auto ToOrErr = Importer.Import(From);
if (!ToOrErr)
return ToOrErr.takeError();
@@ -220,11 +218,11 @@ namespace clang {
return Importer.Import(From);
}
- // Import an Optional<T> by importing the contained T, if any.
- template<typename T>
- Expected<Optional<T>> import(Optional<T> From) {
+ // Import an std::optional<T> by importing the contained T, if any.
+ template <typename T>
+ Expected<std::optional<T>> import(std::optional<T> From) {
if (!From)
- return Optional<T>();
+ return std::nullopt;
return import(*From);
}
@@ -245,8 +243,8 @@ namespace clang {
// then to the already imported Decl. Returns a bool value set to true if
// the `FromD` had been imported before.
template <typename ToDeclT, typename FromDeclT, typename... Args>
- LLVM_NODISCARD bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD,
- Args &&... args) {
+ [[nodiscard]] bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD,
+ Args &&...args) {
// There may be several overloads of ToDeclT::Create. We must make sure
// to call the one which would be chosen by the arguments, thus we use a
// wrapper for the overload set.
@@ -261,8 +259,8 @@ namespace clang {
// GetImportedOrCreateDecl<TypeAliasDecl>(ToTypedef, FromD, ...);
template <typename NewDeclT, typename ToDeclT, typename FromDeclT,
typename... Args>
- LLVM_NODISCARD bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD,
- Args &&... args) {
+ [[nodiscard]] bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD,
+ Args &&...args) {
CallOverloadedCreateFun<NewDeclT> OC;
return GetImportedOrCreateSpecialDecl(ToD, OC, FromD,
std::forward<Args>(args)...);
@@ -271,9 +269,9 @@ namespace clang {
// used, e.g. CXXRecordDecl::CreateLambda .
template <typename ToDeclT, typename CreateFunT, typename FromDeclT,
typename... Args>
- LLVM_NODISCARD bool
+ [[nodiscard]] bool
GetImportedOrCreateSpecialDecl(ToDeclT *&ToD, CreateFunT CreateFun,
- FromDeclT *FromD, Args &&... args) {
+ FromDeclT *FromD, Args &&...args) {
if (Importer.getImportDeclErrorIfAny(FromD)) {
ToD = nullptr;
return true; // Already imported but with error.
@@ -471,9 +469,8 @@ namespace clang {
Error ImportDefinition(
ObjCProtocolDecl *From, ObjCProtocolDecl *To,
ImportDefinitionKind Kind = IDK_Default);
- Error ImportTemplateArguments(
- const TemplateArgument *FromArgs, unsigned NumFromArgs,
- SmallVectorImpl<TemplateArgument> &ToArgs);
+ Error ImportTemplateArguments(ArrayRef<TemplateArgument> FromArgs,
+ SmallVectorImpl<TemplateArgument> &ToArgs);
Expected<TemplateArgument>
ImportTemplateArgument(const TemplateArgument &From);
@@ -791,9 +788,8 @@ ASTNodeImporter::ImportFunctionTemplateWithTemplateArgsFromSpecialization(
return std::move(Err);
// Import template arguments.
- auto TemplArgs = FTSInfo->TemplateArguments->asArray();
- if (Error Err = ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(),
- std::get<1>(Result)))
+ if (Error Err = ImportTemplateArguments(FTSInfo->TemplateArguments->asArray(),
+ std::get<1>(Result)))
return std::move(Err);
return Result;
@@ -894,12 +890,11 @@ ASTNodeImporter::import(const TemplateArgument &From) {
case TemplateArgument::Pack: {
SmallVector<TemplateArgument, 2> ToPack;
ToPack.reserve(From.pack_size());
- if (Error Err = ImportTemplateArguments(
- From.pack_begin(), From.pack_size(), ToPack))
+ if (Error Err = ImportTemplateArguments(From.pack_elements(), ToPack))
return std::move(Err);
return TemplateArgument(
- llvm::makeArrayRef(ToPack).copy(Importer.getToContext()));
+ llvm::ArrayRef(ToPack).copy(Importer.getToContext()));
}
}
@@ -1006,7 +1001,7 @@ ASTNodeImporter::import(const Designator &D) {
template <>
Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) {
- VarDecl *Var = nullptr;
+ ValueDecl *Var = nullptr;
if (From.capturesVariable()) {
if (auto VarOrErr = import(From.getCapturedVar()))
Var = *VarOrErr;
@@ -1362,24 +1357,27 @@ ExpectedType ASTNodeImporter::VisitTypedefType(const TypedefType *T) {
Expected<TypedefNameDecl *> ToDeclOrErr = import(T->getDecl());
if (!ToDeclOrErr)
return ToDeclOrErr.takeError();
+ ExpectedType ToUnderlyingTypeOrErr = import(T->desugar());
+ if (!ToUnderlyingTypeOrErr)
+ return ToUnderlyingTypeOrErr.takeError();
- return Importer.getToContext().getTypeDeclType(*ToDeclOrErr);
+ return Importer.getToContext().getTypedefType(*ToDeclOrErr,
+ *ToUnderlyingTypeOrErr);
}
ExpectedType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) {
ExpectedExpr ToExprOrErr = import(T->getUnderlyingExpr());
if (!ToExprOrErr)
return ToExprOrErr.takeError();
-
- return Importer.getToContext().getTypeOfExprType(*ToExprOrErr);
+ return Importer.getToContext().getTypeOfExprType(*ToExprOrErr, T->getKind());
}
ExpectedType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) {
- ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType());
+ ExpectedType ToUnderlyingTypeOrErr = import(T->getUnmodifiedType());
if (!ToUnderlyingTypeOrErr)
return ToUnderlyingTypeOrErr.takeError();
-
- return Importer.getToContext().getTypeOfType(*ToUnderlyingTypeOrErr);
+ return Importer.getToContext().getTypeOfType(*ToUnderlyingTypeOrErr,
+ T->getKind());
}
ExpectedType ASTNodeImporter::VisitUsingType(const UsingType *T) {
@@ -1432,9 +1430,7 @@ ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) {
return ToTypeConstraintConcept.takeError();
SmallVector<TemplateArgument, 2> ToTemplateArgs;
- ArrayRef<TemplateArgument> FromTemplateArgs = T->getTypeConstraintArguments();
- if (Error Err = ImportTemplateArguments(FromTemplateArgs.data(),
- FromTemplateArgs.size(),
+ if (Error Err = ImportTemplateArguments(T->getTypeConstraintArguments(),
ToTemplateArgs))
return std::move(Err);
@@ -1520,8 +1516,7 @@ ExpectedType ASTNodeImporter::VisitTemplateTypeParmType(
ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType(
const SubstTemplateTypeParmType *T) {
- Expected<const TemplateTypeParmType *> ReplacedOrErr =
- import(T->getReplacedParameter());
+ Expected<Decl *> ReplacedOrErr = import(T->getAssociatedDecl());
if (!ReplacedOrErr)
return ReplacedOrErr.takeError();
@@ -1530,13 +1525,13 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType(
return ToReplacementTypeOrErr.takeError();
return Importer.getToContext().getSubstTemplateTypeParmType(
- *ReplacedOrErr, ToReplacementTypeOrErr->getCanonicalType());
+ *ToReplacementTypeOrErr, *ReplacedOrErr, T->getIndex(),
+ T->getPackIndex());
}
ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
const SubstTemplateTypeParmPackType *T) {
- Expected<const TemplateTypeParmType *> ReplacedOrErr =
- import(T->getReplacedParameter());
+ Expected<Decl *> ReplacedOrErr = import(T->getAssociatedDecl());
if (!ReplacedOrErr)
return ReplacedOrErr.takeError();
@@ -1545,7 +1540,7 @@ ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType(
return ToArgumentPack.takeError();
return Importer.getToContext().getSubstTemplateTypeParmPackType(
- *ReplacedOrErr, *ToArgumentPack);
+ *ReplacedOrErr, T->getIndex(), T->getFinal(), *ToArgumentPack);
}
ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
@@ -1555,8 +1550,8 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType(
return ToTemplateOrErr.takeError();
SmallVector<TemplateArgument, 2> ToTemplateArgs;
- if (Error Err = ImportTemplateArguments(
- T->getArgs(), T->getNumArgs(), ToTemplateArgs))
+ if (Error Err =
+ ImportTemplateArguments(T->template_arguments(), ToTemplateArgs))
return std::move(Err);
QualType ToCanonType;
@@ -1613,9 +1608,8 @@ ExpectedType ASTNodeImporter::VisitDependentTemplateSpecializationType(
IdentifierInfo *ToName = Importer.Import(T->getIdentifier());
SmallVector<TemplateArgument, 2> ToPack;
- ToPack.reserve(T->getNumArgs());
- if (Error Err = ImportTemplateArguments(
- T->getArgs(), T->getNumArgs(), ToPack))
+ ToPack.reserve(T->template_arguments().size());
+ if (Error Err = ImportTemplateArguments(T->template_arguments(), ToPack))
return std::move(Err);
return Importer.getToContext().getDependentTemplateSpecializationType(
@@ -2186,10 +2180,10 @@ Error ASTNodeImporter::ImportDefinition(
}
Error ASTNodeImporter::ImportTemplateArguments(
- const TemplateArgument *FromArgs, unsigned NumFromArgs,
+ ArrayRef<TemplateArgument> FromArgs,
SmallVectorImpl<TemplateArgument> &ToArgs) {
- for (unsigned I = 0; I != NumFromArgs; ++I) {
- if (auto ToOrErr = import(FromArgs[I]))
+ for (const auto &Arg : FromArgs) {
+ if (auto ToOrErr = import(Arg))
ToArgs.push_back(*ToOrErr);
else
return ToOrErr.takeError();
@@ -2417,10 +2411,10 @@ ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
// Create the "to" namespace, if needed.
NamespaceDecl *ToNamespace = MergeWithNamespace;
if (!ToNamespace) {
- if (GetImportedOrCreateDecl(
- ToNamespace, D, Importer.getToContext(), DC, D->isInline(),
- *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(),
- /*PrevDecl=*/nullptr))
+ if (GetImportedOrCreateDecl(ToNamespace, D, Importer.getToContext(), DC,
+ D->isInline(), *BeginLocOrErr, Loc,
+ Name.getAsIdentifierInfo(),
+ /*PrevDecl=*/nullptr, D->isNested()))
return ToNamespace;
ToNamespace->setRBraceLoc(*RBraceLocOrErr);
ToNamespace->setLexicalDeclContext(LexicalDC);
@@ -3179,10 +3173,10 @@ Error ASTNodeImporter::ImportTemplateInformation(
// Import TemplateArgumentListInfo.
TemplateArgumentListInfo ToTAInfo;
if (Error Err = ImportTemplateArgumentListInfo(
- FromInfo->getLAngleLoc(), FromInfo->getRAngleLoc(),
- llvm::makeArrayRef(
- FromInfo->getTemplateArgs(), FromInfo->getNumTemplateArgs()),
- ToTAInfo))
+ FromInfo->getLAngleLoc(), FromInfo->getRAngleLoc(),
+ llvm::ArrayRef(FromInfo->getTemplateArgs(),
+ FromInfo->getNumTemplateArgs()),
+ ToTAInfo))
return Err;
ToFD->setDependentTemplateSpecialization(Importer.getToContext(),
@@ -3234,70 +3228,182 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) {
return false;
}
-// Returns true if the statement S has a parent declaration that has a
-// DeclContext that is inside (or equal to) DC. In a specific use case if DC is
-// a FunctionDecl, check if statement S resides in the body of the function.
+// Check if there is a declaration that has 'DC' as parent context and is
+// referenced from statement 'S' or one of its children. The search is done in
+// BFS order through children of 'S'.
static bool isAncestorDeclContextOf(const DeclContext *DC, const Stmt *S) {
- ParentMapContext &ParentC = DC->getParentASTContext().getParentMapContext();
- DynTypedNodeList Parents = ParentC.getParents(*S);
- while (!Parents.empty()) {
- if (const Decl *PD = Parents.begin()->get<Decl>())
- return isAncestorDeclContextOf(DC, PD);
- Parents = ParentC.getParents(*Parents.begin());
+ SmallVector<const Stmt *> ToProcess;
+ ToProcess.push_back(S);
+ while (!ToProcess.empty()) {
+ const Stmt *CurrentS = ToProcess.pop_back_val();
+ ToProcess.append(CurrentS->child_begin(), CurrentS->child_end());
+ if (const auto *DeclRef = dyn_cast<DeclRefExpr>(CurrentS))
+ if (const Decl *D = DeclRef->getDecl())
+ if (isAncestorDeclContextOf(DC, D))
+ return true;
}
return false;
}
-static bool hasTypeDeclaredInsideFunction(QualType T, const FunctionDecl *FD) {
- if (T.isNull())
+namespace {
+/// Check if a type has any reference to a declaration that is inside the body
+/// of a function.
+/// The \c CheckType(QualType) function should be used to determine
+/// this property.
+///
+/// The type visitor visits one type object only (not recursive).
+/// To find all referenced declarations we must discover all type objects until
+/// the canonical type is reached (walk over typedef and similar objects). This
+/// is done by loop over all "sugar" type objects. For every such type we must
+/// check all declarations that are referenced from it. For this check the
+/// visitor is used. In the visit functions all referenced declarations except
+/// the one that follows in the sugar chain (if any) must be checked. For this
+/// check the same visitor is re-used (it has no state-dependent data).
+///
+/// The visit functions have 3 possible return values:
+/// - True, found a declaration inside \c ParentDC.
+/// - False, found declarations only outside \c ParentDC and it is not possible
+/// to find more declarations (the "sugar" chain does not continue).
+/// - Empty optional value, found no declarations or only outside \c ParentDC,
+/// but it is possible to find more declarations in the type "sugar" chain.
+/// The loop over the "sugar" types can be implemented by using type visit
+/// functions only (call \c CheckType with the desugared type). With the current
+/// solution no visit function is needed if the type has only a desugared type
+/// as data.
+class IsTypeDeclaredInsideVisitor
+ : public TypeVisitor<IsTypeDeclaredInsideVisitor, std::optional<bool>> {
+public:
+ IsTypeDeclaredInsideVisitor(const FunctionDecl *ParentDC)
+ : ParentDC(ParentDC) {}
+
+ bool CheckType(QualType T) {
+ // Check the chain of "sugar" types.
+ // The "sugar" types are typedef or similar types that have the same
+ // canonical type.
+ if (std::optional<bool> Res = Visit(T.getTypePtr()))
+ return *Res;
+ QualType DsT =
+ T.getSingleStepDesugaredType(ParentDC->getParentASTContext());
+ while (DsT != T) {
+ if (std::optional<bool> Res = Visit(DsT.getTypePtr()))
+ return *Res;
+ T = DsT;
+ DsT = T.getSingleStepDesugaredType(ParentDC->getParentASTContext());
+ }
return false;
+ }
+
+ std::optional<bool> VisitTagType(const TagType *T) {
+ if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl()))
+ for (const auto &Arg : Spec->getTemplateArgs().asArray())
+ if (checkTemplateArgument(Arg))
+ return true;
+ return isAncestorDeclContextOf(ParentDC, T->getDecl());
+ }
+
+ std::optional<bool> VisitPointerType(const PointerType *T) {
+ return CheckType(T->getPointeeType());
+ }
+
+ std::optional<bool> VisitReferenceType(const ReferenceType *T) {
+ return CheckType(T->getPointeeTypeAsWritten());
+ }
+
+ std::optional<bool> VisitTypedefType(const TypedefType *T) {
+ const TypedefNameDecl *TD = T->getDecl();
+ assert(TD);
+ return isAncestorDeclContextOf(ParentDC, TD);
+ }
+
+ std::optional<bool> VisitUsingType(const UsingType *T) {
+ if (T->getFoundDecl() &&
+ isAncestorDeclContextOf(ParentDC, T->getFoundDecl()))
+ return true;
+
+ return {};
+ }
- auto CheckTemplateArgument = [FD](const TemplateArgument &Arg) {
+ std::optional<bool>
+ VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
+ for (const auto &Arg : T->template_arguments())
+ if (checkTemplateArgument(Arg))
+ return true;
+ // This type is a "sugar" to a record type, it can have a desugared type.
+ return {};
+ }
+
+ std::optional<bool> VisitConstantArrayType(const ConstantArrayType *T) {
+ if (T->getSizeExpr() && isAncestorDeclContextOf(ParentDC, T->getSizeExpr()))
+ return true;
+
+ return CheckType(T->getElementType());
+ }
+
+ std::optional<bool> VisitVariableArrayType(const VariableArrayType *T) {
+ llvm_unreachable(
+ "Variable array should not occur in deduced return type of a function");
+ }
+
+ std::optional<bool> VisitIncompleteArrayType(const IncompleteArrayType *T) {
+ llvm_unreachable("Incomplete array should not occur in deduced return type "
+ "of a function");
+ }
+
+ std::optional<bool> VisitDependentArrayType(const IncompleteArrayType *T) {
+ llvm_unreachable("Dependent array should not occur in deduced return type "
+ "of a function");
+ }
+
+private:
+ const DeclContext *const ParentDC;
+
+ bool checkTemplateArgument(const TemplateArgument &Arg) {
switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ return false;
+ case TemplateArgument::Integral:
+ return CheckType(Arg.getIntegralType());
case TemplateArgument::Type:
- return hasTypeDeclaredInsideFunction(Arg.getAsType(), FD);
+ return CheckType(Arg.getAsType());
case TemplateArgument::Expression:
- return isAncestorDeclContextOf(FD, Arg.getAsExpr());
- default:
- // FIXME: Handle other argument kinds.
+ return isAncestorDeclContextOf(ParentDC, Arg.getAsExpr());
+ case TemplateArgument::Declaration:
+ // FIXME: The declaration in this case is not allowed to be in a function?
+ return isAncestorDeclContextOf(ParentDC, Arg.getAsDecl());
+ case TemplateArgument::NullPtr:
+ // FIXME: The type is not allowed to be in the function?
+ return CheckType(Arg.getNullPtrType());
+ case TemplateArgument::Pack:
+ for (const auto &PackArg : Arg.getPackAsArray())
+ if (checkTemplateArgument(PackArg))
+ return true;
+ return false;
+ case TemplateArgument::Template:
+ // Templates can not be defined locally in functions.
+ // A template passed as argument can be not in ParentDC.
+ return false;
+ case TemplateArgument::TemplateExpansion:
+ // Templates can not be defined locally in functions.
+ // A template passed as argument can be not in ParentDC.
return false;
}
+ llvm_unreachable("Unknown TemplateArgument::ArgKind enum");
};
-
- if (const auto *RecordT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RecordT->getDecl();
- assert(RD);
- if (isAncestorDeclContextOf(FD, RD)) {
- assert(RD->getLexicalDeclContext() == RD->getDeclContext());
- return true;
- }
- if (const auto *RDTempl = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- if (llvm::count_if(RDTempl->getTemplateArgs().asArray(),
- CheckTemplateArgument))
- return true;
- // Note: It is possible that T can be get as both a RecordType and a
- // TemplateSpecializationType.
- }
- if (const auto *TST = T->getAs<TemplateSpecializationType>())
- return llvm::count_if(TST->template_arguments(), CheckTemplateArgument);
-
- return false;
-}
+};
+} // namespace
bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) {
QualType FromTy = D->getType();
const auto *FromFPT = FromTy->getAs<FunctionProtoType>();
assert(FromFPT && "Must be called on FunctionProtoType");
- if (const AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType())
- return hasTypeDeclaredInsideFunction(AutoT->getDeducedType(), D);
- if (const auto *TypedefT = FromFPT->getReturnType()->getAs<TypedefType>()) {
- const TypedefNameDecl *TD = TypedefT->getDecl();
- assert(TD);
- if (isAncestorDeclContextOf(D, TD)) {
- assert(TD->getLexicalDeclContext() == TD->getDeclContext());
- return true;
- }
+
+ QualType RetT = FromFPT->getReturnType();
+ if (isa<AutoType>(RetT.getTypePtr())) {
+ FunctionDecl *Def = D->getDefinition();
+ IsTypeDeclaredInsideVisitor Visitor(Def ? Def : D);
+ return Visitor.CheckType(RetT);
}
+
return false;
}
@@ -3475,6 +3581,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
auto TInfo = importChecked(Err, FromTSI);
auto ToInnerLocStart = importChecked(Err, D->getInnerLocStart());
auto ToEndLoc = importChecked(Err, D->getEndLoc());
+ auto ToDefaultLoc = importChecked(Err, D->getDefaultLoc());
auto ToQualifierLoc = importChecked(Err, D->getQualifierLoc());
auto TrailingRequiresClause =
importChecked(Err, D->getTrailingRequiresClause());
@@ -3483,7 +3590,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Import the function parameters.
SmallVector<ParmVarDecl *, 8> Parameters;
- for (auto P : D->parameters()) {
+ for (auto *P : D->parameters()) {
if (Expected<ParmVarDecl *> ToPOrErr = import(P))
Parameters.push_back(*ToPOrErr);
else
@@ -3592,7 +3699,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToFunction->setDefaulted(D->isDefaulted());
ToFunction->setExplicitlyDefaulted(D->isExplicitlyDefaulted());
ToFunction->setDeletedAsWritten(D->isDeletedAsWritten());
+ ToFunction->setFriendConstraintRefersToEnclosingTemplate(
+ D->FriendConstraintRefersToEnclosingTemplate());
ToFunction->setRangeEnd(ToEndLoc);
+ ToFunction->setDefaultLoc(ToDefaultLoc);
// Set the parameters.
for (auto *Param : Parameters) {
@@ -3637,6 +3747,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
}
+ // If it is a template, import all related things.
+ if (Error Err = ImportTemplateInformation(D, ToFunction))
+ return std::move(Err);
+
if (D->doesThisDeclarationHaveABody()) {
Error Err = ImportFunctionDeclBody(D, ToFunction);
@@ -3658,10 +3772,6 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// FIXME: Other bits to merge?
- // If it is a template, import all related things.
- if (Error Err = ImportTemplateInformation(D, ToFunction))
- return std::move(Err);
-
addDeclToContexts(D, ToFunction);
if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D))
@@ -3870,7 +3980,7 @@ static FriendCountAndPosition getFriendCountAndPosition(
const FriendDecl *FD,
llvm::function_ref<T(const FriendDecl *)> GetCanTypeOrDecl) {
unsigned int FriendCount = 0;
- llvm::Optional<unsigned int> FriendPosition;
+ std::optional<unsigned int> FriendPosition;
const auto *RD = cast<CXXRecordDecl>(FD->getLexicalDeclContext());
T TypeOrDecl = GetCanTypeOrDecl(FD);
@@ -4754,13 +4864,14 @@ ExpectedDecl ASTNodeImporter::VisitUsingEnumDecl(UsingEnumDecl *D) {
Error Err = Error::success();
auto ToUsingLoc = importChecked(Err, D->getUsingLoc());
auto ToEnumLoc = importChecked(Err, D->getEnumLoc());
- auto ToEnumDecl = importChecked(Err, D->getEnumDecl());
+ auto ToNameLoc = importChecked(Err, D->getLocation());
+ auto *ToEnumType = importChecked(Err, D->getEnumType());
if (Err)
return std::move(Err);
UsingEnumDecl *ToUsingEnum;
if (GetImportedOrCreateDecl(ToUsingEnum, D, Importer.getToContext(), DC,
- ToUsingLoc, ToEnumLoc, Loc, ToEnumDecl))
+ ToUsingLoc, ToEnumLoc, ToNameLoc, ToEnumType))
return ToUsingEnum;
ToUsingEnum->setLexicalDeclContext(LexicalDC);
@@ -5722,8 +5833,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
// Import template arguments.
SmallVector<TemplateArgument, 2> TemplateArgs;
- if (Error Err = ImportTemplateArguments(
- D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs))
+ if (Error Err =
+ ImportTemplateArguments(D->getTemplateArgs().asArray(), TemplateArgs))
return std::move(Err);
// Try to find an existing specialization with these template arguments and
// template parameter list.
@@ -5804,10 +5915,10 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
CanonInjType = CanonInjType.getCanonicalType();
if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>(
- D2, D, Importer.getToContext(), D->getTagKind(), DC,
- *BeginLocOrErr, *IdLocOrErr, ToTPList, ClassTemplate,
- llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()),
- ToTAInfo, CanonInjType,
+ D2, D, Importer.getToContext(), D->getTagKind(), DC, *BeginLocOrErr,
+ *IdLocOrErr, ToTPList, ClassTemplate,
+ llvm::ArrayRef(TemplateArgs.data(), TemplateArgs.size()), ToTAInfo,
+ CanonInjType,
cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl)))
return D2;
@@ -5881,6 +5992,30 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl(
D2->setTemplateSpecializationKind(D->getTemplateSpecializationKind());
+ if (auto P = D->getInstantiatedFrom()) {
+ if (auto *CTD = P.dyn_cast<ClassTemplateDecl *>()) {
+ if (auto CTDorErr = import(CTD))
+ D2->setInstantiationOf(*CTDorErr);
+ } else {
+ auto *CTPSD = cast<ClassTemplatePartialSpecializationDecl *>(P);
+ auto CTPSDOrErr = import(CTPSD);
+ if (!CTPSDOrErr)
+ return CTPSDOrErr.takeError();
+ const TemplateArgumentList &DArgs = D->getTemplateInstantiationArgs();
+ SmallVector<TemplateArgument, 2> D2ArgsVec(DArgs.size());
+ for (unsigned I = 0; I < DArgs.size(); ++I) {
+ const TemplateArgument &DArg = DArgs[I];
+ if (auto ArgOrErr = import(DArg))
+ D2ArgsVec[I] = *ArgOrErr;
+ else
+ return ArgOrErr.takeError();
+ }
+ D2->setInstantiationOf(
+ *CTPSDOrErr,
+ TemplateArgumentList::CreateCopy(Importer.getToContext(), D2ArgsVec));
+ }
+ }
+
if (D->isCompleteDefinition())
if (Error Err = ImportDefinition(D, D2))
return std::move(Err);
@@ -6020,8 +6155,8 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
// Import template arguments.
SmallVector<TemplateArgument, 2> TemplateArgs;
- if (Error Err = ImportTemplateArguments(
- D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs))
+ if (Error Err =
+ ImportTemplateArguments(D->getTemplateArgs().asArray(), TemplateArgs))
return std::move(Err);
// Try to find an existing specialization with these template arguments.
@@ -6044,15 +6179,6 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
}
}
} else {
- // Import the type.
- QualType T;
- if (Error Err = importInto(T, D->getType()))
- return std::move(Err);
-
- auto TInfoOrErr = import(D->getTypeSourceInfo());
- if (!TInfoOrErr)
- return TInfoOrErr.takeError();
-
TemplateArgumentListInfo ToTAInfo;
if (const ASTTemplateArgumentListInfo *Args = D->getTemplateArgsInfo()) {
if (Error Err = ImportTemplateArgumentListInfo(*Args, ToTAInfo))
@@ -6077,7 +6203,7 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
PartVarSpecDecl *ToPartial;
if (GetImportedOrCreateDecl(ToPartial, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr,
- VarTemplate, T, *TInfoOrErr,
+ VarTemplate, QualType(), nullptr,
D->getStorageClass(), TemplateArgs, ArgInfos))
return ToPartial;
@@ -6098,11 +6224,21 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateSpecializationDecl(
} else { // Full specialization
if (GetImportedOrCreateDecl(D2, D, Importer.getToContext(), DC,
*BeginLocOrErr, *IdLocOrErr, VarTemplate,
- T, *TInfoOrErr,
- D->getStorageClass(), TemplateArgs))
+ QualType(), nullptr, D->getStorageClass(),
+ TemplateArgs))
return D2;
}
+ QualType T;
+ if (Error Err = importInto(T, D->getType()))
+ return std::move(Err);
+ D2->setType(T);
+
+ auto TInfoOrErr = import(D->getTypeSourceInfo());
+ if (!TInfoOrErr)
+ return TInfoOrErr.takeError();
+ D2->setTypeSourceInfo(*TInfoOrErr);
+
if (D->getPointOfInstantiation().isValid()) {
if (ExpectedSLoc POIOrErr = import(D->getPointOfInstantiation()))
D2->setPointOfInstantiation(*POIOrErr);
@@ -6875,14 +7011,14 @@ ASTNodeImporter::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
const ASTContext &ToCtx = Importer.getToContext();
if (E->isResultDependent()) {
return GenericSelectionExpr::Create(
- ToCtx, ToGenericLoc, ToControllingExpr,
- llvm::makeArrayRef(ToAssocTypes), llvm::makeArrayRef(ToAssocExprs),
- ToDefaultLoc, ToRParenLoc, E->containsUnexpandedParameterPack());
+ ToCtx, ToGenericLoc, ToControllingExpr, llvm::ArrayRef(ToAssocTypes),
+ llvm::ArrayRef(ToAssocExprs), ToDefaultLoc, ToRParenLoc,
+ E->containsUnexpandedParameterPack());
}
return GenericSelectionExpr::Create(
- ToCtx, ToGenericLoc, ToControllingExpr, llvm::makeArrayRef(ToAssocTypes),
- llvm::makeArrayRef(ToAssocExprs), ToDefaultLoc, ToRParenLoc,
+ ToCtx, ToGenericLoc, ToControllingExpr, llvm::ArrayRef(ToAssocTypes),
+ llvm::ArrayRef(ToAssocExprs), ToDefaultLoc, ToRParenLoc,
E->containsUnexpandedParameterPack(), E->getResultIndex());
}
@@ -7224,7 +7360,7 @@ ExpectedStmt ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) {
return BinaryOperator::Create(
Importer.getToContext(), ToLHS, ToRHS, E->getOpcode(), ToType,
E->getValueKind(), E->getObjectKind(), ToOperatorLoc,
- E->getFPFeatures(Importer.getFromContext().getLangOpts()));
+ E->getFPFeatures());
}
ExpectedStmt ASTNodeImporter::VisitConditionalOperator(ConditionalOperator *E) {
@@ -7335,7 +7471,7 @@ ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
return CompoundAssignOperator::Create(
Importer.getToContext(), ToLHS, ToRHS, E->getOpcode(), ToType,
E->getValueKind(), E->getObjectKind(), ToOperatorLoc,
- E->getFPFeatures(Importer.getFromContext().getLangOpts()),
+ E->getFPFeatures(),
ToComputationLHSType, ToComputationResultType);
}
@@ -7544,15 +7680,23 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
// see VisitParmVarDecl).
ParmVarDecl *ToParam = *ToParamOrErr;
if (!ToParam->getDefaultArg()) {
- Optional<ParmVarDecl *> FromParam = Importer.getImportedFromDecl(ToParam);
+ std::optional<ParmVarDecl *> FromParam =
+ Importer.getImportedFromDecl(ToParam);
assert(FromParam && "ParmVarDecl was not imported?");
if (Error Err = ImportDefaultArgOfParmVarDecl(*FromParam, ToParam))
return std::move(Err);
}
-
+ Expr *RewrittenInit = nullptr;
+ if (E->hasRewrittenInit()) {
+ ExpectedExpr ExprOrErr = import(E->getRewrittenExpr());
+ if (!ExprOrErr)
+ return ExprOrErr.takeError();
+ RewrittenInit = ExprOrErr.get();
+ }
return CXXDefaultArgExpr::Create(Importer.getToContext(), *ToUsedLocOrErr,
- *ToParamOrErr, *UsedContextOrErr);
+ *ToParamOrErr, RewrittenInit,
+ *UsedContextOrErr);
}
ExpectedStmt
@@ -7670,16 +7814,14 @@ ExpectedStmt ASTNodeImporter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
if (Err)
return std::move(Err);
- Optional<unsigned> Length;
+ std::optional<unsigned> Length;
if (!E->isValueDependent())
Length = E->getPackLength();
SmallVector<TemplateArgument, 8> ToPartialArguments;
if (E->isPartiallySubstituted()) {
- if (Error Err = ImportTemplateArguments(
- E->getPartialArguments().data(),
- E->getPartialArguments().size(),
- ToPartialArguments))
+ if (Error Err = ImportTemplateArguments(E->getPartialArguments(),
+ ToPartialArguments))
return std::move(Err);
}
@@ -7806,8 +7948,8 @@ ExpectedStmt ASTNodeImporter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) {
if (!ToLocationOrErr)
return ToLocationOrErr.takeError();
- return new (Importer.getToContext()) CXXBoolLiteralExpr(
- E->getValue(), *ToTypeOrErr, *ToLocationOrErr);
+ return CXXBoolLiteralExpr::Create(Importer.getToContext(), E->getValue(),
+ *ToTypeOrErr, *ToLocationOrErr);
}
ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) {
@@ -7969,7 +8111,7 @@ ExpectedStmt ASTNodeImporter::VisitCXXUnresolvedConstructExpr(
return CXXUnresolvedConstructExpr::Create(
Importer.getToContext(), ToType, ToTypeSourceInfo, ToLParenLoc,
- llvm::makeArrayRef(ToArgs), ToRParenLoc);
+ llvm::ArrayRef(ToArgs), ToRParenLoc);
}
ExpectedStmt
@@ -8246,8 +8388,16 @@ ExpectedStmt ASTNodeImporter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
ToField->setInClassInitializer(*ToInClassInitializerOrErr);
}
+ Expr *RewrittenInit = nullptr;
+ if (E->hasRewrittenInit()) {
+ ExpectedExpr ExprOrErr = import(E->getRewrittenExpr());
+ if (!ExprOrErr)
+ return ExprOrErr.takeError();
+ RewrittenInit = ExprOrErr.get();
+ }
+
return CXXDefaultInitExpr::Create(Importer.getToContext(), *ToBeginLocOrErr,
- ToField, *UsedContextOrErr);
+ ToField, *UsedContextOrErr, RewrittenInit);
}
ExpectedStmt ASTNodeImporter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
@@ -8295,14 +8445,14 @@ ExpectedStmt ASTNodeImporter::VisitSubstNonTypeTemplateParmExpr(
Error Err = Error::success();
auto ToType = importChecked(Err, E->getType());
auto ToExprLoc = importChecked(Err, E->getExprLoc());
- auto ToParameter = importChecked(Err, E->getParameter());
+ auto ToAssociatedDecl = importChecked(Err, E->getAssociatedDecl());
auto ToReplacement = importChecked(Err, E->getReplacement());
if (Err)
return std::move(Err);
return new (Importer.getToContext()) SubstNonTypeTemplateParmExpr(
- ToType, E->getValueKind(), ToExprLoc, ToParameter,
- E->isReferenceParameter(), ToReplacement);
+ ToType, E->getValueKind(), ToExprLoc, ToReplacement, ToAssociatedDecl,
+ E->getIndex(), E->getPackIndex(), E->isReferenceParameter());
}
ExpectedStmt ASTNodeImporter::VisitTypeTraitExpr(TypeTraitExpr *E) {
@@ -8403,13 +8553,13 @@ ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
ASTImporter::~ASTImporter() = default;
-Optional<unsigned> ASTImporter::getFieldIndex(Decl *F) {
+std::optional<unsigned> ASTImporter::getFieldIndex(Decl *F) {
assert(F && (isa<FieldDecl>(*F) || isa<IndirectFieldDecl>(*F)) &&
"Try to get field index for non-field.");
auto *Owner = dyn_cast<RecordDecl>(F->getDeclContext());
if (!Owner)
- return None;
+ return std::nullopt;
unsigned Index = 0;
for (const auto *D : Owner->decls()) {
@@ -8422,7 +8572,7 @@ Optional<unsigned> ASTImporter::getFieldIndex(Decl *F) {
llvm_unreachable("Field was not found in its parent context.");
- return None;
+ return std::nullopt;
}
ASTImporter::FoundDeclsTy
@@ -8533,6 +8683,7 @@ Expected<TypeSourceInfo *> ASTImporter::Import(TypeSourceInfo *FromTSI) {
return ToContext.getTrivialTypeSourceInfo(*TOrErr, *BeginLocOrErr);
}
+namespace {
// To use this object, it should be created before the new attribute is created,
// and destructed after it is created. The construction already performs the
// import of the data.
@@ -8663,6 +8814,7 @@ public:
return ToAttr;
}
};
+} // namespace
Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) {
AttrImporter AI(*this);
@@ -9279,33 +9431,35 @@ Expected<TemplateName> ASTImporter::Import(TemplateName From) {
case TemplateName::SubstTemplateTemplateParm: {
SubstTemplateTemplateParmStorage *Subst =
From.getAsSubstTemplateTemplateParm();
- ExpectedDecl ParamOrErr = Import(Subst->getParameter());
- if (!ParamOrErr)
- return ParamOrErr.takeError();
-
auto ReplacementOrErr = Import(Subst->getReplacement());
if (!ReplacementOrErr)
return ReplacementOrErr.takeError();
+ auto AssociatedDeclOrErr = Import(Subst->getAssociatedDecl());
+ if (!AssociatedDeclOrErr)
+ return AssociatedDeclOrErr.takeError();
+
return ToContext.getSubstTemplateTemplateParm(
- cast<TemplateTemplateParmDecl>(*ParamOrErr), *ReplacementOrErr);
+ *ReplacementOrErr, *AssociatedDeclOrErr, Subst->getIndex(),
+ Subst->getPackIndex());
}
case TemplateName::SubstTemplateTemplateParmPack: {
- SubstTemplateTemplateParmPackStorage *SubstPack
- = From.getAsSubstTemplateTemplateParmPack();
- ExpectedDecl ParamOrErr = Import(SubstPack->getParameterPack());
- if (!ParamOrErr)
- return ParamOrErr.takeError();
-
+ SubstTemplateTemplateParmPackStorage *SubstPack =
+ From.getAsSubstTemplateTemplateParmPack();
ASTNodeImporter Importer(*this);
auto ArgPackOrErr =
Importer.ImportTemplateArgument(SubstPack->getArgumentPack());
if (!ArgPackOrErr)
return ArgPackOrErr.takeError();
+ auto AssociatedDeclOrErr = Import(SubstPack->getAssociatedDecl());
+ if (!AssociatedDeclOrErr)
+ return AssociatedDeclOrErr.takeError();
+
return ToContext.getSubstTemplateTemplateParmPack(
- cast<TemplateTemplateParmDecl>(*ParamOrErr), *ArgPackOrErr);
+ *ArgPackOrErr, *AssociatedDeclOrErr, SubstPack->getIndex(),
+ SubstPack->getFinal());
}
case TemplateName::UsingTemplate: {
auto UsingOrError = Import(From.getAsUsingShadowDecl());
@@ -9410,7 +9564,7 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
if (ToID.isInvalid() || IsBuiltin) {
// FIXME: We want to re-use the existing MemoryBuffer!
- llvm::Optional<llvm::MemoryBufferRef> FromBuf =
+ std::optional<llvm::MemoryBufferRef> FromBuf =
Cache->getBufferOrNone(FromContext.getDiagnostics(),
FromSM.getFileManager(), SourceLocation{});
if (!FromBuf)
@@ -9879,13 +10033,13 @@ Decl *ASTImporter::MapImported(Decl *From, Decl *To) {
return To;
}
-llvm::Optional<ASTImportError>
+std::optional<ASTImportError>
ASTImporter::getImportDeclErrorIfAny(Decl *FromD) const {
auto Pos = ImportDeclErrors.find(FromD);
if (Pos != ImportDeclErrors.end())
return Pos->second;
else
- return Optional<ASTImportError>();
+ return std::nullopt;
}
void ASTImporter::setImportDeclError(Decl *From, ASTImportError Error) {
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index d80fc3ce7292..ba7dfc35edf2 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -84,13 +84,12 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
+#include <optional>
#include <utility>
using namespace clang;
@@ -103,6 +102,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const TemplateArgument &Arg1,
const TemplateArgument &Arg2);
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateArgumentLoc &Arg1,
+ const TemplateArgumentLoc &Arg2);
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
NestedNameSpecifier *NNS1,
NestedNameSpecifier *NNS2);
static bool IsStructurallyEquivalent(const IdentifierInfo *Name1,
@@ -238,8 +240,8 @@ class StmtComparer {
const GenericSelectionExpr *E2) {
for (auto Pair : zip_longest(E1->getAssocTypeSourceInfos(),
E2->getAssocTypeSourceInfos())) {
- Optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
- Optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
+ std::optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
+ std::optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
// Skip this case if there are a different number of associated types.
if (!Child1 || !Child2)
return false;
@@ -289,8 +291,14 @@ class StmtComparer {
bool IsStmtEquivalent(const SubstNonTypeTemplateParmExpr *E1,
const SubstNonTypeTemplateParmExpr *E2) {
- return IsStructurallyEquivalent(Context, E1->getParameter(),
- E2->getParameter());
+ if (!IsStructurallyEquivalent(Context, E1->getAssociatedDecl(),
+ E2->getAssociatedDecl()))
+ return false;
+ if (E1->getIndex() != E2->getIndex())
+ return false;
+ if (E1->getPackIndex() != E2->getPackIndex())
+ return false;
+ return true;
}
bool IsStmtEquivalent(const SubstNonTypeTemplateParmPackExpr *E1,
@@ -304,8 +312,8 @@ class StmtComparer {
return false;
for (auto Pair : zip_longest(E1->getArgs(), E2->getArgs())) {
- Optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
- Optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
+ std::optional<TypeSourceInfo *> Child1 = std::get<0>(Pair);
+ std::optional<TypeSourceInfo *> Child2 = std::get<1>(Pair);
// Different number of args.
if (!Child1 || !Child2)
return false;
@@ -334,6 +342,30 @@ class StmtComparer {
return true;
}
+ bool IsStmtEquivalent(const OverloadExpr *E1, const OverloadExpr *E2) {
+ if (!IsStructurallyEquivalent(Context, E1->getName(), E2->getName()))
+ return false;
+
+ if (static_cast<bool>(E1->getQualifier()) !=
+ static_cast<bool>(E2->getQualifier()))
+ return false;
+ if (E1->getQualifier() &&
+ !IsStructurallyEquivalent(Context, E1->getQualifier(),
+ E2->getQualifier()))
+ return false;
+
+ if (E1->getNumTemplateArgs() != E2->getNumTemplateArgs())
+ return false;
+ const TemplateArgumentLoc *Args1 = E1->getTemplateArgs();
+ const TemplateArgumentLoc *Args2 = E2->getTemplateArgs();
+ for (unsigned int ArgI = 0, ArgN = E1->getNumTemplateArgs(); ArgI < ArgN;
+ ++ArgI)
+ if (!IsStructurallyEquivalent(Context, Args1[ArgI], Args2[ArgI]))
+ return false;
+
+ return true;
+ }
+
/// End point of the traversal chain.
bool TraverseStmt(const Stmt *S1, const Stmt *S2) { return true; }
@@ -394,8 +426,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
// Iterate over the children of both statements and also compare them.
for (auto Pair : zip_longest(S1->children(), S2->children())) {
- Optional<const Stmt *> Child1 = std::get<0>(Pair);
- Optional<const Stmt *> Child2 = std::get<1>(Pair);
+ std::optional<const Stmt *> Child1 = std::get<0>(Pair);
+ std::optional<const Stmt *> Child2 = std::get<1>(Pair);
// One of the statements has a different amount of children than the other,
// so the statements can't be equivalent.
if (!Child1 || !Child2)
@@ -510,8 +542,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
*P2 = N2.getAsSubstTemplateTemplateParmPack();
return IsStructurallyEquivalent(Context, P1->getArgumentPack(),
P2->getArgumentPack()) &&
- IsStructurallyEquivalent(Context, P1->getParameterPack(),
- P2->getParameterPack());
+ IsStructurallyEquivalent(Context, P1->getAssociatedDecl(),
+ P2->getAssociatedDecl()) &&
+ P1->getIndex() == P2->getIndex();
}
case TemplateName::Template:
@@ -526,6 +559,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return true;
}
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ ArrayRef<TemplateArgument> Args1,
+ ArrayRef<TemplateArgument> Args2);
+
/// Determine whether two template arguments are equivalent.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const TemplateArgument &Arg1,
@@ -568,18 +605,32 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Arg2.getAsExpr());
case TemplateArgument::Pack:
- if (Arg1.pack_size() != Arg2.pack_size())
- return false;
+ return IsStructurallyEquivalent(Context, Arg1.pack_elements(),
+ Arg2.pack_elements());
+ }
- for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I)
- if (!IsStructurallyEquivalent(Context, Arg1.pack_begin()[I],
- Arg2.pack_begin()[I]))
- return false;
+ llvm_unreachable("Invalid template argument kind");
+}
- return true;
+/// Determine structural equivalence of two template argument lists.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ ArrayRef<TemplateArgument> Args1,
+ ArrayRef<TemplateArgument> Args2) {
+ if (Args1.size() != Args2.size())
+ return false;
+ for (unsigned I = 0, N = Args1.size(); I != N; ++I) {
+ if (!IsStructurallyEquivalent(Context, Args1[I], Args2[I]))
+ return false;
}
+ return true;
+}
- llvm_unreachable("Invalid template argument kind");
+/// Determine whether two template argument locations are equivalent.
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ const TemplateArgumentLoc &Arg1,
+ const TemplateArgumentLoc &Arg2) {
+ return IsStructurallyEquivalent(Context, Arg1.getArgument(),
+ Arg2.getArgument());
}
/// Determine structural equivalence for the common part of array
@@ -900,7 +951,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
// Fall through to check the bits common with FunctionNoProtoType.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case Type::FunctionNoProto: {
@@ -957,11 +1008,17 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, cast<UsingType>(T1)->getFoundDecl(),
cast<UsingType>(T2)->getFoundDecl()))
return false;
+ if (!IsStructurallyEquivalent(Context,
+ cast<UsingType>(T1)->getUnderlyingType(),
+ cast<UsingType>(T2)->getUnderlyingType()))
+ return false;
break;
case Type::Typedef:
if (!IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->getDecl(),
- cast<TypedefType>(T2)->getDecl()))
+ cast<TypedefType>(T2)->getDecl()) ||
+ !IsStructurallyEquivalent(Context, cast<TypedefType>(T1)->desugar(),
+ cast<TypedefType>(T2)->desugar()))
return false;
break;
@@ -974,8 +1031,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
case Type::TypeOf:
if (!IsStructurallyEquivalent(Context,
- cast<TypeOfType>(T1)->getUnderlyingType(),
- cast<TypeOfType>(T2)->getUnderlyingType()))
+ cast<TypeOfType>(T1)->getUnmodifiedType(),
+ cast<TypeOfType>(T2)->getUnmodifiedType()))
return false;
break;
@@ -1005,16 +1062,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (Auto1->getTypeConstraintConcept() !=
Auto2->getTypeConstraintConcept())
return false;
- ArrayRef<TemplateArgument> Auto1Args =
- Auto1->getTypeConstraintArguments();
- ArrayRef<TemplateArgument> Auto2Args =
- Auto2->getTypeConstraintArguments();
- if (Auto1Args.size() != Auto2Args.size())
+ if (!IsStructurallyEquivalent(Context,
+ Auto1->getTypeConstraintArguments(),
+ Auto2->getTypeConstraintArguments()))
return false;
- for (unsigned I = 0, N = Auto1Args.size(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Auto1Args[I], Auto2Args[I]))
- return false;
- }
}
break;
}
@@ -1055,22 +1106,26 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
case Type::SubstTemplateTypeParm: {
const auto *Subst1 = cast<SubstTemplateTypeParmType>(T1);
const auto *Subst2 = cast<SubstTemplateTypeParmType>(T2);
- if (!IsStructurallyEquivalent(Context,
- QualType(Subst1->getReplacedParameter(), 0),
- QualType(Subst2->getReplacedParameter(), 0)))
- return false;
if (!IsStructurallyEquivalent(Context, Subst1->getReplacementType(),
Subst2->getReplacementType()))
return false;
+ if (!IsStructurallyEquivalent(Context, Subst1->getAssociatedDecl(),
+ Subst2->getAssociatedDecl()))
+ return false;
+ if (Subst1->getIndex() != Subst2->getIndex())
+ return false;
+ if (Subst1->getPackIndex() != Subst2->getPackIndex())
+ return false;
break;
}
case Type::SubstTemplateTypeParmPack: {
const auto *Subst1 = cast<SubstTemplateTypeParmPackType>(T1);
const auto *Subst2 = cast<SubstTemplateTypeParmPackType>(T2);
- if (!IsStructurallyEquivalent(Context,
- QualType(Subst1->getReplacedParameter(), 0),
- QualType(Subst2->getReplacedParameter(), 0)))
+ if (!IsStructurallyEquivalent(Context, Subst1->getAssociatedDecl(),
+ Subst2->getAssociatedDecl()))
+ return false;
+ if (Subst1->getIndex() != Subst2->getIndex())
return false;
if (!IsStructurallyEquivalent(Context, Subst1->getArgumentPack(),
Subst2->getArgumentPack()))
@@ -1084,13 +1139,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Context, Spec1->getTemplateName(),
Spec2->getTemplateName()))
return false;
- if (Spec1->getNumArgs() != Spec2->getNumArgs())
+ if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(),
+ Spec2->template_arguments()))
return false;
- for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
- Spec2->getArg(I)))
- return false;
- }
break;
}
@@ -1141,13 +1192,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!IsStructurallyEquivalent(Spec1->getIdentifier(),
Spec2->getIdentifier()))
return false;
- if (Spec1->getNumArgs() != Spec2->getNumArgs())
+ if (!IsStructurallyEquivalent(Context, Spec1->template_arguments(),
+ Spec2->template_arguments()))
return false;
- for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) {
- if (!IsStructurallyEquivalent(Context, Spec1->getArg(I),
- Spec2->getArg(I)))
- return false;
- }
break;
}
@@ -1434,9 +1481,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (!D1->getDeclName() && !D2->getDeclName()) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
- if (Optional<unsigned> Index1 =
+ if (std::optional<unsigned> Index1 =
StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(D1)) {
- if (Optional<unsigned> Index2 =
+ if (std::optional<unsigned> Index2 =
StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(
D2)) {
if (*Index1 != *Index2)
@@ -2108,14 +2155,14 @@ DiagnosticBuilder StructuralEquivalenceContext::Diag2(SourceLocation Loc,
return ToCtx.getDiagnostics().Report(Loc, DiagID);
}
-Optional<unsigned>
+std::optional<unsigned>
StructuralEquivalenceContext::findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
ASTContext &Context = Anon->getASTContext();
QualType AnonTy = Context.getRecordType(Anon);
const auto *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
if (!Owner)
- return None;
+ return std::nullopt;
unsigned Index = 0;
for (const auto *D : Owner->noload_decls()) {
diff --git a/clang/lib/AST/AttrDocTable.cpp b/clang/lib/AST/AttrDocTable.cpp
index 3bfedac8b8f1..df7e3d63a6c3 100644
--- a/clang/lib/AST/AttrDocTable.cpp
+++ b/clang/lib/AST/AttrDocTable.cpp
@@ -21,7 +21,7 @@ static const llvm::StringRef AttrDoc[] = {
};
llvm::StringRef clang::Attr::getDocumentation(clang::attr::Kind K) {
- if(K < llvm::array_lengthof(AttrDoc))
+ if (K < std::size(AttrDoc))
return AttrDoc[K];
return "";
}
diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp
index deb28bee5ed8..0adcca7731d9 100644
--- a/clang/lib/AST/AttrImpl.cpp
+++ b/clang/lib/AST/AttrImpl.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
+#include <optional>
using namespace clang;
void LoopHintAttr::printPrettyPragma(raw_ostream &OS,
@@ -137,7 +138,7 @@ void OMPDeclareTargetDeclAttr::printPrettyPragma(
// Use fake syntax because it is for testing and debugging purpose only.
if (getDevType() != DT_Any)
OS << " device_type(" << ConvertDevTypeTyToStr(getDevType()) << ")";
- if (getMapType() != MT_To)
+ if (getMapType() != MT_To && getMapType() != MT_Enter)
OS << ' ' << ConvertMapTypeTyToStr(getMapType());
if (Expr *E = getIndirectExpr()) {
OS << " indirect(";
@@ -148,10 +149,10 @@ void OMPDeclareTargetDeclAttr::printPrettyPragma(
}
}
-llvm::Optional<OMPDeclareTargetDeclAttr *>
+std::optional<OMPDeclareTargetDeclAttr *>
OMPDeclareTargetDeclAttr::getActiveAttr(const ValueDecl *VD) {
if (!VD->hasAttrs())
- return llvm::None;
+ return std::nullopt;
unsigned Level = 0;
OMPDeclareTargetDeclAttr *FoundAttr = nullptr;
for (auto *Attr : VD->specific_attrs<OMPDeclareTargetDeclAttr>()) {
@@ -162,31 +163,31 @@ OMPDeclareTargetDeclAttr::getActiveAttr(const ValueDecl *VD) {
}
if (FoundAttr)
return FoundAttr;
- return llvm::None;
+ return std::nullopt;
}
-llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy>
+std::optional<OMPDeclareTargetDeclAttr::MapTypeTy>
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(const ValueDecl *VD) {
- llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
+ std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
if (ActiveAttr)
- return ActiveAttr.value()->getMapType();
- return llvm::None;
+ return (*ActiveAttr)->getMapType();
+ return std::nullopt;
}
-llvm::Optional<OMPDeclareTargetDeclAttr::DevTypeTy>
+std::optional<OMPDeclareTargetDeclAttr::DevTypeTy>
OMPDeclareTargetDeclAttr::getDeviceType(const ValueDecl *VD) {
- llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
+ std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
if (ActiveAttr)
- return ActiveAttr.value()->getDevType();
- return llvm::None;
+ return (*ActiveAttr)->getDevType();
+ return std::nullopt;
}
-llvm::Optional<SourceLocation>
+std::optional<SourceLocation>
OMPDeclareTargetDeclAttr::getLocation(const ValueDecl *VD) {
- llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
+ std::optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
if (ActiveAttr)
- return ActiveAttr.value()->getRange().getBegin();
- return llvm::None;
+ return (*ActiveAttr)->getRange().getBegin();
+ return std::nullopt;
}
namespace clang {
@@ -222,18 +223,18 @@ void OMPDeclareVariantAttr::printPrettyPragma(
OS << ")";
}
- auto PrintInteropTypes = [&OS](InteropType *Begin, InteropType *End) {
- for (InteropType *I = Begin; I != End; ++I) {
+ auto PrintInteropInfo = [&OS](OMPInteropInfo *Begin, OMPInteropInfo *End) {
+ for (OMPInteropInfo *I = Begin; I != End; ++I) {
if (I != Begin)
OS << ", ";
OS << "interop(";
- OS << ConvertInteropTypeToStr(*I);
+ OS << getInteropTypeString(I);
OS << ")";
}
};
if (appendArgs_size()) {
OS << " append_args(";
- PrintInteropTypes(appendArgs_begin(), appendArgs_end());
+ PrintInteropInfo(appendArgs_begin(), appendArgs_end());
OS << ")";
}
}
diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp
index 96a6f344be7c..1abbe8139ae9 100644
--- a/clang/lib/AST/CXXInheritance.cpp
+++ b/clang/lib/AST/CXXInheritance.cpp
@@ -22,7 +22,6 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Casting.h"
diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp
index 43820fc566e4..2bb6bb5cbcb6 100644
--- a/clang/lib/AST/Comment.cpp
+++ b/clang/lib/AST/Comment.cpp
@@ -29,7 +29,7 @@ namespace comments {
#undef ABSTRACT_COMMENT
// DeclInfo is also allocated with a BumpPtrAllocator.
-static_assert(std::is_trivially_destructible<DeclInfo>::value,
+static_assert(std::is_trivially_destructible_v<DeclInfo>,
"DeclInfo should be trivially destructible!");
const char *Comment::getCommentKindName() const {
@@ -206,7 +206,7 @@ void DeclInfo::fill() {
IsInstanceMethod = false;
IsClassMethod = false;
IsVariadic = false;
- ParamVars = None;
+ ParamVars = std::nullopt;
TemplateParameters = nullptr;
if (!CommentDecl) {
@@ -301,7 +301,7 @@ void DeclInfo::fill() {
TemplateKind = TemplateSpecialization;
TemplateParameters = VTD->getTemplateParameters();
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Decl::Field:
case Decl::EnumConstant:
case Decl::ObjCIvar:
diff --git a/clang/lib/AST/CommentCommandTraits.cpp b/clang/lib/AST/CommentCommandTraits.cpp
index bdc0dd47fb7d..a37a0e18432c 100644
--- a/clang/lib/AST/CommentCommandTraits.cpp
+++ b/clang/lib/AST/CommentCommandTraits.cpp
@@ -16,8 +16,8 @@ namespace comments {
#include "clang/AST/CommentCommandInfo.inc"
CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator,
- const CommentOptions &CommentOptions) :
- NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) {
+ const CommentOptions &CommentOptions)
+ : NextID(std::size(Commands)), Allocator(Allocator) {
registerCommentOptions(CommentOptions);
}
@@ -115,7 +115,7 @@ const CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) {
const CommandInfo *CommandTraits::getBuiltinCommandInfo(
unsigned CommandID) {
- if (CommandID < llvm::array_lengthof(Commands))
+ if (CommandID < std::size(Commands))
return &Commands[CommandID];
return nullptr;
}
@@ -131,7 +131,7 @@ const CommandInfo *CommandTraits::getRegisteredCommandInfo(
const CommandInfo *CommandTraits::getRegisteredCommandInfo(
unsigned CommandID) const {
- return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)];
+ return RegisteredCommands[CommandID - std::size(Commands)];
}
} // end namespace comments
diff --git a/clang/lib/AST/CommentLexer.cpp b/clang/lib/AST/CommentLexer.cpp
index 61ce8979f13f..f0250fc9fd55 100644
--- a/clang/lib/AST/CommentLexer.cpp
+++ b/clang/lib/AST/CommentLexer.cpp
@@ -701,7 +701,7 @@ void Lexer::lexHTMLStartTag(Token &T) {
C = *BufferPtr;
if (!isHTMLIdentifierStartingCharacter(C) &&
- C != '=' && C != '\"' && C != '\'' && C != '>') {
+ C != '=' && C != '\"' && C != '\'' && C != '>' && C != '/') {
State = LS_Normal;
return;
}
diff --git a/clang/lib/AST/CommentParser.cpp b/clang/lib/AST/CommentParser.cpp
index 7bac1fb99b88..8adfd85d0160 100644
--- a/clang/lib/AST/CommentParser.cpp
+++ b/clang/lib/AST/CommentParser.cpp
@@ -245,7 +245,7 @@ public:
Pos.CurToken++;
}
- P.putBack(llvm::makeArrayRef(Toks.begin() + Pos.CurToken, Toks.end()));
+ P.putBack(llvm::ArrayRef(Toks.begin() + Pos.CurToken, Toks.end()));
Pos.CurToken = Toks.size();
if (HavePartialTok)
@@ -301,7 +301,7 @@ Parser::parseCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs) {
ParsedArgs++;
}
- return llvm::makeArrayRef(Args, ParsedArgs);
+ return llvm::ArrayRef(Args, ParsedArgs);
}
BlockCommandComment *Parser::parseBlockCommand() {
@@ -334,7 +334,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
if (isTokBlockCommand()) {
// Block command ahead. We can't nest block commands, so pretend that this
// command has an empty argument.
- ParagraphComment *Paragraph = S.actOnParagraphComment(None);
+ ParagraphComment *Paragraph = S.actOnParagraphComment(std::nullopt);
if (PC) {
S.actOnParamCommandFinish(PC, Paragraph);
return PC;
@@ -376,7 +376,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
ParagraphComment *Paragraph;
if (EmptyParagraph)
- Paragraph = S.actOnParagraphComment(None);
+ Paragraph = S.actOnParagraphComment(std::nullopt);
else {
BlockContentComment *Block = parseParagraphOrBlockCommand();
// Since we have checked for a block command, we should have parsed a
@@ -467,16 +467,14 @@ HTMLStartTagComment *Parser::parseHTMLStartTag() {
}
case tok::html_greater:
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
Tok.getLocation(),
/* IsSelfClosing = */ false);
consumeToken();
return HST;
case tok::html_slash_greater:
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
Tok.getLocation(),
/* IsSelfClosing = */ true);
consumeToken();
@@ -494,16 +492,14 @@ HTMLStartTagComment *Parser::parseHTMLStartTag() {
Tok.is(tok::html_slash_greater))
continue;
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
SourceLocation(),
/* IsSelfClosing = */ false);
return HST;
default:
// Not a token from an HTML start tag. Thus HTML tag prematurely ended.
- S.actOnHTMLStartTagFinish(HST,
- S.copyArray(llvm::makeArrayRef(Attrs)),
+ S.actOnHTMLStartTagFinish(HST, S.copyArray(llvm::ArrayRef(Attrs)),
SourceLocation(),
/* IsSelfClosing = */ false);
bool StartLineInvalid;
@@ -642,7 +638,7 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
break;
}
- return S.actOnParagraphComment(S.copyArray(llvm::makeArrayRef(Content)));
+ return S.actOnParagraphComment(S.copyArray(llvm::ArrayRef(Content)));
}
VerbatimBlockComment *Parser::parseVerbatimBlock() {
@@ -679,14 +675,13 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() {
if (Tok.is(tok::verbatim_block_end)) {
const CommandInfo *Info = Traits.getCommandInfo(Tok.getVerbatimBlockID());
- S.actOnVerbatimBlockFinish(VB, Tok.getLocation(),
- Info->Name,
- S.copyArray(llvm::makeArrayRef(Lines)));
+ S.actOnVerbatimBlockFinish(VB, Tok.getLocation(), Info->Name,
+ S.copyArray(llvm::ArrayRef(Lines)));
consumeToken();
} else {
// Unterminated \\verbatim block
S.actOnVerbatimBlockFinish(VB, SourceLocation(), "",
- S.copyArray(llvm::makeArrayRef(Lines)));
+ S.copyArray(llvm::ArrayRef(Lines)));
}
return VB;
@@ -762,7 +757,7 @@ FullComment *Parser::parseFullComment() {
while (Tok.is(tok::newline))
consumeToken();
}
- return S.actOnFullComment(S.copyArray(llvm::makeArrayRef(Blocks)));
+ return S.actOnFullComment(S.copyArray(llvm::ArrayRef(Blocks)));
}
} // end namespace comments
diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp
index 9b0f03445888..a4250c0b7cbb 100644
--- a/clang/lib/AST/CommentSema.cpp
+++ b/clang/lib/AST/CommentSema.cpp
@@ -267,7 +267,7 @@ void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
}
auto *A = new (Allocator)
Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
- Command->setArgs(llvm::makeArrayRef(A, 1));
+ Command->setArgs(llvm::ArrayRef(A, 1));
}
void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
@@ -303,7 +303,7 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
auto *A = new (Allocator)
Comment::Argument{SourceRange(ArgLocBegin, ArgLocEnd), Arg};
- Command->setArgs(llvm::makeArrayRef(A, 1));
+ Command->setArgs(llvm::ArrayRef(A, 1));
if (!isTemplateOrSpecialization()) {
// We already warned that this \\tparam is not attached to a template decl.
@@ -314,7 +314,7 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
ThisDeclInfo->TemplateParameters;
SmallVector<unsigned, 2> Position;
if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
- Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
+ Command->setPosition(copyArray(llvm::ArrayRef(Position)));
TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
if (PrevCommand) {
SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
diff --git a/clang/lib/AST/ComparisonCategories.cpp b/clang/lib/AST/ComparisonCategories.cpp
index a42960ad3c7f..58411201c3b0 100644
--- a/clang/lib/AST/ComparisonCategories.cpp
+++ b/clang/lib/AST/ComparisonCategories.cpp
@@ -17,10 +17,11 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
using namespace clang;
-Optional<ComparisonCategoryType>
+std::optional<ComparisonCategoryType>
clang::getComparisonCategoryForBuiltinCmp(QualType T) {
using CCT = ComparisonCategoryType;
@@ -37,7 +38,7 @@ clang::getComparisonCategoryForBuiltinCmp(QualType T) {
return CCT::StrongOrdering;
// TODO: Extend support for operator<=> to ObjC types.
- return llvm::None;
+ return std::nullopt;
}
bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const {
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 1f573346b441..eb9afbdb1c87 100644
--- a/clang/lib/AST/ComputeDependence.cpp
+++ b/clang/lib/AST/ComputeDependence.cpp
@@ -573,7 +573,7 @@ ExprDependence clang::computeDependence(RecoveryExpr *E) {
// - type-dependent if we don't know the type (fallback to an opaque
// dependent type), or the type is known and dependent, or it has
// type-dependent subexpressions.
- auto D = toExprDependenceForImpliedType(E->getType()->getDependence()) |
+ auto D = toExprDependenceAsWritten(E->getType()->getDependence()) |
ExprDependence::ErrorDependent;
// FIXME: remove the type-dependent bit from subexpressions, if the
// RecoveryExpr has a non-dependent type.
@@ -594,7 +594,7 @@ ExprDependence clang::computeDependence(PredefinedExpr *E) {
ExprDependence clang::computeDependence(CallExpr *E,
llvm::ArrayRef<Expr *> PreArgs) {
auto D = E->getCallee()->getDependence();
- for (auto *A : llvm::makeArrayRef(E->getArgs(), E->getNumArgs())) {
+ for (auto *A : llvm::ArrayRef(E->getArgs(), E->getNumArgs())) {
if (A)
D |= A->getDependence();
}
@@ -642,7 +642,7 @@ ExprDependence clang::computeDependence(InitListExpr *E) {
ExprDependence clang::computeDependence(ShuffleVectorExpr *E) {
auto D = toExprDependenceForImpliedType(E->getType()->getDependence());
- for (auto *C : llvm::makeArrayRef(E->getSubExprs(), E->getNumSubExprs()))
+ for (auto *C : llvm::ArrayRef(E->getSubExprs(), E->getNumSubExprs()))
D |= C->getDependence();
return D;
}
@@ -686,7 +686,7 @@ ExprDependence clang::computeDependence(PseudoObjectExpr *O) {
ExprDependence clang::computeDependence(AtomicExpr *A) {
auto D = ExprDependence::None;
- for (auto *E : llvm::makeArrayRef(A->getSubExprs(), A->getNumSubExprs()))
+ for (auto *E : llvm::ArrayRef(A->getSubExprs(), A->getNumSubExprs()))
D |= E->getDependence();
return D;
}
@@ -831,6 +831,13 @@ ExprDependence clang::computeDependence(CXXFoldExpr *E) {
return D;
}
+ExprDependence clang::computeDependence(CXXParenListInitExpr *E) {
+ auto D = ExprDependence::None;
+ for (const auto *A : E->getInitExprs())
+ D |= A->getDependence();
+ return D;
+}
+
ExprDependence clang::computeDependence(TypeTraitExpr *E) {
auto D = ExprDependence::None;
for (const auto *A : E->getArgs())
@@ -853,7 +860,10 @@ ExprDependence clang::computeDependence(ConceptSpecializationExpr *E,
ExprDependence D =
ValueDependent ? ExprDependence::Value : ExprDependence::None;
- return D | toExprDependence(TA);
+ auto Res = D | toExprDependence(TA);
+ if(!ValueDependent && E->getSatisfaction().ContainsErrors)
+ Res |= ExprDependence::Error;
+ return Res;
}
ExprDependence clang::computeDependence(ObjCArrayLiteral *E) {
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index aaba4345587b..e60cc28f6e0f 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -54,8 +54,6 @@
#include "clang/Basic/Visibility.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
@@ -69,6 +67,7 @@
#include <cstddef>
#include <cstring>
#include <memory>
+#include <optional>
#include <string>
#include <tuple>
#include <type_traits>
@@ -170,8 +169,8 @@ withExplicitVisibilityAlready(LVComputationKind Kind) {
return Kind;
}
-static Optional<Visibility> getExplicitVisibility(const NamedDecl *D,
- LVComputationKind kind) {
+static std::optional<Visibility> getExplicitVisibility(const NamedDecl *D,
+ LVComputationKind kind) {
assert(!kind.IgnoreExplicitVisibility &&
"asking for explicit visibility when we shouldn't be");
return D->getExplicitVisibility(kind.getExplicitVisibilityKind());
@@ -187,8 +186,8 @@ static bool usesTypeVisibility(const NamedDecl *D) {
/// Does the given declaration have member specialization information,
/// and if so, is it an explicit specialization?
-template <class T> static typename
-std::enable_if<!std::is_base_of<RedeclarableTemplateDecl, T>::value, bool>::type
+template <class T>
+static std::enable_if_t<!std::is_base_of_v<RedeclarableTemplateDecl, T>, bool>
isExplicitMemberSpecialization(const T *D) {
if (const MemberSpecializationInfo *member =
D->getMemberSpecializationInfo()) {
@@ -220,8 +219,8 @@ static Visibility getVisibilityFromAttr(const T *attr) {
}
/// Return the explicit visibility of the given declaration.
-static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
- NamedDecl::ExplicitVisibilityKind kind) {
+static std::optional<Visibility>
+getVisibilityOf(const NamedDecl *D, NamedDecl::ExplicitVisibilityKind kind) {
// If we're ultimately computing the visibility of a type, look for
// a 'type_visibility' attribute before looking for 'visibility'.
if (kind == NamedDecl::VisibilityForType) {
@@ -235,7 +234,7 @@ static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
return getVisibilityFromAttr(A);
}
- return None;
+ return std::nullopt;
}
LinkageInfo LinkageComputer::getLVForType(const Type &T,
@@ -729,7 +728,7 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
LinkageInfo LV = getExternalLinkageFor(D);
if (!hasExplicitVisibilityAlready(computation)) {
- if (Optional<Visibility> Vis = getExplicitVisibility(D, computation)) {
+ if (std::optional<Visibility> Vis = getExplicitVisibility(D, computation)) {
LV.mergeVisibility(*Vis, true);
} else {
// If we're declared in a namespace with a visibility attribute,
@@ -739,7 +738,8 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
DC = DC->getParent()) {
const auto *ND = dyn_cast<NamespaceDecl>(DC);
if (!ND) continue;
- if (Optional<Visibility> Vis = getExplicitVisibility(ND, computation)) {
+ if (std::optional<Visibility> Vis =
+ getExplicitVisibility(ND, computation)) {
LV.mergeVisibility(*Vis, true);
break;
}
@@ -834,6 +834,15 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Function->getStorageClass() == SC_PrivateExtern)
LV.mergeVisibility(HiddenVisibility, true);
+ // OpenMP target declare device functions are not callable from the host so
+ // they should not be exported from the device image. This applies to all
+ // functions as the host-callable kernel functions are emitted at codegen.
+ if (Context.getLangOpts().OpenMP && Context.getLangOpts().OpenMPIsDevice &&
+ ((Context.getTargetInfo().getTriple().isAMDGPU() ||
+ Context.getTargetInfo().getTriple().isNVPTX()) ||
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(Function)))
+ LV.mergeVisibility(HiddenVisibility, /*newExplicit=*/false);
+
// Note that Sema::MergeCompatibleFunctionDecls already takes care of
// merging storage classes and visibility attributes, so we don't have to
// look at previous decls in here.
@@ -956,7 +965,7 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D,
// If we have an explicit visibility attribute, merge that in.
if (!hasExplicitVisibilityAlready(computation)) {
- if (Optional<Visibility> Vis = getExplicitVisibility(D, computation))
+ if (std::optional<Visibility> Vis = getExplicitVisibility(D, computation))
LV.mergeVisibility(*Vis, true);
// If we're paying attention to global visibility, apply
// -finline-visibility-hidden if this is an inline method.
@@ -1012,6 +1021,16 @@ LinkageComputer::getLVForClassMember(const NamedDecl *D,
explicitSpecSuppressor = MD;
}
+ // OpenMP target declare device functions are not callable from the host so
+ // they should not be exported from the device image. This applies to all
+ // functions as the host-callable kernel functions are emitted at codegen.
+ ASTContext &Context = D->getASTContext();
+ if (Context.getLangOpts().OpenMP && Context.getLangOpts().OpenMPIsDevice &&
+ ((Context.getTargetInfo().getTriple().isAMDGPU() ||
+ Context.getTargetInfo().getTriple().isNVPTX()) ||
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(MD)))
+ LV.mergeVisibility(HiddenVisibility, /*newExplicit=*/false);
+
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(D)) {
if (const auto *spec = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
mergeTemplateLV(LV, spec, computation);
@@ -1158,14 +1177,14 @@ LinkageInfo NamedDecl::getLinkageAndVisibility() const {
return LinkageComputer{}.getDeclLinkageAndVisibility(this);
}
-static Optional<Visibility>
+static std::optional<Visibility>
getExplicitVisibilityAux(const NamedDecl *ND,
NamedDecl::ExplicitVisibilityKind kind,
bool IsMostRecent) {
assert(!IsMostRecent || ND == ND->getMostRecentDecl());
// Check the declaration itself first.
- if (Optional<Visibility> V = getVisibilityOf(ND, kind))
+ if (std::optional<Visibility> V = getVisibilityOf(ND, kind))
return V;
// If this is a member class of a specialization of a class template
@@ -1185,11 +1204,11 @@ getExplicitVisibilityAux(const NamedDecl *ND,
const auto *TD = spec->getSpecializedTemplate()->getTemplatedDecl();
while (TD != nullptr) {
auto Vis = getVisibilityOf(TD, kind);
- if (Vis != None)
+ if (Vis != std::nullopt)
return Vis;
TD = TD->getPreviousDecl();
}
- return None;
+ return std::nullopt;
}
// Use the most recent declaration.
@@ -1210,7 +1229,7 @@ getExplicitVisibilityAux(const NamedDecl *ND,
return getVisibilityOf(VTSD->getSpecializedTemplate()->getTemplatedDecl(),
kind);
- return None;
+ return std::nullopt;
}
// Also handle function template specializations.
if (const auto *fn = dyn_cast<FunctionDecl>(ND)) {
@@ -1227,17 +1246,17 @@ getExplicitVisibilityAux(const NamedDecl *ND,
if (InstantiatedFrom)
return getVisibilityOf(InstantiatedFrom, kind);
- return None;
+ return std::nullopt;
}
// The visibility of a template is stored in the templated decl.
if (const auto *TD = dyn_cast<TemplateDecl>(ND))
return getVisibilityOf(TD->getTemplatedDecl(), kind);
- return None;
+ return std::nullopt;
}
-Optional<Visibility>
+std::optional<Visibility>
NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
return getExplicitVisibilityAux(this, kind, false);
}
@@ -1252,8 +1271,13 @@ LinkageInfo LinkageComputer::getLVForClosure(const DeclContext *DC,
else if (isa<ParmVarDecl>(ContextDecl))
Owner =
dyn_cast<NamedDecl>(ContextDecl->getDeclContext()->getRedeclContext());
- else
+ else if (isa<ImplicitConceptSpecializationDecl>(ContextDecl)) {
+ // Replace with the concept's owning decl, which is either a namespace or a
+ // TU, so this needs a dyn_cast.
+ Owner = dyn_cast<NamedDecl>(ContextDecl->getDeclContext());
+ } else {
Owner = cast<NamedDecl>(ContextDecl);
+ }
if (!Owner)
return LinkageInfo::none();
@@ -1289,7 +1313,7 @@ LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D,
LinkageInfo LV;
if (!hasExplicitVisibilityAlready(computation)) {
- if (Optional<Visibility> Vis =
+ if (std::optional<Visibility> Vis =
getExplicitVisibility(Function, computation))
LV.mergeVisibility(*Vis, true);
}
@@ -1310,7 +1334,8 @@ LinkageInfo LinkageComputer::getLVForLocalDecl(const NamedDecl *D,
if (Var->getStorageClass() == SC_PrivateExtern)
LV.mergeVisibility(HiddenVisibility, true);
else if (!hasExplicitVisibilityAlready(computation)) {
- if (Optional<Visibility> Vis = getExplicitVisibility(Var, computation))
+ if (std::optional<Visibility> Vis =
+ getExplicitVisibility(Var, computation))
LV.mergeVisibility(*Vis, true);
}
@@ -1505,7 +1530,7 @@ LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D,
if (computation.IgnoreAllVisibility && D->hasCachedLinkage())
return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
- if (llvm::Optional<LinkageInfo> LI = lookup(D, computation))
+ if (std::optional<LinkageInfo> LI = lookup(D, computation))
return *LI;
LinkageInfo LV = computeLVForDecl(D, computation);
@@ -1527,7 +1552,7 @@ LinkageInfo LinkageComputer::getLVForDecl(const NamedDecl *D,
// that all other computed linkages match, check that the one we just
// computed also does.
NamedDecl *Old = nullptr;
- for (auto I : D->redecls()) {
+ for (auto *I : D->redecls()) {
auto *T = cast<NamedDecl>(I);
if (T == D)
continue;
@@ -1601,8 +1626,12 @@ Module *Decl::getOwningModuleForLinkage(bool IgnoreLinkage) const {
llvm_unreachable("unknown module kind");
}
-void NamedDecl::printName(raw_ostream &os) const {
- os << Name;
+void NamedDecl::printName(raw_ostream &OS, const PrintingPolicy&) const {
+ OS << Name;
+}
+
+void NamedDecl::printName(raw_ostream &OS) const {
+ printName(OS, getASTContext().getPrintingPolicy());
}
std::string NamedDecl::getQualifiedNameAsString() const {
@@ -1620,7 +1649,7 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
const PrintingPolicy &P) const {
if (getDeclContext()->isFunctionOrMethod()) {
// We do not print '(anonymous)' for function parameters without name.
- printName(OS);
+ printName(OS, P);
return;
}
printNestedNameSpecifier(OS, P);
@@ -1631,7 +1660,7 @@ void NamedDecl::printQualifiedName(raw_ostream &OS,
// fall back to "(anonymous)".
SmallString<64> NameBuffer;
llvm::raw_svector_ostream NameOS(NameBuffer);
- printName(NameOS);
+ printName(NameOS, P);
if (NameBuffer.empty())
OS << "(anonymous)";
else
@@ -1754,7 +1783,7 @@ void NamedDecl::getNameForDiagnostic(raw_ostream &OS,
if (Qualified)
printQualifiedName(OS, Policy);
else
- printName(OS);
+ printName(OS, Policy);
}
template<typename T> static bool isRedeclarableImpl(Redeclarable<T> *) {
@@ -1825,7 +1854,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const {
// Check whether this is actually newer than OldD. We want to keep the
// newer declaration. This loop will usually only iterate once, because
// OldD is usually the previous declaration.
- for (auto D : redecls()) {
+ for (auto *D : redecls()) {
if (D == OldD)
break;
@@ -2273,7 +2302,7 @@ VarDecl *VarDecl::getActingDefinition() {
VarDecl *VarDecl::getDefinition(ASTContext &C) {
VarDecl *First = getFirstDecl();
- for (auto I : First->redecls()) {
+ for (auto *I : First->redecls()) {
if (I->isThisDeclarationADefinition(C) == Definition)
return I;
}
@@ -2284,7 +2313,7 @@ VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const {
DefinitionKind Kind = DeclarationOnly;
const VarDecl *First = getFirstDecl();
- for (auto I : First->redecls()) {
+ for (auto *I : First->redecls()) {
Kind = std::max(Kind, I->isThisDeclarationADefinition(C));
if (Kind == Definition)
break;
@@ -2294,7 +2323,7 @@ VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const {
}
const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const {
- for (auto I : redecls()) {
+ for (auto *I : redecls()) {
if (auto Expr = I->getInit()) {
D = I;
return Expr;
@@ -2330,7 +2359,7 @@ Stmt **VarDecl::getInitAddress() {
VarDecl *VarDecl::getInitializingDeclaration() {
VarDecl *Def = nullptr;
- for (auto I : redecls()) {
+ for (auto *I : redecls()) {
if (I->hasInit())
return I;
@@ -2580,7 +2609,7 @@ bool VarDecl::isNonEscapingByref() const {
bool VarDecl::hasDependentAlignment() const {
QualType T = getType();
- return T->isDependentType() || T->isUndeducedAutoType() ||
+ return T->isDependentType() || T->isUndeducedType() ||
llvm::any_of(specific_attrs<AlignedAttr>(), [](const AlignedAttr *AA) {
return AA->isAlignmentDependent();
});
@@ -2870,8 +2899,7 @@ Expr *ParmVarDecl::getDefaultArg() {
Expr *Arg = getInit();
if (auto *E = dyn_cast_or_null<FullExpr>(Arg))
- if (!isa<ConstantExpr>(E))
- return E->getSubExpr();
+ return E->getSubExpr();
return Arg;
}
@@ -2970,6 +2998,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
FunctionDeclBits.IsMultiVersion = false;
FunctionDeclBits.IsCopyDeductionCandidate = false;
FunctionDeclBits.HasODRHash = false;
+ FunctionDeclBits.FriendConstraintRefersToEnclosingTemplate = false;
if (TrailingRequiresClause)
setTrailingRequiresClause(TrailingRequiresClause);
}
@@ -3015,7 +3044,7 @@ FunctionDecl::getDefaultedFunctionInfo() const {
}
bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
- for (auto I : redecls()) {
+ for (auto *I : redecls()) {
if (I->doesThisDeclarationHaveABody()) {
Definition = I;
return true;
@@ -3162,11 +3191,13 @@ bool FunctionDecl::isMSVCRTEntryPoint() const {
}
bool FunctionDecl::isReservedGlobalPlacementOperator() const {
- assert(getDeclName().getNameKind() == DeclarationName::CXXOperatorName);
- assert(getDeclName().getCXXOverloadedOperator() == OO_New ||
- getDeclName().getCXXOverloadedOperator() == OO_Delete ||
- getDeclName().getCXXOverloadedOperator() == OO_Array_New ||
- getDeclName().getCXXOverloadedOperator() == OO_Array_Delete);
+ if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
+ return false;
+ if (getDeclName().getCXXOverloadedOperator() != OO_New &&
+ getDeclName().getCXXOverloadedOperator() != OO_Delete &&
+ getDeclName().getCXXOverloadedOperator() != OO_Array_New &&
+ getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
+ return false;
if (!getDeclContext()->getRedeclContext()->isTranslationUnit())
return false;
@@ -3185,7 +3216,7 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
}
bool FunctionDecl::isReplaceableGlobalAllocationFunction(
- Optional<unsigned> *AlignmentParam, bool *IsNothrow) const {
+ std::optional<unsigned> *AlignmentParam, bool *IsNothrow) const {
if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
return false;
if (getDeclName().getCXXOverloadedOperator() != OO_New &&
@@ -3329,6 +3360,8 @@ bool FunctionDecl::isNoReturn() const {
MultiVersionKind FunctionDecl::getMultiVersionKind() const {
if (hasAttr<TargetAttr>())
return MultiVersionKind::Target;
+ if (hasAttr<TargetVersionAttr>())
+ return MultiVersionKind::TargetVersion;
if (hasAttr<CPUDispatchAttr>())
return MultiVersionKind::CPUDispatch;
if (hasAttr<CPUSpecificAttr>())
@@ -3347,7 +3380,8 @@ bool FunctionDecl::isCPUSpecificMultiVersion() const {
}
bool FunctionDecl::isTargetMultiVersion() const {
- return isMultiVersion() && hasAttr<TargetAttr>();
+ return isMultiVersion() &&
+ (hasAttr<TargetAttr>() || hasAttr<TargetVersionAttr>());
}
bool FunctionDecl::isTargetClonesMultiVersion() const {
@@ -3486,8 +3520,8 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
bool FunctionDecl::hasOneParamOrDefaultArgs() const {
return getNumParams() == 1 ||
(getNumParams() > 1 &&
- std::all_of(param_begin() + 1, param_end(),
- [](ParmVarDecl *P) { return P->hasDefaultArg(); }));
+ llvm::all_of(llvm::drop_begin(parameters()),
+ [](ParmVarDecl *P) { return P->hasDefaultArg(); }));
}
/// The combination of the extern and inline keywords under MSVC forces
@@ -3686,7 +3720,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// If any declaration is 'inline' but not 'extern', then this definition
// is externally visible.
- for (auto Redecl : redecls()) {
+ for (auto *Redecl : redecls()) {
if (Redecl->isInlineSpecified() &&
Redecl->getStorageClass() != SC_Extern)
return true;
@@ -3703,7 +3737,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// [...] If all of the file scope declarations for a function in a
// translation unit include the inline function specifier without extern,
// then the definition in that translation unit is an inline definition.
- for (auto Redecl : redecls()) {
+ for (auto *Redecl : redecls()) {
if (RedeclForcesDefC99(Redecl))
return true;
}
@@ -4408,7 +4442,7 @@ void TagDecl::startDefinition() {
if (auto *D = dyn_cast<CXXRecordDecl>(this)) {
struct CXXRecordDecl::DefinitionData *Data =
new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
- for (auto I : redecls())
+ for (auto *I : redecls())
cast<CXXRecordDecl>(I)->DefinitionData = Data;
}
}
@@ -4441,7 +4475,7 @@ TagDecl *TagDecl::getDefinition() const {
if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(this))
return CXXRD->getDefinition();
- for (auto R : redecls())
+ for (auto *R : redecls())
if (R->isCompleteDefinition())
return R;
@@ -4468,6 +4502,23 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
}
}
+void TagDecl::printName(raw_ostream &OS, const PrintingPolicy &Policy) const {
+ DeclarationName Name = getDeclName();
+ // If the name is supposed to have an identifier but does not have one, then
+ // the tag is anonymous and we should print it differently.
+ if (Name.isIdentifier() && !Name.getAsIdentifierInfo()) {
+ // If the caller wanted to print a qualified name, they've already printed
+ // the scope. And if the caller doesn't want that, the scope information
+ // is already printed as part of the type.
+ PrintingPolicy Copy(Policy);
+ Copy.SuppressScope = true;
+ getASTContext().getTagDeclType(this).print(OS, Copy);
+ return;
+ }
+ // Otherwise, do the normal printing.
+ Name.print(OS, Policy);
+}
+
void TagDecl::setTemplateParameterListsInfo(
ASTContext &Context, ArrayRef<TemplateParameterList *> TPLists) {
assert(!TPLists.empty());
@@ -4621,6 +4672,21 @@ SourceRange EnumDecl::getSourceRange() const {
return Res;
}
+void EnumDecl::getValueRange(llvm::APInt &Max, llvm::APInt &Min) const {
+ unsigned Bitwidth = getASTContext().getIntWidth(getIntegerType());
+ unsigned NumNegativeBits = getNumNegativeBits();
+ unsigned NumPositiveBits = getNumPositiveBits();
+
+ if (NumNegativeBits) {
+ unsigned NumBits = std::max(NumNegativeBits, NumPositiveBits + 1);
+ Max = llvm::APInt(Bitwidth, 1) << (NumBits - 1);
+ Min = -Max;
+ } else {
+ Max = llvm::APInt(Bitwidth, 1) << NumPositiveBits;
+ Min = llvm::APInt::getZero(Bitwidth);
+ }
+}
+
//===----------------------------------------------------------------------===//
// RecordDecl Implementation
//===----------------------------------------------------------------------===//
@@ -4645,6 +4711,7 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, const ASTContext &C,
setParamDestroyedInCallee(false);
setArgPassingRestrictions(APK_CanPassInRegs);
setIsRandomized(false);
+ setODRHash(0);
}
RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
@@ -4819,6 +4886,19 @@ const FieldDecl *RecordDecl::findFirstNamedDataMember() const {
return nullptr;
}
+unsigned RecordDecl::getODRHash() {
+ if (hasODRHash())
+ return RecordDeclBits.ODRHash;
+
+ // Only calculate hash on first call of getODRHash per record.
+ ODRHash Hash;
+ Hash.AddRecordDecl(this);
+ // For RecordDecl the ODRHash is stored in the remaining 26
+ // bit of RecordDeclBits, adjust the hash to accomodate.
+ setODRHash(Hash.CalculateHash() >> 6);
+ return RecordDeclBits.ODRHash;
+}
+
//===----------------------------------------------------------------------===//
// BlockDecl Implementation
//===----------------------------------------------------------------------===//
@@ -4968,6 +5048,12 @@ bool ValueDecl::isWeak() const {
MostRecent->hasAttr<WeakRefAttr>() || isWeakImported();
}
+bool ValueDecl::isInitCapture() const {
+ if (auto *Var = llvm::dyn_cast<VarDecl>(this))
+ return Var->isInitCapture();
+ return false;
+}
+
void ImplicitParamDecl::anchor() {}
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
@@ -5073,8 +5159,9 @@ IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IndirectFieldDecl *IndirectFieldDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
- return new (C, ID) IndirectFieldDecl(C, nullptr, SourceLocation(),
- DeclarationName(), QualType(), None);
+ return new (C, ID)
+ IndirectFieldDecl(C, nullptr, SourceLocation(), DeclarationName(),
+ QualType(), std::nullopt);
}
SourceRange EnumConstantDecl::getSourceRange() const {
@@ -5179,6 +5266,29 @@ FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C,
SourceLocation());
}
+void TopLevelStmtDecl::anchor() {}
+
+TopLevelStmtDecl *TopLevelStmtDecl::Create(ASTContext &C, Stmt *Statement) {
+ assert(Statement);
+ assert(C.getLangOpts().IncrementalExtensions &&
+ "Must be used only in incremental mode");
+
+ SourceLocation BeginLoc = Statement->getBeginLoc();
+ DeclContext *DC = C.getTranslationUnitDecl();
+
+ return new (C, DC) TopLevelStmtDecl(DC, BeginLoc, Statement);
+}
+
+TopLevelStmtDecl *TopLevelStmtDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ return new (C, ID)
+ TopLevelStmtDecl(/*DC=*/nullptr, SourceLocation(), /*S=*/nullptr);
+}
+
+SourceRange TopLevelStmtDecl::getSourceRange() const {
+ return SourceRange(getLocation(), Statement->getEndLoc());
+}
+
void EmptyDecl::anchor() {}
EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
@@ -5189,6 +5299,40 @@ EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) EmptyDecl(nullptr, SourceLocation());
}
+HLSLBufferDecl::HLSLBufferDecl(DeclContext *DC, bool CBuffer,
+ SourceLocation KwLoc, IdentifierInfo *ID,
+ SourceLocation IDLoc, SourceLocation LBrace)
+ : NamedDecl(Decl::Kind::HLSLBuffer, DC, IDLoc, DeclarationName(ID)),
+ DeclContext(Decl::Kind::HLSLBuffer), LBraceLoc(LBrace), KwLoc(KwLoc),
+ IsCBuffer(CBuffer) {}
+
+HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C,
+ DeclContext *LexicalParent, bool CBuffer,
+ SourceLocation KwLoc, IdentifierInfo *ID,
+ SourceLocation IDLoc,
+ SourceLocation LBrace) {
+ // For hlsl like this
+ // cbuffer A {
+ // cbuffer B {
+ // }
+ // }
+ // compiler should treat it as
+ // cbuffer A {
+ // }
+ // cbuffer B {
+ // }
+ // FIXME: support nested buffers if required for back-compat.
+ DeclContext *DC = LexicalParent;
+ HLSLBufferDecl *Result =
+ new (C, DC) HLSLBufferDecl(DC, CBuffer, KwLoc, ID, IDLoc, LBrace);
+ return Result;
+}
+
+HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ return new (C, ID) HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr,
+ SourceLocation(), SourceLocation());
+}
+
//===----------------------------------------------------------------------===//
// ImportDecl Implementation
//===----------------------------------------------------------------------===//
@@ -5248,11 +5392,11 @@ ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, unsigned ID,
ArrayRef<SourceLocation> ImportDecl::getIdentifierLocs() const {
if (!isImportComplete())
- return None;
+ return std::nullopt;
const auto *StoredLocs = getTrailingObjects<SourceLocation>();
- return llvm::makeArrayRef(StoredLocs,
- getNumModuleIdentifiers(getImportedModule()));
+ return llvm::ArrayRef(StoredLocs,
+ getNumModuleIdentifiers(getImportedModule()));
}
SourceRange ImportDecl::getSourceRange() const {
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index d12330de1500..c94fc602155b 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -152,6 +152,15 @@ void Decl::setInvalidDecl(bool Invalid) {
}
}
+bool DeclContext::hasValidDeclKind() const {
+ switch (getDeclKind()) {
+#define DECL(DERIVED, BASE) case Decl::DERIVED: return true;
+#define ABSTRACT_DECL(DECL)
+#include "clang/AST/DeclNodes.inc"
+ }
+ return false;
+}
+
const char *DeclContext::getDeclKindName() const {
switch (getDeclKind()) {
#define DECL(DERIVED, BASE) case Decl::DERIVED: return #DERIVED;
@@ -252,12 +261,12 @@ const TemplateParameterList *Decl::getDescribedTemplateParams() const {
bool Decl::isTemplated() const {
// A declaration is templated if it is a template or a template pattern, or
- // is within (lexcially for a friend, semantically otherwise) a dependent
- // context.
- // FIXME: Should local extern declarations be treated like friends?
+ // is within (lexcially for a friend or local function declaration,
+ // semantically otherwise) a dependent context.
if (auto *AsDC = dyn_cast<DeclContext>(this))
return AsDC->isDependentContext();
- auto *DC = getFriendObjectKind() ? getLexicalDeclContext() : getDeclContext();
+ auto *DC = getFriendObjectKind() || isLocalExternDecl()
+ ? getLexicalDeclContext() : getDeclContext();
return DC->isDependentContext() || isTemplateDecl() ||
getDescribedTemplateParams();
}
@@ -286,8 +295,7 @@ unsigned Decl::getTemplateDepth() const {
const DeclContext *Decl::getParentFunctionOrMethod(bool LexicalParent) const {
for (const DeclContext *DC = LexicalParent ? getLexicalDeclContext()
: getDeclContext();
- DC && !DC->isTranslationUnit() && !DC->isNamespace();
- DC = DC->getParent())
+ DC && !DC->isFileContext(); DC = DC->getParent())
if (DC->isFunctionOrMethod())
return DC;
@@ -397,6 +405,11 @@ bool Decl::isInStdNamespace() const {
return DC && DC->isStdNamespace();
}
+bool Decl::isFileContextDecl() const {
+ const auto *DC = dyn_cast<DeclContext>(this);
+ return DC && DC->isFileContext();
+}
+
TranslationUnitDecl *Decl::getTranslationUnitDecl() {
if (auto *TUD = dyn_cast<TranslationUnitDecl>(this))
return TUD;
@@ -750,6 +763,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCMethod:
case ObjCProperty:
case MSProperty:
+ case HLSLBuffer:
return IDNS_Ordinary;
case Label:
return IDNS_Label;
@@ -829,6 +843,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case LinkageSpec:
case Export:
case FileScopeAsm:
+ case TopLevelStmt:
case StaticAssert:
case ObjCPropertyImpl:
case PragmaComment:
@@ -860,6 +875,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case Empty:
case LifetimeExtendedTemporary:
case RequiresExprBody:
+ case ImplicitConceptSpecialization:
// Never looked up by name.
return 0;
}
@@ -1032,6 +1048,11 @@ const FunctionType *Decl::getFunctionType(bool BlocksToo) const {
return Ty->getAs<FunctionType>();
}
+DeclContext *Decl::getNonTransparentDeclContext() {
+ assert(getDeclContext());
+ return getDeclContext()->getNonTransparentContext();
+}
+
/// Starting at a given context (a Decl or DeclContext), look for a
/// code context that is not a closure (a lambda, block, etc.).
template <class T> static Decl *getNonClosureContext(T *D) {
@@ -1188,7 +1209,7 @@ bool DeclContext::isTransparentContext() const {
if (getDeclKind() == Decl::Enum)
return !cast<EnumDecl>(this)->isScoped();
- return getDeclKind() == Decl::LinkageSpec || getDeclKind() == Decl::Export;
+ return isa<LinkageSpecDecl, ExportDecl, HLSLBufferDecl>(this);
}
static bool isLinkageSpecContext(const DeclContext *DC,
@@ -1253,6 +1274,15 @@ DeclContext *DeclContext::getPrimaryContext() {
// There is only one DeclContext for these entities.
return this;
+ case Decl::HLSLBuffer:
+ // Each buffer, even with the same name, is a distinct construct.
+ // Multiple buffers with the same name are allowed for backward
+ // compatibility.
+ // As long as buffers have unique resource bindings the names don't matter.
+ // The names get exposed via the CPU-side reflection API which
+ // supports querying bindings, so we cannot remove them.
+ return this;
+
case Decl::TranslationUnit:
return static_cast<TranslationUnitDecl *>(this)->getFirstDecl();
case Decl::Namespace:
@@ -1766,7 +1796,8 @@ void DeclContext::localUncachedLookup(DeclarationName Name,
if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage() && Name) {
lookup_result LookupResults = lookup(Name);
Results.insert(Results.end(), LookupResults.begin(), LookupResults.end());
- return;
+ if (!Results.empty())
+ return;
}
// If we have a lookup table, check there first. Maybe we'll get lucky.
diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp
index c307cbe02ecf..3cf355714107 100644
--- a/clang/lib/AST/DeclCXX.cpp
+++ b/clang/lib/AST/DeclCXX.cpp
@@ -36,7 +36,7 @@
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
-#include "llvm/ADT/None.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator_range.h"
@@ -768,12 +768,16 @@ void CXXRecordDecl::addedMember(Decl *D) {
// Note that we have a user-declared constructor.
data().UserDeclaredConstructor = true;
- // C++ [class]p4:
- // A POD-struct is an aggregate class [...]
- // Since the POD bit is meant to be C++03 POD-ness, clear it even if
- // the type is technically an aggregate in C++0x since it wouldn't be
- // in 03.
- data().PlainOldData = false;
+ const TargetInfo &TI = getASTContext().getTargetInfo();
+ if ((!Constructor->isDeleted() && !Constructor->isDefaulted()) ||
+ !TI.areDefaultedSMFStillPOD(getLangOpts())) {
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ // Since the POD bit is meant to be C++03 POD-ness, clear it even if
+ // the type is technically an aggregate in C++0x since it wouldn't be
+ // in 03.
+ data().PlainOldData = false;
+ }
}
if (Constructor->isDefaultConstructor()) {
@@ -881,22 +885,30 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!Method->isImplicit()) {
data().UserDeclaredSpecialMembers |= SMKind;
- // C++03 [class]p4:
- // A POD-struct is an aggregate class that has [...] no user-defined
- // copy assignment operator and no user-defined destructor.
- //
- // Since the POD bit is meant to be C++03 POD-ness, and in C++03,
- // aggregates could not have any constructors, clear it even for an
- // explicitly defaulted or deleted constructor.
- // type is technically an aggregate in C++0x since it wouldn't be in 03.
- //
- // Also, a user-declared move assignment operator makes a class non-POD.
- // This is an extension in C++03.
- data().PlainOldData = false;
+ const TargetInfo &TI = getASTContext().getTargetInfo();
+ if ((!Method->isDeleted() && !Method->isDefaulted() &&
+ SMKind != SMF_MoveAssignment) ||
+ !TI.areDefaultedSMFStillPOD(getLangOpts())) {
+ // C++03 [class]p4:
+ // A POD-struct is an aggregate class that has [...] no user-defined
+ // copy assignment operator and no user-defined destructor.
+ //
+ // Since the POD bit is meant to be C++03 POD-ness, and in C++03,
+ // aggregates could not have any constructors, clear it even for an
+ // explicitly defaulted or deleted constructor.
+ // type is technically an aggregate in C++0x since it wouldn't be in
+ // 03.
+ //
+ // Also, a user-declared move assignment operator makes a class
+ // non-POD. This is an extension in C++03.
+ data().PlainOldData = false;
+ }
}
- // We delay updating destructor relevant properties until
- // addedSelectedDestructor.
- // FIXME: Defer this for the other special member functions as well.
+ // When instantiating a class, we delay updating the destructor and
+ // triviality properties of the class until selecting a destructor and
+ // computing the eligibility of its special member functions. This is
+ // because there might be function constraints that we need to evaluate
+ // and compare later in the instantiation.
if (!Method->isIneligibleOrNotSelected()) {
addedEligibleSpecialMemberFunction(Method, SMKind);
}
@@ -1365,7 +1377,11 @@ void CXXRecordDecl::addedSelectedDestructor(CXXDestructorDecl *DD) {
}
void CXXRecordDecl::addedEligibleSpecialMemberFunction(const CXXMethodDecl *MD,
- unsigned SMKind) {
+ unsigned SMKind) {
+ // FIXME: We shouldn't change DeclaredNonTrivialSpecialMembers if `MD` is
+ // a function template, but this needs CWG attention before we break ABI.
+ // See https://github.com/llvm/llvm-project/issues/59206
+
if (const auto *DD = dyn_cast<CXXDestructorDecl>(MD)) {
if (DD->isUserProvided())
data().HasIrrelevantDestructor = false;
@@ -1437,10 +1453,21 @@ void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
// Update which trivial / non-trivial special members we have.
// addedMember will have skipped this step for this member.
- if (D->isTrivial())
- data().HasTrivialSpecialMembers |= SMKind;
- else
- data().DeclaredNonTrivialSpecialMembers |= SMKind;
+ if (!D->isIneligibleOrNotSelected()) {
+ if (D->isTrivial())
+ data().HasTrivialSpecialMembers |= SMKind;
+ else
+ data().DeclaredNonTrivialSpecialMembers |= SMKind;
+ }
+}
+
+void CXXRecordDecl::LambdaDefinitionData::AddCaptureList(ASTContext &Ctx,
+ Capture *CaptureList) {
+ Captures.push_back(CaptureList);
+ if (Captures.size() == 2) {
+ // The TinyPtrVector member now needs destruction.
+ Ctx.addDestruction(&Captures);
+ }
}
void CXXRecordDecl::setCaptures(ASTContext &Context,
@@ -1450,9 +1477,9 @@ void CXXRecordDecl::setCaptures(ASTContext &Context,
// Copy captures.
Data.NumCaptures = Captures.size();
Data.NumExplicitCaptures = 0;
- Data.Captures = (LambdaCapture *)Context.Allocate(sizeof(LambdaCapture) *
- Captures.size());
- LambdaCapture *ToCapture = Data.Captures;
+ auto *ToCapture = (LambdaCapture *)Context.Allocate(sizeof(LambdaCapture) *
+ Captures.size());
+ Data.AddCaptureList(Context, ToCapture);
for (unsigned I = 0, N = Captures.size(); I != N; ++I) {
if (Captures[I].isExplicit())
++Data.NumExplicitCaptures;
@@ -1570,21 +1597,23 @@ CXXMethodDecl *CXXRecordDecl::getLambdaStaticInvoker(CallingConv CC) const {
}
void CXXRecordDecl::getCaptureFields(
- llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
- FieldDecl *&ThisCapture) const {
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> &Captures,
+ FieldDecl *&ThisCapture) const {
Captures.clear();
ThisCapture = nullptr;
LambdaDefinitionData &Lambda = getLambdaData();
- RecordDecl::field_iterator Field = field_begin();
- for (const LambdaCapture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures;
- C != CEnd; ++C, ++Field) {
- if (C->capturesThis())
- ThisCapture = *Field;
- else if (C->capturesVariable())
- Captures[C->getCapturedVar()] = *Field;
+ for (const LambdaCapture *List : Lambda.Captures) {
+ RecordDecl::field_iterator Field = field_begin();
+ for (const LambdaCapture *C = List, *CEnd = C + Lambda.NumCaptures;
+ C != CEnd; ++C, ++Field) {
+ if (C->capturesThis())
+ ThisCapture = *Field;
+ else if (C->capturesVariable())
+ Captures[C->getCapturedVar()] = *Field;
+ }
+ assert(Field == field_end());
}
- assert(Field == field_end());
}
TemplateParameterList *
@@ -1608,7 +1637,7 @@ CXXRecordDecl::getLambdaExplicitTemplateParameters() const {
const auto ExplicitEnd = llvm::partition_point(
*List, [](const NamedDecl *D) { return !D->isImplicit(); });
- return llvm::makeArrayRef(List->begin(), ExplicitEnd);
+ return llvm::ArrayRef(List->begin(), ExplicitEnd);
}
Decl *CXXRecordDecl::getLambdaContextDecl() const {
@@ -2566,7 +2595,7 @@ SourceLocation CXXCtorInitializer::getSourceLocation() const {
return getMemberLocation();
if (const auto *TSInfo = Initializee.get<TypeSourceInfo *>())
- return TSInfo->getTypeLoc().getLocalSourceRange().getBegin();
+ return TSInfo->getTypeLoc().getBeginLoc();
return {};
}
@@ -2865,41 +2894,47 @@ NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
NamespaceDecl::NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline,
SourceLocation StartLoc, SourceLocation IdLoc,
- IdentifierInfo *Id, NamespaceDecl *PrevDecl)
+ IdentifierInfo *Id, NamespaceDecl *PrevDecl,
+ bool Nested)
: NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
- redeclarable_base(C), LocStart(StartLoc),
- AnonOrFirstNamespaceAndInline(nullptr, Inline) {
+ redeclarable_base(C), LocStart(StartLoc) {
+ unsigned Flags = 0;
+ if (Inline)
+ Flags |= F_Inline;
+ if (Nested)
+ Flags |= F_Nested;
+ AnonOrFirstNamespaceAndFlags = {nullptr, Flags};
setPreviousDecl(PrevDecl);
if (PrevDecl)
- AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace());
+ AnonOrFirstNamespaceAndFlags.setPointer(PrevDecl->getOriginalNamespace());
}
NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
bool Inline, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
- NamespaceDecl *PrevDecl) {
- return new (C, DC) NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id,
- PrevDecl);
+ NamespaceDecl *PrevDecl, bool Nested) {
+ return new (C, DC)
+ NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id, PrevDecl, Nested);
}
NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) NamespaceDecl(C, nullptr, false, SourceLocation(),
- SourceLocation(), nullptr, nullptr);
+ SourceLocation(), nullptr, nullptr, false);
}
NamespaceDecl *NamespaceDecl::getOriginalNamespace() {
if (isFirstDecl())
return this;
- return AnonOrFirstNamespaceAndInline.getPointer();
+ return AnonOrFirstNamespaceAndFlags.getPointer();
}
const NamespaceDecl *NamespaceDecl::getOriginalNamespace() const {
if (isFirstDecl())
return this;
- return AnonOrFirstNamespaceAndInline.getPointer();
+ return AnonOrFirstNamespaceAndFlags.getPointer();
}
bool NamespaceDecl::isOriginalNamespace() const { return isFirstDecl(); }
@@ -3087,18 +3122,23 @@ SourceRange UsingDecl::getSourceRange() const {
void UsingEnumDecl::anchor() {}
UsingEnumDecl *UsingEnumDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation UL, SourceLocation EL,
- SourceLocation NL, EnumDecl *Enum) {
- return new (C, DC) UsingEnumDecl(DC, Enum->getDeclName(), UL, EL, NL, Enum);
+ 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 *UsingEnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- return new (C, ID) UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(),
- SourceLocation(), SourceLocation(), nullptr);
+ return new (C, ID)
+ UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(),
+ SourceLocation(), SourceLocation(), nullptr);
}
SourceRange UsingEnumDecl::getSourceRange() const {
- return SourceRange(EnumLocation, getLocation());
+ return SourceRange(UsingLocation, EnumType->getTypeLoc().getEndLoc());
}
void UsingPackDecl::anchor() {}
@@ -3113,7 +3153,8 @@ UsingPackDecl *UsingPackDecl::Create(ASTContext &C, DeclContext *DC,
UsingPackDecl *UsingPackDecl::CreateDeserialized(ASTContext &C, unsigned ID,
unsigned NumExpansions) {
size_t Extra = additionalSizeToAlloc<NamedDecl *>(NumExpansions);
- auto *Result = new (C, ID, Extra) UsingPackDecl(nullptr, nullptr, None);
+ auto *Result =
+ new (C, ID, Extra) UsingPackDecl(nullptr, nullptr, std::nullopt);
Result->NumExpansions = NumExpansions;
auto *Trail = Result->getTrailingObjects<NamedDecl *>();
for (unsigned I = 0; I != NumExpansions; ++I)
@@ -3208,6 +3249,16 @@ StaticAssertDecl *StaticAssertDecl::CreateDeserialized(ASTContext &C,
nullptr, SourceLocation(), false);
}
+VarDecl *ValueDecl::getPotentiallyDecomposedVarDecl() {
+ assert((isa<VarDecl, BindingDecl>(this)) &&
+ "expected a VarDecl or a BindingDecl");
+ if (auto *Var = llvm::dyn_cast<VarDecl>(this))
+ return Var;
+ if (auto *BD = llvm::dyn_cast<BindingDecl>(this))
+ return llvm::dyn_cast<VarDecl>(BD->getDecomposedDecl());
+ return nullptr;
+}
+
void BindingDecl::anchor() {}
BindingDecl *BindingDecl::Create(ASTContext &C, DeclContext *DC,
@@ -3251,7 +3302,7 @@ DecompositionDecl *DecompositionDecl::CreateDeserialized(ASTContext &C,
size_t Extra = additionalSizeToAlloc<BindingDecl *>(NumBindings);
auto *Result = new (C, ID, Extra)
DecompositionDecl(C, nullptr, SourceLocation(), SourceLocation(),
- QualType(), nullptr, StorageClass(), None);
+ QualType(), nullptr, StorageClass(), std::nullopt);
// Set up and clean out the bindings array.
Result->NumBindings = NumBindings;
auto *Trail = Result->getTrailingObjects<BindingDecl *>();
@@ -3260,16 +3311,17 @@ DecompositionDecl *DecompositionDecl::CreateDeserialized(ASTContext &C,
return Result;
}
-void DecompositionDecl::printName(llvm::raw_ostream &os) const {
- os << '[';
+void DecompositionDecl::printName(llvm::raw_ostream &OS,
+ const PrintingPolicy &Policy) const {
+ OS << '[';
bool Comma = false;
for (const auto *B : bindings()) {
if (Comma)
- os << ", ";
- B->printName(os);
+ OS << ", ";
+ B->printName(OS, Policy);
Comma = true;
}
- os << ']';
+ OS << ']';
}
void MSPropertyDecl::anchor() {}
@@ -3305,7 +3357,8 @@ MSGuidDecl *MSGuidDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) MSGuidDecl(nullptr, QualType(), Parts());
}
-void MSGuidDecl::printName(llvm::raw_ostream &OS) const {
+void MSGuidDecl::printName(llvm::raw_ostream &OS,
+ const PrintingPolicy &) const {
OS << llvm::format("GUID{%08" PRIx32 "-%04" PRIx16 "-%04" PRIx16 "-",
PartVal.Part1, PartVal.Part2, PartVal.Part3);
unsigned I = 0;
@@ -3414,7 +3467,8 @@ UnnamedGlobalConstantDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
UnnamedGlobalConstantDecl(C, nullptr, QualType(), APValue());
}
-void UnnamedGlobalConstantDecl::printName(llvm::raw_ostream &OS) const {
+void UnnamedGlobalConstantDecl::printName(llvm::raw_ostream &OS,
+ const PrintingPolicy &) const {
OS << "unnamed-global-constant";
}
diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp
index 15c545b59c81..e934a81d086e 100644
--- a/clang/lib/AST/DeclObjC.cpp
+++ b/clang/lib/AST/DeclObjC.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
+#include "clang/AST/ODRHash.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
@@ -23,7 +24,6 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
@@ -403,21 +403,18 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
return nullptr;
}
-void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM,
- PropertyDeclOrder &PO) const {
+void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM) const {
for (auto *Prop : properties()) {
PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
- PO.push_back(Prop);
}
for (const auto *Ext : known_extensions()) {
const ObjCCategoryDecl *ClassExt = Ext;
for (auto *Prop : ClassExt->properties()) {
PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
- PO.push_back(Prop);
}
}
for (const auto *PI : all_referenced_protocols())
- PI->collectPropertiesToImplement(PM, PO);
+ PI->collectPropertiesToImplement(PM);
// Note, the properties declared only in class extensions are still copied
// into the main @interface's property list, and therefore we don't
// explicitly, have to search class extension properties.
@@ -627,6 +624,17 @@ void ObjCInterfaceDecl::startDefinition() {
}
}
+void ObjCInterfaceDecl::startDuplicateDefinitionForComparison() {
+ Data.setPointer(nullptr);
+ allocateDefinitionData();
+ // Don't propagate data to other redeclarations.
+}
+
+void ObjCInterfaceDecl::mergeDuplicateDefinitionWithCommon(
+ const ObjCInterfaceDecl *Definition) {
+ Data = Definition->Data;
+}
+
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ObjCInterfaceDecl *&clsDeclared) {
// FIXME: Should make sure no callers ever do this.
@@ -781,6 +789,33 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
return Method;
}
+unsigned ObjCInterfaceDecl::getODRHash() {
+ assert(hasDefinition() && "ODRHash only for records with definitions");
+
+ // Previously calculated hash is stored in DefinitionData.
+ if (hasODRHash())
+ return data().ODRHash;
+
+ // Only calculate hash on first call of getODRHash per record.
+ ODRHash Hasher;
+ Hasher.AddObjCInterfaceDecl(getDefinition());
+ data().ODRHash = Hasher.CalculateHash();
+ setHasODRHash(true);
+
+ return data().ODRHash;
+}
+
+bool ObjCInterfaceDecl::hasODRHash() const {
+ if (!hasDefinition())
+ return false;
+ return data().HasODRHash;
+}
+
+void ObjCInterfaceDecl::setHasODRHash(bool HasHash) {
+ assert(hasDefinition() && "Cannot set ODRHash without definition");
+ data().HasODRHash = HasHash;
+}
+
//===----------------------------------------------------------------------===//
// ObjCMethodDecl
//===----------------------------------------------------------------------===//
@@ -864,7 +899,7 @@ bool ObjCMethodDecl::isDesignatedInitializerForTheInterface(
}
bool ObjCMethodDecl::hasParamDestroyedInCallee() const {
- for (auto param : parameters()) {
+ for (auto *param : parameters()) {
if (param->isDestroyedInCallee())
return true;
}
@@ -912,12 +947,12 @@ void ObjCMethodDecl::setMethodParams(ASTContext &C,
assert((!SelLocs.empty() || isImplicit()) &&
"No selector locs for non-implicit method");
if (isImplicit())
- return setParamsAndSelLocs(C, Params, llvm::None);
+ return setParamsAndSelLocs(C, Params, std::nullopt);
setSelLocsKind(hasStandardSelectorLocs(getSelector(), SelLocs, Params,
DeclEndLoc));
if (getSelLocsKind() != SelLoc_NonStandard)
- return setParamsAndSelLocs(C, Params, llvm::None);
+ return setParamsAndSelLocs(C, Params, std::nullopt);
setParamsAndSelLocs(C, Params, SelLocs);
}
@@ -1496,7 +1531,7 @@ ObjCTypeParamList *ObjCTypeParamList::create(
void ObjCTypeParamList::gatherDefaultTypeArgs(
SmallVectorImpl<QualType> &typeArgs) const {
typeArgs.reserve(size());
- for (auto typeParam : *this)
+ for (auto *typeParam : *this)
typeArgs.push_back(typeParam->getUnderlyingType());
}
@@ -1988,6 +2023,7 @@ void ObjCProtocolDecl::allocateDefinitionData() {
assert(!Data.getPointer() && "Protocol already has a definition!");
Data.setPointer(new (getASTContext()) DefinitionData);
Data.getPointer()->Definition = this;
+ Data.getPointer()->HasODRHash = false;
}
void ObjCProtocolDecl::startDefinition() {
@@ -1998,19 +2034,28 @@ void ObjCProtocolDecl::startDefinition() {
RD->Data = this->Data;
}
-void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
- PropertyDeclOrder &PO) const {
+void ObjCProtocolDecl::startDuplicateDefinitionForComparison() {
+ Data.setPointer(nullptr);
+ allocateDefinitionData();
+ // Don't propagate data to other redeclarations.
+}
+
+void ObjCProtocolDecl::mergeDuplicateDefinitionWithCommon(
+ const ObjCProtocolDecl *Definition) {
+ Data = Definition->Data;
+}
+
+void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM) const {
if (const ObjCProtocolDecl *PDecl = getDefinition()) {
for (auto *Prop : PDecl->properties()) {
// Insert into PM if not there already.
PM.insert(std::make_pair(
std::make_pair(Prop->getIdentifier(), Prop->isClassProperty()),
Prop));
- PO.push_back(Prop);
}
// Scan through protocol's protocols.
for (const auto *PI : PDecl->protocols())
- PI->collectPropertiesToImplement(PM, PO);
+ PI->collectPropertiesToImplement(PM);
}
}
@@ -2042,6 +2087,33 @@ ObjCProtocolDecl::getObjCRuntimeNameAsString() const {
return getName();
}
+unsigned ObjCProtocolDecl::getODRHash() {
+ assert(hasDefinition() && "ODRHash only for records with definitions");
+
+ // Previously calculated hash is stored in DefinitionData.
+ if (hasODRHash())
+ return data().ODRHash;
+
+ // Only calculate hash on first call of getODRHash per record.
+ ODRHash Hasher;
+ Hasher.AddObjCProtocolDecl(getDefinition());
+ data().ODRHash = Hasher.CalculateHash();
+ setHasODRHash(true);
+
+ return data().ODRHash;
+}
+
+bool ObjCProtocolDecl::hasODRHash() const {
+ if (!hasDefinition())
+ return false;
+ return data().HasODRHash;
+}
+
+void ObjCProtocolDecl::setHasODRHash(bool HasHash) {
+ assert(hasDefinition() && "Cannot set ODRHash without definition");
+ data().HasODRHash = HasHash;
+}
+
//===----------------------------------------------------------------------===//
// ObjCCategoryDecl
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/DeclOpenMP.cpp b/clang/lib/AST/DeclOpenMP.cpp
index 867ef31656f7..e29fc564fd34 100644
--- a/clang/lib/AST/DeclOpenMP.cpp
+++ b/clang/lib/AST/DeclOpenMP.cpp
@@ -30,7 +30,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
SourceLocation L,
ArrayRef<Expr *> VL) {
auto *D = OMPDeclarativeDirective::createDirective<OMPThreadPrivateDecl>(
- C, DC, llvm::None, VL.size(), L);
+ C, DC, std::nullopt, VL.size(), L);
D->setVars(VL);
return D;
}
diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index b041e2a67e95..f3bad9f45b74 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -72,6 +72,7 @@ namespace {
void VisitLabelDecl(LabelDecl *D);
void VisitParmVarDecl(ParmVarDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
+ void VisitTopLevelStmtDecl(TopLevelStmtDecl *D);
void VisitImportDecl(ImportDecl *D);
void VisitStaticAssertDecl(StaticAssertDecl *D);
void VisitNamespaceDecl(NamespaceDecl *D);
@@ -108,6 +109,7 @@ namespace {
void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D);
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *TTP);
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *NTTP);
+ void VisitHLSLBufferDecl(HLSLBufferDecl *D);
void printTemplateParameters(const TemplateParameterList *Params,
bool OmitTemplateKW = false);
@@ -462,12 +464,9 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
Terminator = nullptr;
else
Terminator = ";";
- } else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) ||
- isa<ObjCImplementationDecl>(*D) ||
- isa<ObjCInterfaceDecl>(*D) ||
- isa<ObjCProtocolDecl>(*D) ||
- isa<ObjCCategoryImplDecl>(*D) ||
- isa<ObjCCategoryDecl>(*D))
+ } else if (isa<NamespaceDecl, LinkageSpecDecl, ObjCImplementationDecl,
+ ObjCInterfaceDecl, ObjCProtocolDecl, ObjCCategoryImplDecl,
+ ObjCCategoryDecl, HLSLBufferDecl>(*D))
Terminator = nullptr;
else if (isa<EnumConstantDecl>(*D)) {
DeclContext::decl_iterator Next = D;
@@ -934,6 +933,11 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
Out << ")";
}
+void DeclPrinter::VisitTopLevelStmtDecl(TopLevelStmtDecl *D) {
+ assert(D->getStmt());
+ D->getStmt()->printPretty(Out, nullptr, Policy, Indentation, "\n", &Context);
+}
+
void DeclPrinter::VisitImportDecl(ImportDecl *D) {
Out << "@import " << D->getImportedModule()->getFullModuleName()
<< ";\n";
@@ -1658,6 +1662,21 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
}
}
+void DeclPrinter::VisitHLSLBufferDecl(HLSLBufferDecl *D) {
+ if (D->isCBuffer())
+ Out << "cbuffer ";
+ else
+ Out << "tbuffer ";
+
+ Out << *D;
+
+ prettyPrintAttributes(D);
+
+ Out << " {\n";
+ VisitDeclContext(D);
+ Indent() << "}";
+}
+
void DeclPrinter::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
Out << "#pragma omp allocate";
if (!D->varlist_empty()) {
@@ -1698,7 +1717,7 @@ void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
Out << OpName;
} else {
assert(D->getDeclName().isIdentifier());
- D->printName(Out);
+ D->printName(Out, Policy);
}
Out << " : ";
D->getType().print(Out, Policy);
@@ -1728,7 +1747,7 @@ void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) {
void DeclPrinter::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
if (!D->isInvalidDecl()) {
Out << "#pragma omp declare mapper (";
- D->printName(Out);
+ D->printName(Out, Policy);
Out << " : ";
D->getType().print(Out, Policy);
Out << " ";
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index e7e5f355809b..531be708b6fd 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -26,7 +26,6 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/PointerUnion.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
@@ -36,6 +35,7 @@
#include <cassert>
#include <cstdint>
#include <memory>
+#include <optional>
#include <utility>
using namespace clang;
@@ -131,7 +131,7 @@ unsigned TemplateParameterList::getMinRequiredArguments() const {
unsigned NumRequiredArgs = 0;
for (const NamedDecl *P : asArray()) {
if (P->isTemplateParameterPack()) {
- if (Optional<unsigned> Expansions = getExpandedPackSize(P)) {
+ if (std::optional<unsigned> Expansions = getExpandedPackSize(P)) {
NumRequiredArgs += *Expansions;
continue;
}
@@ -250,6 +250,16 @@ bool TemplateDecl::hasAssociatedConstraints() const {
return false;
}
+bool TemplateDecl::isTypeAlias() const {
+ switch (getKind()) {
+ case TemplateDecl::TypeAliasTemplate:
+ case TemplateDecl::BuiltinTemplate:
+ return true;
+ default:
+ return false;
+ };
+}
+
//===----------------------------------------------------------------------===//
// RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -343,6 +353,22 @@ void RedeclarableTemplateDecl::addSpecializationImpl(
SETraits::getDecl(Entry));
}
+ArrayRef<TemplateArgument> RedeclarableTemplateDecl::getInjectedTemplateArgs() {
+ TemplateParameterList *Params = getTemplateParameters();
+ auto *CommonPtr = getCommonPtr();
+ if (!CommonPtr->InjectedArgs) {
+ auto &Context = getASTContext();
+ SmallVector<TemplateArgument, 16> TemplateArgs;
+ Context.getInjectedTemplateArgs(Params, TemplateArgs);
+ CommonPtr->InjectedArgs =
+ new (Context) TemplateArgument[TemplateArgs.size()];
+ std::copy(TemplateArgs.begin(), TemplateArgs.end(),
+ CommonPtr->InjectedArgs);
+ }
+
+ return llvm::ArrayRef(CommonPtr->InjectedArgs, Params->size());
+}
+
//===----------------------------------------------------------------------===//
// FunctionTemplateDecl Implementation
//===----------------------------------------------------------------------===//
@@ -393,22 +419,6 @@ void FunctionTemplateDecl::addSpecialization(
InsertPos);
}
-ArrayRef<TemplateArgument> FunctionTemplateDecl::getInjectedTemplateArgs() {
- TemplateParameterList *Params = getTemplateParameters();
- Common *CommonPtr = getCommonPtr();
- if (!CommonPtr->InjectedArgs) {
- auto &Context = getASTContext();
- SmallVector<TemplateArgument, 16> TemplateArgs;
- Context.getInjectedTemplateArgs(Params, TemplateArgs);
- CommonPtr->InjectedArgs =
- new (Context) TemplateArgument[TemplateArgs.size()];
- std::copy(TemplateArgs.begin(), TemplateArgs.end(),
- CommonPtr->InjectedArgs);
- }
-
- return llvm::makeArrayRef(CommonPtr->InjectedArgs, Params->size());
-}
-
void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) {
using Base = RedeclarableTemplateDecl;
@@ -519,6 +529,9 @@ static void ProfileTemplateParameterList(ASTContext &C,
ID.AddInteger(0);
ID.AddBoolean(NTTP->isParameterPack());
NTTP->getType().getCanonicalType().Profile(ID);
+ ID.AddBoolean(NTTP->hasPlaceholderTypeConstraint());
+ if (const Expr *E = NTTP->getPlaceholderTypeConstraint())
+ E->Profile(ID, C, /*Canonical=*/true);
continue;
}
if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D)) {
@@ -624,13 +637,11 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
// TemplateTypeParm Allocation/Deallocation Method Implementations
//===----------------------------------------------------------------------===//
-TemplateTypeParmDecl *
-TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
- SourceLocation KeyLoc, SourceLocation NameLoc,
- unsigned D, unsigned P, IdentifierInfo *Id,
- bool Typename, bool ParameterPack,
- bool HasTypeConstraint,
- Optional<unsigned> NumExpanded) {
+TemplateTypeParmDecl *TemplateTypeParmDecl::Create(
+ const ASTContext &C, DeclContext *DC, SourceLocation KeyLoc,
+ SourceLocation NameLoc, unsigned D, unsigned P, IdentifierInfo *Id,
+ bool Typename, bool ParameterPack, bool HasTypeConstraint,
+ std::optional<unsigned> NumExpanded) {
auto *TTPDecl =
new (C, DC,
additionalSizeToAlloc<TypeConstraint>(HasTypeConstraint ? 1 : 0))
@@ -643,9 +654,9 @@ TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
TemplateTypeParmDecl *
TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
- return new (C, ID) TemplateTypeParmDecl(nullptr, SourceLocation(),
- SourceLocation(), nullptr, false,
- false, None);
+ return new (C, ID)
+ TemplateTypeParmDecl(nullptr, SourceLocation(), SourceLocation(), nullptr,
+ false, false, std::nullopt);
}
TemplateTypeParmDecl *
@@ -653,8 +664,8 @@ TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, unsigned ID,
bool HasTypeConstraint) {
return new (C, ID,
additionalSizeToAlloc<TypeConstraint>(HasTypeConstraint ? 1 : 0))
- TemplateTypeParmDecl(nullptr, SourceLocation(), SourceLocation(),
- nullptr, false, HasTypeConstraint, None);
+ TemplateTypeParmDecl(nullptr, SourceLocation(), SourceLocation(), nullptr,
+ false, HasTypeConstraint, std::nullopt);
}
SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const {
@@ -768,12 +779,12 @@ NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
unsigned NumExpandedTypes,
bool HasTypeConstraint) {
auto *NTTP =
- new (C, ID, additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>,
- Expr *>(
- NumExpandedTypes, HasTypeConstraint ? 1 : 0))
+ new (C, ID,
+ additionalSizeToAlloc<std::pair<QualType, TypeSourceInfo *>, Expr *>(
+ NumExpandedTypes, HasTypeConstraint ? 1 : 0))
NonTypeTemplateParmDecl(nullptr, SourceLocation(), SourceLocation(),
- 0, 0, nullptr, QualType(), nullptr, None,
- None);
+ 0, 0, nullptr, QualType(), nullptr,
+ std::nullopt, std::nullopt);
NTTP->NumExpandedTypes = NumExpandedTypes;
return NTTP;
}
@@ -841,7 +852,7 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
auto *TTP =
new (C, ID, additionalSizeToAlloc<TemplateParameterList *>(NumExpansions))
TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, nullptr,
- nullptr, None);
+ nullptr, std::nullopt);
TTP->NumExpandedParams = NumExpansions;
return TTP;
}
@@ -930,6 +941,14 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
SpecializedTemplate, Args, 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
+ // complete using the external AST if the template's declaration came from an
+ // external AST.
+ if (!SpecializedTemplate->getTemplatedDecl()->isCompleteDefinition())
+ Result->setHasExternalLexicalStorage(
+ SpecializedTemplate->getTemplatedDecl()->hasExternalLexicalStorage());
+
Context.getTypeDeclType(Result, PrevDecl);
return Result;
}
@@ -1032,6 +1051,44 @@ ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C,
}
//===----------------------------------------------------------------------===//
+// ImplicitConceptSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+ImplicitConceptSpecializationDecl::ImplicitConceptSpecializationDecl(
+ DeclContext *DC, SourceLocation SL,
+ ArrayRef<TemplateArgument> ConvertedArgs)
+ : Decl(ImplicitConceptSpecialization, DC, SL),
+ NumTemplateArgs(ConvertedArgs.size()) {
+ setTemplateArguments(ConvertedArgs);
+}
+
+ImplicitConceptSpecializationDecl::ImplicitConceptSpecializationDecl(
+ EmptyShell Empty, unsigned NumTemplateArgs)
+ : Decl(ImplicitConceptSpecialization, Empty),
+ NumTemplateArgs(NumTemplateArgs) {}
+
+ImplicitConceptSpecializationDecl *ImplicitConceptSpecializationDecl::Create(
+ const ASTContext &C, DeclContext *DC, SourceLocation SL,
+ ArrayRef<TemplateArgument> ConvertedArgs) {
+ return new (C, DC,
+ additionalSizeToAlloc<TemplateArgument>(ConvertedArgs.size()))
+ ImplicitConceptSpecializationDecl(DC, SL, ConvertedArgs);
+}
+
+ImplicitConceptSpecializationDecl *
+ImplicitConceptSpecializationDecl::CreateDeserialized(
+ const ASTContext &C, unsigned ID, unsigned NumTemplateArgs) {
+ return new (C, ID, additionalSizeToAlloc<TemplateArgument>(NumTemplateArgs))
+ ImplicitConceptSpecializationDecl(EmptyShell{}, NumTemplateArgs);
+}
+
+void ImplicitConceptSpecializationDecl::setTemplateArguments(
+ ArrayRef<TemplateArgument> Converted) {
+ assert(Converted.size() == NumTemplateArgs);
+ std::uninitialized_copy(Converted.begin(), Converted.end(),
+ getTrailingObjects<TemplateArgument>());
+}
+
+//===----------------------------------------------------------------------===//
// ClassTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
void ClassTemplatePartialSpecializationDecl::anchor() {}
@@ -1457,8 +1514,8 @@ createTypePackElementParameterList(const ASTContext &C, DeclContext *DC) {
// template <std::size_t Index, typename ...T>
NamedDecl *Params[] = {Index, Ts};
return TemplateParameterList::Create(C, SourceLocation(), SourceLocation(),
- llvm::makeArrayRef(Params),
- SourceLocation(), nullptr);
+ llvm::ArrayRef(Params), SourceLocation(),
+ nullptr);
}
static TemplateParameterList *createBuiltinTemplateParameterList(
@@ -1511,9 +1568,10 @@ TemplateParamObjectDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return TPOD;
}
-void TemplateParamObjectDecl::printName(llvm::raw_ostream &OS) const {
+void TemplateParamObjectDecl::printName(llvm::raw_ostream &OS,
+ const PrintingPolicy &Policy) const {
OS << "<template param ";
- printAsExpr(OS);
+ printAsExpr(OS, Policy);
OS << ">";
}
@@ -1535,3 +1593,56 @@ void TemplateParamObjectDecl::printAsInit(llvm::raw_ostream &OS,
const PrintingPolicy &Policy) const {
getValue().printPretty(OS, Policy, getType(), &getASTContext());
}
+
+TemplateParameterList *clang::getReplacedTemplateParameterList(Decl *D) {
+ switch (D->getKind()) {
+ case Decl::Kind::ClassTemplate:
+ return cast<ClassTemplateDecl>(D)->getTemplateParameters();
+ case Decl::Kind::ClassTemplateSpecialization: {
+ const auto *CTSD = cast<ClassTemplateSpecializationDecl>(D);
+ auto P = CTSD->getSpecializedTemplateOrPartial();
+ if (const auto *CTPSD =
+ P.dyn_cast<ClassTemplatePartialSpecializationDecl *>())
+ return CTPSD->getTemplateParameters();
+ return cast<ClassTemplateDecl *>(P)->getTemplateParameters();
+ }
+ case Decl::Kind::ClassTemplatePartialSpecialization:
+ return cast<ClassTemplatePartialSpecializationDecl>(D)
+ ->getTemplateParameters();
+ case Decl::Kind::TypeAliasTemplate:
+ return cast<TypeAliasTemplateDecl>(D)->getTemplateParameters();
+ case Decl::Kind::BuiltinTemplate:
+ return cast<BuiltinTemplateDecl>(D)->getTemplateParameters();
+ case Decl::Kind::CXXDeductionGuide:
+ case Decl::Kind::CXXConversion:
+ case Decl::Kind::CXXConstructor:
+ case Decl::Kind::CXXDestructor:
+ case Decl::Kind::CXXMethod:
+ case Decl::Kind::Function:
+ return cast<FunctionDecl>(D)
+ ->getTemplateSpecializationInfo()
+ ->getTemplate()
+ ->getTemplateParameters();
+ case Decl::Kind::FunctionTemplate:
+ return cast<FunctionTemplateDecl>(D)->getTemplateParameters();
+ case Decl::Kind::VarTemplate:
+ return cast<VarTemplateDecl>(D)->getTemplateParameters();
+ case Decl::Kind::VarTemplateSpecialization: {
+ const auto *VTSD = cast<VarTemplateSpecializationDecl>(D);
+ auto P = VTSD->getSpecializedTemplateOrPartial();
+ if (const auto *VTPSD =
+ P.dyn_cast<VarTemplatePartialSpecializationDecl *>())
+ return VTPSD->getTemplateParameters();
+ return cast<VarTemplateDecl *>(P)->getTemplateParameters();
+ }
+ case Decl::Kind::VarTemplatePartialSpecialization:
+ return cast<VarTemplatePartialSpecializationDecl>(D)
+ ->getTemplateParameters();
+ case Decl::Kind::TemplateTemplateParm:
+ return cast<TemplateTemplateParmDecl>(D)->getTemplateParameters();
+ case Decl::Kind::Concept:
+ return cast<ConceptDecl>(D)->getTemplateParameters();
+ default:
+ llvm_unreachable("Unhandled templated declaration kind");
+ }
+}
diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp
index b2232ddfced3..c1219041a466 100644
--- a/clang/lib/AST/DeclarationName.cpp
+++ b/clang/lib/AST/DeclarationName.cpp
@@ -72,15 +72,9 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
}
unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs();
for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) {
- switch (LHSSelector.getNameForSlot(I).compare(
- RHSSelector.getNameForSlot(I))) {
- case -1:
- return -1;
- case 1:
- return 1;
- default:
- break;
- }
+ if (int Compare = LHSSelector.getNameForSlot(I).compare(
+ RHSSelector.getNameForSlot(I)))
+ return Compare;
}
return compareInt(LN, RN);
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index ca477e6500c5..67862a8692ac 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -37,6 +37,7 @@
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstring>
+#include <optional>
using namespace clang;
const Expr *Expr::getBestDynamicClassTypeExpr() const {
@@ -203,6 +204,88 @@ bool Expr::isKnownToHaveBooleanValue(bool Semantic) const {
return false;
}
+bool Expr::isFlexibleArrayMemberLike(
+ ASTContext &Context,
+ LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
+ bool IgnoreTemplateOrMacroSubstitution) const {
+
+ // For compatibility with existing code, we treat arrays of length 0 or
+ // 1 as flexible array members.
+ const auto *CAT = Context.getAsConstantArrayType(getType());
+ if (CAT) {
+ llvm::APInt Size = CAT->getSize();
+
+ using FAMKind = LangOptions::StrictFlexArraysLevelKind;
+
+ if (StrictFlexArraysLevel == FAMKind::IncompleteOnly)
+ return false;
+
+ // GCC extension, only allowed to represent a FAM.
+ if (Size == 0)
+ return true;
+
+ if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1))
+ return false;
+
+ if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete && Size.uge(2))
+ return false;
+ } else if (!Context.getAsIncompleteArrayType(getType()))
+ return false;
+
+ const Expr *E = IgnoreParens();
+
+ const NamedDecl *ND = nullptr;
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
+ ND = DRE->getDecl();
+ else if (const auto *ME = dyn_cast<MemberExpr>(E))
+ ND = ME->getMemberDecl();
+ else if (const auto *IRE = dyn_cast<ObjCIvarRefExpr>(E))
+ return IRE->getDecl()->getNextIvar() == nullptr;
+
+ if (!ND)
+ return false;
+
+ // A flexible array member must be the last member in the class.
+ // FIXME: If the base type of the member expr is not FD->getParent(),
+ // this should not be treated as a flexible array member access.
+ if (const auto *FD = dyn_cast<FieldDecl>(ND)) {
+ // GCC treats an array memeber of a union as an FAM if the size is one or
+ // zero.
+ if (CAT) {
+ llvm::APInt Size = CAT->getSize();
+ if (FD->getParent()->isUnion() && (Size.isZero() || Size.isOne()))
+ return true;
+ }
+
+ // Don't consider sizes resulting from macro expansions or template argument
+ // substitution to form C89 tail-padded arrays.
+ if (IgnoreTemplateOrMacroSubstitution) {
+ TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
+ while (TInfo) {
+ TypeLoc TL = TInfo->getTypeLoc();
+ // Look through typedefs.
+ if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) {
+ const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
+ TInfo = TDL->getTypeSourceInfo();
+ continue;
+ }
+ if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) {
+ const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
+ if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
+ return false;
+ }
+ break;
+ }
+ }
+
+ RecordDecl::field_iterator FI(
+ DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
+ return ++FI == FD->getParent()->field_end();
+ }
+
+ return false;
+}
+
const ValueDecl *
Expr::getAsBuiltinConstantDeclRef(const ASTContext &Context) const {
Expr::EvalResult Eval;
@@ -277,7 +360,7 @@ ConstantExpr::getStorageKind(const APValue &Value) {
case APValue::Int:
if (!Value.getInt().needsCleanup())
return ConstantExpr::RSK_Int64;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return ConstantExpr::RSK_APValue;
}
@@ -562,10 +645,10 @@ std::string SYCLUniqueStableNameExpr::ComputeName(ASTContext &Context) const {
std::string SYCLUniqueStableNameExpr::ComputeName(ASTContext &Context,
QualType Ty) {
auto MangleCallback = [](ASTContext &Ctx,
- const NamedDecl *ND) -> llvm::Optional<unsigned> {
+ const NamedDecl *ND) -> std::optional<unsigned> {
if (const auto *RD = dyn_cast<CXXRecordDecl>(ND))
return RD->getDeviceLambdaManglingNumber();
- return llvm::None;
+ return std::nullopt;
};
std::unique_ptr<MangleContext> Ctx{ItaniumMangleContext::create(
@@ -2633,7 +2716,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
}
// Fallthrough for generic call handling.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
}
case CallExprClass:
case CXXMemberCallExprClass:
@@ -3562,6 +3645,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
case ShuffleVectorExprClass:
case ConvertVectorExprClass:
case AsTypeExprClass:
+ case CXXParenListInitExprClass:
// These have a side-effect if any subexpression does.
break;
@@ -3609,7 +3693,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx,
DCE->getCastKind() == CK_Dynamic)
return true;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case ImplicitCastExprClass:
case CStyleCastExprClass:
case CXXStaticCastExprClass:
@@ -3857,7 +3941,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
if (getType().isNull())
return NPCK_NotNull;
- // C++11 nullptr_t is always a null pointer constant.
+ // C++11/C2x nullptr_t is always a null pointer constant.
if (getType()->isNullPtrType())
return NPCK_CXX11_nullptr;
@@ -4451,7 +4535,8 @@ DesignatedInitUpdateExpr::DesignatedInitUpdateExpr(const ASTContext &C,
OK_Ordinary) {
BaseAndUpdaterExprs[0] = baseExpr;
- InitListExpr *ILE = new (C) InitListExpr(C, lBraceLoc, None, rBraceLoc);
+ InitListExpr *ILE =
+ new (C) InitListExpr(C, lBraceLoc, std::nullopt, rBraceLoc);
ILE->setType(baseExpr->getType());
BaseAndUpdaterExprs[1] = ILE;
@@ -4831,7 +4916,7 @@ RecoveryExpr::RecoveryExpr(ASTContext &Ctx, QualType T, SourceLocation BeginLoc,
OK_Ordinary),
BeginLoc(BeginLoc), EndLoc(EndLoc), NumExprs(SubExprs.size()) {
assert(!T.isNull());
- assert(llvm::all_of(SubExprs, [](Expr* E) { return E != nullptr; }));
+ assert(!llvm::is_contained(SubExprs, nullptr));
llvm::copy(SubExprs, getTrailingObjects<Expr *>());
setDependence(computeDependence(this));
diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp
index 891105692980..2a9e33595013 100644
--- a/clang/lib/AST/ExprCXX.cpp
+++ b/clang/lib/AST/ExprCXX.cpp
@@ -38,6 +38,7 @@
#include <cstddef>
#include <cstring>
#include <memory>
+#include <optional>
using namespace clang;
@@ -182,7 +183,7 @@ CXXNewExpr::CXXNewExpr(bool IsGlobalNew, FunctionDecl *OperatorNew,
FunctionDecl *OperatorDelete, bool ShouldPassAlignment,
bool UsualArrayDeleteWantsSize,
ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens,
- Optional<Expr *> ArraySize,
+ std::optional<Expr *> ArraySize,
InitializationStyle InitializationStyle,
Expr *Initializer, QualType Ty,
TypeSourceInfo *AllocatedTypeInfo, SourceRange Range,
@@ -244,7 +245,7 @@ CXXNewExpr::Create(const ASTContext &Ctx, bool IsGlobalNew,
FunctionDecl *OperatorNew, FunctionDecl *OperatorDelete,
bool ShouldPassAlignment, bool UsualArrayDeleteWantsSize,
ArrayRef<Expr *> PlacementArgs, SourceRange TypeIdParens,
- Optional<Expr *> ArraySize,
+ std::optional<Expr *> ArraySize,
InitializationStyle InitializationStyle, Expr *Initializer,
QualType Ty, TypeSourceInfo *AllocatedTypeInfo,
SourceRange Range, SourceRange DirectInitRange) {
@@ -314,7 +315,7 @@ QualType CXXDeleteExpr::getDestroyedType() const {
// CXXPseudoDestructorExpr
PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info)
: Type(Info) {
- Location = Info->getTypeLoc().getLocalSourceRange().getBegin();
+ Location = Info->getTypeLoc().getBeginLoc();
}
CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(
@@ -341,7 +342,7 @@ QualType CXXPseudoDestructorExpr::getDestroyedType() const {
SourceLocation CXXPseudoDestructorExpr::getEndLoc() const {
SourceLocation End = DestroyedType.getLocation();
if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo())
- End = TInfo->getTypeLoc().getLocalSourceRange().getEnd();
+ End = TInfo->getTypeLoc().getSourceRange().getEnd();
return End;
}
@@ -949,9 +950,43 @@ const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const {
return cast<FunctionDecl>(getCalleeDecl())->getLiteralIdentifier();
}
+CXXDefaultArgExpr *CXXDefaultArgExpr::CreateEmpty(const ASTContext &C,
+ bool HasRewrittenInit) {
+ size_t Size = totalSizeToAlloc<Expr *>(HasRewrittenInit);
+ auto *Mem = C.Allocate(Size, alignof(CXXDefaultArgExpr));
+ return new (Mem) CXXDefaultArgExpr(EmptyShell(), HasRewrittenInit);
+}
+
+CXXDefaultArgExpr *CXXDefaultArgExpr::Create(const ASTContext &C,
+ SourceLocation Loc,
+ ParmVarDecl *Param,
+ Expr *RewrittenExpr,
+ DeclContext *UsedContext) {
+ size_t Size = totalSizeToAlloc<Expr *>(RewrittenExpr != nullptr);
+ auto *Mem = C.Allocate(Size, alignof(CXXDefaultArgExpr));
+ return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param,
+ RewrittenExpr, UsedContext);
+}
+
+Expr *CXXDefaultArgExpr::getExpr() {
+ return CXXDefaultArgExprBits.HasRewrittenInit ? getAdjustedRewrittenExpr()
+ : getParam()->getDefaultArg();
+}
+
+Expr *CXXDefaultArgExpr::getAdjustedRewrittenExpr() {
+ assert(hasRewrittenInit() &&
+ "expected this CXXDefaultArgExpr to have a rewritten init.");
+ Expr *Init = getRewrittenExpr();
+ if (auto *E = dyn_cast_if_present<FullExpr>(Init))
+ if (!isa<ConstantExpr>(E))
+ return E->getSubExpr();
+ return Init;
+}
+
CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &Ctx,
SourceLocation Loc, FieldDecl *Field,
- QualType Ty, DeclContext *UsedContext)
+ QualType Ty, DeclContext *UsedContext,
+ Expr *RewrittenInitExpr)
: Expr(CXXDefaultInitExprClass, Ty.getNonLValueExprType(Ctx),
Ty->isLValueReferenceType() ? VK_LValue
: Ty->isRValueReferenceType() ? VK_XValue
@@ -959,11 +994,43 @@ CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &Ctx,
/*FIXME*/ OK_Ordinary),
Field(Field), UsedContext(UsedContext) {
CXXDefaultInitExprBits.Loc = Loc;
+ CXXDefaultInitExprBits.HasRewrittenInit = RewrittenInitExpr != nullptr;
+
+ if (CXXDefaultInitExprBits.HasRewrittenInit)
+ *getTrailingObjects<Expr *>() = RewrittenInitExpr;
+
assert(Field->hasInClassInitializer());
setDependence(computeDependence(this));
}
+CXXDefaultInitExpr *CXXDefaultInitExpr::CreateEmpty(const ASTContext &C,
+ bool HasRewrittenInit) {
+ size_t Size = totalSizeToAlloc<Expr *>(HasRewrittenInit);
+ auto *Mem = C.Allocate(Size, alignof(CXXDefaultInitExpr));
+ return new (Mem) CXXDefaultInitExpr(EmptyShell(), HasRewrittenInit);
+}
+
+CXXDefaultInitExpr *CXXDefaultInitExpr::Create(const ASTContext &Ctx,
+ SourceLocation Loc,
+ FieldDecl *Field,
+ DeclContext *UsedContext,
+ Expr *RewrittenInitExpr) {
+
+ size_t Size = totalSizeToAlloc<Expr *>(RewrittenInitExpr != nullptr);
+ auto *Mem = Ctx.Allocate(Size, alignof(CXXDefaultInitExpr));
+ return new (Mem) CXXDefaultInitExpr(Ctx, Loc, Field, Field->getType(),
+ UsedContext, RewrittenInitExpr);
+}
+
+Expr *CXXDefaultInitExpr::getExpr() {
+ assert(Field->getInClassInitializer() && "initializer hasn't been parsed");
+ if (hasRewrittenInit())
+ return getRewrittenExpr();
+
+ return Field->getInClassInitializer();
+}
+
CXXTemporary *CXXTemporary::Create(const ASTContext &C,
const CXXDestructorDecl *Destructor) {
return new (C) CXXTemporary(Destructor);
@@ -1087,7 +1154,7 @@ CXXConstructExpr::CXXConstructExpr(StmtClass SC, EmptyShell Empty,
: Expr(SC, Empty), NumArgs(NumArgs) {}
LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit,
- LambdaCaptureKind Kind, VarDecl *Var,
+ LambdaCaptureKind Kind, ValueDecl *Var,
SourceLocation EllipsisLoc)
: DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc) {
unsigned Bits = 0;
@@ -1097,7 +1164,7 @@ LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit,
switch (Kind) {
case LCK_StarThis:
Bits |= Capture_ByCopy;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LCK_This:
assert(!Var && "'this' capture cannot have a variable!");
Bits |= Capture_This;
@@ -1105,7 +1172,7 @@ LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit,
case LCK_ByCopy:
Bits |= Capture_ByCopy;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LCK_ByRef:
assert(Var && "capture must have a variable!");
break;
@@ -1211,16 +1278,16 @@ const CompoundStmt *LambdaExpr::getCompoundStmtBody() const {
}
bool LambdaExpr::isInitCapture(const LambdaCapture *C) const {
- return (C->capturesVariable() && C->getCapturedVar()->isInitCapture() &&
- (getCallOperator() == C->getCapturedVar()->getDeclContext()));
+ return C->capturesVariable() && C->getCapturedVar()->isInitCapture() &&
+ getCallOperator() == C->getCapturedVar()->getDeclContext();
}
LambdaExpr::capture_iterator LambdaExpr::capture_begin() const {
- return getLambdaClass()->getLambdaData().Captures;
+ return getLambdaClass()->captures_begin();
}
LambdaExpr::capture_iterator LambdaExpr::capture_end() const {
- return capture_begin() + capture_size();
+ return getLambdaClass()->captures_end();
}
LambdaExpr::capture_range LambdaExpr::captures() const {
@@ -1232,9 +1299,8 @@ LambdaExpr::capture_iterator LambdaExpr::explicit_capture_begin() const {
}
LambdaExpr::capture_iterator LambdaExpr::explicit_capture_end() const {
- struct CXXRecordDecl::LambdaDefinitionData &Data
- = getLambdaClass()->getLambdaData();
- return Data.Captures + Data.NumExplicitCaptures;
+ return capture_begin() +
+ getLambdaClass()->getLambdaData().NumExplicitCaptures;
}
LambdaExpr::capture_range LambdaExpr::explicit_captures() const {
@@ -1555,12 +1621,12 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() {
return Record;
}
-SizeOfPackExpr *
-SizeOfPackExpr::Create(ASTContext &Context, SourceLocation OperatorLoc,
- NamedDecl *Pack, SourceLocation PackLoc,
- SourceLocation RParenLoc,
- Optional<unsigned> Length,
- ArrayRef<TemplateArgument> PartialArgs) {
+SizeOfPackExpr *SizeOfPackExpr::Create(ASTContext &Context,
+ SourceLocation OperatorLoc,
+ NamedDecl *Pack, SourceLocation PackLoc,
+ SourceLocation RParenLoc,
+ std::optional<unsigned> Length,
+ ArrayRef<TemplateArgument> PartialArgs) {
void *Storage =
Context.Allocate(totalSizeToAlloc<TemplateArgument>(PartialArgs.size()));
return new (Storage) SizeOfPackExpr(Context.getSizeType(), OperatorLoc, Pack,
@@ -1574,6 +1640,11 @@ SizeOfPackExpr *SizeOfPackExpr::CreateDeserialized(ASTContext &Context,
return new (Storage) SizeOfPackExpr(EmptyShell(), NumPartialArgs);
}
+NonTypeTemplateParmDecl *SubstNonTypeTemplateParmExpr::getParameter() const {
+ return cast<NonTypeTemplateParmDecl>(
+ getReplacedTemplateParameterList(getAssociatedDecl())->asArray()[Index]);
+}
+
QualType SubstNonTypeTemplateParmExpr::getParameterType(
const ASTContext &Context) const {
// Note that, for a class type NTTP, we will have an lvalue of type 'const
@@ -1584,17 +1655,24 @@ QualType SubstNonTypeTemplateParmExpr::getParameterType(
}
SubstNonTypeTemplateParmPackExpr::SubstNonTypeTemplateParmPackExpr(
- QualType T, ExprValueKind ValueKind, NonTypeTemplateParmDecl *Param,
- SourceLocation NameLoc, const TemplateArgument &ArgPack)
+ QualType T, ExprValueKind ValueKind, SourceLocation NameLoc,
+ const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index)
: Expr(SubstNonTypeTemplateParmPackExprClass, T, ValueKind, OK_Ordinary),
- Param(Param), Arguments(ArgPack.pack_begin()),
- NumArguments(ArgPack.pack_size()), NameLoc(NameLoc) {
+ AssociatedDecl(AssociatedDecl), Arguments(ArgPack.pack_begin()),
+ NumArguments(ArgPack.pack_size()), Index(Index), NameLoc(NameLoc) {
+ assert(AssociatedDecl != nullptr);
setDependence(ExprDependence::TypeValueInstantiation |
ExprDependence::UnexpandedPack);
}
+NonTypeTemplateParmDecl *
+SubstNonTypeTemplateParmPackExpr::getParameterPack() const {
+ return cast<NonTypeTemplateParmDecl>(
+ getReplacedTemplateParameterList(getAssociatedDecl())->asArray()[Index]);
+}
+
TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const {
- return TemplateArgument(llvm::makeArrayRef(Arguments, NumArguments));
+ return TemplateArgument(llvm::ArrayRef(Arguments, NumArguments));
}
FunctionParmPackExpr::FunctionParmPackExpr(QualType T, VarDecl *ParamPack,
@@ -1746,3 +1824,21 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx,
alignof(CUDAKernelCallExpr));
return new (Mem) CUDAKernelCallExpr(NumArgs, HasFPFeatures, Empty);
}
+
+CXXParenListInitExpr *
+CXXParenListInitExpr::Create(ASTContext &C, ArrayRef<Expr *> Args, QualType T,
+ unsigned NumUserSpecifiedExprs,
+ SourceLocation InitLoc, SourceLocation LParenLoc,
+ SourceLocation RParenLoc) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(Args.size()));
+ return new (Mem) CXXParenListInitExpr(Args, T, NumUserSpecifiedExprs, InitLoc,
+ LParenLoc, RParenLoc);
+}
+
+CXXParenListInitExpr *CXXParenListInitExpr::CreateEmpty(ASTContext &C,
+ unsigned NumExprs,
+ EmptyShell Empty) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(NumExprs),
+ alignof(CXXParenListInitExpr));
+ return new (Mem) CXXParenListInitExpr(Empty, NumExprs);
+}
diff --git a/clang/lib/AST/ExprClassification.cpp b/clang/lib/AST/ExprClassification.cpp
index 6c122cac2c60..12193b7812f9 100644
--- a/clang/lib/AST/ExprClassification.cpp
+++ b/clang/lib/AST/ExprClassification.cpp
@@ -160,7 +160,6 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXPseudoDestructorExprClass:
case Expr::UnaryExprOrTypeTraitExprClass:
case Expr::CXXNewExprClass:
- case Expr::CXXThisExprClass:
case Expr::CXXNullPtrLiteralExprClass:
case Expr::ImaginaryLiteralClass:
case Expr::GNUNullExprClass:
@@ -205,6 +204,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::RequiresExprClass:
return Cl::CL_PRValue;
+ // Make HLSL this reference-like
+ case Expr::CXXThisExprClass:
+ return Lang.HLSL ? Cl::CL_LValue : Cl::CL_PRValue;
+
case Expr::ConstantExprClass:
return ClassifyInternal(Ctx, cast<ConstantExpr>(E)->getSubExpr());
@@ -442,6 +445,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::SYCLUniqueStableNameExprClass:
return Cl::CL_PRValue;
break;
+
+ case Expr::CXXParenListInitExprClass:
+ if (isa<ArrayType>(E->getType()))
+ return Cl::CL_ArrayTemporary;
+ return Cl::CL_ClassTemporary;
}
llvm_unreachable("unhandled expression kind in classification");
diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp
index c17453fb45fb..fc8f1eb2abf1 100644
--- a/clang/lib/AST/ExprConcepts.cpp
+++ b/clang/lib/AST/ExprConcepts.cpp
@@ -35,16 +35,15 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
+ ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction)
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
NamedConcept, ArgsAsWritten),
- NumTemplateArgs(ConvertedArgs.size()),
+ SpecDecl(SpecDecl),
Satisfaction(Satisfaction
? ASTConstraintSatisfaction::Create(C, *Satisfaction)
: nullptr) {
- setTemplateArguments(ConvertedArgs);
setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
// Currently guaranteed by the fact concepts can only be at namespace-scope.
@@ -56,50 +55,34 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
"should not be value-dependent");
}
-ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty,
- unsigned NumTemplateArgs)
- : Expr(ConceptSpecializationExprClass, Empty),
- NumTemplateArgs(NumTemplateArgs) {}
+ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty)
+ : Expr(ConceptSpecializationExprClass, Empty) {}
-void ConceptSpecializationExpr::setTemplateArguments(
- ArrayRef<TemplateArgument> Converted) {
- assert(Converted.size() == NumTemplateArgs);
- std::uninitialized_copy(Converted.begin(), Converted.end(),
- getTrailingObjects<TemplateArgument>());
-}
-
-ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(const ASTContext &C,
- NestedNameSpecifierLoc NNS,
- SourceLocation TemplateKWLoc,
- DeclarationNameInfo ConceptNameInfo,
- NamedDecl *FoundDecl,
- ConceptDecl *NamedConcept,
- const ASTTemplateArgumentListInfo *ArgsAsWritten,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction) {
- void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
- ConvertedArgs.size()));
- return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc,
- ConceptNameInfo, FoundDecl,
- NamedConcept, ArgsAsWritten,
- ConvertedArgs, Satisfaction);
+ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
+ const ASTContext &C, NestedNameSpecifierLoc NNS,
+ SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
+ NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+ const ASTTemplateArgumentListInfo *ArgsAsWritten,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ const ConstraintSatisfaction *Satisfaction) {
+ return new (C) ConceptSpecializationExpr(
+ C, NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
+ ArgsAsWritten, SpecDecl, Satisfaction);
}
ConceptSpecializationExpr::ConceptSpecializationExpr(
const ASTContext &C, ConceptDecl *NamedConcept,
- ArrayRef<TemplateArgument> ConvertedArgs,
+ ImplicitConceptSpecializationDecl *SpecDecl,
const ConstraintSatisfaction *Satisfaction, bool Dependent,
bool ContainsUnexpandedParameterPack)
: Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
DeclarationNameInfo(), NamedConcept, NamedConcept,
nullptr),
- NumTemplateArgs(ConvertedArgs.size()),
+ SpecDecl(SpecDecl),
Satisfaction(Satisfaction
? ASTConstraintSatisfaction::Create(C, *Satisfaction)
: nullptr) {
- setTemplateArguments(ConvertedArgs);
ExprDependence D = ExprDependence::None;
if (!Satisfaction)
D |= ExprDependence::Value;
@@ -110,26 +93,14 @@ ConceptSpecializationExpr::ConceptSpecializationExpr(
setDependence(D);
}
-ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(const ASTContext &C,
- ConceptDecl *NamedConcept,
- ArrayRef<TemplateArgument> ConvertedArgs,
- const ConstraintSatisfaction *Satisfaction,
- bool Dependent,
- bool ContainsUnexpandedParameterPack) {
- void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
- ConvertedArgs.size()));
- return new (Buffer) ConceptSpecializationExpr(
- C, NamedConcept, ConvertedArgs, Satisfaction, Dependent,
- ContainsUnexpandedParameterPack);
-}
-
-ConceptSpecializationExpr *
-ConceptSpecializationExpr::Create(ASTContext &C, EmptyShell Empty,
- unsigned NumTemplateArgs) {
- void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>(
- NumTemplateArgs));
- return new (Buffer) ConceptSpecializationExpr(Empty, NumTemplateArgs);
+ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
+ const ASTContext &C, ConceptDecl *NamedConcept,
+ ImplicitConceptSpecializationDecl *SpecDecl,
+ const ConstraintSatisfaction *Satisfaction, bool Dependent,
+ bool ContainsUnexpandedParameterPack) {
+ return new (C)
+ ConceptSpecializationExpr(C, NamedConcept, SpecDecl, Satisfaction,
+ Dependent, ContainsUnexpandedParameterPack);
}
const TypeConstraint *
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 9d92c848ccb8..912a210fd254 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -52,13 +52,14 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/APFixedPoint.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cstring>
#include <functional>
+#include <optional>
#define DEBUG_TYPE "exprconstant"
@@ -68,7 +69,6 @@ using llvm::APInt;
using llvm::APSInt;
using llvm::APFloat;
using llvm::FixedPointSemantics;
-using llvm::Optional;
namespace {
struct LValue;
@@ -578,7 +578,7 @@ namespace {
/// LambdaCaptureFields - Mapping from captured variables/this to
/// corresponding data members in the closure class.
- llvm::DenseMap<const VarDecl *, FieldDecl *> LambdaCaptureFields;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> LambdaCaptureFields;
FieldDecl *LambdaThisCaptureField;
CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
@@ -592,11 +592,6 @@ namespace {
auto LB = Temporaries.lower_bound(KV);
if (LB != Temporaries.end() && LB->first == KV)
return &LB->second;
- // Pair (Key,Version) wasn't found in the map. Check that no elements
- // in the map have 'Key' as their key.
- assert((LB == Temporaries.end() || LB->first.first != Key) &&
- (LB == Temporaries.begin() || std::prev(LB)->first.first != Key) &&
- "Element with key 'Key' found in map");
return nullptr;
}
@@ -660,6 +655,19 @@ namespace {
CallStackFrame &Frame;
const LValue *OldThis;
};
+
+ // A shorthand time trace scope struct, prints source range, for example
+ // {"name":"EvaluateAsRValue","args":{"detail":"<test.cc:8:21, col:25>"}}}
+ class ExprTimeTraceScope {
+ public:
+ ExprTimeTraceScope(const Expr *E, const ASTContext &Ctx, StringRef Name)
+ : TimeScope(Name, [E, &Ctx] {
+ return E->getSourceRange().printToString(Ctx.getSourceManager());
+ }) {}
+
+ private:
+ llvm::TimeTraceScope TimeScope;
+ };
}
static bool HandleDestruction(EvalInfo &Info, const Expr *E,
@@ -917,10 +925,6 @@ namespace {
/// fold (not just why it's not strictly a constant expression)?
bool HasFoldFailureDiagnostic;
- /// Whether or not we're in a context where the front end requires a
- /// constant value.
- bool InConstantContext;
-
/// Whether we're checking that an expression is a potential constant
/// expression. If so, do not fail on constructs that could become constant
/// later on (such as a use of an undefined global).
@@ -976,8 +980,7 @@ namespace {
BottomFrame(*this, SourceLocation(), nullptr, nullptr, CallRef()),
EvaluatingDecl((const ValueDecl *)nullptr),
EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false),
- HasFoldFailureDiagnostic(false), InConstantContext(false),
- EvalMode(Mode) {}
+ HasFoldFailureDiagnostic(false), EvalMode(Mode) {}
~EvalInfo() {
discardCleanups();
@@ -1036,8 +1039,8 @@ namespace {
APValue *createHeapAlloc(const Expr *E, QualType T, LValue &LV);
- Optional<DynAlloc*> lookupDynamicAlloc(DynamicAllocLValue DA) {
- Optional<DynAlloc*> Result;
+ std::optional<DynAlloc *> lookupDynamicAlloc(DynamicAllocLValue DA) {
+ std::optional<DynAlloc *> Result;
auto It = HeapAllocs.find(DA);
if (It != HeapAllocs.end())
Result = &It->second;
@@ -1132,7 +1135,7 @@ namespace {
if (!HasFoldFailureDiagnostic)
break;
// We've already failed to fold something. Keep that diagnostic.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case EM_ConstantExpression:
case EM_ConstantExpressionUnevaluated:
setActiveDiagnostic(false);
@@ -1219,7 +1222,7 @@ namespace {
/// (Foo(), 1) // use noteSideEffect
/// (Foo() || true) // use noteSideEffect
/// Foo() + 1 // use noteFailure
- LLVM_NODISCARD bool noteFailure() {
+ [[nodiscard]] bool noteFailure() {
// Failure when evaluating some expression often means there is some
// subexpression whose evaluation was skipped. Therefore, (because we
// don't track whether we skipped an expression when unwinding after an
@@ -1954,8 +1957,8 @@ static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) {
return true;
}
-/// Should this call expression be treated as a constant?
-static bool IsConstantCall(const CallExpr *E) {
+/// Should this call expression be treated as a no-op?
+static bool IsNoOpCall(const CallExpr *E) {
unsigned Builtin = E->getBuiltinCallee();
return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
@@ -2006,7 +2009,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
case Expr::ObjCBoxedExprClass:
return cast<ObjCBoxedExpr>(E)->isExpressibleAsConstantInitializer();
case Expr::CallExprClass:
- return IsConstantCall(cast<CallExpr>(E));
+ return IsNoOpCall(cast<CallExpr>(E));
// For GCC compatibility, &&label has static storage duration.
case Expr::AddrLabelExprClass:
return true;
@@ -2095,7 +2098,7 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
Info.Note(E->getExprLoc(), diag::note_constexpr_temporary_here);
else if (DynamicAllocLValue DA = Base.dyn_cast<DynamicAllocLValue>()) {
// FIXME: Produce a note for dangling pointers too.
- if (Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA))
+ if (std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA))
Info.Note((*Alloc)->AllocExpr->getExprLoc(),
diag::note_constexpr_dynamic_alloc_here);
}
@@ -2174,12 +2177,10 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// assumed to be global here.
if (!IsGlobalLValue(Base)) {
if (Info.getLangOpts().CPlusPlus11) {
- const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
Info.FFDiag(Loc, diag::note_constexpr_non_global, 1)
- << IsReferenceType << !Designator.Entries.empty()
- << !!VD << VD;
-
- auto *VarD = dyn_cast_or_null<VarDecl>(VD);
+ << IsReferenceType << !Designator.Entries.empty() << !!BaseVD
+ << BaseVD;
+ auto *VarD = dyn_cast_or_null<VarDecl>(BaseVD);
if (VarD && VarD->isConstexpr()) {
// Non-static local constexpr variables have unintuitive semantics:
// constexpr int a = 1;
@@ -2470,6 +2471,7 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
// A null base expression indicates a null pointer. These are always
// evaluatable, and they are false unless the offset is zero.
if (!Value.getLValueBase()) {
+ // TODO: Should a non-null pointer with an offset of zero evaluate to true?
Result = !Value.getLValueOffset().isZero();
return true;
}
@@ -2482,6 +2484,7 @@ static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) {
}
static bool HandleConversionToBool(const APValue &Val, bool &Result) {
+ // TODO: This function should produce notes if it fails.
switch (Val.getKind()) {
case APValue::None:
case APValue::Indeterminate:
@@ -2506,6 +2509,9 @@ static bool HandleConversionToBool(const APValue &Val, bool &Result) {
case APValue::LValue:
return EvalPointerValueAsBool(Val, Result);
case APValue::MemberPointer:
+ if (Val.getMemberPointerDecl() && Val.getMemberPointerDecl()->isWeak()) {
+ return false;
+ }
Result = Val.getMemberPointerDecl();
return true;
case APValue::Vector:
@@ -2636,14 +2642,9 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
QualType SrcType, const APSInt &Value,
QualType DestType, APFloat &Result) {
Result = APFloat(Info.Ctx.getFloatTypeSemantics(DestType), 1);
- APFloat::opStatus St = Result.convertFromAPInt(Value, Value.isSigned(),
- APFloat::rmNearestTiesToEven);
- if (!Info.InConstantContext && St != llvm::APFloatBase::opOK &&
- FPO.isFPConstrained()) {
- Info.FFDiag(E, diag::note_constexpr_float_arithmetic_strict);
- return false;
- }
- return true;
+ llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
+ APFloat::opStatus St = Result.convertFromAPInt(Value, Value.isSigned(), RM);
+ return checkFloatingPointResult(Info, E, St);
}
static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
@@ -2743,6 +2744,7 @@ static bool CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
BinaryOperatorKind Opcode, APSInt RHS,
APSInt &Result) {
+ bool HandleOverflowResult = true;
switch (Opcode) {
default:
Info.FFDiag(E);
@@ -2765,14 +2767,14 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
Info.FFDiag(E, diag::note_expr_divide_by_zero);
return false;
}
- Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
// Check for overflow case: INT_MIN / -1 or INT_MIN % -1. APSInt supports
// this operation and gives the two's complement result.
if (RHS.isNegative() && RHS.isAllOnes() && LHS.isSigned() &&
LHS.isMinSignedValue())
- return HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1),
- E->getType());
- return true;
+ HandleOverflowResult = HandleOverflow(
+ Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType());
+ Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
+ return HandleOverflowResult;
case BO_Shl: {
if (Info.getLangOpts().OpenCL)
// OpenCL 6.3j: shift values are effectively % word size of LHS.
@@ -3647,9 +3649,9 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if ((ObjType.isConstQualified() || ObjType.isVolatileQualified()) &&
ObjType->isRecordType() &&
Info.isEvaluatingCtorDtor(
- Obj.Base, llvm::makeArrayRef(Sub.Entries.begin(),
- Sub.Entries.begin() + I)) !=
- ConstructionPhase::None) {
+ Obj.Base,
+ llvm::ArrayRef(Sub.Entries.begin(), Sub.Entries.begin() + I)) !=
+ ConstructionPhase::None) {
ObjType = Info.Ctx.getCanonicalType(ObjType);
ObjType.removeLocalConst();
ObjType.removeLocalVolatile();
@@ -4129,7 +4131,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
return CompleteObject();
} else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
- Optional<DynAlloc*> Alloc = Info.lookupDynamicAlloc(DA);
+ std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
if (!Alloc) {
Info.FFDiag(E, diag::note_constexpr_access_deleted_object) << AK;
return CompleteObject();
@@ -4844,6 +4846,8 @@ enum EvalStmtResult {
}
static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
+ if (VD->isInvalidDecl())
+ return false;
// We don't need to evaluate the initializer for a static local.
if (!VD->hasLocalStorage())
return true;
@@ -5040,8 +5044,10 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info,
static bool CheckLocalVariableDeclaration(EvalInfo &Info, const VarDecl *VD) {
// An expression E is a core constant expression unless the evaluation of E
// would evaluate one of the following: [C++2b] - a control flow that passes
- // through a declaration of a variable with static or thread storage duration.
- if (VD->isLocalVarDecl() && VD->isStaticLocal()) {
+ // through a declaration of a variable with static or thread storage duration
+ // unless that variable is usable in constant expressions.
+ if (VD->isLocalVarDecl() && VD->isStaticLocal() &&
+ !VD->isUsableInConstantExpressions(Info.Ctx)) {
Info.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)
<< (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;
return false;
@@ -5663,13 +5669,15 @@ static const CXXRecordDecl *getBaseClassType(SubobjectDesignator &Designator,
}
/// Determine the dynamic type of an object.
-static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E,
- LValue &This, AccessKinds AK) {
+static std::optional<DynamicType> ComputeDynamicType(EvalInfo &Info,
+ const Expr *E,
+ LValue &This,
+ AccessKinds AK) {
// If we don't have an lvalue denoting an object of class type, there is no
// meaningful dynamic type. (We consider objects of non-class type to have no
// dynamic type.)
if (!checkDynamicType(Info, E, This, AK, true))
- return None;
+ return std::nullopt;
// Refuse to compute a dynamic type in the presence of virtual bases. This
// shouldn't happen other than in constant-folding situations, since literal
@@ -5681,7 +5689,7 @@ static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E,
This.Designator.MostDerivedType->getAsCXXRecordDecl();
if (!Class || Class->getNumVBases()) {
Info.FFDiag(E);
- return None;
+ return std::nullopt;
}
// FIXME: For very deep class hierarchies, it might be beneficial to use a
@@ -5714,14 +5722,14 @@ static Optional<DynamicType> ComputeDynamicType(EvalInfo &Info, const Expr *E,
// 'This', so that object has not yet begun its period of construction and
// any polymorphic operation on it results in undefined behavior.
Info.FFDiag(E);
- return None;
+ return std::nullopt;
}
/// Perform virtual dispatch.
static const CXXMethodDecl *HandleVirtualDispatch(
EvalInfo &Info, const Expr *E, LValue &This, const CXXMethodDecl *Found,
llvm::SmallVectorImpl<QualType> &CovariantAdjustmentPath) {
- Optional<DynamicType> DynType = ComputeDynamicType(
+ std::optional<DynamicType> DynType = ComputeDynamicType(
Info, E, This,
isa<CXXDestructorDecl>(Found) ? AK_Destroy : AK_MemberCall);
if (!DynType)
@@ -5839,7 +5847,7 @@ static bool HandleDynamicCast(EvalInfo &Info, const ExplicitCastExpr *E,
// For all the other cases, we need the pointer to point to an object within
// its lifetime / period of construction / destruction, and we need to know
// its dynamic type.
- Optional<DynamicType> DynType =
+ std::optional<DynamicType> DynType =
ComputeDynamicType(Info, E, Ptr, AK_DynamicCast);
if (!DynType)
return false;
@@ -6728,10 +6736,10 @@ static const FunctionDecl *getVirtualOperatorDelete(QualType T) {
/// still exists and is of the right kind for the purpose of a deletion.
///
/// On success, returns the heap allocation to deallocate. On failure, produces
-/// a diagnostic and returns None.
-static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
- const LValue &Pointer,
- DynAlloc::Kind DeallocKind) {
+/// a diagnostic and returns std::nullopt.
+static std::optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
+ const LValue &Pointer,
+ DynAlloc::Kind DeallocKind) {
auto PointerAsString = [&] {
return Pointer.toString(Info.Ctx, Info.Ctx.VoidPtrTy);
};
@@ -6742,13 +6750,13 @@ static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
<< PointerAsString();
if (Pointer.Base)
NoteLValueLocation(Info, Pointer.Base);
- return None;
+ return std::nullopt;
}
- Optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
+ std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
if (!Alloc) {
Info.FFDiag(E, diag::note_constexpr_double_delete);
- return None;
+ return std::nullopt;
}
QualType AllocType = Pointer.Base.getDynamicAllocType();
@@ -6756,7 +6764,7 @@ static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
Info.FFDiag(E, diag::note_constexpr_new_delete_mismatch)
<< DeallocKind << (*Alloc)->getKind() << AllocType;
NoteLValueLocation(Info, Pointer.Base);
- return None;
+ return std::nullopt;
}
bool Subobject = false;
@@ -6770,7 +6778,7 @@ static Optional<DynAlloc *> CheckDeleteKind(EvalInfo &Info, const Expr *E,
if (Subobject) {
Info.FFDiag(E, diag::note_constexpr_delete_subobject)
<< PointerAsString() << Pointer.Designator.isOnePastTheEnd();
- return None;
+ return std::nullopt;
}
return Alloc;
@@ -6822,7 +6830,7 @@ class BitCastBuffer {
// FIXME: Its possible under the C++ standard for 'char' to not be 8 bits, but
// we don't support a host or target where that is the case. Still, we should
// use a more generic type in case we ever do.
- SmallVector<Optional<unsigned char>, 32> Bytes;
+ SmallVector<std::optional<unsigned char>, 32> Bytes;
static_assert(std::numeric_limits<unsigned char>::digits >= 8,
"Need at least 8 bit unsigned char");
@@ -6834,9 +6842,8 @@ public:
: Bytes(Width.getQuantity()),
TargetIsLittleEndian(TargetIsLittleEndian) {}
- LLVM_NODISCARD
- bool readObject(CharUnits Offset, CharUnits Width,
- SmallVectorImpl<unsigned char> &Output) const {
+ [[nodiscard]] bool readObject(CharUnits Offset, CharUnits Width,
+ SmallVectorImpl<unsigned char> &Output) const {
for (CharUnits I = Offset, E = Offset + Width; I != E; ++I) {
// If a byte of an integer is uninitialized, then the whole integer is
// uninitialized.
@@ -7013,12 +7020,12 @@ class APValueToBufferConverter {
}
public:
- static Optional<BitCastBuffer> convert(EvalInfo &Info, const APValue &Src,
- const CastExpr *BCE) {
+ static std::optional<BitCastBuffer>
+ convert(EvalInfo &Info, const APValue &Src, const CastExpr *BCE) {
CharUnits DstSize = Info.Ctx.getTypeSizeInChars(BCE->getType());
APValueToBufferConverter Converter(Info, DstSize, BCE);
if (!Converter.visit(Src, BCE->getSubExpr()->getType()))
- return None;
+ return std::nullopt;
return Converter.Buffer;
}
};
@@ -7036,22 +7043,22 @@ class BufferToAPValueConverter {
// Emit an unsupported bit_cast type error. Sema refuses to build a bit_cast
// with an invalid type, so anything left is a deficiency on our part (FIXME).
// Ideally this will be unreachable.
- llvm::NoneType unsupportedType(QualType Ty) {
+ std::nullopt_t unsupportedType(QualType Ty) {
Info.FFDiag(BCE->getBeginLoc(),
diag::note_constexpr_bit_cast_unsupported_type)
<< Ty;
- return None;
+ return std::nullopt;
}
- llvm::NoneType unrepresentableValue(QualType Ty, const APSInt &Val) {
+ std::nullopt_t unrepresentableValue(QualType Ty, const APSInt &Val) {
Info.FFDiag(BCE->getBeginLoc(),
diag::note_constexpr_bit_cast_unrepresentable_value)
<< Ty << toString(Val, /*Radix=*/10);
- return None;
+ return std::nullopt;
}
- Optional<APValue> visit(const BuiltinType *T, CharUnits Offset,
- const EnumType *EnumSugar = nullptr) {
+ std::optional<APValue> visit(const BuiltinType *T, CharUnits Offset,
+ const EnumType *EnumSugar = nullptr) {
if (T->isNullPtrType()) {
uint64_t NullValue = Info.Ctx.getTargetNullPointerValue(QualType(T, 0));
return APValue((Expr *)nullptr,
@@ -7087,7 +7094,7 @@ class BufferToAPValueConverter {
Info.FFDiag(BCE->getExprLoc(),
diag::note_constexpr_bit_cast_indet_dest)
<< DisplayType << Info.Ctx.getLangOpts().CharIsSigned;
- return None;
+ return std::nullopt;
}
return APValue::IndeterminateValue();
@@ -7119,7 +7126,7 @@ class BufferToAPValueConverter {
return unsupportedType(QualType(T, 0));
}
- Optional<APValue> visit(const RecordType *RTy, CharUnits Offset) {
+ std::optional<APValue> visit(const RecordType *RTy, CharUnits Offset) {
const RecordDecl *RD = RTy->getAsRecordDecl();
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
@@ -7139,10 +7146,10 @@ class BufferToAPValueConverter {
Info.Ctx.getASTRecordLayout(BaseDecl).getNonVirtualSize().isZero())
continue;
- Optional<APValue> SubObj = visitType(
+ std::optional<APValue> SubObj = visitType(
BS.getType(), Layout.getBaseClassOffset(BaseDecl) + Offset);
if (!SubObj)
- return None;
+ return std::nullopt;
ResultVal.getStructBase(I) = *SubObj;
}
}
@@ -7155,7 +7162,7 @@ class BufferToAPValueConverter {
if (FD->isBitField()) {
Info.FFDiag(BCE->getBeginLoc(),
diag::note_constexpr_bit_cast_unsupported_bitfield);
- return None;
+ return std::nullopt;
}
uint64_t FieldOffsetBits = Layout.getFieldOffset(FieldIdx);
@@ -7165,9 +7172,9 @@ class BufferToAPValueConverter {
CharUnits::fromQuantity(FieldOffsetBits / Info.Ctx.getCharWidth()) +
Offset;
QualType FieldTy = FD->getType();
- Optional<APValue> SubObj = visitType(FieldTy, FieldOffset);
+ std::optional<APValue> SubObj = visitType(FieldTy, FieldOffset);
if (!SubObj)
- return None;
+ return std::nullopt;
ResultVal.getStructField(FieldIdx) = *SubObj;
++FieldIdx;
}
@@ -7175,7 +7182,7 @@ class BufferToAPValueConverter {
return ResultVal;
}
- Optional<APValue> visit(const EnumType *Ty, CharUnits Offset) {
+ std::optional<APValue> visit(const EnumType *Ty, CharUnits Offset) {
QualType RepresentationType = Ty->getDecl()->getIntegerType();
assert(!RepresentationType.isNull() &&
"enum forward decl should be caught by Sema");
@@ -7186,27 +7193,27 @@ class BufferToAPValueConverter {
return visit(AsBuiltin, Offset, /*EnumTy=*/Ty);
}
- Optional<APValue> visit(const ConstantArrayType *Ty, CharUnits Offset) {
+ std::optional<APValue> visit(const ConstantArrayType *Ty, CharUnits Offset) {
size_t Size = Ty->getSize().getLimitedValue();
CharUnits ElementWidth = Info.Ctx.getTypeSizeInChars(Ty->getElementType());
APValue ArrayValue(APValue::UninitArray(), Size, Size);
for (size_t I = 0; I != Size; ++I) {
- Optional<APValue> ElementValue =
+ std::optional<APValue> ElementValue =
visitType(Ty->getElementType(), Offset + I * ElementWidth);
if (!ElementValue)
- return None;
+ return std::nullopt;
ArrayValue.getArrayInitializedElt(I) = std::move(*ElementValue);
}
return ArrayValue;
}
- Optional<APValue> visit(const Type *Ty, CharUnits Offset) {
+ std::optional<APValue> visit(const Type *Ty, CharUnits Offset) {
return unsupportedType(QualType(Ty, 0));
}
- Optional<APValue> visitType(QualType Ty, CharUnits Offset) {
+ std::optional<APValue> visitType(QualType Ty, CharUnits Offset) {
QualType Can = Ty.getCanonicalType();
switch (Can->getTypeClass()) {
@@ -7231,8 +7238,8 @@ class BufferToAPValueConverter {
public:
// Pull out a full value of type DstType.
- static Optional<APValue> convert(EvalInfo &Info, BitCastBuffer &Buffer,
- const CastExpr *BCE) {
+ static std::optional<APValue> convert(EvalInfo &Info, BitCastBuffer &Buffer,
+ const CastExpr *BCE) {
BufferToAPValueConverter Converter(Info, Buffer, BCE);
return Converter.visitType(BCE->getType(), CharUnits::fromQuantity(0));
}
@@ -7321,13 +7328,13 @@ static bool handleLValueToRValueBitCast(EvalInfo &Info, APValue &DestValue,
return false;
// Read out SourceValue into a char buffer.
- Optional<BitCastBuffer> Buffer =
+ std::optional<BitCastBuffer> Buffer =
APValueToBufferConverter::convert(Info, SourceRValue, BCE);
if (!Buffer)
return false;
// Write out the buffer into a new APValue.
- Optional<APValue> MaybeDestValue =
+ std::optional<APValue> MaybeDestValue =
BufferToAPValueConverter::convert(Info, *Buffer, BCE);
if (!MaybeDestValue)
return false;
@@ -7406,6 +7413,12 @@ protected:
bool ZeroInitialization(const Expr *E) { return Error(E); }
+ bool IsConstantEvaluatedBuiltinCall(const CallExpr *E) {
+ unsigned BuiltinOp = E->getBuiltinCallee();
+ return BuiltinOp != 0 &&
+ Info.Ctx.BuiltinInfo.isConstantEvaluated(BuiltinOp);
+ }
+
public:
ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
@@ -7613,7 +7626,7 @@ public:
const FunctionDecl *FD = nullptr;
LValue *This = nullptr, ThisVal;
- auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
+ auto Args = llvm::ArrayRef(E->getArgs(), E->getNumArgs());
bool HasQualifier = false;
CallRef Call;
@@ -7945,8 +7958,8 @@ public:
bool VisitStmtExpr(const StmtExpr *E) {
// We will have checked the full-expressions inside the statement expression
// when they were completed, and don't need to check them again now.
- llvm::SaveAndRestore<bool> NotCheckingForUB(
- Info.CheckingForUndefinedBehavior, false);
+ llvm::SaveAndRestore NotCheckingForUB(Info.CheckingForUndefinedBehavior,
+ false);
const CompoundStmt *CS = E->getSubStmt();
if (CS->body_empty())
@@ -8179,7 +8192,8 @@ public:
return LValueExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_LValueBitCast:
- this->CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ this->CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << 2 << Info.Ctx.getLangOpts().CPlusPlus;
if (!Visit(E->getSubExpr()))
return false;
Result.Designator.setInvalid();
@@ -8208,7 +8222,7 @@ static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info,
bool InvalidBaseOK) {
assert(!E->isValueDependent());
assert(E->isGLValue() || E->getType()->isFunctionType() ||
- E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E));
+ E->getType()->isVoidType() || isa<ObjCSelectorExpr>(E->IgnoreParens()));
return LValueExprEvaluator(Info, Result, InvalidBaseOK).Visit(E);
}
@@ -8317,7 +8331,12 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
}
bool LValueExprEvaluator::VisitCallExpr(const CallExpr *E) {
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+
switch (E->getBuiltinCallee()) {
+ default:
+ return false;
case Builtin::BIas_const:
case Builtin::BIforward:
case Builtin::BImove:
@@ -8424,7 +8443,7 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
if (!Visit(E->getExprOperand()))
return false;
- Optional<DynamicType> DynType =
+ std::optional<DynamicType> DynType =
ComputeDynamicType(Info, E, Result, AK_TypeId);
if (!DynType)
return false;
@@ -8890,9 +8909,10 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
Result.Designator.setInvalid();
if (SubExpr->getType()->isVoidPointerType())
CCEDiag(E, diag::note_constexpr_invalid_cast)
- << 3 << SubExpr->getType();
+ << 3 << SubExpr->getType();
else
- CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << 2 << Info.Ctx.getLangOpts().CPlusPlus;
}
}
if (E->getCastKind() == CK_AddressSpaceConversion && Result.IsNullPtr)
@@ -8929,7 +8949,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr *E) {
return ZeroInitialization(E);
case CK_IntegralToPointer: {
- CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << 2 << Info.Ctx.getLangOpts().CPlusPlus;
APValue Value;
if (!EvaluateIntegerOrLValue(SubExpr, Value, Info))
@@ -9090,13 +9111,9 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {
}
bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
- if (IsConstantCall(E))
- return Success(E);
-
- if (unsigned BuiltinOp = E->getBuiltinCallee())
- return VisitBuiltinCallExpr(E, BuiltinOp);
-
- return visitNonBuiltinCallExpr(E);
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return visitNonBuiltinCallExpr(E);
+ return VisitBuiltinCallExpr(E, E->getBuiltinCallee());
}
// Determine if T is a character type for which we guarantee that
@@ -9107,6 +9124,9 @@ static bool isOneByteCharacterType(QualType T) {
bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) {
+ if (IsNoOpCall(E))
+ return Success(E);
+
switch (BuiltinOp) {
case Builtin::BIaddressof:
case Builtin::BI__addressof:
@@ -9213,11 +9233,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BIwmemchr:
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
- << /*isConstexpr*/0 << /*isConstructor*/0
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'");
+ << /*isConstexpr*/ 0 << /*isConstructor*/ 0
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_strchr:
case Builtin::BI__builtin_wcschr:
case Builtin::BI__builtin_memchr:
@@ -9259,7 +9279,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
// FIXME: We can compare the bytes in the correct order.
if (IsRawByte && !isOneByteCharacterType(CharTy)) {
Info.FFDiag(E, diag::note_constexpr_memchr_unsupported)
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'")
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str()
<< CharTy;
return false;
}
@@ -9278,7 +9298,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
Desired))
return ZeroInitialization(E);
StopAtNull = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BImemchr:
case Builtin::BI__builtin_memchr:
case Builtin::BI__builtin_char_memchr:
@@ -9291,7 +9311,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BIwcschr:
case Builtin::BI__builtin_wcschr:
StopAtNull = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BIwmemchr:
case Builtin::BI__builtin_wmemchr:
// wcschr and wmemchr are given a wchar_t to look for. Just use it.
@@ -9321,11 +9341,11 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BIwmemmove:
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
- << /*isConstexpr*/0 << /*isConstructor*/0
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'");
+ << /*isConstexpr*/ 0 << /*isConstructor*/ 0
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_memcpy:
case Builtin::BI__builtin_memmove:
case Builtin::BI__builtin_wmemcpy:
@@ -9461,10 +9481,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
}
default:
- break;
+ return false;
}
-
- return visitNonBuiltinCallExpr(E);
}
static bool EvaluateArrayNewInitList(EvalInfo &Info, LValue &This,
@@ -9527,7 +9545,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) {
bool ValueInit = false;
QualType AllocType = E->getAllocatedType();
- if (Optional<const Expr *> ArraySize = E->getArraySize()) {
+ if (std::optional<const Expr *> ArraySize = E->getArraySize()) {
const Expr *Stripped = *ArraySize;
for (; auto *ICE = dyn_cast<ImplicitCastExpr>(Stripped);
Stripped = ICE->getSubExpr())
@@ -9809,6 +9827,9 @@ namespace {
bool VisitCXXConstructExpr(const CXXConstructExpr *E, QualType T);
bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
bool VisitBinCmp(const BinaryOperator *E);
+ bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
+ bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
+ ArrayRef<Expr *> Args);
};
}
@@ -9927,8 +9948,13 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
if (E->isTransparent())
return Visit(E->getInit(0));
+ return VisitCXXParenListOrInitListExpr(E, E->inits());
+}
- const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
+bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
+ const Expr *ExprToVisit, ArrayRef<Expr *> Args) {
+ const RecordDecl *RD =
+ ExprToVisit->getType()->castAs<RecordType>()->getDecl();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
@@ -9939,7 +9965,16 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
CXXRD && CXXRD->getNumBases());
if (RD->isUnion()) {
- const FieldDecl *Field = E->getInitializedFieldInUnion();
+ const FieldDecl *Field;
+ if (auto *ILE = dyn_cast<InitListExpr>(ExprToVisit)) {
+ Field = ILE->getInitializedFieldInUnion();
+ } else if (auto *PLIE = dyn_cast<CXXParenListInitExpr>(ExprToVisit)) {
+ Field = PLIE->getInitializedFieldInUnion();
+ } else {
+ llvm_unreachable(
+ "Expression is neither an init list nor a C++ paren list");
+ }
+
Result = APValue(Field);
if (!Field)
return true;
@@ -9950,7 +9985,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
// Is this difference ever observable for initializer lists which
// we don't build?
ImplicitValueInitExpr VIE(Field->getType());
- const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE;
+ const Expr *InitExpr = Args.empty() ? &VIE : Args[0];
LValue Subobject = This;
if (!HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout))
@@ -9979,8 +10014,8 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
// Initialize base classes.
if (CXXRD && CXXRD->getNumBases()) {
for (const auto &Base : CXXRD->bases()) {
- assert(ElementNo < E->getNumInits() && "missing init for base class");
- const Expr *Init = E->getInit(ElementNo);
+ assert(ElementNo < Args.size() && "missing init for base class");
+ const Expr *Init = Args[ElementNo];
LValue Subobject = This;
if (!HandleLValueBase(Info, Init, Subobject, CXXRD, &Base))
@@ -10007,18 +10042,18 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
LValue Subobject = This;
- bool HaveInit = ElementNo < E->getNumInits();
+ bool HaveInit = ElementNo < Args.size();
// FIXME: Diagnostics here should point to the end of the initializer
// list, not the start.
- if (!HandleLValueMember(Info, HaveInit ? E->getInit(ElementNo) : E,
+ if (!HandleLValueMember(Info, HaveInit ? Args[ElementNo] : ExprToVisit,
Subobject, Field, &Layout))
return false;
// Perform an implicit value-initialization for members beyond the end of
// the initializer list.
ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType());
- const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE;
+ const Expr *Init = HaveInit ? Args[ElementNo++] : &VIE;
if (Field->getType()->isIncompleteArrayType()) {
if (auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType())) {
@@ -10093,7 +10128,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
if (ZeroInit && !ZeroInitialization(E, T))
return false;
- auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs());
+ auto Args = llvm::ArrayRef(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E, This, Args,
cast<CXXConstructorDecl>(Definition), Info,
Result);
@@ -10504,10 +10539,10 @@ bool VectorExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return Success(LHSValue, E);
}
-static llvm::Optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx,
- QualType ResultTy,
- UnaryOperatorKind Op,
- APValue Elt) {
+static std::optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx,
+ QualType ResultTy,
+ UnaryOperatorKind Op,
+ APValue Elt) {
switch (Op) {
case UO_Plus:
// Nothing to do here.
@@ -10550,7 +10585,7 @@ static llvm::Optional<APValue> handleVectorUnaryOperator(ASTContext &Ctx,
}
default:
// FIXME: Implement the rest of the unary operators.
- return llvm::None;
+ return std::nullopt;
}
}
@@ -10581,7 +10616,7 @@ bool VectorExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
SmallVector<APValue, 4> ResultElements;
for (unsigned EltNum = 0; EltNum < VD->getNumElements(); ++EltNum) {
- llvm::Optional<APValue> Elt = handleVectorUnaryOperator(
+ std::optional<APValue> Elt = handleVectorUnaryOperator(
Info.Ctx, ResultEltTy, Op, SubExprValue.getVectorElt(EltNum));
if (!Elt)
return false;
@@ -10652,6 +10687,11 @@ namespace {
expandStringLiteral(Info, E, Result, AllocType);
return true;
}
+ bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
+ bool VisitCXXParenListOrInitListExpr(const Expr *ExprToVisit,
+ ArrayRef<Expr *> Args,
+ const Expr *ArrayFiller,
+ QualType AllocType = QualType());
};
} // end anonymous namespace
@@ -10695,6 +10735,11 @@ static bool MaybeElementDependentArrayFiller(const Expr *FillerExpr) {
if (MaybeElementDependentArrayFiller(ILE->getInit(I)))
return true;
}
+
+ if (ILE->hasArrayFiller() &&
+ MaybeElementDependentArrayFiller(ILE->getArrayFiller()))
+ return true;
+
return false;
}
return true;
@@ -10722,6 +10767,16 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
assert(!E->isTransparent() &&
"transparent array list initialization is not string literal init?");
+ return VisitCXXParenListOrInitListExpr(E, E->inits(), E->getArrayFiller(),
+ AllocType);
+}
+
+bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr(
+ const Expr *ExprToVisit, ArrayRef<Expr *> Args, const Expr *ArrayFiller,
+ QualType AllocType) {
+ const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(
+ AllocType.isNull() ? ExprToVisit->getType() : AllocType);
+
bool Success = true;
assert((!Result.isArray() || Result.getArrayInitializedElts() == 0) &&
@@ -10730,13 +10785,12 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
if (Result.isArray() && Result.hasArrayFiller())
Filler = Result.getArrayFiller();
- unsigned NumEltsToInit = E->getNumInits();
+ unsigned NumEltsToInit = Args.size();
unsigned NumElts = CAT->getSize().getZExtValue();
- const Expr *FillerExpr = E->hasArrayFiller() ? E->getArrayFiller() : nullptr;
// If the initializer might depend on the array index, run it for each
// array element.
- if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(FillerExpr))
+ if (NumEltsToInit != NumElts && MaybeElementDependentArrayFiller(ArrayFiller))
NumEltsToInit = NumElts;
LLVM_DEBUG(llvm::dbgs() << "The number of elements to initialize: "
@@ -10754,10 +10808,9 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
}
LValue Subobject = This;
- Subobject.addArray(Info, E, CAT);
+ Subobject.addArray(Info, ExprToVisit, CAT);
for (unsigned Index = 0; Index != NumEltsToInit; ++Index) {
- const Expr *Init =
- Index < E->getNumInits() ? E->getInit(Index) : FillerExpr;
+ const Expr *Init = Index < Args.size() ? Args[Index] : ArrayFiller;
if (!EvaluateInPlace(Result.getArrayInitializedElt(Index),
Info, Subobject, Init) ||
!HandleLValueArrayAdjustment(Info, Init, Subobject,
@@ -10773,9 +10826,10 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E,
// If we get here, we have a trivial filler, which we can just evaluate
// once and splat over the rest of the array elements.
- assert(FillerExpr && "no array filler for incomplete init list");
+ assert(ArrayFiller && "no array filler for incomplete init list");
return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject,
- FillerExpr) && Success;
+ ArrayFiller) &&
+ Success;
}
bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
@@ -10833,6 +10887,9 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
if (FinalSize == 0)
return true;
+ bool HasTrivialConstructor = CheckTrivialDefaultConstructor(
+ Info, E->getExprLoc(), E->getConstructor(),
+ E->requiresZeroInitialization());
LValue ArrayElt = Subobject;
ArrayElt.addArray(Info, E, CAT);
// We do the whole initialization in two passes, first for just one element,
@@ -10856,19 +10913,26 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
for (unsigned I = OldElts; I < N; ++I)
Value->getArrayInitializedElt(I) = Filler;
- // Initialize the elements.
- for (unsigned I = OldElts; I < N; ++I) {
- if (!VisitCXXConstructExpr(E, ArrayElt,
- &Value->getArrayInitializedElt(I),
- CAT->getElementType()) ||
- !HandleLValueArrayAdjustment(Info, E, ArrayElt,
- CAT->getElementType(), 1))
- return false;
- // When checking for const initilization any diagnostic is considered
- // an error.
- if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
- !Info.keepEvaluatingAfterFailure())
- return false;
+ if (HasTrivialConstructor && N == FinalSize) {
+ // If we have a trivial constructor, only evaluate it once and copy
+ // the result into all the array elements.
+ APValue &FirstResult = Value->getArrayInitializedElt(0);
+ for (unsigned I = OldElts; I < FinalSize; ++I)
+ Value->getArrayInitializedElt(I) = FirstResult;
+ } else {
+ for (unsigned I = OldElts; I < N; ++I) {
+ if (!VisitCXXConstructExpr(E, ArrayElt,
+ &Value->getArrayInitializedElt(I),
+ CAT->getElementType()) ||
+ !HandleLValueArrayAdjustment(Info, E, ArrayElt,
+ CAT->getElementType(), 1))
+ return false;
+ // When checking for const initilization any diagnostic is considered
+ // an error.
+ if (Info.EvalStatus.Diag && !Info.EvalStatus.Diag->empty() &&
+ !Info.keepEvaluatingAfterFailure())
+ return false;
+ }
}
}
@@ -10882,6 +10946,15 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E,
.VisitCXXConstructExpr(E, Type);
}
+bool ArrayExprEvaluator::VisitCXXParenListInitExpr(
+ const CXXParenListInitExpr *E) {
+ assert(dyn_cast<ConstantArrayType>(E->getType()) &&
+ "Expression result is not a constant array type");
+
+ return VisitCXXParenListOrInitListExpr(E, E->getInitExprs(),
+ E->getArrayFiller());
+}
+
//===----------------------------------------------------------------------===//
// Integer Evaluation
//
@@ -11596,15 +11669,31 @@ static bool isUserWritingOffTheEnd(const ASTContext &Ctx, const LValue &LVal) {
// conservative with the last element in structs (if it's an array), so our
// current behavior is more compatible than an explicit list approach would
// be.
- int StrictFlexArraysLevel = Ctx.getLangOpts().StrictFlexArrays;
+ auto isFlexibleArrayMember = [&] {
+ using FAMKind = LangOptions::StrictFlexArraysLevelKind;
+ FAMKind StrictFlexArraysLevel =
+ Ctx.getLangOpts().getStrictFlexArraysLevel();
+
+ if (Designator.isMostDerivedAnUnsizedArray())
+ return true;
+
+ if (StrictFlexArraysLevel == FAMKind::Default)
+ return true;
+
+ if (Designator.getMostDerivedArraySize() == 0 &&
+ StrictFlexArraysLevel != FAMKind::IncompleteOnly)
+ return true;
+
+ if (Designator.getMostDerivedArraySize() == 1 &&
+ StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete)
+ return true;
+
+ return false;
+ };
+
return LVal.InvalidBase &&
Designator.Entries.size() == Designator.MostDerivedPathLength &&
- Designator.MostDerivedIsArrayElement &&
- (Designator.isMostDerivedAnUnsizedArray() ||
- Designator.getMostDerivedArraySize() == 0 ||
- (Designator.getMostDerivedArraySize() == 1 &&
- StrictFlexArraysLevel < 2) ||
- StrictFlexArraysLevel == 0) &&
+ Designator.MostDerivedIsArrayElement && isFlexibleArrayMember() &&
isDesignatorAtObjectEnd(Ctx, LVal);
}
@@ -11751,10 +11840,9 @@ static bool tryEvaluateBuiltinObjectSize(const Expr *E, unsigned Type,
}
bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
- if (unsigned BuiltinOp = E->getBuiltinCallee())
- return VisitBuiltinCallExpr(E, BuiltinOp);
-
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ return VisitBuiltinCallExpr(E, E->getBuiltinCallee());
}
static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info,
@@ -11788,7 +11876,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) {
switch (BuiltinOp) {
default:
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ return false;
case Builtin::BI__builtin_dynamic_object_size:
case Builtin::BI__builtin_object_size: {
@@ -12103,11 +12191,11 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
// A call to strlen is not a constant expression.
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
- << /*isConstexpr*/0 << /*isConstructor*/0
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'");
+ << /*isConstexpr*/ 0 << /*isConstructor*/ 0
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_strlen:
case Builtin::BI__builtin_wcslen: {
// As an extension, we support __builtin_strlen() as a constant expression,
@@ -12128,11 +12216,11 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
// A call to strlen is not a constant expression.
if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
- << /*isConstexpr*/0 << /*isConstructor*/0
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'");
+ << /*isConstexpr*/ 0 << /*isConstructor*/ 0
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str();
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Builtin::BI__builtin_strcmp:
case Builtin::BI__builtin_wcscmp:
case Builtin::BI__builtin_strncmp:
@@ -12184,7 +12272,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
!(isOneByteCharacterType(CharTy1) && isOneByteCharacterType(CharTy2))) {
// FIXME: Consider using our bit_cast implementation to support this.
Info.FFDiag(E, diag::note_constexpr_memcmp_unsupported)
- << (std::string("'") + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'")
+ << ("'" + Info.Ctx.BuiltinInfo.getName(BuiltinOp) + "'").str()
<< CharTy1 << CharTy2;
return false;
}
@@ -12886,41 +12974,55 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
// Reject differing bases from the normal codepath; we special-case
// comparisons to null.
if (!HasSameBase(LHSValue, RHSValue)) {
+ auto DiagComparison = [&] (unsigned DiagID, bool Reversed = false) {
+ std::string LHS = LHSValue.toString(Info.Ctx, E->getLHS()->getType());
+ std::string RHS = RHSValue.toString(Info.Ctx, E->getRHS()->getType());
+ Info.FFDiag(E, DiagID)
+ << (Reversed ? RHS : LHS) << (Reversed ? LHS : RHS);
+ return false;
+ };
// Inequalities and subtractions between unrelated pointers have
// unspecified or undefined behavior.
- if (!IsEquality) {
- Info.FFDiag(E, diag::note_constexpr_pointer_comparison_unspecified);
- return false;
- }
+ if (!IsEquality)
+ return DiagComparison(
+ diag::note_constexpr_pointer_comparison_unspecified);
// A constant address may compare equal to the address of a symbol.
// The one exception is that address of an object cannot compare equal
// to a null pointer constant.
+ // TODO: Should we restrict this to actual null pointers, and exclude the
+ // case of zero cast to pointer type?
if ((!LHSValue.Base && !LHSValue.Offset.isZero()) ||
(!RHSValue.Base && !RHSValue.Offset.isZero()))
- return Error(E);
+ return DiagComparison(diag::note_constexpr_pointer_constant_comparison,
+ !RHSValue.Base);
// It's implementation-defined whether distinct literals will have
// distinct addresses. In clang, the result of such a comparison is
// unspecified, so it is not a constant expression. However, we do know
// that the address of a literal will be non-null.
if ((IsLiteralLValue(LHSValue) || IsLiteralLValue(RHSValue)) &&
LHSValue.Base && RHSValue.Base)
- return Error(E);
+ return DiagComparison(diag::note_constexpr_literal_comparison);
// We can't tell whether weak symbols will end up pointing to the same
// object.
if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue))
- return Error(E);
+ return DiagComparison(diag::note_constexpr_pointer_weak_comparison,
+ !IsWeakLValue(LHSValue));
// We can't compare the address of the start of one object with the
// past-the-end address of another object, per C++ DR1652.
- if ((LHSValue.Base && LHSValue.Offset.isZero() &&
- isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) ||
- (RHSValue.Base && RHSValue.Offset.isZero() &&
- isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue)))
- return Error(E);
+ if (LHSValue.Base && LHSValue.Offset.isZero() &&
+ isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue))
+ return DiagComparison(diag::note_constexpr_pointer_comparison_past_end,
+ true);
+ if (RHSValue.Base && RHSValue.Offset.isZero() &&
+ isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))
+ return DiagComparison(diag::note_constexpr_pointer_comparison_past_end,
+ false);
// We can't tell whether an object is at the same address as another
// zero sized object.
if ((RHSValue.Base && isZeroSized(LHSValue)) ||
(LHSValue.Base && isZeroSized(RHSValue)))
- return Error(E);
+ return DiagComparison(
+ diag::note_constexpr_pointer_comparison_zero_sized);
return Success(CmpResult::Unequal, E);
}
@@ -13024,6 +13126,19 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E,
if (!EvaluateMemberPointer(E->getRHS(), RHSValue, Info) || !LHSOK)
return false;
+ // If either operand is a pointer to a weak function, the comparison is not
+ // constant.
+ if (LHSValue.getDecl() && LHSValue.getDecl()->isWeak()) {
+ Info.FFDiag(E, diag::note_constexpr_mem_pointer_weak_comparison)
+ << LHSValue.getDecl();
+ return true;
+ }
+ if (RHSValue.getDecl() && RHSValue.getDecl()->isWeak()) {
+ Info.FFDiag(E, diag::note_constexpr_mem_pointer_weak_comparison)
+ << RHSValue.getDecl();
+ return true;
+ }
+
// C++11 [expr.eq]p2:
// If both operands are null, they compare equal. Otherwise if only one is
// null, they compare unequal.
@@ -13101,6 +13216,11 @@ bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) {
});
}
+bool RecordExprEvaluator::VisitCXXParenListInitExpr(
+ const CXXParenListInitExpr *E) {
+ return VisitCXXParenListOrInitListExpr(E, E->getInitExprs());
+}
+
bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
// We don't support assignment in C. C++ assignments don't get here because
// assignment is an lvalue in C++.
@@ -13519,12 +13639,62 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType);
}
+ if (Info.Ctx.getLangOpts().CPlusPlus && Info.InConstantContext &&
+ Info.EvalMode == EvalInfo::EM_ConstantExpression &&
+ DestType->isEnumeralType()) {
+
+ bool ConstexprVar = true;
+
+ // We know if we are here that we are in a context that we might require
+ // a constant expression or a context that requires a constant
+ // value. But if we are initializing a value we don't know if it is a
+ // constexpr variable or not. We can check the EvaluatingDecl to determine
+ // if it constexpr or not. If not then we don't want to emit a diagnostic.
+ if (const auto *VD = dyn_cast_or_null<VarDecl>(
+ Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()))
+ ConstexprVar = VD->isConstexpr();
+
+ const EnumType *ET = dyn_cast<EnumType>(DestType.getCanonicalType());
+ const EnumDecl *ED = ET->getDecl();
+ // Check that the value is within the range of the enumeration values.
+ //
+ // This corressponds to [expr.static.cast]p10 which says:
+ // A value of integral or enumeration type can be explicitly converted
+ // to a complete enumeration type ... If the enumeration type does not
+ // have a fixed underlying type, the value is unchanged if the original
+ // value is within the range of the enumeration values ([dcl.enum]), and
+ // otherwise, the behavior is undefined.
+ //
+ // This was resolved as part of DR2338 which has CD5 status.
+ if (!ED->isFixed()) {
+ llvm::APInt Min;
+ llvm::APInt Max;
+
+ ED->getValueRange(Max, Min);
+ --Max;
+
+ if (ED->getNumNegativeBits() && ConstexprVar &&
+ (Max.slt(Result.getInt().getSExtValue()) ||
+ Min.sgt(Result.getInt().getSExtValue())))
+ Info.Ctx.getDiagnostics().Report(
+ E->getExprLoc(), diag::warn_constexpr_unscoped_enum_out_of_range)
+ << llvm::toString(Result.getInt(), 10) << Min.getSExtValue()
+ << Max.getSExtValue();
+ else if (!ED->getNumNegativeBits() && ConstexprVar &&
+ Max.ult(Result.getInt().getZExtValue()))
+ Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
+ diag::warn_constexpr_unscoped_enum_out_of_range)
+ << llvm::toString(Result.getInt(),10) << Min.getZExtValue() << Max.getZExtValue();
+ }
+ }
+
return Success(HandleIntToIntCast(Info, E, DestType, SrcType,
Result.getInt()), E);
}
case CK_PointerToIntegral: {
- CCEDiag(E, diag::note_constexpr_invalid_cast) << 2;
+ CCEDiag(E, diag::note_constexpr_invalid_cast)
+ << 2 << Info.Ctx.getLangOpts().CPlusPlus;
LValue LV;
if (!EvaluatePointer(SubExpr, LV, Info))
@@ -13878,9 +14048,12 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
}
bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+
switch (E->getBuiltinCallee()) {
default:
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ return false;
case Builtin::BI__builtin_huge_val:
case Builtin::BI__builtin_huge_valf:
@@ -13954,6 +14127,42 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
Result.copySign(RHS);
return true;
}
+
+ case Builtin::BI__builtin_fmax:
+ case Builtin::BI__builtin_fmaxf:
+ case Builtin::BI__builtin_fmaxl:
+ case Builtin::BI__builtin_fmaxf16:
+ case Builtin::BI__builtin_fmaxf128: {
+ // TODO: Handle sNaN.
+ APFloat RHS(0.);
+ if (!EvaluateFloat(E->getArg(0), Result, Info) ||
+ !EvaluateFloat(E->getArg(1), RHS, Info))
+ return false;
+ // When comparing zeroes, return +0.0 if one of the zeroes is positive.
+ if (Result.isZero() && RHS.isZero() && Result.isNegative())
+ Result = RHS;
+ else if (Result.isNaN() || RHS > Result)
+ Result = RHS;
+ return true;
+ }
+
+ case Builtin::BI__builtin_fmin:
+ case Builtin::BI__builtin_fminf:
+ case Builtin::BI__builtin_fminl:
+ case Builtin::BI__builtin_fminf16:
+ case Builtin::BI__builtin_fminf128: {
+ // TODO: Handle sNaN.
+ APFloat RHS(0.);
+ if (!EvaluateFloat(E->getArg(0), Result, Info) ||
+ !EvaluateFloat(E->getArg(1), RHS, Info))
+ return false;
+ // When comparing zeroes, return -0.0 if one of the zeroes is negative.
+ if (Result.isZero() && RHS.isZero() && RHS.isNegative())
+ Result = RHS;
+ else if (Result.isNaN() || RHS < Result)
+ Result = RHS;
+ return true;
+ }
}
}
@@ -14564,6 +14773,9 @@ bool ComplexExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
}
bool ComplexExprEvaluator::VisitCallExpr(const CallExpr *E) {
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+
switch (E->getBuiltinCallee()) {
case Builtin::BI__builtin_complex:
Result.makeComplexFloat();
@@ -14574,10 +14786,8 @@ bool ComplexExprEvaluator::VisitCallExpr(const CallExpr *E) {
return true;
default:
- break;
+ return false;
}
-
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
//===----------------------------------------------------------------------===//
@@ -14653,6 +14863,9 @@ public:
}
bool VisitCallExpr(const CallExpr *E) {
+ if (!IsConstantEvaluatedBuiltinCall(E))
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+
switch (E->getBuiltinCallee()) {
case Builtin::BI__assume:
case Builtin::BI__builtin_assume:
@@ -14663,10 +14876,8 @@ public:
return HandleOperatorDeleteCall(Info, E);
default:
- break;
+ return false;
}
-
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
bool VisitCXXDeleteExpr(const CXXDeleteExpr *E);
@@ -14703,7 +14914,7 @@ bool VoidExprEvaluator::VisitCXXDeleteExpr(const CXXDeleteExpr *E) {
return true;
}
- Optional<DynAlloc *> Alloc = CheckDeleteKind(
+ std::optional<DynAlloc *> Alloc = CheckDeleteKind(
Info, E, Pointer, E->isArrayForm() ? DynAlloc::ArrayNew : DynAlloc::New);
if (!Alloc)
return false;
@@ -14871,25 +15082,27 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
/// lvalue-to-rvalue cast if it is an lvalue.
static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
assert(!E->isValueDependent());
+
+ if (E->getType().isNull())
+ return false;
+
+ if (!CheckLiteralType(Info, E))
+ return false;
+
if (Info.EnableNewConstInterp) {
if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
return false;
} else {
- if (E->getType().isNull())
- return false;
-
- if (!CheckLiteralType(Info, E))
- return false;
-
if (!::Evaluate(Result, Info, E))
return false;
+ }
- if (E->isGLValue()) {
- LValue LV;
- LV.setFrom(Info.Ctx, Result);
- if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
- return false;
- }
+ // Implicit lvalue-to-rvalue cast.
+ if (E->isGLValue()) {
+ LValue LV;
+ LV.setFrom(Info.Ctx, Result);
+ if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
+ return false;
}
// Check this core constant expression is a constant expression.
@@ -14909,6 +15122,12 @@ static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result,
return true;
}
+ if (const auto *L = dyn_cast<CXXBoolLiteralExpr>(Exp)) {
+ Result.Val = APValue(APSInt(APInt(1, L->getValue())));
+ IsConst = true;
+ return true;
+ }
+
// This case should be rare, but we need to check it before we check on
// the type below.
if (Exp->getType().isNull()) {
@@ -14986,6 +15205,7 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx,
bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsRValue");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
Info.InConstantContext = InConstantContext;
return ::EvaluateAsRValue(this, Result, Ctx, Info);
@@ -14995,6 +15215,7 @@ bool Expr::EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx,
bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsBooleanCondition");
EvalResult Scratch;
return EvaluateAsRValue(Scratch, Ctx, InConstantContext) &&
HandleConversionToBool(Scratch.Val, Result);
@@ -15005,6 +15226,7 @@ bool Expr::EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx,
bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsInt");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
Info.InConstantContext = InConstantContext;
return ::EvaluateAsInt(this, Result, Ctx, AllowSideEffects, Info);
@@ -15015,6 +15237,7 @@ bool Expr::EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx,
bool InConstantContext) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsFixedPoint");
EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
Info.InConstantContext = InConstantContext;
return ::EvaluateAsFixedPoint(this, Result, Ctx, AllowSideEffects, Info);
@@ -15029,6 +15252,7 @@ bool Expr::EvaluateAsFloat(APFloat &Result, const ASTContext &Ctx,
if (!getType()->isRealFloatingType())
return false;
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsFloat");
EvalResult ExprResult;
if (!EvaluateAsRValue(ExprResult, Ctx, InConstantContext) ||
!ExprResult.Val.isFloat() ||
@@ -15044,6 +15268,7 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx,
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsLValue");
EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
Info.InConstantContext = InConstantContext;
LValue LV;
@@ -15087,7 +15312,11 @@ bool Expr::EvaluateAsConstantExpr(EvalResult &Result, const ASTContext &Ctx,
ConstantExprKind Kind) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ bool IsConst;
+ if (FastEvaluateAsRValue(this, Result, Ctx, IsConst) && Result.Val.hasValue())
+ return true;
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateAsConstantExpr");
EvalInfo::EvaluationMode EM = EvalInfo::EM_ConstantExpression;
EvalInfo Info(Ctx, Result, EM);
Info.InConstantContext = true;
@@ -15140,6 +15369,13 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ llvm::TimeTraceScope TimeScope("EvaluateAsInitializer", [&] {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ VD->printQualifiedName(OS);
+ return Name;
+ });
+
// FIXME: Evaluating initializers for large array and record types can cause
// performance problems. Only do so in C++11 for now.
if (isPRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
@@ -15228,6 +15464,7 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateKnownConstInt");
EvalResult EVResult;
EVResult.Diag = Diag;
EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
@@ -15246,6 +15483,7 @@ APSInt Expr::EvaluateKnownConstIntCheckOverflow(
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateKnownConstIntCheckOverflow");
EvalResult EVResult;
EVResult.Diag = Diag;
EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
@@ -15264,6 +15502,7 @@ void Expr::EvaluateForOverflow(const ASTContext &Ctx) const {
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "EvaluateForOverflow");
bool IsConst;
EvalResult EVResult;
if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) {
@@ -15425,6 +15664,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case Expr::DependentCoawaitExprClass:
case Expr::CoyieldExprClass:
case Expr::SYCLUniqueStableNameExprClass:
+ case Expr::CXXParenListInitExprClass:
return ICEDiag(IK_NotICE, E->getBeginLoc());
case Expr::InitListExprClass: {
@@ -15755,6 +15995,8 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ ExprTimeTraceScope TimeScope(this, Ctx, "isIntegerConstantExpr");
+
if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, nullptr, Loc);
@@ -15766,12 +16008,12 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
return true;
}
-Optional<llvm::APSInt> Expr::getIntegerConstantExpr(const ASTContext &Ctx,
- SourceLocation *Loc,
- bool isEvaluated) const {
+std::optional<llvm::APSInt>
+Expr::getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc,
+ bool isEvaluated) const {
if (isValueDependent()) {
// Expression evaluator can't succeed on a dependent expression.
- return None;
+ return std::nullopt;
}
APSInt Value;
@@ -15779,11 +16021,11 @@ Optional<llvm::APSInt> Expr::getIntegerConstantExpr(const ASTContext &Ctx,
if (Ctx.getLangOpts().CPlusPlus11) {
if (EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc))
return Value;
- return None;
+ return std::nullopt;
}
if (!isIntegerConstantExpr(Ctx, Loc))
- return None;
+ return std::nullopt;
// The only possible side-effects here are due to UB discovered in the
// evaluation (for instance, INT_MAX + 1). In such a case, we are still
@@ -15847,6 +16089,14 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
+ llvm::TimeTraceScope TimeScope("EvaluateWithSubstitution", [&] {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ Callee->getNameForDiagnostic(OS, Ctx.getPrintingPolicy(),
+ /*Qualified=*/true);
+ return Name;
+ });
+
Expr::EvalStatus Status;
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpressionUnevaluated);
Info.InConstantContext = true;
@@ -15911,6 +16161,14 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
if (FD->isDependentContext())
return true;
+ llvm::TimeTraceScope TimeScope("isPotentialConstantExpr", [&] {
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ FD->getNameForDiagnostic(OS, FD->getASTContext().getPrintingPolicy(),
+ /*Qualified=*/true);
+ return Name;
+ });
+
Expr::EvalStatus Status;
Status.Diag = &Diags;
diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp
index 257833182621..090ef02aa422 100644
--- a/clang/lib/AST/ExternalASTSource.cpp
+++ b/clang/lib/AST/ExternalASTSource.cpp
@@ -20,9 +20,9 @@
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/None.h"
#include "llvm/Support/ErrorHandling.h"
#include <cstdint>
+#include <optional>
using namespace clang;
@@ -30,9 +30,9 @@ char ExternalASTSource::ID;
ExternalASTSource::~ExternalASTSource() = default;
-llvm::Optional<ASTSourceDescriptor>
+std::optional<ASTSourceDescriptor>
ExternalASTSource::getSourceDescriptor(unsigned ID) {
- return None;
+ return std::nullopt;
}
ExternalASTSource::ExtKind
diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp
index c0879704de4d..c7dee2d421bb 100644
--- a/clang/lib/AST/FormatString.cpp
+++ b/clang/lib/AST/FormatString.cpp
@@ -15,6 +15,7 @@
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/ConvertUTF.h"
+#include <optional>
using clang::analyze_format_string::ArgType;
using clang::analyze_format_string::FormatStringHandler;
@@ -348,7 +349,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
return Match;
case AnyCharTy: {
- if (const EnumType *ETy = argTy->getAs<EnumType>()) {
+ if (const auto *ETy = argTy->getAs<EnumType>()) {
// If the enum is incomplete we know nothing about the underlying type.
// Assume that it's 'int'.
if (!ETy->getDecl()->isComplete())
@@ -356,17 +357,34 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
argTy = ETy->getDecl()->getIntegerType();
}
- if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
+ if (const auto *BT = argTy->getAs<BuiltinType>()) {
+ // The types are perfectly matched?
switch (BT->getKind()) {
+ default:
+ break;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ case BuiltinType::UChar:
+ case BuiltinType::Char_U:
+ case BuiltinType::Bool:
+ return Match;
+ }
+ // "Partially matched" because of promotions?
+ if (!Ptr) {
+ switch (BT->getKind()) {
default:
break;
- case BuiltinType::Char_S:
- case BuiltinType::SChar:
- case BuiltinType::UChar:
- case BuiltinType::Char_U:
- case BuiltinType::Bool:
- return Match;
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ return MatchPromotion;
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ return NoMatchPromotionTypeConfusion;
+ }
}
+ }
return NoMatch;
}
@@ -383,8 +401,9 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
if (T == argTy)
return Match;
- // Check for "compatible types".
- if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
+ if (const auto *BT = argTy->getAs<BuiltinType>()) {
+ // Check if the only difference between them is signed vs unsigned
+ // if true, we consider they are compatible.
switch (BT->getKind()) {
default:
break;
@@ -395,25 +414,66 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
case BuiltinType::Bool:
if (T == C.UnsignedShortTy || T == C.ShortTy)
return NoMatchTypeConfusion;
- return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match
- : NoMatch;
+ if (T == C.UnsignedCharTy || T == C.SignedCharTy)
+ return Match;
+ break;
case BuiltinType::Short:
- return T == C.UnsignedShortTy ? Match : NoMatch;
+ if (T == C.UnsignedShortTy)
+ return Match;
+ break;
case BuiltinType::UShort:
- return T == C.ShortTy ? Match : NoMatch;
+ if (T == C.ShortTy)
+ return Match;
+ break;
case BuiltinType::Int:
- return T == C.UnsignedIntTy ? Match : NoMatch;
+ if (T == C.UnsignedIntTy)
+ return Match;
+ break;
case BuiltinType::UInt:
- return T == C.IntTy ? Match : NoMatch;
+ if (T == C.IntTy)
+ return Match;
+ break;
case BuiltinType::Long:
- return T == C.UnsignedLongTy ? Match : NoMatch;
+ if (T == C.UnsignedLongTy)
+ return Match;
+ break;
case BuiltinType::ULong:
- return T == C.LongTy ? Match : NoMatch;
+ if (T == C.LongTy)
+ return Match;
+ break;
case BuiltinType::LongLong:
- return T == C.UnsignedLongLongTy ? Match : NoMatch;
+ if (T == C.UnsignedLongLongTy)
+ return Match;
+ break;
case BuiltinType::ULongLong:
- return T == C.LongLongTy ? Match : NoMatch;
- }
+ if (T == C.LongLongTy)
+ return Match;
+ break;
+ }
+ // "Partially matched" because of promotions?
+ if (!Ptr) {
+ switch (BT->getKind()) {
+ default:
+ break;
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ if (T == C.SignedCharTy || T == C.UnsignedCharTy ||
+ T == C.ShortTy || T == C.UnsignedShortTy || T == C.WCharTy ||
+ T == C.WideCharTy)
+ return MatchPromotion;
+ break;
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ if (T == C.SignedCharTy || T == C.UnsignedCharTy)
+ return NoMatchPromotionTypeConfusion;
+ break;
+ case BuiltinType::WChar_U:
+ case BuiltinType::WChar_S:
+ if (T != C.WCharTy && T != C.WideCharTy)
+ return NoMatchPromotionTypeConfusion;
+ }
+ }
+ }
return NoMatch;
}
@@ -451,7 +511,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const {
if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)
return Match;
- QualType PromoArg = argTy->isPromotableIntegerType()
+ QualType PromoArg = C.isPromotableIntegerType(argTy)
? C.getPromotedIntegerType(argTy)
: argTy;
PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();
@@ -624,6 +684,8 @@ analyze_format_string::LengthModifier::toString() const {
const char *ConversionSpecifier::toString() const {
switch (kind) {
+ case bArg: return "b";
+ case BArg: return "B";
case dArg: return "d";
case DArg: return "D";
case iArg: return "i";
@@ -673,13 +735,13 @@ const char *ConversionSpecifier::toString() const {
return nullptr;
}
-Optional<ConversionSpecifier>
+std::optional<ConversionSpecifier>
ConversionSpecifier::getStandardSpecifier() const {
ConversionSpecifier::Kind NewKind;
switch (getKind()) {
default:
- return None;
+ return std::nullopt;
case DArg:
NewKind = dArg;
break;
@@ -745,7 +807,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
break;
}
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case LengthModifier::AsChar:
case LengthModifier::AsLongLong:
case LengthModifier::AsQuad:
@@ -753,6 +815,8 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target,
case LengthModifier::AsSizeT:
case LengthModifier::AsPtrDiff:
switch (CS.getKind()) {
+ case ConversionSpecifier::bArg:
+ case ConversionSpecifier::BArg:
case ConversionSpecifier::dArg:
case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
@@ -908,6 +972,8 @@ bool FormatSpecifier::hasStandardLengthModifier() const {
bool FormatSpecifier::hasStandardConversionSpecifier(
const LangOptions &LangOpt) const {
switch (CS.getKind()) {
+ case ConversionSpecifier::bArg:
+ case ConversionSpecifier::BArg:
case ConversionSpecifier::cArg:
case ConversionSpecifier::dArg:
case ConversionSpecifier::iArg:
@@ -966,7 +1032,8 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const {
return true;
}
-Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier() const {
+std::optional<LengthModifier>
+FormatSpecifier::getCorrectedLengthModifier() const {
if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {
if (LM.getKind() == LengthModifier::AsLongDouble ||
LM.getKind() == LengthModifier::AsQuad) {
@@ -976,15 +1043,14 @@ Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier() const {
}
}
- return None;
+ return std::nullopt;
}
bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
LengthModifier &LM) {
- assert(isa<TypedefType>(QT) && "Expected a TypedefType");
- const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();
-
- for (;;) {
+ for (/**/; const auto *TT = QT->getAs<TypedefType>();
+ QT = TT->getDecl()->getUnderlyingType()) {
+ const TypedefNameDecl *Typedef = TT->getDecl();
const IdentifierInfo *Identifier = Typedef->getIdentifier();
if (Identifier->getName() == "size_t") {
LM.setKind(LengthModifier::AsSizeT);
@@ -1003,12 +1069,6 @@ bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,
LM.setKind(LengthModifier::AsPtrDiff);
return true;
}
-
- QualType T = Typedef->getUnderlyingType();
- if (!isa<TypedefType>(T))
- break;
-
- Typedef = cast<TypedefType>(T)->getDecl();
}
return false;
}
diff --git a/clang/lib/AST/Interp/Boolean.h b/clang/lib/AST/Interp/Boolean.h
index 2baa717311bc..3122388a49a5 100644
--- a/clang/lib/AST/Interp/Boolean.h
+++ b/clang/lib/AST/Interp/Boolean.h
@@ -22,7 +22,7 @@ namespace clang {
namespace interp {
/// Wrapper around boolean types.
-class Boolean {
+class Boolean final {
private:
/// Underlying boolean.
bool V;
@@ -46,9 +46,15 @@ class Boolean {
Boolean operator-() const { return Boolean(V); }
Boolean operator~() const { return Boolean(true); }
- explicit operator unsigned() const { return V; }
+ explicit operator int8_t() const { return V; }
+ explicit operator uint8_t() const { return V; }
+ explicit operator int16_t() const { return V; }
+ explicit operator uint16_t() const { return V; }
+ explicit operator int32_t() const { return V; }
+ explicit operator uint32_t() const { return V; }
explicit operator int64_t() const { return V; }
explicit operator uint64_t() const { return V; }
+ explicit operator bool() const { return V; }
APSInt toAPSInt() const {
return APSInt(APInt(1, static_cast<uint64_t>(V), false), true);
@@ -84,9 +90,10 @@ class Boolean {
static Boolean min(unsigned NumBits) { return Boolean(false); }
static Boolean max(unsigned NumBits) { return Boolean(true); }
- template <typename T>
- static std::enable_if_t<std::is_integral<T>::value, Boolean> from(T Value) {
- return Boolean(Value != 0);
+ template <typename T> static Boolean from(T Value) {
+ if constexpr (std::is_integral<T>::value)
+ return Boolean(Value != 0);
+ return Boolean(static_cast<decltype(Boolean::V)>(Value) != 0);
}
template <unsigned SrcBits, bool SrcSign>
@@ -134,6 +141,16 @@ class Boolean {
*R = Boolean(A.V && B.V);
return false;
}
+
+ static bool inv(Boolean A, Boolean *R) {
+ *R = Boolean(!A.V);
+ return false;
+ }
+
+ static bool neg(Boolean A, Boolean *R) {
+ *R = Boolean(A.V);
+ return false;
+ }
};
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Boolean &B) {
diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
index a69b23fd613c..4633d1e0823b 100644
--- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp
@@ -19,51 +19,72 @@ using namespace clang::interp;
using APSInt = llvm::APSInt;
using Error = llvm::Error;
-Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
- // Do not try to compile undefined functions.
- if (!F->isDefined(F) || (!F->hasBody() && F->willHaveBody()))
- return nullptr;
-
- // Set up argument indices.
- unsigned ParamOffset = 0;
- SmallVector<PrimType, 8> ParamTypes;
- llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
-
- // If the return is not a primitive, a pointer to the storage where the value
- // is initialized in is passed as the first argument.
- QualType Ty = F->getReturnType();
- if (!Ty->isVoidType() && !Ctx.classify(Ty)) {
- ParamTypes.push_back(PT_Ptr);
- ParamOffset += align(primSize(PT_Ptr));
- }
+Expected<Function *>
+ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) {
+ // Function is not defined at all or not yet. We will
+ // create a Function instance but not compile the body. That
+ // will (maybe) happen later.
+ bool HasBody = FuncDecl->hasBody(FuncDecl);
+
+ // Create a handle over the emitted code.
+ Function *Func = P.getFunction(FuncDecl);
+ if (!Func) {
+ // Set up argument indices.
+ unsigned ParamOffset = 0;
+ SmallVector<PrimType, 8> ParamTypes;
+ llvm::DenseMap<unsigned, Function::ParamDescriptor> ParamDescriptors;
+
+ // If the return is not a primitive, a pointer to the storage where the
+ // value is initialized in is passed as the first argument. See 'RVO'
+ // elsewhere in the code.
+ QualType Ty = FuncDecl->getReturnType();
+ bool HasRVO = false;
+ if (!Ty->isVoidType() && !Ctx.classify(Ty)) {
+ HasRVO = true;
+ ParamTypes.push_back(PT_Ptr);
+ ParamOffset += align(primSize(PT_Ptr));
+ }
+
+ // If the function decl is a member decl, the next parameter is
+ // the 'this' pointer. This parameter is pop()ed from the
+ // InterpStack when calling the function.
+ bool HasThisPointer = false;
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(FuncDecl);
+ MD && MD->isInstance()) {
+ HasThisPointer = true;
+ ParamTypes.push_back(PT_Ptr);
+ ParamOffset += align(primSize(PT_Ptr));
+ }
- // Assign descriptors to all parameters.
- // Composite objects are lowered to pointers.
- for (const ParmVarDecl *PD : F->parameters()) {
- PrimType Ty;
- if (llvm::Optional<PrimType> T = Ctx.classify(PD->getType())) {
- Ty = *T;
- } else {
- Ty = PT_Ptr;
+ // Assign descriptors to all parameters.
+ // Composite objects are lowered to pointers.
+ for (const ParmVarDecl *PD : FuncDecl->parameters()) {
+ PrimType Ty = Ctx.classify(PD->getType()).value_or(PT_Ptr);
+ Descriptor *Desc = P.createDescriptor(PD, Ty);
+ ParamDescriptors.insert({ParamOffset, {Ty, Desc}});
+ Params.insert({PD, ParamOffset});
+ ParamOffset += align(primSize(Ty));
+ ParamTypes.push_back(Ty);
}
- Descriptor *Desc = P.createDescriptor(PD, Ty);
- ParamDescriptors.insert({ParamOffset, {Ty, Desc}});
- Params.insert({PD, ParamOffset});
- ParamOffset += align(primSize(Ty));
- ParamTypes.push_back(Ty);
+ Func =
+ P.createFunction(FuncDecl, ParamOffset, std::move(ParamTypes),
+ std::move(ParamDescriptors), HasThisPointer, HasRVO);
}
- // Create a handle over the emitted code.
- Function *Func = P.createFunction(F, ParamOffset, std::move(ParamTypes),
- std::move(ParamDescriptors));
+ assert(Func);
+ if (!HasBody)
+ return Func;
+
// Compile the function body.
- if (!F->isConstexpr() || !visitFunc(F)) {
+ if (!FuncDecl->isConstexpr() || !visitFunc(FuncDecl)) {
// Return a dummy function if compilation failed.
if (BailLocation)
return llvm::make_error<ByteCodeGenError>(*BailLocation);
- else
+ else {
+ Func->setIsFullyCompiled(true);
return Func;
+ }
} else {
// Create scopes from descriptors.
llvm::SmallVector<Scope, 2> Scopes;
@@ -74,6 +95,7 @@ Expected<Function *> ByteCodeEmitter::compileFunc(const FunctionDecl *F) {
// Set the function's code.
Func->setCode(NextLocalOffset, std::move(Code), std::move(SrcMap),
std::move(Scopes));
+ Func->setIsFullyCompiled(true);
return Func;
}
}
@@ -94,7 +116,8 @@ void ByteCodeEmitter::emitLabel(LabelTy Label) {
using namespace llvm::support;
/// Rewrite the operand of all jumps to this label.
- void *Location = Code.data() + Reloc - sizeof(int32_t);
+ void *Location = Code.data() + Reloc - align(sizeof(int32_t));
+ assert(aligned(Location));
const int32_t Offset = Target - static_cast<int64_t>(Reloc);
endian::write<int32_t, endianness::native, 1>(Location, Offset);
}
@@ -104,7 +127,9 @@ void ByteCodeEmitter::emitLabel(LabelTy Label) {
int32_t ByteCodeEmitter::getOffset(LabelTy Label) {
// Compute the PC offset which the jump is relative to.
- const int64_t Position = Code.size() + sizeof(Opcode) + sizeof(int32_t);
+ const int64_t Position =
+ Code.size() + align(sizeof(Opcode)) + align(sizeof(int32_t));
+ assert(aligned(Position));
// If target is known, compute jump offset.
auto It = LabelOffsets.find(Label);
@@ -126,30 +151,32 @@ bool ByteCodeEmitter::bail(const SourceLocation &Loc) {
/// Helper to write bytecode and bail out if 32-bit offsets become invalid.
/// Pointers will be automatically marshalled as 32-bit IDs.
template <typename T>
-static std::enable_if_t<!std::is_pointer<T>::value, void>
-emit(Program &P, std::vector<char> &Code, const T &Val, bool &Success) {
- size_t Size = sizeof(Val);
- if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
- Success = false;
- return;
- }
+static void emit(Program &P, std::vector<char> &Code, const T &Val,
+ bool &Success) {
+ size_t Size;
- const char *Data = reinterpret_cast<const char *>(&Val);
- Code.insert(Code.end(), Data, Data + Size);
-}
+ if constexpr (std::is_pointer_v<T>)
+ Size = sizeof(uint32_t);
+ else
+ Size = sizeof(T);
-template <typename T>
-static std::enable_if_t<std::is_pointer<T>::value, void>
-emit(Program &P, std::vector<char> &Code, const T &Val, bool &Success) {
- size_t Size = sizeof(uint32_t);
if (Code.size() + Size > std::numeric_limits<unsigned>::max()) {
Success = false;
return;
}
- uint32_t ID = P.getOrCreateNativePointer(Val);
- const char *Data = reinterpret_cast<const char *>(&ID);
- Code.insert(Code.end(), Data, Data + Size);
+ // Access must be aligned!
+ size_t ValPos = align(Code.size());
+ Size = align(Size);
+ assert(aligned(ValPos + Size));
+ Code.resize(ValPos + Size);
+
+ if constexpr (!std::is_pointer_v<T>) {
+ new (Code.data() + ValPos) T(Val);
+ } else {
+ uint32_t ID = P.getOrCreateNativePointer(Val);
+ new (Code.data() + ValPos) uint32_t(ID);
+ }
}
template <typename... Tys>
diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.h b/clang/lib/AST/Interp/ByteCodeEmitter.h
index 03452a350c96..30da06b20250 100644
--- a/clang/lib/AST/Interp/ByteCodeEmitter.h
+++ b/clang/lib/AST/Interp/ByteCodeEmitter.h
@@ -37,7 +37,7 @@ protected:
public:
/// Compiles the function into the module.
- llvm::Expected<Function *> compileFunc(const FunctionDecl *F);
+ llvm::Expected<Function *> compileFunc(const FunctionDecl *FuncDecl);
protected:
ByteCodeEmitter(Context &Ctx, Program &P) : Ctx(Ctx), P(P) {}
@@ -83,7 +83,7 @@ private:
/// Offset of the next local variable.
unsigned NextLocalOffset = 0;
/// Location of a failure.
- llvm::Optional<SourceLocation> BailLocation;
+ std::optional<SourceLocation> BailLocation;
/// Label information for linker.
llvm::DenseMap<LabelTy, unsigned> LabelOffsets;
/// Location of label relocations.
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 9b729e347a24..615dbdefefbe 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -9,6 +9,7 @@
#include "ByteCodeExprGen.h"
#include "ByteCodeEmitter.h"
#include "ByteCodeGenError.h"
+#include "ByteCodeStmtGen.h"
#include "Context.h"
#include "Function.h"
#include "PrimType.h"
@@ -19,8 +20,6 @@ using namespace clang;
using namespace clang::interp;
using APSInt = llvm::APSInt;
-template <typename T> using Expected = llvm::Expected<T>;
-template <typename T> using Optional = llvm::Optional<T>;
namespace clang {
namespace interp {
@@ -42,45 +41,19 @@ private:
/// Scope used to handle initialization methods.
template <class Emitter> class OptionScope {
public:
- using InitFnRef = typename ByteCodeExprGen<Emitter>::InitFnRef;
- using ChainedInitFnRef = std::function<bool(InitFnRef)>;
-
/// Root constructor, compiling or discarding primitives.
OptionScope(ByteCodeExprGen<Emitter> *Ctx, bool NewDiscardResult)
- : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
- OldInitFn(std::move(Ctx->InitFn)) {
+ : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult) {
Ctx->DiscardResult = NewDiscardResult;
- Ctx->InitFn = llvm::Optional<InitFnRef>{};
- }
-
- /// Root constructor, setting up compilation state.
- OptionScope(ByteCodeExprGen<Emitter> *Ctx, InitFnRef NewInitFn)
- : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
- OldInitFn(std::move(Ctx->InitFn)) {
- Ctx->DiscardResult = true;
- Ctx->InitFn = NewInitFn;
}
- /// Extends the chain of initialisation pointers.
- OptionScope(ByteCodeExprGen<Emitter> *Ctx, ChainedInitFnRef NewInitFn)
- : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
- OldInitFn(std::move(Ctx->InitFn)) {
- assert(OldInitFn && "missing initializer");
- Ctx->InitFn = [this, NewInitFn] { return NewInitFn(*OldInitFn); };
- }
-
- ~OptionScope() {
- Ctx->DiscardResult = OldDiscardResult;
- Ctx->InitFn = std::move(OldInitFn);
- }
+ ~OptionScope() { Ctx->DiscardResult = OldDiscardResult; }
private:
/// Parent context.
ByteCodeExprGen<Emitter> *Ctx;
/// Old discard flag to restore.
bool OldDiscardResult;
- /// Old pointer emitter to restore.
- llvm::Optional<InitFnRef> OldInitFn;
};
} // namespace interp
@@ -106,6 +79,22 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
});
}
+ case CK_UncheckedDerivedToBase:
+ case CK_DerivedToBase: {
+ if (!this->visit(SubExpr))
+ return false;
+
+ const CXXRecordDecl *FromDecl = getRecordDecl(SubExpr);
+ assert(FromDecl);
+ const CXXRecordDecl *ToDecl = getRecordDecl(CE);
+ assert(ToDecl);
+ const Record *R = getRecord(FromDecl);
+ const Record::Base *ToBase = R->getBase(ToDecl);
+ assert(ToBase);
+
+ return this->emitGetPtrBase(ToBase->Offset, CE);
+ }
+
case CK_ArrayToPointerDecay:
case CK_AtomicToNonAtomic:
case CK_ConstructorConversion:
@@ -113,16 +102,30 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_NonAtomicToAtomic:
case CK_NoOp:
case CK_UserDefinedConversion:
- return this->Visit(SubExpr);
+ case CK_NullToPointer:
+ return this->visit(SubExpr);
+
+ case CK_IntegralToBoolean:
+ case CK_IntegralCast: {
+ std::optional<PrimType> FromT = classify(SubExpr->getType());
+ std::optional<PrimType> ToT = classify(CE->getType());
+ if (!FromT || !ToT)
+ return false;
+
+ if (!this->visit(SubExpr))
+ return false;
+
+ // TODO: Emit this only if FromT != ToT.
+ return this->emitCast(*FromT, *ToT, CE);
+ }
case CK_ToVoid:
return discard(SubExpr);
- default: {
- // TODO: implement other casts.
- return this->bail(CE);
- }
+ default:
+ assert(false && "Cast not implemented");
}
+ llvm_unreachable("Unhandled clang::CastKind enum");
}
template <class Emitter>
@@ -130,16 +133,12 @@ bool ByteCodeExprGen<Emitter>::VisitIntegerLiteral(const IntegerLiteral *LE) {
if (DiscardResult)
return true;
- auto Val = LE->getValue();
- QualType LitTy = LE->getType();
- if (Optional<PrimType> T = classify(LitTy))
- return emitConst(*T, getIntWidth(LitTy), LE->getValue(), LE);
- return this->bail(LE);
+ return this->emitConst(LE->getValue(), LE);
}
template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitParenExpr(const ParenExpr *PE) {
- return this->Visit(PE->getSubExpr());
+ return this->visit(PE->getSubExpr());
}
template <class Emitter>
@@ -152,7 +151,7 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
case BO_Comma:
if (!discard(LHS))
return false;
- if (!this->Visit(RHS))
+ if (!this->visit(RHS))
return false;
return true;
default:
@@ -160,53 +159,398 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
}
// Typecheck the args.
- Optional<PrimType> LT = classify(LHS->getType());
- Optional<PrimType> RT = classify(RHS->getType());
- if (!LT || !RT) {
+ std::optional<PrimType> LT = classify(LHS->getType());
+ std::optional<PrimType> RT = classify(RHS->getType());
+ std::optional<PrimType> T = classify(BO->getType());
+ if (!LT || !RT || !T) {
return this->bail(BO);
}
- if (Optional<PrimType> T = classify(BO->getType())) {
- if (!visit(LHS))
+ auto Discard = [this, T, BO](bool Result) {
+ if (!Result)
return false;
- if (!visit(RHS))
+ return DiscardResult ? this->emitPop(*T, BO) : true;
+ };
+
+ // Pointer arithmetic special case.
+ if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) {
+ if (*T == PT_Ptr || (*LT == PT_Ptr && *RT == PT_Ptr))
+ return this->VisitPointerArithBinOp(BO);
+ }
+
+ if (!visit(LHS) || !visit(RHS))
+ return false;
+
+ switch (BO->getOpcode()) {
+ case BO_EQ:
+ return Discard(this->emitEQ(*LT, BO));
+ case BO_NE:
+ return Discard(this->emitNE(*LT, BO));
+ case BO_LT:
+ return Discard(this->emitLT(*LT, BO));
+ case BO_LE:
+ return Discard(this->emitLE(*LT, BO));
+ case BO_GT:
+ return Discard(this->emitGT(*LT, BO));
+ case BO_GE:
+ return Discard(this->emitGE(*LT, BO));
+ case BO_Sub:
+ return Discard(this->emitSub(*T, BO));
+ case BO_Add:
+ return Discard(this->emitAdd(*T, BO));
+ case BO_Mul:
+ return Discard(this->emitMul(*T, BO));
+ case BO_Rem:
+ return Discard(this->emitRem(*T, BO));
+ case BO_Div:
+ return Discard(this->emitDiv(*T, BO));
+ case BO_Assign:
+ if (DiscardResult)
+ return this->emitStorePop(*T, BO);
+ return this->emitStore(*T, BO);
+ case BO_And:
+ return Discard(this->emitBitAnd(*T, BO));
+ case BO_Or:
+ return Discard(this->emitBitOr(*T, BO));
+ case BO_Shl:
+ return Discard(this->emitShl(*LT, *RT, BO));
+ case BO_Shr:
+ return Discard(this->emitShr(*LT, *RT, BO));
+ case BO_Xor:
+ return Discard(this->emitBitXor(*T, BO));
+ case BO_LAnd:
+ case BO_LOr:
+ default:
+ return this->bail(BO);
+ }
+
+ llvm_unreachable("Unhandled binary op");
+}
+
+/// Perform addition/subtraction of a pointer and an integer or
+/// subtraction of two pointers.
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) {
+ BinaryOperatorKind Op = E->getOpcode();
+ const Expr *LHS = E->getLHS();
+ const Expr *RHS = E->getRHS();
+
+ if ((Op != BO_Add && Op != BO_Sub) ||
+ (!LHS->getType()->isPointerType() && !RHS->getType()->isPointerType()))
+ return false;
+
+ std::optional<PrimType> LT = classify(LHS);
+ std::optional<PrimType> RT = classify(RHS);
+
+ if (!LT || !RT)
+ return false;
+
+ if (LHS->getType()->isPointerType() && RHS->getType()->isPointerType()) {
+ if (Op != BO_Sub)
+ return false;
+
+ assert(E->getType()->isIntegerType());
+ if (!visit(RHS) || !visit(LHS))
+ return false;
+
+ return this->emitSubPtr(classifyPrim(E->getType()), E);
+ }
+
+ PrimType OffsetType;
+ if (LHS->getType()->isIntegerType()) {
+ if (!visit(RHS) || !visit(LHS))
+ return false;
+ OffsetType = *LT;
+ } else if (RHS->getType()->isIntegerType()) {
+ if (!visit(LHS) || !visit(RHS))
+ return false;
+ OffsetType = *RT;
+ } else {
+ return false;
+ }
+
+ if (Op == BO_Add)
+ return this->emitAddOffset(OffsetType, E);
+ else if (Op == BO_Sub)
+ return this->emitSubOffset(OffsetType, E);
+
+ return this->bail(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
+ if (std::optional<PrimType> T = classify(E))
+ return this->emitZero(*T, E);
+
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitArraySubscriptExpr(
+ const ArraySubscriptExpr *E) {
+ const Expr *Base = E->getBase();
+ const Expr *Index = E->getIdx();
+ PrimType IndexT = classifyPrim(Index->getType());
+
+ // Take pointer of LHS, add offset from RHS, narrow result.
+ // What's left on the stack after this is a pointer.
+ if (!this->visit(Base))
+ return false;
+
+ if (!this->visit(Index))
+ return false;
+
+ if (!this->emitAddOffset(IndexT, E))
+ return false;
+
+ if (!this->emitNarrowPtr(E))
+ return false;
+
+ if (DiscardResult)
+ return this->emitPopPtr(E);
+
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
+ for (const Expr *Init : E->inits()) {
+ if (!this->visit(Init))
return false;
+ }
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitSubstNonTypeTemplateParmExpr(
+ const SubstNonTypeTemplateParmExpr *E) {
+ return this->visit(E->getReplacement());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitConstantExpr(const ConstantExpr *E) {
+ // TODO: Check if the ConstantExpr already has a value set and if so,
+ // use that instead of evaluating it again.
+ return this->visit(E->getSubExpr());
+}
+
+static CharUnits AlignOfType(QualType T, const ASTContext &ASTCtx,
+ UnaryExprOrTypeTrait Kind) {
+ bool AlignOfReturnsPreferred =
+ ASTCtx.getLangOpts().getClangABICompat() <= LangOptions::ClangABI::Ver7;
- auto Discard = [this, T, BO](bool Result) {
- if (!Result)
+ // C++ [expr.alignof]p3:
+ // When alignof is applied to a reference type, the result is the
+ // alignment of the referenced type.
+ if (const auto *Ref = T->getAs<ReferenceType>())
+ T = Ref->getPointeeType();
+
+ // __alignof is defined to return the preferred alignment.
+ // Before 8, clang returned the preferred alignment for alignof and
+ // _Alignof as well.
+ if (Kind == UETT_PreferredAlignOf || AlignOfReturnsPreferred)
+ return ASTCtx.toCharUnitsFromBits(ASTCtx.getPreferredTypeAlign(T));
+
+ return ASTCtx.getTypeAlignInChars(T);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr *E) {
+ UnaryExprOrTypeTrait Kind = E->getKind();
+ ASTContext &ASTCtx = Ctx.getASTContext();
+
+ if (Kind == UETT_SizeOf) {
+ QualType ArgType = E->getTypeOfArgument();
+ CharUnits Size;
+ if (ArgType->isVoidType() || ArgType->isFunctionType())
+ Size = CharUnits::One();
+ else {
+ if (ArgType->isDependentType() || !ArgType->isConstantSizeType())
return false;
- return DiscardResult ? this->emitPop(*T, BO) : true;
- };
-
- switch (BO->getOpcode()) {
- case BO_EQ:
- return Discard(this->emitEQ(*LT, BO));
- case BO_NE:
- return Discard(this->emitNE(*LT, BO));
- case BO_LT:
- return Discard(this->emitLT(*LT, BO));
- case BO_LE:
- return Discard(this->emitLE(*LT, BO));
- case BO_GT:
- return Discard(this->emitGT(*LT, BO));
- case BO_GE:
- return Discard(this->emitGE(*LT, BO));
- case BO_Sub:
- return Discard(this->emitSub(*T, BO));
- case BO_Add:
- return Discard(this->emitAdd(*T, BO));
- case BO_Mul:
- return Discard(this->emitMul(*T, BO));
- default:
- return this->bail(BO);
+
+ Size = ASTCtx.getTypeSizeInChars(ArgType);
}
+
+ return this->emitConst(Size.getQuantity(), E);
+ }
+
+ if (Kind == UETT_AlignOf || Kind == UETT_PreferredAlignOf) {
+ CharUnits Size;
+
+ if (E->isArgumentType()) {
+ QualType ArgType = E->getTypeOfArgument();
+
+ Size = AlignOfType(ArgType, ASTCtx, Kind);
+ } else {
+ // Argument is an expression, not a type.
+ const Expr *Arg = E->getArgumentExpr()->IgnoreParens();
+
+ // The kinds of expressions that we have special-case logic here for
+ // should be kept up to date with the special checks for those
+ // expressions in Sema.
+
+ // alignof decl is always accepted, even if it doesn't make sense: we
+ // default to 1 in those cases.
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(Arg))
+ Size = ASTCtx.getDeclAlign(DRE->getDecl(),
+ /*RefAsPointee*/ true);
+ else if (const auto *ME = dyn_cast<MemberExpr>(Arg))
+ Size = ASTCtx.getDeclAlign(ME->getMemberDecl(),
+ /*RefAsPointee*/ true);
+ else
+ Size = AlignOfType(Arg->getType(), ASTCtx, Kind);
+ }
+
+ return this->emitConst(Size.getQuantity(), E);
}
- return this->bail(BO);
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
+ if (DiscardResult)
+ return true;
+
+ // 'Base.Member'
+ const Expr *Base = E->getBase();
+ const ValueDecl *Member = E->getMemberDecl();
+
+ if (!this->visit(Base))
+ return false;
+
+ // Base above gives us a pointer on the stack.
+ // TODO: Implement non-FieldDecl members.
+ if (const auto *FD = dyn_cast<FieldDecl>(Member)) {
+ const RecordDecl *RD = FD->getParent();
+ const Record *R = getRecord(RD);
+ const Record::Field *F = R->getField(FD);
+ // Leave a pointer to the field on the stack.
+ if (F->Decl->getType()->isReferenceType())
+ return this->emitGetFieldPop(PT_Ptr, F->Offset, E);
+ return this->emitGetPtrField(F->Offset, E);
+ }
+
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitArrayInitIndexExpr(
+ const ArrayInitIndexExpr *E) {
+ // ArrayIndex might not be set if a ArrayInitIndexExpr is being evaluated
+ // stand-alone, e.g. via EvaluateAsInt().
+ if (!ArrayIndex)
+ return false;
+ return this->emitConst(*ArrayIndex, E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
+ return this->visit(E->getSourceExpr());
}
template <class Emitter>
-bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
+bool ByteCodeExprGen<Emitter>::VisitAbstractConditionalOperator(
+ const AbstractConditionalOperator *E) {
+ const Expr *Condition = E->getCond();
+ const Expr *TrueExpr = E->getTrueExpr();
+ const Expr *FalseExpr = E->getFalseExpr();
+
+ LabelTy LabelEnd = this->getLabel(); // Label after the operator.
+ LabelTy LabelFalse = this->getLabel(); // Label for the false expr.
+
+ if (!this->visit(Condition))
+ return false;
+ if (!this->jumpFalse(LabelFalse))
+ return false;
+
+ if (!this->visit(TrueExpr))
+ return false;
+ if (!this->jump(LabelEnd))
+ return false;
+
+ this->emitLabel(LabelFalse);
+
+ if (!this->visit(FalseExpr))
+ return false;
+
+ this->fallthrough(LabelEnd);
+ this->emitLabel(LabelEnd);
+
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitStringLiteral(const StringLiteral *E) {
+ unsigned StringIndex = P.createGlobalString(E);
+ return this->emitGetPtrGlobal(StringIndex, E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCharacterLiteral(
+ const CharacterLiteral *E) {
+ return this->emitConst(E->getValue(), E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
+ const CompoundAssignOperator *E) {
+ const Expr *LHS = E->getLHS();
+ const Expr *RHS = E->getRHS();
+ std::optional<PrimType> LT = classify(E->getLHS()->getType());
+ std::optional<PrimType> RT = classify(E->getRHS()->getType());
+
+ if (!LT || !RT)
+ return false;
+
+ assert(!E->getType()->isPointerType() &&
+ "Support pointer arithmethic in compound assignment operators");
+
+ // Get LHS pointer, load its value and get RHS value.
+ if (!visit(LHS))
+ return false;
+ if (!this->emitLoad(*LT, E))
+ return false;
+ if (!visit(RHS))
+ return false;
+
+ // Perform operation.
+ switch (E->getOpcode()) {
+ case BO_AddAssign:
+ if (!this->emitAdd(*LT, E))
+ return false;
+ break;
+ case BO_SubAssign:
+ if (!this->emitSub(*LT, E))
+ return false;
+ break;
+
+ case BO_MulAssign:
+ case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_ShlAssign:
+ if (!this->emitShl(*LT, *RT, E))
+ return false;
+ break;
+ case BO_ShrAssign:
+ if (!this->emitShr(*LT, *RT, E))
+ return false;
+ break;
+ case BO_AndAssign:
+ case BO_XorAssign:
+ case BO_OrAssign:
+ default:
+ llvm_unreachable("Unimplemented compound assign operator");
+ }
+
+ // And store the result in LHS.
+ if (DiscardResult)
+ return this->emitStorePop(*LT, E);
+ return this->emitStore(*LT, E);
+}
+
+template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true);
return this->Visit(E);
}
@@ -219,7 +563,7 @@ bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {
- if (Optional<PrimType> T = classify(E->getType())) {
+ if (std::optional<PrimType> T = classify(E->getType())) {
return visit(E);
} else {
return this->bail(E);
@@ -257,7 +601,7 @@ template <class Emitter>
bool ByteCodeExprGen<Emitter>::dereference(
const Expr *LV, DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
llvm::function_ref<bool(PrimType)> Indirect) {
- if (Optional<PrimType> T = classify(LV->getType())) {
+ if (std::optional<PrimType> T = classify(LV->getType())) {
if (!LV->refersToBitField()) {
// Only primitive, non bit-field types can be dereferenced directly.
if (auto *DE = dyn_cast<DeclRefExpr>(LV)) {
@@ -350,7 +694,7 @@ bool ByteCodeExprGen<Emitter>::dereferenceVar(
return false;
return DiscardResult ? true : this->emitGetPtrLocal(L.Offset, LV);
}
- } else if (auto Idx = getGlobalIdx(VD)) {
+ } else if (auto Idx = P.getGlobal(VD)) {
switch (AK) {
case DerefKind::Read:
if (!this->emitGetGlobal(T, *Idx, LV))
@@ -382,7 +726,7 @@ bool ByteCodeExprGen<Emitter>::dereferenceVar(
if (VD->hasLocalStorage() && VD->hasInit() && !VD->isConstexpr()) {
QualType VT = VD->getType();
if (VT.isConstQualified() && VT->isFundamentalType())
- return this->Visit(VD->getInit());
+ return this->visit(VD->getInit());
}
}
@@ -391,27 +735,27 @@ bool ByteCodeExprGen<Emitter>::dereferenceVar(
}
template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitConst(PrimType T, unsigned NumBits,
- const APInt &Value, const Expr *E) {
- switch (T) {
+template <typename T>
+bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) {
+ switch (classifyPrim(E->getType())) {
case PT_Sint8:
- return this->emitConstSint8(Value.getSExtValue(), E);
+ return this->emitConstSint8(Value, E);
case PT_Uint8:
- return this->emitConstUint8(Value.getZExtValue(), E);
+ return this->emitConstUint8(Value, E);
case PT_Sint16:
- return this->emitConstSint16(Value.getSExtValue(), E);
+ return this->emitConstSint16(Value, E);
case PT_Uint16:
- return this->emitConstUint16(Value.getZExtValue(), E);
+ return this->emitConstUint16(Value, E);
case PT_Sint32:
- return this->emitConstSint32(Value.getSExtValue(), E);
+ return this->emitConstSint32(Value, E);
case PT_Uint32:
- return this->emitConstUint32(Value.getZExtValue(), E);
+ return this->emitConstUint32(Value, E);
case PT_Sint64:
- return this->emitConstSint64(Value.getSExtValue(), E);
+ return this->emitConstSint64(Value, E);
case PT_Uint64:
- return this->emitConstUint64(Value.getZExtValue(), E);
+ return this->emitConstUint64(Value, E);
case PT_Bool:
- return this->emitConstBool(Value.getBoolValue(), E);
+ return this->emitConstBool(Value, E);
case PT_Ptr:
llvm_unreachable("Invalid integral type");
break;
@@ -420,11 +764,29 @@ bool ByteCodeExprGen<Emitter>::emitConst(PrimType T, unsigned NumBits,
}
template <class Emitter>
+bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, const Expr *E) {
+ if (Value.isSigned())
+ return this->emitConst(Value.getSExtValue(), E);
+ return this->emitConst(Value.getZExtValue(), E);
+}
+
+template <class Emitter>
unsigned ByteCodeExprGen<Emitter>::allocateLocalPrimitive(DeclTy &&Src,
PrimType Ty,
bool IsConst,
bool IsExtended) {
- Descriptor *D = P.createDescriptor(Src, Ty, IsConst, Src.is<const Expr *>());
+ // 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.find(VD) == Locals.end());
+ }
+
+ // FIXME: There are cases where Src.is<Expr*>() is wrong, e.g.
+ // (int){12} in C. Consider using Expr::isTemporaryObject() instead
+ // or isa<MaterializeTemporaryExpr>().
+ Descriptor *D = P.createDescriptor(Src, Ty, Descriptor::InlineDescMD, IsConst,
+ Src.is<const Expr *>());
Scope::Local Local = this->createLocal(D);
if (auto *VD = dyn_cast_or_null<ValueDecl>(Src.dyn_cast<const Decl *>()))
Locals.insert({VD, Local});
@@ -433,23 +795,34 @@ unsigned ByteCodeExprGen<Emitter>::allocateLocalPrimitive(DeclTy &&Src,
}
template <class Emitter>
-llvm::Optional<unsigned>
+std::optional<unsigned>
ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src, bool IsExtended) {
- QualType Ty;
+ // 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.find(VD) == Locals.end());
+ }
+ QualType Ty;
const ValueDecl *Key = nullptr;
+ const Expr *Init = nullptr;
bool IsTemporary = false;
- if (auto *VD = dyn_cast_or_null<ValueDecl>(Src.dyn_cast<const Decl *>())) {
+ 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();
}
if (auto *E = Src.dyn_cast<const Expr *>()) {
IsTemporary = true;
Ty = E->getType();
}
- Descriptor *D = P.createDescriptor(Src, Ty.getTypePtr(),
- Ty.isConstQualified(), IsTemporary);
+ Descriptor *D = P.createDescriptor(
+ Src, Ty.getTypePtr(), Descriptor::InlineDescMD, Ty.isConstQualified(),
+ IsTemporary, /*IsMutable=*/false, Init);
if (!D)
return {};
@@ -460,38 +833,230 @@ ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src, bool IsExtended) {
return Local.Offset;
}
+// NB: When calling this function, we have a pointer to the
+// array-to-initialize on the stack.
template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitInitializer(
- const Expr *Init, InitFnRef InitFn) {
- OptionScope<Emitter> Scope(this, InitFn);
- return this->Visit(Init);
+bool ByteCodeExprGen<Emitter>::visitArrayInitializer(const Expr *Initializer) {
+ assert(Initializer->getType()->isArrayType());
+
+ // TODO: Fillers?
+ if (const auto *InitList = dyn_cast<InitListExpr>(Initializer)) {
+ unsigned ElementIndex = 0;
+ for (const Expr *Init : InitList->inits()) {
+ if (std::optional<PrimType> T = classify(Init->getType())) {
+ // Visit the primitive element like normal.
+ if (!this->emitDupPtr(Init))
+ return false;
+ if (!this->visit(Init))
+ return false;
+ if (!this->emitInitElem(*T, ElementIndex, Init))
+ return false;
+ } else {
+ // Advance the pointer currently on the stack to the given
+ // dimension and narrow().
+ if (!this->emitDupPtr(Init))
+ return false;
+ if (!this->emitConstUint32(ElementIndex, Init))
+ return false;
+ if (!this->emitAddOffsetUint32(Init))
+ return false;
+ if (!this->emitNarrowPtr(Init))
+ return false;
+
+ if (!visitInitializer(Init))
+ return false;
+ }
+ if (!this->emitPopPtr(Init))
+ return false;
+
+ ++ElementIndex;
+ }
+ return true;
+ } else if (const auto *DIE = dyn_cast<CXXDefaultInitExpr>(Initializer)) {
+ return this->visitInitializer(DIE->getExpr());
+ } else if (const auto *AILE = dyn_cast<ArrayInitLoopExpr>(Initializer)) {
+ // TODO: This compiles to quite a lot of bytecode if the array is larger.
+ // Investigate compiling this to a loop, or at least try to use
+ // the AILE's Common expr.
+ const Expr *SubExpr = AILE->getSubExpr();
+ size_t Size = AILE->getArraySize().getZExtValue();
+ std::optional<PrimType> ElemT = classify(SubExpr->getType());
+
+ // So, every iteration, we execute an assignment here
+ // where the LHS is on the stack (the target array)
+ // and the RHS is our SubExpr.
+ for (size_t I = 0; I != Size; ++I) {
+ ArrayIndexScope<Emitter> IndexScope(this, I);
+
+ if (!this->emitDupPtr(SubExpr)) // LHS
+ return false;
+
+ if (ElemT) {
+ if (!this->visit(SubExpr))
+ return false;
+ if (!this->emitInitElem(*ElemT, I, Initializer))
+ return false;
+ } else {
+ // Narrow to our array element and recurse into visitInitializer()
+ if (!this->emitConstUint64(I, SubExpr))
+ return false;
+
+ if (!this->emitAddOffsetUint64(SubExpr))
+ return false;
+
+ if (!this->emitNarrowPtr(SubExpr))
+ return false;
+
+ if (!visitInitializer(SubExpr))
+ return false;
+ }
+
+ if (!this->emitPopPtr(Initializer))
+ return false;
+ }
+ return true;
+ } else if (const auto *IVIE = dyn_cast<ImplicitValueInitExpr>(Initializer)) {
+ const ArrayType *AT = IVIE->getType()->getAsArrayTypeUnsafe();
+ assert(AT);
+ const auto *CAT = cast<ConstantArrayType>(AT);
+ size_t NumElems = CAT->getSize().getZExtValue();
+
+ if (std::optional<PrimType> ElemT = classify(CAT->getElementType())) {
+ // TODO(perf): For int and bool types, we can probably just skip this
+ // since we memset our Block*s to 0 and so we have the desired value
+ // without this.
+ for (size_t I = 0; I != NumElems; ++I) {
+ if (!this->emitZero(*ElemT, Initializer))
+ return false;
+ if (!this->emitInitElem(*ElemT, I, Initializer))
+ return false;
+ }
+ } else {
+ assert(false && "default initializer for non-primitive type");
+ }
+
+ return true;
+ } else if (const auto *Ctor = dyn_cast<CXXConstructExpr>(Initializer)) {
+ const ConstantArrayType *CAT =
+ Ctx.getASTContext().getAsConstantArrayType(Ctor->getType());
+ assert(CAT);
+ size_t NumElems = CAT->getSize().getZExtValue();
+ const Function *Func = getFunction(Ctor->getConstructor());
+ if (!Func || !Func->isConstexpr())
+ return false;
+
+ // FIXME(perf): We're calling the constructor once per array element here,
+ // in the old intepreter we had a special-case for trivial constructors.
+ for (size_t I = 0; I != NumElems; ++I) {
+ if (!this->emitDupPtr(Initializer))
+ return false;
+ if (!this->emitConstUint64(I, Initializer))
+ return false;
+ if (!this->emitAddOffsetUint64(Initializer))
+ return false;
+ if (!this->emitNarrowPtr(Initializer))
+ return false;
+
+ // Constructor arguments.
+ for (const auto *Arg : Ctor->arguments()) {
+ if (!this->visit(Arg))
+ return false;
+ }
+
+ if (!this->emitCall(Func, Initializer))
+ return false;
+ }
+ return true;
+ }
+
+ assert(false && "Unknown expression for array initialization");
+ return false;
}
template <class Emitter>
-bool ByteCodeExprGen<Emitter>::getPtrVarDecl(const VarDecl *VD, const Expr *E) {
- // Generate a pointer to the local, loading refs.
- if (Optional<unsigned> Idx = getGlobalIdx(VD)) {
- if (VD->getType()->isReferenceType())
- return this->emitGetGlobalPtr(*Idx, E);
- else
- return this->emitGetPtrGlobal(*Idx, E);
+bool ByteCodeExprGen<Emitter>::visitRecordInitializer(const Expr *Initializer) {
+ Initializer = Initializer->IgnoreParenImpCasts();
+ assert(Initializer->getType()->isRecordType());
+
+ if (const auto CtorExpr = dyn_cast<CXXConstructExpr>(Initializer)) {
+ const Function *Func = getFunction(CtorExpr->getConstructor());
+
+ if (!Func || !Func->isConstexpr())
+ return false;
+
+ // The This pointer is already on the stack because this is an initializer,
+ // but we need to dup() so the call() below has its own copy.
+ if (!this->emitDupPtr(Initializer))
+ return false;
+
+ // Constructor arguments.
+ for (const auto *Arg : CtorExpr->arguments()) {
+ if (!this->visit(Arg))
+ return false;
+ }
+
+ return this->emitCall(Func, Initializer);
+ } else if (const auto *InitList = dyn_cast<InitListExpr>(Initializer)) {
+ const Record *R = getRecord(InitList->getType());
+
+ unsigned InitIndex = 0;
+ for (const Expr *Init : InitList->inits()) {
+ const Record::Field *FieldToInit = R->getField(InitIndex);
+
+ if (!this->emitDupPtr(Initializer))
+ return false;
+
+ if (std::optional<PrimType> T = classify(Init)) {
+ if (!this->visit(Init))
+ return false;
+
+ if (!this->emitInitField(*T, FieldToInit->Offset, Initializer))
+ return false;
+
+ if (!this->emitPopPtr(Initializer))
+ return false;
+ } else {
+ // Non-primitive case. Get a pointer to the field-to-initialize
+ // on the stack and recurse into visitInitializer().
+ if (!this->emitGetPtrField(FieldToInit->Offset, Init))
+ return false;
+
+ if (!this->visitInitializer(Init))
+ return false;
+
+ if (!this->emitPopPtr(Initializer))
+ return false;
+ }
+ ++InitIndex;
+ }
+
+ return true;
+ } else if (const CallExpr *CE = dyn_cast<CallExpr>(Initializer)) {
+ // RVO functions expect a pointer to initialize on the stack.
+ // Dup our existing pointer so it has its own copy to use.
+ if (!this->emitDupPtr(Initializer))
+ return false;
+
+ return this->VisitCallExpr(CE);
+ } else if (const auto *DIE = dyn_cast<CXXDefaultInitExpr>(Initializer)) {
+ return this->visitInitializer(DIE->getExpr());
}
- return this->bail(VD);
+
+ return false;
}
template <class Emitter>
-llvm::Optional<unsigned>
-ByteCodeExprGen<Emitter>::getGlobalIdx(const VarDecl *VD) {
- if (VD->isConstexpr()) {
- // Constexpr decl - it must have already been defined.
- return P.getGlobal(VD);
- }
- if (!VD->hasLocalStorage()) {
- // Not constexpr, but a global var - can have pointer taken.
- Program::DeclScope Scope(P, VD);
- return P.getOrCreateGlobal(VD);
- }
- return {};
+bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *Initializer) {
+ QualType InitializerType = Initializer->getType();
+
+ if (InitializerType->isArrayType())
+ return visitArrayInitializer(Initializer);
+
+ if (InitializerType->isRecordType())
+ return visitRecordInitializer(Initializer);
+
+ // Otherwise, visit the expression like normal.
+ return this->visit(Initializer);
}
template <class Emitter>
@@ -516,52 +1081,339 @@ Record *ByteCodeExprGen<Emitter>::getRecord(const RecordDecl *RD) {
}
template <class Emitter>
+const Function *ByteCodeExprGen<Emitter>::getFunction(const FunctionDecl *FD) {
+ assert(FD);
+ const Function *Func = P.getFunction(FD);
+ bool IsBeingCompiled = Func && !Func->isFullyCompiled();
+ bool WasNotDefined = Func && !Func->hasBody();
+
+ if (IsBeingCompiled)
+ return Func;
+
+ if (!Func || WasNotDefined) {
+ if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(Ctx, P).compileFunc(FD))
+ Func = *R;
+ else {
+ llvm::consumeError(R.takeError());
+ return nullptr;
+ }
+ }
+
+ return Func;
+}
+
+template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *Exp) {
ExprScope<Emitter> RootScope(this);
if (!visit(Exp))
return false;
- if (Optional<PrimType> T = classify(Exp))
+ if (std::optional<PrimType> T = classify(Exp))
return this->emitRet(*T, Exp);
else
return this->emitRetValue(Exp);
}
+/// Toplevel visitDecl().
+/// We get here from evaluateAsInitializer().
+/// We need to evaluate the initializer and return its value.
template <class Emitter>
bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
+ std::optional<PrimType> VarT = classify(VD->getType());
+
+ // Create and initialize the variable.
+ if (!this->visitVarDecl(VD))
+ return false;
+
+ // Get a pointer to the variable
+ if (shouldBeGloballyIndexed(VD)) {
+ auto GlobalIndex = P.getGlobal(VD);
+ assert(GlobalIndex); // visitVarDecl() didn't return false.
+ if (!this->emitGetPtrGlobal(*GlobalIndex, VD))
+ return false;
+ } else {
+ auto Local = Locals.find(VD);
+ assert(Local != Locals.end()); // Same here.
+ if (!this->emitGetPtrLocal(Local->second.Offset, VD))
+ return false;
+ }
+
+ // Return the value
+ if (VarT) {
+ if (!this->emitLoadPop(*VarT, VD))
+ return false;
+
+ return this->emitRet(*VarT, VD);
+ }
+
+ return this->emitRetValue(VD);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
const Expr *Init = VD->getInit();
+ std::optional<PrimType> VarT = classify(VD->getType());
+
+ if (shouldBeGloballyIndexed(VD)) {
+ std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(VD, Init);
+
+ if (!GlobalIndex)
+ return this->bail(VD);
+
+ assert(Init);
+ {
+ DeclScope<Emitter> LocalScope(this, VD);
- if (Optional<unsigned> I = P.createGlobal(VD)) {
- if (Optional<PrimType> T = classify(VD->getType())) {
- {
- // Primitive declarations - compute the value and set it.
- DeclScope<Emitter> LocalScope(this, VD);
- if (!visit(Init))
+ if (VarT) {
+ if (!this->visit(Init))
return false;
+ return this->emitInitGlobal(*VarT, *GlobalIndex, VD);
}
+ return this->visitGlobalInitializer(Init, *GlobalIndex);
+ }
+ } else {
+ VariableScope<Emitter> LocalScope(this);
+ if (VarT) {
+ unsigned Offset = this->allocateLocalPrimitive(
+ VD, *VarT, VD->getType().isConstQualified());
+ if (Init) {
+ // Compile the initializer in its own scope.
+ ExprScope<Emitter> Scope(this);
+ if (!this->visit(Init))
+ return false;
- // If the declaration is global, save the value for later use.
- if (!this->emitDup(*T, VD))
- return false;
- if (!this->emitInitGlobal(*T, *I, VD))
- return false;
- return this->emitRet(*T, VD);
+ return this->emitSetLocal(*VarT, Offset, VD);
+ }
} else {
- {
- // Composite declarations - allocate storage and initialize it.
- DeclScope<Emitter> LocalScope(this, VD);
- if (!visitGlobalInitializer(Init, *I))
+ if (std::optional<unsigned> Offset = this->allocateLocal(VD)) {
+ if (Init)
+ return this->visitLocalInitializer(Init, *Offset);
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
+ assert(!E->getBuiltinCallee() && "Builtin functions aren't supported yet");
+
+ const Decl *Callee = E->getCalleeDecl();
+ if (const auto *FuncDecl = dyn_cast_or_null<FunctionDecl>(Callee)) {
+ const Function *Func = getFunction(FuncDecl);
+ if (!Func)
+ return false;
+ // If the function is being compiled right now, this is a recursive call.
+ // In that case, the function can't be valid yet, even though it will be
+ // later.
+ // If the function is already fully compiled but not constexpr, it was
+ // found to be faulty earlier on, so bail out.
+ if (Func->isFullyCompiled() && !Func->isConstexpr())
+ return false;
+
+ QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
+ std::optional<PrimType> T = classify(ReturnType);
+
+ if (Func->hasRVO() && DiscardResult) {
+ // 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 (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}
+ }
- // Return a pointer to the global.
- if (!this->emitGetPtrGlobal(*I, VD))
+ // Put arguments on the stack.
+ for (const auto *Arg : E->arguments()) {
+ if (!this->visit(Arg))
return false;
- return this->emitRetValue(VD);
}
+
+ // In any case call the function. The return value will end up on the stack and
+ // if the function has RVO, we already have the pointer on the stack to write
+ // the result into.
+ if (!this->emitCall(Func, E))
+ return false;
+
+ if (DiscardResult && !ReturnType->isVoidType() && T)
+ return this->emitPop(*T, E);
+
+ return true;
+ } else {
+ assert(false && "We don't support non-FunctionDecl callees right now.");
}
- return this->bail(VD);
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXMemberCallExpr(
+ const CXXMemberCallExpr *E) {
+ // Get a This pointer on the stack.
+ if (!this->visit(E->getImplicitObjectArgument()))
+ return false;
+
+ return VisitCallExpr(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXDefaultInitExpr(
+ const CXXDefaultInitExpr *E) {
+ return this->visit(E->getExpr());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXDefaultArgExpr(
+ const CXXDefaultArgExpr *E) {
+ return this->visit(E->getExpr());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXBoolLiteralExpr(
+ const CXXBoolLiteralExpr *E) {
+ if (DiscardResult)
+ return true;
+
+ return this->emitConstBool(E->getValue(), E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXNullPtrLiteralExpr(
+ const CXXNullPtrLiteralExpr *E) {
+ if (DiscardResult)
+ return true;
+
+ return this->emitNullPtr(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) {
+ if (DiscardResult)
+ return true;
+ return this->emitThis(E);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
+ const Expr *SubExpr = E->getSubExpr();
+ std::optional<PrimType> T = classify(SubExpr->getType());
+
+ // TODO: Support pointers for inc/dec operators.
+ switch (E->getOpcode()) {
+ case UO_PostInc: { // x++
+ if (!this->visit(SubExpr))
+ return false;
+
+ return DiscardResult ? this->emitIncPop(*T, E) : this->emitInc(*T, E);
+ }
+ case UO_PostDec: { // x--
+ if (!this->visit(SubExpr))
+ return false;
+
+ return DiscardResult ? this->emitDecPop(*T, E) : this->emitDec(*T, E);
+ }
+ case UO_PreInc: { // ++x
+ if (!this->visit(SubExpr))
+ return false;
+
+ // Post-inc and pre-inc are the same if the value is to be discarded.
+ if (DiscardResult)
+ return this->emitIncPop(*T, E);
+
+ this->emitLoad(*T, E);
+ this->emitConst(1, E);
+ this->emitAdd(*T, E);
+ return this->emitStore(*T, E);
+ }
+ case UO_PreDec: { // --x
+ if (!this->visit(SubExpr))
+ return false;
+
+ // Post-dec and pre-dec are the same if the value is to be discarded.
+ if (DiscardResult)
+ return this->emitDecPop(*T, E);
+
+ this->emitLoad(*T, E);
+ this->emitConst(1, E);
+ this->emitSub(*T, E);
+ return this->emitStore(*T, E);
+ }
+ case UO_LNot: // !x
+ if (!this->visit(SubExpr))
+ return false;
+ // The Inv doesn't change anything, so skip it if we don't need the result.
+ return DiscardResult ? this->emitPop(*T, E) : this->emitInvBool(E);
+ case UO_Minus: // -x
+ if (!this->visit(SubExpr))
+ return false;
+ return DiscardResult ? this->emitPop(*T, E) : this->emitNeg(*T, E);
+ case UO_Plus: // +x
+ if (!this->visit(SubExpr)) // noop
+ return false;
+ return DiscardResult ? this->emitPop(*T, E) : true;
+ case UO_AddrOf: // &x
+ // We should already have a pointer when we get here.
+ if (!this->visit(SubExpr))
+ return false;
+ return DiscardResult ? this->emitPop(*T, E) : true;
+ case UO_Deref: // *x
+ return dereference(
+ SubExpr, DerefKind::Read,
+ [](PrimType) {
+ llvm_unreachable("Dereferencing requires a pointer");
+ return false;
+ },
+ [this, E](PrimType T) {
+ return DiscardResult ? this->emitPop(T, E) : true;
+ });
+ case UO_Not: // ~x
+ if (!this->visit(SubExpr))
+ return false;
+ return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E);
+ case UO_Real: // __real x
+ case UO_Imag: // __imag x
+ case UO_Extension:
+ case UO_Coawait:
+ assert(false && "Unhandled opcode");
+ }
+
+ return false;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
+ const auto *Decl = E->getDecl();
+ // References are implemented via pointers, so when we see a DeclRefExpr
+ // pointing to a reference, we need to get its value directly (i.e. the
+ // pointer to the actual value) instead of a pointer to the pointer to the
+ // value.
+ bool IsReference = Decl->getType()->isReferenceType();
+
+ if (auto It = Locals.find(Decl); It != Locals.end()) {
+ const unsigned Offset = It->second.Offset;
+
+ if (IsReference)
+ return this->emitGetLocal(PT_Ptr, Offset, E);
+ return this->emitGetPtrLocal(Offset, E);
+ } else if (auto GlobalIndex = P.getGlobal(Decl)) {
+ if (IsReference)
+ return this->emitGetGlobal(PT_Ptr, *GlobalIndex, E);
+
+ return this->emitGetPtrGlobal(*GlobalIndex, E);
+ } else if (const auto *PVD = dyn_cast<ParmVarDecl>(Decl)) {
+ if (auto It = this->Params.find(PVD); It != this->Params.end()) {
+ if (IsReference)
+ return this->emitGetParam(PT_Ptr, It->second, E);
+ return this->emitGetPtrParam(It->second, E);
+ }
+ } else if (const auto *ECD = dyn_cast<EnumConstantDecl>(Decl)) {
+ return this->emitConst(ECD->getInitVal(), E);
+ }
+
+ return false;
}
template <class Emitter>
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 82aa413dabbc..c7fcc59e5a60 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -22,7 +22,6 @@
#include "clang/AST/Expr.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
-#include "llvm/ADT/Optional.h"
namespace clang {
class QualType;
@@ -34,25 +33,17 @@ template <class Emitter> class RecordScope;
template <class Emitter> class VariableScope;
template <class Emitter> class DeclScope;
template <class Emitter> class OptionScope;
+template <class Emitter> class ArrayIndexScope;
/// Compilation context for expressions.
template <class Emitter>
class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
public Emitter {
protected:
- // Emitters for opcodes of various arities.
- using NullaryFn = bool (ByteCodeExprGen::*)(const SourceInfo &);
- using UnaryFn = bool (ByteCodeExprGen::*)(PrimType, const SourceInfo &);
- using BinaryFn = bool (ByteCodeExprGen::*)(PrimType, PrimType,
- const SourceInfo &);
-
// Aliases for types defined in the emitter.
using LabelTy = typename Emitter::LabelTy;
using AddrTy = typename Emitter::AddrTy;
- // Reference to a function generating the pointer of an initialized object.s
- using InitFnRef = std::function<bool()>;
-
/// Current compilation context.
Context &Ctx;
/// Program to link to.
@@ -64,11 +55,34 @@ public:
ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
: Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
- // Expression visitors - result returned on stack.
+ // Expression visitors - result returned on interp stack.
bool VisitCastExpr(const CastExpr *E);
bool VisitIntegerLiteral(const IntegerLiteral *E);
bool VisitParenExpr(const ParenExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitPointerArithBinOp(const BinaryOperator *E);
+ bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
+ bool VisitCallExpr(const CallExpr *E);
+ bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *E);
+ bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
+ bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
+ bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
+ bool VisitCXXThisExpr(const CXXThisExpr *E);
+ bool VisitUnaryOperator(const UnaryOperator *E);
+ bool VisitDeclRefExpr(const DeclRefExpr *E);
+ bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
+ bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
+ bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
+ bool VisitInitListExpr(const InitListExpr *E);
+ bool VisitConstantExpr(const ConstantExpr *E);
+ bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
+ bool VisitMemberExpr(const MemberExpr *E);
+ bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
+ bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
+ bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
+ bool VisitStringLiteral(const StringLiteral *E);
+ bool VisitCharacterLiteral(const CharacterLiteral *E);
+ bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);
protected:
bool visitExpr(const Expr *E) override;
@@ -85,31 +99,18 @@ protected:
Record *getRecord(QualType Ty);
Record *getRecord(const RecordDecl *RD);
- /// Returns the size int bits of an integer.
- unsigned getIntWidth(QualType Ty) {
- auto &ASTContext = Ctx.getASTContext();
- return ASTContext.getIntWidth(Ty);
- }
-
- /// Returns the value of CHAR_BIT.
- unsigned getCharBit() const {
- auto &ASTContext = Ctx.getASTContext();
- return ASTContext.getTargetInfo().getCharWidth();
- }
+ // Returns a function for the given FunctionDecl.
+ // If the function does not exist yet, it is compiled.
+ const Function *getFunction(const FunctionDecl *FD);
/// Classifies a type.
- llvm::Optional<PrimType> classify(const Expr *E) const {
+ std::optional<PrimType> classify(const Expr *E) const {
return E->isGLValue() ? PT_Ptr : classify(E->getType());
}
- llvm::Optional<PrimType> classify(QualType Ty) const {
+ std::optional<PrimType> classify(QualType Ty) const {
return Ctx.classify(Ty);
}
- /// Checks if a pointer needs adjustment.
- bool needsAdjust(QualType Ty) const {
- return true;
- }
-
/// Classifies a known primitive type
PrimType classifyPrim(QualType Ty) const {
if (auto T = classify(Ty)) {
@@ -122,29 +123,49 @@ protected:
bool discard(const Expr *E);
/// Evaluates an expression and places result on stack.
bool visit(const Expr *E);
- /// Compiles an initializer for a local.
- bool visitInitializer(const Expr *E, InitFnRef GenPtr);
+ /// Compiles an initializer.
+ bool visitInitializer(const Expr *E);
+ /// Compiles an array initializer.
+ bool visitArrayInitializer(const Expr *Initializer);
+ /// Compiles a record initializer.
+ bool visitRecordInitializer(const Expr *Initializer);
+ /// Creates and initializes a variable from the given decl.
+ bool visitVarDecl(const VarDecl *VD);
/// Visits an expression and converts it to a boolean.
bool visitBool(const Expr *E);
/// Visits an initializer for a local.
bool visitLocalInitializer(const Expr *Init, unsigned I) {
- return visitInitializer(Init, [this, I, Init] {
- return this->emitGetPtrLocal(I, Init);
- });
+ if (!this->emitGetPtrLocal(I, Init))
+ return false;
+
+ if (!visitInitializer(Init))
+ return false;
+
+ return this->emitPopPtr(Init);
}
/// Visits an initializer for a global.
bool visitGlobalInitializer(const Expr *Init, unsigned I) {
- return visitInitializer(Init, [this, I, Init] {
- return this->emitGetPtrGlobal(I, Init);
- });
+ if (!this->emitGetPtrGlobal(I, Init))
+ return false;
+
+ if (!visitInitializer(Init))
+ return false;
+
+ return this->emitPopPtr(Init);
}
/// Visits a delegated initializer.
bool visitThisInitializer(const Expr *I) {
- return visitInitializer(I, [this, I] { return this->emitThis(I); });
+ if (!this->emitThis(I))
+ return false;
+
+ if (!visitInitializer(I))
+ return false;
+
+ return this->emitPopPtr(I);
}
/// Creates a local primitive value.
@@ -152,8 +173,7 @@ protected:
bool IsExtended = false);
/// Allocates a space storing a local given its type.
- llvm::Optional<unsigned> allocateLocal(DeclTy &&Decl,
- bool IsExtended = false);
+ std::optional<unsigned> allocateLocal(DeclTy &&Decl, bool IsExtended = false);
private:
friend class VariableScope<Emitter>;
@@ -161,6 +181,7 @@ private:
friend class RecordScope<Emitter>;
friend class DeclScope<Emitter>;
friend class OptionScope<Emitter>;
+ friend class ArrayIndexScope<Emitter>;
/// Emits a zero initializer.
bool visitZeroInitializer(PrimType T, const Expr *E);
@@ -188,28 +209,28 @@ private:
DerefKind AK, llvm::function_ref<bool(PrimType)> Direct,
llvm::function_ref<bool(PrimType)> Indirect);
- /// Emits an APInt constant.
- bool emitConst(PrimType T, unsigned NumBits, const llvm::APInt &Value,
- const Expr *E);
+ /// Emits an APSInt constant.
+ bool emitConst(const APSInt &Value, const Expr *E);
+ bool emitConst(const APInt &Value, const Expr *E) {
+ return emitConst(static_cast<APSInt>(Value), E);
+ }
/// Emits an integer constant.
- template <typename T> bool emitConst(const Expr *E, T Value) {
- QualType Ty = E->getType();
- unsigned NumBits = getIntWidth(Ty);
- APInt WrappedValue(NumBits, Value, std::is_signed<T>::value);
- return emitConst(*Ctx.classify(Ty), NumBits, WrappedValue, E);
+ template <typename T> bool emitConst(T Value, const Expr *E);
+
+ /// Returns the CXXRecordDecl for the type of the given expression,
+ /// or nullptr if no such decl exists.
+ const CXXRecordDecl *getRecordDecl(const Expr *E) const {
+ QualType T = E->getType();
+ if (const auto *RD = T->getPointeeCXXRecordDecl())
+ return RD;
+ return T->getAsCXXRecordDecl();
}
- /// Returns a pointer to a variable declaration.
- bool getPtrVarDecl(const VarDecl *VD, const Expr *E);
-
- /// Returns the index of a global.
- llvm::Optional<unsigned> getGlobalIdx(const VarDecl *VD);
-
- /// Emits the initialized pointer.
- bool emitInitFn() {
- assert(InitFn && "missing initializer");
- return (*InitFn)();
+ /// Returns whether we should create a global variable for the
+ /// given VarDecl.
+ bool shouldBeGloballyIndexed(const VarDecl *VD) const {
+ return VD->hasGlobalStorage() || VD->isConstexpr();
}
protected:
@@ -222,14 +243,11 @@ protected:
/// Current scope.
VariableScope<Emitter> *VarScope = nullptr;
- /// Current argument index.
- llvm::Optional<uint64_t> ArrayIndex;
+ /// Current argument index. Needed to emit ArrayInitIndexExpr.
+ std::optional<uint64_t> ArrayIndex;
/// Flag indicating if return value is to be discarded.
bool DiscardResult = false;
-
- /// Expression being initialized.
- llvm::Optional<InitFnRef> InitFn = {};
};
extern template class ByteCodeExprGen<ByteCodeEmitter>;
@@ -238,6 +256,11 @@ extern template class ByteCodeExprGen<EvalEmitter>;
/// Scope chain managing the variable lifetimes.
template <class Emitter> class VariableScope {
public:
+ VariableScope(ByteCodeExprGen<Emitter> *Ctx)
+ : Ctx(Ctx), Parent(Ctx->VarScope) {
+ Ctx->VarScope = this;
+ }
+
virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
void add(const Scope::Local &Local, bool IsExtended) {
@@ -262,11 +285,6 @@ public:
VariableScope *getParent() { return Parent; }
protected:
- VariableScope(ByteCodeExprGen<Emitter> *Ctx)
- : Ctx(Ctx), Parent(Ctx->VarScope) {
- Ctx->VarScope = this;
- }
-
/// ByteCodeExprGen instance.
ByteCodeExprGen<Emitter> *Ctx;
/// Link to the parent scope.
@@ -300,7 +318,7 @@ public:
protected:
/// Index of the scope in the chain.
- Optional<unsigned> Idx;
+ std::optional<unsigned> Idx;
};
/// Scope for storage declared in a compound statement.
@@ -320,10 +338,25 @@ public:
ExprScope(ByteCodeExprGen<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
void addExtended(const Scope::Local &Local) override {
+ assert(this->Parent);
this->Parent->addLocal(Local);
}
};
+template <class Emitter> class ArrayIndexScope final {
+public:
+ ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
+ OldArrayIndex = Ctx->ArrayIndex;
+ Ctx->ArrayIndex = Index;
+ }
+
+ ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
+
+private:
+ ByteCodeExprGen<Emitter> *Ctx;
+ std::optional<uint64_t> OldArrayIndex;
+};
+
} // namespace interp
} // namespace clang
diff --git a/clang/lib/AST/Interp/ByteCodeGenError.h b/clang/lib/AST/Interp/ByteCodeGenError.h
index a4fa4917705d..af464b5ed4ab 100644
--- a/clang/lib/AST/Interp/ByteCodeGenError.h
+++ b/clang/lib/AST/Interp/ByteCodeGenError.h
@@ -20,19 +20,19 @@ namespace interp {
/// Error thrown by the compiler.
struct ByteCodeGenError : public llvm::ErrorInfo<ByteCodeGenError> {
public:
- ByteCodeGenError(SourceLocation Loc) : Loc(Loc) {}
- ByteCodeGenError(const Stmt *S) : ByteCodeGenError(S->getBeginLoc()) {}
- ByteCodeGenError(const Decl *D) : ByteCodeGenError(D->getBeginLoc()) {}
+ ByteCodeGenError(SourceRange Range) : Range(Range) {}
+ ByteCodeGenError(const Stmt *S) : ByteCodeGenError(S->getSourceRange()) {}
+ ByteCodeGenError(const Decl *D) : ByteCodeGenError(D->getSourceRange()) {}
void log(raw_ostream &OS) const override { OS << "unimplemented feature"; }
- const SourceLocation &getLoc() const { return Loc; }
+ const SourceRange &getRange() const { return Range; }
static char ID;
private:
- // Start of the item where the error occurred.
- SourceLocation Loc;
+ // Range of the item where the error occurred.
+ SourceRange Range;
// Users are not expected to use error_code.
std::error_code convertToErrorCode() const override {
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index 90e84149b055..af97c57c98b7 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -94,11 +94,63 @@ bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
// Classify the return type.
ReturnType = this->classify(F->getReturnType());
- // Set up fields and context if a constructor.
- if (auto *MD = dyn_cast<CXXMethodDecl>(F))
- return this->bail(MD);
+ // Constructor. Set up field initializers.
+ if (const auto Ctor = dyn_cast<CXXConstructorDecl>(F)) {
+ const RecordDecl *RD = Ctor->getParent();
+ const Record *R = this->getRecord(RD);
+ if (!R)
+ return false;
+
+ for (const auto *Init : Ctor->inits()) {
+ const Expr *InitExpr = Init->getInit();
+ if (const FieldDecl *Member = Init->getMember()) {
+ const Record::Field *F = R->getField(Member);
+
+ if (std::optional<PrimType> T = this->classify(InitExpr)) {
+ if (!this->emitThis(InitExpr))
+ return false;
+
+ if (!this->visit(InitExpr))
+ return false;
+
+ if (!this->emitInitField(*T, F->Offset, InitExpr))
+ return false;
+
+ if (!this->emitPopPtr(InitExpr))
+ return false;
+ } else {
+ // Non-primitive case. Get a pointer to the field-to-initialize
+ // on the stack and call visitInitialzer() for it.
+ if (!this->emitThis(InitExpr))
+ return false;
+
+ if (!this->emitGetPtrField(F->Offset, InitExpr))
+ return false;
+
+ if (!this->visitInitializer(InitExpr))
+ return false;
+
+ if (!this->emitPopPtr(InitExpr))
+ return false;
+ }
+ } else if (const Type *Base = Init->getBaseClass()) {
+ // Base class initializer.
+ // Get This Base and call initializer on it.
+ auto *BaseDecl = Base->getAsCXXRecordDecl();
+ assert(BaseDecl);
+ const Record::Base *B = R->getBase(BaseDecl);
+ assert(B);
+ if (!this->emitGetPtrThisBase(B->Offset, InitExpr))
+ return false;
+ if (!this->visitInitializer(InitExpr))
+ return false;
+ if (!this->emitPopPtr(InitExpr))
+ return false;
+ }
+ }
+ }
- if (auto *Body = F->getBody())
+ if (const auto *Body = F->getBody())
if (!visitStmt(Body))
return false;
@@ -120,6 +172,16 @@ bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
return visitReturnStmt(cast<ReturnStmt>(S));
case Stmt::IfStmtClass:
return visitIfStmt(cast<IfStmt>(S));
+ case Stmt::WhileStmtClass:
+ return visitWhileStmt(cast<WhileStmt>(S));
+ case Stmt::DoStmtClass:
+ return visitDoStmt(cast<DoStmt>(S));
+ case Stmt::ForStmtClass:
+ return visitForStmt(cast<ForStmt>(S));
+ case Stmt::BreakStmtClass:
+ return visitBreakStmt(cast<BreakStmt>(S));
+ case Stmt::ContinueStmtClass:
+ return visitContinueStmt(cast<ContinueStmt>(S));
case Stmt::NullStmtClass:
return true;
default: {
@@ -145,7 +207,7 @@ bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
for (auto *D : DS->decls()) {
// Variable declarator.
if (auto *VD = dyn_cast<VarDecl>(D)) {
- if (!visitVarDecl(VD))
+ if (!this->visitVarDecl(VD))
return false;
continue;
}
@@ -171,18 +233,21 @@ bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
return this->emitRet(*ReturnType, RS);
} else {
// RVO - construct the value in the return location.
- auto ReturnLocation = [this, RE] { return this->emitGetParamPtr(0, RE); };
- if (!this->visitInitializer(RE, ReturnLocation))
+ if (!this->emitRVOPtr(RE))
return false;
+ if (!this->visitInitializer(RE))
+ return false;
+ if (!this->emitPopPtr(RE))
+ return false;
+
this->emitCleanup();
return this->emitRetVoid(RS);
}
- } else {
- this->emitCleanup();
- if (!this->emitRetVoid(RS))
- return false;
- return true;
}
+
+ // Void return.
+ this->emitCleanup();
+ return this->emitRetVoid(RS);
}
template <class Emitter>
@@ -231,33 +296,99 @@ bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
}
template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitVarDecl(const VarDecl *VD) {
- auto DT = VD->getType();
+bool ByteCodeStmtGen<Emitter>::visitWhileStmt(const WhileStmt *S) {
+ const Expr *Cond = S->getCond();
+ const Stmt *Body = S->getBody();
- if (!VD->hasLocalStorage()) {
- // No code generation required.
- return true;
- }
+ LabelTy CondLabel = this->getLabel(); // Label before the condition.
+ LabelTy EndLabel = this->getLabel(); // Label after the loop.
+ LoopScope<Emitter> LS(this, EndLabel, CondLabel);
- // Integers, pointers, primitives.
- if (Optional<PrimType> T = this->classify(DT)) {
- auto Off = this->allocateLocalPrimitive(VD, *T, DT.isConstQualified());
- // Compile the initialiser in its own scope.
- {
- ExprScope<Emitter> Scope(this);
- if (!this->visit(VD->getInit()))
- return false;
- }
- // Set the value.
- return this->emitSetLocal(*T, Off, VD);
- } else {
- // Composite types - allocate storage and initialize it.
- if (auto Off = this->allocateLocal(VD)) {
- return this->visitLocalInitializer(VD->getInit(), *Off);
- } else {
- return this->bail(VD);
- }
+ this->emitLabel(CondLabel);
+ if (!this->visitBool(Cond))
+ return false;
+ if (!this->jumpFalse(EndLabel))
+ return false;
+
+ if (!this->visitStmt(Body))
+ return false;
+ if (!this->jump(CondLabel))
+ return false;
+
+ this->emitLabel(EndLabel);
+
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitDoStmt(const DoStmt *S) {
+ const Expr *Cond = S->getCond();
+ const Stmt *Body = S->getBody();
+
+ LabelTy StartLabel = this->getLabel();
+ LabelTy EndLabel = this->getLabel();
+ LabelTy CondLabel = this->getLabel();
+ LoopScope<Emitter> LS(this, EndLabel, CondLabel);
+
+ this->emitLabel(StartLabel);
+ if (!this->visitStmt(Body))
+ return false;
+ this->emitLabel(CondLabel);
+ if (!this->visitBool(Cond))
+ return false;
+ if (!this->jumpTrue(StartLabel))
+ return false;
+ this->emitLabel(EndLabel);
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitForStmt(const ForStmt *S) {
+ // for (Init; Cond; Inc) { Body }
+ const Stmt *Init = S->getInit();
+ const Expr *Cond = S->getCond();
+ const Expr *Inc = S->getInc();
+ const Stmt *Body = S->getBody();
+
+ LabelTy EndLabel = this->getLabel();
+ LabelTy CondLabel = this->getLabel();
+ LabelTy IncLabel = this->getLabel();
+ LoopScope<Emitter> LS(this, EndLabel, IncLabel);
+
+ if (Init && !this->visitStmt(Init))
+ return false;
+ this->emitLabel(CondLabel);
+ if (Cond) {
+ if (!this->visitBool(Cond))
+ return false;
+ if (!this->jumpFalse(EndLabel))
+ return false;
}
+ if (Body && !this->visitStmt(Body))
+ return false;
+ this->emitLabel(IncLabel);
+ if (Inc && !this->discard(Inc))
+ return false;
+ if (!this->jump(CondLabel))
+ return false;
+ this->emitLabel(EndLabel);
+ return true;
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitBreakStmt(const BreakStmt *S) {
+ if (!BreakLabel)
+ return false;
+
+ return this->jump(*BreakLabel);
+}
+
+template <class Emitter>
+bool ByteCodeStmtGen<Emitter>::visitContinueStmt(const ContinueStmt *S) {
+ if (!ContinueLabel)
+ return false;
+
+ return this->jump(*ContinueLabel);
}
namespace clang {
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h
index 3bc665b84b4d..829e199f827c 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.h
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.h
@@ -22,7 +22,6 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/StmtVisitor.h"
-#include "llvm/ADT/Optional.h"
namespace clang {
namespace interp {
@@ -33,10 +32,10 @@ template <class Emitter> class LabelScope;
/// Compilation context for statements.
template <class Emitter>
-class ByteCodeStmtGen : public ByteCodeExprGen<Emitter> {
+class ByteCodeStmtGen final : public ByteCodeExprGen<Emitter> {
using LabelTy = typename Emitter::LabelTy;
using AddrTy = typename Emitter::AddrTy;
- using OptLabelTy = llvm::Optional<LabelTy>;
+ using OptLabelTy = std::optional<LabelTy>;
using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;
public:
@@ -58,13 +57,14 @@ private:
bool visitDeclStmt(const DeclStmt *DS);
bool visitReturnStmt(const ReturnStmt *RS);
bool visitIfStmt(const IfStmt *IS);
+ bool visitWhileStmt(const WhileStmt *S);
+ bool visitDoStmt(const DoStmt *S);
+ bool visitForStmt(const ForStmt *S);
+ bool visitBreakStmt(const BreakStmt *S);
+ bool visitContinueStmt(const ContinueStmt *S);
- /// Compiles a variable declaration.
- bool visitVarDecl(const VarDecl *VD);
-
-private:
/// Type of the expression returned by the function.
- llvm::Optional<PrimType> ReturnType;
+ std::optional<PrimType> ReturnType;
/// Switch case mapping.
CaseMap CaseLabels;
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 3bfcdfcd4c58..16471242f328 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -27,39 +27,52 @@ Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {}
Context::~Context() {}
bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
+ assert(Stk.empty());
Function *Func = P->getFunction(FD);
- if (!Func) {
+ if (!Func || !Func->hasBody()) {
if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) {
Func = *R;
} else {
handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) {
- Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
+ Parent.FFDiag(Err.getRange().getBegin(),
+ diag::err_experimental_clang_interp_failed)
+ << Err.getRange();
});
return false;
}
}
- if (!Func->isConstexpr())
- return false;
-
- APValue Dummy;
- return Run(Parent, Func, Dummy);
+ return Func->isConstexpr();
}
bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
+ assert(Stk.empty());
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
- return Check(Parent, C.interpretExpr(E));
+ if (Check(Parent, C.interpretExpr(E))) {
+ assert(Stk.empty());
+ return true;
+ }
+
+ Stk.clear();
+ return false;
}
bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
APValue &Result) {
+ assert(Stk.empty());
ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result);
- return Check(Parent, C.interpretDecl(VD));
+ if (Check(Parent, C.interpretDecl(VD))) {
+ assert(Stk.empty());
+ return true;
+ }
+
+ Stk.clear();
+ return false;
}
const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
-llvm::Optional<PrimType> Context::classify(QualType T) {
+std::optional<PrimType> Context::classify(QualType T) const {
if (T->isReferenceType() || T->isPointerType()) {
return PT_Ptr;
}
@@ -112,7 +125,7 @@ unsigned Context::getCharBit() const {
bool Context::Run(State &Parent, Function *Func, APValue &Result) {
InterpState State(Parent, *P, Stk, *this);
- State.Current = new InterpFrame(State, Func, nullptr, {}, {});
+ State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, {});
if (Interpret(State, Result))
return true;
Stk.clear();
@@ -123,7 +136,9 @@ bool Context::Check(State &Parent, llvm::Expected<bool> &&Flag) {
if (Flag)
return *Flag;
handleAllErrors(Flag.takeError(), [&Parent](ByteCodeGenError &Err) {
- Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed);
+ Parent.FFDiag(Err.getRange().getBegin(),
+ diag::err_experimental_clang_interp_failed)
+ << Err.getRange();
});
return false;
}
diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h
index 0627d9fb14f5..e49422e64b87 100644
--- a/clang/lib/AST/Interp/Context.h
+++ b/clang/lib/AST/Interp/Context.h
@@ -18,7 +18,6 @@
#include "InterpStack.h"
#include "clang/AST/APValue.h"
-#include "llvm/ADT/PointerIntPair.h"
namespace clang {
class ASTContext;
@@ -33,7 +32,7 @@ class State;
enum PrimType : unsigned;
/// Holds all information required to evaluate constexpr code in a module.
-class Context {
+class Context final {
public:
/// Initialises the constexpr VM.
Context(ASTContext &Ctx);
@@ -60,7 +59,7 @@ public:
unsigned getCharBit() const;
/// Classifies an expression.
- llvm::Optional<PrimType> classify(QualType T);
+ std::optional<PrimType> classify(QualType T) const;
private:
/// Runs a function.
@@ -69,7 +68,6 @@ private:
/// Checks a result from the interpreter.
bool Check(State &Parent, llvm::Expected<bool> &&R);
-private:
/// Current compilation context.
ASTContext &Ctx;
/// Interpreter stack, shared across invocations.
diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp
index 5c1a8a9cf306..04bc8681dd6e 100644
--- a/clang/lib/AST/Interp/Descriptor.cpp
+++ b/clang/lib/AST/Interp/Descriptor.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "Descriptor.h"
+#include "Boolean.h"
#include "Pointer.h"
#include "PrimType.h"
#include "Record.h"
@@ -39,6 +40,11 @@ static void ctorArrayTy(Block *, char *Ptr, bool, bool, bool, Descriptor *D) {
template <typename T>
static void dtorArrayTy(Block *, char *Ptr, Descriptor *D) {
+ InitMap *IM = *reinterpret_cast<InitMap **>(Ptr);
+ if (IM != (InitMap *)-1)
+ free(IM);
+
+ Ptr += sizeof(InitMap *);
for (unsigned I = 0, NE = D->getNumElems(); I < NE; ++I) {
reinterpret_cast<T *>(Ptr)[I].~T();
}
@@ -72,9 +78,10 @@ static void ctorArrayDesc(Block *B, char *Ptr, bool IsConst, bool IsMutable,
Desc->IsBase = false;
Desc->IsActive = IsActive;
Desc->IsConst = IsConst || D->IsConst;
- Desc->IsMutable = IsMutable || D->IsMutable;
+ Desc->IsFieldMutable = IsMutable || D->IsMutable;
if (auto Fn = D->ElemDesc->CtorFn)
- Fn(B, ElemLoc, Desc->IsConst, Desc->IsMutable, IsActive, D->ElemDesc);
+ Fn(B, ElemLoc, Desc->IsConst, Desc->IsFieldMutable, IsActive,
+ D->ElemDesc);
}
}
@@ -121,13 +128,14 @@ static void ctorRecord(Block *B, char *Ptr, bool IsConst, bool IsMutable,
auto *Desc = reinterpret_cast<InlineDescriptor *>(Ptr + SubOff) - 1;
Desc->Offset = SubOff;
Desc->Desc = F;
- Desc->IsInitialized = (B->isStatic() || F->IsArray) && !IsBase;
+ Desc->IsInitialized = F->IsArray && !IsBase;
Desc->IsBase = IsBase;
Desc->IsActive = IsActive && !IsUnion;
Desc->IsConst = IsConst || F->IsConst;
- Desc->IsMutable = IsMutable || F->IsMutable;
+ Desc->IsFieldMutable = IsMutable || F->IsMutable;
if (auto Fn = F->CtorFn)
- Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsMutable, Desc->IsActive, F);
+ Fn(B, Ptr + SubOff, Desc->IsConst, Desc->IsFieldMutable, Desc->IsActive,
+ F);
};
for (const auto &B : D->ElemRecord->bases())
CtorSub(B.Offset, B.Desc, /*isBase=*/true);
@@ -178,26 +186,30 @@ static BlockCtorFn getCtorArrayPrim(PrimType Type) {
}
static BlockDtorFn getDtorArrayPrim(PrimType Type) {
- COMPOSITE_TYPE_SWITCH(Type, return dtorArrayTy<T>, return nullptr);
+ TYPE_SWITCH(Type, return dtorArrayTy<T>);
+ llvm_unreachable("unknown Expr");
}
static BlockMoveFn getMoveArrayPrim(PrimType Type) {
COMPOSITE_TYPE_SWITCH(Type, return moveArrayTy<T>, return nullptr);
}
-Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsConst,
- bool IsTemporary, bool IsMutable)
- : Source(D), ElemSize(primSize(Type)), Size(ElemSize), AllocSize(Size),
- IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
- CtorFn(getCtorPrim(Type)), DtorFn(getDtorPrim(Type)),
- MoveFn(getMovePrim(Type)) {
+Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
+ bool IsConst, bool IsTemporary, bool IsMutable)
+ : Source(D), ElemSize(primSize(Type)), Size(ElemSize),
+ MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), IsConst(IsConst),
+ IsMutable(IsMutable), IsTemporary(IsTemporary), CtorFn(getCtorPrim(Type)),
+ DtorFn(getDtorPrim(Type)), MoveFn(getMovePrim(Type)) {
+ assert(AllocSize >= Size);
assert(Source && "Missing source");
}
-Descriptor::Descriptor(const DeclTy &D, PrimType Type, size_t NumElems,
- bool IsConst, bool IsTemporary, bool IsMutable)
+Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
+ size_t NumElems, bool IsConst, bool IsTemporary,
+ bool IsMutable)
: Source(D), ElemSize(primSize(Type)), Size(ElemSize * NumElems),
- AllocSize(align(Size) + sizeof(InitMap *)), IsConst(IsConst),
+ MDSize(MD.value_or(0)),
+ AllocSize(align(Size) + sizeof(InitMap *) + MDSize), IsConst(IsConst),
IsMutable(IsMutable), IsTemporary(IsTemporary), IsArray(true),
CtorFn(getCtorArrayPrim(Type)), DtorFn(getDtorArrayPrim(Type)),
MoveFn(getMoveArrayPrim(Type)) {
@@ -206,39 +218,42 @@ Descriptor::Descriptor(const DeclTy &D, PrimType Type, size_t NumElems,
Descriptor::Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary,
UnknownSize)
- : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark),
+ : Source(D), ElemSize(primSize(Type)), Size(UnknownSizeMark), MDSize(0),
AllocSize(alignof(void *)), IsConst(true), IsMutable(false),
IsTemporary(IsTemporary), IsArray(true), CtorFn(getCtorArrayPrim(Type)),
DtorFn(getDtorArrayPrim(Type)), MoveFn(getMoveArrayPrim(Type)) {
assert(Source && "Missing source");
}
-Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, unsigned NumElems,
- bool IsConst, bool IsTemporary, bool IsMutable)
+Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, MetadataSize MD,
+ unsigned NumElems, bool IsConst, bool IsTemporary,
+ bool IsMutable)
: Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
- Size(ElemSize * NumElems),
- AllocSize(std::max<size_t>(alignof(void *), Size)), ElemDesc(Elem),
- IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
- IsArray(true), CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc),
- MoveFn(moveArrayDesc) {
+ Size(ElemSize * NumElems), MDSize(MD.value_or(0)),
+ AllocSize(std::max<size_t>(alignof(void *), Size) + MDSize),
+ ElemDesc(Elem), IsConst(IsConst), IsMutable(IsMutable),
+ IsTemporary(IsTemporary), IsArray(true), CtorFn(ctorArrayDesc),
+ DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
assert(Source && "Missing source");
}
Descriptor::Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary,
UnknownSize)
: Source(D), ElemSize(Elem->getAllocSize() + sizeof(InlineDescriptor)),
- Size(UnknownSizeMark), AllocSize(alignof(void *)), ElemDesc(Elem),
- IsConst(true), IsMutable(false), IsTemporary(IsTemporary), IsArray(true),
- CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc), MoveFn(moveArrayDesc) {
+ Size(UnknownSizeMark), MDSize(0), AllocSize(alignof(void *)),
+ ElemDesc(Elem), IsConst(true), IsMutable(false), IsTemporary(IsTemporary),
+ IsArray(true), CtorFn(ctorArrayDesc), DtorFn(dtorArrayDesc),
+ MoveFn(moveArrayDesc) {
assert(Source && "Missing source");
}
-Descriptor::Descriptor(const DeclTy &D, Record *R, bool IsConst,
- bool IsTemporary, bool IsMutable)
+Descriptor::Descriptor(const DeclTy &D, Record *R, MetadataSize MD,
+ bool IsConst, bool IsTemporary, bool IsMutable)
: Source(D), ElemSize(std::max<size_t>(alignof(void *), R->getFullSize())),
- Size(ElemSize), AllocSize(Size), ElemRecord(R), IsConst(IsConst),
- IsMutable(IsMutable), IsTemporary(IsTemporary), CtorFn(ctorRecord),
- DtorFn(dtorRecord), MoveFn(moveRecord) {
+ Size(ElemSize), MDSize(MD.value_or(0)), AllocSize(Size + MDSize),
+ ElemRecord(R), IsConst(IsConst), IsMutable(IsMutable),
+ IsTemporary(IsTemporary), CtorFn(ctorRecord), DtorFn(dtorRecord),
+ MoveFn(moveRecord) {
assert(Source && "Missing source");
}
@@ -259,9 +274,7 @@ SourceLocation Descriptor::getLocation() const {
}
InitMap::InitMap(unsigned N) : UninitFields(N) {
- for (unsigned I = 0; I < N / PER_FIELD; ++I) {
- data()[I] = 0;
- }
+ std::fill_n(data(), (N + PER_FIELD - 1) / PER_FIELD, 0);
}
InitMap::T *InitMap::data() {
@@ -269,9 +282,14 @@ InitMap::T *InitMap::data() {
return reinterpret_cast<T *>(Start);
}
+const InitMap::T *InitMap::data() const {
+ auto *Start = reinterpret_cast<const char *>(this) + align(sizeof(InitMap));
+ return reinterpret_cast<const T *>(Start);
+}
+
bool InitMap::initialize(unsigned I) {
unsigned Bucket = I / PER_FIELD;
- unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD);
+ T Mask = T(1) << (I % PER_FIELD);
if (!(data()[Bucket] & Mask)) {
data()[Bucket] |= Mask;
UninitFields -= 1;
@@ -279,10 +297,9 @@ bool InitMap::initialize(unsigned I) {
return UninitFields == 0;
}
-bool InitMap::isInitialized(unsigned I) {
+bool InitMap::isInitialized(unsigned I) const {
unsigned Bucket = I / PER_FIELD;
- unsigned Mask = 1ull << static_cast<uint64_t>(I % PER_FIELD);
- return data()[Bucket] & Mask;
+ return data()[Bucket] & (T(1) << (I % PER_FIELD));
}
InitMap *InitMap::allocate(unsigned N) {
diff --git a/clang/lib/AST/Interp/Descriptor.h b/clang/lib/AST/Interp/Descriptor.h
index 11072cab3e90..6ef4fc2f4c9b 100644
--- a/clang/lib/AST/Interp/Descriptor.h
+++ b/clang/lib/AST/Interp/Descriptor.h
@@ -47,8 +47,36 @@ using BlockMoveFn = void (*)(Block *Storage, char *SrcFieldPtr,
/// Object size as used by the interpreter.
using InterpSize = unsigned;
+/// Inline descriptor embedded in structures and arrays.
+///
+/// Such descriptors precede all composite array elements and structure fields.
+/// If the base of a pointer is not zero, the base points to the end of this
+/// structure. The offset field is used to traverse the pointer chain up
+/// to the root structure which allocated the object.
+struct InlineDescriptor {
+ /// Offset inside the structure/array.
+ unsigned Offset;
+
+ /// Flag indicating if the storage is constant or not.
+ /// Relevant for primitive fields.
+ unsigned IsConst : 1;
+ /// For primitive fields, it indicates if the field was initialized.
+ /// Primitive fields in static storage are always initialized.
+ /// Arrays are always initialized, even though their elements might not be.
+ /// Base classes are initialized after the constructor is invoked.
+ unsigned IsInitialized : 1;
+ /// Flag indicating if the field is an embedded base class.
+ unsigned IsBase : 1;
+ /// Flag indicating if the field is the active member of a union.
+ unsigned IsActive : 1;
+ /// Flag indicating if the field is mutable (if in a record).
+ unsigned IsFieldMutable : 1;
+
+ Descriptor *Desc;
+};
+
/// Describes a memory block created by an allocation site.
-struct Descriptor {
+struct Descriptor final {
private:
/// Original declaration, used to emit the error message.
const DeclTy Source;
@@ -56,6 +84,8 @@ private:
const InterpSize ElemSize;
/// Size of the storage, in host bytes.
const InterpSize Size;
+ // Size of the metadata.
+ const InterpSize MDSize;
/// Size of the allocation (storage + metadata), in host bytes.
const InterpSize AllocSize;
@@ -66,6 +96,9 @@ public:
/// Token to denote structures of unknown size.
struct UnknownSize {};
+ using MetadataSize = std::optional<InterpSize>;
+ static constexpr MetadataSize InlineDescMD = sizeof(InlineDescriptor);
+
/// Pointer to the record, if block contains records.
Record *const ElemRecord = nullptr;
/// Descriptor of the array element.
@@ -85,26 +118,26 @@ public:
const BlockMoveFn MoveFn = nullptr;
/// Allocates a descriptor for a primitive.
- Descriptor(const DeclTy &D, PrimType Type, bool IsConst, bool IsTemporary,
- bool IsMutable);
+ Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, bool IsConst,
+ bool IsTemporary, bool IsMutable);
/// Allocates a descriptor for an array of primitives.
- Descriptor(const DeclTy &D, PrimType Type, size_t NumElems, bool IsConst,
- bool IsTemporary, bool IsMutable);
+ Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, size_t NumElems,
+ bool IsConst, bool IsTemporary, bool IsMutable);
/// Allocates a descriptor for an array of primitives of unknown size.
Descriptor(const DeclTy &D, PrimType Type, bool IsTemporary, UnknownSize);
/// Allocates a descriptor for an array of composites.
- Descriptor(const DeclTy &D, Descriptor *Elem, unsigned NumElems, bool IsConst,
- bool IsTemporary, bool IsMutable);
+ Descriptor(const DeclTy &D, Descriptor *Elem, MetadataSize MD,
+ unsigned NumElems, bool IsConst, bool IsTemporary, bool IsMutable);
/// Allocates a descriptor for an array of composites of unknown size.
Descriptor(const DeclTy &D, Descriptor *Elem, bool IsTemporary, UnknownSize);
/// Allocates a descriptor for a record.
- Descriptor(const DeclTy &D, Record *R, bool IsConst, bool IsTemporary,
- bool IsMutable);
+ Descriptor(const DeclTy &D, Record *R, MetadataSize MD, bool IsConst,
+ bool IsTemporary, bool IsMutable);
QualType getType() const;
SourceLocation getLocation() const;
@@ -113,15 +146,15 @@ public:
const Expr *asExpr() const { return Source.dyn_cast<const Expr *>(); }
const ValueDecl *asValueDecl() const {
- return dyn_cast_or_null<ValueDecl>(asDecl());
+ return dyn_cast_if_present<ValueDecl>(asDecl());
}
const FieldDecl *asFieldDecl() const {
- return dyn_cast_or_null<FieldDecl>(asDecl());
+ return dyn_cast_if_present<FieldDecl>(asDecl());
}
const RecordDecl *asRecordDecl() const {
- return dyn_cast_or_null<RecordDecl>(asDecl());
+ return dyn_cast_if_present<RecordDecl>(asDecl());
}
/// Returns the size of the object without metadata.
@@ -134,6 +167,8 @@ public:
unsigned getAllocSize() const { return AllocSize; }
/// returns the size of an element when the structure is viewed as an array.
unsigned getElemSize() const { return ElemSize; }
+ /// Returns the size of the metadata.
+ unsigned getMetadataSize() const { return MDSize; }
/// Returns the number of elements stored in the block.
unsigned getNumElems() const {
@@ -154,39 +189,11 @@ public:
bool isArray() const { return IsArray; }
};
-/// Inline descriptor embedded in structures and arrays.
-///
-/// Such descriptors precede all composite array elements and structure fields.
-/// If the base of a pointer is not zero, the base points to the end of this
-/// structure. The offset field is used to traverse the pointer chain up
-/// to the root structure which allocated the object.
-struct InlineDescriptor {
- /// Offset inside the structure/array.
- unsigned Offset;
-
- /// Flag indicating if the storage is constant or not.
- /// Relevant for primitive fields.
- unsigned IsConst : 1;
- /// For primitive fields, it indicates if the field was initialized.
- /// Primitive fields in static storage are always initialized.
- /// Arrays are always initialized, even though their elements might not be.
- /// Base classes are initialized after the constructor is invoked.
- unsigned IsInitialized : 1;
- /// Flag indicating if the field is an embedded base class.
- unsigned IsBase : 1;
- /// Flag indicating if the field is the active member of a union.
- unsigned IsActive : 1;
- /// Flag indicating if the field is mutable (if in a record).
- unsigned IsMutable : 1;
-
- Descriptor *Desc;
-};
-
/// Bitfield tracking the initialisation status of elements of primitive arrays.
/// A pointer to this is embedded at the end of all primitive arrays.
/// If the map was not yet created and nothing was initialized, the pointer to
/// this structure is 0. If the object was fully initialized, the pointer is -1.
-struct InitMap {
+struct InitMap final {
private:
/// Type packing bits.
using T = uint64_t;
@@ -198,13 +205,14 @@ private:
/// Returns a pointer to storage.
T *data();
+ const T *data() const;
public:
/// Initializes an element. Returns true when object if fully initialized.
bool initialize(unsigned I);
/// Checks if an element was initialized.
- bool isInitialized(unsigned I);
+ bool isInitialized(unsigned I) const;
/// Allocates a map holding N elements.
static InitMap *allocate(unsigned N);
diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp
index 36adbe296b0c..d31e879d516f 100644
--- a/clang/lib/AST/Interp/Disasm.cpp
+++ b/clang/lib/AST/Interp/Disasm.cpp
@@ -21,17 +21,13 @@
using namespace clang;
using namespace clang::interp;
-template <typename T>
-inline std::enable_if_t<!std::is_pointer<T>::value, T> ReadArg(Program &P,
- CodePtr OpPC) {
- return OpPC.read<T>();
-}
-
-template <typename T>
-inline std::enable_if_t<std::is_pointer<T>::value, T> ReadArg(Program &P,
- CodePtr OpPC) {
- uint32_t ID = OpPC.read<uint32_t>();
- return reinterpret_cast<T>(P.getNativePointer(ID));
+template <typename T> inline T ReadArg(Program &P, CodePtr &OpPC) {
+ if constexpr (std::is_pointer_v<T>) {
+ uint32_t ID = OpPC.read<uint32_t>();
+ return reinterpret_cast<T>(P.getNativePointer(ID));
+ } else {
+ return OpPC.read<T>();
+ }
}
LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
@@ -40,10 +36,11 @@ LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
if (F) {
if (auto *Cons = dyn_cast<CXXConstructorDecl>(F)) {
DeclarationName Name = Cons->getParent()->getDeclName();
- OS << Name << "::" << Name << ":\n";
+ OS << Name << "::" << Name;
} else {
- OS << F->getDeclName() << ":\n";
+ OS << F->getDeclName();
}
+ OS << " " << (const void*)this << ":\n";
} else {
OS << "<<expr>>\n";
}
@@ -51,6 +48,7 @@ LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
OS << "frame size: " << getFrameSize() << "\n";
OS << "arg size: " << getArgSize() << "\n";
OS << "rvo: " << hasRVO() << "\n";
+ OS << "this arg: " << hasThisPointer() << "\n";
auto PrintName = [&OS](const char *Name) {
OS << Name;
@@ -74,6 +72,10 @@ LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
+ OS << ":: Program\n";
+ OS << "Global Variables: " << Globals.size() << "\n";
+ OS << "Functions: " << Funcs.size() << "\n";
+ OS << "\n";
for (auto &Func : Funcs) {
Func.second->dump();
}
diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index 22e8695b9211..72fd3b45254b 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -23,7 +23,8 @@ EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
InterpStack &Stk, APValue &Result)
: Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), Result(Result) {
// Create a dummy frame for the interpreter which does not have locals.
- S.Current = new InterpFrame(S, nullptr, nullptr, CodePtr(), Pointer());
+ S.Current =
+ new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr());
}
llvm::Expected<bool> EvalEmitter::interpretExpr(const Expr *E) {
@@ -54,6 +55,16 @@ Scope::Local EvalEmitter::createLocal(Descriptor *D) {
auto *B = new (Memory.get()) Block(D, /*isStatic=*/false);
B->invokeCtor();
+ // Initialize local variable inline descriptor.
+ InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
+ Desc.Desc = D;
+ Desc.Offset = sizeof(InlineDescriptor);
+ Desc.IsActive = true;
+ Desc.IsBase = false;
+ Desc.IsFieldMutable = false;
+ Desc.IsConst = false;
+ Desc.IsInitialized = false;
+
// Register the local.
unsigned Off = Locals.size();
Locals.insert({Off, std::move(Memory)});
@@ -123,7 +134,7 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
const Pointer &FP = Ptr.atField(F.Offset);
QualType FieldTy = F.Decl->getType();
if (FP.isActive()) {
- if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
+ if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
} else {
Ok &= Composite(FieldTy, FP, Value);
@@ -145,7 +156,7 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
const Pointer &FP = Ptr.atField(FD->Offset);
APValue &Value = R.getStructField(I);
- if (llvm::Optional<PrimType> T = Ctx.classify(FieldTy)) {
+ if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
TYPE_SWITCH(*T, Ok &= ReturnValue<T>(FP.deref<T>(), Value));
} else {
Ok &= Composite(FieldTy, FP, Value);
@@ -177,7 +188,7 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
for (unsigned I = 0; I < NumElems; ++I) {
APValue &Slot = R.getArrayInitializedElt(I);
const Pointer &EP = Ptr.atIndex(I);
- if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
+ if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
TYPE_SWITCH(*T, Ok &= ReturnValue<T>(EP.deref<T>(), Slot));
} else {
Ok &= Composite(ElemTy, EP.narrow(), Slot);
@@ -199,7 +210,8 @@ bool EvalEmitter::emitGetPtrLocal(uint32_t I, const SourceInfo &Info) {
auto It = Locals.find(I);
assert(It != Locals.end() && "Missing local variable");
- S.Stk.push<Pointer>(reinterpret_cast<Block *>(It->second.get()));
+ Block *B = reinterpret_cast<Block *>(It->second.get());
+ S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));
return true;
}
@@ -213,7 +225,7 @@ bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) {
auto It = Locals.find(I);
assert(It != Locals.end() && "Missing local variable");
auto *B = reinterpret_cast<Block *>(It->second.get());
- S.Stk.push<T>(*reinterpret_cast<T *>(B + 1));
+ S.Stk.push<T>(*reinterpret_cast<T *>(B->data()));
return true;
}
@@ -227,7 +239,10 @@ bool EvalEmitter::emitSetLocal(uint32_t I, const SourceInfo &Info) {
auto It = Locals.find(I);
assert(It != Locals.end() && "Missing local variable");
auto *B = reinterpret_cast<Block *>(It->second.get());
- *reinterpret_cast<T *>(B + 1) = S.Stk.pop<T>();
+ *reinterpret_cast<T *>(B->data()) = S.Stk.pop<T>();
+ InlineDescriptor &Desc = *reinterpret_cast<InlineDescriptor *>(B->rawData());
+ Desc.IsInitialized = true;
+
return true;
}
diff --git a/clang/lib/AST/Interp/EvalEmitter.h b/clang/lib/AST/Interp/EvalEmitter.h
index eec2ff8ee753..6b6d0d621901 100644
--- a/clang/lib/AST/Interp/EvalEmitter.h
+++ b/clang/lib/AST/Interp/EvalEmitter.h
@@ -23,7 +23,6 @@
#include "llvm/Support/Error.h"
namespace clang {
-class FunctionDecl;
namespace interp {
class Context;
class Function;
@@ -71,7 +70,7 @@ protected:
Local createLocal(Descriptor *D);
/// Returns the source location of the current opcode.
- SourceInfo getSource(Function *F, CodePtr PC) const override {
+ SourceInfo getSource(const Function *F, CodePtr PC) const override {
return F ? F->getSource(PC) : CurrentSource;
}
@@ -97,7 +96,7 @@ private:
// value which is mapped to the location of the opcode being evaluated.
CodePtr OpPC;
/// Location of a failure.
- llvm::Optional<SourceLocation> BailLocation;
+ std::optional<SourceLocation> BailLocation;
/// Location of the current instruction.
SourceInfo CurrentSource;
@@ -110,12 +109,7 @@ private:
/// Since expressions can only jump forward, predicated execution is
/// used to deal with if-else statements.
- bool isActive() { return CurrentLabel == ActiveLabel; }
-
- /// Helper to invoke a method.
- bool ExecuteCall(Function *F, Pointer &&This, const SourceInfo &Info);
- /// Helper to emit a diagnostic on a missing method.
- bool ExecuteNoCall(const FunctionDecl *F, const SourceInfo &Info);
+ bool isActive() const { return CurrentLabel == ActiveLabel; }
protected:
#define GET_EVAL_PROTO
diff --git a/clang/lib/AST/Interp/Function.cpp b/clang/lib/AST/Interp/Function.cpp
index 6ba97df1cd30..40001faad411 100644
--- a/clang/lib/AST/Interp/Function.cpp
+++ b/clang/lib/AST/Interp/Function.cpp
@@ -17,13 +17,11 @@ using namespace clang::interp;
Function::Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
llvm::SmallVector<PrimType, 8> &&ParamTypes,
- llvm::DenseMap<unsigned, ParamDescriptor> &&Params)
+ llvm::DenseMap<unsigned, ParamDescriptor> &&Params,
+ bool HasThisPointer, bool HasRVO)
: P(P), Loc(F->getBeginLoc()), F(F), ArgSize(ArgSize),
- ParamTypes(std::move(ParamTypes)), Params(std::move(Params)) {}
-
-CodePtr Function::getCodeBegin() const { return Code.data(); }
-
-CodePtr Function::getCodeEnd() const { return Code.data() + Code.size(); }
+ ParamTypes(std::move(ParamTypes)), Params(std::move(Params)),
+ HasThisPointer(HasThisPointer), HasRVO(HasRVO) {}
Function::ParamDescriptor Function::getParamDescriptor(unsigned Offset) const {
auto It = Params.find(Offset);
@@ -32,11 +30,12 @@ Function::ParamDescriptor Function::getParamDescriptor(unsigned Offset) const {
}
SourceInfo Function::getSource(CodePtr PC) const {
+ assert(PC >= getCodeBegin() && "PC does not belong to this function");
+ assert(PC <= getCodeEnd() && "PC Does not belong to this function");
unsigned Offset = PC - getCodeBegin();
using Elem = std::pair<unsigned, SourceInfo>;
auto It = llvm::lower_bound(SrcMap, Elem{Offset, {}}, llvm::less_first());
- if (It == SrcMap.end() || It->first != Offset)
- llvm::report_fatal_error("missing source location");
+ assert(It != SrcMap.end());
return It->second;
}
diff --git a/clang/lib/AST/Interp/Function.h b/clang/lib/AST/Interp/Function.h
index ac1dffea1160..5b2a77f1a12d 100644
--- a/clang/lib/AST/Interp/Function.h
+++ b/clang/lib/AST/Interp/Function.h
@@ -29,7 +29,7 @@ enum PrimType : uint32_t;
/// Describes a scope block.
///
/// The block gathers all the descriptors of the locals defined in this block.
-class Scope {
+class Scope final {
public:
/// Information about a local's storage.
struct Local {
@@ -43,7 +43,7 @@ public:
Scope(LocalVectorTy &&Descriptors) : Descriptors(std::move(Descriptors)) {}
- llvm::iterator_range<LocalVectorTy::iterator> locals() {
+ llvm::iterator_range<LocalVectorTy::const_iterator> locals() const {
return llvm::make_range(Descriptors.begin(), Descriptors.end());
}
@@ -56,23 +56,42 @@ private:
///
/// Contains links to the bytecode of the function, as well as metadata
/// describing all arguments and stack-local variables.
-class Function {
+///
+/// # Calling Convention
+///
+/// When calling a function, all argument values must be on the stack.
+///
+/// If the function has a This pointer (i.e. hasThisPointer() returns true,
+/// the argument values need to be preceeded by a Pointer for the This object.
+///
+/// If the function uses Return Value Optimization, the arguments (and
+/// potentially the This pointer) need to be proceeded by a Pointer pointing
+/// to the location to construct the returned value.
+///
+/// After the function has been called, it will remove all arguments,
+/// including RVO and This pointer, from the stack.
+///
+class Function final {
public:
using ParamDescriptor = std::pair<PrimType, Descriptor *>;
/// Returns the size of the function's local stack.
unsigned getFrameSize() const { return FrameSize; }
- /// Returns the size of the argument stackx
+ /// Returns the size of the argument stack.
unsigned getArgSize() const { return ArgSize; }
/// Returns a pointer to the start of the code.
- CodePtr getCodeBegin() const;
+ CodePtr getCodeBegin() const { return Code.data(); }
/// Returns a pointer to the end of the code.
- CodePtr getCodeEnd() const;
+ CodePtr getCodeEnd() const { return Code.data() + Code.size(); }
/// Returns the original FunctionDecl.
const FunctionDecl *getDecl() const { return F; }
+ /// Returns the name of the function decl this code
+ /// was generated for.
+ const std::string getName() const { return F->getNameInfo().getAsString(); }
+
/// Returns the location.
SourceLocation getLoc() const { return Loc; }
@@ -80,21 +99,24 @@ public:
ParamDescriptor getParamDescriptor(unsigned Offset) const;
/// Checks if the first argument is a RVO pointer.
- bool hasRVO() const { return ParamTypes.size() != Params.size(); }
+ bool hasRVO() const { return HasRVO; }
/// Range over the scope blocks.
- llvm::iterator_range<llvm::SmallVector<Scope, 2>::iterator> scopes() {
+ llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator>
+ scopes() const {
return llvm::make_range(Scopes.begin(), Scopes.end());
}
/// Range over argument types.
- using arg_reverse_iterator = SmallVectorImpl<PrimType>::reverse_iterator;
- llvm::iterator_range<arg_reverse_iterator> args_reverse() {
- return llvm::make_range(ParamTypes.rbegin(), ParamTypes.rend());
+ using arg_reverse_iterator =
+ SmallVectorImpl<PrimType>::const_reverse_iterator;
+ llvm::iterator_range<arg_reverse_iterator> args_reverse() const {
+ return llvm::reverse(ParamTypes);
}
/// Returns a specific scope.
Scope &getScope(unsigned Idx) { return Scopes[Idx]; }
+ const Scope &getScope(unsigned Idx) const { return Scopes[Idx]; }
/// Returns the source information at a given PC.
SourceInfo getSource(CodePtr PC) const;
@@ -108,11 +130,22 @@ public:
/// Checks if the function is a constructor.
bool isConstructor() const { return isa<CXXConstructorDecl>(F); }
+ /// Checks if the function is fully done compiling.
+ bool isFullyCompiled() const { return IsFullyCompiled; }
+
+ bool hasThisPointer() const { return HasThisPointer; }
+
+ // Checks if the funtion already has a body attached.
+ bool hasBody() const { return HasBody; }
+
+ unsigned getNumParams() const { return ParamTypes.size(); }
+
private:
/// Construct a function representing an actual function.
Function(Program &P, const FunctionDecl *F, unsigned ArgSize,
llvm::SmallVector<PrimType, 8> &&ParamTypes,
- llvm::DenseMap<unsigned, ParamDescriptor> &&Params);
+ llvm::DenseMap<unsigned, ParamDescriptor> &&Params,
+ bool HasThisPointer, bool HasRVO);
/// Sets the code of a function.
void setCode(unsigned NewFrameSize, std::vector<char> &&NewCode, SourceMap &&NewSrcMap,
@@ -122,8 +155,11 @@ private:
SrcMap = std::move(NewSrcMap);
Scopes = std::move(NewScopes);
IsValid = true;
+ HasBody = true;
}
+ void setIsFullyCompiled(bool FC) { IsFullyCompiled = FC; }
+
private:
friend class Program;
friend class ByteCodeEmitter;
@@ -135,7 +171,7 @@ private:
/// Declaration this function was compiled from.
const FunctionDecl *F;
/// Local area size: storage + metadata.
- unsigned FrameSize;
+ unsigned FrameSize = 0;
/// Size of the argument stack.
unsigned ArgSize;
/// Program code.
@@ -150,6 +186,18 @@ private:
llvm::DenseMap<unsigned, ParamDescriptor> Params;
/// Flag to indicate if the function is valid.
bool IsValid = false;
+ /// Flag to indicate if the function is done being
+ /// compiled to bytecode.
+ bool IsFullyCompiled = false;
+ /// Flag indicating if this function takes the this pointer
+ /// as the first implicit argument
+ bool HasThisPointer = false;
+ /// Whether this function has Return Value Optimization, i.e.
+ /// the return value is constructed in the caller's stack frame.
+ /// This is done for functions that return non-primive values.
+ bool HasRVO = false;
+ /// If we've already compiled the function's body.
+ bool HasBody = false;
public:
/// Dumps the disassembled bytecode to \c llvm::errs().
diff --git a/clang/lib/AST/Interp/Integral.h b/clang/lib/AST/Interp/Integral.h
index 46cd611ee389..8a742333ae57 100644
--- a/clang/lib/AST/Interp/Integral.h
+++ b/clang/lib/AST/Interp/Integral.h
@@ -53,17 +53,17 @@ template <> struct Repr<64, true> { using Type = int64_t; };
/// These wrappers are required to shared an interface between APSint and
/// builtin primitive numeral types, while optimising for storage and
/// allowing methods operating on primitive type to compile to fast code.
-template <unsigned Bits, bool Signed> class Integral {
+template <unsigned Bits, bool Signed> class Integral final {
private:
template <unsigned OtherBits, bool OtherSigned> friend class Integral;
// The primitive representing the integral.
- using T = typename Repr<Bits, Signed>::Type;
- T V;
+ using ReprT = typename Repr<Bits, Signed>::Type;
+ ReprT V;
/// Primitive representing limits.
- static const auto Min = std::numeric_limits<T>::min();
- static const auto Max = std::numeric_limits<T>::max();
+ static const auto Min = std::numeric_limits<ReprT>::min();
+ static const auto Max = std::numeric_limits<ReprT>::max();
/// Construct an integral from anything that is convertible to storage.
template <typename T> explicit Integral(T V) : V(V) {}
@@ -107,7 +107,7 @@ public:
return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
}
APSInt toAPSInt(unsigned NumBits) const {
- if (Signed)
+ if constexpr (Signed)
return APSInt(toAPSInt().sextOrTrunc(NumBits), !Signed);
else
return APSInt(toAPSInt().zextOrTrunc(NumBits), !Signed);
@@ -124,25 +124,27 @@ public:
bool isMin() const { return *this == min(bitWidth()); }
- bool isMinusOne() const { return Signed && V == T(-1); }
+ bool isMinusOne() const { return Signed && V == ReprT(-1); }
constexpr static bool isSigned() { return Signed; }
- bool isNegative() const { return V < T(0); }
+ bool isNegative() const { return V < ReprT(0); }
bool isPositive() const { return !isNegative(); }
ComparisonCategoryResult compare(const Integral &RHS) const {
return Compare(V, RHS.V);
}
- unsigned countLeadingZeros() const { return llvm::countLeadingZeros<T>(V); }
+ unsigned countLeadingZeros() const {
+ return llvm::countLeadingZeros<ReprT>(V);
+ }
Integral truncate(unsigned TruncBits) const {
if (TruncBits >= Bits)
return *this;
- const T BitMask = (T(1) << T(TruncBits)) - 1;
- const T SignBit = T(1) << (TruncBits - 1);
- const T ExtMask = ~BitMask;
+ const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;
+ const ReprT SignBit = ReprT(1) << (TruncBits - 1);
+ const ReprT ExtMask = ~BitMask;
return Integral((V & BitMask) | (Signed && (V & SignBit) ? ExtMask : 0));
}
@@ -155,9 +157,11 @@ public:
return Integral(Max);
}
- template <typename T>
- static std::enable_if_t<std::is_integral<T>::value, Integral> from(T Value) {
- return Integral(Value);
+ template <typename ValT> static Integral from(ValT Value) {
+ if constexpr (std::is_integral<ValT>::value)
+ return Integral(Value);
+ else
+ return Integral::from(static_cast<Integral::ReprT>(Value));
}
template <unsigned SrcBits, bool SrcSign>
@@ -167,7 +171,7 @@ public:
}
template <bool SrcSign> static Integral from(Integral<0, SrcSign> Value) {
- if (SrcSign)
+ if constexpr (SrcSign)
return Integral(Value.V.getSExtValue());
else
return Integral(Value.V.getZExtValue());
@@ -180,15 +184,15 @@ public:
}
static bool inRange(int64_t Value, unsigned NumBits) {
- return CheckRange<T, Min, Max>(Value);
+ return CheckRange<ReprT, Min, Max>(Value);
}
static bool increment(Integral A, Integral *R) {
- return add(A, Integral(T(1)), A.bitWidth(), R);
+ return add(A, Integral(ReprT(1)), A.bitWidth(), R);
}
static bool decrement(Integral A, Integral *R) {
- return sub(A, Integral(T(1)), A.bitWidth(), R);
+ return sub(A, Integral(ReprT(1)), A.bitWidth(), R);
}
static bool add(Integral A, Integral B, unsigned OpBits, Integral *R) {
@@ -203,56 +207,74 @@ public:
return CheckMulUB(A.V, B.V, R->V);
}
-private:
- template <typename T>
- static std::enable_if_t<std::is_signed<T>::value, bool> CheckAddUB(T A, T B,
- T &R) {
- return llvm::AddOverflow<T>(A, B, R);
+ static bool rem(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ *R = Integral(A.V % B.V);
+ return false;
+ }
+
+ static bool div(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ *R = Integral(A.V / B.V);
+ return false;
}
- template <typename T>
- static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckAddUB(T A, T B,
- T &R) {
- R = A + B;
+ static bool bitAnd(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ *R = Integral(A.V & B.V);
return false;
}
- template <typename T>
- static std::enable_if_t<std::is_signed<T>::value, bool> CheckSubUB(T A, T B,
- T &R) {
- return llvm::SubOverflow<T>(A, B, R);
+ static bool bitOr(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ *R = Integral(A.V | B.V);
+ return false;
}
- template <typename T>
- static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckSubUB(T A, T B,
- T &R) {
- R = A - B;
+ static bool bitXor(Integral A, Integral B, unsigned OpBits, Integral *R) {
+ *R = Integral(A.V ^ B.V);
return false;
}
- template <typename T>
- static std::enable_if_t<std::is_signed<T>::value, bool> CheckMulUB(T A, T B,
- T &R) {
- return llvm::MulOverflow<T>(A, B, R);
+ static bool neg(Integral A, Integral *R) {
+ *R = -A;
+ return false;
}
- template <typename T>
- static std::enable_if_t<std::is_unsigned<T>::value, bool> CheckMulUB(T A, T B,
- T &R) {
- R = A * B;
+ static bool comp(Integral A, Integral *R) {
+ *R = Integral(~A.V);
return false;
}
- template <typename T, T Min, T Max>
- static std::enable_if_t<std::is_signed<T>::value, bool>
- CheckRange(int64_t V) {
- return Min <= V && V <= Max;
+private:
+ template <typename T> static bool CheckAddUB(T A, T B, T &R) {
+ if constexpr (std::is_signed_v<T>) {
+ return llvm::AddOverflow<T>(A, B, R);
+ } else {
+ R = A + B;
+ return false;
+ }
}
- template <typename T, T Min, T Max>
- static std::enable_if_t<std::is_unsigned<T>::value, bool>
- CheckRange(int64_t V) {
- return V >= 0 && static_cast<uint64_t>(V) <= Max;
+ template <typename T> static bool CheckSubUB(T A, T B, T &R) {
+ if constexpr (std::is_signed_v<T>) {
+ return llvm::SubOverflow<T>(A, B, R);
+ } else {
+ R = A - B;
+ return false;
+ }
+ }
+
+ 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 {
+ R = A * B;
+ return false;
+ }
+ }
+ template <typename T, T Min, T Max> static bool CheckRange(int64_t V) {
+ if constexpr (std::is_signed_v<T>) {
+ return Min <= V && V <= Max;
+ } else {
+ return V >= 0 && static_cast<uint64_t>(V) <= Max;
+ }
}
};
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index cec3f6d6160e..6a600b306bad 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -1,4 +1,4 @@
-//===--- InterpState.cpp - Interpreter for the constexpr VM -----*- C++ -*-===//
+//===------- Interp.cpp - Interpreter for the constexpr VM ------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -201,8 +201,8 @@ bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
AccessKinds AK) {
- const auto &Src = S.Current->getSource(OpPC);
if (Ptr.isZero()) {
+ const auto &Src = S.Current->getSource(OpPC);
if (Ptr.isField())
S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field;
@@ -213,6 +213,7 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
}
if (!Ptr.isLive()) {
+ const auto &Src = S.Current->getSource(OpPC);
bool IsTemp = Ptr.isTemporary();
S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp;
@@ -330,17 +331,18 @@ bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return true;
}
-bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F) {
- const SourceLocation &Loc = S.Current->getLocation(OpPC);
+bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) {
if (F->isVirtual()) {
if (!S.getLangOpts().CPlusPlus20) {
+ const SourceLocation &Loc = S.Current->getLocation(OpPC);
S.CCEDiag(Loc, diag::note_constexpr_virtual_call);
return false;
}
}
if (!F->isConstexpr()) {
+ const SourceLocation &Loc = S.Current->getLocation(OpPC);
if (S.getLangOpts().CPlusPlus11) {
const FunctionDecl *DiagDecl = F->getDecl();
@@ -398,9 +400,92 @@ bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) {
S.Note(MD->getLocation(), diag::note_declared_at);
return false;
}
+
+static void DiagnoseUninitializedSubobject(InterpState &S, const SourceInfo &SI,
+ QualType SubObjType,
+ SourceLocation SubObjLoc) {
+ S.FFDiag(SI, diag::note_constexpr_uninitialized) << true << SubObjType;
+ if (SubObjLoc.isValid())
+ S.Note(SubObjLoc, diag::note_constexpr_subobject_declared_here);
+}
+
+static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
+ const Pointer &BasePtr, const Record *R);
+
+static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC,
+ const Pointer &BasePtr,
+ const ConstantArrayType *CAT) {
+ bool Result = true;
+ size_t NumElems = CAT->getSize().getZExtValue();
+ QualType ElemType = CAT->getElementType();
+
+ if (isa<RecordType>(ElemType.getTypePtr())) {
+ const Record *R = BasePtr.getElemRecord();
+ for (size_t I = 0; I != NumElems; ++I) {
+ Pointer ElemPtr = BasePtr.atIndex(I).narrow();
+ Result &= CheckFieldsInitialized(S, OpPC, ElemPtr, R);
+ }
+ } else if (auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) {
+ for (size_t I = 0; I != NumElems; ++I) {
+ Pointer ElemPtr = BasePtr.atIndex(I).narrow();
+ Result &= CheckArrayInitialized(S, OpPC, ElemPtr, ElemCAT);
+ }
+ } else {
+ for (size_t I = 0; I != NumElems; ++I) {
+ if (!BasePtr.atIndex(I).isInitialized()) {
+ DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), ElemType,
+ BasePtr.getFieldDesc()->getLocation());
+ Result = false;
+ }
+ }
+ }
+
+ return Result;
+}
+
+static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
+ const Pointer &BasePtr, const Record *R) {
+ assert(R);
+ bool Result = true;
+ // Check all fields of this record are initialized.
+ for (const Record::Field &F : R->fields()) {
+ Pointer FieldPtr = BasePtr.atField(F.Offset);
+ QualType FieldType = F.Decl->getType();
+
+ if (FieldType->isRecordType()) {
+ Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord());
+ } else if (FieldType->isArrayType()) {
+ const auto *CAT =
+ cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
+ Result &= CheckArrayInitialized(S, OpPC, FieldPtr, CAT);
+ } else if (!FieldPtr.isInitialized()) {
+ DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC),
+ F.Decl->getType(), F.Decl->getLocation());
+ Result = false;
+ }
+ }
+ return Result;
+}
+
+bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) {
+ assert(!This.isZero());
+ const Record *R = This.getRecord();
+ return CheckFieldsInitialized(S, OpPC, This, R);
+}
+
bool Interpret(InterpState &S, APValue &Result) {
+ // The current stack frame when we started Interpret().
+ // This is being used by the ops to determine wheter
+ // to return from this function and thus terminate
+ // interpretation.
+ const InterpFrame *StartFrame = S.Current;
+ assert(!S.Current->isRoot());
CodePtr PC = S.Current->getPC();
+ // Empty program.
+ if (!PC)
+ return true;
+
for (;;) {
auto Op = PC.read<Opcode>();
CodePtr OpPC = PC;
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index a1d90f26ba46..ed3accd98a90 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_AST_INTERP_INTERP_H
#define LLVM_CLANG_AST_INTERP_INTERP_H
+#include "Boolean.h"
#include "Function.h"
#include "InterpFrame.h"
#include "InterpStack.h"
@@ -30,7 +31,6 @@
#include "llvm/Support/Endian.h"
#include <limits>
#include <type_traits>
-#include <vector>
namespace clang {
namespace interp {
@@ -84,7 +84,7 @@ bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
/// Checks if a method can be called.
-bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F);
+bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
/// Checks the 'this' pointer.
bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
@@ -92,7 +92,53 @@ bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
/// Checks if a method is pure virtual.
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
-template <typename T> inline bool IsTrue(const T &V) { return !V.isZero(); }
+/// Checks that all fields are initialized after a constructor call.
+bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
+
+/// Checks if the shift operation is legal.
+template <typename RT>
+bool CheckShift(InterpState &S, CodePtr OpPC, const RT &RHS, unsigned Bits) {
+ if (RHS.isNegative()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
+ return false;
+ }
+
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of
+ // the shifted type.
+ if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
+ const Expr *E = S.Current->getExpr(OpPC);
+ const APSInt Val = RHS.toAPSInt();
+ QualType Ty = E->getType();
+ S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
+ return false;
+ }
+ return true;
+}
+
+/// Checks if Div/Rem operation on LHS and RHS is valid.
+template <typename T>
+bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
+ if (RHS.isZero()) {
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ S.FFDiag(Loc, diag::note_expr_divide_by_zero);
+ return false;
+ }
+
+ if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
+ APSInt LHSInt = LHS.toAPSInt();
+ SmallString<32> Trunc;
+ (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
+ const SourceInfo &Loc = S.Current->getSource(OpPC);
+ const Expr *E = S.Current->getExpr(OpPC);
+ S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
+ return false;
+ }
+ return true;
+}
+
+/// Interpreter entry point.
+bool Interpret(InterpState &S, APValue &Result);
//===----------------------------------------------------------------------===//
// Add, Sub, Mul
@@ -154,6 +200,240 @@ bool Mul(InterpState &S, CodePtr OpPC) {
return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
}
+/// 1) Pops the RHS from the stack.
+/// 2) Pops the LHS from the stack.
+/// 3) Pushes 'LHS & RHS' on the stack
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool BitAnd(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+
+ unsigned Bits = RHS.bitWidth();
+ T Result;
+ if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+ return false;
+}
+
+/// 1) Pops the RHS from the stack.
+/// 2) Pops the LHS from the stack.
+/// 3) Pushes 'LHS | RHS' on the stack
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool BitOr(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+
+ unsigned Bits = RHS.bitWidth();
+ T Result;
+ if (!T::bitOr(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+ return false;
+}
+
+/// 1) Pops the RHS from the stack.
+/// 2) Pops the LHS from the stack.
+/// 3) Pushes 'LHS ^ RHS' on the stack
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool BitXor(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+
+ unsigned Bits = RHS.bitWidth();
+ T Result;
+ if (!T::bitXor(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+ return false;
+}
+
+/// 1) Pops the RHS from the stack.
+/// 2) Pops the LHS from the stack.
+/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Rem(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+
+ if (!CheckDivRem(S, OpPC, LHS, RHS))
+ return false;
+
+ const unsigned Bits = RHS.bitWidth() * 2;
+ T Result;
+ if (!T::rem(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+ return false;
+}
+
+/// 1) Pops the RHS from the stack.
+/// 2) Pops the LHS from the stack.
+/// 3) Pushes 'LHS / RHS' on the stack
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Div(InterpState &S, CodePtr OpPC) {
+ const T &RHS = S.Stk.pop<T>();
+ const T &LHS = S.Stk.pop<T>();
+
+ if (!CheckDivRem(S, OpPC, LHS, RHS))
+ return false;
+
+ const unsigned Bits = RHS.bitWidth() * 2;
+ T Result;
+ if (!T::div(LHS, RHS, Bits, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Inv
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Inv(InterpState &S, CodePtr OpPC) {
+ using BoolT = PrimConv<PT_Bool>::T;
+ const T &Val = S.Stk.pop<T>();
+ const unsigned Bits = Val.bitWidth();
+ Boolean R;
+ Boolean::inv(BoolT::from(Val, Bits), &R);
+
+ S.Stk.push<BoolT>(R);
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Neg
+//===----------------------------------------------------------------------===//
+
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Neg(InterpState &S, CodePtr OpPC) {
+ const T &Val = S.Stk.pop<T>();
+ T Result;
+ T::neg(Val, &Result);
+
+ S.Stk.push<T>(Result);
+ return true;
+}
+
+enum class PushVal : bool {
+ No,
+ Yes,
+};
+enum class IncDecOp {
+ Inc,
+ Dec,
+};
+
+template <typename T, IncDecOp Op, PushVal DoPush>
+bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ T Value = Ptr.deref<T>();
+ T Result;
+
+ if constexpr (DoPush == PushVal::Yes)
+ S.Stk.push<T>(Result);
+
+ if constexpr (Op == IncDecOp::Inc) {
+ if (!T::increment(Value, &Result)) {
+ Ptr.deref<T>() = Result;
+ return true;
+ }
+ } else {
+ if (!T::decrement(Value, &Result)) {
+ Ptr.deref<T>() = Result;
+ return true;
+ }
+ }
+
+ // Something went wrong with the previous operation. Compute the
+ // result with another bit of precision.
+ unsigned Bits = Value.bitWidth() + 1;
+ APSInt APResult;
+ if constexpr (Op == IncDecOp::Inc)
+ APResult = ++Value.toAPSInt(Bits);
+ else
+ APResult = --Value.toAPSInt(Bits);
+
+ // Report undefined behaviour, stopping if required.
+ const Expr *E = S.Current->getExpr(OpPC);
+ QualType Type = E->getType();
+ if (S.checkingForUndefinedBehavior()) {
+ SmallString<32> Trunc;
+ APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
+ auto Loc = E->getExprLoc();
+ S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
+ return true;
+ }
+
+ S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
+ return S.noteUndefinedBehavior();
+}
+
+/// 1) Pops a pointer from the stack
+/// 2) Load the value from the pointer
+/// 3) Writes the value increased by one back to the pointer
+/// 4) Pushes the original (pre-inc) value on the stack.
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Inc(InterpState &S, CodePtr OpPC) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
+}
+
+/// 1) Pops a pointer from the stack
+/// 2) Load the value from the pointer
+/// 3) Writes the value increased by one back to the pointer
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool IncPop(InterpState &S, CodePtr OpPC) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
+}
+
+/// 1) Pops a pointer from the stack
+/// 2) Load the value from the pointer
+/// 3) Writes the value decreased by one back to the pointer
+/// 4) Pushes the original (pre-dec) value on the stack.
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Dec(InterpState &S, CodePtr OpPC) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
+}
+
+/// 1) Pops a pointer from the stack
+/// 2) Load the value from the pointer
+/// 3) Writes the value decreased by one back to the pointer
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool DecPop(InterpState &S, CodePtr OpPC) {
+ // FIXME: Check initialization of Ptr
+ const Pointer &Ptr = S.Stk.pop<Pointer>();
+
+ return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
+}
+
+/// 1) Pops the value from the stack.
+/// 2) Pushes the bitwise complemented value on the stack (~V).
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+bool Comp(InterpState &S, CodePtr OpPC) {
+ const T &Val = S.Stk.pop<T>();
+ T Result;
+ if (!T::comp(Val, &Result)) {
+ S.Stk.push<T>(Result);
+ return true;
+ }
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// EQ, NE, GT, GE, LT, LE
//===----------------------------------------------------------------------===//
@@ -209,6 +489,16 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
} else {
unsigned VL = LHS.getByteOffset();
unsigned VR = RHS.getByteOffset();
+
+ // In our Pointer class, a pointer to an array and a pointer to the first
+ // element in the same array are NOT equal. They have the same Base value,
+ // but a different Offset. This is a pretty rare case, so we fix this here
+ // by comparing pointers to the first elements.
+ if (LHS.inArray() && LHS.isRoot())
+ VL = LHS.atIndex(0).getByteOffset();
+ if (RHS.inArray() && RHS.isRoot())
+ VR = RHS.atIndex(0).getByteOffset();
+
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
return true;
}
@@ -304,7 +594,10 @@ bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
- S.Stk.push<T>(S.Current->getLocal<T>(I));
+ const Pointer &Ptr = S.Current->getLocalPointer(I);
+ if (!CheckLoad(S, OpPC, Ptr))
+ return false;
+ S.Stk.push<T>(Ptr.deref<T>());
return true;
}
@@ -329,6 +622,8 @@ bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
return true;
}
+/// 1) Peeks a pointer on the stack
+/// 2) Pushes the value of the pointer's field on the stack
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
const Pointer &Obj = S.Stk.peek<Pointer>();
@@ -358,6 +653,8 @@ bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
return true;
}
+/// 1) Pops a pointer from the stack
+/// 2) Pushes the value of the pointer's field on the stack
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
const Pointer &Obj = S.Stk.pop<Pointer>();
@@ -463,10 +760,13 @@ bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
return true;
}
+/// 1) Pops the value from the stack
+/// 2) Peeks a pointer from the stack
+/// 3) Pushes the value to field I of the pointer on the stack
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
const T &Value = S.Stk.pop<T>();
- const Pointer &Field = S.Stk.pop<Pointer>().atField(I);
+ const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
Field.deref<T>() = Value;
Field.activate();
Field.initialize();
@@ -516,6 +816,8 @@ inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
return true;
}
+/// 1) Pops a Pointer from the stack
+/// 2) Pushes Pointer.atField(Off) on the stack
inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckNull(S, OpPC, Ptr, CSK_Field))
@@ -638,6 +940,8 @@ bool Store(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckStore(S, OpPC, Ptr))
return false;
+ if (!Ptr.isRoot())
+ Ptr.initialize();
Ptr.deref<T>() = Value;
return true;
}
@@ -648,6 +952,8 @@ bool StorePop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckStore(S, OpPC, Ptr))
return false;
+ if (!Ptr.isRoot())
+ Ptr.initialize();
Ptr.deref<T>() = Value;
return true;
}
@@ -658,6 +964,8 @@ bool StoreBitField(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckStore(S, OpPC, Ptr))
return false;
+ if (!Ptr.isRoot())
+ Ptr.initialize();
if (auto *FD = Ptr.getField()) {
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
} else {
@@ -672,6 +980,8 @@ bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckStore(S, OpPC, Ptr))
return false;
+ if (!Ptr.isRoot())
+ Ptr.initialize();
if (auto *FD = Ptr.getField()) {
Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
} else {
@@ -691,6 +1001,9 @@ bool InitPop(InterpState &S, CodePtr OpPC) {
return true;
}
+/// 1) Pops the value from the stack
+/// 2) Peeks a pointer and gets its index \Idx
+/// 3) Sets the value on the pointer, leaving the pointer on the stack.
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
const T &Value = S.Stk.pop<T>();
@@ -702,6 +1015,7 @@ bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
return true;
}
+/// The same as InitElem, but pops the pointer as well.
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
const T &Value = S.Stk.pop<T>();
@@ -721,23 +1035,25 @@ template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
// Fetch the pointer and the offset.
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>();
- if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
- return false;
+
if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
return false;
- // Get a version of the index comparable to the type.
- T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
- // A zero offset does not change the pointer, but in the case of an array
- // it has to be adjusted to point to the first element instead of the array.
+ // A zero offset does not change the pointer.
if (Offset.isZero()) {
- S.Stk.push<Pointer>(Index.isZero() ? Ptr.atIndex(0) : Ptr);
+ S.Stk.push<Pointer>(Ptr);
return true;
}
+
+ if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
+ return false;
+
// Arrays of unknown bounds cannot have pointers into them.
if (!CheckArray(S, OpPC, Ptr))
return false;
+ // Get a version of the index comparable to the type.
+ T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
// Compute the largest index into the array.
unsigned MaxIndex = Ptr.getNumElems();
@@ -754,23 +1070,34 @@ template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
return false;
};
- // If the new offset would be negative, bail out.
- if (Add && Offset.isNegative() && (Offset.isMin() || -Offset > Index))
- return InvalidOffset();
- if (!Add && Offset.isPositive() && Index < Offset)
- return InvalidOffset();
-
- // If the new offset would be out of bounds, bail out.
unsigned MaxOffset = MaxIndex - Ptr.getIndex();
- if (Add && Offset.isPositive() && Offset > MaxOffset)
- return InvalidOffset();
- if (!Add && Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
- return InvalidOffset();
+ if constexpr (Add) {
+ // If the new offset would be negative, bail out.
+ if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
+ return InvalidOffset();
+
+ // If the new offset would be out of bounds, bail out.
+ if (Offset.isPositive() && Offset > MaxOffset)
+ return InvalidOffset();
+ } else {
+ // If the new offset would be negative, bail out.
+ if (Offset.isPositive() && Index < Offset)
+ return InvalidOffset();
+
+ // If the new offset would be out of bounds, bail out.
+ if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
+ return InvalidOffset();
+ }
// Offset is valid - compute it on unsigned.
int64_t WideIndex = static_cast<int64_t>(Index);
int64_t WideOffset = static_cast<int64_t>(Offset);
- int64_t Result = Add ? (WideIndex + WideOffset) : (WideIndex - WideOffset);
+ int64_t Result;
+ if constexpr (Add)
+ Result = WideIndex + WideOffset;
+ else
+ Result = WideIndex - WideOffset;
+
S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
return true;
}
@@ -785,6 +1112,23 @@ bool SubOffset(InterpState &S, CodePtr OpPC) {
return OffsetHelper<T, false>(S, OpPC);
}
+/// 1) Pops a Pointer from the stack.
+/// 2) Pops another Pointer from the stack.
+/// 3) Pushes the different of the indices of the two pointers on the stack.
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+inline bool SubPtr(InterpState &S, CodePtr OpPC) {
+ const Pointer &LHS = S.Stk.pop<Pointer>();
+ const Pointer &RHS = S.Stk.pop<Pointer>();
+
+ if (!Pointer::hasSameArray(LHS, RHS)) {
+ // TODO: Diagnose.
+ return false;
+ }
+
+ T A = T::from(LHS.getIndex());
+ T B = T::from(RHS.getIndex());
+ return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
+}
//===----------------------------------------------------------------------===//
// Destroy
@@ -840,88 +1184,47 @@ inline bool This(InterpState &S, CodePtr OpPC) {
return true;
}
+inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
+ assert(S.Current->getFunction()->hasRVO());
+ S.Stk.push<Pointer>(S.Current->getRVOPtr());
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Shr, Shl
//===----------------------------------------------------------------------===//
-template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T>
-unsigned Trunc(InterpState &S, CodePtr OpPC, unsigned Bits, const T &V) {
- // C++11 [expr.shift]p1: Shift width must be less than the bit width of
- // the shifted type.
- if (Bits > 1 && V >= T::from(Bits, V.bitWidth())) {
- const Expr *E = S.Current->getExpr(OpPC);
- const APSInt Val = V.toAPSInt();
- QualType Ty = E->getType();
- S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
- return Bits;
- } else {
- return static_cast<unsigned>(V);
- }
-}
-
-template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
-inline bool ShiftRight(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
- if (RHS >= V.bitWidth()) {
- S.Stk.push<T>(T::from(0, V.bitWidth()));
- } else {
- S.Stk.push<T>(T::from(V >> RHS, V.bitWidth()));
- }
- return true;
-}
+template <PrimType NameL, PrimType NameR>
+inline bool Shr(InterpState &S, CodePtr OpPC) {
+ using LT = typename PrimConv<NameL>::T;
+ using RT = typename PrimConv<NameR>::T;
+ const auto &RHS = S.Stk.pop<RT>();
+ const auto &LHS = S.Stk.pop<LT>();
+ const unsigned Bits = LHS.bitWidth();
-template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
-inline bool ShiftLeft(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
- if (V.isSigned() && !S.getLangOpts().CPlusPlus20) {
- // C++11 [expr.shift]p2: A signed left shift must have a non-negative
- // operand, and must not overflow the corresponding unsigned type.
- // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
- // E1 x 2^E2 module 2^N.
- if (V.isNegative()) {
- const Expr *E = S.Current->getExpr(OpPC);
- S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << V.toAPSInt();
- } else if (V.countLeadingZeros() < RHS) {
- S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_discards);
- }
- }
+ if (!CheckShift<RT>(S, OpPC, RHS, Bits))
+ return false;
- if (V.bitWidth() == 1) {
- S.Stk.push<T>(V);
- } else if (RHS >= V.bitWidth()) {
- S.Stk.push<T>(T::from(0, V.bitWidth()));
- } else {
- S.Stk.push<T>(T::from(V.toUnsigned() << RHS, V.bitWidth()));
- }
+ unsigned URHS = static_cast<unsigned>(RHS);
+ S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) >> URHS, LHS.bitWidth()));
return true;
}
-template <PrimType TL, PrimType TR>
-inline bool Shr(InterpState &S, CodePtr OpPC) {
- const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
- const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
+template <PrimType NameL, PrimType NameR>
+inline bool Shl(InterpState &S, CodePtr OpPC) {
+ using LT = typename PrimConv<NameL>::T;
+ using RT = typename PrimConv<NameR>::T;
+ const auto &RHS = S.Stk.pop<RT>();
+ const auto &LHS = S.Stk.pop<LT>();
const unsigned Bits = LHS.bitWidth();
- if (RHS.isSigned() && RHS.isNegative()) {
- const SourceInfo &Loc = S.Current->getSource(OpPC);
- S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
- return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
- } else {
- return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
- }
-}
+ if (!CheckShift<RT>(S, OpPC, RHS, Bits))
+ return false;
-template <PrimType TL, PrimType TR>
-inline bool Shl(InterpState &S, CodePtr OpPC) {
- const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
- const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
- const unsigned Bits = LHS.bitWidth();
+ unsigned URHS = static_cast<unsigned>(RHS);
+ S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) << URHS, LHS.bitWidth()));
- if (RHS.isSigned() && RHS.isNegative()) {
- const SourceInfo &Loc = S.Current->getSource(OpPC);
- S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
- return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
- } else {
- return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
- }
+ return true;
}
//===----------------------------------------------------------------------===//
@@ -950,26 +1253,56 @@ inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
return true;
}
+inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) {
+ auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
+ Pointer ThisPtr;
+ if (Func->hasThisPointer()) {
+ ThisPtr = NewFrame->getThis();
+ if (!CheckInvoke(S, PC, ThisPtr)) {
+ return false;
+ }
+ }
+
+ if (!CheckCallable(S, PC, Func))
+ return false;
+
+ InterpFrame *FrameBefore = S.Current;
+ S.Current = NewFrame.get();
+
+ APValue CallResult;
+ // Note that we cannot assert(CallResult.hasValue()) here since
+ // Ret() above only sets the APValue if the curent frame doesn't
+ // have a caller set.
+ if (Interpret(S, CallResult)) {
+ NewFrame.release(); // Frame was delete'd already.
+ assert(S.Current == FrameBefore);
+
+ // For constructors, check that all fields have been initialized.
+ if (Func->isConstructor() && !CheckCtorCall(S, PC, ThisPtr))
+ return false;
+
+ return true;
+ }
+
+ // Interpreting the function failed somehow. Reset to
+ // previous state.
+ S.Current = FrameBefore;
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
-template <typename T>
-inline std::enable_if_t<!std::is_pointer<T>::value, T> ReadArg(InterpState &S,
- CodePtr OpPC) {
- return OpPC.read<T>();
-}
-
-template <typename T>
-inline std::enable_if_t<std::is_pointer<T>::value, T> ReadArg(InterpState &S,
- CodePtr OpPC) {
- uint32_t ID = OpPC.read<uint32_t>();
- return reinterpret_cast<T>(S.P.getNativePointer(ID));
+template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
+ if constexpr (std::is_pointer<T>::value) {
+ uint32_t ID = OpPC.read<uint32_t>();
+ return reinterpret_cast<T>(S.P.getNativePointer(ID));
+ } else {
+ return OpPC.read<T>();
+ }
}
-/// Interpreter entry point.
-bool Interpret(InterpState &S, APValue &Result);
-
} // namespace interp
} // namespace clang
diff --git a/clang/lib/AST/Interp/InterpBlock.h b/clang/lib/AST/Interp/InterpBlock.h
index 2d5386e60b8c..f790c50a9123 100644
--- a/clang/lib/AST/Interp/InterpBlock.h
+++ b/clang/lib/AST/Interp/InterpBlock.h
@@ -31,11 +31,25 @@ enum PrimType : unsigned;
/// A memory block, either on the stack or in the heap.
///
-/// The storage described by the block immediately follows it in memory.
-class Block {
+/// The storage described by the block is immediately followed by
+/// optional metadata, which is followed by the actual data.
+///
+/// Block* rawData() data()
+/// │ │ │
+/// │ │ │
+/// ▼ ▼ ▼
+/// ┌───────────────┬─────────────────────────┬─────────────────┐
+/// │ Block │ Metadata │ Data │
+/// │ sizeof(Block) │ Desc->getMetadataSize() │ Desc->getSize() │
+/// └───────────────┴─────────────────────────┴─────────────────┘
+///
+/// Desc->getAllocSize() describes the size after the Block, i.e.
+/// the data size and the metadata size.
+///
+class Block final {
public:
// Creates a new block.
- Block(const llvm::Optional<unsigned> &DeclID, Descriptor *Desc,
+ Block(const std::optional<unsigned> &DeclID, Descriptor *Desc,
bool IsStatic = false, bool IsExtern = false)
: DeclID(DeclID), IsStatic(IsStatic), IsExtern(IsExtern), Desc(Desc) {}
@@ -56,10 +70,27 @@ public:
/// Returns the size of the block.
InterpSize getSize() const { return Desc->getAllocSize(); }
/// Returns the declaration ID.
- llvm::Optional<unsigned> getDeclID() const { return DeclID; }
+ std::optional<unsigned> getDeclID() const { return DeclID; }
/// Returns a pointer to the stored data.
- char *data() { return reinterpret_cast<char *>(this + 1); }
+ /// You are allowed to read Desc->getSize() bytes from this address.
+ char *data() {
+ // rawData might contain metadata as well.
+ size_t DataOffset = Desc->getMetadataSize();
+ return rawData() + DataOffset;
+ }
+ const char *data() const {
+ // rawData might contain metadata as well.
+ size_t DataOffset = Desc->getMetadataSize();
+ return rawData() + DataOffset;
+ }
+
+ /// Returns a pointer to the raw data, including metadata.
+ /// You are allowed to read Desc->getAllocSize() bytes from this address.
+ char *rawData() { return reinterpret_cast<char *>(this) + sizeof(Block); }
+ const char *rawData() const {
+ return reinterpret_cast<const char *>(this) + sizeof(Block);
+ }
/// Returns a view over the data.
template <typename T>
@@ -67,12 +98,18 @@ public:
/// Invokes the constructor.
void invokeCtor() {
- std::memset(data(), 0, getSize());
+ std::memset(rawData(), 0, Desc->getAllocSize());
if (Desc->CtorFn)
Desc->CtorFn(this, data(), Desc->IsConst, Desc->IsMutable,
/*isActive=*/true, Desc);
}
+ // Invokes the Destructor.
+ void invokeDtor() {
+ if (Desc->DtorFn)
+ Desc->DtorFn(this, data(), Desc);
+ }
+
protected:
friend class Pointer;
friend class DeadBlock;
@@ -92,7 +129,7 @@ protected:
/// Start of the chain of pointers.
Pointer *Pointers = nullptr;
/// Unique identifier of the declaration.
- llvm::Optional<unsigned> DeclID;
+ std::optional<unsigned> DeclID;
/// Flag indicating if the block has static storage duration.
bool IsStatic = false;
/// Flag indicating if the block is an extern.
@@ -107,7 +144,7 @@ protected:
///
/// Dead blocks are chained in a double-linked list to deallocate them
/// whenever pointers become dead.
-class DeadBlock {
+class DeadBlock final {
public:
/// Copies the block.
DeadBlock(DeadBlock *&Root, Block *Blk);
diff --git a/clang/lib/AST/Interp/InterpFrame.cpp b/clang/lib/AST/Interp/InterpFrame.cpp
index 9d01bf0333fe..40644c538c6a 100644
--- a/clang/lib/AST/Interp/InterpFrame.cpp
+++ b/clang/lib/AST/Interp/InterpFrame.cpp
@@ -7,37 +7,68 @@
//===----------------------------------------------------------------------===//
#include "InterpFrame.h"
+#include "Boolean.h"
#include "Function.h"
-#include "Interp.h"
#include "InterpStack.h"
+#include "InterpState.h"
+#include "Pointer.h"
#include "PrimType.h"
#include "Program.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
using namespace clang;
using namespace clang::interp;
-InterpFrame::InterpFrame(InterpState &S, Function *Func, InterpFrame *Caller,
- CodePtr RetPC, Pointer &&This)
- : Caller(Caller), S(S), Func(Func), This(std::move(This)), RetPC(RetPC),
+InterpFrame::InterpFrame(InterpState &S, const Function *Func,
+ InterpFrame *Caller, CodePtr RetPC)
+ : Caller(Caller), S(S), Func(Func), RetPC(RetPC),
ArgSize(Func ? Func->getArgSize() : 0),
Args(static_cast<char *>(S.Stk.top())), FrameOffset(S.Stk.size()) {
- if (Func) {
- if (unsigned FrameSize = Func->getFrameSize()) {
- Locals = std::make_unique<char[]>(FrameSize);
- for (auto &Scope : Func->scopes()) {
- for (auto &Local : Scope.locals()) {
- Block *B = new (localBlock(Local.Offset)) Block(Local.Desc);
- B->invokeCtor();
- }
- }
+ if (!Func)
+ return;
+
+ unsigned FrameSize = Func->getFrameSize();
+ if (FrameSize == 0)
+ return;
+
+ Locals = std::make_unique<char[]>(FrameSize);
+ for (auto &Scope : Func->scopes()) {
+ for (auto &Local : Scope.locals()) {
+ Block *B = new (localBlock(Local.Offset)) Block(Local.Desc);
+ B->invokeCtor();
+ InlineDescriptor *ID = localInlineDesc(Local.Offset);
+ ID->Desc = Local.Desc;
+ ID->IsActive = true;
+ ID->Offset = sizeof(InlineDescriptor);
+ ID->IsBase = false;
+ ID->IsFieldMutable = false;
+ ID->IsConst = false;
+ ID->IsInitialized = false;
}
}
}
+InterpFrame::InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC)
+ : InterpFrame(S, Func, S.Current, RetPC) {
+ // As per our calling convention, the this pointer is
+ // part of the ArgSize.
+ // If the function has RVO, the RVO pointer is first.
+ // If the fuction has a This pointer, that one is next.
+ // Then follow the actual arguments (but those are handled
+ // in getParamPointer()).
+ if (Func->hasRVO())
+ RVOPtr = stackRef<Pointer>(0);
+
+ if (Func->hasThisPointer()) {
+ if (Func->hasRVO())
+ This = stackRef<Pointer>(sizeof(Pointer));
+ else
+ This = stackRef<Pointer>(0);
+ }
+}
+
InterpFrame::~InterpFrame() {
- if (Func && Func->isConstructor() && This.isBaseClass())
- This.initialize();
for (auto &Param : Params)
S.deallocate(reinterpret_cast<Block *>(Param.second.get()));
}
@@ -95,17 +126,17 @@ void print(llvm::raw_ostream &OS, const Pointer &P, ASTContext &Ctx,
}
printDesc(P.getDeclDesc());
- for (auto It = Levels.rbegin(); It != Levels.rend(); ++It) {
- if (It->inArray()) {
- OS << "[" << It->expand().getIndex() << "]";
+ for (const auto &It : Levels) {
+ if (It.inArray()) {
+ OS << "[" << It.expand().getIndex() << "]";
continue;
}
- if (auto Index = It->getIndex()) {
+ if (auto Index = It.getIndex()) {
OS << " + " << Index;
continue;
}
OS << ".";
- printDesc(It->getFieldDesc());
+ printDesc(It.getFieldDesc());
}
}
@@ -117,16 +148,15 @@ void InterpFrame::describe(llvm::raw_ostream &OS) {
OS << "->";
}
OS << *F << "(";
- unsigned Off = Func->hasRVO() ? primSize(PT_Ptr) : 0;
+ unsigned Off = 0;
+
+ Off += Func->hasRVO() ? primSize(PT_Ptr) : 0;
+ Off += Func->hasThisPointer() ? primSize(PT_Ptr) : 0;
+
for (unsigned I = 0, N = F->getNumParams(); I < N; ++I) {
QualType Ty = F->getParamDecl(I)->getType();
- PrimType PrimTy;
- if (llvm::Optional<PrimType> T = S.Ctx.classify(Ty)) {
- PrimTy = *T;
- } else {
- PrimTy = PT_Ptr;
- }
+ PrimType PrimTy = S.Ctx.classify(Ty).value_or(PT_Ptr);
TYPE_SWITCH(PrimTy, print(OS, stackRef<T>(Off), S.getCtx(), Ty));
Off += align(primSize(PrimTy));
@@ -152,10 +182,10 @@ const FunctionDecl *InterpFrame::getCallee() const {
return Func->getDecl();
}
-Pointer InterpFrame::getLocalPointer(unsigned Offset) {
+Pointer InterpFrame::getLocalPointer(unsigned Offset) const {
assert(Offset < Func->getFrameSize() && "Invalid local offset.");
- return Pointer(
- reinterpret_cast<Block *>(Locals.get() + Offset - sizeof(Block)));
+ return Pointer(reinterpret_cast<Block *>(localBlock(Offset)),
+ sizeof(InlineDescriptor));
}
Pointer InterpFrame::getParamPointer(unsigned Off) {
diff --git a/clang/lib/AST/Interp/InterpFrame.h b/clang/lib/AST/Interp/InterpFrame.h
index 304e2ad66537..bfa02c90ebec 100644
--- a/clang/lib/AST/Interp/InterpFrame.h
+++ b/clang/lib/AST/Interp/InterpFrame.h
@@ -14,7 +14,6 @@
#define LLVM_CLANG_AST_INTERP_INTERPFRAME_H
#include "Frame.h"
-#include "Pointer.h"
#include "Program.h"
#include "State.h"
#include <cstdint>
@@ -24,6 +23,7 @@ namespace clang {
namespace interp {
class Function;
class InterpState;
+class Pointer;
/// Frame storing local variables.
class InterpFrame final : public Frame {
@@ -32,8 +32,14 @@ public:
InterpFrame *Caller;
/// Creates a new frame for a method call.
- InterpFrame(InterpState &S, Function *Func, InterpFrame *Caller,
- CodePtr RetPC, Pointer &&This);
+ InterpFrame(InterpState &S, const Function *Func, InterpFrame *Caller,
+ CodePtr RetPC);
+
+ /// Creates a new frame with the values that make sense.
+ /// I.e., the caller is the current frame of S,
+ /// the This() pointer is the current Pointer on the top of S's stack,
+ /// and the RVO pointer is before that.
+ InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC);
/// Destroys the frame, killing all live pointers to stack slots.
~InterpFrame();
@@ -57,26 +63,27 @@ public:
const FunctionDecl *getCallee() const override;
/// Returns the current function.
- Function *getFunction() const { return Func; }
+ const Function *getFunction() const { return Func; }
/// Returns the offset on the stack at which the frame starts.
size_t getFrameOffset() const { return FrameOffset; }
/// Returns the value of a local variable.
- template <typename T> const T &getLocal(unsigned Offset) {
+ template <typename T> const T &getLocal(unsigned Offset) const {
return localRef<T>(Offset);
}
/// Mutates a local variable.
template <typename T> void setLocal(unsigned Offset, const T &Value) {
localRef<T>(Offset) = Value;
+ localInlineDesc(Offset)->IsInitialized = true;
}
/// Returns a pointer to a local variables.
- Pointer getLocalPointer(unsigned Offset);
+ Pointer getLocalPointer(unsigned Offset) const;
/// Returns the value of an argument.
- template <typename T> const T &getParam(unsigned Offset) {
+ template <typename T> const T &getParam(unsigned Offset) const {
auto Pt = Params.find(Offset);
if (Pt == Params.end()) {
return stackRef<T>(Offset);
@@ -96,6 +103,9 @@ public:
/// Returns the 'this' pointer.
const Pointer &getThis() const { return This; }
+ /// Returns the RVO pointer, if the Function has one.
+ const Pointer &getRVOPtr() const { return RVOPtr; }
+
/// Checks if the frame is a root frame - return should quit the interpreter.
bool isRoot() const { return !Func; }
@@ -112,27 +122,35 @@ public:
private:
/// Returns an original argument from the stack.
- template <typename T> const T &stackRef(unsigned Offset) {
+ template <typename T> const T &stackRef(unsigned Offset) const {
+ assert(Args);
return *reinterpret_cast<const T *>(Args - ArgSize + Offset);
}
/// Returns an offset to a local.
- template <typename T> T &localRef(unsigned Offset) {
- return *reinterpret_cast<T *>(Locals.get() + Offset);
+ template <typename T> T &localRef(unsigned Offset) const {
+ return getLocalPointer(Offset).deref<T>();
}
/// Returns a pointer to a local's block.
- void *localBlock(unsigned Offset) {
+ void *localBlock(unsigned Offset) const {
return Locals.get() + Offset - sizeof(Block);
}
+ // Returns the inline descriptor of the local.
+ InlineDescriptor *localInlineDesc(unsigned Offset) const {
+ return reinterpret_cast<InlineDescriptor *>(Locals.get() + Offset);
+ }
+
private:
/// Reference to the interpreter state.
InterpState &S;
/// Reference to the function being executed.
- Function *Func;
+ const Function *Func;
/// Current object pointer for methods.
Pointer This;
+ /// Pointer the non-primitive return value gets constructed in.
+ Pointer RVOPtr;
/// Return address.
CodePtr RetPC;
/// The size of all the arguments.
diff --git a/clang/lib/AST/Interp/InterpStack.cpp b/clang/lib/AST/Interp/InterpStack.cpp
index 5c803f3d9424..7fe678e62192 100644
--- a/clang/lib/AST/Interp/InterpStack.cpp
+++ b/clang/lib/AST/Interp/InterpStack.cpp
@@ -46,7 +46,7 @@ void *InterpStack::grow(size_t Size) {
return Object;
}
-void *InterpStack::peek(size_t Size) {
+void *InterpStack::peek(size_t Size) const {
assert(Chunk && "Stack is empty!");
StackChunk *Ptr = Chunk;
diff --git a/clang/lib/AST/Interp/InterpStack.h b/clang/lib/AST/Interp/InterpStack.h
index b02d3c6a34b0..3adaad96515e 100644
--- a/clang/lib/AST/Interp/InterpStack.h
+++ b/clang/lib/AST/Interp/InterpStack.h
@@ -13,7 +13,9 @@
#ifndef LLVM_CLANG_AST_INTERP_INTERPSTACK_H
#define LLVM_CLANG_AST_INTERP_INTERPSTACK_H
+#include "PrimType.h"
#include <memory>
+#include <vector>
namespace clang {
namespace interp {
@@ -29,10 +31,18 @@ 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
auto *Ptr = &peek<T>();
auto Value = std::move(*Ptr);
Ptr->~T();
@@ -42,18 +52,22 @@ public:
/// Discards the top value from the stack.
template <typename T> void discard() {
+#ifndef NDEBUG
+ assert(ItemTypes.back() == toPrimType<T>());
+ ItemTypes.pop_back();
+#endif
auto *Ptr = &peek<T>();
Ptr->~T();
shrink(aligned_size<T>());
}
/// Returns a reference to the value on the top of the stack.
- template <typename T> T &peek() {
+ template <typename T> T &peek() const {
return *reinterpret_cast<T *>(peek(aligned_size<T>()));
}
/// Returns a pointer to the top object.
- void *top() { return Chunk ? peek(0) : nullptr; }
+ void *top() const { return Chunk ? peek(0) : nullptr; }
/// Returns the size of the stack in bytes.
size_t size() const { return StackSize; }
@@ -61,6 +75,9 @@ public:
/// Clears the stack without calling any destructors.
void clear();
+ // Returns whether the stack is empty.
+ bool empty() const { return StackSize == 0; }
+
private:
/// All stack slots are aligned to the native pointer alignment for storage.
/// The size of an object is rounded up to a pointer alignment multiple.
@@ -72,7 +89,7 @@ private:
/// Grows the stack to accommodate a value and returns a pointer to it.
void *grow(size_t Size);
/// Returns a pointer from the top of the stack.
- void *peek(size_t Size);
+ void *peek(size_t Size) const;
/// Shrinks the stack.
void shrink(size_t Size);
@@ -94,10 +111,13 @@ private:
: Next(nullptr), Prev(Prev), End(reinterpret_cast<char *>(this + 1)) {}
/// Returns the size of the chunk, minus the header.
- size_t size() { return End - start(); }
+ size_t size() const { return End - start(); }
/// Returns a pointer to the start of the data region.
char *start() { return reinterpret_cast<char *>(this + 1); }
+ const char *start() const {
+ return reinterpret_cast<const char *>(this + 1);
+ }
};
static_assert(sizeof(StackChunk) < ChunkSize, "Invalid chunk size");
@@ -105,6 +125,45 @@ private:
StackChunk *Chunk = nullptr;
/// 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;
+
+ template <typename T> static constexpr PrimType toPrimType() {
+ if constexpr (std::is_same_v<T, Pointer>)
+ return PT_Ptr;
+ else if constexpr (std::is_same_v<T, bool> ||
+ std::is_same_v<T, Boolean>)
+ return PT_Bool;
+ else if constexpr (std::is_same_v<T, int8_t> ||
+ std::is_same_v<T, Integral<8, true>>)
+ return PT_Sint8;
+ else if constexpr (std::is_same_v<T, uint8_t> ||
+ std::is_same_v<T, Integral<8, false>>)
+ return PT_Uint8;
+ else if constexpr (std::is_same_v<T, int16_t> ||
+ std::is_same_v<T, Integral<16, true>>)
+ return PT_Sint16;
+ else if constexpr (std::is_same_v<T, uint16_t> ||
+ std::is_same_v<T, Integral<16, false>>)
+ return PT_Uint16;
+ else if constexpr (std::is_same_v<T, int32_t> ||
+ std::is_same_v<T, Integral<32, true>>)
+ return PT_Sint32;
+ else if constexpr (std::is_same_v<T, uint32_t> ||
+ std::is_same_v<T, Integral<32, false>>)
+ return PT_Uint32;
+ else if constexpr (std::is_same_v<T, int64_t> ||
+ std::is_same_v<T, Integral<64, true>>)
+ return PT_Sint64;
+ else if constexpr (std::is_same_v<T, uint64_t> ||
+ std::is_same_v<T, Integral<64, false>>)
+ return PT_Uint64;
+
+ llvm_unreachable("unknown type push()'ed into InterpStack");
+ }
+#endif
};
} // namespace interp
diff --git a/clang/lib/AST/Interp/InterpState.h b/clang/lib/AST/Interp/InterpState.h
index 57e36c4c63ea..033080637385 100644
--- a/clang/lib/AST/Interp/InterpState.h
+++ b/clang/lib/AST/Interp/InterpState.h
@@ -65,6 +65,7 @@ public:
bool noteUndefinedBehavior() override {
return Parent.noteUndefinedBehavior();
}
+ bool inConstantContext() const { return Parent.InConstantContext; }
bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); }
void setActiveDiagnostic(bool Flag) override {
Parent.setActiveDiagnostic(Flag);
@@ -81,7 +82,7 @@ public:
void deallocate(Block *B);
/// Delegates source mapping to the mapper.
- SourceInfo getSource(Function *F, CodePtr PC) const override {
+ SourceInfo getSource(const Function *F, CodePtr PC) const override {
return M ? M->getSource(F, PC) : F->getSource(PC);
}
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 638d5b3d2357..058475b2d399 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -42,18 +42,8 @@ def ArgSint64 : ArgType { let Name = "int64_t"; }
def ArgUint64 : ArgType { let Name = "uint64_t"; }
def ArgBool : ArgType { let Name = "bool"; }
-def ArgFunction : ArgType { let Name = "Function *"; }
-def ArgRecord : ArgType { let Name = "Record *"; }
-
-def ArgSema : ArgType { let Name = "const fltSemantics *"; }
-
-def ArgExpr : ArgType { let Name = "const Expr *"; }
-def ArgFloatingLiteral : ArgType { let Name = "const FloatingLiteral *"; }
-def ArgCXXMethodDecl : ArgType { let Name = "const CXXMethodDecl *"; }
-def ArgFunctionDecl : ArgType { let Name = "const FunctionDecl *"; }
+def ArgFunction : ArgType { let Name = "const Function *"; }
def ArgRecordDecl : ArgType { let Name = "const RecordDecl *"; }
-def ArgCXXRecordDecl : ArgType { let Name = "const CXXRecordDecl *"; }
-def ArgValueDecl : ArgType { let Name = "const ValueDecl *"; }
def ArgRecordField : ArgType { let Name = "const Record::Field *"; }
//===----------------------------------------------------------------------===//
@@ -64,15 +54,28 @@ class TypeClass {
list<Type> Types;
}
-def AluTypeClass : TypeClass {
+def NumberTypeClass : TypeClass {
+ let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
+ Uint32, Sint64, Uint64];
+}
+
+def IntegerTypeClass : TypeClass {
let Types = [Sint8, Uint8, Sint16, Uint16, Sint32,
- Uint32, Sint64, Uint64, Bool];
+ Uint32, Sint64, Uint64];
+}
+
+def AluTypeClass : TypeClass {
+ let Types = !listconcat(NumberTypeClass.Types, [Bool]);
}
def PtrTypeClass : TypeClass {
let Types = [Ptr];
}
+def BoolTypeClass : TypeClass {
+ let Types = [Bool];
+}
+
def AllTypeClass : TypeClass {
let Types = !listconcat(AluTypeClass.Types, PtrTypeClass.Types);
}
@@ -105,6 +108,11 @@ class AluOpcode : Opcode {
let HasGroup = 1;
}
+class IntegerOpcode : Opcode {
+ let Types = [IntegerTypeClass];
+ let HasGroup = 1;
+}
+
//===----------------------------------------------------------------------===//
// Jump opcodes
//===----------------------------------------------------------------------===//
@@ -149,6 +157,13 @@ def RetValue : Opcode {
// [] -> EXIT
def NoRet : Opcode {}
+
+def Call : Opcode {
+ let Args = [ArgFunction];
+ let Types = [];
+ let ChangesPC = 1;
+}
+
//===----------------------------------------------------------------------===//
// Frame management
//===----------------------------------------------------------------------===//
@@ -183,6 +198,7 @@ def ConstBool : ConstOpcode<Bool, ArgBool>;
// [] -> [Integer]
def Zero : Opcode {
let Types = [AluTypeClass];
+ let HasGroup = 1;
}
// [] -> [Pointer]
@@ -253,6 +269,9 @@ def GetPtrThisVirtBase : Opcode {
// [] -> [Pointer]
def This : Opcode;
+// [] -> [Pointer]
+def RVOPtr : Opcode;
+
// [Pointer] -> [Pointer]
def NarrowPtr : Opcode;
// [Pointer] -> [Pointer]
@@ -374,6 +393,12 @@ def AddOffset : AluOpcode;
// [Pointer, Integral] -> [Pointer]
def SubOffset : AluOpcode;
+// Pointer, Pointer] - [Integral]
+def SubPtr : Opcode {
+ let Types = [IntegerTypeClass];
+ let HasGroup = 1;
+}
+
//===----------------------------------------------------------------------===//
// Binary operators.
//===----------------------------------------------------------------------===//
@@ -382,6 +407,73 @@ def SubOffset : AluOpcode;
def Sub : AluOpcode;
def Add : AluOpcode;
def Mul : AluOpcode;
+def Rem : Opcode {
+ let Types = [NumberTypeClass];
+ let HasGroup = 1;
+}
+
+def Shl : Opcode {
+ let Types = [IntegerTypeClass, IntegerTypeClass];
+ let HasGroup = 1;
+}
+
+def Shr : Opcode {
+ let Types = [IntegerTypeClass, IntegerTypeClass];
+ let HasGroup = 1;
+}
+
+def BitAnd : IntegerOpcode;
+def BitOr : IntegerOpcode;
+def Div : Opcode {
+ let Types = [NumberTypeClass];
+ let HasGroup = 1;
+}
+def BitXor : IntegerOpcode;
+
+//===----------------------------------------------------------------------===//
+// Unary operators.
+//===----------------------------------------------------------------------===//
+
+// [Real] -> [Real]
+def Inv: Opcode {
+ let Types = [BoolTypeClass];
+ let HasGroup = 1;
+}
+
+def Inc: IntegerOpcode;
+def IncPop : IntegerOpcode;
+def Dec: IntegerOpcode;
+def DecPop: IntegerOpcode;
+
+// [Real] -> [Real]
+def Neg: Opcode {
+ let Types = [AluTypeClass];
+ let HasGroup = 1;
+}
+
+// [Real] -> [Real]
+def Comp: Opcode {
+ let Types = [NumberTypeClass];
+ let HasGroup = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Cast.
+//===----------------------------------------------------------------------===//
+// TODO: Expand this to handle casts between more types.
+
+def FromCastTypeClass : TypeClass {
+ let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
+}
+
+def ToCastTypeClass : TypeClass {
+ let Types = [Uint8, Sint8, Uint16, Sint16, Uint32, Sint32, Uint64, Sint64, Bool];
+}
+
+def Cast: Opcode {
+ let Types = [FromCastTypeClass, ToCastTypeClass];
+ let HasGroup = 1;
+}
//===----------------------------------------------------------------------===//
// Comparison opcodes.
diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp
index ef2638e2a36b..fd8c98fae039 100644
--- a/clang/lib/AST/Interp/Pointer.cpp
+++ b/clang/lib/AST/Interp/Pointer.cpp
@@ -16,6 +16,9 @@ using namespace clang::interp;
Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
+Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
+ : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
+
Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
Pointer::Pointer(Pointer &&P)
@@ -106,7 +109,7 @@ APValue Pointer::toAPValue() const {
// Build the path into the object.
Pointer Ptr = *this;
- while (Ptr.isField()) {
+ while (Ptr.isField() || Ptr.isArrayElement()) {
if (Ptr.isArrayElement()) {
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
Ptr = Ptr.getArray();
@@ -129,14 +132,21 @@ APValue Pointer::toAPValue() const {
}
}
+ // We assemble the LValuePath starting from the innermost pointer to the
+ // outermost one. SO in a.b.c, the first element in Path will refer to
+ // the field 'c', while later code expects it to refer to 'a'.
+ // Just invert the order of the elements.
+ std::reverse(Path.begin(), Path.end());
+
return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
}
bool Pointer::isInitialized() const {
assert(Pointee && "Cannot check if null pointer was initialized");
Descriptor *Desc = getFieldDesc();
+ assert(Desc);
if (Desc->isPrimitiveArray()) {
- if (Pointee->IsStatic)
+ if (isStatic() && Base == 0)
return true;
// Primitive array field are stored in a bitset.
InitMap *Map = getInitMap();
@@ -154,8 +164,14 @@ bool Pointer::isInitialized() const {
void Pointer::initialize() const {
assert(Pointee && "Cannot initialize null pointer");
Descriptor *Desc = getFieldDesc();
- if (Desc->isPrimitiveArray()) {
- if (!Pointee->IsStatic) {
+
+ assert(Desc);
+ if (Desc->isArray()) {
+ if (Desc->isPrimitiveArray()) {
+ // Primitive global arrays don't have an initmap.
+ if (isStatic() && Base == 0)
+ return;
+
// Primitive array initializer.
InitMap *&Map = getInitMap();
if (Map == (InitMap *)-1)
@@ -189,5 +205,5 @@ bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
}
bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
- return A.Base == B.Base && A.getFieldDesc()->IsArray;
+ return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
}
diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h
index 587531aec82a..1462d01c2412 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -33,14 +33,40 @@ enum PrimType : unsigned;
///
/// This object can be allocated into interpreter stack frames. If pointing to
/// a live block, it is a link in the chain of pointers pointing to the block.
+///
+/// In the simplest form, a Pointer has a Block* (the pointee) and both Base
+/// and Offset are 0, which means it will point to raw data.
+///
+/// The Base field is used to access metadata about the data. For primitive
+/// arrays, the Base is followed by an InitMap. In a variety of cases, the
+/// Base is preceded by an InlineDescriptor, which is used to track the
+/// initialization state, among other things.
+///
+/// The Offset field is used to access the actual data. In other words, the
+/// data the pointer decribes can be found at
+/// Pointee->rawData() + Pointer.Offset.
+///
+///
+/// Pointee Offset
+/// │ │
+/// │ │
+/// ▼ ▼
+/// ┌───────┬────────────┬─────────┬────────────────────────────┐
+/// │ Block │ InlineDesc │ InitMap │ Actual Data │
+/// └───────┴────────────┴─────────┴────────────────────────────┘
+/// ▲
+/// │
+/// │
+/// Base
class Pointer {
private:
- static constexpr unsigned PastEndMark = (unsigned)-1;
- static constexpr unsigned RootPtrMark = (unsigned)-1;
+ static constexpr unsigned PastEndMark = ~0u;
+ static constexpr unsigned RootPtrMark = ~0u;
public:
Pointer() {}
Pointer(Block *B);
+ Pointer(Block *B, unsigned BaseAndOffset);
Pointer(const Pointer &P);
Pointer(Pointer &&P);
~Pointer();
@@ -216,6 +242,8 @@ public:
/// Returns the record descriptor of a class.
Record *getRecord() const { return getFieldDesc()->ElemRecord; }
+ // Returns the element record type, if this is a non-primive array.
+ Record *getElemRecord() const { return getFieldDesc()->ElemDesc->ElemRecord; }
/// Returns the field information.
const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
@@ -232,7 +260,9 @@ public:
bool isStaticTemporary() const { return isStatic() && isTemporary(); }
/// Checks if the field is mutable.
- bool isMutable() const { return Base != 0 && getInlineDesc()->IsMutable; }
+ bool isMutable() const {
+ return Base != 0 && getInlineDesc()->IsFieldMutable;
+ }
/// Checks if an object was initialized.
bool isInitialized() const;
/// Checks if the object is active.
@@ -246,7 +276,7 @@ public:
}
/// Returns the declaration ID.
- llvm::Optional<unsigned> getDeclID() const { return Pointee->getDeclID(); }
+ std::optional<unsigned> getDeclID() const { return Pointee->getDeclID(); }
/// Returns the byte offset from the start.
unsigned getByteOffset() const {
@@ -276,12 +306,12 @@ public:
/// Dereferences the pointer, if it's live.
template <typename T> T &deref() const {
assert(isLive() && "Invalid pointer");
- return *reinterpret_cast<T *>(Pointee->data() + Offset);
+ return *reinterpret_cast<T *>(Pointee->rawData() + Offset);
}
/// Dereferences a primitive element.
template <typename T> T &elem(unsigned I) const {
- return reinterpret_cast<T *>(Pointee->data())[I];
+ return reinterpret_cast<T *>(Pointee->rawData())[I];
}
/// Initializes a field.
@@ -298,7 +328,7 @@ public:
/// Prints the pointer.
void print(llvm::raw_ostream &OS) const {
- OS << "{" << Base << ", " << Offset << ", ";
+ OS << Pointee << " {" << Base << ", " << Offset << ", ";
if (Pointee)
OS << Pointee->getSize();
else
@@ -318,12 +348,13 @@ private:
/// Returns a descriptor at a given offset.
InlineDescriptor *getDescriptor(unsigned Offset) const {
assert(Offset != 0 && "Not a nested pointer");
- return reinterpret_cast<InlineDescriptor *>(Pointee->data() + Offset) - 1;
+ return reinterpret_cast<InlineDescriptor *>(Pointee->rawData() + Offset) -
+ 1;
}
/// Returns a reference to the pointer which stores the initialization map.
InitMap *&getInitMap() const {
- return *reinterpret_cast<InitMap **>(Pointee->data() + Base);
+ return *reinterpret_cast<InitMap **>(Pointee->rawData() + Base);
}
/// The block the pointer is pointing to.
diff --git a/clang/lib/AST/Interp/PrimType.cpp b/clang/lib/AST/Interp/PrimType.cpp
index 082bfaf3c207..eda90e1c36c2 100644
--- a/clang/lib/AST/Interp/PrimType.cpp
+++ b/clang/lib/AST/Interp/PrimType.cpp
@@ -1,4 +1,4 @@
-//===--- Type.cpp - Types for the constexpr VM ------------------*- C++ -*-===//
+//===--- PrimType.cpp - Types for the constexpr VM --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,6 +7,8 @@
//===----------------------------------------------------------------------===//
#include "PrimType.h"
+#include "Boolean.h"
+#include "Pointer.h"
using namespace clang;
using namespace clang::interp;
diff --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h
index de4bf9bf802e..c8f2a600fb3c 100644
--- a/clang/lib/AST/Interp/PrimType.h
+++ b/clang/lib/AST/Interp/PrimType.h
@@ -13,16 +13,17 @@
#ifndef LLVM_CLANG_AST_INTERP_TYPE_H
#define LLVM_CLANG_AST_INTERP_TYPE_H
+#include "Integral.h"
#include <climits>
#include <cstddef>
#include <cstdint>
-#include "Boolean.h"
-#include "Integral.h"
-#include "Pointer.h"
namespace clang {
namespace interp {
+class Pointer;
+class Boolean;
+
/// Enumeration of the primitive types of the VM.
enum PrimType : unsigned {
PT_Sint8,
@@ -58,6 +59,13 @@ constexpr size_t align(size_t Size) {
return ((Size + alignof(void *) - 1) / alignof(void *)) * alignof(void *);
}
+constexpr bool aligned(uintptr_t Value) { return Value == align(Value); }
+static_assert(aligned(sizeof(void *)));
+
+static inline bool aligned(const void *P) {
+ return aligned(reinterpret_cast<uintptr_t>(P));
+}
+
inline bool isPrimitiveIntegral(PrimType Type) {
switch (Type) {
case PT_Bool:
diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp
index e310c9678140..5305ddd8de18 100644
--- a/clang/lib/AST/Interp/Program.cpp
+++ b/clang/lib/AST/Interp/Program.cpp
@@ -53,10 +53,11 @@ unsigned Program::createGlobalString(const StringLiteral *S) {
}
// Create a descriptor for the string.
- Descriptor *Desc = allocateDescriptor(S, CharType, S->getLength() + 1,
- /*isConst=*/true,
- /*isTemporary=*/false,
- /*isMutable=*/false);
+ Descriptor *Desc =
+ allocateDescriptor(S, CharType, std::nullopt, S->getLength() + 1,
+ /*isConst=*/true,
+ /*isTemporary=*/false,
+ /*isMutable=*/false);
// Allocate storage for the string.
// The byte length does not include the null terminator.
@@ -64,6 +65,7 @@ unsigned Program::createGlobalString(const StringLiteral *S) {
unsigned Sz = Desc->getAllocSize();
auto *G = new (Allocator, Sz) Global(Desc, /*isStatic=*/true,
/*isExtern=*/false);
+ G->block()->invokeCtor();
Globals.push_back(G);
// Construct the string in storage.
@@ -99,13 +101,13 @@ Pointer Program::getPtrGlobal(unsigned Idx) {
return Pointer(Globals[Idx]->block());
}
-llvm::Optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
+std::optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
auto It = GlobalIndices.find(VD);
if (It != GlobalIndices.end())
return It->second;
// Find any previous declarations which were already evaluated.
- llvm::Optional<unsigned> Index;
+ std::optional<unsigned> Index;
for (const Decl *P = VD; P; P = P->getPreviousDecl()) {
auto It = GlobalIndices.find(P);
if (It != GlobalIndices.end()) {
@@ -123,18 +125,19 @@ llvm::Optional<unsigned> Program::getGlobal(const ValueDecl *VD) {
return Index;
}
-llvm::Optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD) {
+std::optional<unsigned> Program::getOrCreateGlobal(const ValueDecl *VD,
+ const Expr *Init) {
if (auto Idx = getGlobal(VD))
return Idx;
- if (auto Idx = createGlobal(VD)) {
+ if (auto Idx = createGlobal(VD, Init)) {
GlobalIndices[VD] = *Idx;
return Idx;
}
return {};
}
-llvm::Optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) {
+std::optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) {
auto &ASTCtx = Ctx.getASTContext();
// Create a pointer to an incomplete array of the specified elements.
@@ -153,7 +156,9 @@ llvm::Optional<unsigned> Program::getOrCreateDummy(const ParmVarDecl *PD) {
return {};
}
-llvm::Optional<unsigned> Program::createGlobal(const ValueDecl *VD) {
+std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
+ const Expr *Init) {
+ assert(!getGlobal(VD));
bool IsStatic, IsExtern;
if (auto *Var = dyn_cast<VarDecl>(VD)) {
IsStatic = !Var->hasLocalStorage();
@@ -162,7 +167,7 @@ llvm::Optional<unsigned> Program::createGlobal(const ValueDecl *VD) {
IsStatic = false;
IsExtern = true;
}
- if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern)) {
+ if (auto Idx = createGlobal(VD, VD->getType(), IsStatic, IsExtern, Init)) {
for (const Decl *P = VD; P; P = P->getPreviousDecl())
GlobalIndices[P] = *Idx;
return *Idx;
@@ -170,20 +175,22 @@ llvm::Optional<unsigned> Program::createGlobal(const ValueDecl *VD) {
return {};
}
-llvm::Optional<unsigned> Program::createGlobal(const Expr *E) {
+std::optional<unsigned> Program::createGlobal(const Expr *E) {
return createGlobal(E, E->getType(), /*isStatic=*/true, /*isExtern=*/false);
}
-llvm::Optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
- bool IsStatic, bool IsExtern) {
+std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
+ bool IsStatic, bool IsExtern,
+ const Expr *Init) {
// Create a descriptor for the global.
Descriptor *Desc;
const bool IsConst = Ty.isConstQualified();
const bool IsTemporary = D.dyn_cast<const Expr *>();
if (auto T = Ctx.classify(Ty)) {
- Desc = createDescriptor(D, *T, IsConst, IsTemporary);
+ Desc = createDescriptor(D, *T, std::nullopt, IsConst, IsTemporary);
} else {
- Desc = createDescriptor(D, Ty.getTypePtr(), IsConst, IsTemporary);
+ Desc = createDescriptor(D, Ty.getTypePtr(), std::nullopt, IsConst,
+ IsTemporary);
}
if (!Desc)
return {};
@@ -201,24 +208,12 @@ llvm::Optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
}
Function *Program::getFunction(const FunctionDecl *F) {
- F = F->getDefinition();
+ F = F->getCanonicalDecl();
+ assert(F);
auto It = Funcs.find(F);
return It == Funcs.end() ? nullptr : It->second.get();
}
-llvm::Expected<Function *> Program::getOrCreateFunction(const FunctionDecl *F) {
- if (Function *Func = getFunction(F)) {
- return Func;
- }
-
- // Try to compile the function if it wasn't compiled yet.
- if (const FunctionDecl *FD = F->getDefinition())
- return ByteCodeStmtGen<ByteCodeEmitter>(Ctx, *this).compileFunc(FD);
-
- // A relocation which traps if not resolved.
- return nullptr;
-}
-
Record *Program::getOrCreateRecord(const RecordDecl *RD) {
// Use the actual definition as a key.
RD = RD->getDefinition();
@@ -231,8 +226,13 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
return It->second;
}
+ // We insert nullptr now and replace that later, so recursive calls
+ // to this function with the same RecordDecl don't run into
+ // infinite recursion.
+ Records.insert({RD, nullptr});
+
// Number of bytes required by fields and base classes.
- unsigned Size = 0;
+ unsigned BaseSize = 0;
// Number of bytes required by virtual base.
unsigned VirtSize = 0;
@@ -240,7 +240,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
auto GetBaseDesc = [this](const RecordDecl *BD, Record *BR) -> Descriptor * {
if (!BR)
return nullptr;
- return allocateDescriptor(BD, BR, /*isConst=*/false,
+ return allocateDescriptor(BD, BR, std::nullopt, /*isConst=*/false,
/*isTemporary=*/false,
/*isMutable=*/false);
};
@@ -256,9 +256,9 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
const RecordDecl *BD = Spec.getType()->castAs<RecordType>()->getDecl();
Record *BR = getOrCreateRecord(BD);
if (Descriptor *Desc = GetBaseDesc(BD, BR)) {
- Size += align(sizeof(InlineDescriptor));
- Bases.push_back({BD, Size, Desc, BR});
- Size += align(BR->getSize());
+ BaseSize += align(sizeof(InlineDescriptor));
+ Bases.push_back({BD, BaseSize, Desc, BR});
+ BaseSize += align(BR->getSize());
continue;
}
return nullptr;
@@ -282,39 +282,41 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
Record::FieldList Fields;
for (const FieldDecl *FD : RD->fields()) {
// Reserve space for the field's descriptor and the offset.
- Size += align(sizeof(InlineDescriptor));
+ BaseSize += align(sizeof(InlineDescriptor));
// Classify the field and add its metadata.
QualType FT = FD->getType();
const bool IsConst = FT.isConstQualified();
const bool IsMutable = FD->isMutable();
Descriptor *Desc;
- if (llvm::Optional<PrimType> T = Ctx.classify(FT)) {
- Desc = createDescriptor(FD, *T, IsConst, /*isTemporary=*/false,
- IsMutable);
+ if (std::optional<PrimType> T = Ctx.classify(FT)) {
+ Desc = createDescriptor(FD, *T, std::nullopt, IsConst,
+ /*isTemporary=*/false, IsMutable);
} else {
- Desc = createDescriptor(FD, FT.getTypePtr(), IsConst,
+ Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst,
/*isTemporary=*/false, IsMutable);
}
if (!Desc)
return nullptr;
- Fields.push_back({FD, Size, Desc});
- Size += align(Desc->getAllocSize());
+ Fields.push_back({FD, BaseSize, Desc});
+ BaseSize += align(Desc->getAllocSize());
}
Record *R = new (Allocator) Record(RD, std::move(Bases), std::move(Fields),
- std::move(VirtBases), VirtSize, Size);
- Records.insert({RD, R});
+ std::move(VirtBases), VirtSize, BaseSize);
+ Records[RD] = R;
return R;
}
Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
+ Descriptor::MetadataSize MDSize,
bool IsConst, bool IsTemporary,
- bool IsMutable) {
+ bool IsMutable, const Expr *Init) {
// Classes and structures.
if (auto *RT = Ty->getAs<RecordType>()) {
if (auto *Record = getOrCreateRecord(RT->getDecl()))
- return allocateDescriptor(D, Record, IsConst, IsTemporary, IsMutable);
+ return allocateDescriptor(D, Record, MDSize, IsConst, IsTemporary,
+ IsMutable);
}
// Arrays.
@@ -323,38 +325,39 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
// Array of well-known bounds.
if (auto CAT = dyn_cast<ConstantArrayType>(ArrayType)) {
size_t NumElems = CAT->getSize().getZExtValue();
- if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
+ if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
// Arrays of primitives.
unsigned ElemSize = primSize(*T);
if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems) {
return {};
}
- return allocateDescriptor(D, *T, NumElems, IsConst, IsTemporary,
+ return allocateDescriptor(D, *T, MDSize, NumElems, IsConst, IsTemporary,
IsMutable);
} else {
// Arrays of composites. In this case, the array is a list of pointers,
// followed by the actual elements.
- Descriptor *Desc =
- createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
- if (!Desc)
+ Descriptor *ElemDesc = createDescriptor(
+ D, ElemTy.getTypePtr(), std::nullopt, IsConst, IsTemporary);
+ if (!ElemDesc)
return nullptr;
- InterpSize ElemSize = Desc->getAllocSize() + sizeof(InlineDescriptor);
+ InterpSize ElemSize =
+ ElemDesc->getAllocSize() + sizeof(InlineDescriptor);
if (std::numeric_limits<unsigned>::max() / ElemSize <= NumElems)
return {};
- return allocateDescriptor(D, Desc, NumElems, IsConst, IsTemporary,
- IsMutable);
+ return allocateDescriptor(D, ElemDesc, MDSize, NumElems, IsConst,
+ IsTemporary, IsMutable);
}
}
// Array of unknown bounds - cannot be accessed and pointer arithmetic
// is forbidden on pointers to such objects.
if (isa<IncompleteArrayType>(ArrayType)) {
- if (llvm::Optional<PrimType> T = Ctx.classify(ElemTy)) {
+ if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
return allocateDescriptor(D, *T, IsTemporary,
Descriptor::UnknownSize{});
} else {
- Descriptor *Desc =
- createDescriptor(D, ElemTy.getTypePtr(), IsConst, IsTemporary);
+ Descriptor *Desc = createDescriptor(D, ElemTy.getTypePtr(), MDSize,
+ IsConst, IsTemporary);
if (!Desc)
return nullptr;
return allocateDescriptor(D, Desc, IsTemporary,
@@ -366,13 +369,15 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
// Atomic types.
if (auto *AT = Ty->getAs<AtomicType>()) {
const Type *InnerTy = AT->getValueType().getTypePtr();
- return createDescriptor(D, InnerTy, IsConst, IsTemporary, IsMutable);
+ return createDescriptor(D, InnerTy, MDSize, IsConst, IsTemporary,
+ IsMutable);
}
// Complex types - represented as arrays of elements.
if (auto *CT = Ty->getAs<ComplexType>()) {
PrimType ElemTy = *Ctx.classify(CT->getElementType());
- return allocateDescriptor(D, ElemTy, 2, IsConst, IsTemporary, IsMutable);
+ return allocateDescriptor(D, ElemTy, MDSize, 2, IsConst, IsTemporary,
+ IsMutable);
}
return nullptr;
diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h
index ca985af8ad30..5a80dd1ed748 100644
--- a/clang/lib/AST/Interp/Program.h
+++ b/clang/lib/AST/Interp/Program.h
@@ -37,10 +37,26 @@ class Context;
class Record;
/// The program contains and links the bytecode for all functions.
-class Program {
+class Program final {
public:
Program(Context &Ctx) : Ctx(Ctx) {}
+ ~Program() {
+ // Manually destroy all the blocks. They are almost all harmless,
+ // but primitive arrays might have an InitMap* heap allocated and
+ // that needs to be freed.
+ for (Global *G : Globals)
+ G->block()->invokeDtor();
+
+ // Records might actually allocate memory themselves, but they
+ // are allocated using a BumpPtrAllocator. Call their desctructors
+ // here manually so they are properly freeing their resources.
+ for (auto RecordPair : Records) {
+ if (Record *R = RecordPair.second)
+ R->~Record();
+ }
+ }
+
/// Marshals a native pointer to an ID for embedding in bytecode.
unsigned getOrCreateNativePointer(const void *Ptr);
@@ -60,23 +76,25 @@ public:
}
/// Finds a global's index.
- llvm::Optional<unsigned> getGlobal(const ValueDecl *VD);
+ std::optional<unsigned> getGlobal(const ValueDecl *VD);
/// Returns or creates a global an creates an index to it.
- llvm::Optional<unsigned> getOrCreateGlobal(const ValueDecl *VD);
+ std::optional<unsigned> getOrCreateGlobal(const ValueDecl *VD,
+ const Expr *Init = nullptr);
/// Returns or creates a dummy value for parameters.
- llvm::Optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
+ std::optional<unsigned> getOrCreateDummy(const ParmVarDecl *PD);
/// Creates a global and returns its index.
- llvm::Optional<unsigned> createGlobal(const ValueDecl *VD);
+ std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *E);
/// Creates a global from a lifetime-extended temporary.
- llvm::Optional<unsigned> createGlobal(const Expr *E);
+ std::optional<unsigned> createGlobal(const Expr *E);
/// Creates a new function from a code range.
template <typename... Ts>
Function *createFunction(const FunctionDecl *Def, Ts &&... Args) {
+ Def = Def->getCanonicalDecl();
auto *Func = new Function(*this, Def, std::forward<Ts>(Args)...);
Funcs.insert({Def, std::unique_ptr<Function>(Func)});
return Func;
@@ -92,26 +110,23 @@ public:
/// Returns a function.
Function *getFunction(const FunctionDecl *F);
- /// Returns a pointer to a function if it exists and can be compiled.
- /// If a function couldn't be compiled, an error is returned.
- /// If a function was not yet defined, a null pointer is returned.
- llvm::Expected<Function *> getOrCreateFunction(const FunctionDecl *F);
-
/// Returns a record or creates one if it does not exist.
Record *getOrCreateRecord(const RecordDecl *RD);
/// Creates a descriptor for a primitive type.
Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
- bool IsConst = false,
- bool IsTemporary = false,
+ Descriptor::MetadataSize MDSize = std::nullopt,
+ bool IsConst = false, bool IsTemporary = false,
bool IsMutable = false) {
- return allocateDescriptor(D, Type, IsConst, IsTemporary, IsMutable);
+ return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable);
}
/// Creates a descriptor for a composite type.
Descriptor *createDescriptor(const DeclTy &D, const Type *Ty,
+ Descriptor::MetadataSize MDSize = std::nullopt,
bool IsConst = false, bool IsTemporary = false,
- bool IsMutable = false);
+ bool IsMutable = false,
+ const Expr *Init = nullptr);
/// Context to manage declaration lifetimes.
class DeclScope {
@@ -124,17 +139,18 @@ public:
};
/// Returns the current declaration ID.
- llvm::Optional<unsigned> getCurrentDecl() const {
+ std::optional<unsigned> getCurrentDecl() const {
if (CurrentDeclaration == NoDeclaration)
- return llvm::Optional<unsigned>{};
+ return std::optional<unsigned>{};
return LastDeclaration;
}
private:
friend class DeclScope;
- llvm::Optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
- bool IsStatic, bool IsExtern);
+ std::optional<unsigned> createGlobal(const DeclTy &D, QualType Ty,
+ bool IsStatic, bool IsExtern,
+ const Expr *Init = nullptr);
/// Reference to the VM context.
Context &Ctx;
diff --git a/clang/lib/AST/Interp/Record.h b/clang/lib/AST/Interp/Record.h
index 9cdee9003752..1742cb1cc4ee 100644
--- a/clang/lib/AST/Interp/Record.h
+++ b/clang/lib/AST/Interp/Record.h
@@ -13,14 +13,16 @@
#ifndef LLVM_CLANG_AST_INTERP_RECORD_H
#define LLVM_CLANG_AST_INTERP_RECORD_H
-#include "Pointer.h"
+#include "Descriptor.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
namespace clang {
namespace interp {
class Program;
/// Structure/Class descriptor.
-class Record {
+class Record final {
public:
/// Describes a record field.
struct Field {
@@ -47,6 +49,8 @@ public:
public:
/// Returns the underlying declaration.
const RecordDecl *getDecl() const { return Decl; }
+ /// Returns the name of the underlying declaration.
+ const std::string getName() const { return Decl->getNameAsString(); }
/// Checks if the record is a union.
bool isUnion() const { return getDecl()->isUnion(); }
/// Returns the size of the record.
@@ -59,13 +63,20 @@ public:
const Base *getBase(const RecordDecl *FD) const;
/// Returns a virtual base descriptor.
const Base *getVirtualBase(const RecordDecl *RD) const;
+ // Returns the destructor of the record, if any.
+ const CXXDestructorDecl *getDestructor() const {
+ if (const auto *CXXDecl = dyn_cast<CXXRecordDecl>(Decl))
+ return CXXDecl->getDestructor();
+ return nullptr;
+ }
using const_field_iter = FieldList::const_iterator;
llvm::iterator_range<const_field_iter> fields() const {
return llvm::make_range(Fields.begin(), Fields.end());
}
- unsigned getNumFields() { return Fields.size(); }
+ unsigned getNumFields() const { return Fields.size(); }
+ const Field *getField(unsigned I) const { return &Fields[I]; }
Field *getField(unsigned I) { return &Fields[I]; }
using const_base_iter = BaseList::const_iterator;
@@ -73,7 +84,7 @@ public:
return llvm::make_range(Bases.begin(), Bases.end());
}
- unsigned getNumBases() { return Bases.size(); }
+ unsigned getNumBases() const { return Bases.size(); }
Base *getBase(unsigned I) { return &Bases[I]; }
using const_virtual_iter = VirtualBaseList::const_iterator;
@@ -81,7 +92,7 @@ public:
return llvm::make_range(VirtualBases.begin(), VirtualBases.end());
}
- unsigned getNumVirtualBases() { return VirtualBases.size(); }
+ unsigned getNumVirtualBases() const { return VirtualBases.size(); }
Base *getVirtualBase(unsigned I) { return &VirtualBases[I]; }
private:
@@ -108,7 +119,6 @@ private:
llvm::DenseMap<const FieldDecl *, Field *> FieldMap;
/// Mapping from declarations to virtual bases.
llvm::DenseMap<const RecordDecl *, Base *> VirtualBaseMap;
- /// Mapping from
/// Size of the structure.
unsigned BaseSize;
/// Size of all virtual bases.
diff --git a/clang/lib/AST/Interp/Source.cpp b/clang/lib/AST/Interp/Source.cpp
index 4bec87812638..467cde116843 100644
--- a/clang/lib/AST/Interp/Source.cpp
+++ b/clang/lib/AST/Interp/Source.cpp
@@ -28,12 +28,12 @@ const Expr *SourceInfo::asExpr() const {
return nullptr;
}
-const Expr *SourceMapper::getExpr(Function *F, CodePtr PC) const {
+const Expr *SourceMapper::getExpr(const Function *F, CodePtr PC) const {
if (const Expr *E = getSource(F, PC).asExpr())
return E;
llvm::report_fatal_error("missing source expression");
}
-SourceLocation SourceMapper::getLocation(Function *F, CodePtr PC) const {
+SourceLocation SourceMapper::getLocation(const Function *F, CodePtr PC) const {
return getSource(F, PC).getLoc();
}
diff --git a/clang/lib/AST/Interp/Source.h b/clang/lib/AST/Interp/Source.h
index 6acaf406b47a..99ffce34c12f 100644
--- a/clang/lib/AST/Interp/Source.h
+++ b/clang/lib/AST/Interp/Source.h
@@ -13,6 +13,7 @@
#ifndef LLVM_CLANG_AST_INTERP_SOURCE_H
#define LLVM_CLANG_AST_INTERP_SOURCE_H
+#include "PrimType.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h"
#include "llvm/Support/Endian.h"
@@ -22,7 +23,7 @@ namespace interp {
class Function;
/// Pointer into the code segment.
-class CodePtr {
+class CodePtr final {
public:
CodePtr() : Ptr(nullptr) {}
@@ -43,11 +44,14 @@ public:
bool operator!=(const CodePtr &RHS) const { return Ptr != RHS.Ptr; }
+ operator bool() const { return Ptr; }
+
/// Reads data and advances the pointer.
template <typename T> std::enable_if_t<!std::is_pointer<T>::value, T> read() {
+ assert(aligned(Ptr));
using namespace llvm::support;
T Value = endian::read<T, endianness::native, 1>(Ptr);
- Ptr += sizeof(T);
+ Ptr += align(sizeof(T));
return Value;
}
@@ -63,7 +67,7 @@ private:
};
/// Describes the statement/declaration an opcode was generated from.
-class SourceInfo {
+class SourceInfo final {
public:
SourceInfo() {}
SourceInfo(const Stmt *E) : Source(E) {}
@@ -89,12 +93,12 @@ public:
virtual ~SourceMapper() {}
/// Returns source information for a given PC in a function.
- virtual SourceInfo getSource(Function *F, CodePtr PC) const = 0;
+ virtual SourceInfo getSource(const Function *F, CodePtr PC) const = 0;
/// Returns the expression if an opcode belongs to one, null otherwise.
- const Expr *getExpr(Function *F, CodePtr PC) const;
+ const Expr *getExpr(const Function *F, CodePtr PC) const;
/// Returns the location from which an opcode originates.
- SourceLocation getLocation(Function *F, CodePtr PC) const;
+ SourceLocation getLocation(const Function *F, CodePtr PC) const;
};
} // namespace interp
diff --git a/clang/lib/AST/Interp/State.h b/clang/lib/AST/Interp/State.h
index d9a645a3eb3e..131fbcf3cffc 100644
--- a/clang/lib/AST/Interp/State.h
+++ b/clang/lib/AST/Interp/State.h
@@ -71,6 +71,7 @@ public:
virtual unsigned getCallStackDepth() = 0;
public:
+ State() : InConstantContext(false) {}
// Diagnose that the evaluation could not be folded (FF => FoldFailure)
OptionalDiagnostic
FFDiag(SourceLocation Loc,
@@ -118,6 +119,10 @@ public:
const LangOptions &getLangOpts() const;
+ /// Whether or not we're in a context where the front end requires a
+ /// constant value.
+ bool InConstantContext;
+
private:
void addCallStack(unsigned Limit);
diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp
index e99c21dcff73..c9aadce73141 100644
--- a/clang/lib/AST/ItaniumCXXABI.cpp
+++ b/clang/lib/AST/ItaniumCXXABI.cpp
@@ -26,6 +26,7 @@
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/iterator.h"
+#include <optional>
using namespace clang;
@@ -84,8 +85,8 @@ template<typename T> bool isDenseMapKeyTombstone(T V) {
V, llvm::DenseMapInfo<T>::getTombstoneKey());
}
-template<typename T>
-Optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) {
+template <typename T>
+std::optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) {
bool LHSEmpty = isDenseMapKeyEmpty(LHS);
bool RHSEmpty = isDenseMapKeyEmpty(RHS);
if (LHSEmpty || RHSEmpty)
@@ -96,7 +97,7 @@ Optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) {
if (LHSTombstone || RHSTombstone)
return LHSTombstone && RHSTombstone;
- return None;
+ return std::nullopt;
}
template<>
@@ -113,8 +114,8 @@ struct DenseMapInfo<DecompositionDeclName> {
return llvm::hash_combine_range(Key.begin(), Key.end());
}
static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName RHS) {
- if (Optional<bool> Result = areDenseMapKeysEqualSpecialValues(
- LHS.Bindings, RHS.Bindings))
+ if (std::optional<bool> Result =
+ areDenseMapKeysEqualSpecialValues(LHS.Bindings, RHS.Bindings))
return *Result;
return LHS.Bindings.size() == RHS.Bindings.size() &&
@@ -224,7 +225,7 @@ public:
MemberPointerInfo
getMemberPointerInfo(const MemberPointerType *MPT) const override {
const TargetInfo &Target = Context.getTargetInfo();
- TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0);
+ TargetInfo::IntType PtrDiff = Target.getPtrDiffType(LangAS::Default);
MemberPointerInfo MPI;
MPI.Width = Target.getTypeWidth(PtrDiff);
MPI.Align = Target.getTypeAlign(PtrDiff);
@@ -251,8 +252,8 @@ public:
return false;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- CharUnits PointerSize =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ CharUnits PointerSize = Context.toCharUnitsFromBits(
+ Context.getTargetInfo().getPointerWidth(LangAS::Default));
return Layout.getNonVirtualSize() == PointerSize;
}
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 91f41778ee68..b23bc5f8d881 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -35,6 +35,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
@@ -118,9 +119,9 @@ public:
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
void mangleDynamicStermFinalizer(const VarDecl *D, raw_ostream &Out) override;
- void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+ void mangleSEHFilterExpression(GlobalDecl EnclosingDecl,
raw_ostream &Out) override;
- void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+ void mangleSEHFinallyBlock(GlobalDecl EnclosingDecl,
raw_ostream &Out) override;
void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;
void mangleItaniumThreadLocalWrapper(const VarDecl *D,
@@ -484,8 +485,7 @@ private:
const AbiTagList *AdditionalAbiTags);
void mangleModuleName(const NamedDecl *ND);
void mangleTemplateName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
+ ArrayRef<TemplateArgument> Args);
void mangleUnqualifiedName(GlobalDecl GD, const DeclContext *DC,
const AbiTagList *AdditionalAbiTags) {
mangleUnqualifiedName(GD, cast<NamedDecl>(GD.getDecl())->getDeclName(), DC,
@@ -513,8 +513,7 @@ private:
const AbiTagList *AdditionalAbiTags,
bool NoFunction=false);
void mangleNestedName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
+ ArrayRef<TemplateArgument> Args);
void mangleNestedNameWithClosurePrefix(GlobalDecl GD,
const NamedDecl *PrefixND,
const AbiTagList *AdditionalAbiTags);
@@ -578,8 +577,7 @@ private:
void mangleTemplateArgs(TemplateName TN,
const TemplateArgumentLoc *TemplateArgs,
unsigned NumTemplateArgs);
- void mangleTemplateArgs(TemplateName TN, const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
+ void mangleTemplateArgs(TemplateName TN, ArrayRef<TemplateArgument> Args);
void mangleTemplateArgs(TemplateName TN, const TemplateArgumentList &AL);
void mangleTemplateArg(TemplateArgument A, bool NeedExactType);
void mangleTemplateArgExpr(const Expr *E);
@@ -605,9 +603,9 @@ NamespaceDecl *ItaniumMangleContextImpl::getStdNamespace() {
if (!StdNamespace) {
StdNamespace = NamespaceDecl::Create(
getASTContext(), getASTContext().getTranslationUnitDecl(),
- /*Inline*/ false, SourceLocation(), SourceLocation(),
+ /*Inline=*/false, SourceLocation(), SourceLocation(),
&getASTContext().Idents.get("std"),
- /*PrevDecl*/ nullptr);
+ /*PrevDecl=*/nullptr, /*Nested=*/false);
StdNamespace->setImplicit();
}
return StdNamespace;
@@ -1087,15 +1085,14 @@ void CXXNameMangler::mangleModuleNamePrefix(StringRef Name, bool IsPartition) {
}
void CXXNameMangler::mangleTemplateName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
+ ArrayRef<TemplateArgument> Args) {
const DeclContext *DC = Context.getEffectiveDeclContext(TD);
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
mangleUnscopedTemplateName(TD, DC, nullptr);
- mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs);
+ mangleTemplateArgs(asTemplateName(TD), Args);
} else {
- mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
+ mangleNestedName(TD, Args);
}
}
@@ -1244,8 +1241,7 @@ void CXXNameMangler::manglePrefix(QualType type) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
- TST->getNumArgs());
+ mangleTemplateArgs(TST->getTemplateName(), TST->template_arguments());
addSubstitution(QualType(TST, 0));
}
} else if (const auto *DTST =
@@ -1258,7 +1254,7 @@ void CXXNameMangler::manglePrefix(QualType type) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs());
+ mangleTemplateArgs(Template, DTST->template_arguments());
addSubstitution(QualType(DTST, 0));
}
} else {
@@ -1558,7 +1554,7 @@ void CXXNameMangler::mangleUnqualifiedName(
// <lambda-sig> ::= <template-param-decl>* <parameter-type>+
// # Parameter types or 'v' for 'void'.
if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) {
- llvm::Optional<unsigned> DeviceNumber =
+ std::optional<unsigned> DeviceNumber =
Context.getDiscriminatorOverride()(Context.getASTContext(), Record);
// If we have a device-number via the discriminator, use that to mangle
@@ -1588,7 +1584,9 @@ void CXXNameMangler::mangleUnqualifiedName(
// Get a unique id for the anonymous struct. If it is not a real output
// ID doesn't matter so use fake one.
- unsigned AnonStructId = NullOut ? 0 : Context.getAnonymousStructId(TD);
+ unsigned AnonStructId =
+ NullOut ? 0
+ : Context.getAnonymousStructId(TD, dyn_cast<FunctionDecl>(DC));
// Mangle it as a source name in the form
// [n] $_<id>
@@ -1659,7 +1657,7 @@ void CXXNameMangler::mangleUnqualifiedName(
if (!MD->isStatic())
Arity++;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DeclarationName::CXXConversionFunctionName:
case DeclarationName::CXXLiteralOperatorName:
mangleOperatorName(Name, Arity);
@@ -1730,14 +1728,13 @@ void CXXNameMangler::mangleNestedName(GlobalDecl GD,
Out << 'E';
}
void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
+ ArrayRef<TemplateArgument> Args) {
// <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
Out << 'N';
mangleTemplatePrefix(TD);
- mangleTemplateArgs(asTemplateName(TD), TemplateArgs, NumTemplateArgs);
+ mangleTemplateArgs(asTemplateName(TD), Args);
Out << 'E';
}
@@ -2006,7 +2003,7 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
// if the host-side CXX ABI has different numbering for lambda. In such case,
// if the mangle context is that device-side one, use the device-side lambda
// mangling number for this lambda.
- llvm::Optional<unsigned> DeviceNumber =
+ std::optional<unsigned> DeviceNumber =
Context.getDiscriminatorOverride()(Context.getASTContext(), Lambda);
unsigned Number =
DeviceNumber ? *DeviceNumber : Lambda->getLambdaManglingNumber();
@@ -2416,7 +2413,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
// conversions to the corresponding template parameter.
// FIXME: Other compilers mangle partially-resolved template arguments in
// unresolved-qualifier-levels.
- mangleTemplateArgs(TemplateName(), TST->getArgs(), TST->getNumArgs());
+ mangleTemplateArgs(TemplateName(), TST->template_arguments());
break;
}
@@ -2435,7 +2432,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty,
TemplateName Template = getASTContext().getDependentTemplateName(
DTST->getQualifier(), DTST->getIdentifier());
mangleSourceName(DTST->getIdentifier());
- mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs());
+ mangleTemplateArgs(Template, DTST->template_arguments());
break;
}
@@ -3874,7 +3871,7 @@ void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) {
- mangleTemplateName(TD, T->getArgs(), T->getNumArgs());
+ mangleTemplateName(TD, T->template_arguments());
} else {
if (mangleSubstitution(QualType(T, 0)))
return;
@@ -3884,7 +3881,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs());
+ mangleTemplateArgs(T->getTemplateName(), T->template_arguments());
addSubstitution(QualType(T, 0));
}
}
@@ -3936,7 +3933,7 @@ void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) {
// FIXME: GCC does not appear to mangle the template arguments when
// the template in question is a dependent template name. Should we
// emulate that badness?
- mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs());
+ mangleTemplateArgs(Prefix, T->template_arguments());
Out << 'E';
}
@@ -3980,16 +3977,22 @@ void CXXNameMangler::mangleType(const UnaryTransformType *T) {
// If this is dependent, we need to record that. If not, we simply
// mangle it as the underlying type since they are equivalent.
if (T->isDependentType()) {
- Out << 'U';
+ Out << "u";
+ StringRef BuiltinName;
switch (T->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- Out << "3eut";
- break;
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
+ case UnaryTransformType::Enum: \
+ BuiltinName = "__" #Trait; \
+ break;
+#include "clang/Basic/TransformTypeTraits.def"
}
+ Out << BuiltinName.size() << BuiltinName;
}
+ Out << "I";
mangleType(T->getBaseType());
+ Out << "E";
}
void CXXNameMangler::mangleType(const AutoType *T) {
@@ -4247,6 +4250,7 @@ recurse:
case Expr::OMPArrayShapingExprClass:
case Expr::OMPIteratorExprClass:
case Expr::CXXInheritedCtorInitExprClass:
+ case Expr::CXXParenListInitExprClass:
llvm_unreachable("unexpected statement kind");
case Expr::ConstantExprClass:
@@ -4671,7 +4675,7 @@ recurse:
Out << 'E';
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case UETT_AlignOf:
Out << 'a';
MangleAlignofSizeofArg();
@@ -4886,9 +4890,7 @@ recurse:
// <expr-primary> ::= L <mangled-name> E # external name
Out << "L_Z";
auto *CSE = cast<ConceptSpecializationExpr>(E);
- mangleTemplateName(CSE->getNamedConcept(),
- CSE->getTemplateArguments().data(),
- CSE->getTemplateArguments().size());
+ mangleTemplateName(CSE->getNamedConcept(), CSE->getTemplateArguments());
Out << 'E';
break;
}
@@ -5345,13 +5347,12 @@ void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
}
void CXXNameMangler::mangleTemplateArgs(TemplateName TN,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
+ ArrayRef<TemplateArgument> Args) {
// <template-args> ::= I <template-arg>+ E
Out << 'I';
TemplateArgManglingInfo Info(TN);
- for (unsigned i = 0; i != NumTemplateArgs; ++i)
- mangleTemplateArg(TemplateArgs[i], Info.needExactType(i, TemplateArgs[i]));
+ for (unsigned i = 0; i != Args.size(); ++i)
+ mangleTemplateArg(Args[i], Info.needExactType(i, Args[i]));
Out << 'E';
}
@@ -6431,23 +6432,25 @@ void ItaniumMangleContextImpl::mangleDynamicStermFinalizer(const VarDecl *D,
}
void ItaniumMangleContextImpl::mangleSEHFilterExpression(
- const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ GlobalDecl EnclosingDecl, raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "__filt_";
- if (shouldMangleDeclName(EnclosingDecl))
+ auto *EnclosingFD = cast<FunctionDecl>(EnclosingDecl.getDecl());
+ if (shouldMangleDeclName(EnclosingFD))
Mangler.mangle(EnclosingDecl);
else
- Mangler.getStream() << EnclosingDecl->getName();
+ Mangler.getStream() << EnclosingFD->getName();
}
void ItaniumMangleContextImpl::mangleSEHFinallyBlock(
- const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ GlobalDecl EnclosingDecl, raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "__fin_";
- if (shouldMangleDeclName(EnclosingDecl))
+ auto *EnclosingFD = cast<FunctionDecl>(EnclosingDecl.getDecl());
+ if (shouldMangleDeclName(EnclosingFD))
Mangler.mangle(EnclosingDecl);
else
- Mangler.getStream() << EnclosingDecl->getName();
+ Mangler.getStream() << EnclosingFD->getName();
}
void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D,
@@ -6558,8 +6561,8 @@ ItaniumMangleContext *ItaniumMangleContext::create(ASTContext &Context,
bool IsAux) {
return new ItaniumMangleContextImpl(
Context, Diags,
- [](ASTContext &, const NamedDecl *) -> llvm::Optional<unsigned> {
- return llvm::None;
+ [](ASTContext &, const NamedDecl *) -> std::optional<unsigned> {
+ return std::nullopt;
},
IsAux);
}
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 87e4255c2b93..83b097daf8ab 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -1,8 +1,9 @@
#include "clang/AST/JSONNodeDumper.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Lex/Lexer.h"
-#include "llvm/ADT/StringSwitch.h"
+#include <optional>
using namespace clang;
@@ -530,6 +531,14 @@ JSONNodeDumper::createCXXBaseSpecifier(const CXXBaseSpecifier &BS) {
void JSONNodeDumper::VisitTypedefType(const TypedefType *TT) {
JOS.attribute("decl", createBareDeclRef(TT->getDecl()));
+ if (!TT->typeMatchesDecl())
+ JOS.attribute("type", createQualType(TT->desugar()));
+}
+
+void JSONNodeDumper::VisitUsingType(const UsingType *TT) {
+ JOS.attribute("decl", createBareDeclRef(TT->getFoundDecl()));
+ if (!TT->typeMatchesDecl())
+ JOS.attribute("type", createQualType(TT->desugar()));
}
void JSONNodeDumper::VisitFunctionType(const FunctionType *T) {
@@ -662,9 +671,11 @@ void JSONNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *UUT) {
void JSONNodeDumper::VisitUnaryTransformType(const UnaryTransformType *UTT) {
switch (UTT->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- JOS.attribute("transformKind", "underlying_type");
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
+ case UnaryTransformType::Enum: \
+ JOS.attribute("transformKind", #Trait); \
break;
+#include "clang/Basic/TransformTypeTraits.def"
}
}
@@ -680,6 +691,18 @@ void JSONNodeDumper::VisitTemplateTypeParmType(
JOS.attribute("decl", createBareDeclRef(TTPT->getDecl()));
}
+void JSONNodeDumper::VisitSubstTemplateTypeParmType(
+ const SubstTemplateTypeParmType *STTPT) {
+ JOS.attribute("index", STTPT->getIndex());
+ if (auto PackIndex = STTPT->getPackIndex())
+ JOS.attribute("pack_index", *PackIndex);
+}
+
+void JSONNodeDumper::VisitSubstTemplateTypeParmPackType(
+ const SubstTemplateTypeParmPackType *T) {
+ JOS.attribute("index", T->getIndex());
+}
+
void JSONNodeDumper::VisitAutoType(const AutoType *AT) {
JOS.attribute("undeduced", !AT->isDeduced());
switch (AT->getKeyword()) {
@@ -715,7 +738,7 @@ void JSONNodeDumper::VisitObjCInterfaceType(const ObjCInterfaceType *OIT) {
}
void JSONNodeDumper::VisitPackExpansionType(const PackExpansionType *PET) {
- if (llvm::Optional<unsigned> N = PET->getNumExpansions())
+ if (std::optional<unsigned> N = PET->getNumExpansions())
JOS.attribute("numExpansions", *N);
}
@@ -772,6 +795,7 @@ void JSONNodeDumper::VisitTypeAliasDecl(const TypeAliasDecl *TAD) {
void JSONNodeDumper::VisitNamespaceDecl(const NamespaceDecl *ND) {
VisitNamedDecl(ND);
attributeOnlyIfTrue("isInline", ND->isInline());
+ attributeOnlyIfTrue("isNested", ND->isNested());
if (!ND->isOriginalNamespace())
JOS.attribute("originalNamespace",
createBareDeclRef(ND->getOriginalNamespace()));
@@ -827,6 +851,9 @@ void JSONNodeDumper::VisitVarDecl(const VarDecl *VD) {
case VarDecl::CInit: JOS.attribute("init", "c"); break;
case VarDecl::CallInit: JOS.attribute("init", "call"); break;
case VarDecl::ListInit: JOS.attribute("init", "list"); break;
+ case VarDecl::ParenListInit:
+ JOS.attribute("init", "paren-list");
+ break;
}
}
attributeOnlyIfTrue("isParameterPack", VD->isParameterPack());
@@ -893,6 +920,11 @@ void JSONNodeDumper::VisitCXXRecordDecl(const CXXRecordDecl *RD) {
}
}
+void JSONNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
+ VisitNamedDecl(D);
+ JOS.attribute("bufferKind", D->isCBuffer() ? "cbuffer" : "tbuffer");
+}
+
void JSONNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
VisitNamedDecl(D);
JOS.attribute("tagUsed", D->wasDeclaredWithTypename() ? "typename" : "class");
diff --git a/clang/lib/AST/Linkage.h b/clang/lib/AST/Linkage.h
index cd50d138790a..31f384eb75d0 100644
--- a/clang/lib/AST/Linkage.h
+++ b/clang/lib/AST/Linkage.h
@@ -19,8 +19,8 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
+#include <optional>
namespace clang {
/// Kinds of LV computation. The linkage side of the computation is
@@ -91,11 +91,11 @@ class LinkageComputer {
return QueryType(ND, Kind.toBits());
}
- llvm::Optional<LinkageInfo> lookup(const NamedDecl *ND,
- LVComputationKind Kind) const {
+ std::optional<LinkageInfo> lookup(const NamedDecl *ND,
+ LVComputationKind Kind) const {
auto Iter = CachedLinkageInfo.find(makeCacheKey(ND, Kind));
if (Iter == CachedLinkageInfo.end())
- return None;
+ return std::nullopt;
return Iter->second;
}
diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp
index 7ea569c63d9e..31cdad4c8fdd 100644
--- a/clang/lib/AST/Mangle.cpp
+++ b/clang/lib/AST/Mangle.cpp
@@ -223,6 +223,7 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (!MD->isStatic())
++ArgWords;
+ uint64_t DefaultPtrWidth = TI.getPointerWidth(LangAS::Default);
for (const auto &AT : Proto->param_types()) {
// If an argument type is incomplete there is no way to get its size to
// correctly encode into the mangling scheme.
@@ -230,11 +231,10 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) {
if (AT->isIncompleteType())
break;
// Size should be aligned to pointer size.
- ArgWords +=
- llvm::alignTo(ASTContext.getTypeSize(AT), TI.getPointerWidth(0)) /
- TI.getPointerWidth(0);
+ ArgWords += llvm::alignTo(ASTContext.getTypeSize(AT), DefaultPtrWidth) /
+ DefaultPtrWidth;
}
- Out << ((TI.getPointerWidth(0) / 8) * ArgWords);
+ Out << ((DefaultPtrWidth / 8) * ArgWords);
}
void MangleContext::mangleMSGuidDecl(const MSGuidDecl *GD, raw_ostream &Out) {
diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp
index 7f4a7b2b9381..263e263eba7c 100644
--- a/clang/lib/AST/MicrosoftCXXABI.cpp
+++ b/clang/lib/AST/MicrosoftCXXABI.cpp
@@ -303,7 +303,7 @@ CXXABI::MemberPointerInfo MicrosoftCXXABI::getMemberPointerInfo(
// The nominal struct is laid out with pointers followed by ints and aligned
// to a pointer width if any are present and an int width otherwise.
const TargetInfo &Target = Context.getTargetInfo();
- unsigned PtrSize = Target.getPointerWidth(0);
+ unsigned PtrSize = Target.getPointerWidth(LangAS::Default);
unsigned IntSize = Target.getIntWidth();
unsigned Ptrs, Ints;
@@ -318,7 +318,7 @@ CXXABI::MemberPointerInfo MicrosoftCXXABI::getMemberPointerInfo(
if (Ptrs + Ints > 1 && Target.getTriple().isArch32Bit())
MPI.Align = 64;
else if (Ptrs)
- MPI.Align = Target.getPointerAlign(0);
+ MPI.Align = Target.getPointerAlign(LangAS::Default);
else
MPI.Align = Target.getIntAlign();
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 09075e60142a..cdd2c93c4b14 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -35,6 +35,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/xxhash.h"
+#include <optional>
using namespace clang;
@@ -142,8 +143,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
- llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;
- llvm::DenseMap<const NamedDecl *, unsigned> SEHFinallyIds;
+ llvm::DenseMap<GlobalDecl, unsigned> SEHFilterIds;
+ llvm::DenseMap<GlobalDecl, unsigned> SEHFinallyIds;
SmallString<16> AnonymousNamespaceHash;
public:
@@ -201,9 +202,9 @@ public:
void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override;
void mangleDynamicAtExitDestructor(const VarDecl *D,
raw_ostream &Out) override;
- void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
+ void mangleSEHFilterExpression(GlobalDecl EnclosingDecl,
raw_ostream &Out) override;
- void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+ void mangleSEHFinallyBlock(GlobalDecl EnclosingDecl,
raw_ostream &Out) override;
void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
@@ -340,22 +341,22 @@ public:
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_)
: Context(C), Out(Out_), Structor(nullptr), StructorType(-1),
TemplateArgStringStorage(TemplateArgStringStorageAlloc),
- PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
- 64) {}
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(
+ LangAS::Default) == 64) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
const CXXConstructorDecl *D, CXXCtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
TemplateArgStringStorage(TemplateArgStringStorageAlloc),
- PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
- 64) {}
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(
+ LangAS::Default) == 64) {}
MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
TemplateArgStringStorage(TemplateArgStringStorageAlloc),
- PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
- 64) {}
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(
+ LangAS::Default) == 64) {}
raw_ostream &getStream() const { return Out; }
@@ -376,7 +377,7 @@ public:
void mangleBits(llvm::APInt Number);
void mangleTagTypeKind(TagTypeKind TK);
void mangleArtificialTagType(TagTypeKind TK, StringRef UnqualifiedName,
- ArrayRef<StringRef> NestedNames = None);
+ ArrayRef<StringRef> NestedNames = std::nullopt);
void mangleAddressSpaceType(QualType T, Qualifiers Quals, SourceRange Range);
void mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM = QMM_Mangle);
@@ -776,7 +777,7 @@ void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk(
const CXXMethodDecl *MD, const MethodVFTableLocation &ML) {
// Get the vftable offset.
CharUnits PointerWidth = getASTContext().toCharUnitsFromBits(
- getASTContext().getTargetInfo().getPointerWidth(0));
+ getASTContext().getTargetInfo().getPointerWidth(LangAS::Default));
uint64_t OffsetInVFTable = ML.Index * PointerWidth.getQuantity();
Out << "?_9";
@@ -838,6 +839,9 @@ void MicrosoftCXXNameMangler::mangleFloat(llvm::APFloat Number) {
case APFloat::S_x87DoubleExtended: Out << 'X'; break;
case APFloat::S_IEEEquad: Out << 'Y'; break;
case APFloat::S_PPCDoubleDouble: Out << 'Z'; break;
+ case APFloat::S_Float8E5M2:
+ case APFloat::S_Float8E4M3FN:
+ llvm_unreachable("Tried to mangle unexpected APFloat semantics");
}
mangleBits(Number.bitcastToAPInt());
@@ -1505,7 +1509,7 @@ void MicrosoftCXXNameMangler::mangleIntegerLiteral(
void MicrosoftCXXNameMangler::mangleExpression(
const Expr *E, const NonTypeTemplateParmDecl *PD) {
// See if this is a constant expression.
- if (Optional<llvm::APSInt> Value =
+ if (std::optional<llvm::APSInt> Value =
E->getIntegerConstantExpr(Context.getASTContext())) {
mangleIntegerLiteral(*Value, PD, E->getType());
return;
@@ -2469,6 +2473,10 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
Out << "$halff@";
break;
+ case BuiltinType::BFloat16:
+ mangleArtificialTagType(TTK_Struct, "__bf16", {"__clang"});
+ break;
+
#define SVE_TYPE(Name, Id, SingletonId) \
case BuiltinType::Id:
#include "clang/Basic/AArch64SVEACLETypes.def"
@@ -2501,7 +2509,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers,
case BuiltinType::SatUShortFract:
case BuiltinType::SatUFract:
case BuiltinType::SatULongFract:
- case BuiltinType::BFloat16:
case BuiltinType::Ibm128:
case BuiltinType::Float128: {
DiagnosticsEngine &Diags = Context.getDiags();
@@ -3070,14 +3077,17 @@ bool MicrosoftCXXNameMangler::isArtificialTagType(QualType T) const {
void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals,
SourceRange Range) {
- const BuiltinType *ET = T->getElementType()->getAs<BuiltinType>();
- assert(ET && "vectors with non-builtin elements are unsupported");
+ QualType EltTy = T->getElementType();
+ const BuiltinType *ET = EltTy->getAs<BuiltinType>();
+ const BitIntType *BitIntTy = EltTy->getAs<BitIntType>();
+ assert((ET || BitIntTy) &&
+ "vectors with non-builtin/_BitInt elements are unsupported");
uint64_t Width = getASTContext().getTypeSize(T);
// Pattern match exactly the typedefs in our intrinsic headers. Anything that
// doesn't match the Intel types uses a custom mangling below.
size_t OutSizeBefore = Out.tell();
if (!isa<ExtVectorType>(T)) {
- if (getASTContext().getTargetInfo().getTriple().isX86()) {
+ if (getASTContext().getTargetInfo().getTriple().isX86() && ET) {
if (Width == 64 && ET->getKind() == BuiltinType::LongLong) {
mangleArtificialTagType(TTK_Union, "__m64");
} else if (Width >= 128) {
@@ -3102,7 +3112,8 @@ void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals,
MicrosoftCXXNameMangler Extra(Context, Stream);
Stream << "?$";
Extra.mangleSourceName("__vector");
- Extra.mangleType(QualType(ET, 0), Range, QMM_Escape);
+ Extra.mangleType(QualType(ET ? static_cast<const Type *>(ET) : BitIntTy, 0),
+ Range, QMM_Escape);
Extra.mangleIntegerLiteral(llvm::APSInt::getUnsigned(T->getNumElements()));
mangleArtificialTagType(TTK_Union, TemplateMangling, {"__clang"});
@@ -3720,7 +3731,7 @@ void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator(
}
void MicrosoftMangleContextImpl::mangleSEHFilterExpression(
- const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ GlobalDecl EnclosingDecl, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
// The function body is in the same comdat as the function with the handler,
@@ -3732,7 +3743,7 @@ void MicrosoftMangleContextImpl::mangleSEHFilterExpression(
}
void MicrosoftMangleContextImpl::mangleSEHFinallyBlock(
- const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+ GlobalDecl EnclosingDecl, raw_ostream &Out) {
msvc_hashing_ostream MHO(Out);
MicrosoftCXXNameMangler Mangler(*this, MHO);
// The function body is in the same comdat as the function with the handler,
diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp
index db7878e18c42..3621a2eaa573 100644
--- a/clang/lib/AST/NSAPI.cpp
+++ b/clang/lib/AST/NSAPI.cpp
@@ -11,6 +11,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "llvm/ADT/StringSwitch.h"
+#include <optional>
using namespace clang;
@@ -142,14 +143,15 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
return NSArraySelectors[MK];
}
-Optional<NSAPI::NSArrayMethodKind> NSAPI::getNSArrayMethodKind(Selector Sel) {
+std::optional<NSAPI::NSArrayMethodKind>
+NSAPI::getNSArrayMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
NSArrayMethodKind MK = NSArrayMethodKind(i);
if (Sel == getNSArraySelector(MK))
return MK;
}
- return None;
+ return std::nullopt;
}
Selector NSAPI::getNSDictionarySelector(
@@ -243,7 +245,7 @@ Selector NSAPI::getNSDictionarySelector(
return NSDictionarySelectors[MK];
}
-Optional<NSAPI::NSDictionaryMethodKind>
+std::optional<NSAPI::NSDictionaryMethodKind>
NSAPI::getNSDictionaryMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
@@ -251,7 +253,7 @@ NSAPI::getNSDictionaryMethodKind(Selector Sel) {
return MK;
}
- return None;
+ return std::nullopt;
}
Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const {
@@ -300,15 +302,14 @@ Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const {
return NSSetSelectors[MK];
}
-Optional<NSAPI::NSSetMethodKind>
-NSAPI::getNSSetMethodKind(Selector Sel) {
+std::optional<NSAPI::NSSetMethodKind> NSAPI::getNSSetMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSSetMethods; ++i) {
NSSetMethodKind MK = NSSetMethodKind(i);
if (Sel == getNSSetSelector(MK))
return MK;
}
- return None;
+ return std::nullopt;
}
Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
@@ -363,7 +364,7 @@ Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
return Sels[MK];
}
-Optional<NSAPI::NSNumberLiteralMethodKind>
+std::optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
@@ -371,14 +372,14 @@ NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
return MK;
}
- return None;
+ return std::nullopt;
}
-Optional<NSAPI::NSNumberLiteralMethodKind>
+std::optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
const BuiltinType *BT = T->getAs<BuiltinType>();
if (!BT)
- return None;
+ return std::nullopt;
const TypedefType *TDT = T->getAs<TypedefType>();
if (TDT) {
@@ -496,7 +497,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
break;
}
- return None;
+ return std::nullopt;
}
/// Returns true if \param T is a typedef of "BOOL" in objective-c.
diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp
index 8f19d80cbdc5..36f2c47b3000 100644
--- a/clang/lib/AST/NestedNameSpecifier.cpp
+++ b/clang/lib/AST/NestedNameSpecifier.cpp
@@ -280,14 +280,14 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
case TypeSpecWithTemplate:
OS << "template ";
// Fall through to print the type.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case TypeSpec: {
const auto *Record =
dyn_cast_or_null<ClassTemplateSpecializationDecl>(getAsRecordDecl());
if (ResolveTemplateArguments && Record) {
// Print the type trait with resolved template parameters.
- Record->printName(OS);
+ Record->printName(OS, Policy);
printTemplateArgumentList(
OS, Record->getTemplateArgs().asArray(), Policy,
Record->getSpecializedTemplate()->getTemplateParameters());
diff --git a/clang/lib/AST/ODRDiagsEmitter.cpp b/clang/lib/AST/ODRDiagsEmitter.cpp
new file mode 100644
index 000000000000..b3fe070889c5
--- /dev/null
+++ b/clang/lib/AST/ODRDiagsEmitter.cpp
@@ -0,0 +1,2206 @@
+//===-- ODRDiagsEmitter.cpp - Diagnostics for ODR mismatches ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ODRDiagsEmitter.h"
+#include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ODRHash.h"
+#include "clang/Basic/DiagnosticAST.h"
+#include "clang/Basic/Module.h"
+
+using namespace clang;
+
+static unsigned computeODRHash(QualType Ty) {
+ ODRHash Hasher;
+ Hasher.AddQualType(Ty);
+ return Hasher.CalculateHash();
+}
+
+static unsigned computeODRHash(const Stmt *S) {
+ ODRHash Hasher;
+ Hasher.AddStmt(S);
+ return Hasher.CalculateHash();
+}
+
+static unsigned computeODRHash(const Decl *D) {
+ assert(D);
+ ODRHash Hasher;
+ Hasher.AddSubDecl(D);
+ return Hasher.CalculateHash();
+}
+
+static unsigned computeODRHash(const TemplateArgument &TA) {
+ ODRHash Hasher;
+ Hasher.AddTemplateArgument(TA);
+ return Hasher.CalculateHash();
+}
+
+std::string ODRDiagsEmitter::getOwningModuleNameForDiagnostic(const Decl *D) {
+ // If we know the owning module, use it.
+ if (Module *M = D->getImportedOwningModule())
+ return M->getFullModuleName();
+
+ // Not from a module.
+ return {};
+}
+
+template <typename MethodT>
+static bool diagnoseSubMismatchMethodParameters(DiagnosticsEngine &Diags,
+ const NamedDecl *FirstContainer,
+ StringRef FirstModule,
+ StringRef SecondModule,
+ const MethodT *FirstMethod,
+ const MethodT *SecondMethod) {
+ enum DiagMethodType {
+ DiagMethod,
+ DiagConstructor,
+ DiagDestructor,
+ };
+ auto GetDiagMethodType = [](const NamedDecl *D) {
+ if (isa<CXXConstructorDecl>(D))
+ return DiagConstructor;
+ if (isa<CXXDestructorDecl>(D))
+ return DiagDestructor;
+ return DiagMethod;
+ };
+
+ enum ODRMethodParametersDifference {
+ NumberParameters,
+ ParameterType,
+ ParameterName,
+ };
+ auto DiagError = [&Diags, &GetDiagMethodType, FirstContainer, FirstModule,
+ FirstMethod](ODRMethodParametersDifference DiffType) {
+ DeclarationName FirstName = FirstMethod->getDeclName();
+ DiagMethodType FirstMethodType = GetDiagMethodType(FirstMethod);
+ return Diags.Report(FirstMethod->getLocation(),
+ diag::err_module_odr_violation_method_params)
+ << FirstContainer << FirstModule.empty() << FirstModule
+ << FirstMethod->getSourceRange() << DiffType << FirstMethodType
+ << FirstName;
+ };
+ auto DiagNote = [&Diags, &GetDiagMethodType, SecondModule,
+ SecondMethod](ODRMethodParametersDifference DiffType) {
+ DeclarationName SecondName = SecondMethod->getDeclName();
+ DiagMethodType SecondMethodType = GetDiagMethodType(SecondMethod);
+ return Diags.Report(SecondMethod->getLocation(),
+ diag::note_module_odr_violation_method_params)
+ << SecondModule.empty() << SecondModule
+ << SecondMethod->getSourceRange() << DiffType << SecondMethodType
+ << SecondName;
+ };
+
+ const unsigned FirstNumParameters = FirstMethod->param_size();
+ const unsigned SecondNumParameters = SecondMethod->param_size();
+ if (FirstNumParameters != SecondNumParameters) {
+ DiagError(NumberParameters) << FirstNumParameters;
+ DiagNote(NumberParameters) << SecondNumParameters;
+ return true;
+ }
+
+ for (unsigned I = 0; I < FirstNumParameters; ++I) {
+ const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
+ const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
+
+ QualType FirstParamType = FirstParam->getType();
+ QualType SecondParamType = SecondParam->getType();
+ if (FirstParamType != SecondParamType &&
+ computeODRHash(FirstParamType) != computeODRHash(SecondParamType)) {
+ if (const DecayedType *ParamDecayedType =
+ FirstParamType->getAs<DecayedType>()) {
+ DiagError(ParameterType) << (I + 1) << FirstParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagError(ParameterType) << (I + 1) << FirstParamType << false;
+ }
+
+ if (const DecayedType *ParamDecayedType =
+ SecondParamType->getAs<DecayedType>()) {
+ DiagNote(ParameterType) << (I + 1) << SecondParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagNote(ParameterType) << (I + 1) << SecondParamType << false;
+ }
+ return true;
+ }
+
+ DeclarationName FirstParamName = FirstParam->getDeclName();
+ DeclarationName SecondParamName = SecondParam->getDeclName();
+ if (FirstParamName != SecondParamName) {
+ DiagError(ParameterName) << (I + 1) << FirstParamName;
+ DiagNote(ParameterName) << (I + 1) << SecondParamName;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchField(
+ const NamedDecl *FirstRecord, StringRef FirstModule, StringRef SecondModule,
+ const FieldDecl *FirstField, const FieldDecl *SecondField) const {
+ enum ODRFieldDifference {
+ FieldName,
+ FieldTypeName,
+ FieldSingleBitField,
+ FieldDifferentWidthBitField,
+ FieldSingleMutable,
+ FieldSingleInitializer,
+ FieldDifferentInitializers,
+ };
+
+ auto DiagError = [FirstRecord, FirstField, FirstModule,
+ this](ODRFieldDifference DiffType) {
+ return Diag(FirstField->getLocation(), diag::err_module_odr_violation_field)
+ << FirstRecord << FirstModule.empty() << FirstModule
+ << FirstField->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [SecondField, SecondModule,
+ this](ODRFieldDifference DiffType) {
+ return Diag(SecondField->getLocation(),
+ diag::note_module_odr_violation_field)
+ << SecondModule.empty() << SecondModule << SecondField->getSourceRange() << DiffType;
+ };
+
+ IdentifierInfo *FirstII = FirstField->getIdentifier();
+ IdentifierInfo *SecondII = SecondField->getIdentifier();
+ if (FirstII->getName() != SecondII->getName()) {
+ DiagError(FieldName) << FirstII;
+ DiagNote(FieldName) << SecondII;
+ return true;
+ }
+
+ QualType FirstType = FirstField->getType();
+ QualType SecondType = SecondField->getType();
+ if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
+ DiagError(FieldTypeName) << FirstII << FirstType;
+ DiagNote(FieldTypeName) << SecondII << SecondType;
+ return true;
+ }
+
+ assert(Context.hasSameType(FirstField->getType(), SecondField->getType()));
+ (void)Context;
+
+ const bool IsFirstBitField = FirstField->isBitField();
+ const bool IsSecondBitField = SecondField->isBitField();
+ if (IsFirstBitField != IsSecondBitField) {
+ DiagError(FieldSingleBitField) << FirstII << IsFirstBitField;
+ DiagNote(FieldSingleBitField) << SecondII << IsSecondBitField;
+ return true;
+ }
+
+ if (IsFirstBitField && IsSecondBitField) {
+ unsigned FirstBitWidthHash = computeODRHash(FirstField->getBitWidth());
+ unsigned SecondBitWidthHash = computeODRHash(SecondField->getBitWidth());
+ if (FirstBitWidthHash != SecondBitWidthHash) {
+ DiagError(FieldDifferentWidthBitField)
+ << FirstII << FirstField->getBitWidth()->getSourceRange();
+ DiagNote(FieldDifferentWidthBitField)
+ << SecondII << SecondField->getBitWidth()->getSourceRange();
+ return true;
+ }
+ }
+
+ if (!LangOpts.CPlusPlus)
+ return false;
+
+ const bool IsFirstMutable = FirstField->isMutable();
+ const bool IsSecondMutable = SecondField->isMutable();
+ if (IsFirstMutable != IsSecondMutable) {
+ DiagError(FieldSingleMutable) << FirstII << IsFirstMutable;
+ DiagNote(FieldSingleMutable) << SecondII << IsSecondMutable;
+ return true;
+ }
+
+ const Expr *FirstInitializer = FirstField->getInClassInitializer();
+ const Expr *SecondInitializer = SecondField->getInClassInitializer();
+ if ((!FirstInitializer && SecondInitializer) ||
+ (FirstInitializer && !SecondInitializer)) {
+ DiagError(FieldSingleInitializer)
+ << FirstII << (FirstInitializer != nullptr);
+ DiagNote(FieldSingleInitializer)
+ << SecondII << (SecondInitializer != nullptr);
+ return true;
+ }
+
+ if (FirstInitializer && SecondInitializer) {
+ unsigned FirstInitHash = computeODRHash(FirstInitializer);
+ unsigned SecondInitHash = computeODRHash(SecondInitializer);
+ if (FirstInitHash != SecondInitHash) {
+ DiagError(FieldDifferentInitializers)
+ << FirstII << FirstInitializer->getSourceRange();
+ DiagNote(FieldDifferentInitializers)
+ << SecondII << SecondInitializer->getSourceRange();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchTypedef(
+ const NamedDecl *FirstRecord, StringRef FirstModule, StringRef SecondModule,
+ const TypedefNameDecl *FirstTD, const TypedefNameDecl *SecondTD,
+ bool IsTypeAlias) const {
+ enum ODRTypedefDifference {
+ TypedefName,
+ TypedefType,
+ };
+
+ auto DiagError = [FirstRecord, FirstTD, FirstModule,
+ this](ODRTypedefDifference DiffType) {
+ return Diag(FirstTD->getLocation(), diag::err_module_odr_violation_typedef)
+ << FirstRecord << FirstModule.empty() << FirstModule
+ << FirstTD->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [SecondTD, SecondModule,
+ this](ODRTypedefDifference DiffType) {
+ return Diag(SecondTD->getLocation(),
+ diag::note_module_odr_violation_typedef)
+ << SecondModule << SecondTD->getSourceRange() << DiffType;
+ };
+
+ DeclarationName FirstName = FirstTD->getDeclName();
+ DeclarationName SecondName = SecondTD->getDeclName();
+ if (FirstName != SecondName) {
+ DiagError(TypedefName) << IsTypeAlias << FirstName;
+ DiagNote(TypedefName) << IsTypeAlias << SecondName;
+ return true;
+ }
+
+ QualType FirstType = FirstTD->getUnderlyingType();
+ QualType SecondType = SecondTD->getUnderlyingType();
+ if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
+ DiagError(TypedefType) << IsTypeAlias << FirstName << FirstType;
+ DiagNote(TypedefType) << IsTypeAlias << SecondName << SecondType;
+ return true;
+ }
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchVar(const NamedDecl *FirstRecord,
+ StringRef FirstModule,
+ StringRef SecondModule,
+ const VarDecl *FirstVD,
+ const VarDecl *SecondVD) const {
+ enum ODRVarDifference {
+ VarName,
+ VarType,
+ VarSingleInitializer,
+ VarDifferentInitializer,
+ VarConstexpr,
+ };
+
+ auto DiagError = [FirstRecord, FirstVD, FirstModule,
+ this](ODRVarDifference DiffType) {
+ return Diag(FirstVD->getLocation(), diag::err_module_odr_violation_variable)
+ << FirstRecord << FirstModule.empty() << FirstModule
+ << FirstVD->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [SecondVD, SecondModule, this](ODRVarDifference DiffType) {
+ return Diag(SecondVD->getLocation(),
+ diag::note_module_odr_violation_variable)
+ << SecondModule << SecondVD->getSourceRange() << DiffType;
+ };
+
+ DeclarationName FirstName = FirstVD->getDeclName();
+ DeclarationName SecondName = SecondVD->getDeclName();
+ if (FirstName != SecondName) {
+ DiagError(VarName) << FirstName;
+ DiagNote(VarName) << SecondName;
+ return true;
+ }
+
+ QualType FirstType = FirstVD->getType();
+ QualType SecondType = SecondVD->getType();
+ if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
+ DiagError(VarType) << FirstName << FirstType;
+ DiagNote(VarType) << SecondName << SecondType;
+ return true;
+ }
+
+ if (!LangOpts.CPlusPlus)
+ return false;
+
+ const Expr *FirstInit = FirstVD->getInit();
+ const Expr *SecondInit = SecondVD->getInit();
+ if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+ DiagError(VarSingleInitializer)
+ << FirstName << (FirstInit == nullptr)
+ << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
+ DiagNote(VarSingleInitializer)
+ << SecondName << (SecondInit == nullptr)
+ << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+ return true;
+ }
+
+ if (FirstInit && SecondInit &&
+ computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
+ DiagError(VarDifferentInitializer)
+ << FirstName << FirstInit->getSourceRange();
+ DiagNote(VarDifferentInitializer)
+ << SecondName << SecondInit->getSourceRange();
+ return true;
+ }
+
+ const bool FirstIsConstexpr = FirstVD->isConstexpr();
+ const bool SecondIsConstexpr = SecondVD->isConstexpr();
+ if (FirstIsConstexpr != SecondIsConstexpr) {
+ DiagError(VarConstexpr) << FirstName << FirstIsConstexpr;
+ DiagNote(VarConstexpr) << SecondName << SecondIsConstexpr;
+ return true;
+ }
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchProtocols(
+ const ObjCProtocolList &FirstProtocols,
+ const ObjCContainerDecl *FirstContainer, StringRef FirstModule,
+ const ObjCProtocolList &SecondProtocols,
+ const ObjCContainerDecl *SecondContainer, StringRef SecondModule) const {
+ // Keep in sync with err_module_odr_violation_referenced_protocols.
+ enum ODRReferencedProtocolDifference {
+ NumProtocols,
+ ProtocolType,
+ };
+ auto DiagRefProtocolError = [FirstContainer, FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRReferencedProtocolDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_referenced_protocols)
+ << FirstContainer << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto DiagRefProtocolNote = [SecondModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRReferencedProtocolDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_referenced_protocols)
+ << SecondModule.empty() << SecondModule << Range << DiffType;
+ };
+ auto GetProtoListSourceRange = [](const ObjCProtocolList &PL) {
+ if (PL.empty())
+ return SourceRange();
+ return SourceRange(*PL.loc_begin(), *std::prev(PL.loc_end()));
+ };
+
+ if (FirstProtocols.size() != SecondProtocols.size()) {
+ DiagRefProtocolError(FirstContainer->getLocation(),
+ GetProtoListSourceRange(FirstProtocols), NumProtocols)
+ << FirstProtocols.size();
+ DiagRefProtocolNote(SecondContainer->getLocation(),
+ GetProtoListSourceRange(SecondProtocols), NumProtocols)
+ << SecondProtocols.size();
+ return true;
+ }
+
+ for (unsigned I = 0, E = FirstProtocols.size(); I != E; ++I) {
+ const ObjCProtocolDecl *FirstProtocol = FirstProtocols[I];
+ const ObjCProtocolDecl *SecondProtocol = SecondProtocols[I];
+ DeclarationName FirstProtocolName = FirstProtocol->getDeclName();
+ DeclarationName SecondProtocolName = SecondProtocol->getDeclName();
+ if (FirstProtocolName != SecondProtocolName) {
+ SourceLocation FirstLoc = *(FirstProtocols.loc_begin() + I);
+ SourceLocation SecondLoc = *(SecondProtocols.loc_begin() + I);
+ SourceRange EmptyRange;
+ DiagRefProtocolError(FirstLoc, EmptyRange, ProtocolType)
+ << (I + 1) << FirstProtocolName;
+ DiagRefProtocolNote(SecondLoc, EmptyRange, ProtocolType)
+ << (I + 1) << SecondProtocolName;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchObjCMethod(
+ const NamedDecl *FirstObjCContainer, StringRef FirstModule,
+ StringRef SecondModule, const ObjCMethodDecl *FirstMethod,
+ const ObjCMethodDecl *SecondMethod) const {
+ enum ODRMethodDifference {
+ ReturnType,
+ InstanceOrClass,
+ ControlLevel, // optional/required
+ DesignatedInitializer,
+ Directness,
+ Name,
+ };
+
+ auto DiagError = [FirstObjCContainer, FirstModule, FirstMethod,
+ this](ODRMethodDifference DiffType) {
+ return Diag(FirstMethod->getLocation(),
+ diag::err_module_odr_violation_objc_method)
+ << FirstObjCContainer << FirstModule.empty() << FirstModule
+ << FirstMethod->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [SecondModule, SecondMethod,
+ this](ODRMethodDifference DiffType) {
+ return Diag(SecondMethod->getLocation(),
+ diag::note_module_odr_violation_objc_method)
+ << SecondModule.empty() << SecondModule
+ << SecondMethod->getSourceRange() << DiffType;
+ };
+
+ if (computeODRHash(FirstMethod->getReturnType()) !=
+ computeODRHash(SecondMethod->getReturnType())) {
+ DiagError(ReturnType) << FirstMethod << FirstMethod->getReturnType();
+ DiagNote(ReturnType) << SecondMethod << SecondMethod->getReturnType();
+ return true;
+ }
+
+ if (FirstMethod->isInstanceMethod() != SecondMethod->isInstanceMethod()) {
+ DiagError(InstanceOrClass)
+ << FirstMethod << FirstMethod->isInstanceMethod();
+ DiagNote(InstanceOrClass)
+ << SecondMethod << SecondMethod->isInstanceMethod();
+ return true;
+ }
+ if (FirstMethod->getImplementationControl() !=
+ SecondMethod->getImplementationControl()) {
+ DiagError(ControlLevel) << FirstMethod->getImplementationControl();
+ DiagNote(ControlLevel) << SecondMethod->getImplementationControl();
+ return true;
+ }
+ if (FirstMethod->isThisDeclarationADesignatedInitializer() !=
+ SecondMethod->isThisDeclarationADesignatedInitializer()) {
+ DiagError(DesignatedInitializer)
+ << FirstMethod
+ << FirstMethod->isThisDeclarationADesignatedInitializer();
+ DiagNote(DesignatedInitializer)
+ << SecondMethod
+ << SecondMethod->isThisDeclarationADesignatedInitializer();
+ return true;
+ }
+ if (FirstMethod->isDirectMethod() != SecondMethod->isDirectMethod()) {
+ DiagError(Directness) << FirstMethod << FirstMethod->isDirectMethod();
+ DiagNote(Directness) << SecondMethod << SecondMethod->isDirectMethod();
+ return true;
+ }
+ if (diagnoseSubMismatchMethodParameters(Diags, FirstObjCContainer,
+ FirstModule, SecondModule,
+ FirstMethod, SecondMethod))
+ return true;
+
+ // Check method name *after* looking at the parameters otherwise we get a
+ // less ideal diagnostics: a ObjCMethodName mismatch given that selectors
+ // for different parameters are likely to be different.
+ DeclarationName FirstName = FirstMethod->getDeclName();
+ DeclarationName SecondName = SecondMethod->getDeclName();
+ if (FirstName != SecondName) {
+ DiagError(Name) << FirstName;
+ DiagNote(Name) << SecondName;
+ return true;
+ }
+
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseSubMismatchObjCProperty(
+ const NamedDecl *FirstObjCContainer, StringRef FirstModule,
+ StringRef SecondModule, const ObjCPropertyDecl *FirstProp,
+ const ObjCPropertyDecl *SecondProp) const {
+ enum ODRPropertyDifference {
+ Name,
+ Type,
+ ControlLevel, // optional/required
+ Attribute,
+ };
+
+ auto DiagError = [FirstObjCContainer, FirstModule, FirstProp,
+ this](SourceLocation Loc, ODRPropertyDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_objc_property)
+ << FirstObjCContainer << FirstModule.empty() << FirstModule
+ << FirstProp->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [SecondModule, SecondProp,
+ this](SourceLocation Loc, ODRPropertyDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_objc_property)
+ << SecondModule.empty() << SecondModule
+ << SecondProp->getSourceRange() << DiffType;
+ };
+
+ IdentifierInfo *FirstII = FirstProp->getIdentifier();
+ IdentifierInfo *SecondII = SecondProp->getIdentifier();
+ if (FirstII->getName() != SecondII->getName()) {
+ DiagError(FirstProp->getLocation(), Name) << FirstII;
+ DiagNote(SecondProp->getLocation(), Name) << SecondII;
+ return true;
+ }
+ if (computeODRHash(FirstProp->getType()) !=
+ computeODRHash(SecondProp->getType())) {
+ DiagError(FirstProp->getLocation(), Type)
+ << FirstII << FirstProp->getType();
+ DiagNote(SecondProp->getLocation(), Type)
+ << SecondII << SecondProp->getType();
+ return true;
+ }
+ if (FirstProp->getPropertyImplementation() !=
+ SecondProp->getPropertyImplementation()) {
+ DiagError(FirstProp->getLocation(), ControlLevel)
+ << FirstProp->getPropertyImplementation();
+ DiagNote(SecondProp->getLocation(), ControlLevel)
+ << SecondProp->getPropertyImplementation();
+ return true;
+ }
+
+ // Go over the property attributes and stop at the first mismatch.
+ unsigned FirstAttrs = (unsigned)FirstProp->getPropertyAttributes();
+ unsigned SecondAttrs = (unsigned)SecondProp->getPropertyAttributes();
+ if (FirstAttrs != SecondAttrs) {
+ for (unsigned I = 0; I < NumObjCPropertyAttrsBits; ++I) {
+ unsigned CheckedAttr = (1 << I);
+ if ((FirstAttrs & CheckedAttr) == (SecondAttrs & CheckedAttr))
+ continue;
+
+ bool IsFirstWritten =
+ (unsigned)FirstProp->getPropertyAttributesAsWritten() & CheckedAttr;
+ bool IsSecondWritten =
+ (unsigned)SecondProp->getPropertyAttributesAsWritten() & CheckedAttr;
+ DiagError(IsFirstWritten ? FirstProp->getLParenLoc()
+ : FirstProp->getLocation(),
+ Attribute)
+ << FirstII << (I + 1) << IsFirstWritten;
+ DiagNote(IsSecondWritten ? SecondProp->getLParenLoc()
+ : SecondProp->getLocation(),
+ Attribute)
+ << SecondII << (I + 1);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+ODRDiagsEmitter::DiffResult
+ODRDiagsEmitter::FindTypeDiffs(DeclHashes &FirstHashes,
+ DeclHashes &SecondHashes) {
+ auto DifferenceSelector = [](const Decl *D) {
+ assert(D && "valid Decl required");
+ switch (D->getKind()) {
+ default:
+ return Other;
+ case Decl::AccessSpec:
+ switch (D->getAccess()) {
+ case AS_public:
+ return PublicSpecifer;
+ case AS_private:
+ return PrivateSpecifer;
+ case AS_protected:
+ return ProtectedSpecifer;
+ case AS_none:
+ break;
+ }
+ llvm_unreachable("Invalid access specifier");
+ case Decl::StaticAssert:
+ return StaticAssert;
+ case Decl::Field:
+ return Field;
+ case Decl::CXXMethod:
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ return CXXMethod;
+ case Decl::TypeAlias:
+ return TypeAlias;
+ case Decl::Typedef:
+ return TypeDef;
+ case Decl::Var:
+ return Var;
+ case Decl::Friend:
+ return Friend;
+ case Decl::FunctionTemplate:
+ return FunctionTemplate;
+ case Decl::ObjCMethod:
+ return ObjCMethod;
+ case Decl::ObjCIvar:
+ return ObjCIvar;
+ case Decl::ObjCProperty:
+ return ObjCProperty;
+ }
+ };
+
+ DiffResult DR;
+ auto FirstIt = FirstHashes.begin();
+ auto SecondIt = SecondHashes.begin();
+ while (FirstIt != FirstHashes.end() || SecondIt != SecondHashes.end()) {
+ if (FirstIt != FirstHashes.end() && SecondIt != SecondHashes.end() &&
+ FirstIt->second == SecondIt->second) {
+ ++FirstIt;
+ ++SecondIt;
+ continue;
+ }
+
+ DR.FirstDecl = FirstIt == FirstHashes.end() ? nullptr : FirstIt->first;
+ DR.SecondDecl = SecondIt == SecondHashes.end() ? nullptr : SecondIt->first;
+
+ DR.FirstDiffType =
+ DR.FirstDecl ? DifferenceSelector(DR.FirstDecl) : EndOfClass;
+ DR.SecondDiffType =
+ DR.SecondDecl ? DifferenceSelector(DR.SecondDecl) : EndOfClass;
+ return DR;
+ }
+ return DR;
+}
+
+void ODRDiagsEmitter::diagnoseSubMismatchUnexpected(
+ DiffResult &DR, const NamedDecl *FirstRecord, StringRef FirstModule,
+ const NamedDecl *SecondRecord, StringRef SecondModule) const {
+ Diag(FirstRecord->getLocation(),
+ diag::err_module_odr_violation_different_definitions)
+ << FirstRecord << FirstModule.empty() << FirstModule;
+
+ if (DR.FirstDecl) {
+ Diag(DR.FirstDecl->getLocation(), diag::note_first_module_difference)
+ << FirstRecord << DR.FirstDecl->getSourceRange();
+ }
+
+ Diag(SecondRecord->getLocation(),
+ diag::note_module_odr_violation_different_definitions)
+ << SecondModule;
+
+ if (DR.SecondDecl) {
+ Diag(DR.SecondDecl->getLocation(), diag::note_second_module_difference)
+ << DR.SecondDecl->getSourceRange();
+ }
+}
+
+void ODRDiagsEmitter::diagnoseSubMismatchDifferentDeclKinds(
+ DiffResult &DR, const NamedDecl *FirstRecord, StringRef FirstModule,
+ const NamedDecl *SecondRecord, StringRef SecondModule) const {
+ auto GetMismatchedDeclLoc = [](const NamedDecl *Container,
+ ODRMismatchDecl DiffType, const Decl *D) {
+ SourceLocation Loc;
+ SourceRange Range;
+ if (DiffType == EndOfClass) {
+ if (auto *Tag = dyn_cast<TagDecl>(Container))
+ Loc = Tag->getBraceRange().getEnd();
+ else if (auto *IF = dyn_cast<ObjCInterfaceDecl>(Container))
+ Loc = IF->getAtEndRange().getBegin();
+ else
+ Loc = Container->getEndLoc();
+ } else {
+ Loc = D->getLocation();
+ Range = D->getSourceRange();
+ }
+ return std::make_pair(Loc, Range);
+ };
+
+ auto FirstDiagInfo =
+ GetMismatchedDeclLoc(FirstRecord, DR.FirstDiffType, DR.FirstDecl);
+ Diag(FirstDiagInfo.first, diag::err_module_odr_violation_mismatch_decl)
+ << FirstRecord << FirstModule.empty() << FirstModule
+ << FirstDiagInfo.second << DR.FirstDiffType;
+
+ auto SecondDiagInfo =
+ GetMismatchedDeclLoc(SecondRecord, DR.SecondDiffType, DR.SecondDecl);
+ Diag(SecondDiagInfo.first, diag::note_module_odr_violation_mismatch_decl)
+ << SecondModule.empty() << SecondModule << SecondDiagInfo.second
+ << DR.SecondDiffType;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(
+ const CXXRecordDecl *FirstRecord, const CXXRecordDecl *SecondRecord,
+ const struct CXXRecordDecl::DefinitionData *SecondDD) const {
+ // Multiple different declarations got merged together; tell the user
+ // where they came from.
+ if (FirstRecord == SecondRecord)
+ return false;
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
+
+ const struct CXXRecordDecl::DefinitionData *FirstDD =
+ FirstRecord->DefinitionData;
+ assert(FirstDD && SecondDD && "Definitions without DefinitionData");
+
+ // Diagnostics from DefinitionData are emitted here.
+ if (FirstDD != SecondDD) {
+ // Keep in sync with err_module_odr_violation_definition_data.
+ enum ODRDefinitionDataDifference {
+ NumBases,
+ NumVBases,
+ BaseType,
+ BaseVirtual,
+ BaseAccess,
+ };
+ auto DiagBaseError = [FirstRecord, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRDefinitionDataDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_definition_data)
+ << FirstRecord << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto DiagBaseNote = [&SecondModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRDefinitionDataDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_definition_data)
+ << SecondModule << Range << DiffType;
+ };
+ auto GetSourceRange = [](const struct CXXRecordDecl::DefinitionData *DD) {
+ unsigned NumBases = DD->NumBases;
+ if (NumBases == 0)
+ return SourceRange();
+ ArrayRef<CXXBaseSpecifier> bases = DD->bases();
+ return SourceRange(bases[0].getBeginLoc(),
+ bases[NumBases - 1].getEndLoc());
+ };
+
+ unsigned FirstNumBases = FirstDD->NumBases;
+ unsigned FirstNumVBases = FirstDD->NumVBases;
+ unsigned SecondNumBases = SecondDD->NumBases;
+ unsigned SecondNumVBases = SecondDD->NumVBases;
+ if (FirstNumBases != SecondNumBases) {
+ DiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+ NumBases)
+ << FirstNumBases;
+ DiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+ NumBases)
+ << SecondNumBases;
+ return true;
+ }
+
+ if (FirstNumVBases != SecondNumVBases) {
+ DiagBaseError(FirstRecord->getLocation(), GetSourceRange(FirstDD),
+ NumVBases)
+ << FirstNumVBases;
+ DiagBaseNote(SecondRecord->getLocation(), GetSourceRange(SecondDD),
+ NumVBases)
+ << SecondNumVBases;
+ return true;
+ }
+
+ ArrayRef<CXXBaseSpecifier> FirstBases = FirstDD->bases();
+ ArrayRef<CXXBaseSpecifier> SecondBases = SecondDD->bases();
+ for (unsigned I = 0; I < FirstNumBases; ++I) {
+ const CXXBaseSpecifier FirstBase = FirstBases[I];
+ const CXXBaseSpecifier SecondBase = SecondBases[I];
+ if (computeODRHash(FirstBase.getType()) !=
+ computeODRHash(SecondBase.getType())) {
+ DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseType)
+ << (I + 1) << FirstBase.getType();
+ DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(),
+ BaseType)
+ << (I + 1) << SecondBase.getType();
+ return true;
+ }
+
+ if (FirstBase.isVirtual() != SecondBase.isVirtual()) {
+ DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseVirtual)
+ << (I + 1) << FirstBase.isVirtual() << FirstBase.getType();
+ DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(),
+ BaseVirtual)
+ << (I + 1) << SecondBase.isVirtual() << SecondBase.getType();
+ return true;
+ }
+
+ if (FirstBase.getAccessSpecifierAsWritten() !=
+ SecondBase.getAccessSpecifierAsWritten()) {
+ DiagBaseError(FirstRecord->getLocation(), FirstBase.getSourceRange(),
+ BaseAccess)
+ << (I + 1) << FirstBase.getType()
+ << (int)FirstBase.getAccessSpecifierAsWritten();
+ DiagBaseNote(SecondRecord->getLocation(), SecondBase.getSourceRange(),
+ BaseAccess)
+ << (I + 1) << SecondBase.getType()
+ << (int)SecondBase.getAccessSpecifierAsWritten();
+ return true;
+ }
+ }
+ }
+
+ const ClassTemplateDecl *FirstTemplate =
+ FirstRecord->getDescribedClassTemplate();
+ const ClassTemplateDecl *SecondTemplate =
+ SecondRecord->getDescribedClassTemplate();
+
+ assert(!FirstTemplate == !SecondTemplate &&
+ "Both pointers should be null or non-null");
+
+ if (FirstTemplate && SecondTemplate) {
+ ArrayRef<const NamedDecl *> FirstTemplateParams =
+ FirstTemplate->getTemplateParameters()->asArray();
+ ArrayRef<const NamedDecl *> SecondTemplateParams =
+ SecondTemplate->getTemplateParameters()->asArray();
+ assert(FirstTemplateParams.size() == SecondTemplateParams.size() &&
+ "Number of template parameters should be equal.");
+ for (auto Pair : llvm::zip(FirstTemplateParams, SecondTemplateParams)) {
+ const NamedDecl *FirstDecl = std::get<0>(Pair);
+ const NamedDecl *SecondDecl = std::get<1>(Pair);
+ if (computeODRHash(FirstDecl) == computeODRHash(SecondDecl))
+ continue;
+
+ assert(FirstDecl->getKind() == SecondDecl->getKind() &&
+ "Parameter Decl's should be the same kind.");
+
+ enum ODRTemplateDifference {
+ ParamEmptyName,
+ ParamName,
+ ParamSingleDefaultArgument,
+ ParamDifferentDefaultArgument,
+ };
+
+ auto hasDefaultArg = [](const NamedDecl *D) {
+ if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
+ return TTP->hasDefaultArgument() &&
+ !TTP->defaultArgumentWasInherited();
+ if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
+ return NTTP->hasDefaultArgument() &&
+ !NTTP->defaultArgumentWasInherited();
+ auto *TTP = cast<TemplateTemplateParmDecl>(D);
+ return TTP->hasDefaultArgument() && !TTP->defaultArgumentWasInherited();
+ };
+ bool hasFirstArg = hasDefaultArg(FirstDecl);
+ bool hasSecondArg = hasDefaultArg(SecondDecl);
+
+ ODRTemplateDifference ErrDiffType;
+ ODRTemplateDifference NoteDiffType;
+
+ DeclarationName FirstName = FirstDecl->getDeclName();
+ DeclarationName SecondName = SecondDecl->getDeclName();
+
+ if (FirstName != SecondName) {
+ bool FirstNameEmpty =
+ FirstName.isIdentifier() && !FirstName.getAsIdentifierInfo();
+ bool SecondNameEmpty =
+ SecondName.isIdentifier() && !SecondName.getAsIdentifierInfo();
+ ErrDiffType = FirstNameEmpty ? ParamEmptyName : ParamName;
+ NoteDiffType = SecondNameEmpty ? ParamEmptyName : ParamName;
+ } else if (hasFirstArg == hasSecondArg)
+ ErrDiffType = NoteDiffType = ParamDifferentDefaultArgument;
+ else
+ ErrDiffType = NoteDiffType = ParamSingleDefaultArgument;
+
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_template_parameter)
+ << FirstRecord << FirstModule.empty() << FirstModule
+ << FirstDecl->getSourceRange() << ErrDiffType << hasFirstArg
+ << FirstName;
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_template_parameter)
+ << SecondModule << SecondDecl->getSourceRange() << NoteDiffType
+ << hasSecondArg << SecondName;
+ return true;
+ }
+ }
+
+ auto PopulateHashes = [](DeclHashes &Hashes, const RecordDecl *Record,
+ const DeclContext *DC) {
+ for (const Decl *D : Record->decls()) {
+ if (!ODRHash::isSubDeclToBeProcessed(D, DC))
+ continue;
+ Hashes.emplace_back(D, computeODRHash(D));
+ }
+ };
+
+ DeclHashes FirstHashes;
+ DeclHashes SecondHashes;
+ const DeclContext *DC = FirstRecord;
+ PopulateHashes(FirstHashes, FirstRecord, DC);
+ PopulateHashes(SecondHashes, SecondRecord, DC);
+
+ DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
+ ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
+ ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
+ const Decl *FirstDecl = DR.FirstDecl;
+ const Decl *SecondDecl = DR.SecondDecl;
+
+ if (FirstDiffType == Other || SecondDiffType == Other) {
+ diagnoseSubMismatchUnexpected(DR, FirstRecord, FirstModule, SecondRecord,
+ SecondModule);
+ return true;
+ }
+
+ if (FirstDiffType != SecondDiffType) {
+ diagnoseSubMismatchDifferentDeclKinds(DR, FirstRecord, FirstModule,
+ SecondRecord, SecondModule);
+ return true;
+ }
+
+ // Used with err_module_odr_violation_record and
+ // note_module_odr_violation_record
+ enum ODRCXXRecordDifference {
+ StaticAssertCondition,
+ StaticAssertMessage,
+ StaticAssertOnlyMessage,
+ MethodName,
+ MethodDeleted,
+ MethodDefaulted,
+ MethodVirtual,
+ MethodStatic,
+ MethodVolatile,
+ MethodConst,
+ MethodInline,
+ MethodParameterSingleDefaultArgument,
+ MethodParameterDifferentDefaultArgument,
+ MethodNoTemplateArguments,
+ MethodDifferentNumberTemplateArguments,
+ MethodDifferentTemplateArgument,
+ MethodSingleBody,
+ MethodDifferentBody,
+ FriendTypeFunction,
+ FriendType,
+ FriendFunction,
+ FunctionTemplateDifferentNumberParameters,
+ FunctionTemplateParameterDifferentKind,
+ FunctionTemplateParameterName,
+ FunctionTemplateParameterSingleDefaultArgument,
+ FunctionTemplateParameterDifferentDefaultArgument,
+ FunctionTemplateParameterDifferentType,
+ FunctionTemplatePackParameter,
+ };
+ auto DiagError = [FirstRecord, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRCXXRecordDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_record)
+ << FirstRecord << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range,
+ ODRCXXRecordDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_record)
+ << SecondModule << Range << DiffType;
+ };
+
+ assert(FirstDiffType == SecondDiffType);
+ switch (FirstDiffType) {
+ case Other:
+ case EndOfClass:
+ case PublicSpecifer:
+ case PrivateSpecifer:
+ case ProtectedSpecifer:
+ case ObjCMethod:
+ case ObjCIvar:
+ case ObjCProperty:
+ llvm_unreachable("Invalid diff type");
+
+ case StaticAssert: {
+ const StaticAssertDecl *FirstSA = cast<StaticAssertDecl>(FirstDecl);
+ const StaticAssertDecl *SecondSA = cast<StaticAssertDecl>(SecondDecl);
+
+ const Expr *FirstExpr = FirstSA->getAssertExpr();
+ const Expr *SecondExpr = SecondSA->getAssertExpr();
+ unsigned FirstODRHash = computeODRHash(FirstExpr);
+ unsigned SecondODRHash = computeODRHash(SecondExpr);
+ if (FirstODRHash != SecondODRHash) {
+ DiagError(FirstExpr->getBeginLoc(), FirstExpr->getSourceRange(),
+ StaticAssertCondition);
+ DiagNote(SecondExpr->getBeginLoc(), SecondExpr->getSourceRange(),
+ StaticAssertCondition);
+ return true;
+ }
+
+ const StringLiteral *FirstStr = FirstSA->getMessage();
+ const StringLiteral *SecondStr = SecondSA->getMessage();
+ assert((FirstStr || SecondStr) && "Both messages cannot be empty");
+ if ((FirstStr && !SecondStr) || (!FirstStr && SecondStr)) {
+ SourceLocation FirstLoc, SecondLoc;
+ SourceRange FirstRange, SecondRange;
+ if (FirstStr) {
+ FirstLoc = FirstStr->getBeginLoc();
+ FirstRange = FirstStr->getSourceRange();
+ } else {
+ FirstLoc = FirstSA->getBeginLoc();
+ FirstRange = FirstSA->getSourceRange();
+ }
+ if (SecondStr) {
+ SecondLoc = SecondStr->getBeginLoc();
+ SecondRange = SecondStr->getSourceRange();
+ } else {
+ SecondLoc = SecondSA->getBeginLoc();
+ SecondRange = SecondSA->getSourceRange();
+ }
+ DiagError(FirstLoc, FirstRange, StaticAssertOnlyMessage)
+ << (FirstStr == nullptr);
+ DiagNote(SecondLoc, SecondRange, StaticAssertOnlyMessage)
+ << (SecondStr == nullptr);
+ return true;
+ }
+
+ if (FirstStr && SecondStr &&
+ FirstStr->getString() != SecondStr->getString()) {
+ DiagError(FirstStr->getBeginLoc(), FirstStr->getSourceRange(),
+ StaticAssertMessage);
+ DiagNote(SecondStr->getBeginLoc(), SecondStr->getSourceRange(),
+ StaticAssertMessage);
+ return true;
+ }
+ break;
+ }
+
+ case Field: {
+ if (diagnoseSubMismatchField(FirstRecord, FirstModule, SecondModule,
+ cast<FieldDecl>(FirstDecl),
+ cast<FieldDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+
+ case CXXMethod: {
+ enum {
+ DiagMethod,
+ DiagConstructor,
+ DiagDestructor,
+ } FirstMethodType,
+ SecondMethodType;
+ auto GetMethodTypeForDiagnostics = [](const CXXMethodDecl *D) {
+ if (isa<CXXConstructorDecl>(D))
+ return DiagConstructor;
+ if (isa<CXXDestructorDecl>(D))
+ return DiagDestructor;
+ return DiagMethod;
+ };
+ const CXXMethodDecl *FirstMethod = cast<CXXMethodDecl>(FirstDecl);
+ const CXXMethodDecl *SecondMethod = cast<CXXMethodDecl>(SecondDecl);
+ FirstMethodType = GetMethodTypeForDiagnostics(FirstMethod);
+ SecondMethodType = GetMethodTypeForDiagnostics(SecondMethod);
+ DeclarationName FirstName = FirstMethod->getDeclName();
+ DeclarationName SecondName = SecondMethod->getDeclName();
+ auto DiagMethodError = [&DiagError, FirstMethod, FirstMethodType,
+ FirstName](ODRCXXRecordDifference DiffType) {
+ return DiagError(FirstMethod->getLocation(),
+ FirstMethod->getSourceRange(), DiffType)
+ << FirstMethodType << FirstName;
+ };
+ auto DiagMethodNote = [&DiagNote, SecondMethod, SecondMethodType,
+ SecondName](ODRCXXRecordDifference DiffType) {
+ return DiagNote(SecondMethod->getLocation(),
+ SecondMethod->getSourceRange(), DiffType)
+ << SecondMethodType << SecondName;
+ };
+
+ if (FirstMethodType != SecondMethodType || FirstName != SecondName) {
+ DiagMethodError(MethodName);
+ DiagMethodNote(MethodName);
+ return true;
+ }
+
+ const bool FirstDeleted = FirstMethod->isDeletedAsWritten();
+ const bool SecondDeleted = SecondMethod->isDeletedAsWritten();
+ if (FirstDeleted != SecondDeleted) {
+ DiagMethodError(MethodDeleted) << FirstDeleted;
+ DiagMethodNote(MethodDeleted) << SecondDeleted;
+ return true;
+ }
+
+ const bool FirstDefaulted = FirstMethod->isExplicitlyDefaulted();
+ const bool SecondDefaulted = SecondMethod->isExplicitlyDefaulted();
+ if (FirstDefaulted != SecondDefaulted) {
+ DiagMethodError(MethodDefaulted) << FirstDefaulted;
+ DiagMethodNote(MethodDefaulted) << SecondDefaulted;
+ return true;
+ }
+
+ const bool FirstVirtual = FirstMethod->isVirtualAsWritten();
+ const bool SecondVirtual = SecondMethod->isVirtualAsWritten();
+ const bool FirstPure = FirstMethod->isPure();
+ const bool SecondPure = SecondMethod->isPure();
+ if ((FirstVirtual || SecondVirtual) &&
+ (FirstVirtual != SecondVirtual || FirstPure != SecondPure)) {
+ DiagMethodError(MethodVirtual) << FirstPure << FirstVirtual;
+ DiagMethodNote(MethodVirtual) << SecondPure << SecondVirtual;
+ return true;
+ }
+
+ // CXXMethodDecl::isStatic uses the canonical Decl. With Decl merging,
+ // FirstDecl is the canonical Decl of SecondDecl, so the storage
+ // class needs to be checked instead.
+ StorageClass FirstStorage = FirstMethod->getStorageClass();
+ StorageClass SecondStorage = SecondMethod->getStorageClass();
+ const bool FirstStatic = FirstStorage == SC_Static;
+ const bool SecondStatic = SecondStorage == SC_Static;
+ if (FirstStatic != SecondStatic) {
+ DiagMethodError(MethodStatic) << FirstStatic;
+ DiagMethodNote(MethodStatic) << SecondStatic;
+ return true;
+ }
+
+ const bool FirstVolatile = FirstMethod->isVolatile();
+ const bool SecondVolatile = SecondMethod->isVolatile();
+ if (FirstVolatile != SecondVolatile) {
+ DiagMethodError(MethodVolatile) << FirstVolatile;
+ DiagMethodNote(MethodVolatile) << SecondVolatile;
+ return true;
+ }
+
+ const bool FirstConst = FirstMethod->isConst();
+ const bool SecondConst = SecondMethod->isConst();
+ if (FirstConst != SecondConst) {
+ DiagMethodError(MethodConst) << FirstConst;
+ DiagMethodNote(MethodConst) << SecondConst;
+ return true;
+ }
+
+ const bool FirstInline = FirstMethod->isInlineSpecified();
+ const bool SecondInline = SecondMethod->isInlineSpecified();
+ if (FirstInline != SecondInline) {
+ DiagMethodError(MethodInline) << FirstInline;
+ DiagMethodNote(MethodInline) << SecondInline;
+ return true;
+ }
+
+ if (diagnoseSubMismatchMethodParameters(Diags, FirstRecord,
+ FirstModule, SecondModule,
+ FirstMethod, SecondMethod))
+ return true;
+
+ for (unsigned I = 0, N = FirstMethod->param_size(); I < N; ++I) {
+ const ParmVarDecl *FirstParam = FirstMethod->getParamDecl(I);
+ const ParmVarDecl *SecondParam = SecondMethod->getParamDecl(I);
+
+ const Expr *FirstInit = FirstParam->getInit();
+ const Expr *SecondInit = SecondParam->getInit();
+ if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+ DiagMethodError(MethodParameterSingleDefaultArgument)
+ << (I + 1) << (FirstInit == nullptr)
+ << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
+ DiagMethodNote(MethodParameterSingleDefaultArgument)
+ << (I + 1) << (SecondInit == nullptr)
+ << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+ return true;
+ }
+
+ if (FirstInit && SecondInit &&
+ computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
+ DiagMethodError(MethodParameterDifferentDefaultArgument)
+ << (I + 1) << FirstInit->getSourceRange();
+ DiagMethodNote(MethodParameterDifferentDefaultArgument)
+ << (I + 1) << SecondInit->getSourceRange();
+ return true;
+ }
+ }
+
+ const TemplateArgumentList *FirstTemplateArgs =
+ FirstMethod->getTemplateSpecializationArgs();
+ const TemplateArgumentList *SecondTemplateArgs =
+ SecondMethod->getTemplateSpecializationArgs();
+
+ if ((FirstTemplateArgs && !SecondTemplateArgs) ||
+ (!FirstTemplateArgs && SecondTemplateArgs)) {
+ DiagMethodError(MethodNoTemplateArguments)
+ << (FirstTemplateArgs != nullptr);
+ DiagMethodNote(MethodNoTemplateArguments)
+ << (SecondTemplateArgs != nullptr);
+ return true;
+ }
+
+ if (FirstTemplateArgs && SecondTemplateArgs) {
+ // Remove pack expansions from argument list.
+ auto ExpandTemplateArgumentList = [](const TemplateArgumentList *TAL) {
+ llvm::SmallVector<const TemplateArgument *, 8> ExpandedList;
+ for (const TemplateArgument &TA : TAL->asArray()) {
+ if (TA.getKind() != TemplateArgument::Pack) {
+ ExpandedList.push_back(&TA);
+ continue;
+ }
+ llvm::append_range(ExpandedList,
+ llvm::make_pointer_range(TA.getPackAsArray()));
+ }
+ return ExpandedList;
+ };
+ llvm::SmallVector<const TemplateArgument *, 8> FirstExpandedList =
+ ExpandTemplateArgumentList(FirstTemplateArgs);
+ llvm::SmallVector<const TemplateArgument *, 8> SecondExpandedList =
+ ExpandTemplateArgumentList(SecondTemplateArgs);
+
+ if (FirstExpandedList.size() != SecondExpandedList.size()) {
+ DiagMethodError(MethodDifferentNumberTemplateArguments)
+ << (unsigned)FirstExpandedList.size();
+ DiagMethodNote(MethodDifferentNumberTemplateArguments)
+ << (unsigned)SecondExpandedList.size();
+ return true;
+ }
+
+ for (unsigned i = 0, e = FirstExpandedList.size(); i != e; ++i) {
+ const TemplateArgument &FirstTA = *FirstExpandedList[i],
+ &SecondTA = *SecondExpandedList[i];
+ if (computeODRHash(FirstTA) == computeODRHash(SecondTA))
+ continue;
+
+ DiagMethodError(MethodDifferentTemplateArgument) << FirstTA << i + 1;
+ DiagMethodNote(MethodDifferentTemplateArgument) << SecondTA << i + 1;
+ return true;
+ }
+ }
+
+ // Compute the hash of the method as if it has no body.
+ auto ComputeCXXMethodODRHash = [](const CXXMethodDecl *D) {
+ ODRHash Hasher;
+ Hasher.AddFunctionDecl(D, true /*SkipBody*/);
+ return Hasher.CalculateHash();
+ };
+
+ // Compare the hash generated to the hash stored. A difference means
+ // that a body was present in the original source. Due to merging,
+ // the standard way of detecting a body will not work.
+ const bool HasFirstBody =
+ ComputeCXXMethodODRHash(FirstMethod) != FirstMethod->getODRHash();
+ const bool HasSecondBody =
+ ComputeCXXMethodODRHash(SecondMethod) != SecondMethod->getODRHash();
+
+ if (HasFirstBody != HasSecondBody) {
+ DiagMethodError(MethodSingleBody) << HasFirstBody;
+ DiagMethodNote(MethodSingleBody) << HasSecondBody;
+ return true;
+ }
+
+ if (HasFirstBody && HasSecondBody) {
+ DiagMethodError(MethodDifferentBody);
+ DiagMethodNote(MethodDifferentBody);
+ return true;
+ }
+
+ break;
+ }
+
+ case TypeAlias:
+ case TypeDef: {
+ if (diagnoseSubMismatchTypedef(FirstRecord, FirstModule, SecondModule,
+ cast<TypedefNameDecl>(FirstDecl),
+ cast<TypedefNameDecl>(SecondDecl),
+ FirstDiffType == TypeAlias))
+ return true;
+ break;
+ }
+ case Var: {
+ if (diagnoseSubMismatchVar(FirstRecord, FirstModule, SecondModule,
+ cast<VarDecl>(FirstDecl),
+ cast<VarDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ case Friend: {
+ const FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl);
+ const FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl);
+
+ const NamedDecl *FirstND = FirstFriend->getFriendDecl();
+ const NamedDecl *SecondND = SecondFriend->getFriendDecl();
+
+ TypeSourceInfo *FirstTSI = FirstFriend->getFriendType();
+ TypeSourceInfo *SecondTSI = SecondFriend->getFriendType();
+
+ if (FirstND && SecondND) {
+ DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
+ FriendFunction)
+ << FirstND;
+ DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(),
+ FriendFunction)
+ << SecondND;
+ return true;
+ }
+
+ if (FirstTSI && SecondTSI) {
+ QualType FirstFriendType = FirstTSI->getType();
+ QualType SecondFriendType = SecondTSI->getType();
+ assert(computeODRHash(FirstFriendType) !=
+ computeODRHash(SecondFriendType));
+ DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
+ FriendType)
+ << FirstFriendType;
+ DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(),
+ FriendType)
+ << SecondFriendType;
+ return true;
+ }
+
+ DiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
+ FriendTypeFunction)
+ << (FirstTSI == nullptr);
+ DiagNote(SecondFriend->getFriendLoc(), SecondFriend->getSourceRange(),
+ FriendTypeFunction)
+ << (SecondTSI == nullptr);
+ return true;
+ }
+ case FunctionTemplate: {
+ const FunctionTemplateDecl *FirstTemplate =
+ cast<FunctionTemplateDecl>(FirstDecl);
+ const FunctionTemplateDecl *SecondTemplate =
+ cast<FunctionTemplateDecl>(SecondDecl);
+
+ TemplateParameterList *FirstTPL = FirstTemplate->getTemplateParameters();
+ TemplateParameterList *SecondTPL = SecondTemplate->getTemplateParameters();
+
+ auto DiagTemplateError = [&DiagError,
+ FirstTemplate](ODRCXXRecordDifference DiffType) {
+ return DiagError(FirstTemplate->getLocation(),
+ FirstTemplate->getSourceRange(), DiffType)
+ << FirstTemplate;
+ };
+ auto DiagTemplateNote = [&DiagNote,
+ SecondTemplate](ODRCXXRecordDifference DiffType) {
+ return DiagNote(SecondTemplate->getLocation(),
+ SecondTemplate->getSourceRange(), DiffType)
+ << SecondTemplate;
+ };
+
+ if (FirstTPL->size() != SecondTPL->size()) {
+ DiagTemplateError(FunctionTemplateDifferentNumberParameters)
+ << FirstTPL->size();
+ DiagTemplateNote(FunctionTemplateDifferentNumberParameters)
+ << SecondTPL->size();
+ return true;
+ }
+
+ for (unsigned i = 0, e = FirstTPL->size(); i != e; ++i) {
+ NamedDecl *FirstParam = FirstTPL->getParam(i);
+ NamedDecl *SecondParam = SecondTPL->getParam(i);
+
+ if (FirstParam->getKind() != SecondParam->getKind()) {
+ enum {
+ TemplateTypeParameter,
+ NonTypeTemplateParameter,
+ TemplateTemplateParameter,
+ };
+ auto GetParamType = [](NamedDecl *D) {
+ switch (D->getKind()) {
+ default:
+ llvm_unreachable("Unexpected template parameter type");
+ case Decl::TemplateTypeParm:
+ return TemplateTypeParameter;
+ case Decl::NonTypeTemplateParm:
+ return NonTypeTemplateParameter;
+ case Decl::TemplateTemplateParm:
+ return TemplateTemplateParameter;
+ }
+ };
+
+ DiagTemplateError(FunctionTemplateParameterDifferentKind)
+ << (i + 1) << GetParamType(FirstParam);
+ DiagTemplateNote(FunctionTemplateParameterDifferentKind)
+ << (i + 1) << GetParamType(SecondParam);
+ return true;
+ }
+
+ if (FirstParam->getName() != SecondParam->getName()) {
+ DiagTemplateError(FunctionTemplateParameterName)
+ << (i + 1) << (bool)FirstParam->getIdentifier() << FirstParam;
+ DiagTemplateNote(FunctionTemplateParameterName)
+ << (i + 1) << (bool)SecondParam->getIdentifier() << SecondParam;
+ return true;
+ }
+
+ if (isa<TemplateTypeParmDecl>(FirstParam) &&
+ isa<TemplateTypeParmDecl>(SecondParam)) {
+ TemplateTypeParmDecl *FirstTTPD =
+ cast<TemplateTypeParmDecl>(FirstParam);
+ TemplateTypeParmDecl *SecondTTPD =
+ cast<TemplateTypeParmDecl>(SecondParam);
+ bool HasFirstDefaultArgument =
+ FirstTTPD->hasDefaultArgument() &&
+ !FirstTTPD->defaultArgumentWasInherited();
+ bool HasSecondDefaultArgument =
+ SecondTTPD->hasDefaultArgument() &&
+ !SecondTTPD->defaultArgumentWasInherited();
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasFirstDefaultArgument;
+ DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasSecondDefaultArgument;
+ return true;
+ }
+
+ if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
+ QualType FirstType = FirstTTPD->getDefaultArgument();
+ QualType SecondType = SecondTTPD->getDefaultArgument();
+ if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
+ DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << FirstType;
+ DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << SecondType;
+ return true;
+ }
+ }
+
+ if (FirstTTPD->isParameterPack() != SecondTTPD->isParameterPack()) {
+ DiagTemplateError(FunctionTemplatePackParameter)
+ << (i + 1) << FirstTTPD->isParameterPack();
+ DiagTemplateNote(FunctionTemplatePackParameter)
+ << (i + 1) << SecondTTPD->isParameterPack();
+ return true;
+ }
+ }
+
+ if (isa<TemplateTemplateParmDecl>(FirstParam) &&
+ isa<TemplateTemplateParmDecl>(SecondParam)) {
+ TemplateTemplateParmDecl *FirstTTPD =
+ cast<TemplateTemplateParmDecl>(FirstParam);
+ TemplateTemplateParmDecl *SecondTTPD =
+ cast<TemplateTemplateParmDecl>(SecondParam);
+
+ TemplateParameterList *FirstTPL = FirstTTPD->getTemplateParameters();
+ TemplateParameterList *SecondTPL = SecondTTPD->getTemplateParameters();
+
+ auto ComputeTemplateParameterListODRHash =
+ [](const TemplateParameterList *TPL) {
+ assert(TPL);
+ ODRHash Hasher;
+ Hasher.AddTemplateParameterList(TPL);
+ return Hasher.CalculateHash();
+ };
+
+ if (ComputeTemplateParameterListODRHash(FirstTPL) !=
+ ComputeTemplateParameterListODRHash(SecondTPL)) {
+ DiagTemplateError(FunctionTemplateParameterDifferentType) << (i + 1);
+ DiagTemplateNote(FunctionTemplateParameterDifferentType) << (i + 1);
+ return true;
+ }
+
+ bool HasFirstDefaultArgument =
+ FirstTTPD->hasDefaultArgument() &&
+ !FirstTTPD->defaultArgumentWasInherited();
+ bool HasSecondDefaultArgument =
+ SecondTTPD->hasDefaultArgument() &&
+ !SecondTTPD->defaultArgumentWasInherited();
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasFirstDefaultArgument;
+ DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasSecondDefaultArgument;
+ return true;
+ }
+
+ if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
+ TemplateArgument FirstTA =
+ FirstTTPD->getDefaultArgument().getArgument();
+ TemplateArgument SecondTA =
+ SecondTTPD->getDefaultArgument().getArgument();
+ if (computeODRHash(FirstTA) != computeODRHash(SecondTA)) {
+ DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << FirstTA;
+ DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << SecondTA;
+ return true;
+ }
+ }
+
+ if (FirstTTPD->isParameterPack() != SecondTTPD->isParameterPack()) {
+ DiagTemplateError(FunctionTemplatePackParameter)
+ << (i + 1) << FirstTTPD->isParameterPack();
+ DiagTemplateNote(FunctionTemplatePackParameter)
+ << (i + 1) << SecondTTPD->isParameterPack();
+ return true;
+ }
+ }
+
+ if (isa<NonTypeTemplateParmDecl>(FirstParam) &&
+ isa<NonTypeTemplateParmDecl>(SecondParam)) {
+ NonTypeTemplateParmDecl *FirstNTTPD =
+ cast<NonTypeTemplateParmDecl>(FirstParam);
+ NonTypeTemplateParmDecl *SecondNTTPD =
+ cast<NonTypeTemplateParmDecl>(SecondParam);
+
+ QualType FirstType = FirstNTTPD->getType();
+ QualType SecondType = SecondNTTPD->getType();
+ if (computeODRHash(FirstType) != computeODRHash(SecondType)) {
+ DiagTemplateError(FunctionTemplateParameterDifferentType) << (i + 1);
+ DiagTemplateNote(FunctionTemplateParameterDifferentType) << (i + 1);
+ return true;
+ }
+
+ bool HasFirstDefaultArgument =
+ FirstNTTPD->hasDefaultArgument() &&
+ !FirstNTTPD->defaultArgumentWasInherited();
+ bool HasSecondDefaultArgument =
+ SecondNTTPD->hasDefaultArgument() &&
+ !SecondNTTPD->defaultArgumentWasInherited();
+ if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
+ DiagTemplateError(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasFirstDefaultArgument;
+ DiagTemplateNote(FunctionTemplateParameterSingleDefaultArgument)
+ << (i + 1) << HasSecondDefaultArgument;
+ return true;
+ }
+
+ if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
+ Expr *FirstDefaultArgument = FirstNTTPD->getDefaultArgument();
+ Expr *SecondDefaultArgument = SecondNTTPD->getDefaultArgument();
+ if (computeODRHash(FirstDefaultArgument) !=
+ computeODRHash(SecondDefaultArgument)) {
+ DiagTemplateError(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << FirstDefaultArgument;
+ DiagTemplateNote(FunctionTemplateParameterDifferentDefaultArgument)
+ << (i + 1) << SecondDefaultArgument;
+ return true;
+ }
+ }
+
+ if (FirstNTTPD->isParameterPack() != SecondNTTPD->isParameterPack()) {
+ DiagTemplateError(FunctionTemplatePackParameter)
+ << (i + 1) << FirstNTTPD->isParameterPack();
+ DiagTemplateNote(FunctionTemplatePackParameter)
+ << (i + 1) << SecondNTTPD->isParameterPack();
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_mismatch_decl_unknown)
+ << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType
+ << FirstDecl->getSourceRange();
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_mismatch_decl_unknown)
+ << SecondModule.empty() << SecondModule << FirstDiffType
+ << SecondDecl->getSourceRange();
+ return true;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(const RecordDecl *FirstRecord,
+ const RecordDecl *SecondRecord) const {
+ if (FirstRecord == SecondRecord)
+ return false;
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstRecord);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondRecord);
+
+ auto PopulateHashes = [](DeclHashes &Hashes, const RecordDecl *Record,
+ const DeclContext *DC) {
+ for (const Decl *D : Record->decls()) {
+ if (!ODRHash::isSubDeclToBeProcessed(D, DC))
+ continue;
+ Hashes.emplace_back(D, computeODRHash(D));
+ }
+ };
+
+ DeclHashes FirstHashes;
+ DeclHashes SecondHashes;
+ const DeclContext *DC = FirstRecord;
+ PopulateHashes(FirstHashes, FirstRecord, DC);
+ PopulateHashes(SecondHashes, SecondRecord, DC);
+
+ DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
+ ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
+ ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
+ const Decl *FirstDecl = DR.FirstDecl;
+ const Decl *SecondDecl = DR.SecondDecl;
+
+ if (FirstDiffType == Other || SecondDiffType == Other) {
+ diagnoseSubMismatchUnexpected(DR, FirstRecord, FirstModule, SecondRecord,
+ SecondModule);
+ return true;
+ }
+
+ if (FirstDiffType != SecondDiffType) {
+ diagnoseSubMismatchDifferentDeclKinds(DR, FirstRecord, FirstModule,
+ SecondRecord, SecondModule);
+ return true;
+ }
+
+ assert(FirstDiffType == SecondDiffType);
+ switch (FirstDiffType) {
+ // Already handled.
+ case EndOfClass:
+ case Other:
+ // C++ only, invalid in this context.
+ case PublicSpecifer:
+ case PrivateSpecifer:
+ case ProtectedSpecifer:
+ case StaticAssert:
+ case CXXMethod:
+ case TypeAlias:
+ case Friend:
+ case FunctionTemplate:
+ // Cannot be contained by RecordDecl, invalid in this context.
+ case ObjCMethod:
+ case ObjCIvar:
+ case ObjCProperty:
+ llvm_unreachable("Invalid diff type");
+
+ case Field: {
+ if (diagnoseSubMismatchField(FirstRecord, FirstModule, SecondModule,
+ cast<FieldDecl>(FirstDecl),
+ cast<FieldDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ case TypeDef: {
+ if (diagnoseSubMismatchTypedef(FirstRecord, FirstModule, SecondModule,
+ cast<TypedefNameDecl>(FirstDecl),
+ cast<TypedefNameDecl>(SecondDecl),
+ /*IsTypeAlias=*/false))
+ return true;
+ break;
+ }
+ case Var: {
+ if (diagnoseSubMismatchVar(FirstRecord, FirstModule, SecondModule,
+ cast<VarDecl>(FirstDecl),
+ cast<VarDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ }
+
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_mismatch_decl_unknown)
+ << FirstRecord << FirstModule.empty() << FirstModule << FirstDiffType
+ << FirstDecl->getSourceRange();
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_mismatch_decl_unknown)
+ << SecondModule.empty() << SecondModule << FirstDiffType
+ << SecondDecl->getSourceRange();
+ return true;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(
+ const FunctionDecl *FirstFunction,
+ const FunctionDecl *SecondFunction) const {
+ if (FirstFunction == SecondFunction)
+ return false;
+
+ // Keep in sync with select options in err_module_odr_violation_function.
+ enum ODRFunctionDifference {
+ ReturnType,
+ ParameterName,
+ ParameterType,
+ ParameterSingleDefaultArgument,
+ ParameterDifferentDefaultArgument,
+ FunctionBody,
+ };
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstFunction);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondFunction);
+
+ auto DiagError = [FirstFunction, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRFunctionDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_function)
+ << FirstFunction << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range,
+ ODRFunctionDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_function)
+ << SecondModule << Range << DiffType;
+ };
+
+ if (computeODRHash(FirstFunction->getReturnType()) !=
+ computeODRHash(SecondFunction->getReturnType())) {
+ DiagError(FirstFunction->getReturnTypeSourceRange().getBegin(),
+ FirstFunction->getReturnTypeSourceRange(), ReturnType)
+ << FirstFunction->getReturnType();
+ DiagNote(SecondFunction->getReturnTypeSourceRange().getBegin(),
+ SecondFunction->getReturnTypeSourceRange(), ReturnType)
+ << SecondFunction->getReturnType();
+ return true;
+ }
+
+ assert(FirstFunction->param_size() == SecondFunction->param_size() &&
+ "Merged functions with different number of parameters");
+
+ size_t ParamSize = FirstFunction->param_size();
+ for (unsigned I = 0; I < ParamSize; ++I) {
+ const ParmVarDecl *FirstParam = FirstFunction->getParamDecl(I);
+ const ParmVarDecl *SecondParam = SecondFunction->getParamDecl(I);
+
+ assert(Context.hasSameType(FirstParam->getType(), SecondParam->getType()) &&
+ "Merged function has different parameter types.");
+
+ if (FirstParam->getDeclName() != SecondParam->getDeclName()) {
+ DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterName)
+ << I + 1 << FirstParam->getDeclName();
+ DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterName)
+ << I + 1 << SecondParam->getDeclName();
+ return true;
+ };
+
+ QualType FirstParamType = FirstParam->getType();
+ QualType SecondParamType = SecondParam->getType();
+ if (FirstParamType != SecondParamType &&
+ computeODRHash(FirstParamType) != computeODRHash(SecondParamType)) {
+ if (const DecayedType *ParamDecayedType =
+ FirstParamType->getAs<DecayedType>()) {
+ DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterType)
+ << (I + 1) << FirstParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterType)
+ << (I + 1) << FirstParamType << false;
+ }
+
+ if (const DecayedType *ParamDecayedType =
+ SecondParamType->getAs<DecayedType>()) {
+ DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterType)
+ << (I + 1) << SecondParamType << true
+ << ParamDecayedType->getOriginalType();
+ } else {
+ DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterType)
+ << (I + 1) << SecondParamType << false;
+ }
+ return true;
+ }
+
+ const Expr *FirstInit = FirstParam->getInit();
+ const Expr *SecondInit = SecondParam->getInit();
+ if ((FirstInit == nullptr) != (SecondInit == nullptr)) {
+ DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterSingleDefaultArgument)
+ << (I + 1) << (FirstInit == nullptr)
+ << (FirstInit ? FirstInit->getSourceRange() : SourceRange());
+ DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterSingleDefaultArgument)
+ << (I + 1) << (SecondInit == nullptr)
+ << (SecondInit ? SecondInit->getSourceRange() : SourceRange());
+ return true;
+ }
+
+ if (FirstInit && SecondInit &&
+ computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
+ DiagError(FirstParam->getLocation(), FirstParam->getSourceRange(),
+ ParameterDifferentDefaultArgument)
+ << (I + 1) << FirstInit->getSourceRange();
+ DiagNote(SecondParam->getLocation(), SecondParam->getSourceRange(),
+ ParameterDifferentDefaultArgument)
+ << (I + 1) << SecondInit->getSourceRange();
+ return true;
+ }
+
+ assert(computeODRHash(FirstParam) == computeODRHash(SecondParam) &&
+ "Undiagnosed parameter difference.");
+ }
+
+ // If no error has been generated before now, assume the problem is in
+ // the body and generate a message.
+ DiagError(FirstFunction->getLocation(), FirstFunction->getSourceRange(),
+ FunctionBody);
+ DiagNote(SecondFunction->getLocation(), SecondFunction->getSourceRange(),
+ FunctionBody);
+ return true;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(const EnumDecl *FirstEnum,
+ const EnumDecl *SecondEnum) const {
+ if (FirstEnum == SecondEnum)
+ return false;
+
+ // Keep in sync with select options in err_module_odr_violation_enum.
+ enum ODREnumDifference {
+ SingleScopedEnum,
+ EnumTagKeywordMismatch,
+ SingleSpecifiedType,
+ DifferentSpecifiedTypes,
+ DifferentNumberEnumConstants,
+ EnumConstantName,
+ EnumConstantSingleInitializer,
+ EnumConstantDifferentInitializer,
+ };
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstEnum);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondEnum);
+
+ auto DiagError = [FirstEnum, &FirstModule, this](const auto *DiagAnchor,
+ ODREnumDifference DiffType) {
+ return Diag(DiagAnchor->getLocation(), diag::err_module_odr_violation_enum)
+ << FirstEnum << FirstModule.empty() << FirstModule
+ << DiagAnchor->getSourceRange() << DiffType;
+ };
+ auto DiagNote = [&SecondModule, this](const auto *DiagAnchor,
+ ODREnumDifference DiffType) {
+ return Diag(DiagAnchor->getLocation(), diag::note_module_odr_violation_enum)
+ << SecondModule << DiagAnchor->getSourceRange() << DiffType;
+ };
+
+ if (FirstEnum->isScoped() != SecondEnum->isScoped()) {
+ DiagError(FirstEnum, SingleScopedEnum) << FirstEnum->isScoped();
+ DiagNote(SecondEnum, SingleScopedEnum) << SecondEnum->isScoped();
+ return true;
+ }
+
+ if (FirstEnum->isScoped() && SecondEnum->isScoped()) {
+ if (FirstEnum->isScopedUsingClassTag() !=
+ SecondEnum->isScopedUsingClassTag()) {
+ DiagError(FirstEnum, EnumTagKeywordMismatch)
+ << FirstEnum->isScopedUsingClassTag();
+ DiagNote(SecondEnum, EnumTagKeywordMismatch)
+ << SecondEnum->isScopedUsingClassTag();
+ return true;
+ }
+ }
+
+ QualType FirstUnderlyingType =
+ FirstEnum->getIntegerTypeSourceInfo()
+ ? FirstEnum->getIntegerTypeSourceInfo()->getType()
+ : QualType();
+ QualType SecondUnderlyingType =
+ SecondEnum->getIntegerTypeSourceInfo()
+ ? SecondEnum->getIntegerTypeSourceInfo()->getType()
+ : QualType();
+ if (FirstUnderlyingType.isNull() != SecondUnderlyingType.isNull()) {
+ DiagError(FirstEnum, SingleSpecifiedType) << !FirstUnderlyingType.isNull();
+ DiagNote(SecondEnum, SingleSpecifiedType) << !SecondUnderlyingType.isNull();
+ return true;
+ }
+
+ if (!FirstUnderlyingType.isNull() && !SecondUnderlyingType.isNull()) {
+ if (computeODRHash(FirstUnderlyingType) !=
+ computeODRHash(SecondUnderlyingType)) {
+ DiagError(FirstEnum, DifferentSpecifiedTypes) << FirstUnderlyingType;
+ DiagNote(SecondEnum, DifferentSpecifiedTypes) << SecondUnderlyingType;
+ return true;
+ }
+ }
+
+ // Compare enum constants.
+ using DeclHashes =
+ llvm::SmallVector<std::pair<const EnumConstantDecl *, unsigned>, 4>;
+ auto PopulateHashes = [FirstEnum](DeclHashes &Hashes, const EnumDecl *Enum) {
+ for (const Decl *D : Enum->decls()) {
+ // Due to decl merging, the first EnumDecl is the parent of
+ // Decls in both records.
+ if (!ODRHash::isSubDeclToBeProcessed(D, FirstEnum))
+ continue;
+ assert(isa<EnumConstantDecl>(D) && "Unexpected Decl kind");
+ Hashes.emplace_back(cast<EnumConstantDecl>(D), computeODRHash(D));
+ }
+ };
+ DeclHashes FirstHashes;
+ PopulateHashes(FirstHashes, FirstEnum);
+ DeclHashes SecondHashes;
+ PopulateHashes(SecondHashes, SecondEnum);
+
+ if (FirstHashes.size() != SecondHashes.size()) {
+ DiagError(FirstEnum, DifferentNumberEnumConstants)
+ << (int)FirstHashes.size();
+ DiagNote(SecondEnum, DifferentNumberEnumConstants)
+ << (int)SecondHashes.size();
+ return true;
+ }
+
+ for (unsigned I = 0, N = FirstHashes.size(); I < N; ++I) {
+ if (FirstHashes[I].second == SecondHashes[I].second)
+ continue;
+ const EnumConstantDecl *FirstConstant = FirstHashes[I].first;
+ const EnumConstantDecl *SecondConstant = SecondHashes[I].first;
+
+ if (FirstConstant->getDeclName() != SecondConstant->getDeclName()) {
+ DiagError(FirstConstant, EnumConstantName) << I + 1 << FirstConstant;
+ DiagNote(SecondConstant, EnumConstantName) << I + 1 << SecondConstant;
+ return true;
+ }
+
+ const Expr *FirstInit = FirstConstant->getInitExpr();
+ const Expr *SecondInit = SecondConstant->getInitExpr();
+ if (!FirstInit && !SecondInit)
+ continue;
+
+ if (!FirstInit || !SecondInit) {
+ DiagError(FirstConstant, EnumConstantSingleInitializer)
+ << I + 1 << FirstConstant << (FirstInit != nullptr);
+ DiagNote(SecondConstant, EnumConstantSingleInitializer)
+ << I + 1 << SecondConstant << (SecondInit != nullptr);
+ return true;
+ }
+
+ if (computeODRHash(FirstInit) != computeODRHash(SecondInit)) {
+ DiagError(FirstConstant, EnumConstantDifferentInitializer)
+ << I + 1 << FirstConstant;
+ DiagNote(SecondConstant, EnumConstantDifferentInitializer)
+ << I + 1 << SecondConstant;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(
+ const ObjCInterfaceDecl *FirstID, const ObjCInterfaceDecl *SecondID,
+ const struct ObjCInterfaceDecl::DefinitionData *SecondDD) const {
+ // Multiple different declarations got merged together; tell the user
+ // where they came from.
+ if (FirstID == SecondID)
+ return false;
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstID);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondID);
+
+ // Keep in sync with err_module_odr_violation_objc_interface.
+ enum ODRInterfaceDifference {
+ SuperClassType,
+ IVarAccess,
+ };
+
+ auto DiagError = [FirstID, &FirstModule,
+ this](SourceLocation Loc, SourceRange Range,
+ ODRInterfaceDifference DiffType) {
+ return Diag(Loc, diag::err_module_odr_violation_objc_interface)
+ << FirstID << FirstModule.empty() << FirstModule << Range
+ << DiffType;
+ };
+ auto DiagNote = [&SecondModule, this](SourceLocation Loc, SourceRange Range,
+ ODRInterfaceDifference DiffType) {
+ return Diag(Loc, diag::note_module_odr_violation_objc_interface)
+ << SecondModule.empty() << SecondModule << Range << DiffType;
+ };
+
+ const struct ObjCInterfaceDecl::DefinitionData *FirstDD = &FirstID->data();
+ assert(FirstDD && SecondDD && "Definitions without DefinitionData");
+ if (FirstDD != SecondDD) {
+ // Check for matching super class.
+ auto GetSuperClassSourceRange = [](const TypeSourceInfo *SuperInfo,
+ const ObjCInterfaceDecl *ID) {
+ if (!SuperInfo)
+ return ID->getSourceRange();
+ TypeLoc Loc = SuperInfo->getTypeLoc();
+ return SourceRange(Loc.getBeginLoc(), Loc.getEndLoc());
+ };
+
+ ObjCInterfaceDecl *FirstSuperClass = FirstID->getSuperClass();
+ ObjCInterfaceDecl *SecondSuperClass = nullptr;
+ const TypeSourceInfo *FirstSuperInfo = FirstID->getSuperClassTInfo();
+ const TypeSourceInfo *SecondSuperInfo = SecondDD->SuperClassTInfo;
+ if (SecondSuperInfo)
+ SecondSuperClass =
+ SecondSuperInfo->getType()->castAs<ObjCObjectType>()->getInterface();
+
+ if ((FirstSuperClass && SecondSuperClass &&
+ FirstSuperClass->getODRHash() != SecondSuperClass->getODRHash()) ||
+ (FirstSuperClass && !SecondSuperClass) ||
+ (!FirstSuperClass && SecondSuperClass)) {
+ QualType FirstType;
+ if (FirstSuperInfo)
+ FirstType = FirstSuperInfo->getType();
+
+ DiagError(FirstID->getLocation(),
+ GetSuperClassSourceRange(FirstSuperInfo, FirstID),
+ SuperClassType)
+ << (bool)FirstSuperInfo << FirstType;
+
+ QualType SecondType;
+ if (SecondSuperInfo)
+ SecondType = SecondSuperInfo->getType();
+
+ DiagNote(SecondID->getLocation(),
+ GetSuperClassSourceRange(SecondSuperInfo, SecondID),
+ SuperClassType)
+ << (bool)SecondSuperInfo << SecondType;
+ return true;
+ }
+
+ // Check both interfaces reference the same protocols.
+ auto &FirstProtos = FirstID->getReferencedProtocols();
+ auto &SecondProtos = SecondDD->ReferencedProtocols;
+ if (diagnoseSubMismatchProtocols(FirstProtos, FirstID, FirstModule,
+ SecondProtos, SecondID, SecondModule))
+ return true;
+ }
+
+ auto PopulateHashes = [](DeclHashes &Hashes, const ObjCInterfaceDecl *ID,
+ const DeclContext *DC) {
+ for (auto *D : ID->decls()) {
+ if (!ODRHash::isSubDeclToBeProcessed(D, DC))
+ continue;
+ Hashes.emplace_back(D, computeODRHash(D));
+ }
+ };
+
+ DeclHashes FirstHashes;
+ DeclHashes SecondHashes;
+ // Use definition as DeclContext because definitions are merged when
+ // DeclContexts are merged and separate when DeclContexts are separate.
+ PopulateHashes(FirstHashes, FirstID, FirstID->getDefinition());
+ PopulateHashes(SecondHashes, SecondID, SecondID->getDefinition());
+
+ DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
+ ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
+ ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
+ const Decl *FirstDecl = DR.FirstDecl;
+ const Decl *SecondDecl = DR.SecondDecl;
+
+ if (FirstDiffType == Other || SecondDiffType == Other) {
+ diagnoseSubMismatchUnexpected(DR, FirstID, FirstModule, SecondID,
+ SecondModule);
+ return true;
+ }
+
+ if (FirstDiffType != SecondDiffType) {
+ diagnoseSubMismatchDifferentDeclKinds(DR, FirstID, FirstModule, SecondID,
+ SecondModule);
+ return true;
+ }
+
+ assert(FirstDiffType == SecondDiffType);
+ switch (FirstDiffType) {
+ // Already handled.
+ case EndOfClass:
+ case Other:
+ // Cannot be contained by ObjCInterfaceDecl, invalid in this context.
+ case Field:
+ case TypeDef:
+ case Var:
+ // C++ only, invalid in this context.
+ case PublicSpecifer:
+ case PrivateSpecifer:
+ case ProtectedSpecifer:
+ case StaticAssert:
+ case CXXMethod:
+ case TypeAlias:
+ case Friend:
+ case FunctionTemplate:
+ llvm_unreachable("Invalid diff type");
+
+ case ObjCMethod: {
+ if (diagnoseSubMismatchObjCMethod(FirstID, FirstModule, SecondModule,
+ cast<ObjCMethodDecl>(FirstDecl),
+ cast<ObjCMethodDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ case ObjCIvar: {
+ if (diagnoseSubMismatchField(FirstID, FirstModule, SecondModule,
+ cast<FieldDecl>(FirstDecl),
+ cast<FieldDecl>(SecondDecl)))
+ return true;
+
+ // Check if the access match.
+ const ObjCIvarDecl *FirstIvar = cast<ObjCIvarDecl>(FirstDecl);
+ const ObjCIvarDecl *SecondIvar = cast<ObjCIvarDecl>(SecondDecl);
+ if (FirstIvar->getCanonicalAccessControl() !=
+ SecondIvar->getCanonicalAccessControl()) {
+ DiagError(FirstIvar->getLocation(), FirstIvar->getSourceRange(),
+ IVarAccess)
+ << FirstIvar->getName()
+ << (int)FirstIvar->getCanonicalAccessControl();
+ DiagNote(SecondIvar->getLocation(), SecondIvar->getSourceRange(),
+ IVarAccess)
+ << SecondIvar->getName()
+ << (int)SecondIvar->getCanonicalAccessControl();
+ return true;
+ }
+ break;
+ }
+ case ObjCProperty: {
+ if (diagnoseSubMismatchObjCProperty(FirstID, FirstModule, SecondModule,
+ cast<ObjCPropertyDecl>(FirstDecl),
+ cast<ObjCPropertyDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ }
+
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_mismatch_decl_unknown)
+ << FirstID << FirstModule.empty() << FirstModule << FirstDiffType
+ << FirstDecl->getSourceRange();
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_mismatch_decl_unknown)
+ << SecondModule << FirstDiffType << SecondDecl->getSourceRange();
+ return true;
+}
+
+bool ODRDiagsEmitter::diagnoseMismatch(
+ const ObjCProtocolDecl *FirstProtocol,
+ const ObjCProtocolDecl *SecondProtocol,
+ const struct ObjCProtocolDecl::DefinitionData *SecondDD) const {
+ if (FirstProtocol == SecondProtocol)
+ return false;
+
+ std::string FirstModule = getOwningModuleNameForDiagnostic(FirstProtocol);
+ std::string SecondModule = getOwningModuleNameForDiagnostic(SecondProtocol);
+
+ const ObjCProtocolDecl::DefinitionData *FirstDD = &FirstProtocol->data();
+ assert(FirstDD && SecondDD && "Definitions without DefinitionData");
+ // Diagnostics from ObjCProtocol DefinitionData are emitted here.
+ if (FirstDD != SecondDD) {
+ // Check both protocols reference the same protocols.
+ const ObjCProtocolList &FirstProtocols =
+ FirstProtocol->getReferencedProtocols();
+ const ObjCProtocolList &SecondProtocols = SecondDD->ReferencedProtocols;
+ if (diagnoseSubMismatchProtocols(FirstProtocols, FirstProtocol, FirstModule,
+ SecondProtocols, SecondProtocol,
+ SecondModule))
+ return true;
+ }
+
+ auto PopulateHashes = [](DeclHashes &Hashes, const ObjCProtocolDecl *ID,
+ const DeclContext *DC) {
+ for (const Decl *D : ID->decls()) {
+ if (!ODRHash::isSubDeclToBeProcessed(D, DC))
+ continue;
+ Hashes.emplace_back(D, computeODRHash(D));
+ }
+ };
+
+ DeclHashes FirstHashes;
+ DeclHashes SecondHashes;
+ // Use definition as DeclContext because definitions are merged when
+ // DeclContexts are merged and separate when DeclContexts are separate.
+ PopulateHashes(FirstHashes, FirstProtocol, FirstProtocol->getDefinition());
+ PopulateHashes(SecondHashes, SecondProtocol, SecondProtocol->getDefinition());
+
+ DiffResult DR = FindTypeDiffs(FirstHashes, SecondHashes);
+ ODRMismatchDecl FirstDiffType = DR.FirstDiffType;
+ ODRMismatchDecl SecondDiffType = DR.SecondDiffType;
+ const Decl *FirstDecl = DR.FirstDecl;
+ const Decl *SecondDecl = DR.SecondDecl;
+
+ if (FirstDiffType == Other || SecondDiffType == Other) {
+ diagnoseSubMismatchUnexpected(DR, FirstProtocol, FirstModule,
+ SecondProtocol, SecondModule);
+ return true;
+ }
+
+ if (FirstDiffType != SecondDiffType) {
+ diagnoseSubMismatchDifferentDeclKinds(DR, FirstProtocol, FirstModule,
+ SecondProtocol, SecondModule);
+ return true;
+ }
+
+ assert(FirstDiffType == SecondDiffType);
+ switch (FirstDiffType) {
+ // Already handled.
+ case EndOfClass:
+ case Other:
+ // Cannot be contained by ObjCProtocolDecl, invalid in this context.
+ case Field:
+ case TypeDef:
+ case Var:
+ case ObjCIvar:
+ // C++ only, invalid in this context.
+ case PublicSpecifer:
+ case PrivateSpecifer:
+ case ProtectedSpecifer:
+ case StaticAssert:
+ case CXXMethod:
+ case TypeAlias:
+ case Friend:
+ case FunctionTemplate:
+ llvm_unreachable("Invalid diff type");
+ case ObjCMethod: {
+ if (diagnoseSubMismatchObjCMethod(FirstProtocol, FirstModule, SecondModule,
+ cast<ObjCMethodDecl>(FirstDecl),
+ cast<ObjCMethodDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ case ObjCProperty: {
+ if (diagnoseSubMismatchObjCProperty(FirstProtocol, FirstModule,
+ SecondModule,
+ cast<ObjCPropertyDecl>(FirstDecl),
+ cast<ObjCPropertyDecl>(SecondDecl)))
+ return true;
+ break;
+ }
+ }
+
+ Diag(FirstDecl->getLocation(),
+ diag::err_module_odr_violation_mismatch_decl_unknown)
+ << FirstProtocol << FirstModule.empty() << FirstModule << FirstDiffType
+ << FirstDecl->getSourceRange();
+ Diag(SecondDecl->getLocation(),
+ diag::note_module_odr_violation_mismatch_decl_unknown)
+ << SecondModule.empty() << SecondModule << FirstDiffType
+ << SecondDecl->getSourceRange();
+ return true;
+}
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 04cbb09356d7..3374b49f5d8e 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -72,7 +72,10 @@ void ODRHash::AddDeclarationNameImpl(DeclarationName Name) {
AddBoolean(S.isUnarySelector());
unsigned NumArgs = S.getNumArgs();
ID.AddInteger(NumArgs);
- for (unsigned i = 0; i < NumArgs; ++i) {
+ // Compare all selector slots. For selectors with arguments it means all arg
+ // slots. And if there are no arguments, compare the first-and-only slot.
+ unsigned SlotsToCheck = NumArgs > 0 ? NumArgs : 1;
+ for (unsigned i = 0; i < SlotsToCheck; ++i) {
const IdentifierInfo *II = S.getIdentifierInfoForSlot(i);
AddBoolean(II);
if (II) {
@@ -169,8 +172,14 @@ void ODRHash::AddTemplateArgument(TemplateArgument TA) {
AddDecl(TA.getAsDecl());
break;
case TemplateArgument::NullPtr:
- case TemplateArgument::Integral:
+ ID.AddPointer(nullptr);
break;
+ case TemplateArgument::Integral: {
+ // There are integrals (e.g.: _BitInt(128)) that cannot be represented as
+ // any builtin integral type, so we use the hash of APSInt instead.
+ TA.getAsIntegral().Profile(ID);
+ break;
+ }
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
AddTemplateName(TA.getAsTemplateOrTemplatePattern());
@@ -334,6 +343,20 @@ public:
Inherited::VisitFieldDecl(D);
}
+ void VisitObjCIvarDecl(const ObjCIvarDecl *D) {
+ ID.AddInteger(D->getCanonicalAccessControl());
+ Inherited::VisitObjCIvarDecl(D);
+ }
+
+ void VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
+ ID.AddInteger(D->getPropertyAttributes());
+ ID.AddInteger(D->getPropertyImplementation());
+ AddQualType(D->getType());
+ AddDecl(D);
+
+ Inherited::VisitObjCPropertyDecl(D);
+ }
+
void VisitFunctionDecl(const FunctionDecl *D) {
// Handled by the ODRHash for FunctionDecl
ID.AddInteger(D->getODRHash());
@@ -347,6 +370,64 @@ public:
Inherited::VisitCXXMethodDecl(D);
}
+ void VisitObjCMethodDecl(const ObjCMethodDecl *Method) {
+ ID.AddInteger(Method->getDeclKind());
+ Hash.AddBoolean(Method->isInstanceMethod()); // false if class method
+ Hash.AddBoolean(Method->isPropertyAccessor());
+ Hash.AddBoolean(Method->isVariadic());
+ Hash.AddBoolean(Method->isSynthesizedAccessorStub());
+ Hash.AddBoolean(Method->isDefined());
+ Hash.AddBoolean(Method->isOverriding());
+ Hash.AddBoolean(Method->isDirectMethod());
+ Hash.AddBoolean(Method->isThisDeclarationADesignatedInitializer());
+ Hash.AddBoolean(Method->hasSkippedBody());
+
+ ID.AddInteger(Method->getImplementationControl());
+ ID.AddInteger(Method->getMethodFamily());
+ ImplicitParamDecl *Cmd = Method->getCmdDecl();
+ Hash.AddBoolean(Cmd);
+ if (Cmd)
+ ID.AddInteger(Cmd->getParameterKind());
+
+ ImplicitParamDecl *Self = Method->getSelfDecl();
+ Hash.AddBoolean(Self);
+ if (Self)
+ ID.AddInteger(Self->getParameterKind());
+
+ AddDecl(Method);
+
+ AddQualType(Method->getReturnType());
+ ID.AddInteger(Method->param_size());
+ for (auto Param : Method->parameters())
+ Hash.AddSubDecl(Param);
+
+ if (Method->hasBody()) {
+ const bool IsDefinition = Method->isThisDeclarationADefinition();
+ Hash.AddBoolean(IsDefinition);
+ if (IsDefinition) {
+ Stmt *Body = Method->getBody();
+ Hash.AddBoolean(Body);
+ if (Body)
+ AddStmt(Body);
+
+ // Filter out sub-Decls which will not be processed in order to get an
+ // accurate count of Decl's.
+ llvm::SmallVector<const Decl *, 16> Decls;
+ for (Decl *SubDecl : Method->decls())
+ if (ODRHash::isSubDeclToBeProcessed(SubDecl, Method))
+ Decls.push_back(SubDecl);
+
+ ID.AddInteger(Decls.size());
+ for (auto SubDecl : Decls)
+ Hash.AddSubDecl(SubDecl);
+ }
+ } else {
+ Hash.AddBoolean(false);
+ }
+
+ Inherited::VisitObjCMethodDecl(Method);
+ }
+
void VisitTypedefNameDecl(const TypedefNameDecl *D) {
AddQualType(D->getUnderlyingType());
@@ -441,7 +522,7 @@ public:
// Only allow a small portion of Decl's to be processed. Remove this once
// all Decl's can be handled.
-bool ODRHash::isDeclToBeProcessed(const Decl *D, const DeclContext *Parent) {
+bool ODRHash::isSubDeclToBeProcessed(const Decl *D, const DeclContext *Parent) {
if (D->isImplicit()) return false;
if (D->getDeclContext() != Parent) return false;
@@ -460,6 +541,9 @@ bool ODRHash::isDeclToBeProcessed(const Decl *D, const DeclContext *Parent) {
case Decl::TypeAlias:
case Decl::Typedef:
case Decl::Var:
+ case Decl::ObjCMethod:
+ case Decl::ObjCIvar:
+ case Decl::ObjCProperty:
return true;
}
}
@@ -488,7 +572,7 @@ void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
// accurate count of Decl's.
llvm::SmallVector<const Decl *, 16> Decls;
for (Decl *SubDecl : Record->decls()) {
- if (isDeclToBeProcessed(SubDecl, Record)) {
+ if (isSubDeclToBeProcessed(SubDecl, Record)) {
Decls.push_back(SubDecl);
if (auto *Function = dyn_cast<FunctionDecl>(SubDecl)) {
// Compute/Preload ODRHash into FunctionDecl.
@@ -517,6 +601,51 @@ void ODRHash::AddCXXRecordDecl(const CXXRecordDecl *Record) {
}
}
+void ODRHash::AddRecordDecl(const RecordDecl *Record) {
+ assert(!isa<CXXRecordDecl>(Record) &&
+ "For CXXRecordDecl should call AddCXXRecordDecl.");
+ AddDecl(Record);
+
+ // Filter out sub-Decls which will not be processed in order to get an
+ // accurate count of Decl's.
+ llvm::SmallVector<const Decl *, 16> Decls;
+ for (Decl *SubDecl : Record->decls()) {
+ if (isSubDeclToBeProcessed(SubDecl, Record))
+ Decls.push_back(SubDecl);
+ }
+
+ ID.AddInteger(Decls.size());
+ for (const Decl *SubDecl : Decls)
+ AddSubDecl(SubDecl);
+}
+
+void ODRHash::AddObjCInterfaceDecl(const ObjCInterfaceDecl *IF) {
+ AddDecl(IF);
+
+ auto *SuperClass = IF->getSuperClass();
+ AddBoolean(SuperClass);
+ if (SuperClass)
+ ID.AddInteger(SuperClass->getODRHash());
+
+ // Hash referenced protocols.
+ ID.AddInteger(IF->getReferencedProtocols().size());
+ for (const ObjCProtocolDecl *RefP : IF->protocols()) {
+ // Hash the name only as a referenced protocol can be a forward declaration.
+ AddDeclarationName(RefP->getDeclName());
+ }
+
+ // Filter out sub-Decls which will not be processed in order to get an
+ // accurate count of Decl's.
+ llvm::SmallVector<const Decl *, 16> Decls;
+ for (Decl *SubDecl : IF->decls())
+ if (isSubDeclToBeProcessed(SubDecl, IF))
+ Decls.push_back(SubDecl);
+
+ ID.AddInteger(Decls.size());
+ for (auto *SubDecl : Decls)
+ AddSubDecl(SubDecl);
+}
+
void ODRHash::AddFunctionDecl(const FunctionDecl *Function,
bool SkipBody) {
assert(Function && "Expecting non-null pointer.");
@@ -564,7 +693,7 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function,
AddQualType(Function->getReturnType());
ID.AddInteger(Function->param_size());
- for (auto Param : Function->parameters())
+ for (auto *Param : Function->parameters())
AddSubDecl(Param);
if (SkipBody) {
@@ -589,7 +718,7 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function,
// accurate count of Decl's.
llvm::SmallVector<const Decl *, 16> Decls;
for (Decl *SubDecl : Function->decls()) {
- if (isDeclToBeProcessed(SubDecl, Function)) {
+ if (isSubDeclToBeProcessed(SubDecl, Function)) {
Decls.push_back(SubDecl);
}
}
@@ -615,7 +744,7 @@ void ODRHash::AddEnumDecl(const EnumDecl *Enum) {
// accurate count of Decl's.
llvm::SmallVector<const Decl *, 16> Decls;
for (Decl *SubDecl : Enum->decls()) {
- if (isDeclToBeProcessed(SubDecl, Enum)) {
+ if (isSubDeclToBeProcessed(SubDecl, Enum)) {
assert(isa<EnumConstantDecl>(SubDecl) && "Unexpected Decl");
Decls.push_back(SubDecl);
}
@@ -628,6 +757,31 @@ void ODRHash::AddEnumDecl(const EnumDecl *Enum) {
}
+void ODRHash::AddObjCProtocolDecl(const ObjCProtocolDecl *P) {
+ AddDecl(P);
+
+ // Hash referenced protocols.
+ ID.AddInteger(P->getReferencedProtocols().size());
+ for (const ObjCProtocolDecl *RefP : P->protocols()) {
+ // Hash the name only as a referenced protocol can be a forward declaration.
+ AddDeclarationName(RefP->getDeclName());
+ }
+
+ // Filter out sub-Decls which will not be processed in order to get an
+ // accurate count of Decl's.
+ llvm::SmallVector<const Decl *, 16> Decls;
+ for (Decl *SubDecl : P->decls()) {
+ if (isSubDeclToBeProcessed(SubDecl, P)) {
+ Decls.push_back(SubDecl);
+ }
+ }
+
+ ID.AddInteger(Decls.size());
+ for (auto *SubDecl : Decls) {
+ AddSubDecl(SubDecl);
+ }
+}
+
void ODRHash::AddDecl(const Decl *D) {
assert(D && "Expecting non-null pointer.");
D = D->getCanonicalDecl();
@@ -671,7 +825,7 @@ public:
}
}
- void AddDecl(Decl *D) {
+ void AddDecl(const Decl *D) {
Hash.AddBoolean(D);
if (D) {
Hash.AddDecl(D);
@@ -861,7 +1015,7 @@ public:
ID.AddInteger(T->isConstrained());
if (T->isConstrained()) {
AddDecl(T->getTypeConstraintConcept());
- ID.AddInteger(T->getNumArgs());
+ ID.AddInteger(T->getTypeConstraintArguments().size());
for (const auto &TA : T->getTypeConstraintArguments())
Hash.AddTemplateArgument(TA);
}
@@ -934,7 +1088,7 @@ public:
auto Protocols = T->getProtocols();
ID.AddInteger(Protocols.size());
- for (auto Protocol : Protocols) {
+ for (auto *Protocol : Protocols) {
AddDecl(Protocol);
}
@@ -952,7 +1106,7 @@ public:
AddDecl(T->getDecl());
auto Protocols = T->getProtocols();
ID.AddInteger(Protocols.size());
- for (auto Protocol : Protocols) {
+ for (auto *Protocol : Protocols) {
AddDecl(Protocol);
}
@@ -995,13 +1149,13 @@ public:
void
VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T) {
- AddType(T->getReplacedParameter());
+ AddDecl(T->getAssociatedDecl());
Hash.AddTemplateArgument(T->getArgumentPack());
VisitType(T);
}
void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) {
- AddType(T->getReplacedParameter());
+ AddDecl(T->getAssociatedDecl());
AddQualType(T->getReplacementType());
VisitType(T);
}
@@ -1015,7 +1169,7 @@ public:
void VisitEnumType(const EnumType *T) { VisitTagType(T); }
void VisitTemplateSpecializationType(const TemplateSpecializationType *T) {
- ID.AddInteger(T->getNumArgs());
+ ID.AddInteger(T->template_arguments().size());
for (const auto &TA : T->template_arguments()) {
Hash.AddTemplateArgument(TA);
}
@@ -1061,7 +1215,7 @@ public:
VisitType(T);
}
void VisitTypeOfType(const TypeOfType *T) {
- AddQualType(T->getUnderlyingType());
+ AddQualType(T->getUnmodifiedType());
VisitType(T);
}
@@ -1080,7 +1234,7 @@ public:
const DependentTemplateSpecializationType *T) {
AddIdentifierInfo(T->getIdentifier());
AddNestedNameSpecifier(T->getQualifier());
- ID.AddInteger(T->getNumArgs());
+ ID.AddInteger(T->template_arguments().size());
for (const auto &TA : T->template_arguments()) {
Hash.AddTemplateArgument(TA);
}
diff --git a/clang/lib/AST/OSLog.cpp b/clang/lib/AST/OSLog.cpp
index 40fa8c3802c3..5e320416b30d 100644
--- a/clang/lib/AST/OSLog.cpp
+++ b/clang/lib/AST/OSLog.cpp
@@ -8,6 +8,7 @@
#include "clang/AST/FormatString.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/SmallBitVector.h"
+#include <optional>
using namespace clang;
@@ -20,11 +21,11 @@ class OSLogFormatStringHandler
private:
struct ArgData {
const Expr *E = nullptr;
- Optional<OSLogBufferItem::Kind> Kind;
- Optional<unsigned> Size;
- Optional<const Expr *> Count;
- Optional<const Expr *> Precision;
- Optional<const Expr *> FieldWidth;
+ std::optional<OSLogBufferItem::Kind> Kind;
+ std::optional<unsigned> Size;
+ std::optional<const Expr *> Count;
+ std::optional<const Expr *> Precision;
+ std::optional<const Expr *> FieldWidth;
unsigned char Flags = 0;
StringRef MaskType;
};
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index dc2d90e366bc..2e88c08ae789 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -23,6 +23,7 @@
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <cassert>
+#include <optional>
using namespace clang;
using namespace llvm;
@@ -102,6 +103,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
return static_cast<const OMPNocontextClause *>(C);
case OMPC_filter:
return static_cast<const OMPFilterClause *>(C);
+ case OMPC_ompx_dyn_cgroup_mem:
+ return static_cast<const OMPXDynCGroupMemClause *>(C);
case OMPC_default:
case OMPC_proc_bind:
case OMPC_safelen:
@@ -152,6 +155,9 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
@@ -251,6 +257,9 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_at:
+ case OMPC_severity:
+ case OMPC_message:
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
@@ -307,7 +316,7 @@ OMPClause::child_range OMPNumTasksClause::used_children() {
OMPClause::child_range OMPFinalClause::used_children() {
if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
return child_range(C, C + 1);
- return child_range(&Condition, &Condition + 1);
+ return children();
}
OMPClause::child_range OMPPriorityClause::used_children() {
@@ -319,13 +328,13 @@ OMPClause::child_range OMPPriorityClause::used_children() {
OMPClause::child_range OMPNovariantsClause::used_children() {
if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
return child_range(C, C + 1);
- return child_range(&Condition, &Condition + 1);
+ return children();
}
OMPClause::child_range OMPNocontextClause::used_children() {
if (Stmt **C = getAddrOfExprAsWritten(getPreInitStmt()))
return child_range(C, C + 1);
- return child_range(&Condition, &Condition + 1);
+ return children();
}
OMPOrderedClause *OMPOrderedClause::Create(const ASTContext &C, Expr *Num,
@@ -361,7 +370,7 @@ void OMPOrderedClause::setLoopNumIterations(unsigned NumLoop,
}
ArrayRef<Expr *> OMPOrderedClause::getLoopNumIterations() const {
- return llvm::makeArrayRef(getTrailingObjects<Expr *>(), NumberOfLoops);
+ return llvm::ArrayRef(getTrailingObjects<Expr *>(), NumberOfLoops);
}
void OMPOrderedClause::setLoopCounter(unsigned NumLoop, Expr *Counter) {
@@ -1127,7 +1136,7 @@ OMPMapClause *OMPMapClause::Create(
const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef<Expr *> Vars,
ArrayRef<ValueDecl *> Declarations,
MappableExprComponentListsRef ComponentLists, ArrayRef<Expr *> UDMapperRefs,
- ArrayRef<OpenMPMapModifierKind> MapModifiers,
+ Expr *IteratorModifier, ArrayRef<OpenMPMapModifierKind> MapModifiers,
ArrayRef<SourceLocation> MapModifiersLoc,
NestedNameSpecifierLoc UDMQualifierLoc, DeclarationNameInfo MapperId,
OpenMPMapClauseKind Type, bool TypeIsImplicit, SourceLocation TypeLoc) {
@@ -1150,7 +1159,7 @@ OMPMapClause *OMPMapClause::Create(
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ 2 * Sizes.NumVars + 1, Sizes.NumUniqueDeclarations,
Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
Sizes.NumComponents));
OMPMapClause *Clause = new (Mem)
@@ -1159,6 +1168,7 @@ OMPMapClause *OMPMapClause::Create(
Clause->setVarRefs(Vars);
Clause->setUDMapperRefs(UDMapperRefs);
+ Clause->setIteratorModifier(IteratorModifier);
Clause->setClauseInfo(Declarations, ComponentLists);
Clause->setMapType(Type);
Clause->setMapLoc(TypeLoc);
@@ -1171,10 +1181,12 @@ OMPMapClause::CreateEmpty(const ASTContext &C,
void *Mem = C.Allocate(
totalSizeToAlloc<Expr *, ValueDecl *, unsigned,
OMPClauseMappableExprCommon::MappableComponent>(
- 2 * Sizes.NumVars, Sizes.NumUniqueDeclarations,
+ 2 * Sizes.NumVars + 1, Sizes.NumUniqueDeclarations,
Sizes.NumUniqueDeclarations + Sizes.NumComponentLists,
Sizes.NumComponents));
- return new (Mem) OMPMapClause(Sizes);
+ OMPMapClause *Clause = new (Mem) OMPMapClause(Sizes);
+ Clause->setIteratorModifier(nullptr);
+ return Clause;
}
OMPToClause *OMPToClause::Create(
@@ -1626,18 +1638,19 @@ OMPAffinityClause *OMPAffinityClause::CreateEmpty(const ASTContext &C,
}
OMPInitClause *OMPInitClause::Create(const ASTContext &C, Expr *InteropVar,
- ArrayRef<Expr *> PrefExprs, bool IsTarget,
- bool IsTargetSync, SourceLocation StartLoc,
+ OMPInteropInfo &InteropInfo,
+ SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation VarLoc,
SourceLocation EndLoc) {
- void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(PrefExprs.size() + 1));
- auto *Clause =
- new (Mem) OMPInitClause(IsTarget, IsTargetSync, StartLoc, LParenLoc,
- VarLoc, EndLoc, PrefExprs.size() + 1);
+ void *Mem =
+ C.Allocate(totalSizeToAlloc<Expr *>(InteropInfo.PreferTypes.size() + 1));
+ auto *Clause = new (Mem) OMPInitClause(
+ InteropInfo.IsTarget, InteropInfo.IsTargetSync, StartLoc, LParenLoc,
+ VarLoc, EndLoc, InteropInfo.PreferTypes.size() + 1);
Clause->setInteropVar(InteropVar);
- llvm::copy(PrefExprs, Clause->getTrailingObjects<Expr *>() + 1);
+ llvm::copy(InteropInfo.PreferTypes, Clause->getTrailingObjects<Expr *>() + 1);
return Clause;
}
@@ -1701,7 +1714,7 @@ void OMPClausePrinter::VisitOMPSimdlenClause(OMPSimdlenClause *Node) {
void OMPClausePrinter::VisitOMPSizesClause(OMPSizesClause *Node) {
OS << "sizes(";
bool First = true;
- for (auto Size : Node->getSizesRefs()) {
+ for (auto *Size : Node->getSizesRefs()) {
if (!First)
OS << ", ";
Size->printPretty(OS, nullptr, Policy, 0);
@@ -1780,6 +1793,22 @@ void OMPClausePrinter::VisitOMPAtomicDefaultMemOrderClause(
<< ")";
}
+void OMPClausePrinter::VisitOMPAtClause(OMPAtClause *Node) {
+ OS << "at(" << getOpenMPSimpleClauseTypeName(OMPC_at, Node->getAtKind())
+ << ")";
+}
+
+void OMPClausePrinter::VisitOMPSeverityClause(OMPSeverityClause *Node) {
+ OS << "severity("
+ << getOpenMPSimpleClauseTypeName(OMPC_severity, Node->getSeverityKind())
+ << ")";
+}
+
+void OMPClausePrinter::VisitOMPMessageClause(OMPMessageClause *Node) {
+ OS << "message(\""
+ << cast<StringLiteral>(Node->getMessageString())->getString() << "\")";
+}
+
void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) {
OS << "schedule(";
if (Node->getFirstScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown) {
@@ -1904,12 +1933,22 @@ void OMPClausePrinter::VisitOMPPriorityClause(OMPPriorityClause *Node) {
void OMPClausePrinter::VisitOMPGrainsizeClause(OMPGrainsizeClause *Node) {
OS << "grainsize(";
+ OpenMPGrainsizeClauseModifier Modifier = Node->getModifier();
+ if (Modifier != OMPC_GRAINSIZE_unknown) {
+ OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(), Modifier)
+ << ": ";
+ }
Node->getGrainsize()->printPretty(OS, nullptr, Policy, 0);
OS << ")";
}
void OMPClausePrinter::VisitOMPNumTasksClause(OMPNumTasksClause *Node) {
OS << "num_tasks(";
+ OpenMPNumTasksClauseModifier Modifier = Node->getModifier();
+ if (Modifier != OMPC_NUMTASKS_unknown) {
+ OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(), Modifier)
+ << ": ";
+ }
Node->getNumTasks()->printPretty(OS, nullptr, Policy, 0);
OS << ")";
}
@@ -2215,16 +2254,27 @@ static void PrintMapper(raw_ostream &OS, T *Node,
OS << Node->getMapperIdInfo() << ')';
}
+template <typename T>
+static void PrintIterator(raw_ostream &OS, T *Node,
+ const PrintingPolicy &Policy) {
+ if (Expr *IteratorModifier = Node->getIteratorModifier())
+ IteratorModifier->printPretty(OS, nullptr, Policy);
+}
+
void OMPClausePrinter::VisitOMPMapClause(OMPMapClause *Node) {
if (!Node->varlist_empty()) {
OS << "map(";
if (Node->getMapType() != OMPC_MAP_unknown) {
for (unsigned I = 0; I < NumberOfOMPMapClauseModifiers; ++I) {
if (Node->getMapTypeModifier(I) != OMPC_MAP_MODIFIER_unknown) {
- OS << getOpenMPSimpleClauseTypeName(OMPC_map,
- Node->getMapTypeModifier(I));
- if (Node->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_mapper)
- PrintMapper(OS, Node, Policy);
+ if (Node->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_iterator) {
+ PrintIterator(OS, Node, Policy);
+ } else {
+ OS << getOpenMPSimpleClauseTypeName(OMPC_map,
+ Node->getMapTypeModifier(I));
+ if (Node->getMapTypeModifier(I) == OMPC_MAP_MODIFIER_mapper)
+ PrintMapper(OS, Node, Policy);
+ }
OS << ',';
}
}
@@ -2337,8 +2387,12 @@ void OMPClausePrinter::VisitOMPNontemporalClause(OMPNontemporalClause *Node) {
}
void OMPClausePrinter::VisitOMPOrderClause(OMPOrderClause *Node) {
- OS << "order(" << getOpenMPSimpleClauseTypeName(OMPC_order, Node->getKind())
- << ")";
+ OS << "order(";
+ if (Node->getModifier() != OMPC_ORDER_MODIFIER_unknown) {
+ OS << getOpenMPSimpleClauseTypeName(OMPC_order, Node->getModifier());
+ OS << ": ";
+ }
+ OS << getOpenMPSimpleClauseTypeName(OMPC_order, Node->getKind()) << ")";
}
void OMPClausePrinter::VisitOMPInclusiveClause(OMPInclusiveClause *Node) {
@@ -2403,6 +2457,13 @@ void OMPClausePrinter::VisitOMPBindClause(OMPBindClause *Node) {
<< ")";
}
+void OMPClausePrinter::VisitOMPXDynCGroupMemClause(
+ OMPXDynCGroupMemClause *Node) {
+ OS << "ompx_dyn_cgroup_mem(";
+ Node->getSize()->printPretty(OS, nullptr, Policy, 0);
+ OS << ")";
+}
+
void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx,
VariantMatchInfo &VMI) const {
for (const OMPTraitSet &Set : Sets) {
@@ -2417,7 +2478,7 @@ void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx,
TraitProperty::user_condition_unknown &&
"Ill-formed user condition, expected unknown trait property!");
- if (Optional<APSInt> CondVal =
+ if (std::optional<APSInt> CondVal =
Selector.ScoreOrCondition->getIntegerConstantExpr(ASTCtx))
VMI.addTrait(CondVal->isZero() ? TraitProperty::user_condition_false
: TraitProperty::user_condition_true,
@@ -2427,7 +2488,7 @@ void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx,
continue;
}
- Optional<llvm::APSInt> Score;
+ std::optional<llvm::APSInt> Score;
llvm::APInt *ScorePtr = nullptr;
if (Selector.ScoreOrCondition) {
if ((Score = Selector.ScoreOrCondition->getIntegerConstantExpr(ASTCtx)))
diff --git a/clang/lib/AST/ParentMap.cpp b/clang/lib/AST/ParentMap.cpp
index da21e573c320..3d6a1cc84c7b 100644
--- a/clang/lib/AST/ParentMap.cpp
+++ b/clang/lib/AST/ParentMap.cpp
@@ -33,9 +33,11 @@ static void BuildParentMap(MapTy& M, Stmt* S,
switch (S->getStmtClass()) {
case Stmt::PseudoObjectExprClass: {
- assert(OVMode == OV_Transparent && "Should not appear alongside OVEs");
PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S);
+ if (OVMode == OV_Opaque && M[POE->getSyntacticForm()])
+ break;
+
// If we are rebuilding the map, clear out any existing state.
if (M[POE->getSyntacticForm()])
for (Stmt *SubStmt : S->children())
diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp
index e0d4700e4b10..21cfd5b1de6e 100644
--- a/clang/lib/AST/ParentMapContext.cpp
+++ b/clang/lib/AST/ParentMapContext.cpp
@@ -99,7 +99,7 @@ class ParentMapContext::ParentMap {
return llvm::ArrayRef<DynTypedNode>();
}
if (const auto *V = I->second.template dyn_cast<ParentVector *>()) {
- return llvm::makeArrayRef(*V);
+ return llvm::ArrayRef(*V);
}
return getSingleDynTypedNodeFromParentMap(I->second);
}
@@ -252,7 +252,7 @@ public:
const auto *S = It->second.dyn_cast<const Stmt *>();
if (!S) {
if (auto *Vec = It->second.dyn_cast<ParentVector *>())
- return llvm::makeArrayRef(*Vec);
+ return llvm::ArrayRef(*Vec);
return getSingleDynTypedNodeFromParentMap(It->second);
}
const auto *P = dyn_cast<Expr>(S);
@@ -265,16 +265,6 @@ public:
}
};
-template <typename Tuple, std::size_t... Is>
-auto tuple_pop_front_impl(const Tuple &tuple, std::index_sequence<Is...>) {
- return std::make_tuple(std::get<1 + Is>(tuple)...);
-}
-
-template <typename Tuple> auto tuple_pop_front(const Tuple &tuple) {
- return tuple_pop_front_impl(
- tuple, std::make_index_sequence<std::tuple_size<Tuple>::value - 1>());
-}
-
template <typename T, typename... U> struct MatchParents {
static std::tuple<bool, DynTypedNodeList, const T *, const U *...>
match(const DynTypedNodeList &NodeList,
@@ -285,10 +275,11 @@ template <typename T, typename... U> struct MatchParents {
if (NextParentList.size() == 1) {
auto TailTuple = MatchParents<U...>::match(NextParentList, ParentMap);
if (std::get<bool>(TailTuple)) {
- return std::tuple_cat(
- std::make_tuple(true, std::get<DynTypedNodeList>(TailTuple),
- TypedNode),
- tuple_pop_front(tuple_pop_front(TailTuple)));
+ return std::apply(
+ [TypedNode](bool, DynTypedNodeList NodeList, auto... TupleTail) {
+ return std::make_tuple(true, NodeList, TypedNode, TupleTail...);
+ },
+ TailTuple);
}
}
}
diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp
index c6c41abc7e9a..96079c235c5e 100644
--- a/clang/lib/AST/PrintfFormatString.cpp
+++ b/clang/lib/AST/PrintfFormatString.cpp
@@ -326,6 +326,14 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case 's': k = ConversionSpecifier::sArg; break;
case 'u': k = ConversionSpecifier::uArg; break;
case 'x': k = ConversionSpecifier::xArg; break;
+ // C23.
+ case 'b':
+ if (isFreeBSDKPrintf)
+ k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
+ else
+ k = ConversionSpecifier::bArg;
+ break;
+ case 'B': k = ConversionSpecifier::BArg; break;
// POSIX specific.
case 'C': k = ConversionSpecifier::CArg; break;
case 'S': k = ConversionSpecifier::SArg; break;
@@ -337,11 +345,6 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,
case '@': k = ConversionSpecifier::ObjCObjArg; break;
// Glibc specific.
case 'm': k = ConversionSpecifier::PrintErrno; break;
- // FreeBSD kernel specific.
- case 'b':
- if (isFreeBSDKPrintf)
- k = ConversionSpecifier::FreeBSDbArg; // int followed by char *
- break;
case 'r':
if (isFreeBSDKPrintf)
k = ConversionSpecifier::FreeBSDrArg; // int
@@ -497,7 +500,7 @@ ArgType PrintfSpecifier::getScalarArgType(ASTContext &Ctx,
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return Ctx.IntTy;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return ArgType::Invalid();
}
@@ -844,7 +847,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
}
// Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
- if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
+ if (LangOpt.C99 || LangOpt.CPlusPlus11)
namedTypeToLengthModifier(QT, LM);
// If fixing the length modifier was enough, we might be done.
@@ -874,7 +877,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
// Set conversion specifier and disable any flags which do not apply to it.
// Let typedefs to char fall through to int, as %c is silly for uint8_t.
- if (!isa<TypedefType>(QT) && QT->isCharType()) {
+ if (!QT->getAs<TypedefType>() && QT->isCharType()) {
CS.setKind(ConversionSpecifier::cArg);
LM.setKind(LengthModifier::None);
Precision.setHowSpecified(OptionalAmount::NotSpecified);
@@ -885,12 +888,10 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,
// Test for Floating type first as LongDouble can pass isUnsignedIntegerType
else if (QT->isRealFloatingType()) {
CS.setKind(ConversionSpecifier::fArg);
- }
- else if (QT->isSignedIntegerType()) {
+ } else if (QT->isSignedIntegerType()) {
CS.setKind(ConversionSpecifier::dArg);
HasAlternativeForm = false;
- }
- else if (QT->isUnsignedIntegerType()) {
+ } else if (QT->isUnsignedIntegerType()) {
CS.setKind(ConversionSpecifier::uArg);
HasAlternativeForm = false;
HasPlusPrefix = false;
@@ -963,8 +964,10 @@ bool PrintfSpecifier::hasValidAlternativeForm() const {
if (!HasAlternativeForm)
return true;
- // Alternate form flag only valid with the oxXaAeEfFgG conversions
+ // Alternate form flag only valid with the bBoxXaAeEfFgG conversions
switch (CS.getKind()) {
+ case ConversionSpecifier::bArg:
+ case ConversionSpecifier::BArg:
case ConversionSpecifier::oArg:
case ConversionSpecifier::OArg:
case ConversionSpecifier::xArg:
@@ -990,8 +993,10 @@ bool PrintfSpecifier::hasValidLeadingZeros() const {
if (!HasLeadingZeroes)
return true;
- // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions
+ // Leading zeroes flag only valid with the bBdiouxXaAeEfFgG conversions
switch (CS.getKind()) {
+ case ConversionSpecifier::bArg:
+ case ConversionSpecifier::BArg:
case ConversionSpecifier::dArg:
case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
@@ -1082,8 +1087,10 @@ bool PrintfSpecifier::hasValidPrecision() const {
if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)
return true;
- // Precision is only valid with the diouxXaAeEfFgGsP conversions
+ // Precision is only valid with the bBdiouxXaAeEfFgGsP conversions
switch (CS.getKind()) {
+ case ConversionSpecifier::bArg:
+ case ConversionSpecifier::BArg:
case ConversionSpecifier::dArg:
case ConversionSpecifier::DArg:
case ConversionSpecifier::iArg:
diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp
index 26aaa96a1dc6..7557336f0aaf 100644
--- a/clang/lib/AST/QualTypeNames.cpp
+++ b/clang/lib/AST/QualTypeNames.cpp
@@ -129,11 +129,9 @@ static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx,
if (const auto *TST = dyn_cast<const TemplateSpecializationType>(TypePtr)) {
bool MightHaveChanged = false;
SmallVector<TemplateArgument, 4> FQArgs;
- for (TemplateSpecializationType::iterator I = TST->begin(), E = TST->end();
- I != E; ++I) {
- // Cheap to copy and potentially modified by
- // getFullyQualifedTemplateArgument.
- TemplateArgument Arg(*I);
+ // Cheap to copy and potentially modified by
+ // getFullyQualifedTemplateArgument.
+ for (TemplateArgument Arg : TST->template_arguments()) {
MightHaveChanged |= getFullyQualifiedTemplateArgument(
Ctx, Arg, WithGlobalNsPrefix);
FQArgs.push_back(Arg);
@@ -422,13 +420,6 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
return QT;
}
- // We don't consider the alias introduced by `using a::X` as a new type.
- // The qualified name is still a::X.
- if (isa<UsingType>(QT.getTypePtr())) {
- return getFullyQualifiedType(QT.getSingleStepDesugaredType(Ctx), Ctx,
- WithGlobalNsPrefix);
- }
-
// Remove the part of the type related to the type being a template
// parameter (we won't report it as part of the 'type name' and it
// is actually make the code below to be more complex (to handle
@@ -455,6 +446,14 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx,
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);
+ return getFullyQualifiedType(QT, Ctx, WithGlobalNsPrefix);
+ }
+
// Create a nested name specifier if needed.
Prefix = createNestedNameSpecifierForScopeOf(Ctx, QT.getTypePtr(),
true /*FullyQualified*/,
diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp
index 6f3ede2ce42a..2f546398338c 100644
--- a/clang/lib/AST/RecordLayoutBuilder.cpp
+++ b/clang/lib/AST/RecordLayoutBuilder.cpp
@@ -1059,10 +1059,10 @@ void ItaniumRecordLayoutBuilder::LayoutNonVirtualBases(
// primary base, add it in now.
} else if (RD->isDynamicClass()) {
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
- CharUnits PtrWidth =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- CharUnits PtrAlign =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
+ CharUnits PtrWidth = Context.toCharUnitsFromBits(
+ Context.getTargetInfo().getPointerWidth(LangAS::Default));
+ CharUnits PtrAlign = Context.toCharUnitsFromBits(
+ Context.getTargetInfo().getPointerAlign(LangAS::Default));
EnsureVTablePointerAlignment(PtrAlign);
HasOwnVFPtr = true;
@@ -1890,11 +1890,6 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
LastBitfieldStorageUnitSize = 0;
llvm::Triple Target = Context.getTargetInfo().getTriple();
- bool FieldPacked = (Packed && (!FieldClass || FieldClass->isPOD() ||
- Context.getLangOpts().getClangABICompat() <=
- LangOptions::ClangABI::Ver14 ||
- Target.isPS() || Target.isOSDarwin())) ||
- D->hasAttr<PackedAttr>();
AlignRequirementKind AlignRequirement = AlignRequirementKind::None;
CharUnits FieldSize;
@@ -1916,12 +1911,6 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
if (D->getType()->isIncompleteArrayType()) {
setDeclInfo(true /* IsIncompleteArrayType */);
- } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
- unsigned AS = Context.getTargetAddressSpace(RT->getPointeeType());
- EffectiveFieldSize = FieldSize = Context.toCharUnitsFromBits(
- Context.getTargetInfo().getPointerWidth(AS));
- FieldAlign = Context.toCharUnitsFromBits(
- Context.getTargetInfo().getPointerAlign(AS));
} else {
setDeclInfo(false /* IsIncompleteArrayType */);
@@ -1975,6 +1964,14 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
}
}
+ bool FieldPacked = (Packed && (!FieldClass || FieldClass->isPOD() ||
+ FieldClass->hasAttr<PackedAttr>() ||
+ Context.getLangOpts().getClangABICompat() <=
+ LangOptions::ClangABI::Ver15 ||
+ Target.isPS() || Target.isOSDarwin() ||
+ Target.isOSAIX())) ||
+ D->hasAttr<PackedAttr>();
+
// When used as part of a typedef, or together with a 'packed' attribute, the
// 'aligned' attribute can be used to decrease alignment. In that case, it
// overrides any computed alignment we have, and there is no need to upgrade
@@ -2025,28 +2022,34 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
// The align if the field is not packed. This is to check if the attribute
// was unnecessary (-Wpacked).
- CharUnits UnpackedFieldAlign =
- !DefaultsToAIXPowerAlignment ? FieldAlign : PreferredAlign;
+ CharUnits UnpackedFieldAlign = FieldAlign;
+ CharUnits PackedFieldAlign = CharUnits::One();
CharUnits UnpackedFieldOffset = FieldOffset;
CharUnits OriginalFieldAlign = UnpackedFieldAlign;
- if (FieldPacked) {
- FieldAlign = CharUnits::One();
- PreferredAlign = CharUnits::One();
- }
CharUnits MaxAlignmentInChars =
Context.toCharUnitsFromBits(D->getMaxAlignment());
- FieldAlign = std::max(FieldAlign, MaxAlignmentInChars);
+ PackedFieldAlign = std::max(PackedFieldAlign, MaxAlignmentInChars);
PreferredAlign = std::max(PreferredAlign, MaxAlignmentInChars);
UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars);
// The maximum field alignment overrides the aligned attribute.
if (!MaxFieldAlignment.isZero()) {
- FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+ PackedFieldAlign = std::min(PackedFieldAlign, MaxFieldAlignment);
PreferredAlign = std::min(PreferredAlign, MaxFieldAlignment);
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
}
+
+ if (!FieldPacked)
+ FieldAlign = UnpackedFieldAlign;
+ if (DefaultsToAIXPowerAlignment)
+ UnpackedFieldAlign = PreferredAlign;
+ if (FieldPacked) {
+ PreferredAlign = PackedFieldAlign;
+ FieldAlign = PackedFieldAlign;
+ }
+
CharUnits AlignTo =
!DefaultsToAIXPowerAlignment ? FieldAlign : PreferredAlign;
// Round up the current record size to the field's alignment boundary.
@@ -2129,6 +2132,9 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D,
<< Context.getTypeDeclType(RD) << D->getName() << D->getType();
}
}
+
+ if (Packed && !FieldPacked && PackedFieldAlign < FieldAlign)
+ Diag(D->getLocation(), diag::warn_unpacked_field) << D;
}
void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
@@ -2757,7 +2763,8 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
// than the pointer size.
if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>()){
unsigned PackedAlignment = MFAA->getAlignment();
- if (PackedAlignment <= Context.getTargetInfo().getPointerWidth(0))
+ if (PackedAlignment <=
+ Context.getTargetInfo().getPointerWidth(LangAS::Default))
MaxFieldAlignment = Context.toCharUnitsFromBits(PackedAlignment);
}
// Packed attribute forces max field alignment to be 1.
@@ -2782,10 +2789,10 @@ MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
SharedVBPtrBase = nullptr;
// Calculate pointer size and alignment. These are used for vfptr and vbprt
// injection.
- PointerInfo.Size =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- PointerInfo.Alignment =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
+ PointerInfo.Size = Context.toCharUnitsFromBits(
+ Context.getTargetInfo().getPointerWidth(LangAS::Default));
+ PointerInfo.Alignment = Context.toCharUnitsFromBits(
+ Context.getTargetInfo().getPointerAlign(LangAS::Default));
// Respect pragma pack.
if (!MaxFieldAlignment.isZero())
PointerInfo.Alignment = std::min(PointerInfo.Alignment, MaxFieldAlignment);
@@ -3070,10 +3077,9 @@ void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) {
VBPtrOffset += Offset;
if (UseExternalLayout) {
- // The class may have no bases or fields, but still have a vfptr
- // (e.g. it's an interface class). The size was not correctly set before
- // in this case.
- if (FieldOffsets.empty() && Bases.empty())
+ // The class may have size 0 and a vfptr (e.g. it's an interface class). The
+ // size was not correctly set before in this case.
+ if (Size.isZero())
Size += Offset;
return;
}
@@ -3275,6 +3281,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
if (D->hasExternalLexicalStorage() && !D->getDefinition())
getExternalSource()->CompleteType(const_cast<RecordDecl*>(D));
+ // Complete the redecl chain (if necessary).
+ (void)D->getMostRecentDecl();
D = D->getDefinition();
assert(D && "Cannot get layout of forward declarations!");
diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp
index 8d763f28e57f..d6ff1a616285 100644
--- a/clang/lib/AST/ScanfFormatString.cpp
+++ b/clang/lib/AST/ScanfFormatString.cpp
@@ -161,6 +161,7 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,
default:
break;
case '%': k = ConversionSpecifier::PercentArg; break;
+ case 'b': k = ConversionSpecifier::bArg; break;
case 'A': k = ConversionSpecifier::AArg; break;
case 'E': k = ConversionSpecifier::EArg; break;
case 'F': k = ConversionSpecifier::FArg; break;
@@ -267,6 +268,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
llvm_unreachable("Unsupported LengthModifier Type");
// Unsigned int.
+ case ConversionSpecifier::bArg:
case ConversionSpecifier::oArg:
case ConversionSpecifier::OArg:
case ConversionSpecifier::uArg:
@@ -343,7 +345,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return ArgType::PtrTo(ArgType::AnyCharTy);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return ArgType::Invalid();
}
@@ -360,7 +362,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {
case LengthModifier::AsShort:
if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())
return ArgType::PtrTo(ArgType::AnyCharTy);
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
default:
return ArgType::Invalid();
}
@@ -500,7 +502,7 @@ bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,
}
// Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.
- if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))
+ if (LangOpt.C99 || LangOpt.CPlusPlus11)
namedTypeToLengthModifier(PT, LM);
// If fixing the length modifier was enough, we are done.
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index 8eae04d0d9fd..8744bba6c6d9 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -41,6 +41,7 @@
#include <algorithm>
#include <cassert>
#include <cstring>
+#include <optional>
#include <string>
#include <type_traits>
#include <utility>
@@ -1001,18 +1002,18 @@ bool IfStmt::isObjCAvailabilityCheck() const {
return isa<ObjCAvailabilityCheckExpr>(getCond());
}
-Optional<Stmt *> IfStmt::getNondiscardedCase(const ASTContext &Ctx) {
+std::optional<Stmt *> IfStmt::getNondiscardedCase(const ASTContext &Ctx) {
if (!isConstexpr() || getCond()->isValueDependent())
- return None;
+ return std::nullopt;
return !getCond()->EvaluateKnownConstInt(Ctx) ? getElse() : getThen();
}
-Optional<const Stmt *>
+std::optional<const Stmt *>
IfStmt::getNondiscardedCase(const ASTContext &Ctx) const {
- if (Optional<Stmt *> Result =
+ if (std::optional<Stmt *> Result =
const_cast<IfStmt *>(this)->getNondiscardedCase(Ctx))
return *Result;
- return None;
+ return std::nullopt;
}
ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index e0a4221db7ec..7c5b9f23fc26 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -31,7 +31,7 @@ void OMPChildren::setClauses(ArrayRef<OMPClause *> Clauses) {
}
MutableArrayRef<Stmt *> OMPChildren::getChildren() {
- return llvm::makeMutableArrayRef(getTrailingObjects<Stmt *>(), NumChildren);
+ return llvm::MutableArrayRef(getTrailingObjects<Stmt *>(), NumChildren);
}
OMPChildren *OMPChildren::Create(void *Mem, ArrayRef<OMPClause *> Clauses) {
@@ -517,7 +517,7 @@ OMPSectionDirective *OMPSectionDirective::Create(const ASTContext &C,
Stmt *AssociatedStmt,
bool HasCancel) {
auto *Dir =
- createDirective<OMPSectionDirective>(C, llvm::None, AssociatedStmt,
+ createDirective<OMPSectionDirective>(C, std::nullopt, AssociatedStmt,
/*NumChildren=*/0, StartLoc, EndLoc);
Dir->setHasCancel(HasCancel);
return Dir;
@@ -550,7 +550,7 @@ OMPMasterDirective *OMPMasterDirective::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation EndLoc,
Stmt *AssociatedStmt) {
- return createDirective<OMPMasterDirective>(C, llvm::None, AssociatedStmt,
+ return createDirective<OMPMasterDirective>(C, std::nullopt, AssociatedStmt,
/*NumChildren=*/0, StartLoc,
EndLoc);
}
@@ -744,6 +744,21 @@ OMPTaskyieldDirective *OMPTaskyieldDirective::CreateEmpty(const ASTContext &C,
return new (C) OMPTaskyieldDirective();
}
+OMPErrorDirective *OMPErrorDirective::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses) {
+ return createDirective<OMPErrorDirective>(
+ C, Clauses, /*AssociatedStmt=*/nullptr, /*NumChildren=*/0, StartLoc,
+ EndLoc);
+}
+
+OMPErrorDirective *OMPErrorDirective::CreateEmpty(const ASTContext &C,
+ unsigned NumClauses,
+ EmptyShell) {
+ return createEmptyDirective<OMPErrorDirective>(C, NumClauses);
+}
+
OMPBarrierDirective *OMPBarrierDirective::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation EndLoc) {
diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp
index 8d778500d103..0a879bb6df2a 100644
--- a/clang/lib/AST/StmtPrinter.cpp
+++ b/clang/lib/AST/StmtPrinter.cpp
@@ -54,6 +54,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
+#include <optional>
#include <string>
using namespace clang;
@@ -843,6 +844,11 @@ void StmtPrinter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *Node) {
PrintOMPExecutableDirective(Node);
}
+void StmtPrinter::VisitOMPErrorDirective(OMPErrorDirective *Node) {
+ Indent() << "#pragma omp error";
+ PrintOMPExecutableDirective(Node);
+}
+
void StmtPrinter::VisitOMPTaskgroupDirective(OMPTaskgroupDirective *Node) {
Indent() << "#pragma omp taskgroup";
PrintOMPExecutableDirective(Node);
@@ -1280,6 +1286,7 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
case BuiltinType::Char_S:
case BuiltinType::Char_U: OS << "i8"; break;
case BuiltinType::UChar: OS << "Ui8"; break;
+ case BuiltinType::SChar: OS << "i8"; break;
case BuiltinType::Short: OS << "i16"; break;
case BuiltinType::UShort: OS << "Ui16"; break;
case BuiltinType::Int: break; // no suffix.
@@ -1292,6 +1299,9 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) {
break; // no suffix.
case BuiltinType::UInt128:
break; // no suffix.
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ break; // no suffix
}
}
@@ -1993,7 +2003,7 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) {
cast<FunctionDecl>(DRE->getDecl())->getTemplateSpecializationArgs();
assert(Args);
- if (Args->size() != 1) {
+ if (Args->size() != 1 || Args->get(0).getKind() != TemplateArgument::Pack) {
const TemplateParameterList *TPL = nullptr;
if (!DRE->hadMultipleCandidates())
if (const auto *TD = dyn_cast<TemplateDecl>(DRE->getDecl()))
@@ -2164,7 +2174,8 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
OS << "...";
if (Node->isInitCapture(C)) {
- VarDecl *D = C->getCapturedVar();
+ // Init captures are always VarDecl.
+ auto *D = cast<VarDecl>(C->getCapturedVar());
llvm::StringRef Pre;
llvm::StringRef Post;
@@ -2265,7 +2276,7 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
if (E->isArray()) {
llvm::raw_string_ostream s(TypeS);
s << '[';
- if (Optional<Expr *> Size = E->getArraySize())
+ if (std::optional<Expr *> Size = E->getArraySize())
(*Size)->printPretty(s, Helper, Policy);
s << ']';
}
@@ -2455,6 +2466,13 @@ void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) {
OS << ")";
}
+void StmtPrinter::VisitCXXParenListInitExpr(CXXParenListInitExpr *Node) {
+ OS << "(";
+ llvm::interleaveComma(Node->getInitExprs(), OS,
+ [&](Expr *E) { PrintExpr(E); });
+ OS << ")";
+}
+
void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc();
if (NNS)
@@ -2511,7 +2529,7 @@ void StmtPrinter::VisitRequiresExpr(RequiresExpr *E) {
} else {
auto *NestedReq = cast<concepts::NestedRequirement>(Req);
OS << "requires ";
- if (NestedReq->isSubstitutionFailure())
+ if (NestedReq->hasInvalidConstraint())
OS << "<<error-expression>>";
else
PrintExpr(NestedReq->getConstraintExpr());
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 92a8b18cf68a..960cc4f4fc27 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -472,7 +472,7 @@ void OMPClauseProfiler::VisitOMPSimdlenClause(const OMPSimdlenClause *C) {
}
void OMPClauseProfiler::VisitOMPSizesClause(const OMPSizesClause *C) {
- for (auto E : C->getSizesRefs())
+ for (auto *E : C->getSizesRefs())
if (E)
Profiler->VisitExpr(E);
}
@@ -530,6 +530,15 @@ void OMPClauseProfiler::VisitOMPDynamicAllocatorsClause(
void OMPClauseProfiler::VisitOMPAtomicDefaultMemOrderClause(
const OMPAtomicDefaultMemOrderClause *C) {}
+void OMPClauseProfiler::VisitOMPAtClause(const OMPAtClause *C) {}
+
+void OMPClauseProfiler::VisitOMPSeverityClause(const OMPSeverityClause *C) {}
+
+void OMPClauseProfiler::VisitOMPMessageClause(const OMPMessageClause *C) {
+ if (C->getMessageString())
+ Profiler->VisitStmt(C->getMessageString());
+}
+
void OMPClauseProfiler::VisitOMPScheduleClause(const OMPScheduleClause *C) {
VistOMPClauseWithPreInit(C);
if (auto *S = C->getChunkSize())
@@ -894,6 +903,12 @@ void OMPClauseProfiler::VisitOMPAffinityClause(const OMPAffinityClause *C) {
}
void OMPClauseProfiler::VisitOMPOrderClause(const OMPOrderClause *C) {}
void OMPClauseProfiler::VisitOMPBindClause(const OMPBindClause *C) {}
+void OMPClauseProfiler::VisitOMPXDynCGroupMemClause(
+ const OMPXDynCGroupMemClause *C) {
+ VistOMPClauseWithPreInit(C);
+ if (Expr *Size = C->getSize())
+ Profiler->VisitStmt(Size);
+}
} // namespace
void
@@ -1014,6 +1029,9 @@ void StmtProfiler::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *S) {
VisitOMPExecutableDirective(S);
}
+void StmtProfiler::VisitOMPErrorDirective(const OMPErrorDirective *S) {
+ VisitOMPExecutableDirective(S);
+}
void StmtProfiler::VisitOMPTaskgroupDirective(const OMPTaskgroupDirective *S) {
VisitOMPExecutableDirective(S);
if (const Expr *E = S->getReductionRef())
@@ -1610,8 +1628,8 @@ void StmtProfiler::VisitRequiresExpr(const RequiresExpr *S) {
} else {
ID.AddInteger(concepts::Requirement::RK_Nested);
auto *NestedReq = cast<concepts::NestedRequirement>(Req);
- ID.AddBoolean(NestedReq->isSubstitutionFailure());
- if (!NestedReq->isSubstitutionFailure())
+ ID.AddBoolean(NestedReq->hasInvalidConstraint());
+ if (!NestedReq->hasInvalidConstraint())
Visit(NestedReq->getConstraintExpr());
}
}
@@ -2181,6 +2199,10 @@ void StmtProfiler::VisitCXXFoldExpr(const CXXFoldExpr *S) {
ID.AddInteger(S->getOperator());
}
+void StmtProfiler::VisitCXXParenListInitExpr(const CXXParenListInitExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCoroutineBodyStmt(const CoroutineBodyStmt *S) {
VisitStmt(S);
}
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index e0f5916a9a0b..ceff7a313716 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -29,7 +29,6 @@
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
@@ -41,6 +40,7 @@
#include <cstddef>
#include <cstdint>
#include <cstring>
+#include <optional>
using namespace clang;
@@ -271,12 +271,12 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
return getDependence() & TemplateArgumentDependence::UnexpandedPack;
}
-Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
+std::optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
assert(getKind() == TemplateExpansion);
if (TemplateArg.NumExpansions)
return TemplateArg.NumExpansions - 1;
- return None;
+ return std::nullopt;
}
QualType TemplateArgument::getNonTypeTemplateArgumentType() const {
@@ -321,26 +321,15 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
case Declaration:
getParamTypeForDecl().Profile(ID);
- ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : nullptr);
+ ID.AddPointer(getAsDecl());
break;
+ case TemplateExpansion:
+ ID.AddInteger(TemplateArg.NumExpansions);
+ LLVM_FALLTHROUGH;
case Template:
- case TemplateExpansion: {
- TemplateName Template = getAsTemplateOrTemplatePattern();
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast_or_null<TemplateTemplateParmDecl>(
- Template.getAsTemplateDecl())) {
- ID.AddBoolean(true);
- ID.AddInteger(TTP->getDepth());
- ID.AddInteger(TTP->getPosition());
- ID.AddBoolean(TTP->isParameterPack());
- } else {
- ID.AddBoolean(false);
- ID.AddPointer(Context.getCanonicalTemplateName(Template)
- .getAsVoidPointer());
- }
+ getAsTemplateOrTemplatePattern().Profile(ID);
break;
- }
case Integral:
getAsIntegral().Profile(ID);
@@ -374,7 +363,8 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
TemplateArg.NumExpansions == Other.TemplateArg.NumExpansions;
case Declaration:
- return getAsDecl() == Other.getAsDecl();
+ return getAsDecl() == Other.getAsDecl() &&
+ getParamTypeForDecl() == Other.getParamTypeForDecl();
case Integral:
return getIntegralType() == Other.getIntegralType() &&
@@ -432,10 +422,10 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out,
}
case Declaration: {
- // FIXME: Include the type if it's not obvious from the context.
NamedDecl *ND = getAsDecl();
if (getParamTypeForDecl()->isRecordType()) {
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
+ TPO->getType().getUnqualifiedType().print(Out, Policy);
TPO->printAsInit(Out, Policy);
break;
}
diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp
index 11dc3d2e1985..a6dd0fad9331 100644
--- a/clang/lib/AST/TemplateName.cpp
+++ b/clang/lib/AST/TemplateName.cpp
@@ -29,37 +29,74 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
+#include <optional>
#include <string>
using namespace clang;
TemplateArgument
SubstTemplateTemplateParmPackStorage::getArgumentPack() const {
- return TemplateArgument(llvm::makeArrayRef(Arguments, size()));
+ return TemplateArgument(llvm::ArrayRef(Arguments, Bits.Data));
+}
+
+TemplateTemplateParmDecl *
+SubstTemplateTemplateParmPackStorage::getParameterPack() const {
+ return cast<TemplateTemplateParmDecl>(
+ getReplacedTemplateParameterList(getAssociatedDecl())
+ ->asArray()[Bits.Index]);
+}
+
+TemplateTemplateParmDecl *
+SubstTemplateTemplateParmStorage::getParameter() const {
+ return cast<TemplateTemplateParmDecl>(
+ getReplacedTemplateParameterList(getAssociatedDecl())
+ ->asArray()[Bits.Index]);
}
void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, Parameter, Replacement);
+ Profile(ID, Replacement, getAssociatedDecl(), getIndex(), getPackIndex());
+}
+
+void SubstTemplateTemplateParmStorage::Profile(
+ llvm::FoldingSetNodeID &ID, TemplateName Replacement, Decl *AssociatedDecl,
+ unsigned Index, std::optional<unsigned> PackIndex) {
+ Replacement.Profile(ID);
+ ID.AddPointer(AssociatedDecl);
+ ID.AddInteger(Index);
+ ID.AddInteger(PackIndex ? *PackIndex + 1 : 0);
}
-void SubstTemplateTemplateParmStorage::Profile(llvm::FoldingSetNodeID &ID,
- TemplateTemplateParmDecl *parameter,
- TemplateName replacement) {
- ID.AddPointer(parameter);
- ID.AddPointer(replacement.getAsVoidPointer());
+SubstTemplateTemplateParmPackStorage::SubstTemplateTemplateParmPackStorage(
+ ArrayRef<TemplateArgument> ArgPack, Decl *AssociatedDecl, unsigned Index,
+ bool Final)
+ : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Index,
+ ArgPack.size()),
+ Arguments(ArgPack.data()), AssociatedDeclAndFinal(AssociatedDecl, Final) {
+ assert(AssociatedDecl != nullptr);
}
void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
ASTContext &Context) {
- Profile(ID, Context, Parameter, getArgumentPack());
+ Profile(ID, Context, getArgumentPack(), getAssociatedDecl(), getIndex(),
+ getFinal());
}
-void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
- ASTContext &Context,
- TemplateTemplateParmDecl *Parameter,
- const TemplateArgument &ArgPack) {
- ID.AddPointer(Parameter);
+Decl *SubstTemplateTemplateParmPackStorage::getAssociatedDecl() const {
+ return AssociatedDeclAndFinal.getPointer();
+}
+
+bool SubstTemplateTemplateParmPackStorage::getFinal() const {
+ return AssociatedDeclAndFinal.getInt();
+}
+
+void SubstTemplateTemplateParmPackStorage::Profile(
+ llvm::FoldingSetNodeID &ID, ASTContext &Context,
+ const TemplateArgument &ArgPack, Decl *AssociatedDecl, unsigned Index,
+ bool Final) {
ArgPack.Profile(ID, Context);
+ ID.AddPointer(AssociatedDecl);
+ ID.AddInteger(Index);
+ ID.AddBoolean(Final);
}
TemplateName::TemplateName(void *Ptr) {
@@ -304,7 +341,7 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy,
} else {
assert(getKind() == TemplateName::OverloadedTemplate);
OverloadedTemplateStorage *OTS = getAsOverloadedTemplate();
- (*OTS->begin())->printName(OS);
+ (*OTS->begin())->printName(OS, Policy);
}
}
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 22643d4edbec..a5573c117e62 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -1543,17 +1543,23 @@ void TextNodeDumper::VisitUnresolvedUsingType(const UnresolvedUsingType *T) {
void TextNodeDumper::VisitUsingType(const UsingType *T) {
dumpDeclRef(T->getFoundDecl());
+ if (!T->typeMatchesDecl())
+ OS << " divergent";
}
void TextNodeDumper::VisitTypedefType(const TypedefType *T) {
dumpDeclRef(T->getDecl());
+ if (!T->typeMatchesDecl())
+ OS << " divergent";
}
void TextNodeDumper::VisitUnaryTransformType(const UnaryTransformType *T) {
switch (T->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- OS << " underlying_type";
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
+ case UnaryTransformType::Enum: \
+ OS << " " #Trait; \
break;
+#include "clang/Basic/TransformTypeTraits.def"
}
}
@@ -1568,6 +1574,20 @@ void TextNodeDumper::VisitTemplateTypeParmType(const TemplateTypeParmType *T) {
dumpDeclRef(T->getDecl());
}
+void TextNodeDumper::VisitSubstTemplateTypeParmType(
+ const SubstTemplateTypeParmType *T) {
+ dumpDeclRef(T->getAssociatedDecl());
+ VisitTemplateTypeParmDecl(T->getReplacedParameter());
+ if (auto PackIndex = T->getPackIndex())
+ OS << " pack_index " << *PackIndex;
+}
+
+void TextNodeDumper::VisitSubstTemplateTypeParmPackType(
+ const SubstTemplateTypeParmPackType *T) {
+ dumpDeclRef(T->getAssociatedDecl());
+ VisitTemplateTypeParmDecl(T->getReplacedParameter());
+}
+
void TextNodeDumper::VisitAutoType(const AutoType *T) {
if (T->isDecltypeAuto())
OS << " decltype(auto)";
@@ -1786,6 +1806,8 @@ void TextNodeDumper::VisitVarDecl(const VarDecl *D) {
case VarDecl::ListInit:
OS << " listinit";
break;
+ case VarDecl::ParenListInit:
+ OS << " parenlistinit";
}
}
if (D->needsDestruction(D->getASTContext()))
@@ -1911,6 +1933,8 @@ void TextNodeDumper::VisitNamespaceDecl(const NamespaceDecl *D) {
dumpName(D);
if (D->isInline())
OS << " inline";
+ if (D->isNested())
+ OS << " nested";
if (!D->isOriginalNamespace())
dumpDeclRef(D->getOriginalNamespace(), "original");
}
@@ -2380,3 +2404,11 @@ void TextNodeDumper::VisitCompoundStmt(const CompoundStmt *S) {
if (S->hasStoredFPFeatures())
printFPOptions(S->getStoredFPFeatures());
}
+
+void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
+ if (D->isCBuffer())
+ OS << " cbuffer";
+ else
+ OS << " tbuffer";
+ dumpName(D);
+}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 0f168a518707..a713d6e3bd03 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -42,7 +42,6 @@
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/ADT/None.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
@@ -51,6 +50,7 @@
#include <cassert>
#include <cstdint>
#include <cstring>
+#include <optional>
#include <type_traits>
using namespace clang;
@@ -525,6 +525,10 @@ template <> const TypedefType *Type::getAs() const {
return getAsSugar<TypedefType>(this);
}
+template <> const UsingType *Type::getAs() const {
+ return getAsSugar<UsingType>(this);
+}
+
template <> const TemplateSpecializationType *Type::getAs() const {
return getAsSugar<TemplateSpecializationType>(this);
}
@@ -1073,7 +1077,7 @@ public:
if (exceptionChanged) {
info.ExceptionSpec.Exceptions =
- llvm::makeArrayRef(exceptionTypes).copy(Ctx);
+ llvm::ArrayRef(exceptionTypes).copy(Ctx);
}
}
@@ -1166,8 +1170,9 @@ public:
== T->getReplacementType().getAsOpaquePtr())
return QualType(T, 0);
- return Ctx.getSubstTemplateTypeParmType(T->getReplacedParameter(),
- replacementType);
+ return Ctx.getSubstTemplateTypeParmType(replacementType,
+ T->getAssociatedDecl(),
+ T->getIndex(), T->getPackIndex());
}
// FIXME: Non-trivial to implement, but important for C++
@@ -1214,10 +1219,10 @@ public:
!typeArgChanged)
return QualType(T, 0);
- return Ctx.getObjCObjectType(baseType, typeArgs,
- llvm::makeArrayRef(T->qual_begin(),
- T->getNumProtocols()),
- T->isKindOfTypeAsWritten());
+ return Ctx.getObjCObjectType(
+ baseType, typeArgs,
+ llvm::ArrayRef(T->qual_begin(), T->getNumProtocols()),
+ T->isKindOfTypeAsWritten());
}
TRIVIAL_TYPE_CLASS(ObjCInterface)
@@ -1369,7 +1374,7 @@ struct SubstObjCTypeArgsVisitor
if (exceptionChanged) {
info.ExceptionSpec.Exceptions =
- llvm::makeArrayRef(exceptionTypes).copy(Ctx);
+ llvm::ArrayRef(exceptionTypes).copy(Ctx);
}
}
@@ -1479,6 +1484,25 @@ struct StripObjCKindOfTypeVisitor
} // namespace
+bool QualType::UseExcessPrecision(const ASTContext &Ctx) {
+ const BuiltinType *BT = getTypePtr()->getAs<BuiltinType>();
+ if (BT) {
+ switch (BT->getKind()) {
+ case BuiltinType::Kind::Float16: {
+ const TargetInfo &TI = Ctx.getTargetInfo();
+ if (TI.hasFloat16Type() && !TI.hasLegalHalfType() &&
+ Ctx.getLangOpts().getFloat16ExcessPrecision() !=
+ Ctx.getLangOpts().ExcessPrecisionKind::FPP_None)
+ return true;
+ return false;
+ }
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
/// Substitute the given type arguments for Objective-C type
/// parameters within the given type, recursively.
QualType QualType::substObjCTypeArgs(ASTContext &ctx,
@@ -1510,8 +1534,8 @@ QualType QualType::getAtomicUnqualifiedType() const {
return getUnqualifiedType();
}
-Optional<ArrayRef<QualType>> Type::getObjCSubstitutions(
- const DeclContext *dc) const {
+std::optional<ArrayRef<QualType>>
+Type::getObjCSubstitutions(const DeclContext *dc) const {
// Look through method scopes.
if (const auto method = dyn_cast<ObjCMethodDecl>(dc))
dc = method->getDeclContext();
@@ -1526,23 +1550,23 @@ Optional<ArrayRef<QualType>> Type::getObjCSubstitutions(
// substitution to do.
dcTypeParams = dcClassDecl->getTypeParamList();
if (!dcTypeParams)
- return None;
+ return std::nullopt;
} else {
// If we are in neither a class nor a category, there's no
// substitution to perform.
dcCategoryDecl = dyn_cast<ObjCCategoryDecl>(dc);
if (!dcCategoryDecl)
- return None;
+ return std::nullopt;
// If the category does not have any type parameters, there's no
// substitution to do.
dcTypeParams = dcCategoryDecl->getTypeParamList();
if (!dcTypeParams)
- return None;
+ return std::nullopt;
dcClassDecl = dcCategoryDecl->getClassInterface();
if (!dcClassDecl)
- return None;
+ return std::nullopt;
}
assert(dcTypeParams && "No substitutions to perform");
assert(dcClassDecl && "No class context");
@@ -2320,6 +2344,20 @@ bool Type::isSizelessBuiltinType() const {
bool Type::isSizelessType() const { return isSizelessBuiltinType(); }
+bool Type::isSVESizelessBuiltinType() const {
+ if (const BuiltinType *BT = getAs<BuiltinType>()) {
+ switch (BT->getKind()) {
+ // SVE Types
+#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
+#include "clang/Basic/AArch64SVEACLETypes.def"
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
bool Type::isVLSTBuiltinType() const {
if (const BuiltinType *BT = getAs<BuiltinType>()) {
switch (BT->getKind()) {
@@ -2777,39 +2815,6 @@ bool Type::isStdByteType() const {
return false;
}
-bool Type::isPromotableIntegerType() const {
- if (const auto *BT = getAs<BuiltinType>())
- switch (BT->getKind()) {
- case BuiltinType::Bool:
- case BuiltinType::Char_S:
- case BuiltinType::Char_U:
- case BuiltinType::SChar:
- case BuiltinType::UChar:
- case BuiltinType::Short:
- case BuiltinType::UShort:
- case BuiltinType::WChar_S:
- case BuiltinType::WChar_U:
- case BuiltinType::Char8:
- case BuiltinType::Char16:
- case BuiltinType::Char32:
- return true;
- default:
- return false;
- }
-
- // 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 = getAs<EnumType>()){
- if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull()
- || ET->getDecl()->isScoped())
- return false;
-
- return true;
- }
-
- return false;
-}
-
bool Type::isSpecifierType() const {
// Note that this intentionally does not use the canonical type.
switch (getTypeClass()) {
@@ -2928,7 +2933,7 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType(
DependentTemplateSpecializationTypeBits.NumArgs = Args.size();
assert((!NNS || NNS->isDependent()) &&
"DependentTemplateSpecializatonType requires dependent qualifier");
- TemplateArgument *ArgBuffer = getArgBuffer();
+ auto *ArgBuffer = const_cast<TemplateArgument *>(template_arguments().data());
for (const TemplateArgument &Arg : Args) {
addDependence(toTypeDependence(Arg.getDependence() &
TemplateArgumentDependence::UnexpandedPack));
@@ -3084,7 +3089,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case Char32:
return "char32_t";
case NullPtr:
- return "std::nullptr_t";
+ return Policy.NullptrTypeInNamespace ? "std::nullptr_t" : "nullptr_t";
case Overload:
return "<overloaded function type>";
case BoundMember:
@@ -3434,25 +3439,34 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID,
}
TypedefType::TypedefType(TypeClass tc, const TypedefNameDecl *D,
- QualType underlying, QualType can)
- : Type(tc, can, toSemanticDependence(underlying->getDependence())),
+ QualType Underlying, QualType can)
+ : Type(tc, can, toSemanticDependence(can->getDependence())),
Decl(const_cast<TypedefNameDecl *>(D)) {
assert(!isa<TypedefType>(can) && "Invalid canonical type");
+ TypedefBits.hasTypeDifferentFromDecl = !Underlying.isNull();
+ if (!typeMatchesDecl())
+ *getTrailingObjects<QualType>() = Underlying;
}
QualType TypedefType::desugar() const {
- return getDecl()->getUnderlyingType();
+ return typeMatchesDecl() ? Decl->getUnderlyingType()
+ : *getTrailingObjects<QualType>();
}
UsingType::UsingType(const UsingShadowDecl *Found, QualType Underlying,
QualType Canon)
- : Type(Using, Canon, toSemanticDependence(Underlying->getDependence())),
+ : Type(Using, Canon, toSemanticDependence(Canon->getDependence())),
Found(const_cast<UsingShadowDecl *>(Found)) {
- assert(Underlying == getUnderlyingType());
+ UsingBits.hasTypeDifferentFromDecl = !Underlying.isNull();
+ if (!typeMatchesDecl())
+ *getTrailingObjects<QualType>() = Underlying;
}
QualType UsingType::getUnderlyingType() const {
- return QualType(cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(), 0);
+ return typeMatchesDecl()
+ ? QualType(
+ cast<TypeDecl>(Found->getTargetDecl())->getTypeForDecl(), 0)
+ : *getTrailingObjects<QualType>();
}
QualType MacroQualifiedType::desugar() const { return getUnderlyingType(); }
@@ -3469,27 +3483,37 @@ QualType MacroQualifiedType::getModifiedType() const {
return Inner;
}
-TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
- : Type(TypeOfExpr, can,
+TypeOfExprType::TypeOfExprType(Expr *E, TypeOfKind Kind, QualType Can)
+ : Type(TypeOfExpr,
+ // We have to protect against 'Can' being invalid through its
+ // default argument.
+ Kind == TypeOfKind::Unqualified && !Can.isNull()
+ ? Can.getAtomicUnqualifiedType()
+ : Can,
toTypeDependence(E->getDependence()) |
(E->getType()->getDependence() &
TypeDependence::VariablyModified)),
- TOExpr(E) {}
+ TOExpr(E) {
+ TypeOfBits.IsUnqual = Kind == TypeOfKind::Unqualified;
+}
bool TypeOfExprType::isSugared() const {
return !TOExpr->isTypeDependent();
}
QualType TypeOfExprType::desugar() const {
- if (isSugared())
- return getUnderlyingExpr()->getType();
-
+ if (isSugared()) {
+ QualType QT = getUnderlyingExpr()->getType();
+ return TypeOfBits.IsUnqual ? QT.getAtomicUnqualifiedType() : QT;
+ }
return QualType(this, 0);
}
void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
- const ASTContext &Context, Expr *E) {
+ const ASTContext &Context, Expr *E,
+ bool IsUnqual) {
E->Profile(ID, Context, true);
+ ID.AddBoolean(IsUnqual);
}
DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
@@ -3539,7 +3563,7 @@ TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
decl(const_cast<TagDecl *>(D)) {}
static TagDecl *getInterestingTagDecl(TagDecl *decl) {
- for (auto I : decl->redecls()) {
+ for (auto *I : decl->redecls()) {
if (I->isCompleteDefinition() || I->isBeingDefined())
return I;
}
@@ -3649,28 +3673,80 @@ IdentifierInfo *TemplateTypeParmType::getIdentifier() const {
return isCanonicalUnqualified() ? nullptr : getDecl()->getIdentifier();
}
+static const TemplateTypeParmDecl *getReplacedParameter(Decl *D,
+ unsigned Index) {
+ if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
+ return TTP;
+ return cast<TemplateTypeParmDecl>(
+ getReplacedTemplateParameterList(D)->getParam(Index));
+}
+
+SubstTemplateTypeParmType::SubstTemplateTypeParmType(
+ QualType Replacement, Decl *AssociatedDecl, unsigned Index,
+ std::optional<unsigned> PackIndex)
+ : Type(SubstTemplateTypeParm, Replacement.getCanonicalType(),
+ Replacement->getDependence()),
+ AssociatedDecl(AssociatedDecl) {
+ SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType =
+ Replacement != getCanonicalTypeInternal();
+ if (SubstTemplateTypeParmTypeBits.HasNonCanonicalUnderlyingType)
+ *getTrailingObjects<QualType>() = Replacement;
+
+ SubstTemplateTypeParmTypeBits.Index = Index;
+ SubstTemplateTypeParmTypeBits.PackIndex = PackIndex ? *PackIndex + 1 : 0;
+ assert(AssociatedDecl != nullptr);
+}
+
+const TemplateTypeParmDecl *
+SubstTemplateTypeParmType::getReplacedParameter() const {
+ return ::getReplacedParameter(getAssociatedDecl(), getIndex());
+}
+
SubstTemplateTypeParmPackType::SubstTemplateTypeParmPackType(
- const TemplateTypeParmType *Param, QualType Canon,
+ QualType Canon, Decl *AssociatedDecl, unsigned Index, bool Final,
const TemplateArgument &ArgPack)
: Type(SubstTemplateTypeParmPack, Canon,
TypeDependence::DependentInstantiation |
TypeDependence::UnexpandedPack),
- Replaced(Param), Arguments(ArgPack.pack_begin()) {
+ Arguments(ArgPack.pack_begin()),
+ AssociatedDeclAndFinal(AssociatedDecl, Final) {
+ SubstTemplateTypeParmPackTypeBits.Index = Index;
SubstTemplateTypeParmPackTypeBits.NumArgs = ArgPack.pack_size();
+ assert(AssociatedDecl != nullptr);
+}
+
+Decl *SubstTemplateTypeParmPackType::getAssociatedDecl() const {
+ return AssociatedDeclAndFinal.getPointer();
+}
+
+bool SubstTemplateTypeParmPackType::getFinal() const {
+ return AssociatedDeclAndFinal.getInt();
+}
+
+const TemplateTypeParmDecl *
+SubstTemplateTypeParmPackType::getReplacedParameter() const {
+ return ::getReplacedParameter(getAssociatedDecl(), getIndex());
+}
+
+IdentifierInfo *SubstTemplateTypeParmPackType::getIdentifier() const {
+ return getReplacedParameter()->getIdentifier();
}
TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const {
- return TemplateArgument(llvm::makeArrayRef(Arguments, getNumArgs()));
+ return TemplateArgument(llvm::ArrayRef(Arguments, getNumArgs()));
}
void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getReplacedParameter(), getArgumentPack());
+ Profile(ID, getAssociatedDecl(), getIndex(), getFinal(), getArgumentPack());
}
void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID,
- const TemplateTypeParmType *Replaced,
+ const Decl *AssociatedDecl,
+ unsigned Index, bool Final,
const TemplateArgument &ArgPack) {
- ID.AddPointer(Replaced);
+ 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());
@@ -3740,10 +3816,22 @@ TemplateSpecializationType::TemplateSpecializationType(
// Store the aliased type if this is a type alias template specialization.
if (isTypeAlias()) {
auto *Begin = reinterpret_cast<TemplateArgument *>(this + 1);
- *reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType;
+ *reinterpret_cast<QualType *>(Begin + Args.size()) = AliasedType;
}
}
+QualType TemplateSpecializationType::getAliasedType() const {
+ assert(isTypeAlias() && "not a type alias template specialization");
+ return *reinterpret_cast<const QualType *>(template_arguments().end());
+}
+
+void TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
+ const ASTContext &Ctx) {
+ Profile(ID, Template, template_arguments(), Ctx);
+ if (isTypeAlias())
+ getAliasedType().Profile(ID);
+}
+
void
TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
TemplateName T,
@@ -3780,14 +3868,14 @@ void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID,
for (auto typeArg : typeArgs)
ID.AddPointer(typeArg.getAsOpaquePtr());
ID.AddInteger(protocols.size());
- for (auto proto : protocols)
+ for (auto *proto : protocols)
ID.AddPointer(proto);
ID.AddBoolean(isKindOf);
}
void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getBaseType(), getTypeArgsAsWritten(),
- llvm::makeArrayRef(qual_begin(), getNumProtocols()),
+ llvm::ArrayRef(qual_begin(), getNumProtocols()),
isKindOfTypeAsWritten());
}
@@ -3798,13 +3886,13 @@ void ObjCTypeParamType::Profile(llvm::FoldingSetNodeID &ID,
ID.AddPointer(OTPDecl);
ID.AddPointer(CanonicalType.getAsOpaquePtr());
ID.AddInteger(protocols.size());
- for (auto proto : protocols)
+ for (auto *proto : protocols)
ID.AddPointer(proto);
}
void ObjCTypeParamType::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getDecl(), getCanonicalTypeInternal(),
- llvm::makeArrayRef(qual_begin(), getNumProtocols()));
+ llvm::ArrayRef(qual_begin(), getNumProtocols()));
}
namespace {
@@ -4091,8 +4179,7 @@ LinkageInfo Type::getLinkageAndVisibility() const {
return LinkageComputer{}.getTypeLinkageAndVisibility(this);
}
-Optional<NullabilityKind>
-Type::getNullability(const ASTContext &Context) const {
+std::optional<NullabilityKind> Type::getNullability() const {
QualType Type(this, 0);
while (const auto *AT = Type->getAs<AttributedType>()) {
// Check whether this is an attributed type with nullability
@@ -4102,7 +4189,7 @@ Type::getNullability(const ASTContext &Context) const {
Type = AT->getEquivalentType();
}
- return None;
+ return std::nullopt;
}
bool Type::canHaveNullability(bool ResultIfUnknown) const {
@@ -4233,8 +4320,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const {
llvm_unreachable("bad type kind!");
}
-llvm::Optional<NullabilityKind>
-AttributedType::getImmediateNullability() const {
+std::optional<NullabilityKind> AttributedType::getImmediateNullability() const {
if (getAttrKind() == attr::TypeNonNull)
return NullabilityKind::NonNull;
if (getAttrKind() == attr::TypeNullable)
@@ -4243,10 +4329,11 @@ AttributedType::getImmediateNullability() const {
return NullabilityKind::Unspecified;
if (getAttrKind() == attr::TypeNullableResult)
return NullabilityKind::NullableResult;
- return None;
+ return std::nullopt;
}
-Optional<NullabilityKind> AttributedType::stripOuterNullability(QualType &T) {
+std::optional<NullabilityKind>
+AttributedType::stripOuterNullability(QualType &T) {
QualType AttrTy = T;
if (auto MacroTy = dyn_cast<MacroQualifiedType>(T))
AttrTy = MacroTy->getUnderlyingType();
@@ -4258,7 +4345,7 @@ Optional<NullabilityKind> AttributedType::stripOuterNullability(QualType &T) {
}
}
- return None;
+ return std::nullopt;
}
bool Type::isBlockCompatibleObjCPointerType(ASTContext &ctx) const {
@@ -4320,20 +4407,13 @@ bool Type::isObjCARCImplicitlyUnretainedType() const {
}
bool Type::isObjCNSObjectType() const {
- const Type *cur = this;
- while (true) {
- if (const auto *typedefType = dyn_cast<TypedefType>(cur))
- return typedefType->getDecl()->hasAttr<ObjCNSObjectAttr>();
-
- // Single-step desugar until we run out of sugar.
- QualType next = cur->getLocallyUnqualifiedSingleStepDesugaredType();
- if (next.getTypePtr() == cur) return false;
- cur = next.getTypePtr();
- }
+ if (const auto *typedefType = getAs<TypedefType>())
+ return typedefType->getDecl()->hasAttr<ObjCNSObjectAttr>();
+ return false;
}
bool Type::isObjCIndependentClassType() const {
- if (const auto *typedefType = dyn_cast<TypedefType>(this))
+ if (const auto *typedefType = getAs<TypedefType>())
return typedefType->getDecl()->hasAttr<ObjCIndependentClassAttr>();
return false;
}
@@ -4465,7 +4545,8 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
AutoTypeBits.NumArgs = TypeConstraintArgs.size();
this->TypeConstraintConcept = TypeConstraintConcept;
if (TypeConstraintConcept) {
- TemplateArgument *ArgBuffer = getArgBuffer();
+ auto *ArgBuffer =
+ const_cast<TemplateArgument *>(getTypeConstraintArguments().data());
for (const TemplateArgument &Arg : TypeConstraintArgs) {
addDependence(
toSyntacticDependence(toTypeDependence(Arg.getDependence())));
@@ -4486,3 +4567,8 @@ void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
for (const TemplateArgument &Arg : Arguments)
Arg.Profile(ID, Context);
}
+
+void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) {
+ Profile(ID, Context, getDeducedType(), getKeyword(), isDependentType(),
+ getTypeConstraintConcept(), getTypeConstraintArguments());
+}
diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp
index cf5e2f979230..bcc5a223e6f7 100644
--- a/clang/lib/AST/TypeLoc.cpp
+++ b/clang/lib/AST/TypeLoc.cpp
@@ -194,15 +194,21 @@ SourceLocation TypeLoc::getBeginLoc() const {
while (true) {
switch (Cur.getTypeLocClass()) {
case Elaborated:
- LeftMost = Cur;
- break;
+ if (Cur.getLocalSourceRange().getBegin().isValid()) {
+ LeftMost = Cur;
+ break;
+ }
+ Cur = Cur.getNextTypeLoc();
+ if (Cur.isNull())
+ break;
+ continue;
case FunctionProto:
if (Cur.castAs<FunctionProtoTypeLoc>().getTypePtr()
->hasTrailingReturn()) {
LeftMost = Cur;
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case FunctionNoProto:
case ConstantArray:
case DependentSizedArray:
@@ -254,7 +260,7 @@ SourceLocation TypeLoc::getEndLoc() const {
// `id` and `id<...>` have no star location.
if (Cur.castAs<ObjCObjectPointerTypeLoc>().getStarLoc().isInvalid())
break;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Pointer:
case BlockPointer:
case MemberPointer:
@@ -515,8 +521,8 @@ void TypeOfTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo>
::initializeLocal(Context, Loc);
- this->getLocalData()->UnderlyingTInfo = Context.getTrivialTypeSourceInfo(
- getUnderlyingType(), Loc);
+ this->getLocalData()->UnmodifiedTInfo =
+ Context.getTrivialTypeSourceInfo(getUnmodifiedType(), Loc);
}
void UnaryTransformTypeLoc::initializeLocal(ASTContext &Context,
@@ -530,6 +536,8 @@ void UnaryTransformTypeLoc::initializeLocal(ASTContext &Context,
void ElaboratedTypeLoc::initializeLocal(ASTContext &Context,
SourceLocation Loc) {
+ if (isEmpty())
+ return;
setElaboratedKeywordLoc(Loc);
NestedNameSpecifierLocBuilder Builder;
Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc);
@@ -560,17 +568,14 @@ DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context,
setTemplateNameLoc(Loc);
setLAngleLoc(Loc);
setRAngleLoc(Loc);
- TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
- getTypePtr()->getArgs(),
- getArgInfos(), Loc);
+ TemplateSpecializationTypeLoc::initializeArgLocs(
+ Context, getTypePtr()->template_arguments(), getArgInfos(), Loc);
}
-void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
- unsigned NumArgs,
- const TemplateArgument *Args,
- TemplateArgumentLocInfo *ArgInfos,
- SourceLocation Loc) {
- for (unsigned i = 0, e = NumArgs; i != e; ++i) {
+void TemplateSpecializationTypeLoc::initializeArgLocs(
+ ASTContext &Context, ArrayRef<TemplateArgument> Args,
+ TemplateArgumentLocInfo *ArgInfos, SourceLocation Loc) {
+ for (unsigned i = 0, e = Args.size(); i != e; ++i) {
switch (Args[i].getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Impossible TemplateArgument");
@@ -627,9 +632,8 @@ void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) {
setRAngleLoc(Loc);
setLAngleLoc(Loc);
setRParenLoc(Loc);
- TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(),
- getTypePtr()->getArgs(),
- getArgInfos(), Loc);
+ TemplateSpecializationTypeLoc::initializeArgLocs(
+ Context, getTypePtr()->getTypeConstraintArguments(), getArgInfos(), Loc);
setNameLoc(Loc);
}
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 6b13d3806037..5c2464904485 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
+#include "clang/AST/TextNodeDumper.h"
#include "clang/AST/Type.h"
#include "clang/Basic/AddressSpaces.h"
#include "clang/Basic/ExceptionSpecificationType.h"
@@ -32,6 +33,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -47,109 +49,103 @@ using namespace clang;
namespace {
- /// RAII object that enables printing of the ARC __strong lifetime
- /// qualifier.
- class IncludeStrongLifetimeRAII {
- PrintingPolicy &Policy;
- bool Old;
-
- public:
- explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy)
- : Policy(Policy), Old(Policy.SuppressStrongLifetime) {
- if (!Policy.SuppressLifetimeQualifiers)
- Policy.SuppressStrongLifetime = false;
- }
+/// RAII object that enables printing of the ARC __strong lifetime
+/// qualifier.
+class IncludeStrongLifetimeRAII {
+ PrintingPolicy &Policy;
+ bool Old;
+
+public:
+ explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy)
+ : Policy(Policy), Old(Policy.SuppressStrongLifetime) {
+ if (!Policy.SuppressLifetimeQualifiers)
+ Policy.SuppressStrongLifetime = false;
+ }
- ~IncludeStrongLifetimeRAII() {
- Policy.SuppressStrongLifetime = Old;
- }
- };
+ ~IncludeStrongLifetimeRAII() { Policy.SuppressStrongLifetime = Old; }
+};
- class ParamPolicyRAII {
- PrintingPolicy &Policy;
- bool Old;
+class ParamPolicyRAII {
+ PrintingPolicy &Policy;
+ bool Old;
- public:
- explicit ParamPolicyRAII(PrintingPolicy &Policy)
- : Policy(Policy), Old(Policy.SuppressSpecifiers) {
- Policy.SuppressSpecifiers = false;
- }
+public:
+ explicit ParamPolicyRAII(PrintingPolicy &Policy)
+ : Policy(Policy), Old(Policy.SuppressSpecifiers) {
+ Policy.SuppressSpecifiers = false;
+ }
- ~ParamPolicyRAII() {
- Policy.SuppressSpecifiers = Old;
- }
- };
+ ~ParamPolicyRAII() { Policy.SuppressSpecifiers = Old; }
+};
- class DefaultTemplateArgsPolicyRAII {
- PrintingPolicy &Policy;
- bool Old;
+class DefaultTemplateArgsPolicyRAII {
+ PrintingPolicy &Policy;
+ bool Old;
- public:
- explicit DefaultTemplateArgsPolicyRAII(PrintingPolicy &Policy)
- : Policy(Policy), Old(Policy.SuppressDefaultTemplateArgs) {
- Policy.SuppressDefaultTemplateArgs = false;
- }
+public:
+ explicit DefaultTemplateArgsPolicyRAII(PrintingPolicy &Policy)
+ : Policy(Policy), Old(Policy.SuppressDefaultTemplateArgs) {
+ Policy.SuppressDefaultTemplateArgs = false;
+ }
- ~DefaultTemplateArgsPolicyRAII() {
- Policy.SuppressDefaultTemplateArgs = Old;
- }
- };
-
- class ElaboratedTypePolicyRAII {
- PrintingPolicy &Policy;
- bool SuppressTagKeyword;
- bool SuppressScope;
-
- public:
- explicit ElaboratedTypePolicyRAII(PrintingPolicy &Policy) : Policy(Policy) {
- SuppressTagKeyword = Policy.SuppressTagKeyword;
- SuppressScope = Policy.SuppressScope;
- Policy.SuppressTagKeyword = true;
- Policy.SuppressScope = true;
- }
+ ~DefaultTemplateArgsPolicyRAII() { Policy.SuppressDefaultTemplateArgs = Old; }
+};
- ~ElaboratedTypePolicyRAII() {
- Policy.SuppressTagKeyword = SuppressTagKeyword;
- Policy.SuppressScope = SuppressScope;
- }
- };
-
- class TypePrinter {
- PrintingPolicy Policy;
- unsigned Indentation;
- bool HasEmptyPlaceHolder = false;
- bool InsideCCAttribute = false;
-
- public:
- explicit TypePrinter(const PrintingPolicy &Policy, unsigned Indentation = 0)
- : Policy(Policy), Indentation(Indentation) {}
-
- void print(const Type *ty, Qualifiers qs, raw_ostream &OS,
- StringRef PlaceHolder);
- void print(QualType T, raw_ostream &OS, StringRef PlaceHolder);
-
- static bool canPrefixQualifiers(const Type *T, bool &NeedARCStrongQualifier);
- void spaceBeforePlaceHolder(raw_ostream &OS);
- void printTypeSpec(NamedDecl *D, raw_ostream &OS);
- void printTemplateId(const TemplateSpecializationType *T, raw_ostream &OS,
- bool FullyQualify);
-
- void printBefore(QualType T, raw_ostream &OS);
- void printAfter(QualType T, raw_ostream &OS);
- void AppendScope(DeclContext *DC, raw_ostream &OS,
- DeclarationName NameInScope);
- void printTag(TagDecl *T, raw_ostream &OS);
- void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS);
+class ElaboratedTypePolicyRAII {
+ PrintingPolicy &Policy;
+ bool SuppressTagKeyword;
+ bool SuppressScope;
+
+public:
+ explicit ElaboratedTypePolicyRAII(PrintingPolicy &Policy) : Policy(Policy) {
+ SuppressTagKeyword = Policy.SuppressTagKeyword;
+ SuppressScope = Policy.SuppressScope;
+ Policy.SuppressTagKeyword = true;
+ Policy.SuppressScope = true;
+ }
+
+ ~ElaboratedTypePolicyRAII() {
+ Policy.SuppressTagKeyword = SuppressTagKeyword;
+ Policy.SuppressScope = SuppressScope;
+ }
+};
+
+class TypePrinter {
+ PrintingPolicy Policy;
+ unsigned Indentation;
+ bool HasEmptyPlaceHolder = false;
+ bool InsideCCAttribute = false;
+
+public:
+ explicit TypePrinter(const PrintingPolicy &Policy, unsigned Indentation = 0)
+ : Policy(Policy), Indentation(Indentation) {}
+
+ void print(const Type *ty, Qualifiers qs, raw_ostream &OS,
+ StringRef PlaceHolder);
+ void print(QualType T, raw_ostream &OS, StringRef PlaceHolder);
+
+ static bool canPrefixQualifiers(const Type *T, bool &NeedARCStrongQualifier);
+ void spaceBeforePlaceHolder(raw_ostream &OS);
+ void printTypeSpec(NamedDecl *D, raw_ostream &OS);
+ void printTemplateId(const TemplateSpecializationType *T, raw_ostream &OS,
+ bool FullyQualify);
+
+ void printBefore(QualType T, raw_ostream &OS);
+ void printAfter(QualType T, raw_ostream &OS);
+ void AppendScope(DeclContext *DC, raw_ostream &OS,
+ DeclarationName NameInScope);
+ void printTag(TagDecl *T, raw_ostream &OS);
+ void printFunctionAfter(const FunctionType::ExtInfo &Info, raw_ostream &OS);
#define ABSTRACT_TYPE(CLASS, PARENT)
-#define TYPE(CLASS, PARENT) \
- void print##CLASS##Before(const CLASS##Type *T, raw_ostream &OS); \
- void print##CLASS##After(const CLASS##Type *T, raw_ostream &OS);
+#define TYPE(CLASS, PARENT) \
+ void print##CLASS##Before(const CLASS##Type *T, raw_ostream &OS); \
+ void print##CLASS##After(const CLASS##Type *T, raw_ostream &OS);
#include "clang/AST/TypeNodes.inc"
- private:
- void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS);
- void printAfter(const Type *ty, Qualifiers qs, raw_ostream &OS);
- };
+private:
+ void printBefore(const Type *ty, Qualifiers qs, raw_ostream &OS);
+ void printAfter(const Type *ty, Qualifiers qs, raw_ostream &OS);
+};
} // namespace
@@ -199,7 +195,7 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, raw_ostream &OS,
return;
}
- SaveAndRestore<bool> PHVal(HasEmptyPlaceHolder, PlaceHolder.empty());
+ SaveAndRestore PHVal(HasEmptyPlaceHolder, PlaceHolder.empty());
printBefore(T, Quals, OS);
OS << PlaceHolder;
@@ -262,7 +258,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::VariableArray:
case Type::DependentSizedArray:
NeedARCStrongQualifier = true;
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Type::ConstantArray:
case Type::IncompleteArray:
@@ -323,7 +319,7 @@ void TypePrinter::printBefore(const Type *T,Qualifiers Quals, raw_ostream &OS) {
if (Policy.SuppressSpecifiers && T->isSpecifierType())
return;
- SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder);
+ SaveAndRestore PrevPHIsEmpty(HasEmptyPlaceHolder);
// Print qualifiers as appropriate.
@@ -400,7 +396,7 @@ void TypePrinter::printComplexAfter(const ComplexType *T, raw_ostream &OS) {
void TypePrinter::printPointerBefore(const PointerType *T, raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
printBefore(T->getPointeeType(), OS);
// Handle things like 'int (*A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
@@ -411,7 +407,7 @@ void TypePrinter::printPointerBefore(const PointerType *T, raw_ostream &OS) {
void TypePrinter::printPointerAfter(const PointerType *T, raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
// Handle things like 'int (*A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
if (isa<ArrayType>(T->getPointeeType()))
@@ -421,14 +417,14 @@ void TypePrinter::printPointerAfter(const PointerType *T, raw_ostream &OS) {
void TypePrinter::printBlockPointerBefore(const BlockPointerType *T,
raw_ostream &OS) {
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
printBefore(T->getPointeeType(), OS);
OS << '^';
}
void TypePrinter::printBlockPointerAfter(const BlockPointerType *T,
raw_ostream &OS) {
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
printAfter(T->getPointeeType(), OS);
}
@@ -443,7 +439,7 @@ static QualType skipTopLevelReferences(QualType T) {
void TypePrinter::printLValueReferenceBefore(const LValueReferenceType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
printBefore(Inner, OS);
// Handle things like 'int (&A)[4];' correctly.
@@ -456,7 +452,7 @@ void TypePrinter::printLValueReferenceBefore(const LValueReferenceType *T,
void TypePrinter::printLValueReferenceAfter(const LValueReferenceType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
// Handle things like 'int (&A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
@@ -468,7 +464,7 @@ void TypePrinter::printLValueReferenceAfter(const LValueReferenceType *T,
void TypePrinter::printRValueReferenceBefore(const RValueReferenceType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
printBefore(Inner, OS);
// Handle things like 'int (&&A)[4];' correctly.
@@ -481,7 +477,7 @@ void TypePrinter::printRValueReferenceBefore(const RValueReferenceType *T,
void TypePrinter::printRValueReferenceAfter(const RValueReferenceType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
QualType Inner = skipTopLevelReferences(T->getPointeeTypeAsWritten());
// Handle things like 'int (&&A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
@@ -493,7 +489,7 @@ void TypePrinter::printRValueReferenceAfter(const RValueReferenceType *T,
void TypePrinter::printMemberPointerBefore(const MemberPointerType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
printBefore(T->getPointeeType(), OS);
// Handle things like 'int (Cls::*A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
@@ -510,7 +506,7 @@ void TypePrinter::printMemberPointerBefore(const MemberPointerType *T,
void TypePrinter::printMemberPointerAfter(const MemberPointerType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
// Handle things like 'int (Cls::*A)[4];' correctly.
// FIXME: this should include vectors, but vectors use attributes I guess.
if (isa<ArrayType>(T->getPointeeType()))
@@ -852,7 +848,7 @@ void TypePrinter::printFunctionProtoBefore(const FunctionProtoType *T,
OS << '(';
} else {
// If needed for precedence reasons, wrap the inner part in grouping parens.
- SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder, false);
+ SaveAndRestore PrevPHIsEmpty(HasEmptyPlaceHolder, false);
printBefore(T->getReturnType(), OS);
if (!PrevPHIsEmpty.get())
OS << '(';
@@ -880,7 +876,7 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
// If needed for precedence reasons, wrap the inner part in grouping parens.
if (!HasEmptyPlaceHolder)
OS << ')';
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
OS << '(';
{
@@ -1031,7 +1027,7 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
void TypePrinter::printFunctionNoProtoBefore(const FunctionNoProtoType *T,
raw_ostream &OS) {
// If needed for precedence reasons, wrap the inner part in grouping parens.
- SaveAndRestore<bool> PrevPHIsEmpty(HasEmptyPlaceHolder, false);
+ SaveAndRestore PrevPHIsEmpty(HasEmptyPlaceHolder, false);
printBefore(T->getReturnType(), OS);
if (!PrevPHIsEmpty.get())
OS << '(';
@@ -1042,7 +1038,7 @@ void TypePrinter::printFunctionNoProtoAfter(const FunctionNoProtoType *T,
// If needed for precedence reasons, wrap the inner part in grouping parens.
if (!HasEmptyPlaceHolder)
OS << ')';
- SaveAndRestore<bool> NonEmptyPH(HasEmptyPlaceHolder, false);
+ SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false);
OS << "()";
printFunctionAfter(T->getExtInfo(), OS);
@@ -1108,7 +1104,8 @@ void TypePrinter::printTypedefAfter(const TypedefType *T, raw_ostream &OS) {}
void TypePrinter::printTypeOfExprBefore(const TypeOfExprType *T,
raw_ostream &OS) {
- OS << "typeof ";
+ OS << (T->getKind() == TypeOfKind::Unqualified ? "typeof_unqual "
+ : "typeof ");
if (T->getUnderlyingExpr())
T->getUnderlyingExpr()->printPretty(OS, nullptr, Policy);
spaceBeforePlaceHolder(OS);
@@ -1118,8 +1115,9 @@ void TypePrinter::printTypeOfExprAfter(const TypeOfExprType *T,
raw_ostream &OS) {}
void TypePrinter::printTypeOfBefore(const TypeOfType *T, raw_ostream &OS) {
- OS << "typeof(";
- print(T->getUnderlyingType(), OS, StringRef());
+ OS << (T->getKind() == TypeOfKind::Unqualified ? "typeof_unqual("
+ : "typeof(");
+ print(T->getUnmodifiedType(), OS, StringRef());
OS << ')';
spaceBeforePlaceHolder(OS);
}
@@ -1140,29 +1138,19 @@ void TypePrinter::printUnaryTransformBefore(const UnaryTransformType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- switch (T->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- OS << "__underlying_type(";
- print(T->getBaseType(), OS, StringRef());
- OS << ')';
- spaceBeforePlaceHolder(OS);
- return;
- }
-
- printBefore(T->getBaseType(), OS);
+ static llvm::DenseMap<int, const char *> Transformation = {{
+#define TRANSFORM_TYPE_TRAIT_DEF(Enum, Trait) \
+ {UnaryTransformType::Enum, "__" #Trait},
+#include "clang/Basic/TransformTypeTraits.def"
+ }};
+ OS << Transformation[T->getUTTKind()] << '(';
+ print(T->getBaseType(), OS, StringRef());
+ OS << ')';
+ spaceBeforePlaceHolder(OS);
}
void TypePrinter::printUnaryTransformAfter(const UnaryTransformType *T,
- raw_ostream &OS) {
- IncludeStrongLifetimeRAII Strong(Policy);
-
- switch (T->getUTTKind()) {
- case UnaryTransformType::EnumUnderlyingType:
- return;
- }
-
- printAfter(T->getBaseType(), OS);
-}
+ raw_ostream &OS) {}
void TypePrinter::printAutoBefore(const AutoType *T, raw_ostream &OS) {
// If the type has been deduced, do not print 'auto'.
@@ -1470,14 +1458,27 @@ void TypePrinter::printSubstTemplateTypeParmPackBefore(
const SubstTemplateTypeParmPackType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- printTemplateTypeParmBefore(T->getReplacedParameter(), OS);
+ if (const TemplateTypeParmDecl *D = T->getReplacedParameter()) {
+ if (D && D->isImplicit()) {
+ if (auto *TC = D->getTypeConstraint()) {
+ TC->print(OS, Policy);
+ OS << ' ';
+ }
+ OS << "auto";
+ } else if (IdentifierInfo *Id = D->getIdentifier())
+ OS << (Policy.CleanUglifiedParameters ? Id->deuglifiedName()
+ : Id->getName());
+ else
+ OS << "type-parameter-" << D->getDepth() << '-' << D->getIndex();
+
+ spaceBeforePlaceHolder(OS);
+ }
}
void TypePrinter::printSubstTemplateTypeParmPackAfter(
const SubstTemplateTypeParmPackType *T,
raw_ostream &OS) {
IncludeStrongLifetimeRAII Strong(Policy);
- printTemplateTypeParmAfter(T->getReplacedParameter(), OS);
}
void TypePrinter::printTemplateId(const TemplateSpecializationType *T,
@@ -1675,7 +1676,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
// If this is a calling convention attribute, don't print the implicit CC from
// the modified type.
- SaveAndRestore<bool> MaybeSuppressCC(InsideCCAttribute, T->isCallingConv());
+ SaveAndRestore MaybeSuppressCC(InsideCCAttribute, T->isCallingConv());
printAfter(T->getModifiedType(), OS);
@@ -1733,6 +1734,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::OpenCLLocalAddressSpace:
case attr::OpenCLConstantAddressSpace:
case attr::OpenCLGenericAddressSpace:
+ case attr::HLSLGroupSharedAddressSpace:
// FIXME: Update printAttributedBefore to print these once we generate
// AttributedType nodes for them.
break;
@@ -1992,11 +1994,11 @@ static bool isSubstitutedType(ASTContext &Ctx, QualType T, QualType Pattern,
if (!isSubstitutedTemplateArgument(Ctx, Template, PTST->getTemplateName(),
Args, Depth))
return false;
- if (TemplateArgs.size() != PTST->getNumArgs())
+ if (TemplateArgs.size() != PTST->template_arguments().size())
return false;
for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I)
- if (!isSubstitutedTemplateArgument(Ctx, TemplateArgs[I], PTST->getArg(I),
- Args, Depth))
+ if (!isSubstitutedTemplateArgument(
+ Ctx, TemplateArgs[I], PTST->template_arguments()[I], Args, Depth))
return false;
return true;
}
@@ -2023,6 +2025,16 @@ static bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,
}
}
+ if (Arg.getKind() == TemplateArgument::Integral &&
+ Pattern.getKind() == TemplateArgument::Expression) {
+ Expr const *expr = Pattern.getAsExpr();
+
+ if (!expr->isValueDependent() && expr->isIntegerConstantExpr(Ctx)) {
+ return llvm::APSInt::isSameValue(expr->EvaluateKnownConstInt(Ctx),
+ Arg.getAsIntegral());
+ }
+ }
+
if (Arg.getKind() != Pattern.getKind())
return false;
@@ -2042,9 +2054,7 @@ static bool isSubstitutedTemplateArgument(ASTContext &Ctx, TemplateArgument Arg,
return false;
}
-/// Make a best-effort determination of whether the type T can be produced by
-/// substituting Args into the default argument of Param.
-static bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
+bool clang::isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg,
const NamedDecl *Param,
ArrayRef<TemplateArgument> Args,
unsigned Depth) {
@@ -2228,6 +2238,8 @@ std::string Qualifiers::getAddrSpaceAsString(LangAS AS) {
return "__uptr __ptr32";
case LangAS::ptr64:
return "__ptr64";
+ case LangAS::hlsl_groupshared:
+ return "groupshared";
default:
return std::to_string(toTargetAddressSpace(AS));
}
diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp
index 3d64cb17fa9c..bc9a83bde8a0 100644
--- a/clang/lib/AST/VTableBuilder.cpp
+++ b/clang/lib/AST/VTableBuilder.cpp
@@ -670,8 +670,9 @@ CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const {
// Under the relative ABI, the offset widths are 32-bit ints instead of
// pointer widths.
CharUnits OffsetWidth = Context.toCharUnitsFromBits(
- VTables.isRelativeLayout() ? 32
- : Context.getTargetInfo().getPointerWidth(0));
+ VTables.isRelativeLayout()
+ ? 32
+ : Context.getTargetInfo().getPointerWidth(LangAS::Default));
CharUnits OffsetOffset = OffsetWidth * OffsetIndex;
return OffsetOffset;