summaryrefslogtreecommitdiffstats
path: root/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST')
-rw-r--r--lib/AST/APValue.cpp34
-rw-r--r--lib/AST/ASTContext.cpp816
-rw-r--r--lib/AST/ASTDiagnostic.cpp83
-rw-r--r--lib/AST/ASTDumper.cpp219
-rw-r--r--lib/AST/ASTImporter.cpp291
-rw-r--r--lib/AST/ASTTypeTraits.cpp105
-rw-r--r--lib/AST/AttrImpl.cpp1
-rw-r--r--lib/AST/CMakeLists.txt4
-rw-r--r--lib/AST/CXXABI.h8
-rw-r--r--lib/AST/CXXInheritance.cpp14
-rw-r--r--lib/AST/Comment.cpp15
-rw-r--r--lib/AST/CommentCommandTraits.cpp43
-rw-r--r--lib/AST/CommentLexer.cpp21
-rw-r--r--lib/AST/CommentParser.cpp21
-rw-r--r--lib/AST/CommentSema.cpp145
-rw-r--r--lib/AST/Decl.cpp800
-rw-r--r--lib/AST/DeclBase.cpp195
-rw-r--r--lib/AST/DeclCXX.cpp198
-rw-r--r--lib/AST/DeclFriend.cpp5
-rw-r--r--lib/AST/DeclObjC.cpp86
-rw-r--r--lib/AST/DeclOpenMP.cpp11
-rw-r--r--lib/AST/DeclPrinter.cpp29
-rw-r--r--lib/AST/DeclTemplate.cpp357
-rw-r--r--lib/AST/DeclarationName.cpp142
-rw-r--r--lib/AST/DumpXML.cpp1053
-rw-r--r--lib/AST/Expr.cpp462
-rw-r--r--lib/AST/ExprCXX.cpp268
-rw-r--r--lib/AST/ExprClassification.cpp13
-rw-r--r--lib/AST/ExprConstant.cpp1981
-rw-r--r--lib/AST/InheritViz.cpp38
-rw-r--r--lib/AST/ItaniumCXXABI.cpp18
-rw-r--r--lib/AST/ItaniumMangle.cpp577
-rw-r--r--lib/AST/Mangle.cpp153
-rw-r--r--lib/AST/MangleNumberingContext.cpp (renamed from lib/AST/LambdaMangleContext.cpp)28
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp21
-rw-r--r--lib/AST/MicrosoftMangle.cpp992
-rw-r--r--lib/AST/NestedNameSpecifier.cpp3
-rw-r--r--lib/AST/ParentMap.cpp30
-rw-r--r--lib/AST/RawCommentList.cpp106
-rw-r--r--lib/AST/RecordLayout.cpp9
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp1484
-rw-r--r--lib/AST/Stmt.cpp266
-rw-r--r--lib/AST/StmtIterator.cpp63
-rw-r--r--lib/AST/StmtPrinter.cpp112
-rw-r--r--lib/AST/StmtProfile.cpp75
-rw-r--r--lib/AST/TemplateBase.cpp81
-rw-r--r--lib/AST/Type.cpp128
-rw-r--r--lib/AST/TypeLoc.cpp53
-rw-r--r--lib/AST/TypePrinter.cpp130
-rw-r--r--lib/AST/VTableBuilder.cpp1662
50 files changed, 8689 insertions, 4760 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 98e825b..541836b21b 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -212,6 +212,40 @@ void APValue::DestroyDataAndMakeUninit() {
Kind = Uninitialized;
}
+bool APValue::needsCleanup() const {
+ switch (getKind()) {
+ case Uninitialized:
+ case AddrLabelDiff:
+ return false;
+ case Struct:
+ case Union:
+ case Array:
+ case Vector:
+ return true;
+ case Int:
+ return getInt().needsCleanup();
+ case Float:
+ return getFloat().needsCleanup();
+ case ComplexFloat:
+ assert(getComplexFloatImag().needsCleanup() ==
+ getComplexFloatReal().needsCleanup() &&
+ "In _Complex float types, real and imaginary values always have the "
+ "same size.");
+ return getComplexFloatReal().needsCleanup();
+ case ComplexInt:
+ assert(getComplexIntImag().needsCleanup() ==
+ getComplexIntReal().needsCleanup() &&
+ "In _Complex int types, real and imaginary values must have the "
+ "same size.");
+ return getComplexIntReal().needsCleanup();
+ case LValue:
+ return reinterpret_cast<const LV *>(Data)->hasPathPtr();
+ case MemberPointer:
+ return reinterpret_cast<const MemberPointerData *>(Data)->hasPathPtr();
+ }
+ llvm_unreachable("Unknown APValue kind!");
+}
+
void APValue::swap(APValue &RHS) {
std::swap(Kind, RHS.Kind);
char TmpData[MaxSize];
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 176aec5..a03cf9e7 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -25,13 +25,16 @@
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/AST/Mangle.h"
+#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/Support/Capacity.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
@@ -132,8 +135,14 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
isa<RedeclarableTemplateDecl>(D) ||
isa<ClassTemplateSpecializationDecl>(D))
DeclLoc = D->getLocStart();
- else
+ else {
DeclLoc = D->getLocation();
+ // If location of the typedef name is in a macro, it is because being
+ // declared via a macro. Try using declaration's starting location
+ // as the "declaration location".
+ if (DeclLoc.isMacroID() && isa<TypedefDecl>(D))
+ DeclLoc = D->getLocStart();
+ }
// If the declaration doesn't map directly to a location in a file, we
// can't find the comment.
@@ -175,7 +184,8 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// First check whether we have a trailing comment.
if (Comment != RawComments.end() &&
(*Comment)->isDocumentation() && (*Comment)->isTrailingComment() &&
- (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D))) {
+ (isa<FieldDecl>(D) || isa<EnumConstantDecl>(D) || isa<VarDecl>(D) ||
+ isa<ObjCMethodDecl>(D) || isa<ObjCPropertyDecl>(D))) {
std::pair<FileID, unsigned> CommentBeginDecomp
= SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getBegin());
// Check that Doxygen trailing comment comes after the declaration, starts
@@ -220,7 +230,7 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
// There should be no other declarations or preprocessor directives between
// comment and declaration.
- if (Text.find_first_of(",;{}#@") != StringRef::npos)
+ if (Text.find_first_of(";{}#@") != StringRef::npos)
return NULL;
return *Comment;
@@ -406,9 +416,16 @@ comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC,
}
+comments::FullComment *ASTContext::getLocalCommentForDeclUncached(const Decl *D) const {
+ const RawComment *RC = getRawCommentForDeclNoCache(D);
+ return RC ? RC->parse(*this, 0, D) : 0;
+}
+
comments::FullComment *ASTContext::getCommentForDecl(
const Decl *D,
const Preprocessor *PP) const {
+ if (D->isInvalidDecl())
+ return NULL;
D = adjustDeclToTemplate(D);
const Decl *Canonical = D->getCanonicalDecl();
@@ -679,6 +696,19 @@ static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T,
}
}
+static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI,
+ const LangOptions &LangOpts) {
+ switch (LangOpts.getAddressSpaceMapMangling()) {
+ case LangOptions::ASMM_Target:
+ return TI.useAddressSpaceMapMangling();
+ case LangOptions::ASMM_On:
+ return true;
+ case LangOptions::ASMM_Off:
+ return false;
+ }
+ llvm_unreachable("getAddressSpaceMapMangling() doesn't cover anything.");
+}
+
ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
const TargetInfo *t,
IdentifierTable &idents, SelectorTable &sels,
@@ -690,7 +720,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
DependentTemplateSpecializationTypes(this_()),
SubstTemplateTemplateParmPacks(this_()),
GlobalNestedNameSpecifier(0),
- Int128Decl(0), UInt128Decl(0),
+ Int128Decl(0), UInt128Decl(0), Float128StubDecl(0),
BuiltinVaListDecl(0),
ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0),
BOOLDecl(0),
@@ -709,8 +739,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
ExternalSource(0), Listener(0),
Comments(SM), CommentsLoaded(false),
CommentCommandTraits(BumpAlloc, LOpts.CommentOpts),
- LastSDM(0, 0),
- UniqueBlockByRefTypeID(0)
+ LastSDM(0, 0)
{
if (size_reserve > 0) Types.reserve(size_reserve);
TUDecl = TranslationUnitDecl::Create(*this);
@@ -726,10 +755,12 @@ ASTContext::~ASTContext() {
// FIXME: Is this the ideal solution?
ReleaseDeclContextMaps();
- // Call all of the deallocation functions.
- for (unsigned I = 0, N = Deallocations.size(); I != N; ++I)
- Deallocations[I].first(Deallocations[I].second);
-
+ // Call all of the deallocation functions on all of their targets.
+ for (DeallocationMap::const_iterator I = Deallocations.begin(),
+ E = Deallocations.end(); I != E; ++I)
+ for (unsigned J = 0, N = I->second.size(); J != N; ++J)
+ (I->first)((I->second)[J]);
+
// ASTRecordLayout objects in ASTRecordLayouts must always be destroyed
// because they can contain DenseMaps.
for (llvm::DenseMap<const ObjCContainerDecl*,
@@ -750,10 +781,16 @@ ASTContext::~ASTContext() {
AEnd = DeclAttrs.end();
A != AEnd; ++A)
A->second->~AttrVec();
+
+ for (llvm::DenseMap<const DeclContext *, MangleNumberingContext *>::iterator
+ I = MangleNumberingContexts.begin(),
+ E = MangleNumberingContexts.end();
+ I != E; ++I)
+ delete I->second;
}
void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) {
- Deallocations.push_back(std::make_pair(Callback, Data));
+ Deallocations[Callback].push_back(Data);
}
void
@@ -848,6 +885,20 @@ TypedefDecl *ASTContext::getUInt128Decl() const {
return UInt128Decl;
}
+TypeDecl *ASTContext::getFloat128StubType() const {
+ assert(LangOpts.CPlusPlus && "should only be called for c++");
+ if (!Float128StubDecl) {
+ Float128StubDecl = CXXRecordDecl::Create(const_cast<ASTContext &>(*this),
+ TTK_Struct,
+ getTranslationUnitDecl(),
+ SourceLocation(),
+ SourceLocation(),
+ &Idents.get("__float128"));
+ }
+
+ return Float128StubDecl;
+}
+
void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) {
BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K);
R = CanQualType::CreateUnsafe(QualType(Ty, 0));
@@ -863,6 +914,7 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
ABI.reset(createCXXABI(Target));
AddrSpaceMap = getAddressSpaceMap(Target, LangOpts);
+ AddrSpaceMapMangling = isAddrSpaceMapManglingEnabled(Target, LangOpts);
// C99 6.2.5p19.
InitBuiltinType(VoidTy, BuiltinType::Void);
@@ -897,13 +949,17 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
InitBuiltinType(Int128Ty, BuiltinType::Int128);
InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
- if (LangOpts.CPlusPlus && LangOpts.WChar) { // C++ 3.9.1p5
- if (TargetInfo::isTypeSigned(Target.getWCharType()))
- InitBuiltinType(WCharTy, BuiltinType::WChar_S);
- else // -fshort-wchar makes wchar_t be unsigned.
- InitBuiltinType(WCharTy, BuiltinType::WChar_U);
- } else // C99 (or C++ using -fno-wchar)
- WCharTy = getFromTargetType(Target.getWCharType());
+ // C++ 3.9.1p5
+ if (TargetInfo::isTypeSigned(Target.getWCharType()))
+ InitBuiltinType(WCharTy, BuiltinType::WChar_S);
+ else // -fshort-wchar makes wchar_t be unsigned.
+ InitBuiltinType(WCharTy, BuiltinType::WChar_U);
+ if (LangOpts.CPlusPlus && LangOpts.WChar)
+ WideCharTy = WCharTy;
+ else {
+ // C99 (or C++ using -fno-wchar).
+ WideCharTy = getFromTargetType(Target.getWCharType());
+ }
WIntTy = getFromTargetType(Target.getWIntType());
@@ -1008,13 +1064,20 @@ void ASTContext::eraseDeclAttrs(const Decl *D) {
}
}
+// FIXME: Remove ?
MemberSpecializationInfo *
ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) {
assert(Var->isStaticDataMember() && "Not a static data member");
- llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>::iterator Pos
- = InstantiatedFromStaticDataMember.find(Var);
- if (Pos == InstantiatedFromStaticDataMember.end())
- return 0;
+ return getTemplateOrSpecializationInfo(Var)
+ .dyn_cast<MemberSpecializationInfo *>();
+}
+
+ASTContext::TemplateOrSpecializationInfo
+ASTContext::getTemplateOrSpecializationInfo(const VarDecl *Var) {
+ llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>::iterator Pos =
+ TemplateOrInstantiation.find(Var);
+ if (Pos == TemplateOrInstantiation.end())
+ return TemplateOrSpecializationInfo();
return Pos->second;
}
@@ -1025,10 +1088,16 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
SourceLocation PointOfInstantiation) {
assert(Inst->isStaticDataMember() && "Not a static data member");
assert(Tmpl->isStaticDataMember() && "Not a static data member");
- assert(!InstantiatedFromStaticDataMember[Inst] &&
- "Already noted what static data member was instantiated from");
- InstantiatedFromStaticDataMember[Inst]
- = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation);
+ setTemplateOrSpecializationInfo(Inst, new (*this) MemberSpecializationInfo(
+ Tmpl, TSK, PointOfInstantiation));
+}
+
+void
+ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst,
+ TemplateOrSpecializationInfo TSI) {
+ assert(!TemplateOrInstantiation[Inst] &&
+ "Already noted what the variable was instantiated from");
+ TemplateOrInstantiation[Inst] = TSI;
}
FunctionDecl *ASTContext::getClassScopeSpecializationPattern(
@@ -1105,38 +1174,6 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst,
InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl;
}
-bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && !LastFD->isBitField() &&
- FD->getBitWidthValue(*this) == 0);
-}
-
-bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && LastFD->isBitField() &&
- FD->getBitWidthValue(*this) == 0 &&
- LastFD->getBitWidthValue(*this) != 0);
-}
-
-bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && LastFD->isBitField() &&
- FD->getBitWidthValue(*this) &&
- LastFD->getBitWidthValue(*this));
-}
-
-bool ASTContext::NonBitfieldFollowsBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (!FD->isBitField() && LastFD && LastFD->isBitField() &&
- LastFD->getBitWidthValue(*this));
-}
-
-bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD,
- const FieldDecl *LastFD) const {
- return (FD->isBitField() && LastFD && !LastFD->isBitField() &&
- FD->getBitWidthValue(*this));
-}
-
ASTContext::overridden_cxx_method_iterator
ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const {
llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos
@@ -1224,12 +1261,7 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
}
}
-/// getDeclAlign - Return a conservative estimate of the alignment of the
-/// specified decl. Note that bitfields do not have a valid alignment, so
-/// this method will assert on them.
-/// If @p RefAsPointee, references are treated like their underlying type
-/// (for alignof), else they're treated like pointers (for CodeGen).
-CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
+CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const {
unsigned Align = Target->getCharWidth();
bool UseAlignAttrOnly = false;
@@ -1262,7 +1294,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
} else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
QualType T = VD->getType();
if (const ReferenceType* RT = T->getAs<ReferenceType>()) {
- if (RefAsPointee)
+ if (ForAlignof)
T = RT->getPointeeType();
else
T = getPointerType(RT->getPointeeType());
@@ -1270,14 +1302,15 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
if (!T->isIncompleteType() && !T->isFunctionType()) {
// Adjust alignments of declarations with array type by the
// large-array alignment on the target.
- unsigned MinWidth = Target->getLargeArrayMinWidth();
- const ArrayType *arrayType;
- if (MinWidth && (arrayType = getAsArrayType(T))) {
- if (isa<VariableArrayType>(arrayType))
- Align = std::max(Align, Target->getLargeArrayAlign());
- else if (isa<ConstantArrayType>(arrayType) &&
- MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType)))
- Align = std::max(Align, Target->getLargeArrayAlign());
+ if (const ArrayType *arrayType = getAsArrayType(T)) {
+ unsigned MinWidth = Target->getLargeArrayMinWidth();
+ if (!ForAlignof && MinWidth) {
+ if (isa<VariableArrayType>(arrayType))
+ Align = std::max(Align, Target->getLargeArrayAlign());
+ else if (isa<ConstantArrayType>(arrayType) &&
+ MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType)))
+ Align = std::max(Align, Target->getLargeArrayAlign());
+ }
// Walk through any array types while we're at it.
T = getBaseElementType(arrayType);
@@ -1294,24 +1327,27 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
// a max-field-alignment constraint (#pragma pack). So calculate
// the actual alignment of the field within the struct, and then
// (as we're expected to) constrain that by the alignment of the type.
- if (const FieldDecl *field = dyn_cast<FieldDecl>(VD)) {
- // So calculate the alignment of the field.
- const ASTRecordLayout &layout = getASTRecordLayout(field->getParent());
-
- // Start with the record's overall alignment.
- unsigned fieldAlign = toBits(layout.getAlignment());
-
- // Use the GCD of that and the offset within the record.
- uint64_t offset = layout.getFieldOffset(field->getFieldIndex());
- if (offset > 0) {
- // Alignment is always a power of 2, so the GCD will be a power of 2,
- // which means we get to do this crazy thing instead of Euclid's.
- uint64_t lowBitOfOffset = offset & (~offset + 1);
- if (lowBitOfOffset < fieldAlign)
- fieldAlign = static_cast<unsigned>(lowBitOfOffset);
- }
+ if (const FieldDecl *Field = dyn_cast<FieldDecl>(VD)) {
+ const RecordDecl *Parent = Field->getParent();
+ // We can only produce a sensible answer if the record is valid.
+ if (!Parent->isInvalidDecl()) {
+ const ASTRecordLayout &Layout = getASTRecordLayout(Parent);
+
+ // Start with the record's overall alignment.
+ unsigned FieldAlign = toBits(Layout.getAlignment());
+
+ // Use the GCD of that and the offset within the record.
+ uint64_t Offset = Layout.getFieldOffset(Field->getFieldIndex());
+ if (Offset > 0) {
+ // Alignment is always a power of 2, so the GCD will be a power of 2,
+ // which means we get to do this crazy thing instead of Euclid's.
+ uint64_t LowBitOfOffset = Offset & (~Offset + 1);
+ if (LowBitOfOffset < FieldAlign)
+ FieldAlign = static_cast<unsigned>(LowBitOfOffset);
+ }
- Align = std::min(Align, fieldAlign);
+ Align = std::min(Align, FieldAlign);
+ }
}
}
@@ -1339,8 +1375,30 @@ ASTContext::getTypeInfoDataSizeInChars(QualType T) const {
return sizeAndAlign;
}
+/// getConstantArrayInfoInChars - Performing the computation in CharUnits
+/// instead of in bits prevents overflowing the uint64_t for some large arrays.
+std::pair<CharUnits, CharUnits>
+static getConstantArrayInfoInChars(const ASTContext &Context,
+ const ConstantArrayType *CAT) {
+ std::pair<CharUnits, CharUnits> EltInfo =
+ Context.getTypeInfoInChars(CAT->getElementType());
+ uint64_t Size = CAT->getSize().getZExtValue();
+ assert((Size == 0 || static_cast<uint64_t>(EltInfo.first.getQuantity()) <=
+ (uint64_t)(-1)/Size) &&
+ "Overflow in array type char size evaluation");
+ uint64_t Width = EltInfo.first.getQuantity() * Size;
+ unsigned Align = EltInfo.second.getQuantity();
+ if (!Context.getTargetInfo().getCXXABI().isMicrosoft() ||
+ Context.getTargetInfo().getPointerWidth(0) == 64)
+ Width = llvm::RoundUpToAlignment(Width, Align);
+ return std::make_pair(CharUnits::fromQuantity(Width),
+ CharUnits::fromQuantity(Align));
+}
+
std::pair<CharUnits, CharUnits>
ASTContext::getTypeInfoInChars(const Type *T) const {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T))
+ return getConstantArrayInfoInChars(*this, CAT);
std::pair<uint64_t, unsigned> Info = getTypeInfo(T);
return std::make_pair(toCharUnitsFromBits(Info.first),
toCharUnitsFromBits(Info.second));
@@ -1376,6 +1434,10 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
#define ABSTRACT_TYPE(Class, Base)
#define NON_CANONICAL_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base) case Type::Class:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) \
+ case Type::Class: \
+ assert(!T->isDependentType() && "should not see dependent types here"); \
+ return getTypeInfo(cast<Class##Type>(T)->desugar().getTypePtr());
#include "clang/AST/TypeNodes.def"
llvm_unreachable("Should not see dependent types");
@@ -1401,7 +1463,9 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
"Overflow in array type bit size evaluation");
Width = EltInfo.first*Size;
Align = EltInfo.second;
- Width = llvm::RoundUpToAlignment(Width, Align);
+ if (!getTargetInfo().getCXXABI().isMicrosoft() ||
+ getTargetInfo().getPointerWidth(0) == 64)
+ Width = llvm::RoundUpToAlignment(Width, Align);
break;
}
case Type::ExtVector:
@@ -1568,6 +1632,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::ObjCObject:
return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr());
+ case Type::Decayed:
+ return getTypeInfo(cast<DecayedType>(T)->getDecayedType().getTypePtr());
case Type::ObjCInterface: {
const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T);
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
@@ -1624,20 +1690,6 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
break;
}
- case Type::TypeOfExpr:
- return getTypeInfo(cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType()
- .getTypePtr());
-
- case Type::TypeOf:
- return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr());
-
- case Type::Decltype:
- return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType()
- .getTypePtr());
-
- case Type::UnaryTransform:
- return getTypeInfo(cast<UnaryTransformType>(T)->getUnderlyingType());
-
case Type::Elaborated:
return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
@@ -1645,18 +1697,6 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
return getTypeInfo(
cast<AttributedType>(T)->getEquivalentType().getTypePtr());
- case Type::TemplateSpecialization: {
- assert(getCanonicalType(T) != T &&
- "Cannot request the size of a dependent type");
- const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T);
- // A type alias template specialization may refer to a typedef with the
- // aligned attribute on it.
- if (TST->isTypeAlias())
- return getTypeInfo(TST->getAliasedType().getTypePtr());
- else
- return getTypeInfo(getCanonicalType(T));
- }
-
case Type::Atomic: {
// Start with the base type information.
std::pair<uint64_t, unsigned> Info
@@ -1696,10 +1736,10 @@ int64_t ASTContext::toBits(CharUnits CharSize) const {
/// getTypeSizeInChars - Return the size of the specified type, in characters.
/// This method does not work on incomplete types.
CharUnits ASTContext::getTypeSizeInChars(QualType T) const {
- return toCharUnitsFromBits(getTypeSize(T));
+ return getTypeInfoInChars(T).first;
}
CharUnits ASTContext::getTypeSizeInChars(const Type *T) const {
- return toCharUnitsFromBits(getTypeSize(T));
+ return getTypeInfoInChars(T).first;
}
/// getTypeAlignInChars - Return the ABI-specified alignment of a type, in
@@ -1718,6 +1758,9 @@ CharUnits ASTContext::getTypeAlignInChars(const Type *T) const {
unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
unsigned ABIAlign = getTypeAlign(T);
+ if (Target->getTriple().getArch() == llvm::Triple::xcore)
+ return ABIAlign; // Never overalign on XCore.
+
// Double and long long should be naturally aligned if possible.
if (const ComplexType* CT = T->getAs<ComplexType>())
T = CT->getElementType().getTypePtr();
@@ -2042,10 +2085,7 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = Info;
- Result = getFunctionType(FPT->getResultType(),
- ArrayRef<QualType>(FPT->arg_type_begin(),
- FPT->getNumArgs()),
- EPI);
+ Result = getFunctionType(FPT->getResultType(), FPT->getArgTypes(), EPI);
}
return cast<FunctionType>(Result.getTypePtr());
@@ -2053,12 +2093,18 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
QualType ResultType) {
- // FIXME: Need to inform serialization code about this!
- for (FD = FD->getMostRecentDecl(); FD; FD = FD->getPreviousDecl()) {
+ FD = FD->getMostRecentDecl();
+ while (true) {
const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
FD->setType(getFunctionType(ResultType, FPT->getArgTypes(), EPI));
+ if (FunctionDecl *Next = FD->getPreviousDecl())
+ FD = Next;
+ else
+ break;
}
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->DeducedReturnType(FD, ResultType);
}
/// getComplexType - Return the uniqued reference to the type for a complex
@@ -2117,6 +2163,45 @@ QualType ASTContext::getPointerType(QualType T) const {
return QualType(New, 0);
}
+QualType ASTContext::getDecayedType(QualType T) const {
+ assert((T->isArrayType() || T->isFunctionType()) && "T does not decay");
+
+ llvm::FoldingSetNodeID ID;
+ DecayedType::Profile(ID, T);
+ void *InsertPos = 0;
+ if (DecayedType *DT = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(DT, 0);
+
+ QualType Decayed;
+
+ // C99 6.7.5.3p7:
+ // A declaration of a parameter as "array of type" shall be
+ // adjusted to "qualified pointer to type", where the type
+ // qualifiers (if any) are those specified within the [ and ] of
+ // the array type derivation.
+ if (T->isArrayType())
+ Decayed = getArrayDecayedType(T);
+
+ // C99 6.7.5.3p8:
+ // A declaration of a parameter as "function returning type"
+ // shall be adjusted to "pointer to function returning type", as
+ // in 6.3.2.1.
+ if (T->isFunctionType())
+ Decayed = getPointerType(T);
+
+ QualType Canonical = getCanonicalType(Decayed);
+
+ // Get the new insert position for the node we care about.
+ DecayedType *NewIP = DecayedTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
+
+ DecayedType *New =
+ new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical);
+ Types.push_back(New);
+ DecayedTypes.InsertNode(New, InsertPos);
+ return QualType(New, 0);
+}
+
/// getBlockPointerType - Return the uniqued reference to the type for
/// a pointer to the specified block.
QualType ASTContext::getBlockPointerType(QualType T) const {
@@ -2676,9 +2761,8 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType,
QualType
ASTContext::getFunctionNoProtoType(QualType ResultTy,
const FunctionType::ExtInfo &Info) const {
- const CallingConv DefaultCC = Info.getCC();
- const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
- CC_X86StdCall : DefaultCC;
+ const CallingConv CallConv = Info.getCC();
+
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -2690,11 +2774,8 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
return QualType(FT, 0);
QualType Canonical;
- if (!ResultTy.isCanonical() ||
- getCanonicalCallConv(CallConv) != CallConv) {
- Canonical =
- getFunctionNoProtoType(getCanonicalType(ResultTy),
- Info.withCallingConv(getCanonicalCallConv(CallConv)));
+ if (!ResultTy.isCanonical()) {
+ Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), Info);
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
@@ -2743,14 +2824,10 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
if (!ArgArray[i].isCanonicalAsParam())
isCanonical = false;
- const CallingConv DefaultCC = EPI.ExtInfo.getCC();
- const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ?
- CC_X86StdCall : DefaultCC;
-
// If this type isn't canonical, get the canonical version of it.
// The exception spec is not part of the canonical type.
QualType Canonical;
- if (!isCanonical || getCanonicalCallConv(CallConv) != CallConv) {
+ if (!isCanonical) {
SmallVector<QualType, 16> CanonicalArgs;
CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
@@ -2760,8 +2837,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
CanonicalEPI.HasTrailingReturn = false;
CanonicalEPI.ExceptionSpecType = EST_None;
CanonicalEPI.NumExceptions = 0;
- CanonicalEPI.ExtInfo
- = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv));
// Result types do not have ARC lifetime qualifiers.
QualType CanResultTy = getCanonicalType(ResultTy);
@@ -2803,7 +2878,6 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
FunctionProtoType::ExtProtoInfo newEPI = EPI;
- newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
@@ -2856,13 +2930,11 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
"Template type parameter types are always available.");
if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) {
- assert(!Record->getPreviousDecl() &&
- "struct/union has previous declaration");
+ assert(Record->isFirstDecl() && "struct/union has previous declaration");
assert(!NeedsInjectedClassNameType(Record));
return getRecordType(Record);
} else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) {
- assert(!Enum->getPreviousDecl() &&
- "enum has previous declaration");
+ assert(Enum->isFirstDecl() && "enum has previous declaration");
return getEnumType(Enum);
} else if (const UnresolvedUsingTypenameDecl *Using =
dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) {
@@ -4104,22 +4176,9 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const {
}
QualType ASTContext::getAdjustedParameterType(QualType T) const {
- // C99 6.7.5.3p7:
- // A declaration of a parameter as "array of type" shall be
- // adjusted to "qualified pointer to type", where the type
- // qualifiers (if any) are those specified within the [ and ] of
- // the array type derivation.
- if (T->isArrayType())
- return getArrayDecayedType(T);
-
- // C99 6.7.5.3p8:
- // A declaration of a parameter as "function returning type"
- // shall be adjusted to "pointer to function returning type", as
- // in 6.3.2.1.
- if (T->isFunctionType())
- return getPointerType(T);
-
- return T;
+ if (T->isArrayType() || T->isFunctionType())
+ return getDecayedType(T);
+ return T;
}
QualType ASTContext::getSignatureParameterType(QualType T) const {
@@ -4364,12 +4423,27 @@ Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const {
return Qualifiers::OCL_None;
}
+static const Type *getIntegerTypeForEnum(const EnumType *ET) {
+ // Incomplete enum types are not treated as integer types.
+ // FIXME: In C++, enum types are never integer types.
+ if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped())
+ return ET->getDecl()->getIntegerType().getTypePtr();
+ return NULL;
+}
+
/// getIntegerTypeOrder - Returns the highest ranked integer type:
/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
/// LHS < RHS, return -1.
int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) const {
const Type *LHSC = getCanonicalType(LHS).getTypePtr();
const Type *RHSC = getCanonicalType(RHS).getTypePtr();
+
+ // Unwrap enums to their underlying type.
+ if (const EnumType *ET = dyn_cast<EnumType>(LHSC))
+ LHSC = getIntegerTypeForEnum(ET);
+ if (const EnumType *ET = dyn_cast<EnumType>(RHSC))
+ RHSC = getIntegerTypeForEnum(ET);
+
if (LHSC == RHSC) return 0;
bool LHSUnsigned = LHSC->isUnsignedIntegerType();
@@ -4484,7 +4558,7 @@ QualType ASTContext::getBlockDescriptorType() const {
UnsignedLongTy,
};
- const char *FieldNames[] = {
+ static const char *const FieldNames[] = {
"reserved",
"Size"
};
@@ -4525,7 +4599,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
getPointerType(VoidPtrTy)
};
- const char *FieldNames[] = {
+ static const char *const FieldNames[] = {
"reserved",
"Size",
"CopyFuncPtr",
@@ -4910,6 +4984,10 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
if (PD->isReadOnly()) {
S += ",R";
+ if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy)
+ S += ",C";
+ if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain)
+ S += ",&";
} else {
switch (PD->getSetterKind()) {
case ObjCPropertyDecl::Assign: break;
@@ -5200,12 +5278,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
} else {
S += '[';
- if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
- if (getTypeSize(CAT->getElementType()) == 0)
- S += '0';
- else
- S += llvm::utostr(CAT->getSize().getZExtValue());
- } else {
+ if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
+ S += llvm::utostr(CAT->getSize().getZExtValue());
+ else {
//Variable length arrays are encoded as a regular array with 0 elements.
assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) &&
"Unknown array type!");
@@ -5384,6 +5459,20 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// We encode the underlying type which comes out as
// {...};
S += '^';
+ if (FD && OPT->getInterfaceDecl()) {
+ // Prevent recursive encoding of fields in some rare cases.
+ ObjCInterfaceDecl *OI = OPT->getInterfaceDecl();
+ SmallVector<const ObjCIvarDecl*, 32> Ivars;
+ DeepCollectObjCIvars(OI, true, Ivars);
+ for (unsigned i = 0, e = Ivars.size(); i != e; ++i) {
+ if (cast<FieldDecl>(Ivars[i]) == FD) {
+ S += '{';
+ S += OI->getIdentifier()->getName();
+ S += '}';
+ return;
+ }
+ }
+ }
getObjCEncodingForTypeImpl(PointeeTy, S,
false, ExpandPointedToStructures,
NULL,
@@ -5484,7 +5573,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
if (base->isEmpty())
continue;
uint64_t offs = toBits(layout.getVBaseClassOffset(base));
- if (FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end())
+ if (offs >= uint64_t(toBits(layout.getNonVirtualSize())) &&
+ FieldOrBaseOffsets.find(offs) == FieldOrBaseOffsets.end())
FieldOrBaseOffsets.insert(FieldOrBaseOffsets.end(),
std::make_pair(offs, base));
}
@@ -6267,6 +6357,8 @@ ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param,
CanQualType ASTContext::getFromTargetType(unsigned Type) const {
switch (Type) {
case TargetInfo::NoInt: return CanQualType();
+ case TargetInfo::SignedChar: return SignedCharTy;
+ case TargetInfo::UnsignedChar: return UnsignedCharTy;
case TargetInfo::SignedShort: return ShortTy;
case TargetInfo::UnsignedShort: return UnsignedShortTy;
case TargetInfo::SignedInt: return IntTy;
@@ -6369,15 +6461,6 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
return false;
}
-/// QualifiedIdConformsQualifiedId - compare id<pr,...> with id<pr1,...>
-/// return true if lhs's protocols conform to rhs's protocol; false
-/// otherwise.
-bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
- if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType())
- return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false);
- return false;
-}
-
/// ObjCQualifiedClassTypesAreCompatible - compare Class<pr,...> and
/// Class<pr1, ...>.
bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs,
@@ -6890,7 +6973,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo();
// Compatible functions must have compatible calling conventions
- if (!isSameCallConv(lbaseInfo.getCC(), rbaseInfo.getCC()))
+ if (lbaseInfo.getCC() != rbaseInfo.getCC())
return QualType();
// Regparm is part of the calling convention.
@@ -7000,10 +7083,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType,
- ArrayRef<QualType>(proto->arg_type_begin(),
- proto->getNumArgs()),
- EPI);
+ return getFunctionType(retType, proto->getArgTypes(), EPI);
}
if (allLTypes) return lhs;
@@ -7351,11 +7431,8 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = getFunctionExtInfo(LHS);
- QualType ResultType
- = getFunctionType(OldReturnType,
- ArrayRef<QualType>(FPT->arg_type_begin(),
- FPT->getNumArgs()),
- EPI);
+ QualType ResultType =
+ getFunctionType(OldReturnType, FPT->getArgTypes(), EPI);
return ResultType;
}
}
@@ -7407,7 +7484,7 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
//===----------------------------------------------------------------------===//
unsigned ASTContext::getIntWidth(QualType T) const {
- if (const EnumType *ET = dyn_cast<EnumType>(T))
+ if (const EnumType *ET = T->getAs<EnumType>())
T = ET->getDecl()->getIntegerType();
if (T->isBooleanType())
return 1;
@@ -7450,6 +7527,8 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) const {
ASTMutationListener::~ASTMutationListener() { }
+void ASTMutationListener::DeducedReturnType(const FunctionDecl *FD,
+ QualType ReturnType) {}
//===----------------------------------------------------------------------===//
// Builtin Type Computation
@@ -7507,6 +7586,11 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
"Bad modifiers used with 'v'!");
Type = Context.VoidTy;
break;
+ case 'h':
+ assert(HowLong == 0 && !Signed && !Unsigned &&
+ "Bad modifiers used with 'f'!");
+ Type = Context.HalfTy;
+ break;
case 'f':
assert(HowLong == 0 && !Signed && !Unsigned &&
"Bad modifiers used with 'f'!");
@@ -7734,7 +7818,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
"'.' should only occur at end of builtin type list!");
- FunctionType::ExtInfo EI;
+ FunctionType::ExtInfo EI(CC_C);
if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true);
bool Variadic = (TypeStr[0] == '.');
@@ -7751,36 +7835,30 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
- GVALinkage External = GVA_StrongExternal;
-
- Linkage L = FD->getLinkage();
- switch (L) {
- case NoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
+ if (!FD->isExternallyVisible())
return GVA_Internal;
-
- case ExternalLinkage:
- switch (FD->getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- External = GVA_StrongExternal;
- break;
- case TSK_ExplicitInstantiationDefinition:
- return GVA_ExplicitTemplateInstantiation;
+ GVALinkage External = GVA_StrongExternal;
+ switch (FD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ External = GVA_StrongExternal;
+ break;
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ImplicitInstantiation:
- External = GVA_TemplateInstantiation;
- break;
- }
+ case TSK_ExplicitInstantiationDefinition:
+ return GVA_ExplicitTemplateInstantiation;
+
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ImplicitInstantiation:
+ External = GVA_TemplateInstantiation;
+ break;
}
if (!FD->isInlined())
return External;
-
- if (!getLangOpts().CPlusPlus || FD->hasAttr<GNUInlineAttr>()) {
+
+ if ((!getLangOpts().CPlusPlus && !getLangOpts().MicrosoftMode) ||
+ FD->hasAttr<GNUInlineAttr>()) {
// GNU or C99 inline semantics. Determine whether this symbol should be
// externally visible.
if (FD->isInlineDefinitionExternallyVisible())
@@ -7804,37 +7882,23 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
}
GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
- // If this is a static data member, compute the kind of template
- // specialization. Otherwise, this variable is not part of a
- // template.
- TemplateSpecializationKind TSK = TSK_Undeclared;
- if (VD->isStaticDataMember())
- TSK = VD->getTemplateSpecializationKind();
-
- Linkage L = VD->getLinkage();
-
- switch (L) {
- case NoLinkage:
- case InternalLinkage:
- case UniqueExternalLinkage:
+ if (!VD->isExternallyVisible())
return GVA_Internal;
- case ExternalLinkage:
- switch (TSK) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- return GVA_StrongExternal;
+ switch (VD->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ExplicitSpecialization:
+ return GVA_StrongExternal;
- case TSK_ExplicitInstantiationDeclaration:
- llvm_unreachable("Variable should not be instantiated");
- // Fall through to treat this like any other instantiation.
-
- case TSK_ExplicitInstantiationDefinition:
- return GVA_ExplicitTemplateInstantiation;
+ case TSK_ExplicitInstantiationDeclaration:
+ llvm_unreachable("Variable should not be instantiated");
+ // Fall through to treat this like any other instantiation.
- case TSK_ImplicitInstantiation:
- return GVA_TemplateInstantiation;
- }
+ case TSK_ExplicitInstantiationDefinition:
+ return GVA_ExplicitTemplateInstantiation;
+
+ case TSK_ImplicitInstantiation:
+ return GVA_TemplateInstantiation;
}
llvm_unreachable("Invalid Linkage!");
@@ -7918,16 +7982,13 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return false;
}
-CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
+CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic,
+ bool IsCXXMethod) const {
// Pass through to the C++ ABI object
- return ABI->getDefaultMethodCallConv(isVariadic);
-}
+ if (IsCXXMethod)
+ return ABI->getDefaultMethodCallConv(IsVariadic);
-CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const {
- if (CC == CC_C && !LangOpts.MRTD &&
- getTargetInfo().getCXXABI().isMemberFunctionCCDefault())
- return CC_Default;
- return CC;
+ return (LangOpts.MRTD && !IsVariadic) ? CC_X86StdCall : CC_C;
}
bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
@@ -7941,9 +8002,9 @@ MangleContext *ASTContext::createMangleContext() {
case TargetCXXABI::GenericItanium:
case TargetCXXABI::GenericARM:
case TargetCXXABI::iOS:
- return createItaniumMangleContext(*this, getDiagnostics());
+ return ItaniumMangleContext::create(*this, getDiagnostics());
case TargetCXXABI::Microsoft:
- return createMicrosoftMangleContext(*this, getDiagnostics());
+ return MicrosoftMangleContext::create(*this, getDiagnostics());
}
llvm_unreachable("Unsupported ABI");
}
@@ -7951,45 +8012,77 @@ MangleContext *ASTContext::createMangleContext() {
CXXABI::~CXXABI() {}
size_t ASTContext::getSideTableAllocatedMemory() const {
- return ASTRecordLayouts.getMemorySize()
- + llvm::capacity_in_bytes(ObjCLayouts)
- + llvm::capacity_in_bytes(KeyFunctions)
- + llvm::capacity_in_bytes(ObjCImpls)
- + llvm::capacity_in_bytes(BlockVarCopyInits)
- + llvm::capacity_in_bytes(DeclAttrs)
- + llvm::capacity_in_bytes(InstantiatedFromStaticDataMember)
- + llvm::capacity_in_bytes(InstantiatedFromUsingDecl)
- + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl)
- + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl)
- + llvm::capacity_in_bytes(OverriddenMethods)
- + llvm::capacity_in_bytes(Types)
- + llvm::capacity_in_bytes(VariableArrayTypes)
- + llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
-}
-
-void ASTContext::addUnnamedTag(const TagDecl *Tag) {
- // FIXME: This mangling should be applied to function local classes too
- if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() ||
- !isa<CXXRecordDecl>(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage)
- return;
+ return ASTRecordLayouts.getMemorySize() +
+ llvm::capacity_in_bytes(ObjCLayouts) +
+ llvm::capacity_in_bytes(KeyFunctions) +
+ llvm::capacity_in_bytes(ObjCImpls) +
+ llvm::capacity_in_bytes(BlockVarCopyInits) +
+ llvm::capacity_in_bytes(DeclAttrs) +
+ llvm::capacity_in_bytes(TemplateOrInstantiation) +
+ llvm::capacity_in_bytes(InstantiatedFromUsingDecl) +
+ llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) +
+ llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) +
+ llvm::capacity_in_bytes(OverriddenMethods) +
+ llvm::capacity_in_bytes(Types) +
+ llvm::capacity_in_bytes(VariableArrayTypes) +
+ llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
+}
+
+/// getIntTypeForBitwidth -
+/// sets integer QualTy according to specified details:
+/// bitwidth, signed/unsigned.
+/// Returns empty type if there is no appropriate target types.
+QualType ASTContext::getIntTypeForBitwidth(unsigned DestWidth,
+ unsigned Signed) const {
+ TargetInfo::IntType Ty = getTargetInfo().getIntTypeByWidth(DestWidth, Signed);
+ CanQualType QualTy = getFromTargetType(Ty);
+ if (!QualTy && DestWidth == 128)
+ return Signed ? Int128Ty : UnsignedInt128Ty;
+ return QualTy;
+}
+
+/// getRealTypeForBitwidth -
+/// sets floating point QualTy according to specified bitwidth.
+/// Returns empty type if there is no appropriate target types.
+QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth) const {
+ TargetInfo::RealType Ty = getTargetInfo().getRealTypeByWidth(DestWidth);
+ switch (Ty) {
+ case TargetInfo::Float:
+ return FloatTy;
+ case TargetInfo::Double:
+ return DoubleTy;
+ case TargetInfo::LongDouble:
+ return LongDoubleTy;
+ case TargetInfo::NoFloat:
+ return QualType();
+ }
- std::pair<llvm::DenseMap<const DeclContext *, unsigned>::iterator, bool> P =
- UnnamedMangleContexts.insert(std::make_pair(Tag->getParent(), 0));
- UnnamedMangleNumbers.insert(std::make_pair(Tag, P.first->second++));
+ llvm_unreachable("Unhandled TargetInfo::RealType value");
}
-int ASTContext::getUnnamedTagManglingNumber(const TagDecl *Tag) const {
- llvm::DenseMap<const TagDecl *, unsigned>::const_iterator I =
- UnnamedMangleNumbers.find(Tag);
- return I != UnnamedMangleNumbers.end() ? I->second : -1;
+void ASTContext::setManglingNumber(const NamedDecl *ND, unsigned Number) {
+ if (Number > 1)
+ MangleNumbers[ND] = Number;
}
-unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) {
- CXXRecordDecl *Lambda = CallOperator->getParent();
- return LambdaMangleContexts[Lambda->getDeclContext()]
- .getManglingNumber(CallOperator);
+unsigned ASTContext::getManglingNumber(const NamedDecl *ND) const {
+ llvm::DenseMap<const NamedDecl *, unsigned>::const_iterator I =
+ MangleNumbers.find(ND);
+ return I != MangleNumbers.end() ? I->second : 1;
}
+MangleNumberingContext &
+ASTContext::getManglingNumberContext(const DeclContext *DC) {
+ assert(LangOpts.CPlusPlus); // We don't need mangling numbers for plain C.
+ MangleNumberingContext *&MCtx = MangleNumberingContexts[DC];
+ if (!MCtx)
+ MCtx = createMangleNumberingContext();
+ return *MCtx;
+}
+
+MangleNumberingContext *ASTContext::createMangleNumberingContext() const {
+ return ABI->createMangleNumberingContext();
+}
void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) {
ParamIndices[D] = index;
@@ -8001,3 +8094,160 @@ unsigned ASTContext::getParameterIndex(const ParmVarDecl *D) const {
"ParmIndices lacks entry set by ParmVarDecl");
return I->second;
}
+
+APValue *
+ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E,
+ bool MayCreate) {
+ assert(E && E->getStorageDuration() == SD_Static &&
+ "don't need to cache the computed value for this temporary");
+ if (MayCreate)
+ return &MaterializedTemporaryValues[E];
+
+ llvm::DenseMap<const MaterializeTemporaryExpr *, APValue>::iterator I =
+ MaterializedTemporaryValues.find(E);
+ return I == MaterializedTemporaryValues.end() ? 0 : &I->second;
+}
+
+bool ASTContext::AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const {
+ const llvm::Triple &T = getTargetInfo().getTriple();
+ if (!T.isOSDarwin())
+ return false;
+
+ if (!(T.isiOS() && T.isOSVersionLT(7)) &&
+ !(T.isMacOSX() && T.isOSVersionLT(10, 9)))
+ return false;
+
+ QualType AtomicTy = E->getPtr()->getType()->getPointeeType();
+ CharUnits sizeChars = getTypeSizeInChars(AtomicTy);
+ uint64_t Size = sizeChars.getQuantity();
+ CharUnits alignChars = getTypeAlignInChars(AtomicTy);
+ unsigned Align = alignChars.getQuantity();
+ unsigned MaxInlineWidthInBits = getTargetInfo().getMaxAtomicInlineWidth();
+ return (Size != Align || toBits(sizeChars) > MaxInlineWidthInBits);
+}
+
+namespace {
+
+ /// \brief A \c RecursiveASTVisitor that builds a map from nodes to their
+ /// parents as defined by the \c RecursiveASTVisitor.
+ ///
+ /// Note that the relationship described here is purely in terms of AST
+ /// traversal - there are other relationships (for example declaration context)
+ /// in the AST that are better modeled by special matchers.
+ ///
+ /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
+ class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
+
+ public:
+ /// \brief Builds and returns the translation unit's parent map.
+ ///
+ /// The caller takes ownership of the returned \c ParentMap.
+ static ASTContext::ParentMap *buildMap(TranslationUnitDecl &TU) {
+ ParentMapASTVisitor Visitor(new ASTContext::ParentMap);
+ Visitor.TraverseDecl(&TU);
+ return Visitor.Parents;
+ }
+
+ private:
+ typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;
+
+ ParentMapASTVisitor(ASTContext::ParentMap *Parents) : Parents(Parents) {
+ }
+
+ bool shouldVisitTemplateInstantiations() const {
+ return true;
+ }
+ bool shouldVisitImplicitCode() const {
+ return true;
+ }
+ // Disables data recursion. We intercept Traverse* methods in the RAV, which
+ // are not triggered during data recursion.
+ bool shouldUseDataRecursionFor(clang::Stmt *S) const {
+ return false;
+ }
+
+ template <typename T>
+ bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {
+ if (Node == NULL)
+ return true;
+ if (ParentStack.size() > 0)
+ // FIXME: Currently we add the same parent multiple times, for example
+ // when we visit all subexpressions of template instantiations; this is
+ // suboptimal, bug benign: the only way to visit those is with
+ // hasAncestor / hasParent, and those do not create new matches.
+ // The plan is to enable DynTypedNode to be storable in a map or hash
+ // map. The main problem there is to implement hash functions /
+ // comparison operators for all types that DynTypedNode supports that
+ // do not have pointer identity.
+ (*Parents)[Node].push_back(ParentStack.back());
+ ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
+ bool Result = (this ->* traverse) (Node);
+ ParentStack.pop_back();
+ return Result;
+ }
+
+ bool TraverseDecl(Decl *DeclNode) {
+ return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);
+ }
+
+ bool TraverseStmt(Stmt *StmtNode) {
+ return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);
+ }
+
+ ASTContext::ParentMap *Parents;
+ llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
+
+ friend class RecursiveASTVisitor<ParentMapASTVisitor>;
+ };
+
+} // end namespace
+
+ASTContext::ParentVector
+ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
+ assert(Node.getMemoizationData() &&
+ "Invariant broken: only nodes that support memoization may be "
+ "used in the parent map.");
+ if (!AllParents) {
+ // We always need to run over the whole translation unit, as
+ // hasAncestor can escape any subtree.
+ AllParents.reset(
+ ParentMapASTVisitor::buildMap(*getTranslationUnitDecl()));
+ }
+ ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData());
+ if (I == AllParents->end()) {
+ return ParentVector();
+ }
+ return I->second;
+}
+
+bool
+ASTContext::ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
+ const ObjCMethodDecl *MethodImpl) {
+ // No point trying to match an unavailable/deprecated mothod.
+ if (MethodDecl->hasAttr<UnavailableAttr>()
+ || MethodDecl->hasAttr<DeprecatedAttr>())
+ return false;
+ if (MethodDecl->getObjCDeclQualifier() !=
+ MethodImpl->getObjCDeclQualifier())
+ return false;
+ if (!hasSameType(MethodDecl->getResultType(),
+ MethodImpl->getResultType()))
+ return false;
+
+ if (MethodDecl->param_size() != MethodImpl->param_size())
+ return false;
+
+ for (ObjCMethodDecl::param_const_iterator IM = MethodImpl->param_begin(),
+ IF = MethodDecl->param_begin(), EM = MethodImpl->param_end(),
+ EF = MethodDecl->param_end();
+ IM != EM && IF != EF; ++IM, ++IF) {
+ const ParmVarDecl *DeclVar = (*IF);
+ const ParmVarDecl *ImplVar = (*IM);
+ if (ImplVar->getObjCDeclQualifier() != DeclVar->getObjCDeclQualifier())
+ return false;
+ if (!hasSameType(DeclVar->getType(), ImplVar->getType()))
+ return false;
+ }
+ return (MethodDecl->isVariadic() == MethodImpl->isVariadic());
+
+}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 1ed65e4..fce8f64 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -300,8 +300,7 @@ void clang::FormatASTNodeDiagnosticArgument(
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for DeclarationName argument");
- DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
- N.printName(OS);
+ OS << DeclarationName::getFromOpaqueInteger(Val);
break;
}
case DiagnosticsEngine::ak_nameddecl: {
@@ -459,6 +458,10 @@ class TemplateDiff {
/// FromValueDecl, ToValueDecl - Whether the argument is a decl.
ValueDecl *FromValueDecl, *ToValueDecl;
+ /// FromAddressOf, ToAddressOf - Whether the ValueDecl needs an address of
+ /// operator before it.
+ bool FromAddressOf, ToAddressOf;
+
/// FromDefault, ToDefault - Whether the argument is a default argument.
bool FromDefault, ToDefault;
@@ -469,7 +472,8 @@ class TemplateDiff {
: Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode),
FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0),
IsValidFromInt(false), IsValidToInt(false), FromValueDecl(0),
- ToValueDecl(0), FromDefault(false), ToDefault(false), Same(false) { }
+ ToValueDecl(0), FromAddressOf(false), ToAddressOf(false),
+ FromDefault(false), ToDefault(false), Same(false) { }
};
/// FlatTree - A flattened tree used to store the DiffNodes.
@@ -526,9 +530,12 @@ class TemplateDiff {
}
/// SetNode - Set FromValueDecl and ToValueDecl of the current node.
- void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl) {
+ void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
+ bool FromAddressOf, bool ToAddressOf) {
FlatTree[CurrentNode].FromValueDecl = FromValueDecl;
FlatTree[CurrentNode].ToValueDecl = ToValueDecl;
+ FlatTree[CurrentNode].FromAddressOf = FromAddressOf;
+ FlatTree[CurrentNode].ToAddressOf = ToAddressOf;
}
/// SetSame - Sets the same flag of the current node.
@@ -620,9 +627,12 @@ class TemplateDiff {
}
/// GetNode - Gets the FromValueDecl and ToValueDecl.
- void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl) {
+ void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl,
+ bool &FromAddressOf, bool &ToAddressOf) {
FromValueDecl = FlatTree[ReadNode].FromValueDecl;
ToValueDecl = FlatTree[ReadNode].ToValueDecl;
+ FromAddressOf = FlatTree[ReadNode].FromAddressOf;
+ ToAddressOf = FlatTree[ReadNode].ToAddressOf;
}
/// NodeIsSame - Returns true the arguments are the same.
@@ -821,8 +831,10 @@ class TemplateDiff {
void DiffTemplate(const TemplateSpecializationType *FromTST,
const TemplateSpecializationType *ToTST) {
// Begin descent into diffing template tree.
- TemplateParameterList *Params =
+ TemplateParameterList *ParamsFrom =
FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();
+ TemplateParameterList *ParamsTo =
+ ToTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();
unsigned TotalArgs = 0;
for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST);
!FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) {
@@ -831,15 +843,18 @@ class TemplateDiff {
// Get the parameter at index TotalArgs. If index is larger
// than the total number of parameters, then there is an
// argument pack, so re-use the last parameter.
- NamedDecl *ParamND = Params->getParam(
- (TotalArgs < Params->size()) ? TotalArgs
- : Params->size() - 1);
+ unsigned ParamIndex = std::min(TotalArgs, ParamsFrom->size() - 1);
+ NamedDecl *ParamND = ParamsFrom->getParam(ParamIndex);
+
// Handle Types
if (TemplateTypeParmDecl *DefaultTTPD =
dyn_cast<TemplateTypeParmDecl>(ParamND)) {
QualType FromType, ToType;
FromType = GetType(FromIter, DefaultTTPD);
- ToType = GetType(ToIter, DefaultTTPD);
+ // A forward declaration can have no default arg but the actual class
+ // can, don't mix up iterators and get the original parameter.
+ ToType = GetType(
+ ToIter, cast<TemplateTypeParmDecl>(ParamsTo->getParam(ParamIndex)));
Tree.SetNode(FromType, ToType);
Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(),
ToIter.isEnd() && !ToType.isNull());
@@ -942,7 +957,14 @@ class TemplateDiff {
FromValueDecl = GetValueDecl(FromIter, FromExpr);
if (!HasToValueDecl && ToExpr)
ToValueDecl = GetValueDecl(ToIter, ToExpr);
- Tree.SetNode(FromValueDecl, ToValueDecl);
+ QualType ArgumentType = DefaultNTTPD->getType();
+ bool FromAddressOf = FromValueDecl &&
+ !ArgumentType->isReferenceType() &&
+ !FromValueDecl->getType()->isArrayType();
+ bool ToAddressOf = ToValueDecl &&
+ !ArgumentType->isReferenceType() &&
+ !ToValueDecl->getType()->isArrayType();
+ Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
Tree.SetSame(FromValueDecl && ToValueDecl &&
FromValueDecl->getCanonicalDecl() ==
ToValueDecl->getCanonicalDecl());
@@ -973,7 +995,7 @@ class TemplateDiff {
/// makeTemplateList - Dump every template alias into the vector.
static void makeTemplateList(
- SmallVector<const TemplateSpecializationType*, 1> &TemplateList,
+ SmallVectorImpl<const TemplateSpecializationType *> &TemplateList,
const TemplateSpecializationType *TST) {
while (TST) {
TemplateList.push_back(TST);
@@ -1008,7 +1030,7 @@ class TemplateDiff {
makeTemplateList(FromTemplateList, FromTST);
makeTemplateList(ToTemplateList, ToTST);
- SmallVector<const TemplateSpecializationType*, 1>::reverse_iterator
+ SmallVectorImpl<const TemplateSpecializationType *>::reverse_iterator
FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(),
ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend();
@@ -1037,10 +1059,14 @@ class TemplateDiff {
if (!Iter.isEnd())
return Iter->getAsType();
- if (!isVariadic)
- return DefaultTTPD->getDefaultArgument();
+ if (isVariadic)
+ return QualType();
+
+ QualType ArgType = DefaultTTPD->getDefaultArgument();
+ if (ArgType->isDependentType())
+ return Iter.getDesugar().getAsType();
- return QualType();
+ return ArgType;
}
/// GetExpr - Retrieves the template expression argument, including default
@@ -1080,7 +1106,7 @@ class TemplateDiff {
return ArgExpr->EvaluateKnownConstInt(Context);
}
- /// GetValueDecl - Retrieves the template integer argument, including
+ /// GetValueDecl - Retrieves the template Decl argument, including
/// default expression argument.
ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) {
// Default, value-depenedent expressions require fetching
@@ -1095,7 +1121,12 @@ class TemplateDiff {
default:
assert(0 && "Unexpected template argument kind");
}
- return cast<DeclRefExpr>(ArgExpr)->getDecl();
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr);
+ if (!DRE) {
+ DRE = cast<DeclRefExpr>(cast<UnaryOperator>(ArgExpr)->getSubExpr());
+ }
+
+ return DRE->getDecl();
}
/// GetTemplateDecl - Retrieves the template template arguments, including
@@ -1228,9 +1259,10 @@ class TemplateDiff {
}
case DiffTree::Declaration: {
ValueDecl *FromValueDecl, *ToValueDecl;
- Tree.GetNode(FromValueDecl, ToValueDecl);
- PrintValueDecl(FromValueDecl, ToValueDecl, Tree.FromDefault(),
- Tree.ToDefault(), Tree.NodeIsSame());
+ bool FromAddressOf, ToAddressOf;
+ Tree.GetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf);
+ PrintValueDecl(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf,
+ Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
return;
}
case DiffTree::Template: {
@@ -1478,7 +1510,8 @@ class TemplateDiff {
/// PrintDecl - Handles printing of Decl arguments, highlighting
/// argument differences.
void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
- bool FromDefault, bool ToDefault, bool Same) {
+ bool FromAddressOf, bool ToAddressOf, bool FromDefault,
+ bool ToDefault, bool Same) {
assert((FromValueDecl || ToValueDecl) &&
"Only one Decl argument may be NULL");
@@ -1487,15 +1520,21 @@ class TemplateDiff {
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
Bold();
+ if (FromAddressOf)
+ OS << "&";
OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
+ if (FromAddressOf)
+ OS << "&";
OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
+ if (ToAddressOf)
+ OS << "&";
OS << (ToValueDecl ? ToValueDecl->getName() : "(no argument)");
Unbold();
OS << ']';
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
index 340cc41..2f40255 100644
--- a/lib/AST/ASTDumper.cpp
+++ b/lib/AST/ASTDumper.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/CommentVisitor.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclLookups.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
@@ -62,6 +63,9 @@ namespace {
// Null statements
static const TerminalColor NullColor = { raw_ostream::BLUE, false };
+ // Undeserialized entities
+ static const TerminalColor UndeserializedColor = { raw_ostream::GREEN, true };
+
// CastKind from CastExpr's
static const TerminalColor CastColor = { raw_ostream::RED, false };
@@ -173,6 +177,7 @@ namespace {
void dumpName(const NamedDecl *D);
bool hasNodes(const DeclContext *DC);
void dumpDeclContext(const DeclContext *DC);
+ void dumpLookups(const DeclContext *DC);
void dumpAttr(const Attr *A);
// C++ Utilities
@@ -214,6 +219,11 @@ namespace {
const ClassTemplatePartialSpecializationDecl *D);
void VisitClassScopeFunctionSpecializationDecl(
const ClassScopeFunctionSpecializationDecl *D);
+ void VisitVarTemplateDecl(const VarTemplateDecl *D);
+ void VisitVarTemplateSpecializationDecl(
+ const VarTemplateSpecializationDecl *D);
+ void VisitVarTemplatePartialSpecializationDecl(
+ const VarTemplatePartialSpecializationDecl *D);
void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
@@ -244,6 +254,7 @@ namespace {
void VisitAttributedStmt(const AttributedStmt *Node);
void VisitLabelStmt(const LabelStmt *Node);
void VisitGotoStmt(const GotoStmt *Node);
+ void VisitCXXCatchStmt(const CXXCatchStmt *Node);
// Exprs
void VisitExpr(const Expr *Node);
@@ -271,9 +282,14 @@ namespace {
void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);
void VisitCXXConstructExpr(const CXXConstructExpr *Node);
void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);
+ void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node);
void VisitExprWithCleanups(const ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
void dumpCXXTemporary(const CXXTemporary *Temporary);
+ void VisitLambdaExpr(const LambdaExpr *Node) {
+ VisitExpr(Node);
+ dumpDecl(Node->getLambdaClass());
+ }
// ObjC
void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node);
@@ -329,8 +345,8 @@ void ASTDumper::indent() {
OS << "\n";
ColorScope Color(*this, IndentColor);
- for (llvm::SmallVector<IndentType, 32>::const_iterator I = Indents.begin(),
- E = Indents.end();
+ for (SmallVectorImpl<IndentType>::const_iterator I = Indents.begin(),
+ E = Indents.end();
I != E; ++I) {
switch (*I) {
case IT_Child:
@@ -449,9 +465,7 @@ void ASTDumper::dumpBareDeclRef(const Decl *D) {
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
ColorScope Color(*this, DeclNameColor);
- OS << " '";
- ND->getDeclName().printName(OS);
- OS << "'";
+ OS << " '" << ND->getDeclName() << '\'';
}
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
@@ -479,20 +493,76 @@ bool ASTDumper::hasNodes(const DeclContext *DC) {
if (!DC)
return false;
- return DC->decls_begin() != DC->decls_end();
+ return DC->hasExternalLexicalStorage() ||
+ DC->noload_decls_begin() != DC->noload_decls_end();
}
void ASTDumper::dumpDeclContext(const DeclContext *DC) {
if (!DC)
return;
- for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+ bool HasUndeserializedDecls = DC->hasExternalLexicalStorage();
+ for (DeclContext::decl_iterator I = DC->noload_decls_begin(),
+ E = DC->noload_decls_end();
I != E; ++I) {
DeclContext::decl_iterator Next = I;
++Next;
- if (Next == E)
+ if (Next == E && !HasUndeserializedDecls)
lastChild();
dumpDecl(*I);
}
+ if (HasUndeserializedDecls) {
+ lastChild();
+ IndentScope Indent(*this);
+ ColorScope Color(*this, UndeserializedColor);
+ OS << "<undeserialized declarations>";
+ }
+}
+
+void ASTDumper::dumpLookups(const DeclContext *DC) {
+ IndentScope Indent(*this);
+
+ OS << "StoredDeclsMap ";
+ dumpBareDeclRef(cast<Decl>(DC));
+
+ const DeclContext *Primary = DC->getPrimaryContext();
+ if (Primary != DC) {
+ OS << " primary";
+ dumpPointer(cast<Decl>(Primary));
+ }
+
+ bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage();
+
+ DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(),
+ E = Primary->noload_lookups_end();
+ while (I != E) {
+ DeclarationName Name = I.getLookupName();
+ DeclContextLookupResult R = *I++;
+ if (I == E && !HasUndeserializedLookups)
+ lastChild();
+
+ IndentScope Indent(*this);
+ OS << "DeclarationName ";
+ {
+ ColorScope Color(*this, DeclNameColor);
+ OS << '\'' << Name << '\'';
+ }
+
+ for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end();
+ RI != RE; ++RI) {
+ if (RI + 1 == RE)
+ lastChild();
+ dumpDeclRef(*RI);
+ if ((*RI)->isHidden())
+ OS << " hidden";
+ }
+ }
+
+ if (HasUndeserializedLookups) {
+ lastChild();
+ IndentScope Indent(*this);
+ ColorScope Color(*this, UndeserializedColor);
+ OS << "<undeserialized lookups>";
+ }
}
void ASTDumper::dumpAttr(const Attr *A) {
@@ -511,21 +581,29 @@ void ASTDumper::dumpAttr(const Attr *A) {
#include "clang/AST/AttrDump.inc"
}
-static Decl *getPreviousDeclImpl(...) {
- return 0;
+static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {}
+
+template<typename T>
+static void dumpPreviousDeclImpl(raw_ostream &OS, const Mergeable<T> *D) {
+ const T *First = D->getFirstDecl();
+ if (First != D)
+ OS << " first " << First;
}
template<typename T>
-static const Decl *getPreviousDeclImpl(const Redeclarable<T> *D) {
- return D->getPreviousDecl();
+static void dumpPreviousDeclImpl(raw_ostream &OS, const Redeclarable<T> *D) {
+ const T *Prev = D->getPreviousDecl();
+ if (Prev)
+ OS << " prev " << Prev;
}
-/// Get the previous declaration in the redeclaration chain for a declaration.
-static const Decl *getPreviousDecl(const Decl *D) {
+/// Dump the previous declaration in the redeclaration chain for a declaration,
+/// if any.
+static void dumpPreviousDecl(raw_ostream &OS, const Decl *D) {
switch (D->getKind()) {
#define DECL(DERIVED, BASE) \
case Decl::DERIVED: \
- return getPreviousDeclImpl(cast<DERIVED##Decl>(D));
+ return dumpPreviousDeclImpl(OS, cast<DERIVED##Decl>(D));
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
}
@@ -662,20 +740,25 @@ void ASTDumper::dumpDecl(const Decl *D) {
dumpPointer(D);
if (D->getLexicalDeclContext() != D->getDeclContext())
OS << " parent " << cast<Decl>(D->getDeclContext());
- if (const Decl *Prev = getPreviousDecl(D))
- OS << " prev " << Prev;
+ dumpPreviousDecl(OS, D);
dumpSourceRange(D->getSourceRange());
+ if (Module *M = D->getOwningModule())
+ OS << " in " << M->getFullModuleName();
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ if (ND->isHidden())
+ OS << " hidden";
bool HasAttrs = D->attr_begin() != D->attr_end();
- bool HasComment = D->getASTContext().getCommentForDecl(D, 0);
+ const FullComment *Comment =
+ D->getASTContext().getLocalCommentForDeclUncached(D);
// Decls within functions are visited by the body
bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) &&
hasNodes(dyn_cast<DeclContext>(D));
- setMoreChildren(HasAttrs || HasComment || HasDeclContext);
+ setMoreChildren(HasAttrs || Comment || HasDeclContext);
ConstDeclVisitor<ASTDumper>::Visit(D);
- setMoreChildren(HasComment || HasDeclContext);
+ setMoreChildren(Comment || HasDeclContext);
for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end();
I != E; ++I) {
if (I + 1 == E)
@@ -685,7 +768,10 @@ void ASTDumper::dumpDecl(const Decl *D) {
setMoreChildren(HasDeclContext);
lastChild();
- dumpFullComment(D->getASTContext().getCommentForDecl(D, 0));
+ dumpFullComment(Comment);
+
+ if (D->isInvalidDecl())
+ OS << " invalid";
setMoreChildren(false);
if (HasDeclContext)
@@ -722,6 +808,8 @@ void ASTDumper::VisitRecordDecl(const RecordDecl *D) {
dumpName(D);
if (D->isModulePrivate())
OS << " __module_private__";
+ if (D->isCompleteDefinition())
+ OS << " definition";
}
void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
@@ -764,6 +852,19 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
else if (D->isDeletedAsWritten())
OS << " delete";
+ if (const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>()) {
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ switch (EPI.ExceptionSpecType) {
+ default: break;
+ case EST_Unevaluated:
+ OS << " noexcept-unevaluated " << EPI.ExceptionSpecDecl;
+ break;
+ case EST_Uninstantiated:
+ OS << " noexcept-uninstantiated " << EPI.ExceptionSpecTemplate;
+ break;
+ }
+ }
+
bool OldMoreChildren = hasMoreChildren();
const FunctionTemplateSpecializationInfo *FTSI =
D->getTemplateSpecializationInfo();
@@ -1012,6 +1113,49 @@ void ASTDumper::VisitClassScopeFunctionSpecializationDecl(
dumpTemplateArgumentListInfo(D->templateArgs());
}
+void ASTDumper::VisitVarTemplateDecl(const VarTemplateDecl *D) {
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+
+ VarTemplateDecl::spec_iterator I = D->spec_begin();
+ VarTemplateDecl::spec_iterator E = D->spec_end();
+ if (I == E)
+ lastChild();
+ dumpDecl(D->getTemplatedDecl());
+ for (; I != E; ++I) {
+ VarTemplateDecl::spec_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
+ switch (I->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ if (D == D->getCanonicalDecl())
+ dumpDecl(*I);
+ else
+ dumpDeclRef(*I);
+ break;
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ dumpDeclRef(*I);
+ break;
+ }
+ }
+}
+
+void ASTDumper::VisitVarTemplateSpecializationDecl(
+ const VarTemplateSpecializationDecl *D) {
+ dumpTemplateArgumentList(D->getTemplateArgs());
+ VisitVarDecl(D);
+}
+
+void ASTDumper::VisitVarTemplatePartialSpecializationDecl(
+ const VarTemplatePartialSpecializationDecl *D) {
+ dumpTemplateParameters(D->getTemplateParameters());
+ VisitVarTemplateSpecializationDecl(D);
+}
+
void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
if (D->wasDeclaredWithTypename())
OS << " typename";
@@ -1097,6 +1241,8 @@ void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
dumpType(D->getType());
if (D->getSynthesize())
OS << " synthesize";
+ if (D->getBackingIvarReferencedInAccessor())
+ OS << " BackingIvarReferencedInAccessor";
switch (D->getAccessControl()) {
case ObjCIvarDecl::None:
@@ -1331,7 +1477,7 @@ void ASTDumper::dumpStmt(const Stmt *S) {
return;
}
- setMoreChildren(S->children());
+ setMoreChildren(!S->children().empty());
ConstStmtVisitor<ASTDumper>::Visit(S);
setMoreChildren(false);
for (Stmt::const_child_range CI = S->children(); CI; ++CI) {
@@ -1385,6 +1531,11 @@ void ASTDumper::VisitGotoStmt(const GotoStmt *Node) {
dumpPointer(Node->getLabel());
}
+void ASTDumper::VisitCXXCatchStmt(const CXXCatchStmt *Node) {
+ VisitStmt(Node);
+ dumpDecl(Node->getExceptionDecl());
+}
+
//===----------------------------------------------------------------------===//
// Expr dumping methods.
//===----------------------------------------------------------------------===//
@@ -1510,6 +1661,7 @@ void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
default: llvm_unreachable("unknown case");
case PredefinedExpr::Func: OS << " __func__"; break;
case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
+ case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break;
case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
}
@@ -1659,6 +1811,15 @@ void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) {
dumpCXXTemporary(Node->getTemporary());
}
+void
+ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) {
+ VisitExpr(Node);
+ if (const ValueDecl *VD = Node->getExtendingDecl()) {
+ OS << " extended by ";
+ dumpBareDeclRef(VD);
+ }
+}
+
void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {
VisitExpr(Node);
for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
@@ -1949,6 +2110,20 @@ void Decl::dumpColor() const {
&getASTContext().getSourceManager(), /*ShowColors*/true);
P.dumpDecl(this);
}
+
+void DeclContext::dumpLookups() const {
+ dumpLookups(llvm::errs());
+}
+
+void DeclContext::dumpLookups(raw_ostream &OS) const {
+ const DeclContext *DC = this;
+ while (!DC->isTranslationUnit())
+ DC = DC->getParent();
+ ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext();
+ ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager());
+ P.dumpLookups(this);
+}
+
//===----------------------------------------------------------------------===//
// Stmt method implementations
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 915eb6f..e16015b 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -106,6 +106,8 @@ namespace clang {
bool ImportDefinition(RecordDecl *From, RecordDecl *To,
ImportDefinitionKind Kind = IDK_Default);
+ bool ImportDefinition(VarDecl *From, VarDecl *To,
+ ImportDefinitionKind Kind = IDK_Default);
bool ImportDefinition(EnumDecl *From, EnumDecl *To,
ImportDefinitionKind Kind = IDK_Default);
bool ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To,
@@ -120,9 +122,12 @@ namespace clang {
SmallVectorImpl<TemplateArgument> &ToArgs);
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord,
bool Complain = true);
+ bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar,
+ bool Complain = true);
bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC);
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
+ bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To);
Decl *VisitDecl(Decl *D);
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
@@ -157,7 +162,9 @@ namespace clang {
Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
Decl *VisitClassTemplateSpecializationDecl(
ClassTemplateSpecializationDecl *D);
-
+ Decl *VisitVarTemplateDecl(VarTemplateDecl *D);
+ Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D);
+
// Importing statements
Stmt *VisitStmt(Stmt *S);
@@ -400,6 +407,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
+ case Type::Decayed:
+ if (!IsStructurallyEquivalent(Context,
+ cast<DecayedType>(T1)->getPointeeType(),
+ cast<DecayedType>(T2)->getPointeeType()))
+ return false;
+ break;
+
case Type::Pointer:
if (!IsStructurallyEquivalent(Context,
cast<PointerType>(T1)->getPointeeType(),
@@ -1695,7 +1709,8 @@ QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
return QualType();
}
- return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto());
+ return Importer.getToContext().getAutoType(ToDeduced, T->isDecltypeAuto(),
+ /*IsDependent*/false);
}
QualType ASTNodeImporter::VisitRecordType(const RecordType *T) {
@@ -1968,9 +1983,6 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
= FromData.HasDeclaredCopyConstructorWithConstParam;
ToData.HasDeclaredCopyAssignmentWithConstParam
= FromData.HasDeclaredCopyAssignmentWithConstParam;
- ToData.FailedImplicitMoveConstructor
- = FromData.FailedImplicitMoveConstructor;
- ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment;
ToData.IsLambda = FromData.IsLambda;
SmallVector<CXXBaseSpecifier *, 4> Bases;
@@ -2010,6 +2022,21 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
return false;
}
+bool ASTNodeImporter::ImportDefinition(VarDecl *From, VarDecl *To,
+ ImportDefinitionKind Kind) {
+ if (To->getDefinition())
+ return false;
+
+ // FIXME: Can we really import any initializer? Alternatively, we could force
+ // ourselves to import every declaration of a variable and then only use
+ // getInit() here.
+ To->setInit(Importer.Import(const_cast<Expr *>(From->getAnyInitializer())));
+
+ // FIXME: Other bits to merge?
+
+ return false;
+}
+
bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To,
ImportDefinitionKind Kind) {
if (To->getDefinition() || To->isBeingDefined()) {
@@ -2148,13 +2175,30 @@ bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs,
bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
RecordDecl *ToRecord, bool Complain) {
+ // Eliminate a potential failure point where we attempt to re-import
+ // something we're trying to import while completing ToRecord.
+ Decl *ToOrigin = Importer.GetOriginalDecl(ToRecord);
+ if (ToOrigin) {
+ RecordDecl *ToOriginRecord = dyn_cast<RecordDecl>(ToOrigin);
+ if (ToOriginRecord)
+ ToRecord = ToOriginRecord;
+ }
+
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
- Importer.getToContext(),
+ ToRecord->getASTContext(),
Importer.getNonEquivalentDecls(),
false, Complain);
return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord);
}
+bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar,
+ bool Complain) {
+ StructuralEquivalenceContext Ctx(
+ Importer.getFromContext(), Importer.getToContext(),
+ Importer.getNonEquivalentDecls(), false, Complain);
+ return Ctx.IsStructurallyEquivalent(FromVar, ToVar);
+}
+
bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
Importer.getToContext(),
@@ -2181,6 +2225,14 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
return Ctx.IsStructurallyEquivalent(From, To);
}
+bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From,
+ VarTemplateDecl *To) {
+ StructuralEquivalenceContext Ctx(Importer.getFromContext(),
+ Importer.getToContext(),
+ Importer.getNonEquivalentDecls());
+ return Ctx.IsStructurallyEquivalent(From, To);
+}
+
Decl *ASTNodeImporter::VisitDecl(Decl *D) {
Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
<< D->getDeclKindName();
@@ -2610,8 +2662,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
continue;
if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(FoundDecls[I])) {
- if (isExternalLinkage(FoundFunction->getLinkage()) &&
- isExternalLinkage(D->getLinkage())) {
+ if (FoundFunction->hasExternalFormalLinkage() &&
+ D->hasExternalFormalLinkage()) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundFunction->getType())) {
// FIXME: Actually try to merge the body and other attributes.
@@ -2664,10 +2716,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
FromEPI.NoexceptExpr) {
FunctionProtoType::ExtProtoInfo DefaultEPI;
FromTy = Importer.getFromContext().getFunctionType(
- FromFPT->getResultType(),
- ArrayRef<QualType>(FromFPT->arg_type_begin(),
- FromFPT->getNumArgs()),
- DefaultEPI);
+ FromFPT->getResultType(), FromFPT->getArgTypes(), DefaultEPI);
usedDifferentExceptionSpec = true;
}
}
@@ -2878,7 +2927,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundField->getType(),
- Name)) {
+ !Name.isEmpty())) {
Importer.Imported(D, FoundField);
return FoundField;
}
@@ -2965,7 +3014,8 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getAccessControl(),
- BitWidth, D->getSynthesize());
+ BitWidth, D->getSynthesize(),
+ D->getBackingIvarReferencedInAccessor());
ToIvar->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToIvar);
LexicalDC->addDeclInternal(ToIvar);
@@ -2995,8 +3045,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
if (VarDecl *FoundVar = dyn_cast<VarDecl>(FoundDecls[I])) {
// We have found a variable that we may need to merge with. Check it.
- if (isExternalLinkage(FoundVar->getLinkage()) &&
- isExternalLinkage(D->getLinkage())) {
+ if (FoundVar->hasExternalFormalLinkage() &&
+ D->hasExternalFormalLinkage()) {
if (Importer.IsStructurallyEquivalent(D->getType(),
FoundVar->getType())) {
MergeWithVar = FoundVar;
@@ -3088,13 +3138,9 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
LexicalDC->addDeclInternal(ToVar);
// Merge the initializer.
- // FIXME: Can we really import any initializer? Alternatively, we could force
- // ourselves to import every declaration of a variable and then only use
- // getInit() here.
- ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer())));
+ if (ImportDefinition(D, ToVar))
+ return 0;
- // FIXME: Other bits to merge?
-
return ToVar;
}
@@ -4108,6 +4154,205 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
return D2;
}
+Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
+ // If this variable has a definition in the translation unit we're coming
+ // from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ VarDecl *Definition =
+ cast_or_null<VarDecl>(D->getTemplatedDecl()->getDefinition());
+ if (Definition && Definition != D->getTemplatedDecl()) {
+ Decl *ImportedDef = Importer.Import(Definition->getDescribedVarTemplate());
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ // Import the major distinguishing characteristics of this variable template.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // We may already have a template of the same name; try to find and match it.
+ assert(!DC->isFunctionOrMethod() &&
+ "Variable templates cannot be declared at function scope");
+ SmallVector<NamedDecl *, 4> ConflictingDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
+ DC->localUncachedLookup(Name, FoundDecls);
+ for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
+ if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ continue;
+
+ Decl *Found = FoundDecls[I];
+ if (VarTemplateDecl *FoundTemplate = dyn_cast<VarTemplateDecl>(Found)) {
+ if (IsStructuralMatch(D, FoundTemplate)) {
+ // The variable templates structurally match; call it the same template.
+ Importer.Imported(D->getTemplatedDecl(),
+ FoundTemplate->getTemplatedDecl());
+ return Importer.Imported(D, FoundTemplate);
+ }
+ }
+
+ ConflictingDecls.push_back(FoundDecls[I]);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ }
+
+ if (!Name)
+ return 0;
+
+ VarDecl *DTemplated = D->getTemplatedDecl();
+
+ // Import the type.
+ QualType T = Importer.Import(DTemplated->getType());
+ if (T.isNull())
+ return 0;
+
+ // Create the declaration that is being templated.
+ SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart());
+ SourceLocation IdLoc = Importer.Import(DTemplated->getLocation());
+ TypeSourceInfo *TInfo = Importer.Import(DTemplated->getTypeSourceInfo());
+ VarDecl *D2Templated = VarDecl::Create(Importer.getToContext(), DC, StartLoc,
+ IdLoc, Name.getAsIdentifierInfo(), T,
+ TInfo, DTemplated->getStorageClass());
+ D2Templated->setAccess(DTemplated->getAccess());
+ D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc()));
+ D2Templated->setLexicalDeclContext(LexicalDC);
+
+ // Importer.Imported(DTemplated, D2Templated);
+ // LexicalDC->addDeclInternal(D2Templated);
+
+ // Merge the initializer.
+ if (ImportDefinition(DTemplated, D2Templated))
+ return 0;
+
+ // Create the variable template declaration itself.
+ TemplateParameterList *TemplateParams =
+ ImportTemplateParameterList(D->getTemplateParameters());
+ if (!TemplateParams)
+ return 0;
+
+ VarTemplateDecl *D2 = VarTemplateDecl::Create(
+ Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated,
+ /*PrevDecl=*/0);
+ D2Templated->setDescribedVarTemplate(D2);
+
+ D2->setAccess(D->getAccess());
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(D2);
+
+ // Note the relationship between the variable templates.
+ Importer.Imported(D, D2);
+ Importer.Imported(DTemplated, D2Templated);
+
+ if (DTemplated->isThisDeclarationADefinition() &&
+ !D2Templated->isThisDeclarationADefinition()) {
+ // FIXME: Import definition!
+ }
+
+ return D2;
+}
+
+Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl(
+ VarTemplateSpecializationDecl *D) {
+ // If this record has a definition in the translation unit we're coming from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ VarDecl *Definition = D->getDefinition();
+ if (Definition && Definition != D) {
+ Decl *ImportedDef = Importer.Import(Definition);
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ VarTemplateDecl *VarTemplate = cast_or_null<VarTemplateDecl>(
+ Importer.Import(D->getSpecializedTemplate()));
+ if (!VarTemplate)
+ return 0;
+
+ // Import the context of this declaration.
+ DeclContext *DC = VarTemplate->getDeclContext();
+ if (!DC)
+ return 0;
+
+ DeclContext *LexicalDC = DC;
+ if (D->getDeclContext() != D->getLexicalDeclContext()) {
+ LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
+ if (!LexicalDC)
+ return 0;
+ }
+
+ // Import the location of this declaration.
+ SourceLocation StartLoc = Importer.Import(D->getLocStart());
+ SourceLocation IdLoc = Importer.Import(D->getLocation());
+
+ // Import template arguments.
+ SmallVector<TemplateArgument, 2> TemplateArgs;
+ if (ImportTemplateArguments(D->getTemplateArgs().data(),
+ D->getTemplateArgs().size(), TemplateArgs))
+ return 0;
+
+ // Try to find an existing specialization with these template arguments.
+ void *InsertPos = 0;
+ VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization(
+ TemplateArgs.data(), TemplateArgs.size(), InsertPos);
+ if (D2) {
+ // We already have a variable template specialization with these template
+ // arguments.
+
+ // FIXME: Check for specialization vs. instantiation errors.
+
+ if (VarDecl *FoundDef = D2->getDefinition()) {
+ if (!D->isThisDeclarationADefinition() ||
+ IsStructuralMatch(D, FoundDef)) {
+ // The record types structurally match, or the "from" translation
+ // unit only had a forward declaration anyway; call it the same
+ // variable.
+ return Importer.Imported(D, FoundDef);
+ }
+ }
+ } else {
+
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+
+ // Create a new specialization.
+ D2 = VarTemplateSpecializationDecl::Create(
+ Importer.getToContext(), DC, StartLoc, IdLoc, VarTemplate, T, TInfo,
+ D->getStorageClass(), TemplateArgs.data(), TemplateArgs.size());
+ D2->setSpecializationKind(D->getSpecializationKind());
+ D2->setTemplateArgsInfo(D->getTemplateArgsInfo());
+
+ // Add this specialization to the class template.
+ VarTemplate->AddSpecialization(D2, InsertPos);
+
+ // Import the qualifier, if any.
+ D2->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
+
+ // Add the specialization to this context.
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDeclInternal(D2);
+ }
+ Importer.Imported(D, D2);
+
+ if (D->isThisDeclarationADefinition() && ImportDefinition(D, D2))
+ return 0;
+
+ return D2;
+}
+
//----------------------------------------------------------------------------
// Import Statements
//----------------------------------------------------------------------------
@@ -4406,7 +4651,7 @@ Decl *ASTImporter::Import(Decl *FromD) {
} else if (TypedefNameDecl *FromTypedef = dyn_cast<TypedefNameDecl>(FromD)) {
// When we've finished transforming a typedef, see whether it was the
// typedef for an anonymous tag.
- for (SmallVector<TagDecl *, 4>::iterator
+ for (SmallVectorImpl<TagDecl *>::iterator
FromTag = AnonTagsWithPendingTypedefs.begin(),
FromTagEnd = AnonTagsWithPendingTypedefs.end();
FromTag != FromTagEnd; ++FromTag) {
diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp
new file mode 100644
index 0000000..ae47ea9
--- /dev/null
+++ b/lib/AST/ASTTypeTraits.cpp
@@ -0,0 +1,105 @@
+//===--- ASTTypeTraits.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Provides a dynamic type identifier and a dynamically typed node container
+// that can be used to store an AST base node at runtime in the same storage in
+// a type safe way.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+
+namespace clang {
+namespace ast_type_traits {
+
+const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
+ { NKI_None, "<None>" },
+ { NKI_None, "CXXCtorInitializer" },
+ { NKI_None, "TemplateArgument" },
+ { NKI_None, "NestedNameSpecifier" },
+ { NKI_None, "NestedNameSpecifierLoc" },
+ { NKI_None, "QualType" },
+ { NKI_None, "TypeLoc" },
+ { NKI_None, "Decl" },
+#define DECL(DERIVED, BASE) { NKI_##BASE, #DERIVED "Decl" },
+#include "clang/AST/DeclNodes.inc"
+ { NKI_None, "Stmt" },
+#define STMT(DERIVED, BASE) { NKI_##BASE, #DERIVED },
+#include "clang/AST/StmtNodes.inc"
+ { NKI_None, "Type" },
+#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" },
+#include "clang/AST/TypeNodes.def"
+};
+
+bool ASTNodeKind::isBaseOf(ASTNodeKind Other) const {
+ return isBaseOf(KindId, Other.KindId);
+}
+
+bool ASTNodeKind::isSame(ASTNodeKind Other) const {
+ return KindId != NKI_None && KindId == Other.KindId;
+}
+
+bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived) {
+ if (Base == NKI_None || Derived == NKI_None) return false;
+ while (Derived != Base && Derived != NKI_None)
+ Derived = AllKindInfo[Derived].ParentId;
+ return Derived == Base;
+}
+
+StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; }
+
+void DynTypedNode::print(llvm::raw_ostream &OS,
+ const PrintingPolicy &PP) const {
+ if (const TemplateArgument *TA = get<TemplateArgument>())
+ TA->print(PP, OS);
+ else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>())
+ NNS->print(OS, PP);
+ else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
+ NNSL->getNestedNameSpecifier()->print(OS, PP);
+ else if (const QualType *QT = get<QualType>())
+ QT->print(OS, PP);
+ else if (const TypeLoc *TL = get<TypeLoc>())
+ TL->getType().print(OS, PP);
+ else if (const Decl *D = get<Decl>())
+ D->print(OS, PP);
+ else if (const Stmt *S = get<Stmt>())
+ S->printPretty(OS, 0, PP);
+ else if (const Type *T = get<Type>())
+ QualType(T, 0).print(OS, PP);
+ else
+ OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n";
+}
+
+void DynTypedNode::dump(llvm::raw_ostream &OS, SourceManager &SM) const {
+ if (const Decl *D = get<Decl>())
+ D->dump(OS);
+ else if (const Stmt *S = get<Stmt>())
+ S->dump(OS, SM);
+ else
+ OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n";
+}
+
+SourceRange DynTypedNode::getSourceRange() const {
+ if (const CXXCtorInitializer *CCI = get<CXXCtorInitializer>())
+ return CCI->getSourceRange();
+ if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
+ return NNSL->getSourceRange();
+ if (const TypeLoc *TL = get<TypeLoc>())
+ return TL->getSourceRange();
+ if (const Decl *D = get<Decl>())
+ return D->getSourceRange();
+ if (const Stmt *S = get<Stmt>())
+ return S->getSourceRange();
+ return SourceRange();
+}
+
+} // end namespace ast_type_traits
+} // end namespace clang
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index daf65e5..7af3c8b 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
+#include "llvm/ADT/StringSwitch.h"
using namespace clang;
Attr::~Attr() { }
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index e804fe7..461e8b3 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -7,6 +7,7 @@ add_clang_library(clangAST
ASTDiagnostic.cpp
ASTDumper.cpp
ASTImporter.cpp
+ ASTTypeTraits.cpp
AttrImpl.cpp
CXXInheritance.cpp
Comment.cpp
@@ -25,7 +26,6 @@ add_clang_library(clangAST
DeclOpenMP.cpp
DeclPrinter.cpp
DeclTemplate.cpp
- DumpXML.cpp
Expr.cpp
ExprClassification.cpp
ExprConstant.cpp
@@ -34,8 +34,8 @@ add_clang_library(clangAST
InheritViz.cpp
ItaniumCXXABI.cpp
ItaniumMangle.cpp
- LambdaMangleContext.cpp
Mangle.cpp
+ MangleNumberingContext.cpp
MicrosoftCXXABI.cpp
MicrosoftMangle.cpp
NestedNameSpecifier.cpp
diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h
index 6d67d9a..89203f1 100644
--- a/lib/AST/CXXABI.h
+++ b/lib/AST/CXXABI.h
@@ -21,6 +21,7 @@ namespace clang {
class ASTContext;
class MemberPointerType;
+class MangleNumberingContext;
/// Implements C++ ABI-specific semantic analysis functions.
class CXXABI {
@@ -34,9 +35,12 @@ public:
/// Returns the default calling convention for C++ methods.
virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0;
- // Returns whether the given class is nearly empty, with just virtual pointers
- // and no data except possibly virtual bases.
+ /// Returns whether the given class is nearly empty, with just virtual
+ /// pointers and no data except possibly virtual bases.
virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0;
+
+ /// Returns a new mangling number context for this C++ ABI.
+ virtual MangleNumberingContext *createMangleNumberingContext() const = 0;
};
/// Creates an instance of a C++ ABI class.
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 0e0b35d..b51014b 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -168,9 +168,9 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
}
}
- if (Queue.empty()) break;
- Record = Queue.back(); // not actually a queue.
- Queue.pop_back();
+ if (Queue.empty())
+ break;
+ Record = Queue.pop_back_val(); // not actually a queue.
}
return AllMatches;
@@ -447,7 +447,7 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
void OverridingMethods::add(unsigned OverriddenSubobject,
UniqueVirtualMethod Overriding) {
- SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides
+ SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides
= Overrides[OverriddenSubobject];
if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(),
Overriding) == SubobjectOverrides.end())
@@ -650,11 +650,11 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
SOEnd = OM->second.end();
SO != SOEnd;
++SO) {
- SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second;
+ SmallVectorImpl<UniqueVirtualMethod> &Overriding = SO->second;
if (Overriding.size() < 2)
continue;
- for (SmallVector<UniqueVirtualMethod, 4>::iterator
+ for (SmallVectorImpl<UniqueVirtualMethod>::iterator
Pos = Overriding.begin(), PosEnd = Overriding.end();
Pos != PosEnd;
/* increment in loop */) {
@@ -669,7 +669,7 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
// in a base class subobject that hides the virtual base class
// subobject.
bool Hidden = false;
- for (SmallVector<UniqueVirtualMethod, 4>::iterator
+ for (SmallVectorImpl<UniqueVirtualMethod>::iterator
OP = Overriding.begin(), OPEnd = Overriding.end();
OP != OPEnd && !Hidden;
++OP) {
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 68c73fd..f24a23d 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -12,6 +12,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@@ -41,14 +42,16 @@ good implements_child_begin_end(Comment::child_iterator (T::*)() const) {
return good();
}
+LLVM_ATTRIBUTE_UNUSED
static inline bad implements_child_begin_end(
Comment::child_iterator (Comment::*)() const) {
return bad();
}
#define ASSERT_IMPLEMENTS_child_begin(function) \
- (void) sizeof(good(implements_child_begin_end(function)))
+ (void) good(implements_child_begin_end(function))
+LLVM_ATTRIBUTE_UNUSED
static inline void CheckCommentASTNodes() {
#define ABSTRACT_COMMENT(COMMENT)
#define COMMENT(CLASS, PARENT) \
@@ -94,9 +97,7 @@ Comment::child_iterator Comment::child_end() const {
bool TextComment::isWhitespaceNoCache() const {
for (StringRef::const_iterator I = Text.begin(), E = Text.end();
I != E; ++I) {
- const char C = *I;
- if (C != ' ' && C != '\n' && C != '\r' &&
- C != '\t' && C != '\f' && C != '\v')
+ if (!clang::isWhitespace(*I))
return false;
}
return true;
@@ -293,12 +294,14 @@ void DeclInfo::fill() {
StringRef ParamCommandComment::getParamName(const FullComment *FC) const {
assert(isParamIndexValid());
- return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName();
+ if (isVarArgParam())
+ return "...";
+ return FC->getDeclInfo()->ParamVars[getParamIndex()]->getName();
}
StringRef TParamCommandComment::getParamName(const FullComment *FC) const {
assert(isPositionValid());
- const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters;
+ const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters;
for (unsigned i = 0, e = getDepth(); i != e; ++i) {
if (i == e-1)
return TPL->getParam(getIndex(i))->getName();
diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp
index e24d542..01bd12e 100644
--- a/lib/AST/CommentCommandTraits.cpp
+++ b/lib/AST/CommentCommandTraits.cpp
@@ -43,6 +43,49 @@ const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
return getRegisteredCommandInfo(CommandID);
}
+static void
+HelperTypoCorrectCommandInfo(SmallVectorImpl<const CommandInfo *> &BestCommand,
+ StringRef Typo, const CommandInfo *Command) {
+ const unsigned MaxEditDistance = 1;
+ unsigned BestEditDistance = MaxEditDistance + 1;
+ StringRef Name = Command->Name;
+
+ unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
+ if (MinPossibleEditDistance > 0 &&
+ Typo.size() / MinPossibleEditDistance < 1)
+ return;
+ unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
+ if (EditDistance > MaxEditDistance)
+ return;
+ if (EditDistance == BestEditDistance)
+ BestCommand.push_back(Command);
+ else if (EditDistance < BestEditDistance) {
+ BestCommand.clear();
+ BestCommand.push_back(Command);
+ BestEditDistance = EditDistance;
+ }
+}
+
+const CommandInfo *
+CommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const {
+ // single character command impostures, such as \t or \n must not go
+ // through the fixit logic.
+ if (Typo.size() <= 1)
+ return NULL;
+
+ SmallVector<const CommandInfo *, 2> BestCommand;
+
+ const int NumOfCommands = llvm::array_lengthof(Commands);
+ for (int i = 0; i < NumOfCommands; i++)
+ HelperTypoCorrectCommandInfo(BestCommand, Typo, &Commands[i]);
+
+ for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i)
+ if (!RegisteredCommands[i]->IsUnknownCommand)
+ HelperTypoCorrectCommandInfo(BestCommand, Typo, RegisteredCommands[i]);
+
+ return (BestCommand.size() != 1) ? NULL : BestCommand[0];
+}
+
CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
memcpy(Name, CommandName.data(), CommandName.size());
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index 70410d6..01ed3ce 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -157,7 +157,7 @@ const char *skipDecimalCharacterReference(const char *BufferPtr,
}
const char *skipHexCharacterReference(const char *BufferPtr,
- const char *BufferEnd) {
+ const char *BufferEnd) {
for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
if (!isHTMLHexCharacterReferenceCharacter(*BufferPtr))
return BufferPtr;
@@ -265,6 +265,7 @@ const char *findCCommentEnd(const char *BufferPtr, const char *BufferEnd) {
}
llvm_unreachable("buffer end hit before '*/' was seen");
}
+
} // unnamed namespace
void Lexer::lexCommentText(Token &T) {
@@ -352,10 +353,20 @@ void Lexer::lexCommentText(Token &T) {
const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName);
if (!Info) {
- formTokenWithChars(T, TokenPtr, tok::unknown_command);
- T.setUnknownCommandName(CommandName);
- Diag(T.getLocation(), diag::warn_unknown_comment_command_name);
- return;
+ if ((Info = Traits.getTypoCorrectCommandInfo(CommandName))) {
+ StringRef CorrectedName = Info->Name;
+ SourceLocation Loc = getSourceLocation(BufferPtr);
+ SourceRange CommandRange(Loc.getLocWithOffset(1),
+ getSourceLocation(TokenPtr));
+ Diag(Loc, diag::warn_correct_comment_command_name)
+ << CommandName << CorrectedName
+ << FixItHint::CreateReplacement(CommandRange, CorrectedName);
+ } else {
+ formTokenWithChars(T, TokenPtr, tok::unknown_command);
+ T.setUnknownCommandName(CommandName);
+ Diag(T.getLocation(), diag::warn_unknown_comment_command_name);
+ return;
+ }
}
if (Info->IsVerbatimBlockCommand) {
setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info);
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index d89c79b..03e0101 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -16,6 +16,15 @@
#include "llvm/Support/ErrorHandling.h"
namespace clang {
+
+static inline bool isWhitespace(llvm::StringRef S) {
+ for (StringRef::const_iterator I = S.begin(), E = S.end(); I != E; ++I) {
+ if (!isWhitespace(*I))
+ return false;
+ }
+ return true;
+}
+
namespace comments {
/// Re-lexes a sequence of tok::text tokens.
@@ -594,6 +603,18 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
consumeToken();
break; // Two newlines -- end of paragraph.
}
+ // Also allow [tok::newline, tok::text, tok::newline] if the middle
+ // tok::text is just whitespace.
+ if (Tok.is(tok::text) && isWhitespace(Tok.getText())) {
+ Token WhitespaceTok = Tok;
+ consumeToken();
+ if (Tok.is(tok::newline) || Tok.is(tok::eof)) {
+ consumeToken();
+ break;
+ }
+ // We have [tok::newline, tok::text, non-newline]. Put back tok::text.
+ putBack(WhitespaceTok);
+ }
if (Content.size() > 0)
Content.back()->addTrailingNewline();
continue;
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index e0138d5..1c6222f 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -29,8 +29,7 @@ Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
DiagnosticsEngine &Diags, CommandTraits &Traits,
const Preprocessor *PP) :
Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
- PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL),
- HeaderfileCommand(NULL) {
+ PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), HeaderfileCommand(NULL) {
}
void Sema::setDecl(const Decl *D) {
@@ -99,10 +98,10 @@ void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
unsigned DiagSelect;
switch (Comment->getCommandID()) {
case CommandTraits::KCI_function:
- DiagSelect = !isAnyFunctionDecl() ? 1 : 0;
+ DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0;
break;
case CommandTraits::KCI_functiongroup:
- DiagSelect = !isAnyFunctionDecl() ? 2 : 0;
+ DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0;
break;
case CommandTraits::KCI_method:
DiagSelect = !isObjCMethodDecl() ? 3 : 0;
@@ -131,7 +130,12 @@ void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
unsigned DiagSelect;
switch (Comment->getCommandID()) {
case CommandTraits::KCI_class:
- DiagSelect = !isClassOrStructDecl() ? 1 : 0;
+ DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0;
+ // Allow @class command on @interface declarations.
+ // FIXME. Currently, \class and @class are indistinguishable. So,
+ // \class is also allowed on an @interface declaration
+ if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl())
+ DiagSelect = 0;
break;
case CommandTraits::KCI_interface:
DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
@@ -206,59 +210,43 @@ void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
<< Comment->getSourceRange();
}
+/// \brief Turn a string into the corresponding PassDirection or -1 if it's not
+/// valid.
+static int getParamPassDirection(StringRef Arg) {
+ return llvm::StringSwitch<int>(Arg)
+ .Case("[in]", ParamCommandComment::In)
+ .Case("[out]", ParamCommandComment::Out)
+ .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut)
+ .Default(-1);
+}
+
void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
StringRef Arg) {
- ParamCommandComment::PassDirection Direction;
std::string ArgLower = Arg.lower();
- // TODO: optimize: lower Name first (need an API in SmallString for that),
- // after that StringSwitch.
- if (ArgLower == "[in]")
- Direction = ParamCommandComment::In;
- else if (ArgLower == "[out]")
- Direction = ParamCommandComment::Out;
- else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
- Direction = ParamCommandComment::InOut;
- else {
- // Remove spaces.
- std::string::iterator O = ArgLower.begin();
- for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
- I != E; ++I) {
- const char C = *I;
- if (C != ' ' && C != '\n' && C != '\r' &&
- C != '\t' && C != '\v' && C != '\f')
- *O++ = C;
- }
- ArgLower.resize(O - ArgLower.begin());
-
- bool RemovingWhitespaceHelped = false;
- if (ArgLower == "[in]") {
- Direction = ParamCommandComment::In;
- RemovingWhitespaceHelped = true;
- } else if (ArgLower == "[out]") {
- Direction = ParamCommandComment::Out;
- RemovingWhitespaceHelped = true;
- } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
- Direction = ParamCommandComment::InOut;
- RemovingWhitespaceHelped = true;
- } else {
- Direction = ParamCommandComment::In;
- RemovingWhitespaceHelped = false;
- }
+ int Direction = getParamPassDirection(ArgLower);
+
+ if (Direction == -1) {
+ // Try again with whitespace removed.
+ ArgLower.erase(
+ std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace),
+ ArgLower.end());
+ Direction = getParamPassDirection(ArgLower);
SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
- if (RemovingWhitespaceHelped)
+ if (Direction != -1) {
+ const char *FixedName = ParamCommandComment::getDirectionAsString(
+ (ParamCommandComment::PassDirection)Direction);
Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
- << ArgRange
- << FixItHint::CreateReplacement(
- ArgRange,
- ParamCommandComment::getDirectionAsString(Direction));
- else
- Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction)
- << ArgRange;
+ << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName);
+ } else {
+ Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
+ Direction = ParamCommandComment::In; // Sane fall back.
+ }
}
- Command->setDirection(Direction, /* Explicit = */ true);
+ Command->setDirection((ParamCommandComment::PassDirection)Direction,
+ /*Explicit=*/true);
}
void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
@@ -326,17 +314,15 @@ void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
SmallVector<unsigned, 2> Position;
if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
- llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
- TemplateParameterDocs.find(Arg);
- if (PrevCommandIt != TemplateParameterDocs.end()) {
+ TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
+ if (PrevCommand) {
SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
<< Arg << ArgRange;
- TParamCommandComment *PrevCommand = PrevCommandIt->second;
Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
<< PrevCommand->getParamNameRange();
}
- TemplateParameterDocs[Arg] = Command;
+ PrevCommand = Command;
return;
}
@@ -511,8 +497,7 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
}
while (!HTMLOpenTags.empty()) {
- const HTMLStartTagComment *HST = HTMLOpenTags.back();
- HTMLOpenTags.pop_back();
+ const HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
StringRef LastNotClosedTagName = HST->getTagName();
if (LastNotClosedTagName == TagName)
break;
@@ -618,12 +603,6 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
return;
}
PrevCommand = BriefCommand;
- } else if (Info->IsReturnsCommand) {
- if (!ReturnsCommand) {
- ReturnsCommand = Command;
- return;
- }
- PrevCommand = ReturnsCommand;
} else if (Info->IsHeaderfileCommand) {
if (!HeaderfileCommand) {
HeaderfileCommand = Command;
@@ -728,6 +707,10 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) {
// Check that referenced parameter name is in the function decl.
const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
ParamVars);
+ if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
+ PCC->setIsVarArgParam();
+ continue;
+ }
if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
UnresolvedParamCommands.push_back(PCC);
continue;
@@ -798,14 +781,24 @@ bool Sema::isAnyFunctionDecl() {
return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
}
-
+
+bool Sema::isFunctionOrMethodVariadic() {
+ if (!isAnyFunctionDecl() && !isObjCMethodDecl())
+ return false;
+ if (const FunctionDecl *FD =
+ dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl))
+ return FD->isVariadic();
+ if (const ObjCMethodDecl *MD =
+ dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl))
+ return MD->isVariadic();
+ return false;
+}
+
bool Sema::isObjCMethodDecl() {
return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
}
-
-/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to
-/// function decl.
+
bool Sema::isFunctionPointerVarDecl() {
if (!ThisDeclInfo)
return false;
@@ -865,6 +858,24 @@ bool Sema::isClassOrStructDecl() {
isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
!isUnionDecl();
}
+
+bool Sema::isClassTemplateDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
+}
+
+bool Sema::isFunctionTemplateDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
+}
bool Sema::isObjCInterfaceDecl() {
if (!ThisDeclInfo)
@@ -901,6 +912,8 @@ unsigned Sema::resolveParmVarReference(StringRef Name,
if (II && II->getName() == Name)
return i;
}
+ if (Name == "..." && isFunctionOrMethodVariadic())
+ return ParamCommandComment::VarArgParamIndex;
return ParamCommandComment::InvalidParamIndex;
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index ab9d73b..6bd9858 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -34,6 +34,10 @@
using namespace clang;
+Decl *clang::getPrimaryMergedDecl(Decl *D) {
+ return D->getASTContext().getPrimaryMergedDecl(D);
+}
+
//===----------------------------------------------------------------------===//
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
@@ -85,6 +89,7 @@ using namespace clang;
// and settings from the immediate context.
const unsigned IgnoreExplicitVisibilityBit = 2;
+const unsigned IgnoreAllVisibilityBit = 4;
/// Kinds of LV computation. The linkage side of the computation is
/// always the same, but different things can change how visibility is
@@ -108,7 +113,11 @@ enum LVComputationKind {
/// Do an LV computation for, ultimately, a non-type declaration
/// that already has some sort of explicit visibility. Visibility
/// may only be restricted by the visibility of template arguments.
- LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit)
+ LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit),
+
+ /// Do an LV computation when we only care about the linkage.
+ LVForLinkageOnly =
+ LVForValue | IgnoreExplicitVisibilityBit | IgnoreAllVisibilityBit
};
/// Does this computation kind permit us to consider additional
@@ -211,11 +220,19 @@ static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
return None;
}
+static LinkageInfo
+getLVForType(const Type &T, LVComputationKind computation) {
+ if (computation == LVForLinkageOnly)
+ return LinkageInfo(T.getLinkage(), DefaultVisibility, true);
+ return T.getLinkageAndVisibility();
+}
+
/// \brief Get the most restrictive linkage for the types in the given
/// template parameter list. For visibility purposes, template
/// parameters are part of the signature of a template.
static LinkageInfo
-getLVForTemplateParameterList(const TemplateParameterList *params) {
+getLVForTemplateParameterList(const TemplateParameterList *params,
+ LVComputationKind computation) {
LinkageInfo LV;
for (TemplateParameterList::const_iterator P = params->begin(),
PEnd = params->end();
@@ -234,7 +251,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
// Handle the non-pack case first.
if (!NTTP->isExpandedParameterPack()) {
if (!NTTP->getType()->isDependentType()) {
- LV.merge(NTTP->getType()->getLinkageAndVisibility());
+ LV.merge(getLVForType(*NTTP->getType(), computation));
}
continue;
}
@@ -254,7 +271,8 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
// Handle the non-pack case first.
if (!TTP->isExpandedParameterPack()) {
- LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters()));
+ LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters(),
+ computation));
continue;
}
@@ -262,7 +280,7 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters();
i != n; ++i) {
LV.merge(getLVForTemplateParameterList(
- TTP->getExpansionTemplateParameters(i)));
+ TTP->getExpansionTemplateParameters(i), computation));
}
}
@@ -273,13 +291,25 @@ getLVForTemplateParameterList(const TemplateParameterList *params) {
static LinkageInfo getLVForDecl(const NamedDecl *D,
LVComputationKind computation);
+static const Decl *getOutermostFuncOrBlockContext(const Decl *D) {
+ const Decl *Ret = NULL;
+ const DeclContext *DC = D->getDeclContext();
+ while (DC->getDeclKind() != Decl::TranslationUnit) {
+ if (isa<FunctionDecl>(DC) || isa<BlockDecl>(DC))
+ Ret = cast<Decl>(DC);
+ DC = DC->getParent();
+ }
+ return Ret;
+}
+
/// \brief Get the most restrictive linkage for the types and
/// declarations in the given template argument list.
///
/// Note that we don't take an LVComputationKind because we always
/// want to honor the visibility of template arguments in the same way.
static LinkageInfo
-getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
+getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args,
+ LVComputationKind computation) {
LinkageInfo LV;
for (unsigned i = 0, e = args.size(); i != e; ++i) {
@@ -291,13 +321,13 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
continue;
case TemplateArgument::Type:
- LV.merge(arg.getAsType()->getLinkageAndVisibility());
+ LV.merge(getLVForType(*arg.getAsType(), computation));
continue;
case TemplateArgument::Declaration:
if (NamedDecl *ND = dyn_cast<NamedDecl>(arg.getAsDecl())) {
assert(!usesTypeVisibility(ND));
- LV.merge(getLVForDecl(ND, LVForValue));
+ LV.merge(getLVForDecl(ND, computation));
}
continue;
@@ -309,11 +339,11 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
case TemplateArgument::TemplateExpansion:
if (TemplateDecl *Template
= arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
- LV.merge(getLVForDecl(Template, LVForValue));
+ LV.merge(getLVForDecl(Template, computation));
continue;
case TemplateArgument::Pack:
- LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray()));
+ LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray(), computation));
continue;
}
llvm_unreachable("bad template argument kind");
@@ -323,8 +353,9 @@ getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
}
static LinkageInfo
-getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) {
- return getLVForTemplateArgumentList(TArgs.asArray());
+getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
+ LVComputationKind computation) {
+ return getLVForTemplateArgumentList(TArgs.asArray(), computation);
}
static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
@@ -348,19 +379,20 @@ static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
/// \param[out] LV the computation to use for the parent
static void
mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
- const FunctionTemplateSpecializationInfo *specInfo) {
+ const FunctionTemplateSpecializationInfo *specInfo,
+ LVComputationKind computation) {
bool considerVisibility =
shouldConsiderTemplateVisibility(fn, specInfo);
// Merge information from the template parameters.
FunctionTemplateDecl *temp = specInfo->getTemplate();
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
// Merge information from the template arguments.
const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
- LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs);
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation);
LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
}
@@ -379,6 +411,8 @@ static bool hasDirectVisibilityAttribute(const NamedDecl *D,
if (D->hasAttr<VisibilityAttr>())
return true;
return false;
+ case LVForLinkageOnly:
+ return false;
}
llvm_unreachable("bad visibility computation kind");
}
@@ -431,7 +465,7 @@ static void mergeTemplateLV(LinkageInfo &LV,
ClassTemplateDecl *temp = spec->getSpecializedTemplate();
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV,
considerVisibility && !hasExplicitVisibilityAlready(computation));
@@ -439,8 +473,10 @@ static void mergeTemplateLV(LinkageInfo &LV,
// template-argument visibility if we've got an explicit
// instantiation with a visibility attribute.
const TemplateArgumentList &templateArgs = spec->getTemplateArgs();
- LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs);
- LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs, computation);
+ if (considerVisibility)
+ LV.mergeVisibility(argsLV);
+ LV.mergeExternalVisibility(argsLV);
}
static bool useInlineVisibilityHidden(const NamedDecl *D) {
@@ -472,7 +508,7 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) {
}
template <typename T> static bool isFirstInExternCContext(T *D) {
- const T *First = D->getFirstDeclaration();
+ const T *First = D->getFirstDecl();
return First->isInExternCContext();
}
@@ -508,7 +544,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
!Var->getType().isVolatileQualified()) {
const VarDecl *PrevVar = Var->getPreviousDecl();
if (PrevVar)
- return PrevVar->getLinkageAndVisibility();
+ return getLVForDecl(PrevVar, computation);
if (Var->getStorageClass() != SC_Extern &&
Var->getStorageClass() != SC_PrivateExtern &&
@@ -539,11 +575,10 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// Explicitly declared static.
if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
return LinkageInfo(InternalLinkage, DefaultVisibility, false);
- } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
- // - a data member of an anonymous union.
- if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
- return LinkageInfo::internal();
}
+ // - a data member of an anonymous union.
+ assert(!isa<IndirectFieldDecl>(D) && "Didn't expect an IndirectFieldDecl!");
+ assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!");
if (D->isInAnonymousNamespace()) {
const VarDecl *Var = dyn_cast<VarDecl>(D);
@@ -627,7 +662,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// Note that we don't want to make the variable non-external
// because of this, but unique-external linkage suits us.
if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) {
- LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility();
+ LinkageInfo TypeLV = getLVForType(*Var->getType(), computation);
if (TypeLV.getLinkage() != ExternalLinkage)
return LinkageInfo::uniqueExternal();
if (!LV.isVisibilityExplicit())
@@ -660,16 +695,27 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// this translation unit. However, we should use the C linkage
// rules instead for extern "C" declarations.
if (Context.getLangOpts().CPlusPlus &&
- !Function->isInExternCContext() &&
- Function->getType()->getLinkage() == UniqueExternalLinkage)
- return LinkageInfo::uniqueExternal();
+ !Function->isInExternCContext()) {
+ // Only look at the type-as-written. If this function has an auto-deduced
+ // return type, we can't compute the linkage of that type because it could
+ // require looking at the linkage of this function, and we don't need this
+ // for correctness because the type is not part of the function's
+ // signature.
+ // FIXME: This is a hack. We should be able to solve this circularity and
+ // the one in getLVForClassMember for Functions some other way.
+ QualType TypeAsWritten = Function->getType();
+ if (TypeSourceInfo *TSI = Function->getTypeSourceInfo())
+ TypeAsWritten = TSI->getType();
+ if (TypeAsWritten->getLinkage() == UniqueExternalLinkage)
+ return LinkageInfo::uniqueExternal();
+ }
// Consider LV from the template and the template arguments.
// We're at file scope, so we do not need to worry about nested
// specializations.
if (FunctionTemplateSpecializationInfo *specInfo
= Function->getTemplateSpecializationInfo()) {
- mergeTemplateLV(LV, Function, specInfo);
+ mergeTemplateLV(LV, Function, specInfo, computation);
}
// - a named class (Clause 9), or an unnamed class defined in a
@@ -695,7 +741,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
} else if (isa<EnumConstantDecl>(D)) {
LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()),
computation);
- if (!isExternalLinkage(EnumLV.getLinkage()))
+ if (!isExternalFormalLinkage(EnumLV.getLinkage()))
return LinkageInfo::none();
LV.merge(EnumLV);
@@ -704,7 +750,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
} else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
bool considerVisibility = !hasExplicitVisibilityAlready(computation);
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
// - a namespace (7.3), unless it is declared within an unnamed
@@ -739,6 +785,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
if (!(isa<CXXMethodDecl>(D) ||
isa<VarDecl>(D) ||
isa<FieldDecl>(D) ||
+ isa<IndirectFieldDecl>(D) ||
isa<TagDecl>(D)))
return LinkageInfo::none();
@@ -766,13 +813,14 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
LinkageInfo classLV =
getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation);
- if (!isExternalLinkage(classLV.getLinkage()))
- return LinkageInfo::none();
-
// If the class already has unique-external linkage, we can't improve.
if (classLV.getLinkage() == UniqueExternalLinkage)
return LinkageInfo::uniqueExternal();
+ if (!isExternallyVisible(classLV.getLinkage()))
+ return LinkageInfo::none();
+
+
// Otherwise, don't merge in classLV yet, because in certain cases
// we need to completely ignore the visibility from it.
@@ -782,14 +830,25 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
// If the type of the function uses a type with unique-external
// linkage, it's not legally usable from outside this translation unit.
- if (MD->getType()->getLinkage() == UniqueExternalLinkage)
- return LinkageInfo::uniqueExternal();
-
+ // But only look at the type-as-written. If this function has an auto-deduced
+ // return type, we can't compute the linkage of that type because it could
+ // require looking at the linkage of this function, and we don't need this
+ // for correctness because the type is not part of the function's
+ // signature.
+ // FIXME: This is a hack. We should be able to solve this circularity and the
+ // one in getLVForNamespaceScopeDecl for Functions some other way.
+ {
+ QualType TypeAsWritten = MD->getType();
+ if (TypeSourceInfo *TSI = MD->getTypeSourceInfo())
+ TypeAsWritten = TSI->getType();
+ if (TypeAsWritten->getLinkage() == UniqueExternalLinkage)
+ return LinkageInfo::uniqueExternal();
+ }
// If this is a method template specialization, use the linkage for
// the template parameters and arguments.
if (FunctionTemplateSpecializationInfo *spec
= MD->getTemplateSpecializationInfo()) {
- mergeTemplateLV(LV, MD, spec);
+ mergeTemplateLV(LV, MD, spec, computation);
if (spec->isExplicitSpecialization()) {
explicitSpecSuppressor = MD;
} else if (isExplicitMemberSpecialization(spec->getTemplate())) {
@@ -819,9 +878,10 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
} else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// Modify the variable's linkage by its type, but ignore the
// type's visibility unless it's a definition.
- LinkageInfo typeLV = VD->getType()->getLinkageAndVisibility();
- LV.mergeMaybeWithVisibility(typeLV,
- !LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit());
+ LinkageInfo typeLV = getLVForType(*VD->getType(), computation);
+ if (!LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit())
+ LV.mergeVisibility(typeLV);
+ LV.mergeExternalVisibility(typeLV);
if (isExplicitMemberSpecialization(VD)) {
explicitSpecSuppressor = VD;
@@ -834,7 +894,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
!classLV.isVisibilityExplicit() &&
!hasExplicitVisibilityAlready(computation));
LinkageInfo tempLV =
- getLVForTemplateParameterList(temp->getTemplateParameters());
+ getLVForTemplateParameterList(temp->getTemplateParameters(), computation);
LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
if (const RedeclarableTemplateDecl *redeclTemp =
@@ -866,81 +926,42 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D,
void NamedDecl::anchor() { }
+static LinkageInfo computeLVForDecl(const NamedDecl *D,
+ LVComputationKind computation);
+
bool NamedDecl::isLinkageValid() const {
- if (!HasCachedLinkage)
+ if (!hasCachedLinkage())
return true;
- return getLVForDecl(this, LVForExplicitValue).getLinkage() ==
- Linkage(CachedLinkage);
+ return computeLVForDecl(this, LVForLinkageOnly).getLinkage() ==
+ getCachedLinkage();
}
-Linkage NamedDecl::getLinkage() const {
- if (HasCachedLinkage)
- return Linkage(CachedLinkage);
-
+Linkage NamedDecl::getLinkageInternal() const {
// We don't care about visibility here, so ask for the cheapest
// possible visibility analysis.
- CachedLinkage = getLVForDecl(this, LVForExplicitValue).getLinkage();
- HasCachedLinkage = 1;
-
-#ifndef NDEBUG
- verifyLinkage();
-#endif
-
- return Linkage(CachedLinkage);
+ return getLVForDecl(this, LVForLinkageOnly).getLinkage();
}
LinkageInfo NamedDecl::getLinkageAndVisibility() const {
LVComputationKind computation =
(usesTypeVisibility(this) ? LVForType : LVForValue);
- LinkageInfo LI = getLVForDecl(this, computation);
- if (HasCachedLinkage) {
- assert(Linkage(CachedLinkage) == LI.getLinkage());
- return LI;
- }
- HasCachedLinkage = 1;
- CachedLinkage = LI.getLinkage();
-
-#ifndef NDEBUG
- verifyLinkage();
-#endif
-
- return LI;
+ return getLVForDecl(this, computation);
}
-void NamedDecl::verifyLinkage() const {
- // In C (because of gnu inline) and in c++ with microsoft extensions an
- // static can follow an extern, so we can have two decls with different
- // linkages.
- const LangOptions &Opts = getASTContext().getLangOpts();
- if (!Opts.CPlusPlus || Opts.MicrosoftExt)
- return;
-
- // We have just computed the linkage for this decl. By induction we know
- // that all other computed linkages match, check that the one we just computed
- // also does.
- NamedDecl *D = NULL;
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- NamedDecl *T = cast<NamedDecl>(*I);
- if (T == this)
- continue;
- if (T->HasCachedLinkage != 0) {
- D = T;
- break;
- }
- }
- assert(!D || D->CachedLinkage == CachedLinkage);
-}
+static Optional<Visibility>
+getExplicitVisibilityAux(const NamedDecl *ND,
+ NamedDecl::ExplicitVisibilityKind kind,
+ bool IsMostRecent) {
+ assert(!IsMostRecent || ND == ND->getMostRecentDecl());
-Optional<Visibility>
-NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
// Check the declaration itself first.
- if (Optional<Visibility> V = getVisibilityOf(this, kind))
+ if (Optional<Visibility> V = getVisibilityOf(ND, kind))
return V;
// If this is a member class of a specialization of a class template
// and the corresponding decl has explicit visibility, use that.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND)) {
CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
if (InstantiatedFrom)
return getVisibilityOf(InstantiatedFrom, kind);
@@ -950,16 +971,18 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
// specialization of a class template, check for visibility
// on the pattern.
if (const ClassTemplateSpecializationDecl *spec
- = dyn_cast<ClassTemplateSpecializationDecl>(this))
+ = dyn_cast<ClassTemplateSpecializationDecl>(ND))
return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(),
kind);
// Use the most recent declaration.
- const NamedDecl *MostRecent = cast<NamedDecl>(this->getMostRecentDecl());
- if (MostRecent != this)
- return MostRecent->getExplicitVisibility(kind);
+ if (!IsMostRecent && !isa<NamespaceDecl>(ND)) {
+ const NamedDecl *MostRecent = ND->getMostRecentDecl();
+ if (MostRecent != ND)
+ return getExplicitVisibilityAux(MostRecent, kind, true);
+ }
- if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
+ if (const VarDecl *Var = dyn_cast<VarDecl>(ND)) {
if (Var->isStaticDataMember()) {
VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember();
if (InstantiatedFrom)
@@ -969,7 +992,7 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
return None;
}
// Also handle function template specializations.
- if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
+ if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(ND)) {
// If the function is a specialization of a template with an
// explicit visibility attribute, use that.
if (FunctionTemplateSpecializationInfo *templateInfo
@@ -987,12 +1010,33 @@ NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
}
// The visibility of a template is stored in the templated decl.
- if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(this))
+ if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(ND))
return getVisibilityOf(TD->getTemplatedDecl(), kind);
return None;
}
+Optional<Visibility>
+NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
+ return getExplicitVisibilityAux(this, kind, false);
+}
+
+static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl,
+ LVComputationKind computation) {
+ // This lambda has its linkage/visibility determined by its owner.
+ if (ContextDecl) {
+ if (isa<ParmVarDecl>(ContextDecl))
+ DC = ContextDecl->getDeclContext()->getRedeclContext();
+ else
+ return getLVForDecl(cast<NamedDecl>(ContextDecl), computation);
+ }
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
+ return getLVForDecl(ND, computation);
+
+ return LinkageInfo::external();
+}
+
static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
LVComputationKind computation) {
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
@@ -1040,13 +1084,55 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
return LV;
}
+
+ if (!Var->isStaticLocal())
+ return LinkageInfo::none();
}
- return LinkageInfo::none();
+ ASTContext &Context = D->getASTContext();
+ if (!Context.getLangOpts().CPlusPlus)
+ return LinkageInfo::none();
+
+ const Decl *OuterD = getOutermostFuncOrBlockContext(D);
+ if (!OuterD)
+ return LinkageInfo::none();
+
+ LinkageInfo LV;
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(OuterD)) {
+ if (!BD->getBlockManglingNumber())
+ return LinkageInfo::none();
+
+ LV = getLVForClosure(BD->getDeclContext()->getRedeclContext(),
+ BD->getBlockManglingContextDecl(), computation);
+ } else {
+ const FunctionDecl *FD = cast<FunctionDecl>(OuterD);
+ if (!FD->isInlined() &&
+ FD->getTemplateSpecializationKind() == TSK_Undeclared)
+ return LinkageInfo::none();
+
+ LV = getLVForDecl(FD, computation);
+ }
+ if (!isExternallyVisible(LV.getLinkage()))
+ return LinkageInfo::none();
+ return LinkageInfo(VisibleNoLinkage, LV.getVisibility(),
+ LV.isVisibilityExplicit());
}
-static LinkageInfo getLVForDecl(const NamedDecl *D,
- LVComputationKind computation) {
+static inline const CXXRecordDecl*
+getOutermostEnclosingLambda(const CXXRecordDecl *Record) {
+ const CXXRecordDecl *Ret = Record;
+ while (Record && Record->isLambda()) {
+ Ret = Record;
+ if (!Record->getParent()) break;
+ // Get the Containing Class of this Lambda Class
+ Record = dyn_cast_or_null<CXXRecordDecl>(
+ Record->getParent()->getParent());
+ }
+ return Ret;
+}
+
+static LinkageInfo computeLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
// Objective-C: treat all Objective-C declarations as having external
// linkage.
switch (D->getKind()) {
@@ -1074,20 +1160,25 @@ static LinkageInfo getLVForDecl(const NamedDecl *D,
// This lambda has no mangling number, so it's internal.
return LinkageInfo::internal();
}
-
- // This lambda has its linkage/visibility determined by its owner.
- const DeclContext *DC = D->getDeclContext()->getRedeclContext();
- if (Decl *ContextDecl = Record->getLambdaContextDecl()) {
- if (isa<ParmVarDecl>(ContextDecl))
- DC = ContextDecl->getDeclContext()->getRedeclContext();
- else
- return getLVForDecl(cast<NamedDecl>(ContextDecl), computation);
- }
- if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
- return getLVForDecl(ND, computation);
+ // This lambda has its linkage/visibility determined:
+ // - either by the outermost lambda if that lambda has no mangling
+ // number.
+ // - or by the parent of the outer most lambda
+ // This prevents infinite recursion in settings such as nested lambdas
+ // used in NSDMI's, for e.g.
+ // struct L {
+ // int t{};
+ // int t2 = ([](int a) { return [](int b) { return b; };})(t)(t);
+ // };
+ const CXXRecordDecl *OuterMostLambda =
+ getOutermostEnclosingLambda(Record);
+ if (!OuterMostLambda->getLambdaManglingNumber())
+ return LinkageInfo::internal();
- return LinkageInfo::external();
+ return getLVForClosure(
+ OuterMostLambda->getDeclContext()->getRedeclContext(),
+ OuterMostLambda->getLambdaContextDecl(), computation);
}
break;
@@ -1127,6 +1218,57 @@ static LinkageInfo getLVForDecl(const NamedDecl *D,
return LinkageInfo::none();
}
+namespace clang {
+class LinkageComputer {
+public:
+ static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
+ if (computation == LVForLinkageOnly && D->hasCachedLinkage())
+ return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false);
+
+ LinkageInfo LV = computeLVForDecl(D, computation);
+ if (D->hasCachedLinkage())
+ assert(D->getCachedLinkage() == LV.getLinkage());
+
+ D->setCachedLinkage(LV.getLinkage());
+
+#ifndef NDEBUG
+ // In C (because of gnu inline) and in c++ with microsoft extensions an
+ // static can follow an extern, so we can have two decls with different
+ // linkages.
+ const LangOptions &Opts = D->getASTContext().getLangOpts();
+ if (!Opts.CPlusPlus || Opts.MicrosoftExt)
+ return LV;
+
+ // We have just computed the linkage for this decl. By induction we know
+ // that all other computed linkages match, check that the one we just
+ // computed
+ // also does.
+ NamedDecl *Old = NULL;
+ for (NamedDecl::redecl_iterator I = D->redecls_begin(),
+ E = D->redecls_end();
+ I != E; ++I) {
+ NamedDecl *T = cast<NamedDecl>(*I);
+ if (T == D)
+ continue;
+ if (T->hasCachedLinkage()) {
+ Old = T;
+ break;
+ }
+ }
+ assert(!Old || Old->getCachedLinkage() == D->getCachedLinkage());
+#endif
+
+ return LV;
+ }
+};
+}
+
+static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
+ return clang::LinkageComputer::getLVForDecl(D, computation);
+}
+
std::string NamedDecl::getQualifiedNameAsString() const {
return getQualifiedNameAsString(getASTContext().getPrintingPolicy());
}
@@ -1265,6 +1407,15 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
cast<UsingDecl>(OldD)->getQualifier());
}
+ if (isa<UnresolvedUsingValueDecl>(this) &&
+ isa<UnresolvedUsingValueDecl>(OldD)) {
+ ASTContext &Context = getASTContext();
+ return Context.getCanonicalNestedNameSpecifier(
+ cast<UnresolvedUsingValueDecl>(this)->getQualifier()) ==
+ Context.getCanonicalNestedNameSpecifier(
+ cast<UnresolvedUsingValueDecl>(OldD)->getQualifier());
+ }
+
// A typedef of an Objective-C class type can replace an Objective-C class
// declaration or definition, and vice versa.
if ((isa<TypedefNameDecl>(this) && isa<ObjCInterfaceDecl>(OldD)) ||
@@ -1278,7 +1429,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
}
bool NamedDecl::hasLinkage() const {
- return getLinkage() != NoLinkage;
+ return getFormalLinkage() != NoLinkage;
}
NamedDecl *NamedDecl::getUnderlyingDeclImpl() {
@@ -1469,6 +1620,17 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
llvm_unreachable("Invalid storage class");
}
+VarDecl::VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo, StorageClass SC)
+ : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() {
+ assert(sizeof(VarDeclBitfields) <= sizeof(unsigned));
+ assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned));
+ AllBits = 0;
+ VarDeclBits.SClass = SC;
+ // Everything else is implicitly initialized to false.
+}
+
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartL, SourceLocation IdL,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
@@ -1502,7 +1664,7 @@ template<typename T>
static LanguageLinkage getLanguageLinkageTemplate(const T &D) {
// C++ [dcl.link]p1: All function types, function names with external linkage,
// and variable names with external linkage have a language linkage.
- if (!isExternalLinkage(D.getLinkage()))
+ if (!D.hasExternalFormalLinkage())
return NoLanguageLinkage;
// Language linkage is a C++ concept, but saying that everything else in C has
@@ -1547,32 +1709,15 @@ bool VarDecl::isExternC() const {
return isExternCTemplate(*this);
}
-static bool isLinkageSpecContext(const DeclContext *DC,
- LinkageSpecDecl::LanguageIDs ID) {
- while (DC->getDeclKind() != Decl::TranslationUnit) {
- if (DC->getDeclKind() == Decl::LinkageSpec)
- return cast<LinkageSpecDecl>(DC)->getLanguage() == ID;
- DC = DC->getParent();
- }
- return false;
-}
-
-template <typename T>
-static bool isInLanguageSpecContext(T *D, LinkageSpecDecl::LanguageIDs ID) {
- return isLinkageSpecContext(D->getLexicalDeclContext(), ID);
-}
-
bool VarDecl::isInExternCContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c);
+ return getLexicalDeclContext()->isExternCContext();
}
bool VarDecl::isInExternCXXContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx);
+ return getLexicalDeclContext()->isExternCXXContext();
}
-VarDecl *VarDecl::getCanonicalDecl() {
- return getFirstDeclaration();
-}
+VarDecl *VarDecl::getCanonicalDecl() { return getFirstDecl(); }
VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
ASTContext &C) const
@@ -1581,13 +1726,24 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
// A declaration is a definition unless [...] it contains the 'extern'
// specifier or a linkage-specification and neither an initializer [...],
// it declares a static data member in a class declaration [...].
- // C++ [temp.expl.spec]p15:
- // An explicit specialization of a static data member of a template is a
- // definition if the declaration includes an initializer; otherwise, it is
- // a declaration.
+ // C++1y [temp.expl.spec]p15:
+ // An explicit specialization of a static data member or an explicit
+ // specialization of a static data member template is a definition if the
+ // declaration includes an initializer; otherwise, it is a declaration.
+ //
+ // FIXME: How do you declare (but not define) a partial specialization of
+ // a static data member template outside the containing class?
if (isStaticDataMember()) {
- if (isOutOfLine() && (hasInit() ||
- getTemplateSpecializationKind() != TSK_ExplicitSpecialization))
+ if (isOutOfLine() &&
+ (hasInit() ||
+ // If the first declaration is out-of-line, this may be an
+ // instantiation of an out-of-line partial specialization of a variable
+ // template for which we have not yet instantiated the initializer.
+ (getFirstDecl()->isOutOfLine()
+ ? getTemplateSpecializationKind() == TSK_Undeclared
+ : getTemplateSpecializationKind() !=
+ TSK_ExplicitSpecialization) ||
+ isa<VarTemplatePartialSpecializationDecl>(this)))
return Definition;
else
return DeclarationOnly;
@@ -1602,6 +1758,16 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
if (hasInit())
return Definition;
+ if (hasAttr<AliasAttr>())
+ return Definition;
+
+ // A variable template specialization (other than a static data member
+ // template or an explicit specialization) is a declaration until we
+ // instantiate its initializer.
+ if (isa<VarTemplateSpecializationDecl>(this) &&
+ getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
+ return DeclarationOnly;
+
if (hasExternalStorage())
return DeclarationOnly;
@@ -1631,7 +1797,7 @@ VarDecl *VarDecl::getActingDefinition() {
return 0;
VarDecl *LastTentative = 0;
- VarDecl *First = getFirstDeclaration();
+ VarDecl *First = getFirstDecl();
for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
I != E; ++I) {
Kind = (*I)->isThisDeclarationADefinition();
@@ -1643,20 +1809,8 @@ VarDecl *VarDecl::getActingDefinition() {
return LastTentative;
}
-bool VarDecl::isTentativeDefinitionNow() const {
- DefinitionKind Kind = isThisDeclarationADefinition();
- if (Kind != TentativeDefinition)
- return false;
-
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if ((*I)->isThisDeclarationADefinition() == Definition)
- return false;
- }
- return true;
-}
-
VarDecl *VarDecl::getDefinition(ASTContext &C) {
- VarDecl *First = getFirstDeclaration();
+ VarDecl *First = getFirstDecl();
for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
I != E; ++I) {
if ((*I)->isThisDeclarationADefinition(C) == Definition)
@@ -1668,7 +1822,7 @@ VarDecl *VarDecl::getDefinition(ASTContext &C) {
VarDecl::DefinitionKind VarDecl::hasDefinition(ASTContext &C) const {
DefinitionKind Kind = DeclarationOnly;
- const VarDecl *First = getFirstDeclaration();
+ const VarDecl *First = getFirstDecl();
for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
I != E; ++I) {
Kind = std::max(Kind, (*I)->isThisDeclarationADefinition(C));
@@ -1763,6 +1917,10 @@ EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const {
EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>();
if (!Eval) {
Stmt *S = Init.get<Stmt *>();
+ // Note: EvaluatedStmt contains an APValue, which usually holds
+ // resources not allocated from the ASTContext. We need to do some
+ // work to avoid leaking those, but we do so in VarDecl::evaluateValue
+ // where we can detect whether there's anything to clean up or not.
Eval = new (getASTContext()) EvaluatedStmt;
Eval->Value = S;
Init = Eval;
@@ -1775,6 +1933,13 @@ APValue *VarDecl::evaluateValue() const {
return evaluateValue(Notes);
}
+namespace {
+// Destroy an APValue that was allocated in an ASTContext.
+void DestroyAPValue(void* UntypedValue) {
+ static_cast<APValue*>(UntypedValue)->~APValue();
+}
+} // namespace
+
APValue *VarDecl::evaluateValue(
SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
EvaluatedStmt *Eval = ensureEvaluatedStmt();
@@ -1800,9 +1965,13 @@ APValue *VarDecl::evaluateValue(
bool Result = Init->EvaluateAsInitializer(Eval->Evaluated, getASTContext(),
this, Notes);
- // Ensure the result is an uninitialized APValue if evaluation fails.
+ // Ensure the computed APValue is cleaned up later if evaluation succeeded,
+ // or that it's empty (so that there's nothing to clean up) if evaluation
+ // failed.
if (!Result)
Eval->Evaluated = APValue();
+ else if (Eval->Evaluated.needsCleanup())
+ getASTContext().AddDeallocation(DestroyAPValue, &Eval->Evaluated);
Eval->IsEvaluating = false;
Eval->WasEvaluated = true;
@@ -1853,19 +2022,6 @@ bool VarDecl::checkInitIsICE() const {
return Eval->IsICE;
}
-bool VarDecl::extendsLifetimeOfTemporary() const {
- assert(getType()->isReferenceType() &&"Non-references never extend lifetime");
-
- const Expr *E = getInit();
- if (!E)
- return false;
-
- if (const ExprWithCleanups *Cleanups = dyn_cast<ExprWithCleanups>(E))
- E = Cleanups->getSubExpr();
-
- return isa<MaterializeTemporaryExpr>(E);
-}
-
VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return cast<VarDecl>(MSI->getInstantiatedFrom());
@@ -1874,25 +2030,73 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const {
}
TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const {
+ if (const VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(this))
+ return Spec->getSpecializationKind();
+
if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
return MSI->getTemplateSpecializationKind();
-
+
return TSK_Undeclared;
}
+SourceLocation VarDecl::getPointOfInstantiation() const {
+ if (const VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(this))
+ return Spec->getPointOfInstantiation();
+
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
+ return MSI->getPointOfInstantiation();
+
+ return SourceLocation();
+}
+
+VarTemplateDecl *VarDecl::getDescribedVarTemplate() const {
+ return getASTContext().getTemplateOrSpecializationInfo(this)
+ .dyn_cast<VarTemplateDecl *>();
+}
+
+void VarDecl::setDescribedVarTemplate(VarTemplateDecl *Template) {
+ getASTContext().setTemplateOrSpecializationInfo(this, Template);
+}
+
MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const {
- return getASTContext().getInstantiatedFromStaticDataMember(this);
+ if (isStaticDataMember())
+ // FIXME: Remove ?
+ // return getASTContext().getInstantiatedFromStaticDataMember(this);
+ return getASTContext().getTemplateOrSpecializationInfo(this)
+ .dyn_cast<MemberSpecializationInfo *>();
+ return 0;
}
void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
SourceLocation PointOfInstantiation) {
- MemberSpecializationInfo *MSI = getMemberSpecializationInfo();
- assert(MSI && "Not an instantiated static data member?");
- MSI->setTemplateSpecializationKind(TSK);
- if (TSK != TSK_ExplicitSpecialization &&
- PointOfInstantiation.isValid() &&
- MSI->getPointOfInstantiation().isInvalid())
- MSI->setPointOfInstantiation(PointOfInstantiation);
+ assert((isa<VarTemplateSpecializationDecl>(this) ||
+ getMemberSpecializationInfo()) &&
+ "not a variable or static data member template specialization");
+
+ if (VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(this)) {
+ Spec->setSpecializationKind(TSK);
+ if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
+ Spec->getPointOfInstantiation().isInvalid())
+ Spec->setPointOfInstantiation(PointOfInstantiation);
+ }
+
+ if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) {
+ MSI->setTemplateSpecializationKind(TSK);
+ if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() &&
+ MSI->getPointOfInstantiation().isInvalid())
+ MSI->setPointOfInstantiation(PointOfInstantiation);
+ }
+}
+
+void
+VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD,
+ TemplateSpecializationKind TSK) {
+ assert(getASTContext().getTemplateOrSpecializationInfo(this).isNull() &&
+ "Previous template or instantiation?");
+ getASTContext().setInstantiatedFromStaticDataMember(this, VD, TSK);
}
//===----------------------------------------------------------------------===//
@@ -1908,6 +2112,14 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
S, DefArg);
}
+QualType ParmVarDecl::getOriginalType() const {
+ TypeSourceInfo *TSI = getTypeSourceInfo();
+ QualType T = TSI ? TSI->getType() : getType();
+ if (const DecayedType *DT = dyn_cast<DecayedType>(T))
+ return DT->getOriginalType();
+ return T;
+}
+
ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl));
return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(),
@@ -2010,7 +2222,8 @@ bool FunctionDecl::hasTrivialBody() const
bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed) {
+ if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed ||
+ I->hasAttr<AliasAttr>()) {
Definition = I->IsDeleted ? I->getCanonicalDecl() : *I;
return true;
}
@@ -2020,15 +2233,11 @@ bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
}
Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const {
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if (I->Body) {
- Definition = *I;
- return I->Body.get(getASTContext().getExternalSource());
- } else if (I->IsLateTemplateParsed) {
- Definition = *I;
- return 0;
- }
- }
+ if (!hasBody(Definition))
+ return 0;
+
+ if (Definition->Body)
+ return Definition->Body.get(getASTContext().getExternalSource());
return 0;
}
@@ -2046,13 +2255,45 @@ void FunctionDecl::setPure(bool P) {
Parent->markedVirtualFunctionPure();
}
+template<std::size_t Len>
+static bool isNamed(const NamedDecl *ND, const char (&Str)[Len]) {
+ IdentifierInfo *II = ND->getIdentifier();
+ return II && II->isStr(Str);
+}
+
bool FunctionDecl::isMain() const {
const TranslationUnitDecl *tunit =
dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
return tunit &&
!tunit->getASTContext().getLangOpts().Freestanding &&
- getIdentifier() &&
- getIdentifier()->isStr("main");
+ isNamed(this, "main");
+}
+
+bool FunctionDecl::isMSVCRTEntryPoint() const {
+ const TranslationUnitDecl *TUnit =
+ dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
+ if (!TUnit)
+ return false;
+
+ // Even though we aren't really targeting MSVCRT if we are freestanding,
+ // semantic analysis for these functions remains the same.
+
+ // MSVCRT entry points only exist on MSVCRT targets.
+ if (!TUnit->getASTContext().getTargetInfo().getTriple().isOSMSVCRT())
+ return false;
+
+ // Nameless functions like constructors cannot be entry points.
+ if (!getIdentifier())
+ return false;
+
+ return llvm::StringSwitch<bool>(getName())
+ .Cases("main", // an ANSI console app
+ "wmain", // a Unicode console App
+ "WinMain", // an ANSI GUI app
+ "wWinMain", // a Unicode GUI app
+ "DllMain", // a DLL
+ true)
+ .Default(false);
}
bool FunctionDecl::isReservedGlobalPlacementOperator() const {
@@ -2077,13 +2318,83 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy);
}
-LanguageLinkage FunctionDecl::getLanguageLinkage() const {
- // Users expect to be able to write
- // extern "C" void *__builtin_alloca (size_t);
- // so consider builtins as having C language linkage.
- if (getBuiltinID())
- return CLanguageLinkage;
+static bool isNamespaceStd(const DeclContext *DC) {
+ const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC->getRedeclContext());
+ return ND && isNamed(ND, "std") &&
+ ND->getParent()->getRedeclContext()->isTranslationUnit();
+}
+bool FunctionDecl::isReplaceableGlobalAllocationFunction() const {
+ 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 (isa<CXXRecordDecl>(getDeclContext()))
+ return false;
+ assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+
+ const FunctionProtoType *FPT = getType()->castAs<FunctionProtoType>();
+ if (FPT->getNumArgs() > 2 || FPT->isVariadic())
+ return false;
+
+ // If this is a single-parameter function, it must be a replaceable global
+ // allocation or deallocation function.
+ if (FPT->getNumArgs() == 1)
+ return true;
+
+ // Otherwise, we're looking for a second parameter whose type is
+ // 'const std::nothrow_t &', or, in C++1y, 'std::size_t'.
+ QualType Ty = FPT->getArgType(1);
+ ASTContext &Ctx = getASTContext();
+ if (Ctx.getLangOpts().SizedDeallocation &&
+ Ctx.hasSameType(Ty, Ctx.getSizeType()))
+ return true;
+ if (!Ty->isReferenceType())
+ return false;
+ Ty = Ty->getPointeeType();
+ if (Ty.getCVRQualifiers() != Qualifiers::Const)
+ return false;
+ // FIXME: Recognise nothrow_t in an inline namespace inside std?
+ const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ return RD && isNamed(RD, "nothrow_t") && isNamespaceStd(RD->getDeclContext());
+}
+
+FunctionDecl *
+FunctionDecl::getCorrespondingUnsizedGlobalDeallocationFunction() const {
+ ASTContext &Ctx = getASTContext();
+ if (!Ctx.getLangOpts().SizedDeallocation)
+ return 0;
+
+ if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName)
+ return 0;
+ if (getDeclName().getCXXOverloadedOperator() != OO_Delete &&
+ getDeclName().getCXXOverloadedOperator() != OO_Array_Delete)
+ return 0;
+ if (isa<CXXRecordDecl>(getDeclContext()))
+ return 0;
+ assert(getDeclContext()->getRedeclContext()->isTranslationUnit());
+
+ if (getNumParams() != 2 || isVariadic() ||
+ !Ctx.hasSameType(getType()->castAs<FunctionProtoType>()->getArgType(1),
+ Ctx.getSizeType()))
+ return 0;
+
+ // This is a sized deallocation function. Find the corresponding unsized
+ // deallocation function.
+ lookup_const_result R = getDeclContext()->lookup(getDeclName());
+ for (lookup_const_result::iterator RI = R.begin(), RE = R.end(); RI != RE;
+ ++RI)
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*RI))
+ if (FD->getNumParams() == 1 && !FD->isVariadic())
+ return FD;
+ return 0;
+}
+
+LanguageLinkage FunctionDecl::getLanguageLinkage() const {
return getLanguageLinkageTemplate(*this);
}
@@ -2092,11 +2403,11 @@ bool FunctionDecl::isExternC() const {
}
bool FunctionDecl::isInExternCContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_c);
+ return getLexicalDeclContext()->isExternCContext();
}
bool FunctionDecl::isInExternCXXContext() const {
- return isInLanguageSpecContext(this, LinkageSpecDecl::lang_cxx);
+ return getLexicalDeclContext()->isExternCXXContext();
}
bool FunctionDecl::isGlobal() const {
@@ -2127,13 +2438,13 @@ bool FunctionDecl::isNoReturn() const {
void
FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
- redeclarable_base::setPreviousDeclaration(PrevDecl);
+ redeclarable_base::setPreviousDecl(PrevDecl);
if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
FunctionTemplateDecl *PrevFunTmpl
= PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
- FunTmpl->setPreviousDeclaration(PrevFunTmpl);
+ FunTmpl->setPreviousDecl(PrevFunTmpl);
}
if (PrevDecl && PrevDecl->IsInline)
@@ -2141,12 +2452,10 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
}
const FunctionDecl *FunctionDecl::getCanonicalDecl() const {
- return getFirstDeclaration();
+ return getFirstDecl();
}
-FunctionDecl *FunctionDecl::getCanonicalDecl() {
- return getFirstDeclaration();
-}
+FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); }
/// \brief Returns a value indicating whether this function
/// corresponds to a builtin function.
@@ -2166,6 +2475,22 @@ unsigned FunctionDecl::getBuiltinID() const {
return 0;
ASTContext &Context = getASTContext();
+ if (Context.getLangOpts().CPlusPlus) {
+ const LinkageSpecDecl *LinkageDecl = dyn_cast<LinkageSpecDecl>(
+ getFirstDecl()->getDeclContext());
+ // In C++, the first declaration of a builtin is always inside an implicit
+ // extern "C".
+ // FIXME: A recognised library function may not be directly in an extern "C"
+ // declaration, for instance "extern "C" { namespace std { decl } }".
+ if (!LinkageDecl || LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c)
+ return 0;
+ }
+
+ // If the function is marked "overloadable", it has a different mangled name
+ // and is not the C library function.
+ if (getAttr<OverloadableAttr>())
+ return 0;
+
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return BuiltinID;
@@ -2177,22 +2502,7 @@ unsigned FunctionDecl::getBuiltinID() const {
if (getStorageClass() == SC_Static)
return 0;
- // If this function is at translation-unit scope and we're not in
- // C++, it refers to the C library function.
- if (!Context.getLangOpts().CPlusPlus &&
- getDeclContext()->isTranslationUnit())
- return BuiltinID;
-
- // If the function is in an extern "C" linkage specification and is
- // not marked "overloadable", it's the real function.
- if (isa<LinkageSpecDecl>(getDeclContext()) &&
- cast<LinkageSpecDecl>(getDeclContext())->getLanguage()
- == LinkageSpecDecl::lang_c &&
- !getAttr<OverloadableAttr>())
- return BuiltinID;
-
- // Not a builtin
- return 0;
+ return BuiltinID;
}
@@ -2304,7 +2614,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
const FunctionDecl *Prev = this;
bool FoundBody = false;
while ((Prev = Prev->getPreviousDecl())) {
- FoundBody |= Prev->Body;
+ FoundBody |= Prev->Body.isValid();
if (Prev->Body) {
// If it's not the case that both 'inline' and 'extern' are
@@ -2332,7 +2642,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
const FunctionDecl *Prev = this;
bool FoundBody = false;
while ((Prev = Prev->getPreviousDecl())) {
- FoundBody |= Prev->Body;
+ FoundBody |= Prev->Body.isValid();
if (RedeclForcesDefC99(Prev))
return false;
}
@@ -2818,26 +3128,18 @@ unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const {
}
unsigned FieldDecl::getFieldIndex() const {
+ const FieldDecl *Canonical = getCanonicalDecl();
+ if (Canonical != this)
+ return Canonical->getFieldIndex();
+
if (CachedFieldIndex) return CachedFieldIndex - 1;
unsigned Index = 0;
const RecordDecl *RD = getParent();
- const FieldDecl *LastFD = 0;
- bool IsMsStruct = RD->isMsStruct(getASTContext());
for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I, ++Index) {
- I->CachedFieldIndex = Index + 1;
-
- if (IsMsStruct) {
- // Zero-length bitfields following non-bitfield members are ignored.
- if (getASTContext().ZeroBitfieldFollowsNonBitfield(*I, LastFD)) {
- --Index;
- continue;
- }
- LastFD = *I;
- }
- }
+ I != E; ++I, ++Index)
+ I->getCanonicalDecl()->CachedFieldIndex = Index + 1;
assert(CachedFieldIndex && "failed to find field in parent");
return CachedFieldIndex - 1;
@@ -2874,12 +3176,10 @@ SourceRange TagDecl::getSourceRange() const {
return SourceRange(getOuterLocStart(), E);
}
-TagDecl* TagDecl::getCanonicalDecl() {
- return getFirstDeclaration();
-}
+TagDecl *TagDecl::getCanonicalDecl() { return getFirstDecl(); }
void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
- TypedefNameDeclOrQualifier = TDD;
+ NamedDeclOrQualifier = TDD;
if (TypeForDecl)
assert(TypeForDecl->isLinkageValid());
assert(isLinkageValid());
@@ -2936,7 +3236,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
if (QualifierLoc) {
// Make sure the extended qualifier info is allocated.
if (!hasExtInfo())
- TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo;
+ NamedDeclOrQualifier = new (getASTContext()) ExtInfo;
// Set qualifier info.
getExtInfo()->QualifierLoc = QualifierLoc;
} else {
@@ -2944,7 +3244,7 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) {
if (hasExtInfo()) {
if (getExtInfo()->NumTemplParamLists == 0) {
getASTContext().Deallocate(getExtInfo());
- TypedefNameDeclOrQualifier = (TypedefNameDecl*) 0;
+ NamedDeclOrQualifier = (TypedefNameDecl*) 0;
}
else
getExtInfo()->QualifierLoc = QualifierLoc;
@@ -2959,7 +3259,7 @@ void TagDecl::setTemplateParameterListsInfo(ASTContext &Context,
// Make sure the extended decl info is allocated.
if (!hasExtInfo())
// Allocate external info struct.
- TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo;
+ NamedDeclOrQualifier = new (getASTContext()) ExtInfo;
// Set the template parameter lists info.
getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists);
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 084a432..121c5a6 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -291,6 +291,16 @@ bool Decl::isUsed(bool CheckUsedAttr) const {
return false;
}
+void Decl::markUsed(ASTContext &C) {
+ if (Used)
+ return;
+
+ if (C.getASTMutationListener())
+ C.getASTMutationListener()->DeclarationMarkedUsed(this);
+
+ Used = true;
+}
+
bool Decl::isReferenced() const {
if (Referenced)
return true;
@@ -538,6 +548,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
return IDNS_Namespace;
case FunctionTemplate:
+ case VarTemplate:
return IDNS_Ordinary;
case ClassTemplate:
@@ -560,6 +571,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ClassTemplateSpecialization:
case ClassTemplatePartialSpecialization:
case ClassScopeFunctionSpecialization:
+ case VarTemplateSpecialization:
+ case VarTemplatePartialSpecialization:
case ObjCImplementation:
case ObjCCategory:
case ObjCCategoryImpl:
@@ -595,32 +608,6 @@ const AttrVec &Decl::getAttrs() const {
return getASTContext().getDeclAttrs(this);
}
-void Decl::swapAttrs(Decl *RHS) {
- bool HasLHSAttr = this->HasAttrs;
- bool HasRHSAttr = RHS->HasAttrs;
-
- // Usually, neither decl has attrs, nothing to do.
- if (!HasLHSAttr && !HasRHSAttr) return;
-
- // If 'this' has no attrs, swap the other way.
- if (!HasLHSAttr)
- return RHS->swapAttrs(this);
-
- ASTContext &Context = getASTContext();
-
- // Handle the case when both decls have attrs.
- if (HasRHSAttr) {
- std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS));
- return;
- }
-
- // Otherwise, LHS has an attr and RHS doesn't.
- Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this);
- Context.eraseDeclAttrs(this);
- this->HasAttrs = false;
- RHS->HasAttrs = true;
-}
-
Decl *Decl::castFromDeclContext (const DeclContext *D) {
Decl::Kind DK = D->getDeclKind();
switch(DK) {
@@ -819,6 +806,24 @@ bool DeclContext::isTransparentContext() const {
return false;
}
+static bool isLinkageSpecContext(const DeclContext *DC,
+ LinkageSpecDecl::LanguageIDs ID) {
+ while (DC->getDeclKind() != Decl::TranslationUnit) {
+ if (DC->getDeclKind() == Decl::LinkageSpec)
+ return cast<LinkageSpecDecl>(DC)->getLanguage() == ID;
+ DC = DC->getParent();
+ }
+ return false;
+}
+
+bool DeclContext::isExternCContext() const {
+ return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_c);
+}
+
+bool DeclContext::isExternCXXContext() const {
+ return isLinkageSpecContext(this, clang::LinkageSpecDecl::lang_cxx);
+}
+
bool DeclContext::Encloses(const DeclContext *DC) const {
if (getPrimaryContext() != this)
return getPrimaryContext()->Encloses(DC);
@@ -939,11 +944,8 @@ void DeclContext::reconcileExternalVisibleStorage() {
NeedToReconcileExternalVisibleStorage = false;
StoredDeclsMap &Map = *LookupPtr.getPointer();
- ExternalASTSource *Source = getParentASTContext().getExternalSource();
- for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) {
- I->second.removeExternalDecls();
- Source->FindExternalVisibleDeclsByName(this, I->first);
- }
+ for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I)
+ I->second.setHasExternalDecls();
}
/// \brief Load the declarations within this lexical storage from an
@@ -996,8 +998,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
- // Add an entry to the map for this name, if it's not already present.
- (*Map)[Name];
+ (*Map)[Name].removeExternalDecls();
return DeclContext::lookup_result();
}
@@ -1012,13 +1013,38 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
Map = DC->CreateStoredDeclsMap(Context);
StoredDeclsList &List = (*Map)[Name];
- for (ArrayRef<NamedDecl*>::iterator
- I = Decls.begin(), E = Decls.end(); I != E; ++I) {
- if (List.isNull())
- List.setOnlyValue(*I);
- else
- // FIXME: Need declarationReplaces handling for redeclarations in modules.
- List.AddSubsequentDecl(*I);
+
+ // Clear out any old external visible declarations, to avoid quadratic
+ // performance in the redeclaration checks below.
+ List.removeExternalDecls();
+
+ if (!List.isNull()) {
+ // We have both existing declarations and new declarations for this name.
+ // Some of the declarations may simply replace existing ones. Handle those
+ // first.
+ llvm::SmallVector<unsigned, 8> Skip;
+ for (unsigned I = 0, N = Decls.size(); I != N; ++I)
+ if (List.HandleRedeclaration(Decls[I]))
+ Skip.push_back(I);
+ Skip.push_back(Decls.size());
+
+ // Add in any new declarations.
+ unsigned SkipPos = 0;
+ for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+ if (I == Skip[SkipPos])
+ ++SkipPos;
+ else
+ List.AddSubsequentDecl(Decls[I]);
+ }
+ } else {
+ // Convert the array to a StoredDeclsList.
+ for (ArrayRef<NamedDecl*>::iterator
+ I = Decls.begin(), E = Decls.end(); I != E; ++I) {
+ if (List.isNull())
+ List.setOnlyValue(*I);
+ else
+ List.AddSubsequentDecl(*I);
+ }
}
return List.getLookupResult();
@@ -1171,7 +1197,8 @@ StoredDeclsMap *DeclContext::buildLookup() {
SmallVector<DeclContext *, 2> Contexts;
collectAllContexts(Contexts);
for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
- buildLookupImpl(Contexts[I]);
+ buildLookupImpl<&DeclContext::decls_begin,
+ &DeclContext::decls_end>(Contexts[I]);
// We no longer have any lazy decls.
LookupPtr.setInt(false);
@@ -1183,16 +1210,26 @@ StoredDeclsMap *DeclContext::buildLookup() {
/// declarations contained within DCtx, which will either be this
/// DeclContext, a DeclContext linked to it, or a transparent context
/// nested within it.
+template<DeclContext::decl_iterator (DeclContext::*Begin)() const,
+ DeclContext::decl_iterator (DeclContext::*End)() const>
void DeclContext::buildLookupImpl(DeclContext *DCtx) {
- for (decl_iterator I = DCtx->decls_begin(), E = DCtx->decls_end();
+ for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)();
I != E; ++I) {
Decl *D = *I;
// Insert this declaration into the lookup structure, but only if
// it's semantically within its decl context. Any other decls which
// should be found in this context are added eagerly.
+ //
+ // If it's from an AST file, don't add it now. It'll get handled by
+ // FindExternalVisibleDeclsByName if needed. Exception: if we're not
+ // in C++, we do not track external visible decls for the TU, so in
+ // that case we need to collect them all here.
if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
- if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND))
+ if (ND->getDeclContext() == DCtx && !shouldBeHidden(ND) &&
+ (!ND->isFromASTFile() ||
+ (isTranslationUnit() &&
+ !getParentASTContext().getLangOpts().CPlusPlus)))
makeDeclVisibleInContextImpl(ND, false);
// If this declaration is itself a transparent declaration context
@@ -1200,7 +1237,7 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx) {
// context (recursively).
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D))
if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace())
- buildLookupImpl(InnerCtx);
+ buildLookupImpl<Begin, End>(InnerCtx);
}
}
@@ -1223,16 +1260,14 @@ DeclContext::lookup(DeclarationName Name) {
if (!Map)
Map = CreateStoredDeclsMap(getParentASTContext());
- // If a PCH/module has a result for this name, and we have a local
- // declaration, we will have imported the PCH/module result when adding the
- // local declaration or when reconciling the module.
+ // If we have a lookup result with no external decls, we are done.
std::pair<StoredDeclsMap::iterator, bool> R =
Map->insert(std::make_pair(Name, StoredDeclsList()));
- if (!R.second)
+ if (!R.second && !R.first->second.hasExternalDecls())
return R.first->second.getLookupResult();
ExternalASTSource *Source = getParentASTContext().getExternalSource();
- if (Source->FindExternalVisibleDeclsByName(this, Name)) {
+ if (Source->FindExternalVisibleDeclsByName(this, Name) || R.second) {
if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
StoredDeclsMap::iterator I = Map->find(Name);
if (I != Map->end())
@@ -1257,6 +1292,46 @@ DeclContext::lookup(DeclarationName Name) {
return I->second.getLookupResult();
}
+DeclContext::lookup_result
+DeclContext::noload_lookup(DeclarationName Name) {
+ assert(DeclKind != Decl::LinkageSpec &&
+ "Should not perform lookups into linkage specs!");
+ if (!hasExternalVisibleStorage())
+ return lookup(Name);
+
+ DeclContext *PrimaryContext = getPrimaryContext();
+ if (PrimaryContext != this)
+ return PrimaryContext->noload_lookup(Name);
+
+ StoredDeclsMap *Map = LookupPtr.getPointer();
+ if (LookupPtr.getInt()) {
+ // Carefully build the lookup map, without deserializing anything.
+ SmallVector<DeclContext *, 2> Contexts;
+ collectAllContexts(Contexts);
+ for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
+ buildLookupImpl<&DeclContext::noload_decls_begin,
+ &DeclContext::noload_decls_end>(Contexts[I]);
+
+ // We no longer have any lazy decls.
+ LookupPtr.setInt(false);
+
+ // There may now be names for which we have local decls but are
+ // missing the external decls. FIXME: Just set the hasExternalDecls
+ // flag on those names that have external decls.
+ NeedToReconcileExternalVisibleStorage = true;
+
+ Map = LookupPtr.getPointer();
+ }
+
+ if (!Map)
+ return lookup_result(lookup_iterator(0), lookup_iterator(0));
+
+ StoredDeclsMap::iterator I = Map->find(Name);
+ return I != Map->end()
+ ? I->second.getLookupResult()
+ : lookup_result(lookup_iterator(0), lookup_iterator(0));
+}
+
void DeclContext::localUncachedLookup(DeclarationName Name,
SmallVectorImpl<NamedDecl *> &Results) {
Results.clear();
@@ -1338,14 +1413,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal,
assert(this == getPrimaryContext() && "expected a primary DC");
// Skip declarations within functions.
- // FIXME: We shouldn't need to build lookup tables for function declarations
- // ever, and we can't do so correctly because we can't model the nesting of
- // scopes which occurs within functions. We use "qualified" lookup into
- // function declarations when handling friend declarations inside nested
- // classes, and consequently accept the following invalid code:
- //
- // void f() { void g(); { int g; struct S { friend void g(); }; } }
- if (isFunctionOrMethod() && !isa<FunctionDecl>(D))
+ if (isFunctionOrMethod())
return;
// Skip declarations which should be invisible to name lookup.
@@ -1406,7 +1474,18 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) {
// Insert this declaration into the map.
StoredDeclsList &DeclNameEntries = (*Map)[D->getDeclName()];
- if (DeclNameEntries.isNull()) {
+
+ if (Internal) {
+ // If this is being added as part of loading an external declaration,
+ // this may not be the only external declaration with this name.
+ // In this case, we never try to replace an existing declaration; we'll
+ // handle that when we finalize the list of declarations for this name.
+ DeclNameEntries.setHasExternalDecls();
+ DeclNameEntries.AddSubsequentDecl(D);
+ return;
+ }
+
+ else if (DeclNameEntries.isNull()) {
DeclNameEntries.setOnlyValue(D);
return;
}
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 0646499..a17abdd 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -10,9 +10,9 @@
// This file implements the C++ related Decl classes.
//
//===----------------------------------------------------------------------===//
-
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclTemplate.h"
@@ -35,6 +35,17 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (Mem) AccessSpecDecl(EmptyShell());
}
+void LazyASTUnresolvedSet::getFromExternalSource(ASTContext &C) const {
+ ExternalASTSource *Source = C.getExternalSource();
+ assert(Impl.Decls.isLazy() && "getFromExternalSource for non-lazy set");
+ assert(Source && "getFromExternalSource with no external source");
+
+ for (ASTUnresolvedSet::iterator I = Impl.begin(); I != Impl.end(); ++I)
+ I.setDecl(cast<NamedDecl>(Source->GetExternalDecl(
+ reinterpret_cast<uintptr_t>(I.getDecl()) >> 2)));
+ Impl.Decls.setLazy(false);
+}
+
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
: UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0),
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
@@ -60,9 +71,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
ImplicitCopyAssignmentHasConstParam(true),
HasDeclaredCopyConstructorWithConstParam(false),
HasDeclaredCopyAssignmentWithConstParam(false),
- FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false),
IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
- Definition(D), FirstFriend(0) {
+ Definition(D), FirstFriend() {
}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
@@ -97,12 +107,17 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
TypeSourceInfo *Info, SourceLocation Loc,
- bool Dependent) {
+ bool Dependent, bool IsGeneric,
+ LambdaCaptureDefault CaptureDefault) {
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc,
0, 0);
R->IsBeingDefined = true;
- R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent);
+ R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info,
+ Dependent,
+ IsGeneric,
+ CaptureDefault);
R->MayHaveOutOfDateDef = false;
+ R->setImplicit(true);
C.getTypeDeclType(R, /*PrevDecl=*/0);
return R;
}
@@ -552,18 +567,16 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (Conversion->getPrimaryTemplate()) {
// We don't record specializations.
- } else if (FunTmpl) {
- if (FunTmpl->getPreviousDecl())
- data().Conversions.replace(FunTmpl->getPreviousDecl(),
- FunTmpl, AS);
- else
- data().Conversions.addDecl(getASTContext(), FunTmpl, AS);
} else {
- if (Conversion->getPreviousDecl())
- data().Conversions.replace(Conversion->getPreviousDecl(),
- Conversion, AS);
+ ASTContext &Ctx = getASTContext();
+ ASTUnresolvedSet &Conversions = data().Conversions.get(Ctx);
+ NamedDecl *Primary =
+ FunTmpl ? cast<NamedDecl>(FunTmpl) : cast<NamedDecl>(Conversion);
+ if (Primary->getPreviousDecl())
+ Conversions.replace(cast<NamedDecl>(Primary->getPreviousDecl()),
+ Primary, AS);
else
- data().Conversions.addDecl(getASTContext(), Conversion, AS);
+ Conversions.addDecl(Ctx, Primary, AS);
}
}
@@ -662,7 +675,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (!Context.getLangOpts().ObjCAutoRefCount ||
T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone)
setHasObjectMember(true);
- } else if (!T.isPODType(Context))
+ } else if (!T.isCXX98PODType(Context))
data().PlainOldData = false;
if (T->isReferenceType()) {
@@ -712,6 +725,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
if (FieldRec->getDefinition()) {
addedClassSubobject(FieldRec);
+ // We may need to perform overload resolution to determine whether a
+ // field can be moved if it's const or volatile qualified.
+ if (T.getCVRQualifiers() & (Qualifiers::Const | Qualifiers::Volatile)) {
+ data().NeedOverloadResolutionForMoveConstructor = true;
+ data().NeedOverloadResolutionForMoveAssignment = true;
+ }
+
// C++11 [class.ctor]p5, C++11 [class.copy]p11:
// A defaulted [special member] for a class X is defined as
// deleted if:
@@ -880,10 +900,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
}
// Handle using declarations of conversion functions.
- if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D))
+ if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) {
if (Shadow->getDeclName().getNameKind()
- == DeclarationName::CXXConversionFunctionName)
- data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess());
+ == DeclarationName::CXXConversionFunctionName) {
+ ASTContext &Ctx = getASTContext();
+ data().Conversions.get(Ctx).addDecl(Ctx, Shadow, Shadow->getAccess());
+ }
+ }
}
void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
@@ -929,6 +952,43 @@ bool CXXRecordDecl::isCLike() const {
return isPOD() && data().HasOnlyCMembers;
}
+
+bool CXXRecordDecl::isGenericLambda() const {
+ if (!isLambda()) return false;
+ return getLambdaData().IsGenericLambda;
+}
+
+CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const {
+ if (!isLambda()) return 0;
+ DeclarationName Name =
+ getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
+ DeclContext::lookup_const_result Calls = lookup(Name);
+
+ assert(!Calls.empty() && "Missing lambda call operator!");
+ assert(Calls.size() == 1 && "More than one lambda call operator!");
+
+ NamedDecl *CallOp = Calls.front();
+ if (FunctionTemplateDecl *CallOpTmpl =
+ dyn_cast<FunctionTemplateDecl>(CallOp))
+ return cast<CXXMethodDecl>(CallOpTmpl->getTemplatedDecl());
+
+ return cast<CXXMethodDecl>(CallOp);
+}
+
+CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const {
+ if (!isLambda()) return 0;
+ DeclarationName Name =
+ &getASTContext().Idents.get(getLambdaStaticInvokerName());
+ DeclContext::lookup_const_result Invoker = lookup(Name);
+ if (Invoker.empty()) return 0;
+ assert(Invoker.size() == 1 && "More than one static invoker operator!");
+ NamedDecl *InvokerFun = Invoker.front();
+ if (FunctionTemplateDecl *InvokerTemplate =
+ dyn_cast<FunctionTemplateDecl>(InvokerFun))
+ return cast<CXXMethodDecl>(InvokerTemplate->getTemplatedDecl());
+
+ return cast<CXXMethodDecl>(InvokerFun);
+}
void CXXRecordDecl::getCaptureFields(
llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures,
@@ -940,15 +1000,22 @@ void CXXRecordDecl::getCaptureFields(
RecordDecl::field_iterator Field = field_begin();
for (LambdaExpr::Capture *C = Lambda.Captures, *CEnd = C + Lambda.NumCaptures;
C != CEnd; ++C, ++Field) {
- if (C->capturesThis()) {
+ if (C->capturesThis())
ThisCapture = *Field;
- continue;
- }
-
- Captures[C->getCapturedVar()] = *Field;
+ else if (C->capturesVariable())
+ Captures[C->getCapturedVar()] = *Field;
}
+ assert(Field == field_end());
}
+TemplateParameterList *
+CXXRecordDecl::getGenericLambdaTemplateParameterList() const {
+ if (!isLambda()) return 0;
+ CXXMethodDecl *CallOp = getLambdaCallOperator();
+ if (FunctionTemplateDecl *Tmpl = CallOp->getDescribedFunctionTemplate())
+ return Tmpl->getTemplateParameters();
+ return 0;
+}
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
QualType T;
@@ -1085,16 +1152,21 @@ static void CollectVisibleConversions(ASTContext &Context,
/// in current class; including conversion function templates.
std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator>
CXXRecordDecl::getVisibleConversionFunctions() {
- // If root class, all conversions are visible.
- if (bases_begin() == bases_end())
- return std::make_pair(data().Conversions.begin(), data().Conversions.end());
- // If visible conversion list is already evaluated, return it.
- if (!data().ComputedVisibleConversions) {
- CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
- data().ComputedVisibleConversions = true;
+ ASTContext &Ctx = getASTContext();
+
+ ASTUnresolvedSet *Set;
+ if (bases_begin() == bases_end()) {
+ // If root class, all conversions are visible.
+ Set = &data().Conversions.get(Ctx);
+ } else {
+ Set = &data().VisibleConversions.get(Ctx);
+ // If visible conversion list is not evaluated, evaluate it.
+ if (!data().ComputedVisibleConversions) {
+ CollectVisibleConversions(Ctx, this, *Set);
+ data().ComputedVisibleConversions = true;
+ }
}
- return std::make_pair(data().VisibleConversions.begin(),
- data().VisibleConversions.end());
+ return std::make_pair(Set->begin(), Set->end());
}
void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
@@ -1109,7 +1181,7 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
// with sufficiently large numbers of directly-declared conversions
// that asymptotic behavior matters.
- ASTUnresolvedSet &Convs = data().Conversions;
+ ASTUnresolvedSet &Convs = data().Conversions.get(getASTContext());
for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
if (Convs[I].getDecl() == ConvDecl) {
Convs.erase(I);
@@ -1134,7 +1206,7 @@ CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
TemplateSpecializationKind TSK) {
assert(TemplateOrInstantiation.isNull() &&
"Previous template or instantiation?");
- assert(!isa<ClassTemplateSpecializationDecl>(this));
+ assert(!isa<ClassTemplatePartialSpecializationDecl>(this));
TemplateOrInstantiation
= new (getASTContext()) MemberSpecializationInfo(RD, TSK);
}
@@ -1235,8 +1307,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
}
// Set access bits correctly on the directly-declared conversions.
- for (UnresolvedSetIterator I = data().Conversions.begin(),
- E = data().Conversions.end();
+ for (conversion_iterator I = conversion_begin(), E = conversion_end();
I != E; ++I)
I.setAccess((*I)->getAccess());
}
@@ -1266,21 +1337,8 @@ bool CXXMethodDecl::isStatic() const {
if (MD->getStorageClass() == SC_Static)
return true;
- DeclarationName Name = getDeclName();
- // [class.free]p1:
- // Any allocation function for a class T is a static member
- // (even if not explicitly declared static).
- if (Name.getCXXOverloadedOperator() == OO_New ||
- Name.getCXXOverloadedOperator() == OO_Array_New)
- return true;
-
- // [class.free]p6 Any deallocation function for a class X is a static member
- // (even if not explicitly declared static).
- if (Name.getCXXOverloadedOperator() == OO_Delete ||
- Name.getCXXOverloadedOperator() == OO_Array_Delete)
- return true;
-
- return false;
+ OverloadedOperatorKind OOK = getDeclName().getCXXOverloadedOperator();
+ return isStaticOverloadedOperator(OOK);
}
static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD,
@@ -1408,7 +1466,8 @@ bool CXXMethodDecl::isCopyAssignmentOperator() const {
// type X, X&, const X&, volatile X& or const volatile X&.
if (/*operator=*/getOverloadedOperator() != OO_Equal ||
/*non-static*/ isStatic() ||
- /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate())
+ /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate() ||
+ getNumParams() != 1)
return false;
QualType ParamType = getParamDecl(0)->getType();
@@ -1427,7 +1486,8 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const {
// non-template member function of class X with exactly one parameter of type
// X&&, const X&&, volatile X&&, or const volatile X&&.
if (getOverloadedOperator() != OO_Equal || isStatic() ||
- getPrimaryTemplate() || getDescribedFunctionTemplate())
+ getPrimaryTemplate() || getDescribedFunctionTemplate() ||
+ getNumParams() != 1)
return false;
QualType ParamType = getParamDecl(0)->getType();
@@ -1492,11 +1552,17 @@ bool CXXMethodDecl::hasInlineBody() const {
}
bool CXXMethodDecl::isLambdaStaticInvoker() const {
- return getParent()->isLambda() &&
- getIdentifier() && getIdentifier()->getName() == "__invoke";
+ const CXXRecordDecl *P = getParent();
+ if (P->isLambda()) {
+ if (const CXXMethodDecl *StaticInvoker = P->getLambdaStaticInvoker()) {
+ if (StaticInvoker == this) return true;
+ if (P->isGenericLambda() && this->isFunctionTemplateSpecialization())
+ return StaticInvoker == this->getPrimaryTemplate()->getTemplatedDecl();
+ }
+ }
+ return false;
}
-
CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
TypeSourceInfo *TInfo, bool IsVirtual,
SourceLocation L, Expr *Init,
@@ -1865,7 +1931,7 @@ NamespaceDecl::NamespaceDecl(DeclContext *DC, bool Inline,
: NamedDecl(Namespace, DC, IdLoc, Id), DeclContext(Namespace),
LocStart(StartLoc), RBraceLoc(), AnonOrFirstNamespaceAndInline(0, Inline)
{
- setPreviousDeclaration(PrevDecl);
+ setPreviousDecl(PrevDecl);
if (PrevDecl)
AnonOrFirstNamespaceAndInline.setPointer(PrevDecl->getOriginalNamespace());
@@ -1959,8 +2025,8 @@ void UsingDecl::removeShadowDecl(UsingShadowDecl *S) {
UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo,
- bool IsTypeNameArg) {
- return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, IsTypeNameArg);
+ bool HasTypename) {
+ return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename);
}
UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
@@ -1969,6 +2035,12 @@ UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
DeclarationNameInfo(), false);
}
+SourceRange UsingDecl::getSourceRange() const {
+ SourceLocation Begin = isAccessDeclaration()
+ ? getQualifierLoc().getBeginLoc() : UsingLocation;
+ return SourceRange(Begin, getNameInfo().getEndLoc());
+}
+
void UnresolvedUsingValueDecl::anchor() { }
UnresolvedUsingValueDecl *
@@ -1988,6 +2060,12 @@ UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
DeclarationNameInfo());
}
+SourceRange UnresolvedUsingValueDecl::getSourceRange() const {
+ SourceLocation Begin = isAccessDeclaration()
+ ? getQualifierLoc().getBeginLoc() : UsingLocation;
+ return SourceRange(Begin, getNameInfo().getEndLoc());
+}
+
void UnresolvedUsingTypenameDecl::anchor() { }
UnresolvedUsingTypenameDecl *
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
index 37a812e..1c639d6 100644
--- a/lib/AST/DeclFriend.cpp
+++ b/lib/AST/DeclFriend.cpp
@@ -63,3 +63,8 @@ FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID,
return new (Mem) FriendDecl(EmptyShell(), FriendTypeNumTPLists);
}
+FriendDecl *CXXRecordDecl::getFirstFriend() const {
+ ExternalASTSource *Source = getParentASTContext().getExternalSource();
+ Decl *First = data().FirstFriend.get(Source);
+ return First ? cast<FriendDecl>(First) : 0;
+}
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 4ddbb22..b2b5b70 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -441,6 +441,17 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass(
return NULL;
}
+ObjCProtocolDecl *
+ObjCInterfaceDecl::lookupNestedProtocol(IdentifierInfo *Name) {
+ for (ObjCInterfaceDecl::all_protocol_iterator P =
+ all_referenced_protocol_begin(), PE = all_referenced_protocol_end();
+ P != PE; ++P)
+ if ((*P)->lookupProtocolNamed(Name))
+ return (*P);
+ ObjCInterfaceDecl *SuperClass = getSuperClass();
+ return SuperClass ? SuperClass->lookupNestedProtocol(Name) : NULL;
+}
+
/// lookupMethod - This method returns an instance/class method by looking in
/// the class, its categories, and its super classes (using a linear search).
/// When argument category "C" is specified, any implicit method found
@@ -627,23 +638,29 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() {
Decl *CtxD = cast<Decl>(getDeclContext());
- if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
- if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD))
- Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
-
- } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) {
- if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD))
- Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
-
- } else if (ObjCImplementationDecl *ImplD =
- dyn_cast<ObjCImplementationDecl>(CtxD)) {
- if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
- Redecl = IFD->getMethod(getSelector(), isInstanceMethod());
-
- } else if (ObjCCategoryImplDecl *CImplD =
- dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
- if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
- Redecl = CatD->getMethod(getSelector(), isInstanceMethod());
+ if (!CtxD->isInvalidDecl()) {
+ if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) {
+ if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD))
+ if (!ImplD->isInvalidDecl())
+ Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) {
+ if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD))
+ if (!ImplD->isInvalidDecl())
+ Redecl = ImplD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCImplementationDecl *ImplD =
+ dyn_cast<ObjCImplementationDecl>(CtxD)) {
+ if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface())
+ if (!IFD->isInvalidDecl())
+ Redecl = IFD->getMethod(getSelector(), isInstanceMethod());
+
+ } else if (ObjCCategoryImplDecl *CImplD =
+ dyn_cast<ObjCCategoryImplDecl>(CtxD)) {
+ if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl())
+ if (!CatD->isInvalidDecl())
+ Redecl = CatD->getMethod(getSelector(), isInstanceMethod());
+ }
}
if (!Redecl && isRedeclaration()) {
@@ -1062,7 +1079,7 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
: ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, atLoc),
TypeForDecl(0), Data()
{
- setPreviousDeclaration(PrevDecl);
+ setPreviousDecl(PrevDecl);
// Copy the 'data' pointer over.
if (PrevDecl)
@@ -1308,7 +1325,8 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW,
- bool synthesized) {
+ bool synthesized,
+ bool backingIvarReferencedInAccessor) {
if (DC) {
// Ivar's can only appear in interfaces, implementations (via synthesized
// properties), and class extensions (via direct declaration, or synthesized
@@ -1336,13 +1354,13 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC,
}
return new (C) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo,
- ac, BW, synthesized);
+ ac, BW, synthesized, backingIvarReferencedInAccessor);
}
ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCIvarDecl));
return new (Mem) ObjCIvarDecl(0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, ObjCIvarDecl::None, 0, false);
+ QualType(), 0, ObjCIvarDecl::None, 0, false, false);
}
const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
@@ -1401,7 +1419,7 @@ ObjCProtocolDecl::ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id,
ObjCProtocolDecl *PrevDecl)
: ObjCContainerDecl(ObjCProtocol, DC, Id, nameLoc, atStartLoc), Data()
{
- setPreviousDeclaration(PrevDecl);
+ setPreviousDecl(PrevDecl);
if (PrevDecl)
Data = PrevDecl->Data;
}
@@ -1493,6 +1511,30 @@ void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
}
}
+
+void ObjCProtocolDecl::collectInheritedProtocolProperties(
+ const ObjCPropertyDecl *Property,
+ ProtocolPropertyMap &PM) const {
+ if (const ObjCProtocolDecl *PDecl = getDefinition()) {
+ bool MatchFound = false;
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ if (Prop == Property)
+ continue;
+ if (Prop->getIdentifier() == Property->getIdentifier()) {
+ PM[PDecl] = Prop;
+ MatchFound = true;
+ break;
+ }
+ }
+ // Scan through protocol's protocols which did not have a matching property.
+ if (!MatchFound)
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ (*PI)->collectInheritedProtocolProperties(Property, PM);
+ }
+}
//===----------------------------------------------------------------------===//
// ObjCCategoryDecl
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
index c0d10a0..0d195f7 100644
--- a/lib/AST/DeclOpenMP.cpp
+++ b/lib/AST/DeclOpenMP.cpp
@@ -28,9 +28,9 @@ void OMPThreadPrivateDecl::anchor() { }
OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
- ArrayRef<DeclRefExpr *> VL) {
+ ArrayRef<Expr *> VL) {
unsigned Size = sizeof(OMPThreadPrivateDecl) +
- (VL.size() * sizeof(DeclRefExpr *));
+ (VL.size() * sizeof(Expr *));
void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>());
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
@@ -43,7 +43,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned N) {
- unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *));
+ unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *));
void *Mem = AllocateDeserializedDecl(C, ID, Size);
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
@@ -52,9 +52,10 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
return D;
}
-void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) {
+void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) {
assert(VL.size() == NumVars &&
"Number of variables is not the same as the preallocated buffer");
- DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1);
+ Expr **Vars = reinterpret_cast<Expr **>(this + 1);
std::copy(VL.begin(), VL.end(), Vars);
}
+
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index d47972b..767f662 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -260,6 +260,8 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
QualType CurDeclType = getDeclType(*D);
if (!Decls.empty() && !CurDeclType.isNull()) {
QualType BaseType = GetBaseType(CurDeclType);
+ if (!BaseType.isNull() && isa<ElaboratedType>(BaseType))
+ BaseType = cast<ElaboratedType>(BaseType)->getNamedType();
if (!BaseType.isNull() && isa<TagType>(BaseType) &&
cast<TagType>(BaseType)->getDecl() == Decls[0]) {
Decls.push_back(*D);
@@ -337,12 +339,14 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
if (D->isModulePrivate())
Out << "__module_private__ ";
}
- D->getUnderlyingType().print(Out, Policy, D->getName());
+ D->getTypeSourceInfo()->getType().print(Out, Policy, D->getName());
prettyPrintAttributes(D);
}
void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) {
- Out << "using " << *D << " = " << D->getUnderlyingType().getAsString(Policy);
+ Out << "using " << *D;
+ prettyPrintAttributes(D);
+ Out << " = " << D->getTypeSourceInfo()->getType().getAsString(Policy);
}
void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
@@ -665,9 +669,9 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
Out << "__module_private__ ";
}
- QualType T = D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
- if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D))
- T = Parm->getOriginalType();
+ QualType T = D->getTypeSourceInfo()
+ ? D->getTypeSourceInfo()->getType()
+ : D->getASTContext().getUnqualifiedObjCPointerType(D->getType());
T.print(Out, Policy, D->getName());
Expr *Init = D->getInit();
if (!Policy.SuppressInitializers && Init) {
@@ -1153,7 +1157,10 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
}
void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
- Out << "using ";
+ if (!D->isAccessDeclaration())
+ Out << "using ";
+ if (D->hasTypename())
+ Out << "typename ";
D->getQualifier()->print(Out, Policy);
Out << *D;
}
@@ -1166,7 +1173,8 @@ DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
}
void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
- Out << "using ";
+ if (!D->isAccessDeclaration())
+ Out << "using ";
D->getQualifier()->print(Out, Policy);
Out << D->getName();
}
@@ -1180,9 +1188,10 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
if (!D->varlist_empty()) {
for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
E = D->varlist_end();
- I != E; ++I) {
- Out << (I == D->varlist_begin() ? '(' : ',')
- << *cast<NamedDecl>((*I)->getDecl());
+ I != E; ++I) {
+ Out << (I == D->varlist_begin() ? '(' : ',');
+ NamedDecl *ND = cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl());
+ ND->printQualifiedName(Out);
}
Out << ")";
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 0b94f7d..7172fb7 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -129,33 +129,34 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
//===----------------------------------------------------------------------===//
RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const {
- if (!Common) {
- // Walk the previous-declaration chain until we either find a declaration
- // with a common pointer or we run out of previous declarations.
- SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
- for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
- Prev = Prev->getPreviousDecl()) {
- if (Prev->Common) {
- Common = Prev->Common;
- break;
- }
-
- PrevDecls.push_back(Prev);
+ if (Common)
+ return Common;
+
+ // Walk the previous-declaration chain until we either find a declaration
+ // with a common pointer or we run out of previous declarations.
+ SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
+ for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
+ Prev = Prev->getPreviousDecl()) {
+ if (Prev->Common) {
+ Common = Prev->Common;
+ break;
}
- // If we never found a common pointer, allocate one now.
- if (!Common) {
- // FIXME: If any of the declarations is from an AST file, we probably
- // need an update record to add the common data.
-
- Common = newCommon(getASTContext());
- }
-
- // Update any previous declarations we saw with the common pointer.
- for (unsigned I = 0, N = PrevDecls.size(); I != N; ++I)
- PrevDecls[I]->Common = Common;
+ PrevDecls.push_back(Prev);
+ }
+
+ // If we never found a common pointer, allocate one now.
+ if (!Common) {
+ // FIXME: If any of the declarations is from an AST file, we probably
+ // need an update record to add the common data.
+
+ Common = newCommon(getASTContext());
}
+ // Update any previous declarations we saw with the common pointer.
+ for (unsigned I = 0, N = PrevDecls.size(); I != N; ++I)
+ PrevDecls[I]->Common = Common;
+
return Common;
}
@@ -245,6 +246,23 @@ FunctionTemplateDecl::newCommon(ASTContext &C) const {
return CommonPtr;
}
+void FunctionTemplateDecl::LoadLazySpecializations() const {
+ Common *CommonPtr = getCommonPtr();
+ if (CommonPtr->LazySpecializations) {
+ ASTContext &Context = getASTContext();
+ uint32_t *Specs = CommonPtr->LazySpecializations;
+ CommonPtr->LazySpecializations = 0;
+ for (uint32_t I = 0, N = *Specs++; I != N; ++I)
+ (void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
+ }
+}
+
+llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
+FunctionTemplateDecl::getSpecializations() const {
+ LoadLazySpecializations();
+ return getCommonPtr()->Specializations;
+}
+
FunctionDecl *
FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args,
unsigned NumArgs, void *&InsertPos) {
@@ -261,18 +279,17 @@ void FunctionTemplateDecl::addSpecialization(
L->AddedCXXTemplateSpecialization(this, Info->Function);
}
-std::pair<const TemplateArgument *, unsigned>
-FunctionTemplateDecl::getInjectedTemplateArgs() {
+ArrayRef<TemplateArgument> FunctionTemplateDecl::getInjectedTemplateArgs() {
TemplateParameterList *Params = getTemplateParameters();
Common *CommonPtr = getCommonPtr();
if (!CommonPtr->InjectedArgs) {
CommonPtr->InjectedArgs
- = new (getASTContext()) TemplateArgument [Params->size()];
- GenerateInjectedTemplateArgs(getASTContext(), Params,
+ = new (getASTContext()) TemplateArgument[Params->size()];
+ GenerateInjectedTemplateArgs(getASTContext(), Params,
CommonPtr->InjectedArgs);
}
-
- return std::make_pair(CommonPtr->InjectedArgs, Params->size());
+
+ return llvm::makeArrayRef(CommonPtr->InjectedArgs, Params->size());
}
//===----------------------------------------------------------------------===//
@@ -292,7 +309,7 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
ClassTemplateDecl *PrevDecl) {
AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl);
- New->setPreviousDeclaration(PrevDecl);
+ New->setPreviousDecl(PrevDecl);
return New;
}
@@ -381,13 +398,11 @@ void ClassTemplateDecl::getPartialSpecializations(
llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl> &PartialSpecs
= getPartialSpecializations();
PS.clear();
- PS.resize(PartialSpecs.size());
+ PS.reserve(PartialSpecs.size());
for (llvm::FoldingSetVector<ClassTemplatePartialSpecializationDecl>::iterator
P = PartialSpecs.begin(), PEnd = PartialSpecs.end();
- P != PEnd; ++P) {
- assert(!PS[P->getSequenceNumber()]);
- PS[P->getSequenceNumber()] = P->getMostRecentDecl();
- }
+ P != PEnd; ++P)
+ PS.push_back(P->getMostRecentDecl());
}
ClassTemplatePartialSpecializationDecl *
@@ -813,19 +828,16 @@ ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
ClassTemplateDecl *SpecializedTemplate,
const TemplateArgument *Args,
unsigned NumArgs,
- TemplateArgumentLoc *ArgInfos,
- unsigned NumArgInfos,
- ClassTemplatePartialSpecializationDecl *PrevDecl,
- unsigned SequenceNumber)
+ const ASTTemplateArgumentListInfo *ArgInfos,
+ ClassTemplatePartialSpecializationDecl *PrevDecl)
: ClassTemplateSpecializationDecl(Context,
ClassTemplatePartialSpecialization,
TK, DC, StartLoc, IdLoc,
SpecializedTemplate,
Args, NumArgs, PrevDecl),
TemplateParams(Params), ArgsAsWritten(ArgInfos),
- NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber),
InstantiatedFromMember(0, false)
-{
+{
AdoptTemplateParameterList(Params, this);
}
@@ -839,12 +851,9 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
unsigned NumArgs,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
- ClassTemplatePartialSpecializationDecl *PrevDecl,
- unsigned SequenceNumber) {
- unsigned N = ArgInfos.size();
- TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N];
- for (unsigned I = 0; I != N; ++I)
- ClonedArgs[I] = ArgInfos[I];
+ ClassTemplatePartialSpecializationDecl *PrevDecl) {
+ const ASTTemplateArgumentListInfo *ASTArgInfos =
+ ASTTemplateArgumentListInfo::Create(Context, ArgInfos);
ClassTemplatePartialSpecializationDecl *Result
= new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC,
@@ -852,9 +861,8 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
Params,
SpecializedTemplate,
Args, NumArgs,
- ClonedArgs, N,
- PrevDecl,
- SequenceNumber);
+ ASTArgInfos,
+ PrevDecl);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
Result->MayHaveOutOfDateDef = false;
@@ -942,3 +950,252 @@ ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C,
return new (Mem) ClassScopeFunctionSpecializationDecl(0, SourceLocation(), 0,
false, TemplateArgumentListInfo());
}
+
+//===----------------------------------------------------------------------===//
+// VarTemplateDecl Implementation
+//===----------------------------------------------------------------------===//
+
+void VarTemplateDecl::DeallocateCommon(void *Ptr) {
+ static_cast<Common *>(Ptr)->~Common();
+}
+
+VarTemplateDecl *VarTemplateDecl::getDefinition() {
+ VarTemplateDecl *CurD = this;
+ while (CurD) {
+ if (CurD->isThisDeclarationADefinition())
+ return CurD;
+ CurD = CurD->getPreviousDecl();
+ }
+ return 0;
+}
+
+VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params,
+ NamedDecl *Decl,
+ VarTemplateDecl *PrevDecl) {
+ VarTemplateDecl *New = new (C) VarTemplateDecl(DC, L, Name, Params, Decl);
+ New->setPreviousDecl(PrevDecl);
+ return New;
+}
+
+VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarTemplateDecl));
+ return new (Mem) VarTemplateDecl(EmptyShell());
+}
+
+// TODO: Unify accross class, function and variable templates?
+// May require moving this and Common to RedeclarableTemplateDecl.
+void VarTemplateDecl::LoadLazySpecializations() const {
+ Common *CommonPtr = getCommonPtr();
+ if (CommonPtr->LazySpecializations) {
+ ASTContext &Context = getASTContext();
+ uint32_t *Specs = CommonPtr->LazySpecializations;
+ CommonPtr->LazySpecializations = 0;
+ for (uint32_t I = 0, N = *Specs++; I != N; ++I)
+ (void)Context.getExternalSource()->GetExternalDecl(Specs[I]);
+ }
+}
+
+llvm::FoldingSetVector<VarTemplateSpecializationDecl> &
+VarTemplateDecl::getSpecializations() const {
+ LoadLazySpecializations();
+ return getCommonPtr()->Specializations;
+}
+
+llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &
+VarTemplateDecl::getPartialSpecializations() {
+ LoadLazySpecializations();
+ return getCommonPtr()->PartialSpecializations;
+}
+
+RedeclarableTemplateDecl::CommonBase *
+VarTemplateDecl::newCommon(ASTContext &C) const {
+ Common *CommonPtr = new (C) Common;
+ C.AddDeallocation(DeallocateCommon, CommonPtr);
+ return CommonPtr;
+}
+
+VarTemplateSpecializationDecl *
+VarTemplateDecl::findSpecialization(const TemplateArgument *Args,
+ unsigned NumArgs, void *&InsertPos) {
+ return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos);
+}
+
+void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D,
+ void *InsertPos) {
+ if (InsertPos)
+ getSpecializations().InsertNode(D, InsertPos);
+ else {
+ VarTemplateSpecializationDecl *Existing =
+ getSpecializations().GetOrInsertNode(D);
+ (void)Existing;
+ assert(Existing->isCanonicalDecl() && "Non-canonical specialization?");
+ }
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, D);
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplateDecl::findPartialSpecialization(const TemplateArgument *Args,
+ unsigned NumArgs, void *&InsertPos) {
+ return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs,
+ InsertPos);
+}
+
+void VarTemplateDecl::AddPartialSpecialization(
+ VarTemplatePartialSpecializationDecl *D, void *InsertPos) {
+ if (InsertPos)
+ getPartialSpecializations().InsertNode(D, InsertPos);
+ else {
+ VarTemplatePartialSpecializationDecl *Existing =
+ getPartialSpecializations().GetOrInsertNode(D);
+ (void)Existing;
+ assert(Existing->isCanonicalDecl() && "Non-canonical specialization?");
+ }
+
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, D);
+}
+
+void VarTemplateDecl::getPartialSpecializations(
+ SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS) {
+ llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &PartialSpecs =
+ getPartialSpecializations();
+ PS.clear();
+ PS.reserve(PartialSpecs.size());
+ for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator
+ P = PartialSpecs.begin(),
+ PEnd = PartialSpecs.end();
+ P != PEnd; ++P)
+ PS.push_back(P->getMostRecentDecl());
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplateDecl::findPartialSpecInstantiatedFromMember(
+ VarTemplatePartialSpecializationDecl *D) {
+ Decl *DCanon = D->getCanonicalDecl();
+ for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator
+ P = getPartialSpecializations().begin(),
+ PEnd = getPartialSpecializations().end();
+ P != PEnd; ++P) {
+ if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon)
+ return P->getMostRecentDecl();
+ }
+
+ return 0;
+}
+
+//===----------------------------------------------------------------------===//
+// VarTemplateSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(
+ ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
+ TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
+ unsigned NumArgs)
+ : VarDecl(DK, DC, StartLoc, IdLoc, SpecializedTemplate->getIdentifier(), T,
+ TInfo, S),
+ SpecializedTemplate(SpecializedTemplate), ExplicitInfo(0),
+ TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)),
+ SpecializationKind(TSK_Undeclared) {}
+
+VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK)
+ : VarDecl(DK, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0,
+ SC_None),
+ ExplicitInfo(0), SpecializationKind(TSK_Undeclared) {}
+
+VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T,
+ TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args,
+ unsigned NumArgs) {
+ VarTemplateSpecializationDecl *Result = new (Context)
+ VarTemplateSpecializationDecl(Context, VarTemplateSpecialization, DC,
+ StartLoc, IdLoc, SpecializedTemplate, T,
+ TInfo, S, Args, NumArgs);
+ return Result;
+}
+
+VarTemplateSpecializationDecl *
+VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem =
+ AllocateDeserializedDecl(C, ID, sizeof(VarTemplateSpecializationDecl));
+ VarTemplateSpecializationDecl *Result =
+ new (Mem) VarTemplateSpecializationDecl(VarTemplateSpecialization);
+ return Result;
+}
+
+void VarTemplateSpecializationDecl::getNameForDiagnostic(
+ raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(OS, Policy, Qualified);
+
+ const TemplateArgumentList &TemplateArgs = getTemplateArgs();
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, TemplateArgs.data(), TemplateArgs.size(), Policy);
+}
+
+VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const {
+ if (SpecializedPartialSpecialization *PartialSpec =
+ SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>())
+ return PartialSpec->PartialSpecialization->getSpecializedTemplate();
+ return SpecializedTemplate.get<VarTemplateDecl *>();
+}
+
+void VarTemplateSpecializationDecl::setTemplateArgsInfo(
+ const TemplateArgumentListInfo &ArgsInfo) {
+ unsigned N = ArgsInfo.size();
+ TemplateArgsInfo.setLAngleLoc(ArgsInfo.getLAngleLoc());
+ TemplateArgsInfo.setRAngleLoc(ArgsInfo.getRAngleLoc());
+ for (unsigned I = 0; I != N; ++I)
+ TemplateArgsInfo.addArgument(ArgsInfo[I]);
+}
+
+//===----------------------------------------------------------------------===//
+// VarTemplatePartialSpecializationDecl Implementation
+//===----------------------------------------------------------------------===//
+void VarTemplatePartialSpecializationDecl::anchor() {}
+
+VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, TemplateParameterList *Params,
+ VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
+ const ASTTemplateArgumentListInfo *ArgInfos)
+ : VarTemplateSpecializationDecl(Context, VarTemplatePartialSpecialization,
+ DC, StartLoc, IdLoc, SpecializedTemplate, T,
+ TInfo, S, Args, NumArgs),
+ TemplateParams(Params), ArgsAsWritten(ArgInfos),
+ InstantiatedFromMember(0, false) {
+ // TODO: The template parameters should be in DC by now. Verify.
+ // AdoptTemplateParameterList(Params, DC);
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplatePartialSpecializationDecl::Create(
+ ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
+ SourceLocation IdLoc, TemplateParameterList *Params,
+ VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
+ StorageClass S, const TemplateArgument *Args, unsigned NumArgs,
+ const TemplateArgumentListInfo &ArgInfos) {
+ const ASTTemplateArgumentListInfo *ASTArgInfos
+ = ASTTemplateArgumentListInfo::Create(Context, ArgInfos);
+
+ VarTemplatePartialSpecializationDecl *Result =
+ new (Context) VarTemplatePartialSpecializationDecl(
+ Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo,
+ S, Args, NumArgs, ASTArgInfos);
+ Result->setSpecializationKind(TSK_ExplicitSpecialization);
+ return Result;
+}
+
+VarTemplatePartialSpecializationDecl *
+VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(
+ C, ID, sizeof(VarTemplatePartialSpecializationDecl));
+ VarTemplatePartialSpecializationDecl *Result =
+ new (Mem) VarTemplatePartialSpecializationDecl();
+ return Result;
+}
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index e4a41b6..e064e23 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -133,6 +133,66 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
llvm_unreachable("Invalid DeclarationName Kind!");
}
+raw_ostream &operator<<(raw_ostream &OS, DeclarationName N) {
+ switch (N.getNameKind()) {
+ case DeclarationName::Identifier:
+ if (const IdentifierInfo *II = N.getAsIdentifierInfo())
+ OS << II->getName();
+ return OS;
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ return OS << N.getObjCSelector().getAsString();
+
+ case DeclarationName::CXXConstructorName: {
+ QualType ClassType = N.getCXXNameType();
+ if (const RecordType *ClassRec = ClassType->getAs<RecordType>())
+ return OS << *ClassRec->getDecl();
+ return OS << ClassType.getAsString();
+ }
+
+ case DeclarationName::CXXDestructorName: {
+ OS << '~';
+ QualType Type = N.getCXXNameType();
+ if (const RecordType *Rec = Type->getAs<RecordType>())
+ return OS << *Rec->getDecl();
+ return OS << Type.getAsString();
+ }
+
+ case DeclarationName::CXXOperatorName: {
+ static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
+ 0,
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+ Spelling,
+#include "clang/Basic/OperatorKinds.def"
+ };
+ const char *OpName = OperatorNames[N.getCXXOverloadedOperator()];
+ assert(OpName && "not an overloaded operator");
+
+ OS << "operator";
+ if (OpName[0] >= 'a' && OpName[0] <= 'z')
+ OS << ' ';
+ return OS << OpName;
+ }
+
+ case DeclarationName::CXXLiteralOperatorName:
+ return OS << "operator \"\" " << N.getCXXLiteralIdentifier()->getName();
+
+ case DeclarationName::CXXConversionFunctionName: {
+ OS << "operator ";
+ QualType Type = N.getCXXNameType();
+ if (const RecordType *Rec = Type->getAs<RecordType>())
+ return OS << *Rec->getDecl();
+ return OS << Type.getAsString();
+ }
+ case DeclarationName::CXXUsingDirective:
+ return OS << "<using-directive>";
+ }
+
+ llvm_unreachable("Unexpected declaration name kind");
+}
+
} // end namespace clang
DeclarationName::NameKind DeclarationName::getNameKind() const {
@@ -180,80 +240,10 @@ bool DeclarationName::isDependentName() const {
std::string DeclarationName::getAsString() const {
std::string Result;
llvm::raw_string_ostream OS(Result);
- printName(OS);
+ OS << *this;
return OS.str();
}
-void DeclarationName::printName(raw_ostream &OS) const {
- switch (getNameKind()) {
- case Identifier:
- if (const IdentifierInfo *II = getAsIdentifierInfo())
- OS << II->getName();
- return;
-
- case ObjCZeroArgSelector:
- case ObjCOneArgSelector:
- case ObjCMultiArgSelector:
- OS << getObjCSelector().getAsString();
- return;
-
- case CXXConstructorName: {
- QualType ClassType = getCXXNameType();
- if (const RecordType *ClassRec = ClassType->getAs<RecordType>())
- OS << *ClassRec->getDecl();
- else
- OS << ClassType.getAsString();
- return;
- }
-
- case CXXDestructorName: {
- OS << '~';
- QualType Type = getCXXNameType();
- if (const RecordType *Rec = Type->getAs<RecordType>())
- OS << *Rec->getDecl();
- else
- OS << Type.getAsString();
- return;
- }
-
- case CXXOperatorName: {
- static const char* const OperatorNames[NUM_OVERLOADED_OPERATORS] = {
- 0,
-#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
- Spelling,
-#include "clang/Basic/OperatorKinds.def"
- };
- const char *OpName = OperatorNames[getCXXOverloadedOperator()];
- assert(OpName && "not an overloaded operator");
-
- OS << "operator";
- if (OpName[0] >= 'a' && OpName[0] <= 'z')
- OS << ' ';
- OS << OpName;
- return;
- }
-
- case CXXLiteralOperatorName:
- OS << "operator \"\" " << getCXXLiteralIdentifier()->getName();
- return;
-
- case CXXConversionFunctionName: {
- OS << "operator ";
- QualType Type = getCXXNameType();
- if (const RecordType *Rec = Type->getAs<RecordType>())
- OS << *Rec->getDecl();
- else
- OS << Type.getAsString();
- return;
- }
- case CXXUsingDirective:
- OS << "<using-directive>";
- return;
- }
-
- llvm_unreachable("Unexpected declaration name kind");
-}
-
QualType DeclarationName::getCXXNameType() const {
if (CXXSpecialName *CXXName = getAsCXXSpecialName())
return CXXName->Type;
@@ -336,8 +326,7 @@ DeclarationName DeclarationName::getUsingDirectiveName() {
}
void DeclarationName::dump() const {
- printName(llvm::errs());
- llvm::errs() << '\n';
+ llvm::errs() << *this << '\n';
}
DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) {
@@ -537,7 +526,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
case DeclarationName::CXXOperatorName:
case DeclarationName::CXXLiteralOperatorName:
case DeclarationName::CXXUsingDirective:
- Name.printName(OS);
+ OS << Name;
return;
case DeclarationName::CXXConstructorName:
@@ -549,9 +538,8 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const {
else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
OS << "operator ";
OS << TInfo->getType().getAsString();
- }
- else
- Name.printName(OS);
+ } else
+ OS << Name;
return;
}
llvm_unreachable("Unexpected declaration name kind");
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
deleted file mode 100644
index be22ae4..0000000
--- a/lib/AST/DumpXML.cpp
+++ /dev/null
@@ -1,1053 +0,0 @@
-//===--- DumpXML.cpp - Detailed XML dumping -------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the Decl::dumpXML() method, a debugging tool to
-// print a detailed graph of an AST in an unspecified XML format.
-//
-// There is no guarantee of stability for this format.
-//
-//===----------------------------------------------------------------------===//
-
-// Only pay for this in code size in assertions-enabled builds.
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Attr.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclFriend.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/DeclVisitor.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/NestedNameSpecifier.h"
-#include "clang/AST/Stmt.h"
-#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/TemplateBase.h"
-#include "clang/AST/TemplateName.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/TypeLoc.h"
-#include "clang/AST/TypeLocVisitor.h"
-#include "clang/AST/TypeVisitor.h"
-#include "llvm/ADT/SmallString.h"
-
-using namespace clang;
-
-#ifndef NDEBUG
-
-namespace {
-
-enum NodeState {
- NS_Attrs, NS_LazyChildren, NS_Children
-};
-
-struct Node {
- StringRef Name;
- NodeState State;
- Node(StringRef name) : Name(name), State(NS_Attrs) {}
-
- bool isDoneWithAttrs() const { return State != NS_Attrs; }
-};
-
-template <class Impl> struct XMLDeclVisitor {
-#define DISPATCH(NAME, CLASS) \
- static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(D))
-
- void dispatch(Decl *D) {
- if (D->isUsed())
- static_cast<Impl*>(this)->set("used", "1");
- switch (D->getKind()) {
-#define DECL(DERIVED, BASE) \
- case Decl::DERIVED: \
- DISPATCH(dispatch##DERIVED##DeclAttrs, DERIVED##Decl); \
- static_cast<Impl*>(this)->completeAttrs(); \
- DISPATCH(dispatch##DERIVED##DeclChildren, DERIVED##Decl); \
- DISPATCH(dispatch##DERIVED##DeclAsContext, DERIVED##Decl); \
- break;
-#define ABSTRACT_DECL(DECL)
-#include "clang/AST/DeclNodes.inc"
- }
- }
-
-#define DECL(DERIVED, BASE) \
- void dispatch##DERIVED##DeclAttrs(DERIVED##Decl *D) { \
- DISPATCH(dispatch##BASE##Attrs, BASE); \
- DISPATCH(visit##DERIVED##DeclAttrs, DERIVED##Decl); \
- } \
- void visit##DERIVED##DeclAttrs(DERIVED##Decl *D) {} \
- void dispatch##DERIVED##DeclChildren(DERIVED##Decl *D) { \
- DISPATCH(dispatch##BASE##Children, BASE); \
- DISPATCH(visit##DERIVED##DeclChildren, DERIVED##Decl); \
- } \
- void visit##DERIVED##DeclChildren(DERIVED##Decl *D) {} \
- void dispatch##DERIVED##DeclAsContext(DERIVED##Decl *D) { \
- DISPATCH(dispatch##BASE##AsContext, BASE); \
- DISPATCH(visit##DERIVED##DeclAsContext, DERIVED##Decl); \
- } \
- void visit##DERIVED##DeclAsContext(DERIVED##Decl *D) {}
-#include "clang/AST/DeclNodes.inc"
-
- void dispatchDeclAttrs(Decl *D) {
- DISPATCH(visitDeclAttrs, Decl);
- }
- void visitDeclAttrs(Decl *D) {}
-
- void dispatchDeclChildren(Decl *D) {
- DISPATCH(visitDeclChildren, Decl);
- }
- void visitDeclChildren(Decl *D) {}
-
- void dispatchDeclAsContext(Decl *D) {
- DISPATCH(visitDeclAsContext, Decl);
- }
- void visitDeclAsContext(Decl *D) {}
-
-#undef DISPATCH
-};
-
-template <class Impl> struct XMLTypeVisitor {
-#define DISPATCH(NAME, CLASS) \
- static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(T))
-
- void dispatch(Type *T) {
- switch (T->getTypeClass()) {
-#define TYPE(DERIVED, BASE) \
- case Type::DERIVED: \
- DISPATCH(dispatch##DERIVED##TypeAttrs, DERIVED##Type); \
- static_cast<Impl*>(this)->completeAttrs(); \
- DISPATCH(dispatch##DERIVED##TypeChildren, DERIVED##Type); \
- break;
-#define ABSTRACT_TYPE(DERIVED, BASE)
-#include "clang/AST/TypeNodes.def"
- }
- }
-
-#define TYPE(DERIVED, BASE) \
- void dispatch##DERIVED##TypeAttrs(DERIVED##Type *T) { \
- DISPATCH(dispatch##BASE##Attrs, BASE); \
- DISPATCH(visit##DERIVED##TypeAttrs, DERIVED##Type); \
- } \
- void visit##DERIVED##TypeAttrs(DERIVED##Type *T) {} \
- void dispatch##DERIVED##TypeChildren(DERIVED##Type *T) { \
- DISPATCH(dispatch##BASE##Children, BASE); \
- DISPATCH(visit##DERIVED##TypeChildren, DERIVED##Type); \
- } \
- void visit##DERIVED##TypeChildren(DERIVED##Type *T) {}
-#include "clang/AST/TypeNodes.def"
-
- void dispatchTypeAttrs(Type *T) {
- DISPATCH(visitTypeAttrs, Type);
- }
- void visitTypeAttrs(Type *T) {}
-
- void dispatchTypeChildren(Type *T) {
- DISPATCH(visitTypeChildren, Type);
- }
- void visitTypeChildren(Type *T) {}
-
-#undef DISPATCH
-};
-
-static StringRef getTypeKindName(Type *T) {
- switch (T->getTypeClass()) {
-#define TYPE(DERIVED, BASE) case Type::DERIVED: return #DERIVED "Type";
-#define ABSTRACT_TYPE(DERIVED, BASE)
-#include "clang/AST/TypeNodes.def"
- }
-
- llvm_unreachable("unknown type kind!");
-}
-
-struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
- public XMLTypeVisitor<XMLDumper> {
- raw_ostream &out;
- ASTContext &Context;
- SmallVector<Node, 16> Stack;
- unsigned Indent;
- explicit XMLDumper(raw_ostream &OS, ASTContext &context)
- : out(OS), Context(context), Indent(0) {}
-
- void indent() {
- for (unsigned I = Indent; I; --I)
- out << ' ';
- }
-
- /// Push a new node on the stack.
- void push(StringRef name) {
- if (!Stack.empty()) {
- assert(Stack.back().isDoneWithAttrs());
- if (Stack.back().State == NS_LazyChildren) {
- Stack.back().State = NS_Children;
- out << ">\n";
- }
- Indent++;
- indent();
- }
- Stack.push_back(Node(name));
- out << '<' << name;
- }
-
- /// Set the given attribute to the given value.
- void set(StringRef attr, StringRef value) {
- assert(!Stack.empty() && !Stack.back().isDoneWithAttrs());
- out << ' ' << attr << '=' << '"' << value << '"'; // TODO: quotation
- }
-
- /// Finish attributes.
- void completeAttrs() {
- assert(!Stack.empty() && !Stack.back().isDoneWithAttrs());
- Stack.back().State = NS_LazyChildren;
- }
-
- /// Pop a node.
- void pop() {
- assert(!Stack.empty() && Stack.back().isDoneWithAttrs());
- if (Stack.back().State == NS_LazyChildren) {
- out << "/>\n";
- } else {
- indent();
- out << "</" << Stack.back().Name << ">\n";
- }
- if (Stack.size() > 1) Indent--;
- Stack.pop_back();
- }
-
- //---- General utilities -------------------------------------------//
-
- void setPointer(StringRef prop, const void *p) {
- SmallString<10> buffer;
- llvm::raw_svector_ostream os(buffer);
- os << p;
- os.flush();
- set(prop, buffer);
- }
-
- void setPointer(void *p) {
- setPointer("ptr", p);
- }
-
- void setInteger(StringRef prop, const llvm::APSInt &v) {
- set(prop, v.toString(10));
- }
-
- void setInteger(StringRef prop, unsigned n) {
- SmallString<10> buffer;
- llvm::raw_svector_ostream os(buffer);
- os << n;
- os.flush();
- set(prop, buffer);
- }
-
- void setFlag(StringRef prop, bool flag) {
- if (flag) set(prop, "true");
- }
-
- void setName(DeclarationName Name) {
- if (!Name)
- return set("name", "");
-
- // Common case.
- if (Name.isIdentifier())
- return set("name", Name.getAsIdentifierInfo()->getName());
-
- set("name", Name.getAsString());
- }
-
- class TemporaryContainer {
- XMLDumper &Dumper;
- public:
- TemporaryContainer(XMLDumper &dumper, StringRef name)
- : Dumper(dumper) {
- Dumper.push(name);
- Dumper.completeAttrs();
- }
-
- ~TemporaryContainer() {
- Dumper.pop();
- }
- };
-
- void visitTemplateParameters(TemplateParameterList *L) {
- push("template_parameters");
- completeAttrs();
- for (TemplateParameterList::iterator
- I = L->begin(), E = L->end(); I != E; ++I)
- dispatch(*I);
- pop();
- }
-
- void visitTemplateArguments(const TemplateArgumentList &L) {
- push("template_arguments");
- completeAttrs();
- for (unsigned I = 0, E = L.size(); I != E; ++I)
- dispatch(L[I]);
- pop();
- }
-
- /// Visits a reference to the given declaration.
- void visitDeclRef(Decl *D) {
- push(D->getDeclKindName());
- setPointer("ref", D);
- completeAttrs();
- pop();
- }
- void visitDeclRef(StringRef Name, Decl *D) {
- TemporaryContainer C(*this, Name);
- if (D) visitDeclRef(D);
- }
-
- void dispatch(const TemplateArgument &A) {
- switch (A.getKind()) {
- case TemplateArgument::Null: {
- TemporaryContainer C(*this, "null");
- break;
- }
- case TemplateArgument::Type: {
- dispatch(A.getAsType());
- break;
- }
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion:
- case TemplateArgument::NullPtr:
- // FIXME: Implement!
- break;
-
- case TemplateArgument::Declaration: {
- visitDeclRef(A.getAsDecl());
- break;
- }
- case TemplateArgument::Integral: {
- push("integer");
- setInteger("value", A.getAsIntegral());
- completeAttrs();
- pop();
- break;
- }
- case TemplateArgument::Expression: {
- dispatch(A.getAsExpr());
- break;
- }
- case TemplateArgument::Pack: {
- for (TemplateArgument::pack_iterator P = A.pack_begin(),
- PEnd = A.pack_end();
- P != PEnd; ++P)
- dispatch(*P);
- break;
- }
- }
- }
-
- void dispatch(const TemplateArgumentLoc &A) {
- dispatch(A.getArgument());
- }
-
- //---- Declarations ------------------------------------------------//
- // Calls are made in this order:
- // # Enter a new node.
- // push("FieldDecl")
- //
- // # In this phase, attributes are set on the node.
- // visitDeclAttrs(D)
- // visitNamedDeclAttrs(D)
- // ...
- // visitFieldDeclAttrs(D)
- //
- // # No more attributes after this point.
- // completeAttrs()
- //
- // # Create "header" child nodes, i.e. those which logically
- // # belong to the declaration itself.
- // visitDeclChildren(D)
- // visitNamedDeclChildren(D)
- // ...
- // visitFieldDeclChildren(D)
- //
- // # Create nodes for the lexical children.
- // visitDeclAsContext(D)
- // visitNamedDeclAsContext(D)
- // ...
- // visitFieldDeclAsContext(D)
- //
- // # Finish the node.
- // pop();
- void dispatch(Decl *D) {
- push(D->getDeclKindName());
- XMLDeclVisitor<XMLDumper>::dispatch(D);
- pop();
- }
- void visitDeclAttrs(Decl *D) {
- setPointer(D);
- }
-
- /// Visit all the lexical decls in the given context.
- void visitDeclContext(DeclContext *DC) {
- for (DeclContext::decl_iterator
- I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I)
- dispatch(*I);
-
- // FIXME: point out visible declarations not in lexical context?
- }
-
- /// Set the "access" attribute on the current node according to the
- /// given specifier.
- void setAccess(AccessSpecifier AS) {
- switch (AS) {
- case AS_public: return set("access", "public");
- case AS_protected: return set("access", "protected");
- case AS_private: return set("access", "private");
- case AS_none: llvm_unreachable("explicit forbidden access");
- }
- }
-
- template <class T> void visitRedeclarableAttrs(T *D) {
- if (T *Prev = D->getPreviousDecl())
- setPointer("previous", Prev);
- }
-
-
- // TranslationUnitDecl
- void visitTranslationUnitDeclAsContext(TranslationUnitDecl *D) {
- visitDeclContext(D);
- }
-
- // LinkageSpecDecl
- void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) {
- StringRef lang = "";
- switch (D->getLanguage()) {
- case LinkageSpecDecl::lang_c: lang = "C"; break;
- case LinkageSpecDecl::lang_cxx: lang = "C++"; break;
- }
- set("lang", lang);
- }
- void visitLinkageSpecDeclAsContext(LinkageSpecDecl *D) {
- visitDeclContext(D);
- }
-
- // NamespaceDecl
- void visitNamespaceDeclAttrs(NamespaceDecl *D) {
- setFlag("inline", D->isInline());
- if (!D->isOriginalNamespace())
- setPointer("original", D->getOriginalNamespace());
- }
- void visitNamespaceDeclAsContext(NamespaceDecl *D) {
- visitDeclContext(D);
- }
-
- // NamedDecl
- void visitNamedDeclAttrs(NamedDecl *D) {
- setName(D->getDeclName());
- }
-
- // ValueDecl
- void visitValueDeclChildren(ValueDecl *D) {
- dispatch(D->getType());
- }
-
- // DeclaratorDecl
- void visitDeclaratorDeclChildren(DeclaratorDecl *D) {
- //dispatch(D->getTypeSourceInfo()->getTypeLoc());
- }
-
- // VarDecl
- void visitVarDeclAttrs(VarDecl *D) {
- visitRedeclarableAttrs(D);
- if (D->getStorageClass() != SC_None)
- set("storage",
- VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
- StringRef initStyle = "";
- switch (D->getInitStyle()) {
- case VarDecl::CInit: initStyle = "c"; break;
- case VarDecl::CallInit: initStyle = "call"; break;
- case VarDecl::ListInit: initStyle = "list"; break;
- }
- set("initstyle", initStyle);
- setFlag("nrvo", D->isNRVOVariable());
- // TODO: instantiation, etc.
- }
- void visitVarDeclChildren(VarDecl *D) {
- if (D->hasInit()) dispatch(D->getInit());
- }
-
- // ParmVarDecl?
-
- // FunctionDecl
- void visitFunctionDeclAttrs(FunctionDecl *D) {
- visitRedeclarableAttrs(D);
- setFlag("pure", D->isPure());
- setFlag("trivial", D->isTrivial());
- setFlag("returnzero", D->hasImplicitReturnZero());
- setFlag("prototype", D->hasWrittenPrototype());
- setFlag("deleted", D->isDeletedAsWritten());
- if (D->getStorageClass() != SC_None)
- set("storage",
- VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
- setFlag("inline", D->isInlineSpecified());
- if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>())
- set("asmlabel", ALA->getLabel());
- // TODO: instantiation, etc.
- }
- void visitFunctionDeclChildren(FunctionDecl *D) {
- for (FunctionDecl::param_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I)
- dispatch(*I);
- for (ArrayRef<NamedDecl *>::iterator I = D->getDeclsInPrototypeScope().begin(),
- E = D->getDeclsInPrototypeScope().end();
- I != E; ++I)
- dispatch(*I);
- if (D->doesThisDeclarationHaveABody())
- dispatch(D->getBody());
- }
-
- // CXXMethodDecl ?
- // CXXConstructorDecl ?
- // CXXDestructorDecl ?
- // CXXConversionDecl ?
-
- void dispatch(CXXCtorInitializer *Init) {
- // TODO
- }
-
- // FieldDecl
- void visitFieldDeclAttrs(FieldDecl *D) {
- setFlag("mutable", D->isMutable());
- }
- void visitFieldDeclChildren(FieldDecl *D) {
- if (D->isBitField()) {
- TemporaryContainer C(*this, "bitwidth");
- dispatch(D->getBitWidth());
- }
- // TODO: C++0x member initializer
- }
-
- // EnumConstantDecl
- void visitEnumConstantDeclChildren(EnumConstantDecl *D) {
- // value in any case?
- if (D->getInitExpr()) dispatch(D->getInitExpr());
- }
-
- // IndirectFieldDecl
- void visitIndirectFieldDeclChildren(IndirectFieldDecl *D) {
- for (IndirectFieldDecl::chain_iterator
- I = D->chain_begin(), E = D->chain_end(); I != E; ++I) {
- NamedDecl *VD = const_cast<NamedDecl*>(*I);
- push(isa<VarDecl>(VD) ? "variable" : "field");
- setPointer("ptr", VD);
- completeAttrs();
- pop();
- }
- }
-
- // TypeDecl
- void visitTypeDeclAttrs(TypeDecl *D) {
- setPointer("typeptr", D->getTypeForDecl());
- }
-
- // TypedefDecl
- void visitTypedefDeclAttrs(TypedefDecl *D) {
- visitRedeclarableAttrs<TypedefNameDecl>(D);
- }
- void visitTypedefDeclChildren(TypedefDecl *D) {
- dispatch(D->getTypeSourceInfo()->getTypeLoc());
- }
-
- // TypeAliasDecl
- void visitTypeAliasDeclAttrs(TypeAliasDecl *D) {
- visitRedeclarableAttrs<TypedefNameDecl>(D);
- }
- void visitTypeAliasDeclChildren(TypeAliasDecl *D) {
- dispatch(D->getTypeSourceInfo()->getTypeLoc());
- }
-
- // TagDecl
- void visitTagDeclAttrs(TagDecl *D) {
- visitRedeclarableAttrs(D);
- }
- void visitTagDeclAsContext(TagDecl *D) {
- visitDeclContext(D);
- }
-
- // EnumDecl
- void visitEnumDeclAttrs(EnumDecl *D) {
- setFlag("scoped", D->isScoped());
- setFlag("fixed", D->isFixed());
- }
- void visitEnumDeclChildren(EnumDecl *D) {
- {
- TemporaryContainer C(*this, "promotion_type");
- dispatch(D->getPromotionType());
- }
- {
- TemporaryContainer C(*this, "integer_type");
- dispatch(D->getIntegerType());
- }
- }
-
- // RecordDecl ?
-
- void visitCXXRecordDeclChildren(CXXRecordDecl *D) {
- if (!D->isThisDeclarationADefinition()) return;
-
- for (CXXRecordDecl::base_class_iterator
- I = D->bases_begin(), E = D->bases_end(); I != E; ++I) {
- push("base");
- setAccess(I->getAccessSpecifier());
- completeAttrs();
- dispatch(I->getTypeSourceInfo()->getTypeLoc());
- pop();
- }
- }
-
- // ClassTemplateSpecializationDecl ?
-
- // FileScopeAsmDecl ?
-
- // BlockDecl
- void visitBlockDeclAttrs(BlockDecl *D) {
- setFlag("variadic", D->isVariadic());
- }
- void visitBlockDeclChildren(BlockDecl *D) {
- for (FunctionDecl::param_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I)
- dispatch(*I);
- dispatch(D->getBody());
- }
-
- // AccessSpecDecl
- void visitAccessSpecDeclAttrs(AccessSpecDecl *D) {
- setAccess(D->getAccess());
- }
-
- // TemplateDecl
- void visitTemplateDeclChildren(TemplateDecl *D) {
- visitTemplateParameters(D->getTemplateParameters());
- if (D->getTemplatedDecl())
- dispatch(D->getTemplatedDecl());
- }
-
- // FunctionTemplateDecl
- void visitFunctionTemplateDeclAttrs(FunctionTemplateDecl *D) {
- visitRedeclarableAttrs(D);
- }
- void visitFunctionTemplateDeclChildren(FunctionTemplateDecl *D) {
- // Mention all the specializations which don't have explicit
- // declarations elsewhere.
- for (FunctionTemplateDecl::spec_iterator
- I = D->spec_begin(), E = D->spec_end(); I != E; ++I) {
- FunctionTemplateSpecializationInfo *Info
- = I->getTemplateSpecializationInfo();
-
- bool Unknown = false;
- switch (Info->getTemplateSpecializationKind()) {
- case TSK_ImplicitInstantiation: Unknown = false; break;
- case TSK_Undeclared: Unknown = true; break;
-
- // These will be covered at their respective sites.
- case TSK_ExplicitSpecialization: continue;
- case TSK_ExplicitInstantiationDeclaration: continue;
- case TSK_ExplicitInstantiationDefinition: continue;
- }
-
- TemporaryContainer C(*this,
- Unknown ? "uninstantiated" : "instantiation");
- visitTemplateArguments(*Info->TemplateArguments);
- dispatch(Info->Function);
- }
- }
-
- // ClasTemplateDecl
- void visitClassTemplateDeclAttrs(ClassTemplateDecl *D) {
- visitRedeclarableAttrs(D);
- }
- void visitClassTemplateDeclChildren(ClassTemplateDecl *D) {
- // Mention all the specializations which don't have explicit
- // declarations elsewhere.
- for (ClassTemplateDecl::spec_iterator
- I = D->spec_begin(), E = D->spec_end(); I != E; ++I) {
-
- bool Unknown = false;
- switch (I->getTemplateSpecializationKind()) {
- case TSK_ImplicitInstantiation: Unknown = false; break;
- case TSK_Undeclared: Unknown = true; break;
-
- // These will be covered at their respective sites.
- case TSK_ExplicitSpecialization: continue;
- case TSK_ExplicitInstantiationDeclaration: continue;
- case TSK_ExplicitInstantiationDefinition: continue;
- }
-
- TemporaryContainer C(*this,
- Unknown ? "uninstantiated" : "instantiation");
- visitTemplateArguments(I->getTemplateArgs());
- dispatch(*I);
- }
- }
-
- // TemplateTypeParmDecl
- void visitTemplateTypeParmDeclAttrs(TemplateTypeParmDecl *D) {
- setInteger("depth", D->getDepth());
- setInteger("index", D->getIndex());
- }
- void visitTemplateTypeParmDeclChildren(TemplateTypeParmDecl *D) {
- if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
- dispatch(D->getDefaultArgumentInfo()->getTypeLoc());
- // parameter pack?
- }
-
- // NonTypeTemplateParmDecl
- void visitNonTypeTemplateParmDeclAttrs(NonTypeTemplateParmDecl *D) {
- setInteger("depth", D->getDepth());
- setInteger("index", D->getIndex());
- }
- void visitNonTypeTemplateParmDeclChildren(NonTypeTemplateParmDecl *D) {
- if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
- dispatch(D->getDefaultArgument());
- // parameter pack?
- }
-
- // TemplateTemplateParmDecl
- void visitTemplateTemplateParmDeclAttrs(TemplateTemplateParmDecl *D) {
- setInteger("depth", D->getDepth());
- setInteger("index", D->getIndex());
- }
- void visitTemplateTemplateParmDeclChildren(TemplateTemplateParmDecl *D) {
- if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
- dispatch(D->getDefaultArgument());
- // parameter pack?
- }
-
- // FriendDecl
- void visitFriendDeclChildren(FriendDecl *D) {
- if (TypeSourceInfo *T = D->getFriendType())
- dispatch(T->getTypeLoc());
- else
- dispatch(D->getFriendDecl());
- }
-
- // UsingDirectiveDecl ?
- // UsingDecl ?
- // UsingShadowDecl ?
- // NamespaceAliasDecl ?
- // UnresolvedUsingValueDecl ?
- // UnresolvedUsingTypenameDecl ?
- // StaticAssertDecl ?
-
- // ObjCImplDecl
- void visitObjCImplDeclChildren(ObjCImplDecl *D) {
- visitDeclRef(D->getClassInterface());
- }
- void visitObjCImplDeclAsContext(ObjCImplDecl *D) {
- visitDeclContext(D);
- }
-
- void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) {
- setPointer("typeptr", D->getTypeForDecl());
- setFlag("forward_decl", !D->isThisDeclarationADefinition());
- setFlag("implicit_interface", D->isImplicitInterfaceDecl());
- }
- void visitObjCInterfaceDeclChildren(ObjCInterfaceDecl *D) {
- visitDeclRef("super", D->getSuperClass());
- visitDeclRef("implementation", D->getImplementation());
- if (D->protocol_begin() != D->protocol_end()) {
- TemporaryContainer C(*this, "protocols");
- for (ObjCInterfaceDecl::protocol_iterator
- I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
- visitDeclRef(*I);
- }
-
- if (!D->visible_categories_empty()) {
- TemporaryContainer C(*this, "categories");
-
- for (ObjCInterfaceDecl::visible_categories_iterator
- Cat = D->visible_categories_begin(),
- CatEnd = D->visible_categories_end();
- Cat != CatEnd; ++Cat) {
- visitDeclRef(*Cat);
- }
- }
- }
- void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) {
- visitDeclContext(D);
- }
-
- // ObjCCategoryDecl
- void visitObjCCategoryDeclAttrs(ObjCCategoryDecl *D) {
- setFlag("extension", D->IsClassExtension());
- }
- void visitObjCCategoryDeclChildren(ObjCCategoryDecl *D) {
- visitDeclRef("interface", D->getClassInterface());
- visitDeclRef("implementation", D->getImplementation());
- if (D->protocol_begin() != D->protocol_end()) {
- TemporaryContainer C(*this, "protocols");
- for (ObjCCategoryDecl::protocol_iterator
- I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
- visitDeclRef(*I);
- }
- }
- void visitObjCCategoryDeclAsContext(ObjCCategoryDecl *D) {
- visitDeclContext(D);
- }
-
- // ObjCCategoryImplDecl
- void visitObjCCategoryImplDeclAttrs(ObjCCategoryImplDecl *D) {
- set("identifier", D->getName());
- }
- void visitObjCCategoryImplDeclChildren(ObjCCategoryImplDecl *D) {
- visitDeclRef(D->getCategoryDecl());
- }
-
- // ObjCImplementationDecl
- void visitObjCImplementationDeclAttrs(ObjCImplementationDecl *D) {
- set("identifier", D->getName());
- }
- void visitObjCImplementationDeclChildren(ObjCImplementationDecl *D) {
- visitDeclRef("super", D->getSuperClass());
- if (D->init_begin() != D->init_end()) {
- TemporaryContainer C(*this, "initializers");
- for (ObjCImplementationDecl::init_iterator
- I = D->init_begin(), E = D->init_end(); I != E; ++I)
- dispatch(*I);
- }
- }
-
- // ObjCProtocolDecl
- void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) {
- if (!D->isThisDeclarationADefinition())
- return;
-
- if (D->protocol_begin() != D->protocol_end()) {
- TemporaryContainer C(*this, "protocols");
- for (ObjCInterfaceDecl::protocol_iterator
- I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
- visitDeclRef(*I);
- }
- }
- void visitObjCProtocolDeclAsContext(ObjCProtocolDecl *D) {
- if (!D->isThisDeclarationADefinition())
- return;
-
- visitDeclContext(D);
- }
-
- // ObjCMethodDecl
- void visitObjCMethodDeclAttrs(ObjCMethodDecl *D) {
- // decl qualifier?
- // implementation control?
-
- setFlag("instance", D->isInstanceMethod());
- setFlag("variadic", D->isVariadic());
- setFlag("property_accessor", D->isPropertyAccessor());
- setFlag("defined", D->isDefined());
- setFlag("related_result_type", D->hasRelatedResultType());
- }
- void visitObjCMethodDeclChildren(ObjCMethodDecl *D) {
- dispatch(D->getResultType());
- for (ObjCMethodDecl::param_iterator
- I = D->param_begin(), E = D->param_end(); I != E; ++I)
- dispatch(*I);
- if (D->isThisDeclarationADefinition())
- dispatch(D->getBody());
- }
-
- // ObjCIvarDecl
- void setAccessControl(StringRef prop, ObjCIvarDecl::AccessControl AC) {
- switch (AC) {
- case ObjCIvarDecl::None: return set(prop, "none");
- case ObjCIvarDecl::Private: return set(prop, "private");
- case ObjCIvarDecl::Protected: return set(prop, "protected");
- case ObjCIvarDecl::Public: return set(prop, "public");
- case ObjCIvarDecl::Package: return set(prop, "package");
- }
- }
- void visitObjCIvarDeclAttrs(ObjCIvarDecl *D) {
- setFlag("synthesize", D->getSynthesize());
- setAccessControl("access", D->getAccessControl());
- }
-
- // ObjCCompatibleAliasDecl
- void visitObjCCompatibleAliasDeclChildren(ObjCCompatibleAliasDecl *D) {
- visitDeclRef(D->getClassInterface());
- }
-
- // FIXME: ObjCPropertyDecl
- // FIXME: ObjCPropertyImplDecl
-
- //---- Types -----------------------------------------------------//
- void dispatch(TypeLoc TL) {
- dispatch(TL.getType()); // for now
- }
-
- void dispatch(QualType T) {
- if (T.hasLocalQualifiers()) {
- push("QualType");
- Qualifiers Qs = T.getLocalQualifiers();
- setFlag("const", Qs.hasConst());
- setFlag("volatile", Qs.hasVolatile());
- setFlag("restrict", Qs.hasRestrict());
- if (Qs.hasAddressSpace()) setInteger("addrspace", Qs.getAddressSpace());
- if (Qs.hasObjCGCAttr()) {
- switch (Qs.getObjCGCAttr()) {
- case Qualifiers::Weak: set("gc", "weak"); break;
- case Qualifiers::Strong: set("gc", "strong"); break;
- case Qualifiers::GCNone: llvm_unreachable("explicit none");
- }
- }
-
- completeAttrs();
- dispatch(QualType(T.getTypePtr(), 0));
- pop();
- return;
- }
-
- Type *Ty = const_cast<Type*>(T.getTypePtr());
- push(getTypeKindName(Ty));
- XMLTypeVisitor<XMLDumper>::dispatch(const_cast<Type*>(T.getTypePtr()));
- pop();
- }
-
- void setCallingConv(CallingConv CC) {
- switch (CC) {
- case CC_Default: return;
- case CC_C: return set("cc", "cdecl");
- case CC_X86FastCall: return set("cc", "x86_fastcall");
- case CC_X86StdCall: return set("cc", "x86_stdcall");
- case CC_X86ThisCall: return set("cc", "x86_thiscall");
- case CC_X86Pascal: return set("cc", "x86_pascal");
- case CC_AAPCS: return set("cc", "aapcs");
- case CC_AAPCS_VFP: return set("cc", "aapcs_vfp");
- case CC_PnaclCall: return set("cc", "pnaclcall");
- case CC_IntelOclBicc: return set("cc", "intel_ocl_bicc");
- }
- }
-
- void visitTypeAttrs(Type *D) {
- setPointer(D);
- setFlag("dependent", D->isDependentType());
- setFlag("variably_modified", D->isVariablyModifiedType());
-
- setPointer("canonical", D->getCanonicalTypeInternal().getAsOpaquePtr());
- }
-
- void visitPointerTypeChildren(PointerType *T) {
- dispatch(T->getPointeeType());
- }
- void visitReferenceTypeChildren(ReferenceType *T) {
- dispatch(T->getPointeeType());
- }
- void visitObjCObjectPointerTypeChildren(ObjCObjectPointerType *T) {
- dispatch(T->getPointeeType());
- }
- void visitBlockPointerTypeChildren(BlockPointerType *T) {
- dispatch(T->getPointeeType());
- }
-
- // Types that just wrap declarations.
- void visitTagTypeChildren(TagType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitTypedefTypeChildren(TypedefType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitObjCInterfaceTypeChildren(ObjCInterfaceType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitUnresolvedUsingTypeChildren(UnresolvedUsingType *T) {
- visitDeclRef(T->getDecl());
- }
- void visitInjectedClassNameTypeChildren(InjectedClassNameType *T) {
- visitDeclRef(T->getDecl());
- }
-
- void visitFunctionTypeAttrs(FunctionType *T) {
- setFlag("noreturn", T->getNoReturnAttr());
- setCallingConv(T->getCallConv());
- if (T->getHasRegParm()) setInteger("regparm", T->getRegParmType());
- }
- void visitFunctionTypeChildren(FunctionType *T) {
- dispatch(T->getResultType());
- }
-
- void visitFunctionProtoTypeAttrs(FunctionProtoType *T) {
- setFlag("const", T->isConst());
- setFlag("volatile", T->isVolatile());
- setFlag("restrict", T->isRestrict());
- switch (T->getExceptionSpecType()) {
- case EST_None: break;
- case EST_DynamicNone: set("exception_spec", "throw()"); break;
- case EST_Dynamic: set("exception_spec", "throw(T)"); break;
- case EST_MSAny: set("exception_spec", "throw(...)"); break;
- case EST_BasicNoexcept: set("exception_spec", "noexcept"); break;
- case EST_ComputedNoexcept: set("exception_spec", "noexcept(expr)"); break;
- case EST_Unevaluated: set("exception_spec", "unevaluated"); break;
- case EST_Uninstantiated: set("exception_spec", "uninstantiated"); break;
- }
- }
- void visitFunctionProtoTypeChildren(FunctionProtoType *T) {
- push("parameters");
- setFlag("variadic", T->isVariadic());
- completeAttrs();
- for (FunctionProtoType::arg_type_iterator
- I = T->arg_type_begin(), E = T->arg_type_end(); I != E; ++I)
- dispatch(*I);
- pop();
-
- if (T->hasDynamicExceptionSpec()) {
- push("exception_specifiers");
- setFlag("any", T->getExceptionSpecType() == EST_MSAny);
- completeAttrs();
- for (FunctionProtoType::exception_iterator
- I = T->exception_begin(), E = T->exception_end(); I != E; ++I)
- dispatch(*I);
- pop();
- }
- // FIXME: noexcept specifier
- }
-
- void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) {
- if (const RecordType *RT = T->getAs<RecordType>())
- visitDeclRef(RT->getDecl());
-
- // TODO: TemplateName
-
- push("template_arguments");
- completeAttrs();
- for (unsigned I = 0, E = T->getNumArgs(); I != E; ++I)
- dispatch(T->getArg(I));
- pop();
- }
-
- //---- Statements ------------------------------------------------//
- void dispatch(Stmt *S) {
- // FIXME: this is not really XML at all
- push("Stmt");
- out << ">\n";
- Stack.back().State = NS_Children; // explicitly become non-lazy
- S->dump(out, Context.getSourceManager());
- out << '\n';
- pop();
- }
-};
-}
-
-void Decl::dumpXML() const {
- dumpXML(llvm::errs());
-}
-
-void Decl::dumpXML(raw_ostream &out) const {
- XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this));
-}
-
-#else /* ifndef NDEBUG */
-
-void Decl::dumpXML() const {}
-void Decl::dumpXML(raw_ostream &out) const {}
-
-#endif
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 9538ddf..9055ddac 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/EvaluatedExprVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/Builtins.h"
@@ -50,9 +51,9 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const {
return cast<CXXRecordDecl>(D);
}
-const Expr *
-Expr::skipRValueSubobjectAdjustments(
- SmallVectorImpl<SubobjectAdjustment> &Adjustments) const {
+const Expr *Expr::skipRValueSubobjectAdjustments(
+ SmallVectorImpl<const Expr *> &CommaLHSs,
+ SmallVectorImpl<SubobjectAdjustment> &Adjustments) const {
const Expr *E = this;
while (true) {
E = E->IgnoreParens();
@@ -73,12 +74,14 @@ Expr::skipRValueSubobjectAdjustments(
continue;
}
} else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
- if (!ME->isArrow() && ME->getBase()->isRValue()) {
+ if (!ME->isArrow()) {
assert(ME->getBase()->getType()->isRecordType());
if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) {
- E = ME->getBase();
- Adjustments.push_back(SubobjectAdjustment(Field));
- continue;
+ if (!Field->isBitField() && !Field->getType()->isReferenceType()) {
+ E = ME->getBase();
+ Adjustments.push_back(SubobjectAdjustment(Field));
+ continue;
+ }
}
}
} else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
@@ -88,6 +91,11 @@ Expr::skipRValueSubobjectAdjustments(
const MemberPointerType *MPT =
BO->getRHS()->getType()->getAs<MemberPointerType>();
Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS()));
+ continue;
+ } else if (BO->getOpcode() == BO_Comma) {
+ CommaLHSs.push_back(BO->getLHS());
+ E = BO->getRHS();
+ continue;
}
}
@@ -231,8 +239,8 @@ SourceLocation Expr::getExprLoc() const {
/// \brief Compute the type-, value-, and instantiation-dependence of a
/// declaration reference
/// based on the declaration being referenced.
-static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
- bool &TypeDependent,
+static void computeDeclRefDependence(const ASTContext &Ctx, NamedDecl *D,
+ QualType T, bool &TypeDependent,
bool &ValueDependent,
bool &InstantiationDependent) {
TypeDependent = false;
@@ -307,6 +315,9 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
Var->getDeclContext()->isDependentContext()) {
ValueDependent = true;
InstantiationDependent = true;
+ TypeSourceInfo *TInfo = Var->getFirstDecl()->getTypeSourceInfo();
+ if (TInfo->getType()->isIncompleteArrayType())
+ TypeDependent = true;
}
return;
@@ -321,7 +332,7 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
}
}
-void DeclRefExpr::computeDependence(ASTContext &Ctx) {
+void DeclRefExpr::computeDependence(const ASTContext &Ctx) {
bool TypeDependent = false;
bool ValueDependent = false;
bool InstantiationDependent = false;
@@ -355,7 +366,7 @@ void DeclRefExpr::computeDependence(ASTContext &Ctx) {
ExprBits.ContainsUnexpandedParameterPack = true;
}
-DeclRefExpr::DeclRefExpr(ASTContext &Ctx,
+DeclRefExpr::DeclRefExpr(const ASTContext &Ctx,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D, bool RefersToEnclosingLocal,
@@ -392,7 +403,7 @@ DeclRefExpr::DeclRefExpr(ASTContext &Ctx,
computeDependence(Ctx);
}
-DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
+DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D,
@@ -408,7 +419,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
T, VK, FoundD, TemplateArgs);
}
-DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
+DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *D,
@@ -423,7 +434,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
FoundD = 0;
std::size_t Size = sizeof(DeclRefExpr);
- if (QualifierLoc != 0)
+ if (QualifierLoc)
Size += sizeof(NestedNameSpecifierLoc);
if (FoundD)
Size += sizeof(NamedDecl *);
@@ -438,7 +449,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
NameInfo, FoundD, TemplateArgs, T, VK);
}
-DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
+DeclRefExpr *DeclRefExpr::CreateEmpty(const ASTContext &Context,
bool HasQualifier,
bool HasFoundDecl,
bool HasTemplateKWAndArgsInfo,
@@ -471,6 +482,30 @@ SourceLocation DeclRefExpr::getLocEnd() const {
std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
ASTContext &Context = CurrentDecl->getASTContext();
+ if (IT == PredefinedExpr::FuncDName) {
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(CurrentDecl)) {
+ OwningPtr<MangleContext> MC;
+ MC.reset(Context.createMangleContext());
+
+ if (MC->shouldMangleDeclName(ND)) {
+ SmallString<256> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(ND))
+ MC->mangleCXXCtor(CD, Ctor_Base, Out);
+ else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(ND))
+ MC->mangleCXXDtor(DD, Dtor_Base, Out);
+ else
+ MC->mangleName(ND, Out);
+
+ Out.flush();
+ if (!Buffer.empty() && Buffer.front() == '\01')
+ return Buffer.substr(1);
+ return Buffer.str();
+ } else
+ return ND->getIdentifier()->getName();
+ }
+ return "";
+ }
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) {
if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual)
return FD->getNameAsString();
@@ -578,7 +613,18 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
POut.flush();
- if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
+ // Print "auto" for all deduced return types. This includes C++1y return
+ // type deduction and lambdas. For trailing return types resolve the
+ // decltype expression. Otherwise print the real type when this is
+ // not a constructor or destructor.
+ if ((isa<CXXMethodDecl>(FD) &&
+ cast<CXXMethodDecl>(FD)->getParent()->isLambda()) ||
+ (FT && FT->getResultType()->getAs<AutoType>()))
+ Proto = "auto " + Proto;
+ else if (FT && FT->getResultType()->getAs<DecltypeType>())
+ FT->getResultType()->getAs<DecltypeType>()->getUnderlyingType()
+ .getAsStringInternal(Proto, Policy);
+ else if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD))
AFT->getResultType().getAsStringInternal(Proto, Policy);
Out << Proto;
@@ -586,6 +632,16 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
Out.flush();
return Name.str().str();
}
+ if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(CurrentDecl)) {
+ for (const DeclContext *DC = CD->getParent(); DC; DC = DC->getParent())
+ // Skip to its enclosing function or method, but not its enclosing
+ // CapturedDecl.
+ if (DC->isFunctionOrMethod() && (DC->getDeclKind() != Decl::Captured)) {
+ const Decl *D = Decl::castFromDeclContext(DC);
+ return ComputeName(IT, D);
+ }
+ llvm_unreachable("CapturedDecl not inside a function or method");
+ }
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurrentDecl)) {
SmallString<256> Name;
llvm::raw_svector_ostream Out(Name);
@@ -615,7 +671,8 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
return "";
}
-void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) {
+void APNumericStorage::setIntValue(const ASTContext &C,
+ const llvm::APInt &Val) {
if (hasAllocation())
C.Deallocate(pVal);
@@ -631,7 +688,7 @@ void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) {
VAL = 0;
}
-IntegerLiteral::IntegerLiteral(ASTContext &C, const llvm::APInt &V,
+IntegerLiteral::IntegerLiteral(const ASTContext &C, const llvm::APInt &V,
QualType type, SourceLocation l)
: Expr(IntegerLiteralClass, type, VK_RValue, OK_Ordinary, false, false,
false, false),
@@ -643,17 +700,17 @@ IntegerLiteral::IntegerLiteral(ASTContext &C, const llvm::APInt &V,
}
IntegerLiteral *
-IntegerLiteral::Create(ASTContext &C, const llvm::APInt &V,
+IntegerLiteral::Create(const ASTContext &C, const llvm::APInt &V,
QualType type, SourceLocation l) {
return new (C) IntegerLiteral(C, V, type, l);
}
IntegerLiteral *
-IntegerLiteral::Create(ASTContext &C, EmptyShell Empty) {
+IntegerLiteral::Create(const ASTContext &C, EmptyShell Empty) {
return new (C) IntegerLiteral(Empty);
}
-FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V,
+FloatingLiteral::FloatingLiteral(const ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L)
: Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
false, false), Loc(L) {
@@ -662,20 +719,20 @@ FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V,
setValue(C, V);
}
-FloatingLiteral::FloatingLiteral(ASTContext &C, EmptyShell Empty)
+FloatingLiteral::FloatingLiteral(const ASTContext &C, EmptyShell Empty)
: Expr(FloatingLiteralClass, Empty) {
setRawSemantics(IEEEhalf);
FloatingLiteralBits.IsExact = false;
}
FloatingLiteral *
-FloatingLiteral::Create(ASTContext &C, const llvm::APFloat &V,
+FloatingLiteral::Create(const ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L) {
return new (C) FloatingLiteral(C, V, isexact, Type, L);
}
FloatingLiteral *
-FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) {
+FloatingLiteral::Create(const ASTContext &C, EmptyShell Empty) {
return new (C) FloatingLiteral(C, Empty);
}
@@ -749,7 +806,7 @@ int StringLiteral::mapCharByteWidth(TargetInfo const &target,StringKind k) {
return CharByteWidth;
}
-StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str,
+StringLiteral *StringLiteral::Create(const ASTContext &C, StringRef Str,
StringKind Kind, bool Pascal, QualType Ty,
const SourceLocation *Loc,
unsigned NumStrs) {
@@ -771,7 +828,8 @@ StringLiteral *StringLiteral::Create(ASTContext &C, StringRef Str,
return SL;
}
-StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) {
+StringLiteral *StringLiteral::CreateEmpty(const ASTContext &C,
+ unsigned NumStrs) {
void *Mem = C.Allocate(sizeof(StringLiteral)+
sizeof(SourceLocation)*(NumStrs-1),
llvm::alignOf<StringLiteral>());
@@ -875,7 +933,7 @@ void StringLiteral::outputString(raw_ostream &OS) const {
OS << '"';
}
-void StringLiteral::setString(ASTContext &C, StringRef Str,
+void StringLiteral::setString(const ASTContext &C, StringRef Str,
StringKind Kind, bool IsPascal) {
//FIXME: we assume that the string data comes from a target that uses the same
// code unit size and endianess for the type of string.
@@ -1028,9 +1086,9 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
// Postfix Operators.
//===----------------------------------------------------------------------===//
-CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
- ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
- SourceLocation rparenloc)
+CallExpr::CallExpr(const ASTContext& C, StmtClass SC, Expr *fn,
+ unsigned NumPreArgs, ArrayRef<Expr*> args, QualType t,
+ ExprValueKind VK, SourceLocation rparenloc)
: Expr(SC, t, VK, OK_Ordinary,
fn->isTypeDependent(),
fn->isValueDependent(),
@@ -1057,7 +1115,7 @@ CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
RParenLoc = rparenloc;
}
-CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
+CallExpr::CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
QualType t, ExprValueKind VK, SourceLocation rparenloc)
: Expr(CallExprClass, t, VK, OK_Ordinary,
fn->isTypeDependent(),
@@ -1085,14 +1143,14 @@ CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args,
RParenLoc = rparenloc;
}
-CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty)
+CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty)
: Expr(SC, Empty), SubExprs(0), NumArgs(0) {
// FIXME: Why do we allocate this?
SubExprs = new (C) Stmt*[PREARGS_START];
CallExprBits.NumPreArgs = 0;
}
-CallExpr::CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs,
+CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
EmptyShell Empty)
: Expr(SC, Empty), SubExprs(0), NumArgs(0) {
// FIXME: Why do we allocate this?
@@ -1131,7 +1189,7 @@ FunctionDecl *CallExpr::getDirectCallee() {
/// setNumArgs - This changes the number of arguments present in this call.
/// Any orphaned expressions are deleted by this, and any new operands are set
/// to null.
-void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) {
+void CallExpr::setNumArgs(const ASTContext& C, unsigned NumArgs) {
// No change, just return.
if (NumArgs == getNumArgs()) return;
@@ -1220,7 +1278,7 @@ SourceLocation CallExpr::getLocEnd() const {
return end;
}
-OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
+OffsetOfExpr *OffsetOfExpr::Create(const ASTContext &C, QualType type,
SourceLocation OperatorLoc,
TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps,
@@ -1234,7 +1292,7 @@ OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type,
RParenLoc);
}
-OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
+OffsetOfExpr *OffsetOfExpr::CreateEmpty(const ASTContext &C,
unsigned numComps, unsigned numExprs) {
void *Mem = C.Allocate(sizeof(OffsetOfExpr) +
sizeof(OffsetOfNode) * numComps +
@@ -1242,7 +1300,7 @@ OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C,
return new (Mem) OffsetOfExpr(numComps, numExprs);
}
-OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type,
+OffsetOfExpr::OffsetOfExpr(const ASTContext &C, QualType type,
SourceLocation OperatorLoc, TypeSourceInfo *tsi,
ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs,
SourceLocation RParenLoc)
@@ -1276,7 +1334,7 @@ IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const {
return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask);
}
-MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
+MemberExpr *MemberExpr::Create(const ASTContext &C, Expr *base, bool isarrow,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
ValueDecl *memberdecl,
@@ -1630,7 +1688,7 @@ void CastExpr::setCastPath(const CXXCastPath &Path) {
memcpy(path_buffer(), Path.data(), Path.size() * sizeof(CXXBaseSpecifier*));
}
-ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T,
+ImplicitCastExpr *ImplicitCastExpr::Create(const ASTContext &C, QualType T,
CastKind Kind, Expr *Operand,
const CXXCastPath *BasePath,
ExprValueKind VK) {
@@ -1643,7 +1701,7 @@ ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C,
+ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(ImplicitCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
@@ -1651,7 +1709,7 @@ ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C,
}
-CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T,
+CStyleCastExpr *CStyleCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK, CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
@@ -1665,7 +1723,8 @@ CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-CStyleCastExpr *CStyleCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
+CStyleCastExpr *CStyleCastExpr::CreateEmpty(const ASTContext &C,
+ unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CStyleCastExpr(EmptyShell(), PathSize);
@@ -1774,7 +1833,7 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
return OverOps[Opc];
}
-InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
+InitListExpr::InitListExpr(const ASTContext &C, SourceLocation lbraceloc,
ArrayRef<Expr*> initExprs, SourceLocation rbraceloc)
: Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
false, false),
@@ -1782,7 +1841,6 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true)
{
sawArrayRangeDesignator(false);
- setInitializesStdInitializerList(false);
for (unsigned I = 0; I != initExprs.size(); ++I) {
if (initExprs[I]->isTypeDependent())
ExprBits.TypeDependent = true;
@@ -1797,16 +1855,16 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end());
}
-void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) {
+void InitListExpr::reserveInits(const ASTContext &C, unsigned NumInits) {
if (NumInits > InitExprs.size())
InitExprs.reserve(C, NumInits);
}
-void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) {
+void InitListExpr::resizeInits(const ASTContext &C, unsigned NumInits) {
InitExprs.resize(C, NumInits, 0);
}
-Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) {
+Expr *InitListExpr::updateInit(const ASTContext &C, unsigned Init, Expr *expr) {
if (Init >= InitExprs.size()) {
InitExprs.insert(C, InitExprs.end(), Init - InitExprs.size() + 1, 0);
InitExprs.back() = expr;
@@ -1923,6 +1981,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case GenericSelectionExprClass:
return cast<GenericSelectionExpr>(this)->getResultExpr()->
isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
+ case ChooseExprClass:
+ return cast<ChooseExpr>(this)->getChosenSubExpr()->
+ isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
case UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(this);
@@ -2066,17 +2127,24 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
return false;
case CXXTemporaryObjectExprClass:
- case CXXConstructExprClass:
+ case CXXConstructExprClass: {
+ if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) {
+ if (Type->hasAttr<WarnUnusedAttr>()) {
+ WarnE = this;
+ Loc = getLocStart();
+ R1 = getSourceRange();
+ return true;
+ }
+ }
return false;
+ }
case ObjCMessageExprClass: {
const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this);
if (Ctx.getLangOpts().ObjCAutoRefCount &&
ME->isInstanceMessage() &&
!ME->getType()->isVoidType() &&
- ME->getSelector().getIdentifierInfoForSlot(0) &&
- ME->getSelector().getIdentifierInfoForSlot(0)
- ->getName().startswith("init")) {
+ ME->getMethodFamily() == OMF_init) {
WarnE = this;
Loc = getExprLoc();
R1 = ME->getSourceRange();
@@ -2161,7 +2229,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
WarnE = this;
if (const CXXFunctionalCastExpr *CXXCE =
dyn_cast<CXXFunctionalCastExpr>(this)) {
- Loc = CXXCE->getTypeBeginLoc();
+ Loc = CXXCE->getLocStart();
R1 = CXXCE->getSubExpr()->getSourceRange();
} else {
const CStyleCastExpr *CStyleCE = cast<CStyleCastExpr>(this);
@@ -2291,6 +2359,12 @@ Expr* Expr::IgnoreParens() {
continue;
}
}
+ if (ChooseExpr* P = dyn_cast<ChooseExpr>(E)) {
+ if (!P->isConditionDependent()) {
+ E = P->getChosenSubExpr();
+ continue;
+ }
+ }
return E;
}
}
@@ -2300,26 +2374,11 @@ Expr* Expr::IgnoreParens() {
Expr *Expr::IgnoreParenCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr* P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (CastExpr *P = dyn_cast<CastExpr>(E)) {
E = P->getSubExpr();
continue;
}
- if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- }
- if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
- }
if (MaterializeTemporaryExpr *Materialize
= dyn_cast<MaterializeTemporaryExpr>(E)) {
E = Materialize->GetTemporaryExpr();
@@ -2341,24 +2400,12 @@ Expr *Expr::IgnoreParenCasts() {
Expr *Expr::IgnoreParenLValueCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- } else if (CastExpr *P = dyn_cast<CastExpr>(E)) {
+ E = E->IgnoreParens();
+ if (CastExpr *P = dyn_cast<CastExpr>(E)) {
if (P->getCastKind() == CK_LValueToRValue) {
E = P->getSubExpr();
continue;
}
- } else if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- } else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
} else if (MaterializeTemporaryExpr *Materialize
= dyn_cast<MaterializeTemporaryExpr>(E)) {
E = Materialize->GetTemporaryExpr();
@@ -2376,10 +2423,7 @@ Expr *Expr::IgnoreParenLValueCasts() {
Expr *Expr::ignoreParenBaseCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (CastExpr *CE = dyn_cast<CastExpr>(E)) {
if (CE->getCastKind() == CK_DerivedToBase ||
CE->getCastKind() == CK_UncheckedDerivedToBase ||
@@ -2396,26 +2440,11 @@ Expr *Expr::ignoreParenBaseCasts() {
Expr *Expr::IgnoreParenImpCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) {
E = P->getSubExpr();
continue;
}
- if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- }
- if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
- }
if (MaterializeTemporaryExpr *Materialize
= dyn_cast<MaterializeTemporaryExpr>(E)) {
E = Materialize->GetTemporaryExpr();
@@ -2444,10 +2473,7 @@ Expr *Expr::IgnoreConversionOperator() {
Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
- E = P->getSubExpr();
- continue;
- }
+ E = E->IgnoreParens();
if (CastExpr *P = dyn_cast<CastExpr>(E)) {
// We ignore integer <-> casts that are of the same width, ptr<->ptr and
@@ -2469,20 +2495,6 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
}
}
- if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
- if (P->getOpcode() == UO_Extension) {
- E = P->getSubExpr();
- continue;
- }
- }
-
- if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
- if (!P->isResultDependent()) {
- E = P->getResultExpr();
- continue;
- }
- }
-
if (SubstNonTypeTemplateParmExpr *NTTP
= dyn_cast<SubstNonTypeTemplateParmExpr>(E)) {
E = NTTP->getReplacement();
@@ -2628,11 +2640,11 @@ bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) {
bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
// This function is attempting whether an expression is an initializer
- // which can be evaluated at compile-time. isEvaluatable handles most
- // of the cases, but it can't deal with some initializer-specific
- // expressions, and it can't deal with aggregates; we deal with those here,
- // and fall back to isEvaluatable for the other cases.
-
+ // which can be evaluated at compile-time. It very closely parallels
+ // ConstExprEmitter in CGExprConstant.cpp; if they don't match, it
+ // will lead to unexpected results. Like ConstExprEmitter, it falls back
+ // to isEvaluatable most of the time.
+ //
// If we ever capture reference-binding directly in the AST, we can
// kill the second parameter.
@@ -2643,30 +2655,23 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
switch (getStmtClass()) {
default: break;
- case IntegerLiteralClass:
- case FloatingLiteralClass:
case StringLiteralClass:
- case ObjCStringLiteralClass:
case ObjCEncodeExprClass:
return true;
case CXXTemporaryObjectExprClass:
case CXXConstructExprClass: {
const CXXConstructExpr *CE = cast<CXXConstructExpr>(this);
- // Only if it's
- if (CE->getConstructor()->isTrivial()) {
- // 1) an application of the trivial default constructor or
+ if (CE->getConstructor()->isTrivial() &&
+ CE->getConstructor()->getParent()->hasTrivialDestructor()) {
+ // Trivial default constructor
if (!CE->getNumArgs()) return true;
- // 2) an elidable trivial copy construction of an operand which is
- // itself a constant initializer. Note that we consider the
- // operand on its own, *not* as a reference binding.
- if (CE->isElidable() &&
- CE->getArg(0)->isConstantInitializer(Ctx, false))
- return true;
+ // Trivial copy constructor
+ assert(CE->getNumArgs() == 1 && "trivial ctor with > 1 argument");
+ return CE->getArg(0)->isConstantInitializer(Ctx, false);
}
- // 3) a foldable constexpr constructor.
break;
}
case CompoundLiteralExprClass: {
@@ -2677,16 +2682,47 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
return Exp->isConstantInitializer(Ctx, false);
}
case InitListExprClass: {
- // FIXME: This doesn't deal with fields with reference types correctly.
- // FIXME: This incorrectly allows pointers cast to integers to be assigned
- // to bitfields.
- const InitListExpr *Exp = cast<InitListExpr>(this);
- unsigned numInits = Exp->getNumInits();
- for (unsigned i = 0; i < numInits; i++) {
- if (!Exp->getInit(i)->isConstantInitializer(Ctx, false))
- return false;
+ const InitListExpr *ILE = cast<InitListExpr>(this);
+ if (ILE->getType()->isArrayType()) {
+ unsigned numInits = ILE->getNumInits();
+ for (unsigned i = 0; i < numInits; i++) {
+ if (!ILE->getInit(i)->isConstantInitializer(Ctx, false))
+ return false;
+ }
+ return true;
}
- return true;
+
+ if (ILE->getType()->isRecordType()) {
+ unsigned ElementNo = 0;
+ RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl();
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) {
+ // If this is a union, skip all the fields that aren't being initialized.
+ if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field)
+ continue;
+
+ // Don't emit anonymous bitfields, they just affect layout.
+ if (Field->isUnnamedBitfield())
+ continue;
+
+ if (ElementNo < ILE->getNumInits()) {
+ const Expr *Elt = ILE->getInit(ElementNo++);
+ if (Field->isBitField()) {
+ // Bitfields have to evaluate to an integer.
+ llvm::APSInt ResultTmp;
+ if (!Elt->EvaluateAsInt(ResultTmp, Ctx))
+ return false;
+ } else {
+ bool RefType = Field->getType()->isReferenceType();
+ if (!Elt->isConstantInitializer(Ctx, RefType))
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ break;
}
case ImplicitValueInitExprClass:
return true;
@@ -2694,12 +2730,12 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
return cast<ParenExpr>(this)->getSubExpr()
->isConstantInitializer(Ctx, IsForRef);
case GenericSelectionExprClass:
- if (cast<GenericSelectionExpr>(this)->isResultDependent())
- return false;
return cast<GenericSelectionExpr>(this)->getResultExpr()
->isConstantInitializer(Ctx, IsForRef);
case ChooseExprClass:
- return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)
+ if (cast<ChooseExpr>(this)->isConditionDependent())
+ return false;
+ return cast<ChooseExpr>(this)->getChosenSubExpr()
->isConstantInitializer(Ctx, IsForRef);
case UnaryOperatorClass: {
const UnaryOperator* Exp = cast<UnaryOperator>(this);
@@ -2710,31 +2746,20 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
case CXXFunctionalCastExprClass:
case CXXStaticCastExprClass:
case ImplicitCastExprClass:
- case CStyleCastExprClass: {
+ case CStyleCastExprClass:
+ case ObjCBridgedCastExprClass:
+ case CXXDynamicCastExprClass:
+ case CXXReinterpretCastExprClass:
+ case CXXConstCastExprClass: {
const CastExpr *CE = cast<CastExpr>(this);
- // If we're promoting an integer to an _Atomic type then this is constant
- // if the integer is constant. We also need to check the converse in case
- // someone does something like:
- //
- // int a = (_Atomic(int))42;
- //
- // I doubt anyone would write code like this directly, but it's quite
- // possible as the result of macro expansions.
- if (CE->getCastKind() == CK_NonAtomicToAtomic ||
- CE->getCastKind() == CK_AtomicToNonAtomic)
- return CE->getSubExpr()->isConstantInitializer(Ctx, false);
-
- // Handle bitcasts of vector constants.
- if (getType()->isVectorType() && CE->getCastKind() == CK_BitCast)
- return CE->getSubExpr()->isConstantInitializer(Ctx, false);
-
// Handle misc casts we want to ignore.
- // FIXME: Is it really safe to ignore all these?
if (CE->getCastKind() == CK_NoOp ||
CE->getCastKind() == CK_LValueToRValue ||
CE->getCastKind() == CK_ToUnion ||
- CE->getCastKind() == CK_ConstructorConversion)
+ CE->getCastKind() == CK_ConstructorConversion ||
+ CE->getCastKind() == CK_NonAtomicToAtomic ||
+ CE->getCastKind() == CK_AtomicToNonAtomic)
return CE->getSubExpr()->isConstantInitializer(Ctx, false);
break;
@@ -2742,6 +2767,16 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
case MaterializeTemporaryExprClass:
return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr()
->isConstantInitializer(Ctx, false);
+
+ case SubstNonTypeTemplateParmExprClass:
+ return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement()
+ ->isConstantInitializer(Ctx, false);
+ case CXXDefaultArgExprClass:
+ return cast<CXXDefaultArgExpr>(this)->getExpr()
+ ->isConstantInitializer(Ctx, false);
+ case CXXDefaultInitExprClass:
+ return cast<CXXDefaultInitExpr>(this)->getExpr()
+ ->isConstantInitializer(Ctx, false);
}
return isEvaluatable(Ctx);
}
@@ -2829,9 +2864,11 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case DesignatedInitExprClass:
case ParenListExprClass:
case CXXPseudoDestructorExprClass:
+ case CXXStdInitializerListExprClass:
case SubstNonTypeTemplateParmExprClass:
case MaterializeTemporaryExprClass:
case ShuffleVectorExprClass:
+ case ConvertVectorExprClass:
case AsTypeExprClass:
// These have a side-effect if any subexpression does.
break;
@@ -2858,7 +2895,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
HasSideEffects(Ctx);
case ChooseExprClass:
- return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)->HasSideEffects(Ctx);
+ return cast<ChooseExpr>(this)->getChosenSubExpr()->HasSideEffects(Ctx);
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx);
@@ -3017,7 +3054,8 @@ bool Expr::hasNonTrivialCall(ASTContext &Ctx) {
Expr::NullPointerConstantKind
Expr::isNullPointerConstant(ASTContext &Ctx,
NullPointerConstantValueDependence NPC) const {
- if (isValueDependent()) {
+ if (isValueDependent() &&
+ (!Ctx.getLangOpts().CPlusPlus11 || Ctx.getLangOpts().MicrosoftMode)) {
switch (NPC) {
case NPC_NeverValueDependent:
llvm_unreachable("Unexpected value dependent expression!");
@@ -3053,7 +3091,13 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const GenericSelectionExpr *GE =
dyn_cast<GenericSelectionExpr>(this)) {
+ if (GE->isResultDependent())
+ return NPCK_NotNull;
return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC);
+ } else if (const ChooseExpr *CE = dyn_cast<ChooseExpr>(this)) {
+ if (CE->isConditionDependent())
+ return NPCK_NotNull;
+ return CE->getChosenSubExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const CXXDefaultArgExpr *DefaultArg
= dyn_cast<CXXDefaultArgExpr>(this)) {
// See through default argument expressions.
@@ -3078,7 +3122,8 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return NPCK_CXX11_nullptr;
if (const RecordType *UT = getType()->getAsUnionType())
- if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>())
+ if (!Ctx.getLangOpts().CPlusPlus11 &&
+ UT && UT->getDecl()->hasAttr<TransparentUnionAttr>())
if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(this)){
const Expr *InitExpr = CLE->getInitializer();
if (const InitListExpr *ILE = dyn_cast<InitListExpr>(InitExpr))
@@ -3089,14 +3134,19 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
(Ctx.getLangOpts().CPlusPlus && getType()->isEnumeralType()))
return NPCK_NotNull;
- // If we have an integer constant expression, we need to *evaluate* it and
- // test for the value 0. Don't use the C++11 constant expression semantics
- // for this, for now; once the dust settles on core issue 903, we might only
- // allow a literal 0 here in C++11 mode.
if (Ctx.getLangOpts().CPlusPlus11) {
- if (!isCXX98IntegralConstantExpr(Ctx))
+ // C++11 [conv.ptr]p1: A null pointer constant is an integer literal with
+ // value zero or a prvalue of type std::nullptr_t.
+ // Microsoft mode permits C++98 rules reflecting MSVC behavior.
+ const IntegerLiteral *Lit = dyn_cast<IntegerLiteral>(this);
+ if (Lit && !Lit->getValue())
+ return NPCK_ZeroLiteral;
+ else if (!Ctx.getLangOpts().MicrosoftMode ||
+ !isCXX98IntegralConstantExpr(Ctx))
return NPCK_NotNull;
} else {
+ // If we have an integer constant expression, we need to *evaluate* it and
+ // test for the value 0.
if (!isIntegerConstantExpr(Ctx))
return NPCK_NotNull;
}
@@ -3370,7 +3420,7 @@ void ObjCMessageExpr::initArgsAndSelLocs(ArrayRef<Expr *> Args,
}
}
-ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
SourceLocation SuperLoc,
@@ -3395,7 +3445,7 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
Method, Args, RBracLoc, isImplicit);
}
-ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
@@ -3418,7 +3468,7 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
isImplicit);
}
-ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ObjCMessageExpr *ObjCMessageExpr::Create(const ASTContext &Context, QualType T,
ExprValueKind VK,
SourceLocation LBracLoc,
Expr *Receiver,
@@ -3441,14 +3491,14 @@ ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
isImplicit);
}
-ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context,
+ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(const ASTContext &Context,
unsigned NumArgs,
unsigned NumStoredSelLocs) {
ObjCMessageExpr *Mem = alloc(Context, NumArgs, NumStoredSelLocs);
return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs);
}
-ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C,
+ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C,
ArrayRef<Expr *> Args,
SourceLocation RBraceLoc,
ArrayRef<SourceLocation> SelLocs,
@@ -3460,7 +3510,7 @@ ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C,
return alloc(C, Args.size(), NumStoredSelLocs);
}
-ObjCMessageExpr *ObjCMessageExpr::alloc(ASTContext &C,
+ObjCMessageExpr *ObjCMessageExpr::alloc(const ASTContext &C,
unsigned NumArgs,
unsigned NumStoredSelLocs) {
unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
@@ -3537,11 +3587,7 @@ StringRef ObjCBridgedCastExpr::getBridgeKindName() const {
llvm_unreachable("Invalid BridgeKind!");
}
-bool ChooseExpr::isConditionTrue(const ASTContext &C) const {
- return getCond()->EvaluateKnownConstInt(C) != 0;
-}
-
-ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args,
+ShuffleVectorExpr::ShuffleVectorExpr(const ASTContext &C, ArrayRef<Expr*> args,
QualType Type, SourceLocation BLoc,
SourceLocation RP)
: Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary,
@@ -3565,16 +3611,15 @@ ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args,
}
}
-void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs,
- unsigned NumExprs) {
+void ShuffleVectorExpr::setExprs(const ASTContext &C, ArrayRef<Expr *> Exprs) {
if (SubExprs) C.Deallocate(SubExprs);
- SubExprs = new (C) Stmt* [NumExprs];
- this->NumExprs = NumExprs;
- memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs);
+ this->NumExprs = Exprs.size();
+ SubExprs = new (C) Stmt*[NumExprs];
+ memcpy(SubExprs, Exprs.data(), sizeof(Expr *) * Exprs.size());
}
-GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs,
@@ -3600,7 +3645,7 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR);
}
-GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
+GenericSelectionExpr::GenericSelectionExpr(const ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
ArrayRef<TypeSourceInfo*> AssocTypes,
ArrayRef<Expr*> AssocExprs,
@@ -3637,7 +3682,7 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() const {
return getField()->getIdentifier();
}
-DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
+DesignatedInitExpr::DesignatedInitExpr(const ASTContext &C, QualType Ty,
unsigned NumDesignators,
const Designator *Designators,
SourceLocation EqualOrColonLoc,
@@ -3704,7 +3749,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
}
DesignatedInitExpr *
-DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
+DesignatedInitExpr::Create(const ASTContext &C, Designator *Designators,
unsigned NumDesignators,
ArrayRef<Expr*> IndexExprs,
SourceLocation ColonOrEqualLoc,
@@ -3716,14 +3761,14 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
IndexExprs, Init);
}
-DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C,
+DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(const ASTContext &C,
unsigned NumIndexExprs) {
void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
sizeof(Stmt *) * (NumIndexExprs + 1), 8);
return new (Mem) DesignatedInitExpr(NumIndexExprs + 1);
}
-void DesignatedInitExpr::setDesignators(ASTContext &C,
+void DesignatedInitExpr::setDesignators(const ASTContext &C,
const Designator *Desigs,
unsigned NumDesigs) {
Designators = new (C) Designator[NumDesigs];
@@ -3790,7 +3835,7 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const {
/// \brief Replaces the designator at index @p Idx with the series
/// of designators in [First, Last).
-void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
+void DesignatedInitExpr::ExpandDesignator(const ASTContext &C, unsigned Idx,
const Designator *First,
const Designator *Last) {
unsigned NumNewDesignators = Last - First;
@@ -3815,7 +3860,7 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
NumDesignators = NumDesignators - 1 + NumNewDesignators;
}
-ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
+ParenListExpr::ParenListExpr(const ASTContext& C, SourceLocation lparenloc,
ArrayRef<Expr*> exprs,
SourceLocation rparenloc)
: Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary,
@@ -3847,7 +3892,8 @@ const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
return cast<OpaqueValueExpr>(e);
}
-PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &Context, EmptyShell sh,
+PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &Context,
+ EmptyShell sh,
unsigned numSemanticExprs) {
void *buffer = Context.Allocate(sizeof(PseudoObjectExpr) +
(1 + numSemanticExprs) * sizeof(Expr*),
@@ -3860,7 +3906,7 @@ PseudoObjectExpr::PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs)
PseudoObjectExprBits.NumSubExprs = numSemanticExprs + 1;
}
-PseudoObjectExpr *PseudoObjectExpr::Create(ASTContext &C, Expr *syntax,
+PseudoObjectExpr *PseudoObjectExpr::Create(const ASTContext &C, Expr *syntax,
ArrayRef<Expr*> semantics,
unsigned resultIndex) {
assert(syntax && "no syntactic expression!");
@@ -3975,7 +4021,7 @@ ObjCArrayLiteral::ObjCArrayLiteral(ArrayRef<Expr *> Elements,
}
}
-ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C,
+ObjCArrayLiteral *ObjCArrayLiteral::Create(const ASTContext &C,
ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl * Method,
SourceRange SR) {
@@ -3984,7 +4030,7 @@ ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C,
return new (Mem) ObjCArrayLiteral(Elements, T, Method, SR);
}
-ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(ASTContext &C,
+ObjCArrayLiteral *ObjCArrayLiteral::CreateEmpty(const ASTContext &C,
unsigned NumElements) {
void *Mem = C.Allocate(sizeof(ObjCArrayLiteral)
@@ -4029,7 +4075,7 @@ ObjCDictionaryLiteral::ObjCDictionaryLiteral(
}
ObjCDictionaryLiteral *
-ObjCDictionaryLiteral::Create(ASTContext &C,
+ObjCDictionaryLiteral::Create(const ASTContext &C,
ArrayRef<ObjCDictionaryElement> VK,
bool HasPackExpansions,
QualType T, ObjCMethodDecl *method,
@@ -4044,7 +4090,7 @@ ObjCDictionaryLiteral::Create(ASTContext &C,
}
ObjCDictionaryLiteral *
-ObjCDictionaryLiteral::CreateEmpty(ASTContext &C, unsigned NumElements,
+ObjCDictionaryLiteral::CreateEmpty(const ASTContext &C, unsigned NumElements,
bool HasPackExpansions) {
unsigned ExpansionsSize = 0;
if (HasPackExpansions)
@@ -4055,7 +4101,7 @@ ObjCDictionaryLiteral::CreateEmpty(ASTContext &C, unsigned NumElements,
HasPackExpansions);
}
-ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(ASTContext &C,
+ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(const ASTContext &C,
Expr *base,
Expr *key, QualType T,
ObjCMethodDecl *getMethod,
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 402d7b5..3738c0e 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -40,46 +40,106 @@ bool CXXTypeidExpr::isPotentiallyEvaluated() const {
return false;
}
-QualType CXXTypeidExpr::getTypeOperand() const {
+QualType CXXTypeidExpr::getTypeOperand(ASTContext &Context) const {
assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)");
- return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType()
- .getUnqualifiedType();
+ Qualifiers Quals;
+ return Context.getUnqualifiedArrayType(
+ Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType(), Quals);
}
-QualType CXXUuidofExpr::getTypeOperand() const {
+QualType CXXUuidofExpr::getTypeOperand(ASTContext &Context) const {
assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)");
- return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType()
- .getUnqualifiedType();
+ Qualifiers Quals;
+ return Context.getUnqualifiedArrayType(
+ Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType(), Quals);
}
// static
-UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) {
+UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT,
+ bool *RDHasMultipleGUIDsPtr) {
// Optionally remove one level of pointer, reference or array indirection.
const Type *Ty = QT.getTypePtr();
if (QT->isPointerType() || QT->isReferenceType())
Ty = QT->getPointeeType().getTypePtr();
else if (QT->isArrayType())
- Ty = cast<ArrayType>(QT)->getElementType().getTypePtr();
+ Ty = Ty->getBaseElementTypeUnsafe();
// Loop all record redeclaration looking for an uuid attribute.
CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
+ if (!RD)
+ return 0;
+
+ // __uuidof can grab UUIDs from template arguments.
+ if (ClassTemplateSpecializationDecl *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ UuidAttr *UuidForRD = 0;
+
+ for (unsigned I = 0, N = TAL.size(); I != N; ++I) {
+ const TemplateArgument &TA = TAL[I];
+ bool SeenMultipleGUIDs = false;
+
+ UuidAttr *UuidForTA = 0;
+ if (TA.getKind() == TemplateArgument::Type)
+ UuidForTA = GetUuidAttrOfType(TA.getAsType(), &SeenMultipleGUIDs);
+ else if (TA.getKind() == TemplateArgument::Declaration)
+ UuidForTA =
+ GetUuidAttrOfType(TA.getAsDecl()->getType(), &SeenMultipleGUIDs);
+
+ // If the template argument has a UUID, there are three cases:
+ // - This is the first UUID seen for this RecordDecl.
+ // - This is a different UUID than previously seen for this RecordDecl.
+ // - This is the same UUID than previously seen for this RecordDecl.
+ if (UuidForTA) {
+ if (!UuidForRD)
+ UuidForRD = UuidForTA;
+ else if (UuidForRD != UuidForTA)
+ SeenMultipleGUIDs = true;
+ }
+
+ // Seeing multiple UUIDs means that we couldn't find a UUID
+ if (SeenMultipleGUIDs) {
+ if (RDHasMultipleGUIDsPtr)
+ *RDHasMultipleGUIDsPtr = true;
+ return 0;
+ }
+ }
+
+ return UuidForRD;
+ }
+
for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(),
- E = RD->redecls_end(); I != E; ++I) {
+ E = RD->redecls_end();
+ I != E; ++I)
if (UuidAttr *Uuid = I->getAttr<UuidAttr>())
return Uuid;
- }
return 0;
}
+StringRef CXXUuidofExpr::getUuidAsStringRef(ASTContext &Context) const {
+ StringRef Uuid;
+ if (isTypeOperand())
+ Uuid = CXXUuidofExpr::GetUuidAttrOfType(getTypeOperand(Context))->getGuid();
+ else {
+ // Special case: __uuidof(0) means an all-zero GUID.
+ Expr *Op = getExprOperand();
+ if (!Op->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull))
+ Uuid = CXXUuidofExpr::GetUuidAttrOfType(Op->getType())->getGuid();
+ else
+ Uuid = "00000000-0000-0000-0000-000000000000";
+ }
+ return Uuid;
+}
+
// CXXScalarValueInitExpr
SourceLocation CXXScalarValueInitExpr::getLocStart() const {
return TypeInfo ? TypeInfo->getTypeLoc().getBeginLoc() : RParenLoc;
}
// CXXNewExpr
-CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
- FunctionDecl *operatorDelete,
+CXXNewExpr::CXXNewExpr(const ASTContext &C, bool globalNew,
+ FunctionDecl *operatorNew, FunctionDecl *operatorDelete,
bool usualArrayDeleteWantsSize,
ArrayRef<Expr*> placementArgs,
SourceRange typeIdParens, Expr *arraySize,
@@ -134,11 +194,14 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
this->Range.setEnd(DirectInitRange.getEnd()); break;
case ListInit:
this->Range.setEnd(getInitializer()->getSourceRange().getEnd()); break;
- default: break;
+ default:
+ if (TypeIdParens.isValid())
+ this->Range.setEnd(TypeIdParens.getEnd());
+ break;
}
}
-void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
+void CXXNewExpr::AllocateArgsArray(const ASTContext &C, bool isArray,
unsigned numPlaceArgs, bool hasInitializer){
assert(SubExprs == 0 && "SubExprs already allocated");
Array = isArray;
@@ -148,7 +211,7 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
SubExprs = new (C) Stmt*[TotalSize];
}
-bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const {
+bool CXXNewExpr::shouldNullCheckAllocation(const ASTContext &Ctx) const {
return getOperatorNew()->getType()->
castAs<FunctionProtoType>()->isNothrow(Ctx);
}
@@ -172,14 +235,16 @@ PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info)
Location = Info->getTypeLoc().getLocalSourceRange().getBegin();
}
-CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
+CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(const ASTContext &Context,
Expr *Base, bool isArrow, SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc, TypeSourceInfo *ScopeType,
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
- Context.getPointerType(Context.getFunctionType(Context.VoidTy, None,
- FunctionProtoType::ExtProtoInfo())),
+ Context.getPointerType(Context.getFunctionType(
+ Context.VoidTy, None,
+ FunctionProtoType::ExtProtoInfo(
+ Context.getDefaultCallingConvention(false, true)))),
VK_RValue, OK_Ordinary,
/*isTypeDependent=*/(Base->isTypeDependent() ||
(DestroyedType.getTypeSourceInfo() &&
@@ -224,7 +289,7 @@ SourceLocation CXXPseudoDestructorExpr::getLocEnd() const {
// UnresolvedLookupExpr
UnresolvedLookupExpr *
-UnresolvedLookupExpr::Create(ASTContext &C,
+UnresolvedLookupExpr::Create(const ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
@@ -245,7 +310,7 @@ UnresolvedLookupExpr::Create(ASTContext &C,
}
UnresolvedLookupExpr *
-UnresolvedLookupExpr::CreateEmpty(ASTContext &C,
+UnresolvedLookupExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedLookupExpr);
@@ -258,7 +323,7 @@ UnresolvedLookupExpr::CreateEmpty(ASTContext &C,
return E;
}
-OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
+OverloadExpr::OverloadExpr(StmtClass K, const ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
@@ -330,7 +395,7 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
setType(C.DependentTy);
}
-void OverloadExpr::initializeResults(ASTContext &C,
+void OverloadExpr::initializeResults(const ASTContext &C,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End) {
assert(Results == 0 && "Results already initialized!");
@@ -386,11 +451,12 @@ DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T,
}
DependentScopeDeclRefExpr *
-DependentScopeDeclRefExpr::Create(ASTContext &C,
+DependentScopeDeclRefExpr::Create(const ASTContext &C,
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *Args) {
+ assert(QualifierLoc && "should be created for dependent qualifiers");
std::size_t size = sizeof(DependentScopeDeclRefExpr);
if (Args)
size += ASTTemplateKWAndArgsInfo::sizeFor(Args->size());
@@ -402,7 +468,7 @@ DependentScopeDeclRefExpr::Create(ASTContext &C,
}
DependentScopeDeclRefExpr *
-DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C,
+DependentScopeDeclRefExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(DependentScopeDeclRefExpr);
@@ -427,8 +493,8 @@ SourceLocation CXXConstructExpr::getLocEnd() const {
if (isa<CXXTemporaryObjectExpr>(this))
return cast<CXXTemporaryObjectExpr>(this)->getLocEnd();
- if (ParenRange.isValid())
- return ParenRange.getEnd();
+ if (ParenOrBraceRange.isValid())
+ return ParenOrBraceRange.getEnd();
SourceLocation End = Loc;
for (unsigned I = getNumArgs(); I > 0; --I) {
@@ -520,7 +586,7 @@ const char *CXXNamedCastExpr::getCastName() const {
}
}
-CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T,
+CXXStaticCastExpr *CXXStaticCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK,
CastKind K, Expr *Op,
const CXXCastPath *BasePath,
@@ -538,14 +604,14 @@ CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(ASTContext &C,
+CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(CXXStaticCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CXXStaticCastExpr(EmptyShell(), PathSize);
}
-CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T,
+CXXDynamicCastExpr *CXXDynamicCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK,
CastKind K, Expr *Op,
const CXXCastPath *BasePath,
@@ -563,7 +629,7 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T,
return E;
}
-CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C,
+CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(const ASTContext &C,
unsigned PathSize) {
void *Buffer =
C.Allocate(sizeof(CXXDynamicCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
@@ -604,8 +670,8 @@ bool CXXDynamicCastExpr::isAlwaysNull() const
}
CXXReinterpretCastExpr *
-CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
- CastKind K, Expr *Op,
+CXXReinterpretCastExpr::Create(const ASTContext &C, QualType T,
+ ExprValueKind VK, CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy, SourceLocation L,
SourceLocation RParenLoc,
@@ -621,13 +687,13 @@ CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
}
CXXReinterpretCastExpr *
-CXXReinterpretCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
+CXXReinterpretCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) {
void *Buffer = C.Allocate(sizeof(CXXReinterpretCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CXXReinterpretCastExpr(EmptyShell(), PathSize);
}
-CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T,
+CXXConstCastExpr *CXXConstCastExpr::Create(const ASTContext &C, QualType T,
ExprValueKind VK, Expr *Op,
TypeSourceInfo *WrittenTy,
SourceLocation L,
@@ -636,31 +702,39 @@ CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T,
return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc, AngleBrackets);
}
-CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) {
+CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(const ASTContext &C) {
return new (C) CXXConstCastExpr(EmptyShell());
}
CXXFunctionalCastExpr *
-CXXFunctionalCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
- TypeSourceInfo *Written, SourceLocation L,
- CastKind K, Expr *Op, const CXXCastPath *BasePath,
- SourceLocation R) {
+CXXFunctionalCastExpr::Create(const ASTContext &C, QualType T, ExprValueKind VK,
+ TypeSourceInfo *Written, CastKind K, Expr *Op,
+ const CXXCastPath *BasePath,
+ SourceLocation L, SourceLocation R) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXFunctionalCastExpr *E =
- new (Buffer) CXXFunctionalCastExpr(T, VK, Written, L, K, Op, PathSize, R);
+ new (Buffer) CXXFunctionalCastExpr(T, VK, Written, K, Op, PathSize, L, R);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
CXXFunctionalCastExpr *
-CXXFunctionalCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
+CXXFunctionalCastExpr::CreateEmpty(const ASTContext &C, unsigned PathSize) {
void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
return new (Buffer) CXXFunctionalCastExpr(EmptyShell(), PathSize);
}
+SourceLocation CXXFunctionalCastExpr::getLocStart() const {
+ return getTypeInfoAsWritten()->getTypeLoc().getLocStart();
+}
+
+SourceLocation CXXFunctionalCastExpr::getLocEnd() const {
+ return RParenLoc.isValid() ? RParenLoc : getSubExpr()->getLocEnd();
+}
+
UserDefinedLiteral::LiteralOperatorKind
UserDefinedLiteral::getLiteralOperatorKind() const {
if (getNumArgs() == 0)
@@ -696,14 +770,14 @@ const IdentifierInfo *UserDefinedLiteral::getUDSuffix() const {
}
CXXDefaultArgExpr *
-CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc,
+CXXDefaultArgExpr::Create(const ASTContext &C, SourceLocation Loc,
ParmVarDecl *Param, Expr *SubExpr) {
void *Mem = C.Allocate(sizeof(CXXDefaultArgExpr) + sizeof(Stmt *));
return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param,
SubExpr);
}
-CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc,
+CXXDefaultInitExpr::CXXDefaultInitExpr(const ASTContext &C, SourceLocation Loc,
FieldDecl *Field, QualType T)
: Expr(CXXDefaultInitExprClass, T.getNonLValueExprType(C),
T->isLValueReferenceType() ? VK_LValue : T->isRValueReferenceType()
@@ -714,12 +788,12 @@ CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc,
assert(Field->hasInClassInitializer());
}
-CXXTemporary *CXXTemporary::Create(ASTContext &C,
+CXXTemporary *CXXTemporary::Create(const ASTContext &C,
const CXXDestructorDecl *Destructor) {
return new (C) CXXTemporary(Destructor);
}
-CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
+CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(const ASTContext &C,
CXXTemporary *Temp,
Expr* SubExpr) {
assert((SubExpr->getType()->isRecordType() ||
@@ -729,11 +803,11 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
return new (C) CXXBindTemporaryExpr(Temp, SubExpr);
}
-CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
+CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(const ASTContext &C,
CXXConstructorDecl *Cons,
TypeSourceInfo *Type,
ArrayRef<Expr*> Args,
- SourceRange parenRange,
+ SourceRange ParenOrBraceRange,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization)
@@ -743,7 +817,7 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
Cons, false, Args,
HadMultipleCandidates,
ListInitialization, ZeroInitialization,
- CXXConstructExpr::CK_Complete, parenRange),
+ CXXConstructExpr::CK_Complete, ParenOrBraceRange),
Type(Type) {
}
@@ -752,10 +826,13 @@ SourceLocation CXXTemporaryObjectExpr::getLocStart() const {
}
SourceLocation CXXTemporaryObjectExpr::getLocEnd() const {
- return getParenRange().getEnd();
+ SourceLocation Loc = getParenOrBraceRange().getEnd();
+ if (Loc.isInvalid() && getNumArgs())
+ Loc = getArg(getNumArgs()-1)->getLocEnd();
+ return Loc;
}
-CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
+CXXConstructExpr *CXXConstructExpr::Create(const ASTContext &C, QualType T,
SourceLocation Loc,
CXXConstructorDecl *D, bool Elidable,
ArrayRef<Expr*> Args,
@@ -763,28 +840,29 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
- SourceRange ParenRange) {
+ SourceRange ParenOrBraceRange) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
Elidable, Args,
HadMultipleCandidates, ListInitialization,
ZeroInitialization, ConstructKind,
- ParenRange);
+ ParenOrBraceRange);
}
-CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
- SourceLocation Loc,
+CXXConstructExpr::CXXConstructExpr(const ASTContext &C, StmtClass SC,
+ QualType T, SourceLocation Loc,
CXXConstructorDecl *D, bool elidable,
ArrayRef<Expr*> args,
bool HadMultipleCandidates,
bool ListInitialization,
bool ZeroInitialization,
ConstructionKind ConstructKind,
- SourceRange ParenRange)
+ SourceRange ParenOrBraceRange)
: Expr(SC, T, VK_RValue, OK_Ordinary,
T->isDependentType(), T->isDependentType(),
T->isInstantiationDependentType(),
T->containsUnexpandedParameterPack()),
- Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(args.size()),
+ Constructor(D), Loc(Loc), ParenOrBraceRange(ParenOrBraceRange),
+ NumArgs(args.size()),
Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates),
ListInitialization(ListInitialization),
ZeroInitialization(ZeroInitialization),
@@ -811,7 +889,7 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
LambdaCaptureKind Kind, VarDecl *Var,
SourceLocation EllipsisLoc)
- : VarAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc)
+ : DeclAndBits(Var, 0), Loc(Loc), EllipsisLoc(EllipsisLoc)
{
unsigned Bits = 0;
if (Implicit)
@@ -829,20 +907,22 @@ LambdaExpr::Capture::Capture(SourceLocation Loc, bool Implicit,
assert(Var && "capture must have a variable!");
break;
}
- VarAndBits.setInt(Bits);
+ DeclAndBits.setInt(Bits);
}
LambdaCaptureKind LambdaExpr::Capture::getCaptureKind() const {
- if (capturesThis())
+ Decl *D = DeclAndBits.getPointer();
+ if (!D)
return LCK_This;
- return (VarAndBits.getInt() & Capture_ByCopy)? LCK_ByCopy : LCK_ByRef;
+ return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef;
}
-LambdaExpr::LambdaExpr(QualType T,
+LambdaExpr::LambdaExpr(QualType T,
SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
- ArrayRef<Capture> Captures,
+ SourceLocation CaptureDefaultLoc,
+ ArrayRef<Capture> Captures,
bool ExplicitParams,
bool ExplicitResultType,
ArrayRef<Expr *> CaptureInits,
@@ -854,6 +934,7 @@ LambdaExpr::LambdaExpr(QualType T,
T->isDependentType(), T->isDependentType(), T->isDependentType(),
ContainsUnexpandedParameterPack),
IntroducerRange(IntroducerRange),
+ CaptureDefaultLoc(CaptureDefaultLoc),
NumCaptures(Captures.size()),
CaptureDefault(CaptureDefault),
ExplicitParams(ExplicitParams),
@@ -867,7 +948,7 @@ LambdaExpr::LambdaExpr(QualType T,
// FIXME: Propagate "has unexpanded parameter pack" bit.
// Copy captures.
- ASTContext &Context = Class->getASTContext();
+ const ASTContext &Context = Class->getASTContext();
Data.NumCaptures = NumCaptures;
Data.NumExplicitCaptures = 0;
Data.Captures = (Capture *)Context.Allocate(sizeof(Capture) * NumCaptures);
@@ -899,11 +980,12 @@ LambdaExpr::LambdaExpr(QualType T,
}
}
-LambdaExpr *LambdaExpr::Create(ASTContext &Context,
+LambdaExpr *LambdaExpr::Create(const ASTContext &Context,
CXXRecordDecl *Class,
SourceRange IntroducerRange,
LambdaCaptureDefault CaptureDefault,
- ArrayRef<Capture> Captures,
+ SourceLocation CaptureDefaultLoc,
+ ArrayRef<Capture> Captures,
bool ExplicitParams,
bool ExplicitResultType,
ArrayRef<Expr *> CaptureInits,
@@ -923,13 +1005,15 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
Size += sizeof(VarDecl *) * ArrayIndexVars.size();
}
void *Mem = Context.Allocate(Size);
- return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault,
- Captures, ExplicitParams, ExplicitResultType,
+ return new (Mem) LambdaExpr(T, IntroducerRange,
+ CaptureDefault, CaptureDefaultLoc, Captures,
+ ExplicitParams, ExplicitResultType,
CaptureInits, ArrayIndexVars, ArrayIndexStarts,
ClosingBrace, ContainsUnexpandedParameterPack);
}
-LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures,
+LambdaExpr *LambdaExpr::CreateDeserialized(const ASTContext &C,
+ unsigned NumCaptures,
unsigned NumArrayIndexVars) {
unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (NumCaptures + 1);
if (NumArrayIndexVars)
@@ -984,13 +1068,13 @@ CXXRecordDecl *LambdaExpr::getLambdaClass() const {
CXXMethodDecl *LambdaExpr::getCallOperator() const {
CXXRecordDecl *Record = getLambdaClass();
- DeclarationName Name
- = Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
- DeclContext::lookup_result Calls = Record->lookup(Name);
- assert(!Calls.empty() && "Missing lambda call operator!");
- assert(Calls.size() == 1 && "More than one lambda call operator!");
- CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front());
- return Result;
+ return Record->getLambdaCallOperator();
+}
+
+TemplateParameterList *LambdaExpr::getTemplateParameterList() const {
+ CXXRecordDecl *Record = getLambdaClass();
+ return Record->getGenericLambdaTemplateParameterList();
+
}
CompoundStmt *LambdaExpr::getBody() const {
@@ -1017,7 +1101,7 @@ ExprWithCleanups::ExprWithCleanups(Expr *subexpr,
getObjectsBuffer()[i] = objects[i];
}
-ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, Expr *subexpr,
+ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C, Expr *subexpr,
ArrayRef<CleanupObject> objects) {
size_t size = sizeof(ExprWithCleanups)
+ objects.size() * sizeof(CleanupObject);
@@ -1030,7 +1114,8 @@ ExprWithCleanups::ExprWithCleanups(EmptyShell empty, unsigned numObjects)
ExprWithCleanupsBits.NumObjects = numObjects;
}
-ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, EmptyShell empty,
+ExprWithCleanups *ExprWithCleanups::Create(const ASTContext &C,
+ EmptyShell empty,
unsigned numObjects) {
size_t size = sizeof(ExprWithCleanups) + numObjects * sizeof(CleanupObject);
void *buffer = C.Allocate(size, llvm::alignOf<ExprWithCleanups>());
@@ -1063,7 +1148,7 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
}
CXXUnresolvedConstructExpr *
-CXXUnresolvedConstructExpr::Create(ASTContext &C,
+CXXUnresolvedConstructExpr::Create(const ASTContext &C,
TypeSourceInfo *Type,
SourceLocation LParenLoc,
ArrayRef<Expr*> Args,
@@ -1074,7 +1159,7 @@ CXXUnresolvedConstructExpr::Create(ASTContext &C,
}
CXXUnresolvedConstructExpr *
-CXXUnresolvedConstructExpr::CreateEmpty(ASTContext &C, unsigned NumArgs) {
+CXXUnresolvedConstructExpr::CreateEmpty(const ASTContext &C, unsigned NumArgs) {
Stmt::EmptyShell Empty;
void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) +
sizeof(Expr *) * NumArgs);
@@ -1085,7 +1170,7 @@ SourceLocation CXXUnresolvedConstructExpr::getLocStart() const {
return Type->getTypeLoc().getBeginLoc();
}
-CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
+CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
@@ -1121,7 +1206,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
}
}
-CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
+CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(const ASTContext &C,
Expr *Base, QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
@@ -1142,7 +1227,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
MemberNameInfo(MemberNameInfo) { }
CXXDependentScopeMemberExpr *
-CXXDependentScopeMemberExpr::Create(ASTContext &C,
+CXXDependentScopeMemberExpr::Create(const ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
@@ -1171,7 +1256,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
}
CXXDependentScopeMemberExpr *
-CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
+CXXDependentScopeMemberExpr::CreateEmpty(const ASTContext &C,
bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
if (!HasTemplateKWAndArgsInfo)
@@ -1222,7 +1307,7 @@ static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin,
return true;
}
-UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
+UnresolvedMemberExpr::UnresolvedMemberExpr(const ASTContext &C,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType,
bool IsArrow,
@@ -1260,8 +1345,7 @@ bool UnresolvedMemberExpr::isImplicitAccess() const {
}
UnresolvedMemberExpr *
-UnresolvedMemberExpr::Create(ASTContext &C,
- bool HasUnresolvedUsing,
+UnresolvedMemberExpr::Create(const ASTContext &C, bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc,
@@ -1284,7 +1368,8 @@ UnresolvedMemberExpr::Create(ASTContext &C,
}
UnresolvedMemberExpr *
-UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo,
+UnresolvedMemberExpr::CreateEmpty(const ASTContext &C,
+ bool HasTemplateKWAndArgsInfo,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedMemberExpr);
if (HasTemplateKWAndArgsInfo)
@@ -1352,7 +1437,7 @@ FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
}
FunctionParmPackExpr *
-FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
+FunctionParmPackExpr::Create(const ASTContext &Context, QualType T,
ParmVarDecl *ParamPack, SourceLocation NameLoc,
ArrayRef<Decl *> Params) {
return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
@@ -1361,7 +1446,8 @@ FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
}
FunctionParmPackExpr *
-FunctionParmPackExpr::CreateEmpty(ASTContext &Context, unsigned NumParams) {
+FunctionParmPackExpr::CreateEmpty(const ASTContext &Context,
+ unsigned NumParams) {
return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
sizeof(ParmVarDecl*) * NumParams))
FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0);
@@ -1396,7 +1482,7 @@ TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind,
}
}
-TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T,
+TypeTraitExpr *TypeTraitExpr::Create(const ASTContext &C, QualType T,
SourceLocation Loc,
TypeTrait Kind,
ArrayRef<TypeSourceInfo *> Args,
@@ -1407,7 +1493,7 @@ TypeTraitExpr *TypeTraitExpr::Create(ASTContext &C, QualType T,
return new (Mem) TypeTraitExpr(T, Loc, Kind, Args, RParenLoc, Value);
}
-TypeTraitExpr *TypeTraitExpr::CreateDeserialized(ASTContext &C,
+TypeTraitExpr *TypeTraitExpr::CreateDeserialized(const ASTContext &C,
unsigned NumArgs) {
unsigned Size = sizeof(TypeTraitExpr) + sizeof(TypeSourceInfo*) * NumArgs;
void *Mem = C.Allocate(Size);
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index bcb6d4e..54f77ef 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -155,6 +155,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::OffsetOfExprClass:
case Expr::CXXThrowExprClass:
case Expr::ShuffleVectorExprClass:
+ case Expr::ConvertVectorExprClass:
case Expr::IntegerLiteralClass:
case Expr::CharacterLiteralClass:
case Expr::AddrLabelExprClass:
@@ -286,13 +287,16 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// __builtin_choose_expr is equivalent to the chosen expression.
case Expr::ChooseExprClass:
- return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr(Ctx));
+ return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr());
// Extended vector element access is an lvalue unless there are duplicates
// in the shuffle expression.
case Expr::ExtVectorElementExprClass:
- return cast<ExtVectorElementExpr>(E)->containsDuplicateElements() ?
- Cl::CL_DuplicateVectorComponents : Cl::CL_LValue;
+ if (cast<ExtVectorElementExpr>(E)->containsDuplicateElements())
+ return Cl::CL_DuplicateVectorComponents;
+ if (cast<ExtVectorElementExpr>(E)->isArrow())
+ return Cl::CL_LValue;
+ return ClassifyInternal(Ctx, cast<ExtVectorElementExpr>(E)->getBase());
// Simply look at the actual default argument.
case Expr::CXXDefaultArgExprClass:
@@ -353,6 +357,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXConstructExprClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::LambdaExprClass:
+ case Expr::CXXStdInitializerListExprClass:
return Cl::CL_ClassTemporary;
case Expr::VAArgExprClass:
@@ -587,6 +592,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
// Const stuff is obviously not modifiable.
if (CT.isConstQualified())
return Cl::CM_ConstQualified;
+ if (CT.getQualifiers().getAddressSpace() == LangAS::opencl_constant)
+ return Cl::CM_ConstQualified;
// Arrays are not modifiable, only their elements are.
if (CT->isArrayType())
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 8c65029..390cfe9 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -23,8 +23,8 @@
// where it is possible to determine the evaluated result regardless.
//
// * A set of notes indicating why the evaluation was not a constant expression
-// (under the C++11 rules only, at the moment), or, if folding failed too,
-// why the expression could not be folded.
+// (under the C++11 / C++1y rules only, at the moment), or, if folding failed
+// too, why the expression could not be folded.
//
// If we are checking for a potential constant expression, failure to constant
// fold a potential constant sub-expression will be indicated by a 'false'
@@ -63,7 +63,25 @@ namespace {
if (!B) return QualType();
if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>())
return D->getType();
- return B.get<const Expr*>()->getType();
+
+ const Expr *Base = B.get<const Expr*>();
+
+ // For a materialized temporary, the type of the temporary we materialized
+ // may not be the type of the expression.
+ if (const MaterializeTemporaryExpr *MTE =
+ dyn_cast<MaterializeTemporaryExpr>(Base)) {
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ const Expr *Temp = MTE->GetTemporaryExpr();
+ const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs,
+ Adjustments);
+ // Keep any cv-qualifiers from the reference if we generated a temporary
+ // for it.
+ if (Inner != Temp)
+ return Inner->getType();
+ }
+
+ return Base->getType();
}
/// Get an LValue path entry, which is known to not be an array index, as a
@@ -284,7 +302,7 @@ namespace {
/// This - The binding for the this pointer in this call, if any.
const LValue *This;
- /// ParmBindings - Parameter bindings for this function call, indexed by
+ /// Arguments - Parameter bindings for this function call, indexed by
/// parameters' function scope indices.
APValue *Arguments;
@@ -299,6 +317,12 @@ namespace {
const FunctionDecl *Callee, const LValue *This,
APValue *Arguments);
~CallStackFrame();
+
+ APValue *getTemporary(const void *Key) {
+ MapTy::iterator I = Temporaries.find(Key);
+ return I == Temporaries.end() ? 0 : &I->second;
+ }
+ APValue &createTemporary(const void *Key, bool IsLifetimeExtended);
};
/// Temporarily override 'this'.
@@ -343,14 +367,37 @@ namespace {
OptionalDiagnostic &operator<<(const APFloat &F) {
if (Diag) {
+ // FIXME: Force the precision of the source value down so we don't
+ // print digits which are usually useless (we don't really care here if
+ // we truncate a digit by accident in edge cases). Ideally,
+ // APFloat::toString would automatically print the shortest
+ // representation which rounds to the correct value, but it's a bit
+ // tricky to implement.
+ unsigned precision =
+ llvm::APFloat::semanticsPrecision(F.getSemantics());
+ precision = (precision * 59 + 195) / 196;
SmallVector<char, 32> Buffer;
- F.toString(Buffer);
+ F.toString(Buffer, precision);
*Diag << StringRef(Buffer.data(), Buffer.size());
}
return *this;
}
};
+ /// A cleanup, and a flag indicating whether it is lifetime-extended.
+ class Cleanup {
+ llvm::PointerIntPair<APValue*, 1, bool> Value;
+
+ public:
+ Cleanup(APValue *Val, bool IsLifetimeExtended)
+ : Value(Val, IsLifetimeExtended) {}
+
+ bool isLifetimeExtended() const { return Value.getInt(); }
+ void endLifetime() {
+ *Value.getPointer() = APValue();
+ }
+ };
+
/// EvalInfo - This is a private struct used by the evaluator to capture
/// information about a subexpression as it is folded. It retains information
/// about the AST context, but also maintains information about the folded
@@ -380,13 +427,22 @@ namespace {
/// NextCallIndex - The next call index to assign.
unsigned NextCallIndex;
+ /// StepsLeft - The remaining number of evaluation steps we're permitted
+ /// to perform. This is essentially a limit for the number of statements
+ /// we will evaluate.
+ unsigned StepsLeft;
+
/// BottomFrame - The frame in which evaluation started. This must be
/// initialized after CurrentCall and CallStackDepth.
CallStackFrame BottomFrame;
+ /// A stack of values whose lifetimes end at the end of some surrounding
+ /// evaluation frame.
+ llvm::SmallVector<Cleanup, 16> CleanupStack;
+
/// EvaluatingDecl - This is the declaration whose initializer is being
/// evaluated, if any.
- const VarDecl *EvaluatingDecl;
+ APValue::LValueBase EvaluatingDecl;
/// EvaluatingDeclValue - This is the value being constructed for the
/// declaration whose initializer is being evaluated, if any.
@@ -396,24 +452,52 @@ namespace {
/// notes attached to it will also be stored, otherwise they will not be.
bool HasActiveDiagnostic;
- /// CheckingPotentialConstantExpression - Are we checking whether the
- /// expression is a potential constant expression? If so, some diagnostics
- /// are suppressed.
- bool CheckingPotentialConstantExpression;
-
- bool IntOverflowCheckMode;
+ enum EvaluationMode {
+ /// Evaluate as a constant expression. Stop if we find that the expression
+ /// is not a constant expression.
+ EM_ConstantExpression,
+
+ /// Evaluate as a potential constant expression. Keep going if we hit a
+ /// construct that we can't evaluate yet (because we don't yet know the
+ /// value of something) but stop if we hit something that could never be
+ /// a constant expression.
+ EM_PotentialConstantExpression,
+
+ /// Fold the expression to a constant. Stop if we hit a side-effect that
+ /// we can't model.
+ EM_ConstantFold,
+
+ /// Evaluate the expression looking for integer overflow and similar
+ /// issues. Don't worry about side-effects, and try to visit all
+ /// subexpressions.
+ EM_EvaluateForOverflow,
- EvalInfo(const ASTContext &C, Expr::EvalStatus &S,
- bool OverflowCheckMode=false)
+ /// Evaluate in any way we know how. Don't worry about side-effects that
+ /// can't be modeled.
+ EM_IgnoreSideEffects
+ } EvalMode;
+
+ /// Are we checking whether the expression is a potential constant
+ /// expression?
+ bool checkingPotentialConstantExpression() const {
+ return EvalMode == EM_PotentialConstantExpression;
+ }
+
+ /// Are we checking an expression for overflow?
+ // FIXME: We should check for any kind of undefined or suspicious behavior
+ // in such constructs, not just overflow.
+ bool checkingForOverflow() { return EvalMode == EM_EvaluateForOverflow; }
+
+ EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode)
: Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
CallStackDepth(0), NextCallIndex(1),
+ StepsLeft(getLangOpts().ConstexprStepLimit),
BottomFrame(*this, SourceLocation(), 0, 0, 0),
- EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false),
- CheckingPotentialConstantExpression(false),
- IntOverflowCheckMode(OverflowCheckMode) {}
+ EvaluatingDecl((const ValueDecl*)0), EvaluatingDeclValue(0),
+ HasActiveDiagnostic(false), EvalMode(Mode) {}
- void setEvaluatingDecl(const VarDecl *VD, APValue &Value) {
- EvaluatingDecl = VD;
+ void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
+ EvaluatingDecl = Base;
EvaluatingDeclValue = &Value;
}
@@ -422,7 +506,7 @@ namespace {
bool CheckCallLimit(SourceLocation Loc) {
// Don't perform any constexpr calls (other than the call we're checking)
// when checking a potential constant expression.
- if (CheckingPotentialConstantExpression && CallStackDepth > 1)
+ if (checkingPotentialConstantExpression() && CallStackDepth > 1)
return false;
if (NextCallIndex == 0) {
// NextCallIndex has wrapped around.
@@ -446,6 +530,15 @@ namespace {
return (Frame->Index == CallIndex) ? Frame : 0;
}
+ bool nextStep(const Stmt *S) {
+ if (!StepsLeft) {
+ Diag(S->getLocStart(), diag::note_constexpr_step_limit_exceeded);
+ return false;
+ }
+ --StepsLeft;
+ return true;
+ }
+
private:
/// Add a diagnostic to the diagnostics list.
PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) {
@@ -462,22 +555,41 @@ namespace {
OptionalDiagnostic Diag(SourceLocation Loc, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
unsigned ExtraNotes = 0) {
- // If we have a prior diagnostic, it will be noting that the expression
- // isn't a constant expression. This diagnostic is more important.
- // FIXME: We might want to show both diagnostics to the user.
if (EvalStatus.Diag) {
+ // If we have a prior diagnostic, it will be noting that the expression
+ // isn't a constant expression. This diagnostic is more important,
+ // unless we require this evaluation to produce a constant expression.
+ //
+ // FIXME: We might want to show both diagnostics to the user in
+ // EM_ConstantFold mode.
+ if (!EvalStatus.Diag->empty()) {
+ switch (EvalMode) {
+ case EM_ConstantFold:
+ case EM_IgnoreSideEffects:
+ case EM_EvaluateForOverflow:
+ if (!EvalStatus.HasSideEffects)
+ break;
+ // We've had side-effects; we want the diagnostic from them, not
+ // some later problem.
+ case EM_ConstantExpression:
+ case EM_PotentialConstantExpression:
+ HasActiveDiagnostic = false;
+ return OptionalDiagnostic();
+ }
+ }
+
unsigned CallStackNotes = CallStackDepth - 1;
unsigned Limit = Ctx.getDiagnostics().getConstexprBacktraceLimit();
if (Limit)
CallStackNotes = std::min(CallStackNotes, Limit + 1);
- if (CheckingPotentialConstantExpression)
+ if (checkingPotentialConstantExpression())
CallStackNotes = 0;
HasActiveDiagnostic = true;
EvalStatus.Diag->clear();
EvalStatus.Diag->reserve(1 + ExtraNotes + CallStackNotes);
addDiag(Loc, DiagId);
- if (!CheckingPotentialConstantExpression)
+ if (!checkingPotentialConstantExpression())
addCallStack(Limit);
return OptionalDiagnostic(&(*EvalStatus.Diag)[0].second);
}
@@ -494,15 +606,17 @@ namespace {
return OptionalDiagnostic();
}
- bool getIntOverflowCheckMode() { return IntOverflowCheckMode; }
-
/// Diagnose that the evaluation does not produce a C++11 core constant
/// expression.
+ ///
+ /// FIXME: Stop evaluating if we're in EM_ConstantExpression or
+ /// EM_PotentialConstantExpression mode and we produce one of these.
template<typename LocArg>
OptionalDiagnostic CCEDiag(LocArg Loc, diag::kind DiagId
= diag::note_invalid_subexpr_in_const_expr,
unsigned ExtraNotes = 0) {
- // Don't override a previous diagnostic.
+ // Don't override a previous diagnostic. Don't bother collecting
+ // diagnostics if we're evaluating for overflow.
if (!EvalStatus.Diag || !EvalStatus.Diag->empty()) {
HasActiveDiagnostic = false;
return OptionalDiagnostic();
@@ -525,30 +639,72 @@ namespace {
}
}
+ /// Should we continue evaluation after encountering a side-effect that we
+ /// couldn't model?
+ bool keepEvaluatingAfterSideEffect() {
+ switch (EvalMode) {
+ case EM_PotentialConstantExpression:
+ case EM_EvaluateForOverflow:
+ case EM_IgnoreSideEffects:
+ return true;
+
+ case EM_ConstantExpression:
+ case EM_ConstantFold:
+ return false;
+ }
+ llvm_unreachable("Missed EvalMode case");
+ }
+
+ /// Note that we have had a side-effect, and determine whether we should
+ /// keep evaluating.
+ bool noteSideEffect() {
+ EvalStatus.HasSideEffects = true;
+ return keepEvaluatingAfterSideEffect();
+ }
+
/// Should we continue evaluation as much as possible after encountering a
- /// construct which can't be folded?
+ /// construct which can't be reduced to a value?
bool keepEvaluatingAfterFailure() {
- // Should return true in IntOverflowCheckMode, so that we check for
- // overflow even if some subexpressions can't be evaluated as constants.
- return IntOverflowCheckMode ||
- (CheckingPotentialConstantExpression &&
- EvalStatus.Diag && EvalStatus.Diag->empty());
+ if (!StepsLeft)
+ return false;
+
+ switch (EvalMode) {
+ case EM_PotentialConstantExpression:
+ case EM_EvaluateForOverflow:
+ return true;
+
+ case EM_ConstantExpression:
+ case EM_ConstantFold:
+ case EM_IgnoreSideEffects:
+ return false;
+ }
+ llvm_unreachable("Missed EvalMode case");
}
};
/// Object used to treat all foldable expressions as constant expressions.
struct FoldConstant {
+ EvalInfo &Info;
bool Enabled;
-
- explicit FoldConstant(EvalInfo &Info)
- : Enabled(Info.EvalStatus.Diag && Info.EvalStatus.Diag->empty() &&
- !Info.EvalStatus.HasSideEffects) {
- }
- // Treat the value we've computed since this object was created as constant.
- void Fold(EvalInfo &Info) {
- if (Enabled && !Info.EvalStatus.Diag->empty() &&
+ bool HadNoPriorDiags;
+ EvalInfo::EvaluationMode OldMode;
+
+ explicit FoldConstant(EvalInfo &Info, bool Enabled)
+ : Info(Info),
+ Enabled(Enabled),
+ HadNoPriorDiags(Info.EvalStatus.Diag &&
+ Info.EvalStatus.Diag->empty() &&
+ !Info.EvalStatus.HasSideEffects),
+ OldMode(Info.EvalMode) {
+ if (Enabled && Info.EvalMode == EvalInfo::EM_ConstantExpression)
+ Info.EvalMode = EvalInfo::EM_ConstantFold;
+ }
+ void keepDiagnostics() { Enabled = false; }
+ ~FoldConstant() {
+ if (Enabled && HadNoPriorDiags && !Info.EvalStatus.Diag->empty() &&
!Info.EvalStatus.HasSideEffects)
Info.EvalStatus.Diag->clear();
+ Info.EvalMode = OldMode;
}
};
@@ -563,11 +719,50 @@ namespace {
SmallVectorImpl<PartialDiagnosticAt> *NewDiag = 0)
: Info(Info), Old(Info.EvalStatus) {
Info.EvalStatus.Diag = NewDiag;
+ // If we're speculatively evaluating, we may have skipped over some
+ // evaluations and missed out a side effect.
+ Info.EvalStatus.HasSideEffects = true;
}
~SpeculativeEvaluationRAII() {
Info.EvalStatus = Old;
}
};
+
+ /// RAII object wrapping a full-expression or block scope, and handling
+ /// the ending of the lifetime of temporaries created within it.
+ template<bool IsFullExpression>
+ class ScopeRAII {
+ EvalInfo &Info;
+ unsigned OldStackSize;
+ public:
+ ScopeRAII(EvalInfo &Info)
+ : Info(Info), OldStackSize(Info.CleanupStack.size()) {}
+ ~ScopeRAII() {
+ // Body moved to a static method to encourage the compiler to inline away
+ // instances of this class.
+ cleanup(Info, OldStackSize);
+ }
+ private:
+ static void cleanup(EvalInfo &Info, unsigned OldStackSize) {
+ unsigned NewEnd = OldStackSize;
+ for (unsigned I = OldStackSize, N = Info.CleanupStack.size();
+ I != N; ++I) {
+ if (IsFullExpression && Info.CleanupStack[I].isLifetimeExtended()) {
+ // Full-expression cleanup of a lifetime-extended temporary: nothing
+ // to do, just move this cleanup to the right place in the stack.
+ std::swap(Info.CleanupStack[I], Info.CleanupStack[NewEnd]);
+ ++NewEnd;
+ } else {
+ // End the lifetime of the object.
+ Info.CleanupStack[I].endLifetime();
+ }
+ }
+ Info.CleanupStack.erase(Info.CleanupStack.begin() + NewEnd,
+ Info.CleanupStack.end());
+ }
+ };
+ typedef ScopeRAII<false> BlockScopeRAII;
+ typedef ScopeRAII<true> FullExpressionRAII;
}
bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
@@ -610,32 +805,16 @@ CallStackFrame::~CallStackFrame() {
Info.CurrentCall = Caller;
}
-/// Produce a string describing the given constexpr call.
-static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
- unsigned ArgIndex = 0;
- bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
- !isa<CXXConstructorDecl>(Frame->Callee) &&
- cast<CXXMethodDecl>(Frame->Callee)->isInstance();
-
- if (!IsMemberCall)
- Out << *Frame->Callee << '(';
-
- for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(),
- E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) {
- if (ArgIndex > (unsigned)IsMemberCall)
- Out << ", ";
-
- const ParmVarDecl *Param = *I;
- const APValue &Arg = Frame->Arguments[ArgIndex];
- Arg.printPretty(Out, Frame->Info.Ctx, Param->getType());
-
- if (ArgIndex == 0 && IsMemberCall)
- Out << "->" << *Frame->Callee << '(';
- }
-
- Out << ')';
+APValue &CallStackFrame::createTemporary(const void *Key,
+ bool IsLifetimeExtended) {
+ APValue &Result = Temporaries[Key];
+ assert(Result.isUninit() && "temporary created multiple times");
+ Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended));
+ return Result;
}
+static void describeCall(CallStackFrame *Frame, raw_ostream &Out);
+
void EvalInfo::addCallStack(unsigned Limit) {
// Determine which calls to skip, if any.
unsigned ActiveCalls = CallStackDepth - 1;
@@ -884,19 +1063,11 @@ namespace {
return false;
return LHS.Path == RHS.Path;
}
-
- /// Kinds of constant expression checking, for diagnostics.
- enum CheckConstantExpressionKind {
- CCEK_Constant, ///< A normal constant.
- CCEK_ReturnValue, ///< A constexpr function return value.
- CCEK_MemberInit ///< A constexpr constructor mem-initializer.
- };
}
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
const LValue &This, const Expr *E,
- CheckConstantExpressionKind CCEK = CCEK_Constant,
bool AllowNonLiteralTypes = false);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
@@ -908,23 +1079,66 @@ static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result,
EvalInfo &Info);
static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
+static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info);
//===----------------------------------------------------------------------===//
// Misc utilities
//===----------------------------------------------------------------------===//
+/// Produce a string describing the given constexpr call.
+static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
+ unsigned ArgIndex = 0;
+ bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
+ !isa<CXXConstructorDecl>(Frame->Callee) &&
+ cast<CXXMethodDecl>(Frame->Callee)->isInstance();
+
+ if (!IsMemberCall)
+ Out << *Frame->Callee << '(';
+
+ if (Frame->This && IsMemberCall) {
+ APValue Val;
+ Frame->This->moveInto(Val);
+ Val.printPretty(Out, Frame->Info.Ctx,
+ Frame->This->Designator.MostDerivedType);
+ // FIXME: Add parens around Val if needed.
+ Out << "->" << *Frame->Callee << '(';
+ IsMemberCall = false;
+ }
+
+ for (FunctionDecl::param_const_iterator I = Frame->Callee->param_begin(),
+ E = Frame->Callee->param_end(); I != E; ++I, ++ArgIndex) {
+ if (ArgIndex > (unsigned)IsMemberCall)
+ Out << ", ";
+
+ const ParmVarDecl *Param = *I;
+ const APValue &Arg = Frame->Arguments[ArgIndex];
+ Arg.printPretty(Out, Frame->Info.Ctx, Param->getType());
+
+ if (ArgIndex == 0 && IsMemberCall)
+ Out << "->" << *Frame->Callee << '(';
+ }
+
+ Out << ')';
+}
+
/// Evaluate an expression to see if it had side-effects, and discard its
/// result.
/// \return \c true if the caller should keep evaluating.
static bool EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) {
APValue Scratch;
- if (!Evaluate(Scratch, Info, E)) {
- Info.EvalStatus.HasSideEffects = true;
- return Info.keepEvaluatingAfterFailure();
- }
+ if (!Evaluate(Scratch, Info, E))
+ // We don't need the value, but we might have skipped a side effect here.
+ return Info.noteSideEffect();
return true;
}
+/// Sign- or zero-extend a value to 64 bits. If it's already 64 bits, just
+/// return its existing value.
+static int64_t getExtValue(const APSInt &Value) {
+ return Value.isSigned() ? Value.getSExtValue()
+ : static_cast<int64_t>(Value.getZExtValue());
+}
+
/// Should this call expression be treated as a string literal?
static bool IsStringLiteralCall(const CallExpr *E) {
unsigned Builtin = E->isBuiltinCall();
@@ -956,6 +1170,10 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
const CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
return CLE->isFileScope() && CLE->isLValue();
}
+ case Expr::MaterializeTemporaryExprClass:
+ // A materialized temporary might have been lifetime-extended to static
+ // storage duration.
+ return cast<MaterializeTemporaryExpr>(E)->getStorageDuration() == SD_Static;
// A string literal has static storage duration.
case Expr::StringLiteralClass:
case Expr::PredefinedExprClass:
@@ -1020,7 +1238,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// Don't allow references to temporaries to escape.
return false;
}
- assert((Info.CheckingPotentialConstantExpression ||
+ assert((Info.checkingPotentialConstantExpression() ||
LVal.getLValueCallIndex() == 0) &&
"have call index for global lvalue");
@@ -1057,10 +1275,18 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
/// Check that this core constant expression is of literal type, and if not,
/// produce an appropriate diagnostic.
-static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
+static bool CheckLiteralType(EvalInfo &Info, const Expr *E,
+ const LValue *This = 0) {
if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx))
return true;
+ // C++1y: A constant initializer for an object o [...] may also invoke
+ // constexpr constructors for o and its subobjects even if those objects
+ // are of non-literal class types.
+ if (Info.getLangOpts().CPlusPlus1y && This &&
+ Info.EvaluatingDecl == This->getLValueBase())
+ return true;
+
// Prvalue constant expressions must be of literal types.
if (Info.getLangOpts().CPlusPlus11)
Info.Diag(E, diag::note_constexpr_nonliteral)
@@ -1075,6 +1301,12 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
/// check that the expression is of literal type.
static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
QualType Type, const APValue &Value) {
+ if (Value.isUninit()) {
+ Info.Diag(DiagLoc, diag::note_constexpr_uninitialized)
+ << true << Type;
+ return false;
+ }
+
// Core issue 1454: For a literal constant expression of array or class type,
// each subobject of its value shall have been initialized by a constant
// expression.
@@ -1129,7 +1361,10 @@ const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
}
static bool IsLiteralLValue(const LValue &Value) {
- return Value.Base.dyn_cast<const Expr*>() && !Value.CallIndex;
+ if (Value.CallIndex)
+ return false;
+ const Expr *E = Value.Base.dyn_cast<const Expr*>();
+ return E && !isa<MaterializeTemporaryExpr>(E);
}
static bool IsWeakLValue(const LValue &Value) {
@@ -1252,6 +1487,27 @@ static bool HandleIntToFloatCast(EvalInfo &Info, const Expr *E,
return true;
}
+static bool truncateBitfieldValue(EvalInfo &Info, const Expr *E,
+ APValue &Value, const FieldDecl *FD) {
+ assert(FD->isBitField() && "truncateBitfieldValue on non-bitfield");
+
+ if (!Value.isInt()) {
+ // Trying to store a pointer-cast-to-integer into a bitfield.
+ // FIXME: In this case, we should provide the diagnostic for casting
+ // a pointer to an integer.
+ assert(Value.isLValue() && "integral value neither int nor lvalue?");
+ Info.Diag(E);
+ return false;
+ }
+
+ APSInt &Int = Value.getInt();
+ unsigned OldBitWidth = Int.getBitWidth();
+ unsigned NewBitWidth = FD->getBitWidthValue(Info.Ctx);
+ if (NewBitWidth < OldBitWidth)
+ Int = Int.trunc(NewBitWidth).extend(OldBitWidth);
+ return true;
+}
+
static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
llvm::APInt &Res) {
APValue SVal;
@@ -1299,6 +1555,155 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
return false;
}
+/// Perform the given integer operation, which is known to need at most BitWidth
+/// bits, and check for overflow in the original type (if that type was not an
+/// unsigned type).
+template<typename Operation>
+static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
+ const APSInt &LHS, const APSInt &RHS,
+ unsigned BitWidth, Operation Op) {
+ if (LHS.isUnsigned())
+ return Op(LHS, RHS);
+
+ APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
+ APSInt Result = Value.trunc(LHS.getBitWidth());
+ if (Result.extend(BitWidth) != Value) {
+ if (Info.checkingForOverflow())
+ Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
+ diag::warn_integer_constant_overflow)
+ << Result.toString(10) << E->getType();
+ else
+ HandleOverflow(Info, E, Value, E->getType());
+ }
+ return Result;
+}
+
+/// Perform the given binary integer operation.
+static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS,
+ BinaryOperatorKind Opcode, APSInt RHS,
+ APSInt &Result) {
+ switch (Opcode) {
+ default:
+ Info.Diag(E);
+ return false;
+ case BO_Mul:
+ Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() * 2,
+ std::multiplies<APSInt>());
+ return true;
+ case BO_Add:
+ Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
+ std::plus<APSInt>());
+ return true;
+ case BO_Sub:
+ Result = CheckedIntArithmetic(Info, E, LHS, RHS, LHS.getBitWidth() + 1,
+ std::minus<APSInt>());
+ return true;
+ case BO_And: Result = LHS & RHS; return true;
+ case BO_Xor: Result = LHS ^ RHS; return true;
+ case BO_Or: Result = LHS | RHS; return true;
+ case BO_Div:
+ case BO_Rem:
+ if (RHS == 0) {
+ Info.Diag(E, diag::note_expr_divide_by_zero);
+ return false;
+ }
+ // Check for overflow case: INT_MIN / -1 or INT_MIN % -1.
+ if (RHS.isNegative() && RHS.isAllOnesValue() &&
+ LHS.isSigned() && LHS.isMinSignedValue())
+ HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType());
+ Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS);
+ return true;
+ case BO_Shl: {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such
+ // a shift is not a constant expression.
+ Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
+ RHS = -RHS;
+ goto shift_right;
+ }
+ shift_left:
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of
+ // the shifted type.
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ if (SA != RHS) {
+ Info.CCEDiag(E, diag::note_constexpr_large_shift)
+ << RHS << E->getType() << LHS.getBitWidth();
+ } else if (LHS.isSigned()) {
+ // C++11 [expr.shift]p2: A signed left shift must have a non-negative
+ // operand, and must not overflow the corresponding unsigned type.
+ if (LHS.isNegative())
+ Info.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS;
+ else if (LHS.countLeadingZeros() < SA)
+ Info.CCEDiag(E, diag::note_constexpr_lshift_discards);
+ }
+ Result = LHS << SA;
+ return true;
+ }
+ case BO_Shr: {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such a
+ // shift is not a constant expression.
+ Info.CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
+ RHS = -RHS;
+ goto shift_left;
+ }
+ shift_right:
+ // C++11 [expr.shift]p1: Shift width must be less than the bit width of the
+ // shifted type.
+ unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+ if (SA != RHS)
+ Info.CCEDiag(E, diag::note_constexpr_large_shift)
+ << RHS << E->getType() << LHS.getBitWidth();
+ Result = LHS >> SA;
+ return true;
+ }
+
+ case BO_LT: Result = LHS < RHS; return true;
+ case BO_GT: Result = LHS > RHS; return true;
+ case BO_LE: Result = LHS <= RHS; return true;
+ case BO_GE: Result = LHS >= RHS; return true;
+ case BO_EQ: Result = LHS == RHS; return true;
+ case BO_NE: Result = LHS != RHS; return true;
+ }
+}
+
+/// Perform the given binary floating-point operation, in-place, on LHS.
+static bool handleFloatFloatBinOp(EvalInfo &Info, const Expr *E,
+ APFloat &LHS, BinaryOperatorKind Opcode,
+ const APFloat &RHS) {
+ switch (Opcode) {
+ default:
+ Info.Diag(E);
+ return false;
+ case BO_Mul:
+ LHS.multiply(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case BO_Add:
+ LHS.add(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case BO_Sub:
+ LHS.subtract(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ case BO_Div:
+ LHS.divide(RHS, APFloat::rmNearestTiesToEven);
+ break;
+ }
+
+ if (LHS.isInfinity() || LHS.isNaN())
+ Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
+ return true;
+}
+
/// Cast an lvalue referring to a base subobject to a derived class, by
/// truncating the lvalue's path to the given length.
static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
@@ -1369,6 +1774,19 @@ static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj,
return true;
}
+static bool HandleLValueBasePath(EvalInfo &Info, const CastExpr *E,
+ QualType Type, LValue &Result) {
+ for (CastExpr::path_const_iterator PathI = E->path_begin(),
+ PathE = E->path_end();
+ PathI != PathE; ++PathI) {
+ if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
+ *PathI))
+ return false;
+ Type = (*PathI)->getType();
+ }
+ return true;
+}
+
/// Update LVal to refer to the given field, which must be a member of the type
/// currently described by LVal.
static bool HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
@@ -1470,7 +1888,7 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
// Assume arguments of a potential constant expression are unknown
// constant expressions.
- if (Info.CheckingPotentialConstantExpression)
+ if (Info.checkingPotentialConstantExpression())
return false;
if (!Frame || !Frame->Arguments) {
Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
@@ -1482,11 +1900,9 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// If this is a local variable, dig out its value.
if (Frame) {
- Result = &Frame->Temporaries[VD];
- // If we've carried on past an unevaluatable local variable initializer,
- // we can't go any further. This can happen during potential constant
- // expression checking.
- return !Result->isUninit();
+ Result = Frame->getTemporary(VD);
+ assert(Result && "missing value for local variable");
+ return true;
}
// Dig out the initializer, and use the declaration which it's attached to.
@@ -1494,16 +1910,16 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
if (!Init || Init->isValueDependent()) {
// If we're checking a potential constant expression, the variable could be
// initialized later.
- if (!Info.CheckingPotentialConstantExpression)
+ if (!Info.checkingPotentialConstantExpression())
Info.Diag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
// If we're currently evaluating the initializer of this declaration, use that
// in-flight value.
- if (Info.EvaluatingDecl == VD) {
+ if (Info.EvaluatingDecl.dyn_cast<const ValueDecl*>() == VD) {
Result = Info.EvaluatingDeclValue;
- return !Result->isUninit();
+ return true;
}
// Never evaluate the initializer of a weak variable. We can't be sure that
@@ -1615,7 +2031,7 @@ static void expandArray(APValue &Array, unsigned Index) {
Array.swap(NewValue);
}
-/// Kinds of access we can perform on an object.
+/// Kinds of access we can perform on an object, for diagnostics.
enum AccessKinds {
AK_Read,
AK_Assign,
@@ -1637,7 +2053,7 @@ struct CompleteObject {
assert(Value && "missing value for complete object");
}
- operator bool() const { return Value; }
+ LLVM_EXPLICIT operator bool() const { return Value; }
};
/// Find the designated sub-object of an rvalue.
@@ -1656,16 +2072,33 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
Info.Diag(E);
return handler.failed();
}
- if (Sub.Entries.empty())
- return handler.found(*Obj.Value, Obj.Type);
- if (Info.CheckingPotentialConstantExpression && Obj.Value->isUninit())
- // This object might be initialized later.
- return handler.failed();
APValue *O = Obj.Value;
QualType ObjType = Obj.Type;
+ const FieldDecl *LastField = 0;
+
// Walk the designator's path to find the subobject.
- for (unsigned I = 0, N = Sub.Entries.size(); I != N; ++I) {
+ for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) {
+ if (O->isUninit()) {
+ if (!Info.checkingPotentialConstantExpression())
+ Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind;
+ return handler.failed();
+ }
+
+ if (I == N) {
+ if (!handler.found(*O, ObjType))
+ return false;
+
+ // If we modified a bit-field, truncate it to the right width.
+ if (handler.AccessKind != AK_Read &&
+ LastField && LastField->isBitField() &&
+ !truncateBitfieldValue(Info, E, *O, LastField))
+ return false;
+
+ return true;
+ }
+
+ LastField = 0;
if (ObjType->isArrayType()) {
// Next subobject is an array element.
const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(ObjType);
@@ -1767,6 +2200,8 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
}
return handler.failed();
}
+
+ LastField = Field;
} else {
// Next subobject is a base class.
const CXXRecordDecl *Derived = ObjType->getAsCXXRecordDecl();
@@ -1778,15 +2213,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (WasConstQualified)
ObjType.addConst();
}
-
- if (O->isUninit()) {
- if (!Info.CheckingPotentialConstantExpression)
- Info.Diag(E, diag::note_constexpr_access_uninit) << handler.AccessKind;
- return handler.failed();
- }
}
-
- return handler.found(*O, ObjType);
}
namespace {
@@ -1963,9 +2390,6 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
NoteLValueLocation(Info, LVal.Base);
return CompleteObject();
}
- } else if (AK != AK_Read) {
- Info.Diag(E, diag::note_constexpr_modify_global);
- return CompleteObject();
}
// C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type
@@ -1983,7 +2407,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
// Compute value storage location and type of base object.
APValue *BaseVal = 0;
- QualType BaseType;
+ QualType BaseType = getType(LVal.Base);
if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) {
// In C++98, const, non-volatile integers initialized with ICEs are ICEs.
@@ -2004,7 +2428,6 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
}
// Accesses of volatile-qualified objects are not allowed.
- BaseType = VD->getType();
if (BaseType.isVolatileQualified()) {
if (Info.getLangOpts().CPlusPlus) {
Info.Diag(E, diag::note_constexpr_access_volatile_obj, 1)
@@ -2019,8 +2442,16 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
// Unless we're looking at a local variable or argument in a constexpr call,
// the variable we're reading must be const.
if (!Frame) {
- assert(AK == AK_Read && "can't modify non-local");
- if (VD->isConstexpr()) {
+ if (Info.getLangOpts().CPlusPlus1y &&
+ VD == Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()) {
+ // OK, we can read and modify an object if we're in the process of
+ // evaluating its initializer, because its lifetime began in this
+ // evaluation.
+ } else if (AK != AK_Read) {
+ // All the remaining cases only permit reading.
+ Info.Diag(E, diag::note_constexpr_modify_global);
+ return CompleteObject();
+ } else if (VD->isConstexpr()) {
// OK, we can read this variable.
} else if (BaseType->isIntegralOrEnumerationType()) {
if (!BaseType.isConstQualified()) {
@@ -2060,12 +2491,45 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
if (!Frame) {
- Info.Diag(E);
- return CompleteObject();
- }
+ if (const MaterializeTemporaryExpr *MTE =
+ dyn_cast<MaterializeTemporaryExpr>(Base)) {
+ assert(MTE->getStorageDuration() == SD_Static &&
+ "should have a frame for a non-global materialized temporary");
+
+ // Per C++1y [expr.const]p2:
+ // an lvalue-to-rvalue conversion [is not allowed unless it applies to]
+ // - a [...] glvalue of integral or enumeration type that refers to
+ // a non-volatile const object [...]
+ // [...]
+ // - a [...] glvalue of literal type that refers to a non-volatile
+ // object whose lifetime began within the evaluation of e.
+ //
+ // C++11 misses the 'began within the evaluation of e' check and
+ // instead allows all temporaries, including things like:
+ // int &&r = 1;
+ // int x = ++r;
+ // constexpr int k = r;
+ // Therefore we use the C++1y rules in C++11 too.
+ const ValueDecl *VD = Info.EvaluatingDecl.dyn_cast<const ValueDecl*>();
+ const ValueDecl *ED = MTE->getExtendingDecl();
+ if (!(BaseType.isConstQualified() &&
+ BaseType->isIntegralOrEnumerationType()) &&
+ !(VD && VD->getCanonicalDecl() == ED->getCanonicalDecl())) {
+ Info.Diag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
+ Info.Note(MTE->getExprLoc(), diag::note_constexpr_temporary_here);
+ return CompleteObject();
+ }
- BaseType = Base->getType();
- BaseVal = &Frame->Temporaries[Base];
+ BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false);
+ assert(BaseVal && "got reference to unevaluated temporary");
+ } else {
+ Info.Diag(E);
+ return CompleteObject();
+ }
+ } else {
+ BaseVal = Frame->getTemporary(Base);
+ assert(BaseVal && "missing value for temporary");
+ }
// Volatile temporary objects cannot be accessed in constant expressions.
if (BaseType.isVolatileQualified()) {
@@ -2080,10 +2544,22 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK,
}
}
- // In C++1y, we can't safely access any mutable state when checking a
- // potential constant expression.
+ // During the construction of an object, it is not yet 'const'.
+ // FIXME: We don't set up EvaluatingDecl for local variables or temporaries,
+ // and this doesn't do quite the right thing for const subobjects of the
+ // object under construction.
+ if (LVal.getLValueBase() == Info.EvaluatingDecl) {
+ BaseType = Info.Ctx.getCanonicalType(BaseType);
+ BaseType.removeLocalConst();
+ }
+
+ // In C++1y, we can't safely access any mutable state when we might be
+ // evaluating after an unmodeled side effect or an evaluation failure.
+ //
+ // FIXME: Not all local state is mutable. Allow local constant subobjects
+ // to be read here (but take care with 'mutable' fields).
if (Frame && Info.getLangOpts().CPlusPlus1y &&
- Info.CheckingPotentialConstantExpression)
+ (Info.EvalStatus.HasSideEffects || Info.keepEvaluatingAfterFailure()))
return CompleteObject();
return CompleteObject(BaseVal, BaseType);
@@ -2159,6 +2635,124 @@ static bool isOverflowingIntegerType(ASTContext &Ctx, QualType T) {
}
namespace {
+struct CompoundAssignSubobjectHandler {
+ EvalInfo &Info;
+ const Expr *E;
+ QualType PromotedLHSType;
+ BinaryOperatorKind Opcode;
+ const APValue &RHS;
+
+ static const AccessKinds AccessKind = AK_Assign;
+
+ typedef bool result_type;
+
+ bool checkConst(QualType QT) {
+ // Assigning to a const object has undefined behavior.
+ if (QT.isConstQualified()) {
+ Info.Diag(E, diag::note_constexpr_modify_const_type) << QT;
+ return false;
+ }
+ return true;
+ }
+
+ bool failed() { return false; }
+ bool found(APValue &Subobj, QualType SubobjType) {
+ switch (Subobj.getKind()) {
+ case APValue::Int:
+ return found(Subobj.getInt(), SubobjType);
+ case APValue::Float:
+ return found(Subobj.getFloat(), SubobjType);
+ case APValue::ComplexInt:
+ case APValue::ComplexFloat:
+ // FIXME: Implement complex compound assignment.
+ Info.Diag(E);
+ return false;
+ case APValue::LValue:
+ return foundPointer(Subobj, SubobjType);
+ default:
+ // FIXME: can this happen?
+ Info.Diag(E);
+ return false;
+ }
+ }
+ bool found(APSInt &Value, QualType SubobjType) {
+ if (!checkConst(SubobjType))
+ return false;
+
+ if (!SubobjType->isIntegerType() || !RHS.isInt()) {
+ // We don't support compound assignment on integer-cast-to-pointer
+ // values.
+ Info.Diag(E);
+ return false;
+ }
+
+ APSInt LHS = HandleIntToIntCast(Info, E, PromotedLHSType,
+ SubobjType, Value);
+ if (!handleIntIntBinOp(Info, E, LHS, Opcode, RHS.getInt(), LHS))
+ return false;
+ Value = HandleIntToIntCast(Info, E, SubobjType, PromotedLHSType, LHS);
+ return true;
+ }
+ bool found(APFloat &Value, QualType SubobjType) {
+ return checkConst(SubobjType) &&
+ HandleFloatToFloatCast(Info, E, SubobjType, PromotedLHSType,
+ Value) &&
+ handleFloatFloatBinOp(Info, E, Value, Opcode, RHS.getFloat()) &&
+ HandleFloatToFloatCast(Info, E, PromotedLHSType, SubobjType, Value);
+ }
+ bool foundPointer(APValue &Subobj, QualType SubobjType) {
+ if (!checkConst(SubobjType))
+ return false;
+
+ QualType PointeeType;
+ if (const PointerType *PT = SubobjType->getAs<PointerType>())
+ PointeeType = PT->getPointeeType();
+
+ if (PointeeType.isNull() || !RHS.isInt() ||
+ (Opcode != BO_Add && Opcode != BO_Sub)) {
+ Info.Diag(E);
+ return false;
+ }
+
+ int64_t Offset = getExtValue(RHS.getInt());
+ if (Opcode == BO_Sub)
+ Offset = -Offset;
+
+ LValue LVal;
+ LVal.setFrom(Info.Ctx, Subobj);
+ if (!HandleLValueArrayAdjustment(Info, E, LVal, PointeeType, Offset))
+ return false;
+ LVal.moveInto(Subobj);
+ return true;
+ }
+ bool foundString(APValue &Subobj, QualType SubobjType, uint64_t Character) {
+ llvm_unreachable("shouldn't encounter string elements here");
+ }
+};
+} // end anonymous namespace
+
+const AccessKinds CompoundAssignSubobjectHandler::AccessKind;
+
+/// Perform a compound assignment of LVal <op>= RVal.
+static bool handleCompoundAssignment(
+ EvalInfo &Info, const Expr *E,
+ const LValue &LVal, QualType LValType, QualType PromotedLValType,
+ BinaryOperatorKind Opcode, const APValue &RVal) {
+ if (LVal.Designator.Invalid)
+ return false;
+
+ if (!Info.getLangOpts().CPlusPlus1y) {
+ Info.Diag(E);
+ return false;
+ }
+
+ CompleteObject Obj = findCompleteObject(Info, E, AK_Assign, LVal, LValType);
+ CompoundAssignSubobjectHandler Handler = { Info, E, PromotedLValType, Opcode,
+ RVal };
+ return Obj && findSubobject(Info, E, Obj, LVal.Designator, Handler);
+}
+
+namespace {
struct IncDecSubobjectHandler {
EvalInfo &Info;
const Expr *E;
@@ -2326,54 +2920,53 @@ static bool EvaluateObjectArgument(EvalInfo &Info, const Expr *Object,
/// lvalue referring to the result.
///
/// \param Info - Information about the ongoing evaluation.
-/// \param BO - The member pointer access operation.
-/// \param LV - Filled in with a reference to the resulting object.
+/// \param LV - An lvalue referring to the base of the member pointer.
+/// \param RHS - The member pointer expression.
/// \param IncludeMember - Specifies whether the member itself is included in
/// the resulting LValue subobject designator. This is not possible when
/// creating a bound member function.
/// \return The field or method declaration to which the member pointer refers,
/// or 0 if evaluation fails.
static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
- const BinaryOperator *BO,
+ QualType LVType,
LValue &LV,
+ const Expr *RHS,
bool IncludeMember = true) {
- assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI);
-
- bool EvalObjOK = EvaluateObjectArgument(Info, BO->getLHS(), LV);
- if (!EvalObjOK && !Info.keepEvaluatingAfterFailure())
- return 0;
-
MemberPtr MemPtr;
- if (!EvaluateMemberPointer(BO->getRHS(), MemPtr, Info))
+ if (!EvaluateMemberPointer(RHS, MemPtr, Info))
return 0;
// C++11 [expr.mptr.oper]p6: If the second operand is the null pointer to
// member value, the behavior is undefined.
- if (!MemPtr.getDecl())
- return 0;
-
- if (!EvalObjOK)
+ if (!MemPtr.getDecl()) {
+ // FIXME: Specific diagnostic.
+ Info.Diag(RHS);
return 0;
+ }
if (MemPtr.isDerivedMember()) {
// This is a member of some derived class. Truncate LV appropriately.
// The end of the derived-to-base path for the base object must match the
// derived-to-base path for the member pointer.
if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() >
- LV.Designator.Entries.size())
+ LV.Designator.Entries.size()) {
+ Info.Diag(RHS);
return 0;
+ }
unsigned PathLengthToMember =
LV.Designator.Entries.size() - MemPtr.Path.size();
for (unsigned I = 0, N = MemPtr.Path.size(); I != N; ++I) {
const CXXRecordDecl *LVDecl = getAsBaseClass(
LV.Designator.Entries[PathLengthToMember + I]);
const CXXRecordDecl *MPDecl = MemPtr.Path[I];
- if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl())
+ if (LVDecl->getCanonicalDecl() != MPDecl->getCanonicalDecl()) {
+ Info.Diag(RHS);
return 0;
+ }
}
// Truncate the lvalue to the appropriate derived class.
- if (!CastToDerivedClass(Info, BO, LV, MemPtr.getContainingRecord(),
+ if (!CastToDerivedClass(Info, RHS, LV, MemPtr.getContainingRecord(),
PathLengthToMember))
return 0;
} else if (!MemPtr.Path.empty()) {
@@ -2382,7 +2975,6 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
MemPtr.Path.size() + IncludeMember);
// Walk down to the appropriate base class.
- QualType LVType = BO->getLHS()->getType();
if (const PointerType *PT = LVType->getAs<PointerType>())
LVType = PT->getPointeeType();
const CXXRecordDecl *RD = LVType->getAsCXXRecordDecl();
@@ -2390,23 +2982,24 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
// The first class in the path is that of the lvalue.
for (unsigned I = 1, N = MemPtr.Path.size(); I != N; ++I) {
const CXXRecordDecl *Base = MemPtr.Path[N - I - 1];
- if (!HandleLValueDirectBase(Info, BO, LV, RD, Base))
+ if (!HandleLValueDirectBase(Info, RHS, LV, RD, Base))
return 0;
RD = Base;
}
// Finally cast to the class containing the member.
- if (!HandleLValueDirectBase(Info, BO, LV, RD, MemPtr.getContainingRecord()))
+ if (!HandleLValueDirectBase(Info, RHS, LV, RD,
+ MemPtr.getContainingRecord()))
return 0;
}
// Add the member. Note that we cannot build bound member functions here.
if (IncludeMember) {
if (const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl())) {
- if (!HandleLValueMember(Info, BO, LV, FD))
+ if (!HandleLValueMember(Info, RHS, LV, FD))
return 0;
} else if (const IndirectFieldDecl *IFD =
dyn_cast<IndirectFieldDecl>(MemPtr.getDecl())) {
- if (!HandleLValueIndirectMember(Info, BO, LV, IFD))
+ if (!HandleLValueIndirectMember(Info, RHS, LV, IFD))
return 0;
} else {
llvm_unreachable("can't construct reference to bound member function");
@@ -2416,6 +3009,24 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
return MemPtr.getDecl();
}
+static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
+ const BinaryOperator *BO,
+ LValue &LV,
+ bool IncludeMember = true) {
+ assert(BO->getOpcode() == BO_PtrMemD || BO->getOpcode() == BO_PtrMemI);
+
+ if (!EvaluateObjectArgument(Info, BO->getLHS(), LV)) {
+ if (Info.keepEvaluatingAfterFailure()) {
+ MemberPtr MemPtr;
+ EvaluateMemberPointer(BO->getRHS(), MemPtr, Info);
+ }
+ return 0;
+ }
+
+ return HandleMemberPointerAccess(Info, BO->getLHS()->getType(), LV,
+ BO->getRHS(), IncludeMember);
+}
+
/// HandleBaseToDerivedCast - Apply the given base-to-derived cast operation on
/// the provided lvalue, which currently refers to the base object.
static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
@@ -2465,7 +3076,9 @@ enum EvalStmtResult {
/// Hit a 'continue' statement.
ESR_Continue,
/// Hit a 'break' statement.
- ESR_Break
+ ESR_Break,
+ /// Still scanning for 'case' or 'default' statement.
+ ESR_CaseNotFound
};
}
@@ -2477,7 +3090,14 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
LValue Result;
Result.set(VD, Info.CurrentCall->Index);
- APValue &Val = Info.CurrentCall->Temporaries[VD];
+ APValue &Val = Info.CurrentCall->createTemporary(VD, true);
+
+ if (!VD->getInit()) {
+ Info.Diag(D->getLocStart(), diag::note_constexpr_uninitialized)
+ << false << VD->getType();
+ Val = APValue();
+ return false;
+ }
if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) {
// Wipe out any partially-computed value, to allow tracking that this
@@ -2493,18 +3113,21 @@ static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
/// Evaluate a condition (either a variable declaration or an expression).
static bool EvaluateCond(EvalInfo &Info, const VarDecl *CondDecl,
const Expr *Cond, bool &Result) {
+ FullExpressionRAII Scope(Info);
if (CondDecl && !EvaluateDecl(Info, CondDecl))
return false;
return EvaluateAsBooleanCondition(Cond, Result, Info);
}
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
- const Stmt *S);
+ const Stmt *S, const SwitchCase *SC = 0);
/// Evaluate the body of a loop, and translate the result as appropriate.
static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,
- const Stmt *Body) {
- switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body)) {
+ const Stmt *Body,
+ const SwitchCase *Case = 0) {
+ BlockScopeRAII Scope(Info);
+ switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, Body, Case)) {
case ESR_Break:
return ESR_Succeeded;
case ESR_Succeeded:
@@ -2512,21 +3135,149 @@ static EvalStmtResult EvaluateLoopBody(APValue &Result, EvalInfo &Info,
return ESR_Continue;
case ESR_Failed:
case ESR_Returned:
+ case ESR_CaseNotFound:
+ return ESR;
+ }
+ llvm_unreachable("Invalid EvalStmtResult!");
+}
+
+/// Evaluate a switch statement.
+static EvalStmtResult EvaluateSwitch(APValue &Result, EvalInfo &Info,
+ const SwitchStmt *SS) {
+ BlockScopeRAII Scope(Info);
+
+ // Evaluate the switch condition.
+ APSInt Value;
+ {
+ FullExpressionRAII Scope(Info);
+ if (SS->getConditionVariable() &&
+ !EvaluateDecl(Info, SS->getConditionVariable()))
+ return ESR_Failed;
+ if (!EvaluateInteger(SS->getCond(), Value, Info))
+ return ESR_Failed;
+ }
+
+ // Find the switch case corresponding to the value of the condition.
+ // FIXME: Cache this lookup.
+ const SwitchCase *Found = 0;
+ for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
+ SC = SC->getNextSwitchCase()) {
+ if (isa<DefaultStmt>(SC)) {
+ Found = SC;
+ continue;
+ }
+
+ const CaseStmt *CS = cast<CaseStmt>(SC);
+ APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx);
+ APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx)
+ : LHS;
+ if (LHS <= Value && Value <= RHS) {
+ Found = SC;
+ break;
+ }
+ }
+
+ if (!Found)
+ return ESR_Succeeded;
+
+ // Search the switch body for the switch case and evaluate it from there.
+ switch (EvalStmtResult ESR = EvaluateStmt(Result, Info, SS->getBody(), Found)) {
+ case ESR_Break:
+ return ESR_Succeeded;
+ case ESR_Succeeded:
+ case ESR_Continue:
+ case ESR_Failed:
+ case ESR_Returned:
return ESR;
+ case ESR_CaseNotFound:
+ // This can only happen if the switch case is nested within a statement
+ // expression. We have no intention of supporting that.
+ Info.Diag(Found->getLocStart(), diag::note_constexpr_stmt_expr_unsupported);
+ return ESR_Failed;
}
llvm_unreachable("Invalid EvalStmtResult!");
}
// Evaluate a statement.
static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
- const Stmt *S) {
- // FIXME: Mark all temporaries in the current frame as destroyed at
- // the end of each full-expression.
+ const Stmt *S, const SwitchCase *Case) {
+ if (!Info.nextStep(S))
+ return ESR_Failed;
+
+ // If we're hunting down a 'case' or 'default' label, recurse through
+ // substatements until we hit the label.
+ if (Case) {
+ // FIXME: We don't start the lifetime of objects whose initialization we
+ // jump over. However, such objects must be of class type with a trivial
+ // default constructor that initialize all subobjects, so must be empty,
+ // so this almost never matters.
+ switch (S->getStmtClass()) {
+ case Stmt::CompoundStmtClass:
+ // FIXME: Precompute which substatement of a compound statement we
+ // would jump to, and go straight there rather than performing a
+ // linear scan each time.
+ case Stmt::LabelStmtClass:
+ case Stmt::AttributedStmtClass:
+ case Stmt::DoStmtClass:
+ break;
+
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ if (Case == S)
+ Case = 0;
+ break;
+
+ case Stmt::IfStmtClass: {
+ // FIXME: Precompute which side of an 'if' we would jump to, and go
+ // straight there rather than scanning both sides.
+ const IfStmt *IS = cast<IfStmt>(S);
+
+ // Wrap the evaluation in a block scope, in case it's a DeclStmt
+ // preceded by our switch label.
+ BlockScopeRAII Scope(Info);
+
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, IS->getThen(), Case);
+ if (ESR != ESR_CaseNotFound || !IS->getElse())
+ return ESR;
+ return EvaluateStmt(Result, Info, IS->getElse(), Case);
+ }
+
+ case Stmt::WhileStmtClass: {
+ EvalStmtResult ESR =
+ EvaluateLoopBody(Result, Info, cast<WhileStmt>(S)->getBody(), Case);
+ if (ESR != ESR_Continue)
+ return ESR;
+ break;
+ }
+
+ case Stmt::ForStmtClass: {
+ const ForStmt *FS = cast<ForStmt>(S);
+ EvalStmtResult ESR =
+ EvaluateLoopBody(Result, Info, FS->getBody(), Case);
+ if (ESR != ESR_Continue)
+ return ESR;
+ if (FS->getInc()) {
+ FullExpressionRAII IncScope(Info);
+ if (!EvaluateIgnoredValue(Info, FS->getInc()))
+ return ESR_Failed;
+ }
+ break;
+ }
+
+ case Stmt::DeclStmtClass:
+ // FIXME: If the variable has initialization that can't be jumped over,
+ // bail out of any immediately-surrounding compound-statement too.
+ default:
+ return ESR_CaseNotFound;
+ }
+ }
+
switch (S->getStmtClass()) {
default:
if (const Expr *E = dyn_cast<Expr>(S)) {
// Don't bother evaluating beyond an expression-statement which couldn't
// be evaluated.
+ FullExpressionRAII Scope(Info);
if (!EvaluateIgnoredValue(Info, E))
return ESR_Failed;
return ESR_Succeeded;
@@ -2541,34 +3292,45 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
case Stmt::DeclStmtClass: {
const DeclStmt *DS = cast<DeclStmt>(S);
for (DeclStmt::const_decl_iterator DclIt = DS->decl_begin(),
- DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt)
+ DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt) {
+ // Each declaration initialization is its own full-expression.
+ // FIXME: This isn't quite right; if we're performing aggregate
+ // initialization, each braced subexpression is its own full-expression.
+ FullExpressionRAII Scope(Info);
if (!EvaluateDecl(Info, *DclIt) && !Info.keepEvaluatingAfterFailure())
return ESR_Failed;
+ }
return ESR_Succeeded;
}
case Stmt::ReturnStmtClass: {
const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue();
+ FullExpressionRAII Scope(Info);
if (RetExpr && !Evaluate(Result, Info, RetExpr))
return ESR_Failed;
return ESR_Returned;
}
case Stmt::CompoundStmtClass: {
+ BlockScopeRAII Scope(Info);
+
const CompoundStmt *CS = cast<CompoundStmt>(S);
for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
BE = CS->body_end(); BI != BE; ++BI) {
- EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI);
- if (ESR != ESR_Succeeded)
+ EvalStmtResult ESR = EvaluateStmt(Result, Info, *BI, Case);
+ if (ESR == ESR_Succeeded)
+ Case = 0;
+ else if (ESR != ESR_CaseNotFound)
return ESR;
}
- return ESR_Succeeded;
+ return Case ? ESR_CaseNotFound : ESR_Succeeded;
}
case Stmt::IfStmtClass: {
const IfStmt *IS = cast<IfStmt>(S);
// Evaluate the condition, as either a var decl or as an expression.
+ BlockScopeRAII Scope(Info);
bool Cond;
if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond))
return ESR_Failed;
@@ -2584,6 +3346,7 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
case Stmt::WhileStmtClass: {
const WhileStmt *WS = cast<WhileStmt>(S);
while (true) {
+ BlockScopeRAII Scope(Info);
bool Continue;
if (!EvaluateCond(Info, WS->getConditionVariable(), WS->getCond(),
Continue))
@@ -2602,10 +3365,12 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
const DoStmt *DS = cast<DoStmt>(S);
bool Continue;
do {
- EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody());
+ EvalStmtResult ESR = EvaluateLoopBody(Result, Info, DS->getBody(), Case);
if (ESR != ESR_Continue)
return ESR;
+ Case = 0;
+ FullExpressionRAII CondScope(Info);
if (!EvaluateAsBooleanCondition(DS->getCond(), Continue, Info))
return ESR_Failed;
} while (Continue);
@@ -2614,12 +3379,14 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
case Stmt::ForStmtClass: {
const ForStmt *FS = cast<ForStmt>(S);
+ BlockScopeRAII Scope(Info);
if (FS->getInit()) {
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getInit());
if (ESR != ESR_Succeeded)
return ESR;
}
while (true) {
+ BlockScopeRAII Scope(Info);
bool Continue = true;
if (FS->getCond() && !EvaluateCond(Info, FS->getConditionVariable(),
FS->getCond(), Continue))
@@ -2631,14 +3398,18 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
if (ESR != ESR_Continue)
return ESR;
- if (FS->getInc() && !EvaluateIgnoredValue(Info, FS->getInc()))
- return ESR_Failed;
+ if (FS->getInc()) {
+ FullExpressionRAII IncScope(Info);
+ if (!EvaluateIgnoredValue(Info, FS->getInc()))
+ return ESR_Failed;
+ }
}
return ESR_Succeeded;
}
case Stmt::CXXForRangeStmtClass: {
const CXXForRangeStmt *FS = cast<CXXForRangeStmt>(S);
+ BlockScopeRAII Scope(Info);
// Initialize the __range variable.
EvalStmtResult ESR = EvaluateStmt(Result, Info, FS->getRangeStmt());
@@ -2652,13 +3423,17 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
while (true) {
// Condition: __begin != __end.
- bool Continue = true;
- if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info))
- return ESR_Failed;
- if (!Continue)
- break;
+ {
+ bool Continue = true;
+ FullExpressionRAII CondExpr(Info);
+ if (!EvaluateAsBooleanCondition(FS->getCond(), Continue, Info))
+ return ESR_Failed;
+ if (!Continue)
+ break;
+ }
// User's variable declaration, initialized by *__begin.
+ BlockScopeRAII InnerScope(Info);
ESR = EvaluateStmt(Result, Info, FS->getLoopVarStmt());
if (ESR != ESR_Succeeded)
return ESR;
@@ -2676,11 +3451,27 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
return ESR_Succeeded;
}
+ case Stmt::SwitchStmtClass:
+ return EvaluateSwitch(Result, Info, cast<SwitchStmt>(S));
+
case Stmt::ContinueStmtClass:
return ESR_Continue;
case Stmt::BreakStmtClass:
return ESR_Break;
+
+ case Stmt::LabelStmtClass:
+ return EvaluateStmt(Result, Info, cast<LabelStmt>(S)->getSubStmt(), Case);
+
+ case Stmt::AttributedStmtClass:
+ // As a general principle, C++11 attributes can be ignored without
+ // any semantic impact.
+ return EvaluateStmt(Result, Info, cast<AttributedStmt>(S)->getSubStmt(),
+ Case);
+
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ return EvaluateStmt(Result, Info, cast<SwitchCase>(S)->getSubStmt(), Case);
}
}
@@ -2718,10 +3509,15 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
const FunctionDecl *Definition) {
// Potential constant expressions can contain calls to declared, but not yet
// defined, constexpr functions.
- if (Info.CheckingPotentialConstantExpression && !Definition &&
+ if (Info.checkingPotentialConstantExpression() && !Definition &&
Declaration->isConstexpr())
return false;
+ // Bail out with no diagnostic if the function declaration itself is invalid.
+ // We will have produced a relevant diagnostic while parsing it.
+ if (Declaration->isInvalidDecl())
+ return false;
+
// Can we evaluate this function call?
if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
return true;
@@ -2774,6 +3570,27 @@ static bool HandleFunctionCall(SourceLocation CallLoc,
return false;
CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data());
+
+ // For a trivial copy or move assignment, perform an APValue copy. This is
+ // essential for unions, where the operations performed by the assignment
+ // operator cannot be represented as statements.
+ const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee);
+ if (MD && MD->isDefaulted() && MD->isTrivial()) {
+ assert(This &&
+ (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()));
+ LValue RHS;
+ RHS.setFrom(Info.Ctx, ArgValues[0]);
+ APValue RHSValue;
+ if (!handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(),
+ RHS, RHSValue))
+ return false;
+ if (!handleAssignment(Info, Args[0], *This, MD->getThisType(Info.Ctx),
+ RHSValue))
+ return false;
+ This->moveInto(Result);
+ return true;
+ }
+
EvalStmtResult ESR = EvaluateStmt(Result, Info, Body);
if (ESR == ESR_Succeeded) {
if (Callee->getResultType()->isVoidType())
@@ -2806,8 +3623,11 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
// If it's a delegating constructor, just delegate.
if (Definition->isDelegatingConstructor()) {
CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
- if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()))
- return false;
+ {
+ FullExpressionRAII InitScope(Info);
+ if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()))
+ return false;
+ }
return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed;
}
@@ -2831,6 +3651,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
+ // A scope for temporaries lifetime-extended by reference members.
+ BlockScopeRAII LifetimeExtendedScope(Info);
+
bool Success = true;
unsigned BasesSeen = 0;
#ifndef NDEBUG
@@ -2842,6 +3665,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
APValue *Value = &Result;
// Determine the subobject to initialize.
+ FieldDecl *FD = 0;
if ((*I)->isBaseInitializer()) {
QualType BaseType((*I)->getBaseClass(), 0);
#ifndef NDEBUG
@@ -2856,7 +3680,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
BaseType->getAsCXXRecordDecl(), &Layout))
return false;
Value = &Result.getStructBase(BasesSeen++);
- } else if (FieldDecl *FD = (*I)->getMember()) {
+ } else if ((FD = (*I)->getMember())) {
if (!HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout))
return false;
if (RD->isUnion()) {
@@ -2871,7 +3695,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
for (IndirectFieldDecl::chain_iterator C = IFD->chain_begin(),
CE = IFD->chain_end();
C != CE; ++C) {
- FieldDecl *FD = cast<FieldDecl>(*C);
+ FD = cast<FieldDecl>(*C);
CXXRecordDecl *CD = cast<CXXRecordDecl>(FD->getParent());
// Switch the union field if it differs. This happens if we had
// preceding zero-initialization, and we're now initializing a union
@@ -2897,9 +3721,10 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
llvm_unreachable("unknown base initializer kind");
}
- if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit(),
- (*I)->isBaseInitializer()
- ? CCEK_Constant : CCEK_MemberInit)) {
+ FullExpressionRAII InitScope(Info);
+ if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit()) ||
+ (FD && FD->isBitField() && !truncateBitfieldValue(Info, (*I)->getInit(),
+ *Value, FD))) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
if (!Info.keepEvaluatingAfterFailure())
@@ -2934,7 +3759,7 @@ private:
// expression, then the conditional operator is not either.
template<typename ConditionalOperator>
void CheckPotentialConstantConditional(const ConditionalOperator *E) {
- assert(Info.CheckingPotentialConstantExpression);
+ assert(Info.checkingPotentialConstantExpression());
// Speculatively evaluate both arms.
{
@@ -2959,7 +3784,7 @@ private:
bool HandleConditionalOperator(const ConditionalOperator *E) {
bool BoolResult;
if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info)) {
- if (Info.CheckingPotentialConstantExpression)
+ if (Info.checkingPotentialConstantExpression())
CheckPotentialConstantConditional(E);
return false;
}
@@ -3008,15 +3833,19 @@ public:
RetTy VisitUnaryPlus(const UnaryOperator *E)
{ return StmtVisitorTy::Visit(E->getSubExpr()); }
RetTy VisitChooseExpr(const ChooseExpr *E)
- { return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); }
+ { return StmtVisitorTy::Visit(E->getChosenSubExpr()); }
RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E)
{ return StmtVisitorTy::Visit(E->getResultExpr()); }
RetTy VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
{ return StmtVisitorTy::Visit(E->getReplacement()); }
RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
{ return StmtVisitorTy::Visit(E->getExpr()); }
- RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E)
- { return StmtVisitorTy::Visit(E->getExpr()); }
+ RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
+ // The initializer may not have been parsed yet, or might be erroneous.
+ if (!E->getExpr())
+ return Error(E);
+ return StmtVisitorTy::Visit(E->getExpr());
+ }
// We cannot create any objects for which cleanups are required, so there is
// nothing to do here; all cleanups must come from unevaluated subexpressions.
RetTy VisitExprWithCleanups(const ExprWithCleanups *E)
@@ -3056,7 +3885,7 @@ public:
RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) {
// Evaluate and cache the common expression. We treat it as a temporary,
// even though it's not quite the same thing.
- if (!Evaluate(Info.CurrentCall->Temporaries[E->getOpaqueValue()],
+ if (!Evaluate(Info.CurrentCall->createTemporary(E->getOpaqueValue(), false),
Info, E->getCommon()))
return false;
@@ -3076,33 +3905,30 @@ public:
// Always assume __builtin_constant_p(...) ? ... : ... is a potential
// constant expression; we can't check whether it's potentially foldable.
- if (Info.CheckingPotentialConstantExpression && IsBcpCall)
+ if (Info.checkingPotentialConstantExpression() && IsBcpCall)
return false;
- FoldConstant Fold(Info);
-
- if (!HandleConditionalOperator(E))
+ FoldConstant Fold(Info, IsBcpCall);
+ if (!HandleConditionalOperator(E)) {
+ Fold.keepDiagnostics();
return false;
-
- if (IsBcpCall)
- Fold.Fold(Info);
+ }
return true;
}
RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
- APValue &Value = Info.CurrentCall->Temporaries[E];
- if (Value.isUninit()) {
- const Expr *Source = E->getSourceExpr();
- if (!Source)
- return Error(E);
- if (Source == E) { // sanity checking.
- assert(0 && "OpaqueValueExpr recursively refers to itself");
- return Error(E);
- }
- return StmtVisitorTy::Visit(Source);
+ if (APValue *Value = Info.CurrentCall->getTemporary(E))
+ return DerivedSuccess(*Value, E);
+
+ const Expr *Source = E->getSourceExpr();
+ if (!Source)
+ return Error(E);
+ if (Source == E) { // sanity checking.
+ assert(0 && "OpaqueValueExpr recursively refers to itself");
+ return Error(E);
}
- return DerivedSuccess(Value, E);
+ return StmtVisitorTy::Visit(Source);
}
RetTy VisitCallExpr(const CallExpr *E) {
@@ -3240,8 +4066,13 @@ public:
default:
break;
- case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
+ case CK_AtomicToNonAtomic: {
+ APValue AtomicVal;
+ if (!EvaluateAtomic(E->getSubExpr(), AtomicVal, Info))
+ return false;
+ return DerivedSuccess(AtomicVal, E);
+ }
+
case CK_NoOp:
case CK_UserDefinedConversion:
return StmtVisitorTy::Visit(E->getSubExpr());
@@ -3282,6 +4113,41 @@ public:
return DerivedSuccess(RVal, UO);
}
+ RetTy 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.
+ if (Info.checkingForOverflow())
+ return Error(E);
+
+ BlockScopeRAII Scope(Info);
+ const CompoundStmt *CS = E->getSubStmt();
+ for (CompoundStmt::const_body_iterator BI = CS->body_begin(),
+ BE = CS->body_end();
+ /**/; ++BI) {
+ if (BI + 1 == BE) {
+ const Expr *FinalExpr = dyn_cast<Expr>(*BI);
+ if (!FinalExpr) {
+ Info.Diag((*BI)->getLocStart(),
+ diag::note_constexpr_stmt_expr_unsupported);
+ return false;
+ }
+ return this->Visit(FinalExpr);
+ }
+
+ APValue ReturnValue;
+ EvalStmtResult ESR = EvaluateStmt(ReturnValue, Info, *BI);
+ if (ESR != ESR_Succeeded) {
+ // FIXME: If the statement-expression terminated due to 'return',
+ // 'break', or 'continue', it would be nice to propagate that to
+ // the outer statement evaluation rather than bailing out.
+ if (ESR != ESR_Failed)
+ Info.Diag((*BI)->getLocStart(),
+ diag::note_constexpr_stmt_expr_unsupported);
+ return false;
+ }
+ }
+ }
+
/// Visit a value which is evaluated, but whose value is ignored.
void VisitIgnoredValue(const Expr *E) {
EvaluateIgnoredValue(Info, E);
@@ -3374,24 +4240,14 @@ public:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase: {
+ case CK_UncheckedDerivedToBase:
if (!this->Visit(E->getSubExpr()))
return false;
// Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
- QualType Type = E->getSubExpr()->getType();
-
- for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end(); PathI != PathE; ++PathI) {
- if (!HandleLValueBase(this->Info, E, Result, Type->getAsCXXRecordDecl(),
- *PathI))
- return false;
- Type = (*PathI)->getType();
- }
-
- return true;
- }
+ return HandleLValueBasePath(this->Info, E, E->getSubExpr()->getType(),
+ Result);
}
}
};
@@ -3420,8 +4276,12 @@ public:
// * BlockExpr
// * CallExpr for a MakeStringConstant builtin
// - Locals and temporaries
+// * MaterializeTemporaryExpr
// * Any Expr, with a CallIndex indicating the function in which the temporary
-// was evaluated.
+// was evaluated, for cases where the MaterializeTemporaryExpr is missing
+// from the AST (FIXME).
+// * A MaterializeTemporaryExpr that has static storage duration, with no
+// CallIndex, for a lifetime-extended temporary.
// plus an offset in bytes.
//===----------------------------------------------------------------------===//
namespace {
@@ -3511,17 +4371,78 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
APValue *V;
if (!evaluateVarDeclInit(Info, E, VD, Frame, V))
return false;
+ if (V->isUninit()) {
+ if (!Info.checkingPotentialConstantExpression())
+ Info.Diag(E, diag::note_constexpr_use_uninit_reference);
+ return false;
+ }
return Success(*V, E);
}
bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {
- if (E->getType()->isRecordType())
- return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info);
+ // Walk through the expression to find the materialized temporary itself.
+ SmallVector<const Expr *, 2> CommaLHSs;
+ SmallVector<SubobjectAdjustment, 2> Adjustments;
+ const Expr *Inner = E->GetTemporaryExpr()->
+ skipRValueSubobjectAdjustments(CommaLHSs, Adjustments);
+
+ // If we passed any comma operators, evaluate their LHSs.
+ for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I)
+ if (!EvaluateIgnoredValue(Info, CommaLHSs[I]))
+ return false;
+
+ // A materialized temporary with static storage duration can appear within the
+ // result of a constant expression evaluation, so we need to preserve its
+ // value for use outside this evaluation.
+ APValue *Value;
+ if (E->getStorageDuration() == SD_Static) {
+ Value = Info.Ctx.getMaterializedTemporaryValue(E, true);
+ *Value = APValue();
+ Result.set(E);
+ } else {
+ Value = &Info.CurrentCall->
+ createTemporary(E, E->getStorageDuration() == SD_Automatic);
+ Result.set(E, Info.CurrentCall->Index);
+ }
- Result.set(E, Info.CurrentCall->Index);
- return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info,
- Result, E->GetTemporaryExpr());
+ QualType Type = Inner->getType();
+
+ // Materialize the temporary itself.
+ if (!EvaluateInPlace(*Value, Info, Result, Inner) ||
+ (E->getStorageDuration() == SD_Static &&
+ !CheckConstantExpression(Info, E->getExprLoc(), Type, *Value))) {
+ *Value = APValue();
+ return false;
+ }
+
+ // Adjust our lvalue to refer to the desired subobject.
+ for (unsigned I = Adjustments.size(); I != 0; /**/) {
+ --I;
+ switch (Adjustments[I].Kind) {
+ case SubobjectAdjustment::DerivedToBaseAdjustment:
+ if (!HandleLValueBasePath(Info, Adjustments[I].DerivedToBase.BasePath,
+ Type, Result))
+ return false;
+ Type = Adjustments[I].DerivedToBase.BasePath->getType();
+ break;
+
+ case SubobjectAdjustment::FieldAdjustment:
+ if (!HandleLValueMember(Info, E, Result, Adjustments[I].Field))
+ return false;
+ Type = Adjustments[I].Field->getType();
+ break;
+
+ case SubobjectAdjustment::MemberPointerAdjustment:
+ if (!HandleMemberPointerAccess(this->Info, Type, Result,
+ Adjustments[I].Ptr.RHS))
+ return false;
+ Type = Adjustments[I].Ptr.MPT->getPointeeType();
+ break;
+ }
+ }
+
+ return true;
}
bool
@@ -3576,11 +4497,9 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
APSInt Index;
if (!EvaluateInteger(E->getIdx(), Index, Info))
return false;
- int64_t IndexValue
- = Index.isSigned() ? Index.getSExtValue()
- : static_cast<int64_t>(Index.getZExtValue());
- return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), IndexValue);
+ return HandleLValueArrayAdjustment(Info, E, Result, E->getType(),
+ getExtValue(Index));
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
@@ -3634,14 +4553,10 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator(
if (!Evaluate(RHS, this->Info, CAO->getRHS()))
return false;
- // FIXME:
- //return handleCompoundAssignment(
- // this->Info, CAO,
- // Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(),
- // RHS, CAO->getRHS()->getType(),
- // CAO->getOpForCompoundAssignment(CAO->getOpcode()),
- // CAO->getComputationResultType());
- return Error(CAO);
+ return handleCompoundAssignment(
+ this->Info, CAO,
+ Result, CAO->getLHS()->getType(), CAO->getComputationLHSType(),
+ CAO->getOpForCompoundAssignment(CAO->getOpcode()), RHS);
}
bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) {
@@ -3705,6 +4620,9 @@ public:
return Error(E);
}
bool VisitCXXThisExpr(const CXXThisExpr *E) {
+ // Can't look at 'this' when checking a potential constant expression.
+ if (Info.checkingPotentialConstantExpression())
+ return false;
if (!Info.CurrentCall->This)
return Error(E);
Result = *Info.CurrentCall->This;
@@ -3737,9 +4655,8 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
llvm::APSInt Offset;
if (!EvaluateInteger(IExp, Offset, Info) || !EvalPtrOK)
return false;
- int64_t AdditionalOffset
- = Offset.isSigned() ? Offset.getSExtValue()
- : static_cast<int64_t>(Offset.getZExtValue());
+
+ int64_t AdditionalOffset = getExtValue(Offset);
if (E->getOpcode() == BO_Sub)
AdditionalOffset = -AdditionalOffset;
@@ -3779,7 +4696,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return true;
case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase: {
+ case CK_UncheckedDerivedToBase:
if (!EvaluatePointer(E->getSubExpr(), Result, Info))
return false;
if (!Result.Base && Result.Offset.isZero())
@@ -3787,19 +4704,9 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
// Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
- QualType Type =
- E->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType();
-
- for (CastExpr::path_const_iterator PathI = E->path_begin(),
- PathE = E->path_end(); PathI != PathE; ++PathI) {
- if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
- *PathI))
- return false;
- Type = (*PathI)->getType();
- }
-
- return true;
- }
+ return HandleLValueBasePath(Info, E, E->getSubExpr()->getType()->
+ castAs<PointerType>()->getPointeeType(),
+ Result);
case CK_BaseToDerived:
if (!Visit(E->getSubExpr()))
@@ -3839,7 +4746,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return false;
} else {
Result.set(SubExpr, Info.CurrentCall->Index);
- if (!EvaluateInPlace(Info.CurrentCall->Temporaries[SubExpr],
+ if (!EvaluateInPlace(Info.CurrentCall->createTemporary(SubExpr, false),
Info, Result, SubExpr))
return false;
}
@@ -3862,7 +4769,13 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (IsStringLiteralCall(E))
return Success(E);
- return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ switch (E->isBuiltinCall()) {
+ case Builtin::BI__builtin_addressof:
+ return EvaluateLValue(E->getArg(0), Result, Info);
+
+ default:
+ return ExprEvaluatorBaseTy::VisitCallExpr(E);
+ }
}
//===----------------------------------------------------------------------===//
@@ -3976,6 +4889,7 @@ namespace {
bool VisitCastExpr(const CastExpr *E);
bool VisitInitListExpr(const InitListExpr *E);
bool VisitCXXConstructExpr(const CXXConstructExpr *E);
+ bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
};
}
@@ -4091,10 +5005,6 @@ bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
}
bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
- // Cannot constant-evaluate std::initializer_list inits.
- if (E->initializesStdInitializerList())
- return false;
-
const RecordDecl *RD = E->getType()->castAs<RecordType>()->getDecl();
if (RD->isInvalidDecl()) return false;
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
@@ -4156,8 +5066,10 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This,
isa<CXXDefaultInitExpr>(Init));
- if (!EvaluateInPlace(Result.getStructField(Field->getFieldIndex()), Info,
- Subobject, Init)) {
+ APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
+ if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
+ (Field->isBitField() && !truncateBitfieldValue(Info, Init,
+ FieldVal, *Field))) {
if (!Info.keepEvaluatingAfterFailure())
return false;
Success = false;
@@ -4210,6 +5122,58 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
Result);
}
+bool RecordExprEvaluator::VisitCXXStdInitializerListExpr(
+ const CXXStdInitializerListExpr *E) {
+ const ConstantArrayType *ArrayType =
+ Info.Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
+
+ LValue Array;
+ if (!EvaluateLValue(E->getSubExpr(), Array, Info))
+ return false;
+
+ // Get a pointer to the first element of the array.
+ Array.addArray(Info, E, ArrayType);
+
+ // FIXME: Perform the checks on the field types in SemaInit.
+ RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
+ RecordDecl::field_iterator Field = Record->field_begin();
+ if (Field == Record->field_end())
+ return Error(E);
+
+ // Start pointer.
+ if (!Field->getType()->isPointerType() ||
+ !Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType()))
+ return Error(E);
+
+ // FIXME: What if the initializer_list type has base classes, etc?
+ Result = APValue(APValue::UninitStruct(), 0, 2);
+ Array.moveInto(Result.getStructField(0));
+
+ if (++Field == Record->field_end())
+ return Error(E);
+
+ if (Field->getType()->isPointerType() &&
+ Info.Ctx.hasSameType(Field->getType()->getPointeeType(),
+ ArrayType->getElementType())) {
+ // End pointer.
+ if (!HandleLValueArrayAdjustment(Info, E, Array,
+ ArrayType->getElementType(),
+ ArrayType->getSize().getZExtValue()))
+ return false;
+ Array.moveInto(Result.getStructField(1));
+ } else if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType()))
+ // Length.
+ Result.getStructField(1) = APValue(APSInt(ArrayType->getSize()));
+ else
+ return Error(E);
+
+ if (++Field != Record->field_end())
+ return Error(E);
+
+ return true;
+}
+
static bool EvaluateRecord(const Expr *E, const LValue &This,
APValue &Result, EvalInfo &Info) {
assert(E->isRValue() && E->getType()->isRecordType() &&
@@ -4234,7 +5198,8 @@ public:
/// Visit an expression which constructs the value of this temporary.
bool VisitConstructExpr(const Expr *E) {
Result.set(E, Info.CurrentCall->Index);
- return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, Result, E);
+ return EvaluateInPlace(Info.CurrentCall->createTemporary(E, false),
+ Info, Result, E);
}
bool VisitCastExpr(const CastExpr *E) {
@@ -4393,7 +5358,7 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
while (CountElts < NumElements) {
// Handle nested vector initialization.
if (CountInits < NumInits
- && E->getInit(CountInits)->getType()->isExtVectorType()) {
+ && E->getInit(CountInits)->getType()->isVectorType()) {
APValue v;
if (!EvaluateVector(E->getInit(CountInits), v, Info))
return Error(E);
@@ -4951,7 +5916,7 @@ static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) {
} else if (ArgType->isPointerType() || Arg->isGLValue()) {
LValue LV;
Expr::EvalStatus Status;
- EvalInfo Info(Ctx, Status);
+ EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold);
if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, Info)
: EvaluatePointer(Arg, LV, Info)) &&
!Status.HasSideEffects)
@@ -5045,9 +6010,37 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_classify_type:
return Success(EvaluateBuiltinClassifyType(E), E);
+ // FIXME: BI__builtin_clrsb
+ // FIXME: BI__builtin_clrsbl
+ // FIXME: BI__builtin_clrsbll
+
+ case Builtin::BI__builtin_clz:
+ case Builtin::BI__builtin_clzl:
+ case Builtin::BI__builtin_clzll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+ if (!Val)
+ return Error(E);
+
+ return Success(Val.countLeadingZeros(), E);
+ }
+
case Builtin::BI__builtin_constant_p:
return Success(EvaluateBuiltinConstantP(Info.Ctx, E->getArg(0)), E);
+ case Builtin::BI__builtin_ctz:
+ case Builtin::BI__builtin_ctzl:
+ case Builtin::BI__builtin_ctzll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+ if (!Val)
+ return Error(E);
+
+ return Success(Val.countTrailingZeros(), E);
+ }
+
case Builtin::BI__builtin_eh_return_data_regno: {
int Operand = E->getArg(0)->EvaluateKnownConstInt(Info.Ctx).getZExtValue();
Operand = Info.Ctx.getTargetInfo().getEHDataRegisterNumber(Operand);
@@ -5057,6 +6050,81 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_expect:
return Visit(E->getArg(0));
+ case Builtin::BI__builtin_ffs:
+ case Builtin::BI__builtin_ffsl:
+ case Builtin::BI__builtin_ffsll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+
+ unsigned N = Val.countTrailingZeros();
+ return Success(N == Val.getBitWidth() ? 0 : N + 1, E);
+ }
+
+ case Builtin::BI__builtin_fpclassify: {
+ APFloat Val(0.0);
+ if (!EvaluateFloat(E->getArg(5), Val, Info))
+ return false;
+ unsigned Arg;
+ switch (Val.getCategory()) {
+ case APFloat::fcNaN: Arg = 0; break;
+ case APFloat::fcInfinity: Arg = 1; break;
+ case APFloat::fcNormal: Arg = Val.isDenormal() ? 3 : 2; break;
+ case APFloat::fcZero: Arg = 4; break;
+ }
+ return Visit(E->getArg(Arg));
+ }
+
+ case Builtin::BI__builtin_isinf_sign: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isInfinity() ? (Val.isNegative() ? -1 : 1) : 0, E);
+ }
+
+ case Builtin::BI__builtin_isinf: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isInfinity() ? 1 : 0, E);
+ }
+
+ case Builtin::BI__builtin_isfinite: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isFinite() ? 1 : 0, E);
+ }
+
+ case Builtin::BI__builtin_isnan: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isNaN() ? 1 : 0, E);
+ }
+
+ case Builtin::BI__builtin_isnormal: {
+ APFloat Val(0.0);
+ return EvaluateFloat(E->getArg(0), Val, Info) &&
+ Success(Val.isNormal() ? 1 : 0, E);
+ }
+
+ case Builtin::BI__builtin_parity:
+ case Builtin::BI__builtin_parityl:
+ case Builtin::BI__builtin_parityll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+
+ return Success(Val.countPopulation() % 2, E);
+ }
+
+ case Builtin::BI__builtin_popcount:
+ case Builtin::BI__builtin_popcountl:
+ case Builtin::BI__builtin_popcountll: {
+ APSInt Val;
+ if (!EvaluateInteger(E->getArg(0), Val, Info))
+ return false;
+
+ return Success(Val.countPopulation(), E);
+ }
+
case Builtin::BIstrlen:
// A call to strlen is not a constant expression.
if (Info.getLangOpts().CPlusPlus11)
@@ -5065,22 +6133,47 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
else
Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr);
// Fall through.
- case Builtin::BI__builtin_strlen:
- // As an extension, we support strlen() and __builtin_strlen() as constant
- // expressions when the argument is a string literal.
- if (const StringLiteral *S
- = dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) {
+ case Builtin::BI__builtin_strlen: {
+ // As an extension, we support __builtin_strlen() as a constant expression,
+ // and support folding strlen() to a constant.
+ LValue String;
+ if (!EvaluatePointer(E->getArg(0), String, Info))
+ return false;
+
+ // Fast path: if it's a string literal, search the string value.
+ if (const StringLiteral *S = dyn_cast_or_null<StringLiteral>(
+ String.getLValueBase().dyn_cast<const Expr *>())) {
// The string literal may have embedded null characters. Find the first
// one and truncate there.
- StringRef Str = S->getString();
- StringRef::size_type Pos = Str.find(0);
- if (Pos != StringRef::npos)
- Str = Str.substr(0, Pos);
-
- return Success(Str.size(), E);
+ StringRef Str = S->getBytes();
+ int64_t Off = String.Offset.getQuantity();
+ if (Off >= 0 && (uint64_t)Off <= (uint64_t)Str.size() &&
+ S->getCharByteWidth() == 1) {
+ Str = Str.substr(Off);
+
+ StringRef::size_type Pos = Str.find(0);
+ if (Pos != StringRef::npos)
+ Str = Str.substr(0, Pos);
+
+ return Success(Str.size(), E);
+ }
+
+ // Fall through to slow path to issue appropriate diagnostic.
}
-
- return Error(E);
+
+ // Slow path: scan the bytes of the string looking for the terminating 0.
+ QualType CharTy = E->getArg(0)->getType()->getPointeeType();
+ for (uint64_t Strlen = 0; /**/; ++Strlen) {
+ APValue Char;
+ if (!handleLValueToRValueConversion(Info, E, CharTy, String, Char) ||
+ !Char.isInt())
+ return false;
+ if (!Char.getInt())
+ return Success(Strlen, E);
+ if (!HandleLValueArrayAdjustment(Info, E, String, CharTy, 1))
+ return false;
+ }
+ }
case Builtin::BI__atomic_always_lock_free:
case Builtin::BI__atomic_is_lock_free:
@@ -5149,29 +6242,6 @@ static bool HasSameBase(const LValue &A, const LValue &B) {
A.getLValueCallIndex() == B.getLValueCallIndex();
}
-/// Perform the given integer operation, which is known to need at most BitWidth
-/// bits, and check for overflow in the original type (if that type was not an
-/// unsigned type).
-template<typename Operation>
-static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
- const APSInt &LHS, const APSInt &RHS,
- unsigned BitWidth, Operation Op) {
- if (LHS.isUnsigned())
- return Op(LHS, RHS);
-
- APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
- APSInt Result = Value.trunc(LHS.getBitWidth());
- if (Result.extend(BitWidth) != Value) {
- if (Info.getIntOverflowCheckMode())
- Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
- diag::warn_integer_constant_overflow)
- << Result.toString(10) << E->getType();
- else
- HandleOverflow(Info, E, Value, E->getType());
- }
- return Result;
-}
-
namespace {
/// \brief Data recursive integer evaluator of certain binary operators.
@@ -5296,36 +6366,39 @@ bool DataRecursiveIntBinOpEvaluator::
if (E->getOpcode() == BO_Comma) {
// Ignore LHS but note if we could not evaluate it.
if (LHSResult.Failed)
- Info.EvalStatus.HasSideEffects = true;
+ return Info.noteSideEffect();
return true;
}
-
+
if (E->isLogicalOp()) {
- bool lhsResult;
- if (HandleConversionToBool(LHSResult.Val, lhsResult)) {
+ bool LHSAsBool;
+ if (!LHSResult.Failed && HandleConversionToBool(LHSResult.Val, LHSAsBool)) {
// We were able to evaluate the LHS, see if we can get away with not
// evaluating the RHS: 0 && X -> 0, 1 || X -> 1
- if (lhsResult == (E->getOpcode() == BO_LOr)) {
- Success(lhsResult, E, LHSResult.Val);
+ if (LHSAsBool == (E->getOpcode() == BO_LOr)) {
+ Success(LHSAsBool, E, LHSResult.Val);
return false; // Ignore RHS
}
} else {
+ LHSResult.Failed = true;
+
// Since we weren't able to evaluate the left hand side, it
// must have had side effects.
- Info.EvalStatus.HasSideEffects = true;
-
+ if (!Info.noteSideEffect())
+ return false;
+
// We can't evaluate the LHS; however, sometimes the result
// is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
// Don't ignore RHS and suppress diagnostics from this arm.
SuppressRHSDiags = true;
}
-
+
return true;
}
-
+
assert(E->getLHS()->getType()->isIntegralOrEnumerationType() &&
E->getRHS()->getType()->isIntegralOrEnumerationType());
-
+
if (LHSResult.Failed && !Info.keepEvaluatingAfterFailure())
return false; // Ignore RHS;
@@ -5378,8 +6451,8 @@ bool DataRecursiveIntBinOpEvaluator::
// Handle cases like (unsigned long)&a + 4.
if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) {
Result = LHSVal;
- CharUnits AdditionalOffset = CharUnits::fromQuantity(
- RHSVal.getInt().getZExtValue());
+ CharUnits AdditionalOffset =
+ CharUnits::fromQuantity(RHSVal.getInt().getZExtValue());
if (E->getOpcode() == BO_Add)
Result.getLValueOffset() += AdditionalOffset;
else
@@ -5391,8 +6464,8 @@ bool DataRecursiveIntBinOpEvaluator::
if (E->getOpcode() == BO_Add &&
RHSVal.isLValue() && LHSVal.isInt()) {
Result = RHSVal;
- Result.getLValueOffset() += CharUnits::fromQuantity(
- LHSVal.getInt().getZExtValue());
+ Result.getLValueOffset() +=
+ CharUnits::fromQuantity(LHSVal.getInt().getZExtValue());
return true;
}
@@ -5416,108 +6489,20 @@ bool DataRecursiveIntBinOpEvaluator::
Result = APValue(LHSAddrExpr, RHSAddrExpr);
return true;
}
-
- // All the following cases expect both operands to be an integer
+
+ // All the remaining cases expect both operands to be an integer
if (!LHSVal.isInt() || !RHSVal.isInt())
return Error(E);
-
- const APSInt &LHS = LHSVal.getInt();
- APSInt RHS = RHSVal.getInt();
-
- switch (E->getOpcode()) {
- default:
- return Error(E);
- case BO_Mul:
- return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
- LHS.getBitWidth() * 2,
- std::multiplies<APSInt>()), E,
- Result);
- case BO_Add:
- return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
- LHS.getBitWidth() + 1,
- std::plus<APSInt>()), E, Result);
- case BO_Sub:
- return Success(CheckedIntArithmetic(Info, E, LHS, RHS,
- LHS.getBitWidth() + 1,
- std::minus<APSInt>()), E, Result);
- case BO_And: return Success(LHS & RHS, E, Result);
- case BO_Xor: return Success(LHS ^ RHS, E, Result);
- case BO_Or: return Success(LHS | RHS, E, Result);
- case BO_Div:
- case BO_Rem:
- if (RHS == 0)
- return Error(E, diag::note_expr_divide_by_zero);
- // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. The latter is
- // not actually undefined behavior in C++11 due to a language defect.
- if (RHS.isNegative() && RHS.isAllOnesValue() &&
- LHS.isSigned() && LHS.isMinSignedValue())
- HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType());
- return Success(E->getOpcode() == BO_Rem ? LHS % RHS : LHS / RHS, E,
- Result);
- case BO_Shl: {
- if (Info.getLangOpts().OpenCL)
- // OpenCL 6.3j: shift values are effectively % word size of LHS.
- RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
- static_cast<uint64_t>(LHS.getBitWidth() - 1)),
- RHS.isUnsigned());
- else if (RHS.isSigned() && RHS.isNegative()) {
- // During constant-folding, a negative shift is an opposite shift. Such
- // a shift is not a constant expression.
- CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
- RHS = -RHS;
- goto shift_right;
- }
-
- shift_left:
- // C++11 [expr.shift]p1: Shift width must be less than the bit width of
- // the shifted type.
- unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
- if (SA != RHS) {
- CCEDiag(E, diag::note_constexpr_large_shift)
- << RHS << E->getType() << LHS.getBitWidth();
- } else if (LHS.isSigned()) {
- // C++11 [expr.shift]p2: A signed left shift must have a non-negative
- // operand, and must not overflow the corresponding unsigned type.
- if (LHS.isNegative())
- CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS;
- else if (LHS.countLeadingZeros() < SA)
- CCEDiag(E, diag::note_constexpr_lshift_discards);
- }
-
- return Success(LHS << SA, E, Result);
- }
- case BO_Shr: {
- if (Info.getLangOpts().OpenCL)
- // OpenCL 6.3j: shift values are effectively % word size of LHS.
- RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
- static_cast<uint64_t>(LHS.getBitWidth() - 1)),
- RHS.isUnsigned());
- else if (RHS.isSigned() && RHS.isNegative()) {
- // During constant-folding, a negative shift is an opposite shift. Such a
- // shift is not a constant expression.
- CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
- RHS = -RHS;
- goto shift_left;
- }
-
- shift_right:
- // C++11 [expr.shift]p1: Shift width must be less than the bit width of the
- // shifted type.
- unsigned SA = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
- if (SA != RHS)
- CCEDiag(E, diag::note_constexpr_large_shift)
- << RHS << E->getType() << LHS.getBitWidth();
-
- return Success(LHS >> SA, E, Result);
- }
-
- case BO_LT: return Success(LHS < RHS, E, Result);
- case BO_GT: return Success(LHS > RHS, E, Result);
- case BO_LE: return Success(LHS <= RHS, E, Result);
- case BO_GE: return Success(LHS >= RHS, E, Result);
- case BO_EQ: return Success(LHS == RHS, E, Result);
- case BO_NE: return Success(LHS != RHS, E, Result);
- }
+
+ // Set up the width and signedness manually, in case it can't be deduced
+ // from the operation we're performing.
+ // FIXME: Don't do this in the cases where we can deduce it.
+ APSInt Value(Info.Ctx.getIntWidth(E->getType()),
+ E->getType()->isUnsignedIntegerOrEnumerationType());
+ if (!handleIntIntBinOp(Info, E, LHSVal.getInt(), E->getOpcode(),
+ RHSVal.getInt(), Value))
+ return false;
+ return Success(Value, E, Result);
}
void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) {
@@ -5737,6 +6722,15 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
if (!HandleSizeof(Info, E->getExprLoc(), ElementType, ElementSize))
return false;
+ // As an extension, a type may have zero size (empty struct or union in
+ // C, array of zero length). Pointer subtraction in such cases has
+ // undefined behavior, so is not constant.
+ if (ElementSize.isZero()) {
+ Info.Diag(E, diag::note_constexpr_pointer_subtraction_zero_size)
+ << ElementType;
+ return false;
+ }
+
// FIXME: LLVM and GCC both compute LHSOffset - RHSOffset at runtime,
// and produce incorrect results when it overflows. Such behavior
// appears to be non-conforming, but is common, so perhaps we should
@@ -5999,7 +6993,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) {
CurrentType = AT->getElementType();
CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType);
Result += IdxResult.getSExtValue() * ElementSize;
- break;
+ break;
}
case OffsetOfExpr::OffsetOfNode::Field: {
@@ -6125,6 +7119,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralComplexToFloatingComplex:
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
+ case CK_NonAtomicToAtomic:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -6140,7 +7135,6 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_UserDefinedConversion:
case CK_LValueToRValue:
case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
case CK_NoOp:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
@@ -6369,6 +7363,10 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
Result.changeSign();
return true;
+ // FIXME: Builtin::BI__builtin_powi
+ // FIXME: Builtin::BI__builtin_powif
+ // FIXME: Builtin::BI__builtin_powil
+
case Builtin::BI__builtin_copysign:
case Builtin::BI__builtin_copysignf:
case Builtin::BI__builtin_copysignl: {
@@ -6430,28 +7428,8 @@ bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
bool LHSOK = EvaluateFloat(E->getLHS(), Result, Info);
if (!LHSOK && !Info.keepEvaluatingAfterFailure())
return false;
- if (!EvaluateFloat(E->getRHS(), RHS, Info) || !LHSOK)
- return false;
-
- switch (E->getOpcode()) {
- default: return Error(E);
- case BO_Mul:
- Result.multiply(RHS, APFloat::rmNearestTiesToEven);
- break;
- case BO_Add:
- Result.add(RHS, APFloat::rmNearestTiesToEven);
- break;
- case BO_Sub:
- Result.subtract(RHS, APFloat::rmNearestTiesToEven);
- break;
- case BO_Div:
- Result.divide(RHS, APFloat::rmNearestTiesToEven);
- break;
- }
-
- if (Result.isInfinity() || Result.isNaN())
- CCEDiag(E, diag::note_constexpr_float_arithmetic) << Result.isNaN();
- return true;
+ return EvaluateFloat(E->getRHS(), RHS, Info) && LHSOK &&
+ handleFloatFloatBinOp(Info, E, Result, E->getOpcode(), RHS);
}
bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) {
@@ -6613,11 +7591,11 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
case CK_ZeroToOCLEvent:
+ case CK_NonAtomicToAtomic:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
case CK_AtomicToNonAtomic:
- case CK_NonAtomicToAtomic:
case CK_NoOp:
return ExprEvaluatorBaseTy::VisitCastExpr(E);
@@ -6874,6 +7852,46 @@ bool ComplexExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
}
//===----------------------------------------------------------------------===//
+// Atomic expression evaluation, essentially just handling the NonAtomicToAtomic
+// implicit conversion.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class AtomicExprEvaluator :
+ public ExprEvaluatorBase<AtomicExprEvaluator, bool> {
+ APValue &Result;
+public:
+ AtomicExprEvaluator(EvalInfo &Info, APValue &Result)
+ : ExprEvaluatorBaseTy(Info), Result(Result) {}
+
+ bool Success(const APValue &V, const Expr *E) {
+ Result = V;
+ return true;
+ }
+
+ bool ZeroInitialization(const Expr *E) {
+ ImplicitValueInitExpr VIE(
+ E->getType()->castAs<AtomicType>()->getValueType());
+ return Evaluate(Result, Info, &VIE);
+ }
+
+ bool VisitCastExpr(const CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ return ExprEvaluatorBaseTy::VisitCastExpr(E);
+ case CK_NonAtomicToAtomic:
+ return Evaluate(Result, Info, E->getSubExpr());
+ }
+ }
+};
+} // end anonymous namespace
+
+static bool EvaluateAtomic(const Expr *E, APValue &Result, EvalInfo &Info) {
+ assert(E->isRValue() && E->getType()->isAtomicType());
+ return AtomicExprEvaluator(Info, Result).Visit(E);
+}
+
+//===----------------------------------------------------------------------===//
// Void expression evaluation, primarily for a cast to void on the LHS of a
// comma operator
//===----------------------------------------------------------------------===//
@@ -6910,56 +7928,62 @@ static bool EvaluateVoid(const Expr *E, EvalInfo &Info) {
static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
// In C, function designators are not lvalues, but we evaluate them as if they
// are.
- if (E->isGLValue() || E->getType()->isFunctionType()) {
+ QualType T = E->getType();
+ if (E->isGLValue() || T->isFunctionType()) {
LValue LV;
if (!EvaluateLValue(E, LV, Info))
return false;
LV.moveInto(Result);
- } else if (E->getType()->isVectorType()) {
+ } else if (T->isVectorType()) {
if (!EvaluateVector(E, Result, Info))
return false;
- } else if (E->getType()->isIntegralOrEnumerationType()) {
+ } else if (T->isIntegralOrEnumerationType()) {
if (!IntExprEvaluator(Info, Result).Visit(E))
return false;
- } else if (E->getType()->hasPointerRepresentation()) {
+ } else if (T->hasPointerRepresentation()) {
LValue LV;
if (!EvaluatePointer(E, LV, Info))
return false;
LV.moveInto(Result);
- } else if (E->getType()->isRealFloatingType()) {
+ } else if (T->isRealFloatingType()) {
llvm::APFloat F(0.0);
if (!EvaluateFloat(E, F, Info))
return false;
Result = APValue(F);
- } else if (E->getType()->isAnyComplexType()) {
+ } else if (T->isAnyComplexType()) {
ComplexValue C;
if (!EvaluateComplex(E, C, Info))
return false;
C.moveInto(Result);
- } else if (E->getType()->isMemberPointerType()) {
+ } else if (T->isMemberPointerType()) {
MemberPtr P;
if (!EvaluateMemberPointer(E, P, Info))
return false;
P.moveInto(Result);
return true;
- } else if (E->getType()->isArrayType()) {
+ } else if (T->isArrayType()) {
LValue LV;
LV.set(E, Info.CurrentCall->Index);
- if (!EvaluateArray(E, LV, Info.CurrentCall->Temporaries[E], Info))
+ APValue &Value = Info.CurrentCall->createTemporary(E, false);
+ if (!EvaluateArray(E, LV, Value, Info))
return false;
- Result = Info.CurrentCall->Temporaries[E];
- } else if (E->getType()->isRecordType()) {
+ Result = Value;
+ } else if (T->isRecordType()) {
LValue LV;
LV.set(E, Info.CurrentCall->Index);
- if (!EvaluateRecord(E, LV, Info.CurrentCall->Temporaries[E], Info))
+ APValue &Value = Info.CurrentCall->createTemporary(E, false);
+ if (!EvaluateRecord(E, LV, Value, Info))
return false;
- Result = Info.CurrentCall->Temporaries[E];
- } else if (E->getType()->isVoidType()) {
+ Result = Value;
+ } else if (T->isVoidType()) {
if (!Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_nonliteral)
<< E->getType();
if (!EvaluateVoid(E, Info))
return false;
+ } else if (T->isAtomicType()) {
+ if (!EvaluateAtomic(E, Result, Info))
+ return false;
} else if (Info.getLangOpts().CPlusPlus11) {
Info.Diag(E, diag::note_constexpr_nonliteral) << E->getType();
return false;
@@ -6975,9 +7999,8 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
/// cases, the in-place evaluation is essential, since later initializers for
/// an object can indirectly refer to subobjects which were initialized earlier.
static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This,
- const Expr *E, CheckConstantExpressionKind CCEK,
- bool AllowNonLiteralTypes) {
- if (!AllowNonLiteralTypes && !CheckLiteralType(Info, E))
+ const Expr *E, bool AllowNonLiteralTypes) {
+ if (!AllowNonLiteralTypes && !CheckLiteralType(Info, E, &This))
return false;
if (E->isRValue()) {
@@ -7046,7 +8069,7 @@ bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const {
if (FastEvaluateAsRValue(this, Result, Ctx, IsConst))
return IsConst;
- EvalInfo Info(Ctx, Result);
+ EvalInfo Info(Ctx, Result, EvalInfo::EM_IgnoreSideEffects);
return ::EvaluateAsRValue(Info, this, Result.Val);
}
@@ -7072,7 +8095,7 @@ bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx,
}
bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
- EvalInfo Info(Ctx, Result);
+ EvalInfo Info(Ctx, Result, EvalInfo::EM_ConstantFold);
LValue LV;
if (!EvaluateLValue(this, LV, Info) || Result.HasSideEffects ||
@@ -7096,7 +8119,7 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
Expr::EvalStatus EStatus;
EStatus.Diag = &Notes;
- EvalInfo InitInfo(Ctx, EStatus);
+ EvalInfo InitInfo(Ctx, EStatus, EvalInfo::EM_ConstantFold);
InitInfo.setEvaluatingDecl(VD, Value);
LValue LVal;
@@ -7109,13 +8132,13 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
if (Ctx.getLangOpts().CPlusPlus && !VD->hasLocalStorage() &&
!VD->getType()->isReferenceType()) {
ImplicitValueInitExpr VIE(VD->getType());
- if (!EvaluateInPlace(Value, InitInfo, LVal, &VIE, CCEK_Constant,
+ if (!EvaluateInPlace(Value, InitInfo, LVal, &VIE,
/*AllowNonLiteralTypes=*/true))
return false;
}
- if (!EvaluateInPlace(Value, InitInfo, LVal, this, CCEK_Constant,
- /*AllowNonLiteralTypes=*/true) ||
+ if (!EvaluateInPlace(Value, InitInfo, LVal, this,
+ /*AllowNonLiteralTypes=*/true) ||
EStatus.HasSideEffects)
return false;
@@ -7142,21 +8165,19 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
return EvalResult.Val.getInt();
}
-void Expr::EvaluateForOverflow(const ASTContext &Ctx,
- SmallVectorImpl<PartialDiagnosticAt> *Diags) const {
+void Expr::EvaluateForOverflow(const ASTContext &Ctx) const {
bool IsConst;
EvalResult EvalResult;
- EvalResult.Diag = Diags;
if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst)) {
- EvalInfo Info(Ctx, EvalResult, true);
+ EvalInfo Info(Ctx, EvalResult, EvalInfo::EM_EvaluateForOverflow);
(void)::EvaluateAsRValue(Info, this, EvalResult.Val);
}
}
- bool Expr::EvalResult::isGlobalLValue() const {
- assert(Val.isLValue());
- return IsGlobalLValue(Val.getLValueBase());
- }
+bool Expr::EvalResult::isGlobalLValue() const {
+ assert(Val.isLValue());
+ return IsGlobalLValue(Val.getLValueBase());
+}
/// isIntegerConstantExpr - this recursive routine will test if an expression is
@@ -7200,7 +8221,7 @@ static ICEDiag NoDiag() { return ICEDiag(IK_ICE, SourceLocation()); }
static ICEDiag Worst(ICEDiag A, ICEDiag B) { return A.Kind >= B.Kind ? A : B; }
-static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
+static ICEDiag CheckEvalInICE(const Expr* E, const ASTContext &Ctx) {
Expr::EvalResult EVResult;
if (!E->EvaluateAsRValue(EVResult, Ctx) || EVResult.HasSideEffects ||
!EVResult.Val.isInt())
@@ -7209,7 +8230,7 @@ static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
return NoDiag();
}
-static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
+static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
assert(!E->isValueDependent() && "Should not see value dependent exprs!");
if (!E->getType()->isIntegralOrEnumerationType())
return ICEDiag(IK_NotICE, E->getLocStart());
@@ -7250,6 +8271,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::UnresolvedLookupExprClass:
case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
+ case Expr::CXXStdInitializerListExprClass:
case Expr::CXXBindTemporaryExprClass:
case Expr::ExprWithCleanupsClass:
case Expr::CXXTemporaryObjectExprClass:
@@ -7269,6 +8291,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::ObjCSubscriptRefExprClass:
case Expr::ObjCIsaExprClass:
case Expr::ShuffleVectorExprClass:
+ case Expr::ConvertVectorExprClass:
case Expr::BlockExprClass:
case Expr::NoStmtClass:
case Expr::OpaqueValueExprClass:
@@ -7561,7 +8584,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CXXDefaultInitExprClass:
return CheckICE(cast<CXXDefaultInitExpr>(E)->getExpr(), Ctx);
case Expr::ChooseExprClass: {
- return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx);
+ return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(), Ctx);
}
}
@@ -7569,7 +8592,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
/// Evaluate an expression as a C++11 integral constant expression.
-static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx,
+static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx,
const Expr *E,
llvm::APSInt *Value,
SourceLocation *Loc) {
@@ -7587,7 +8610,8 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx,
return true;
}
-bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
+bool Expr::isIntegerConstantExpr(const ASTContext &Ctx,
+ SourceLocation *Loc) const {
if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, 0, Loc);
@@ -7599,7 +8623,7 @@ bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
return true;
}
-bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
+bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, const ASTContext &Ctx,
SourceLocation *Loc, bool isEvaluated) const {
if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc);
@@ -7611,11 +8635,11 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
return true;
}
-bool Expr::isCXX98IntegralConstantExpr(ASTContext &Ctx) const {
+bool Expr::isCXX98IntegralConstantExpr(const ASTContext &Ctx) const {
return CheckICE(this, Ctx).Kind == IK_ICE;
}
-bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
+bool Expr::isCXX11ConstantExpr(const ASTContext &Ctx, APValue *Result,
SourceLocation *Loc) const {
// We support this checking in C++98 mode in order to diagnose compatibility
// issues.
@@ -7625,7 +8649,7 @@ bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
Expr::EvalStatus Status;
SmallVector<PartialDiagnosticAt, 8> Diags;
Status.Diag = &Diags;
- EvalInfo Info(Ctx, Status);
+ EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
APValue Scratch;
bool IsConstExpr = ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch);
@@ -7653,13 +8677,13 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
Expr::EvalStatus Status;
Status.Diag = &Diags;
- EvalInfo Info(FD->getASTContext(), Status);
- Info.CheckingPotentialConstantExpression = true;
+ EvalInfo Info(FD->getASTContext(), Status,
+ EvalInfo::EM_PotentialConstantExpression);
const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
const CXXRecordDecl *RD = MD ? MD->getParent()->getCanonicalDecl() : 0;
- // FIXME: Fabricate an arbitrary expression on the stack and pretend that it
+ // Fabricate an arbitrary expression on the stack and pretend that it
// is a temporary being used as the 'this' pointer.
LValue This;
ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy);
@@ -7670,9 +8694,12 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
SourceLocation Loc = FD->getLocation();
APValue Scratch;
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+ // Evaluate the call as a constant initializer, to allow the construction
+ // of objects of non-literal types.
+ Info.setEvaluatingDecl(This.getLValueBase(), Scratch);
HandleConstructorCall(Loc, This, Args, CD, Info, Scratch);
- else
+ } else
HandleFunctionCall(Loc, FD, (MD && MD->isInstance()) ? &This : 0,
Args, FD->getBody(), Info, Scratch);
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index e03632a..3d64310 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -17,9 +17,11 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/TypeOrdering.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
+#include <set>
using namespace llvm;
@@ -135,34 +137,28 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
/// class using GraphViz.
void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
QualType Self = Context.getTypeDeclType(this);
- std::string ErrMsg;
- sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
- if (Filename.isEmpty()) {
- llvm::errs() << "Error: " << ErrMsg << "\n";
- return;
- }
- Filename.appendComponent(Self.getAsString() + ".dot");
- if (Filename.makeUnique(true,&ErrMsg)) {
- llvm::errs() << "Error: " << ErrMsg << "\n";
+
+ int FD;
+ SmallString<128> Filename;
+ error_code EC =
+ sys::fs::createTemporaryFile(Self.getAsString(), "dot", FD, Filename);
+ if (EC) {
+ llvm::errs() << "Error: " << EC.message() << "\n";
return;
}
- llvm::errs() << "Writing '" << Filename.c_str() << "'... ";
+ llvm::errs() << "Writing '" << Filename << "'... ";
- llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg);
+ llvm::raw_fd_ostream O(FD, true);
- if (ErrMsg.empty()) {
- InheritanceHierarchyWriter Writer(Context, O);
- Writer.WriteGraph(Self);
- llvm::errs() << " done. \n";
+ InheritanceHierarchyWriter Writer(Context, O);
+ Writer.WriteGraph(Self);
+ llvm::errs() << " done. \n";
- O.close();
+ O.close();
- // Display the graph
- DisplayGraph(Filename);
- } else {
- llvm::errs() << "error opening file for writing!\n";
- }
+ // Display the graph
+ DisplayGraph(Filename);
}
}
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index 894eb3b..5784660 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -20,6 +20,7 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
@@ -27,6 +28,19 @@
using namespace clang;
namespace {
+
+/// \brief Keeps track of the mangled names of lambda expressions and block
+/// literals within a particular context.
+class ItaniumNumberingContext : public MangleNumberingContext {
+ llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers;
+
+public:
+ /// Variable decls are numbered by identifier.
+ virtual unsigned getManglingNumber(const VarDecl *VD) {
+ return ++VarManglingNumbers[VD->getIdentifier()];
+ }
+};
+
class ItaniumCXXABI : public CXXABI {
protected:
ASTContext &Context;
@@ -61,6 +75,10 @@ public:
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
return Layout.getNonVirtualSize() == PointerSize;
}
+
+ virtual MangleNumberingContext *createMangleNumberingContext() const {
+ return new ItaniumNumberingContext();
+ }
};
class ARMCXXABI : public ItaniumCXXABI {
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 5ad8021..0621d7b 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -56,23 +56,36 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) {
= dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl()))
return ContextParam->getDeclContext();
}
+
+ // Perform the same check for block literals.
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ if (ParmVarDecl *ContextParam
+ = dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl()))
+ return ContextParam->getDeclContext();
+ }
- return D->getDeclContext();
+ const DeclContext *DC = D->getDeclContext();
+ if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC))
+ return getEffectiveDeclContext(CD);
+
+ return DC;
}
static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
return getEffectiveDeclContext(cast<Decl>(DC));
}
-
-static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) {
- const DeclContext *DC = dyn_cast<DeclContext>(ND);
- if (!DC)
- DC = getEffectiveDeclContext(ND);
+
+static bool isLocalContainerContext(const DeclContext *DC) {
+ return isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC) || isa<BlockDecl>(DC);
+}
+
+static const RecordDecl *GetLocalClassDecl(const Decl *D) {
+ const DeclContext *DC = getEffectiveDeclContext(D);
while (!DC->isNamespace() && !DC->isTranslationUnit()) {
- const DeclContext *Parent = getEffectiveDeclContext(cast<Decl>(DC));
- if (isa<FunctionDecl>(Parent))
- return dyn_cast<CXXRecordDecl>(DC);
- DC = Parent;
+ if (isLocalContainerContext(DC))
+ return dyn_cast<RecordDecl>(D);
+ D = cast<Decl>(DC);
+ DC = getEffectiveDeclContext(D);
}
return 0;
}
@@ -91,15 +104,16 @@ static const NamedDecl *getStructor(const NamedDecl *decl) {
static const unsigned UnknownArity = ~0U;
-class ItaniumMangleContext : public MangleContext {
+class ItaniumMangleContextImpl : public ItaniumMangleContext {
llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
- unsigned Discriminator;
+ typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy;
+ llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator;
llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
public:
- explicit ItaniumMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags)
- : MangleContext(Context, Diags) { }
+ explicit ItaniumMangleContextImpl(ASTContext &Context,
+ DiagnosticsEngine &Diags)
+ : ItaniumMangleContext(Context, Diags) {}
uint64_t getAnonymousStructId(const TagDecl *TD) {
std::pair<llvm::DenseMap<const TagDecl *,
@@ -108,16 +122,11 @@ public:
return Result.first->second;
}
- void startNewFunction() {
- MangleContext::startNewFunction();
- mangleInitDiscriminator();
- }
-
/// @name Mangler Entry Points
/// @{
- bool shouldMangleDeclName(const NamedDecl *D);
- void mangleName(const NamedDecl *D, raw_ostream &);
+ bool shouldMangleCXXName(const NamedDecl *D);
+ void mangleCXXName(const NamedDecl *D, raw_ostream &);
void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &);
@@ -135,30 +144,45 @@ public:
raw_ostream &);
void mangleCXXRTTI(QualType T, raw_ostream &);
void mangleCXXRTTIName(QualType T, raw_ostream &);
+ void mangleTypeName(QualType T, raw_ostream &);
void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
raw_ostream &);
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
raw_ostream &);
- void mangleItaniumGuardVariable(const VarDecl *D, raw_ostream &);
+ void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &);
+ void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out);
+ void mangleDynamicAtExitDestructor(const VarDecl *D, raw_ostream &Out);
void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &);
void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &);
- void mangleInitDiscriminator() {
- Discriminator = 0;
- }
-
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
- // Lambda closure types with external linkage (indicated by a
- // non-zero lambda mangling number) have their own numbering scheme, so
- // they do not need a discriminator.
+ // Lambda closure types are already numbered.
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND))
- if (RD->isLambda() && RD->getLambdaManglingNumber() > 0)
+ if (RD->isLambda())
return false;
-
+
+ // Anonymous tags are already numbered.
+ if (const TagDecl *Tag = dyn_cast<TagDecl>(ND)) {
+ if (Tag->getName().empty() && !Tag->getTypedefNameForAnonDecl())
+ return false;
+ }
+
+ // Use the canonical number for externally visible decls.
+ if (ND->isExternallyVisible()) {
+ unsigned discriminator = getASTContext().getManglingNumber(ND);
+ if (discriminator == 1)
+ return false;
+ disc = discriminator - 2;
+ return true;
+ }
+
+ // Make up a reasonable number for internal decls.
unsigned &discriminator = Uniquifier[ND];
- if (!discriminator)
- discriminator = ++Discriminator;
+ if (!discriminator) {
+ const DeclContext *DC = getEffectiveDeclContext(ND);
+ discriminator = ++Discriminator[std::make_pair(DC, ND->getIdentifier())];
+ }
if (discriminator == 1)
return false;
disc = discriminator-2;
@@ -169,7 +193,7 @@ public:
/// CXXNameMangler - Manage the mangling of a single name.
class CXXNameMangler {
- ItaniumMangleContext &Context;
+ ItaniumMangleContextImpl &Context;
raw_ostream &Out;
/// The "structor" is the top-level declaration being mangled, if
@@ -225,7 +249,7 @@ class CXXNameMangler {
ASTContext &getASTContext() const { return Context.getASTContext(); }
public:
- CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
+ CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_,
const NamedDecl *D = 0)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0),
SeqID(0) {
@@ -233,11 +257,11 @@ public:
assert(!D || (!isa<CXXDestructorDecl>(D) &&
!isa<CXXConstructorDecl>(D)));
}
- CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
+ CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_,
const CXXConstructorDecl *D, CXXCtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
SeqID(0) { }
- CXXNameMangler(ItaniumMangleContext &C, raw_ostream &Out_,
+ CXXNameMangler(ItaniumMangleContextImpl &C, raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
SeqID(0) { }
@@ -305,7 +329,9 @@ private:
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleUnscopedTemplateName(TemplateName);
void mangleSourceName(const IdentifierInfo *II);
- void mangleLocalName(const NamedDecl *ND);
+ void mangleLocalName(const Decl *D);
+ void mangleBlockForPrefix(const BlockDecl *Block);
+ void mangleUnqualifiedBlock(const BlockDecl *Block);
void mangleLambda(const CXXRecordDecl *Lambda);
void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
bool NoFunction=false);
@@ -315,7 +341,7 @@ private:
void manglePrefix(NestedNameSpecifier *qualifier);
void manglePrefix(const DeclContext *DC, bool NoFunction=false);
void manglePrefix(QualType type);
- void mangleTemplatePrefix(const TemplateDecl *ND);
+ void mangleTemplatePrefix(const TemplateDecl *ND, bool NoFunction=false);
void mangleTemplatePrefix(TemplateName Template);
void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
void mangleQualifiers(Qualifiers Quals);
@@ -334,6 +360,7 @@ private:
void mangleBareFunctionType(const FunctionType *T,
bool MangleReturnType);
void mangleNeonVectorType(const VectorType *T);
+ void mangleAArch64NeonVectorType(const VectorType *T);
void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
void mangleMemberExpr(const Expr *base, bool isArrow,
@@ -358,16 +385,7 @@ private:
}
-bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
- // In C, functions with no attributes never need to be mangled. Fastpath them.
- if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
- return false;
-
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (D->hasAttr<AsmLabelAttr>())
- return true;
-
+bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
if (FD) {
LanguageLinkage L = FD->getLanguageLinkage();
@@ -405,7 +423,8 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
if (DC->isFunctionOrMethod() && D->hasLinkage())
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = getEffectiveParentContext(DC);
- if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage)
+ if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage &&
+ !isa<VarTemplateSpecializationDecl>(D))
return false;
}
@@ -413,26 +432,6 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
}
void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
- // If we have an asm name, then we use it as the mangling.
-
- // Adding the prefix can cause problems when one file has a "foo" and
- // another has a "\01foo". That is known to happen on ELF with the
- // tricks normally used for producing aliases (PR9177). Fortunately the
- // llvm mangler on ELF is a nop, so we can just avoid adding the \01
- // marker. We also avoid adding the marker if this is an alias for an
- // LLVM intrinsic.
- StringRef UserLabelPrefix =
- getASTContext().getTargetInfo().getUserLabelPrefix();
- if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm."))
- Out << '\01'; // LLVM IR Marker for __asm("foo")
-
- Out << ALA->getLabel();
- return;
- }
-
// <mangled-name> ::= _Z <encoding>
// ::= <data name>
// ::= <special-name>
@@ -441,6 +440,8 @@ void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) {
mangleFunctionEncoding(FD);
else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
mangleName(VD);
+ else if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(D))
+ mangleName(IFD->getAnonField());
else
mangleName(cast<FieldDecl>(D));
}
@@ -527,6 +528,13 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
return Spec->getSpecializedTemplate();
}
+ // Check if we have a variable template.
+ if (const VarTemplateSpecializationDecl *Spec =
+ dyn_cast<VarTemplateSpecializationDecl>(ND)) {
+ TemplateArgs = &Spec->getTemplateArgs();
+ return Spec->getSpecializedTemplate();
+ }
+
return 0;
}
@@ -550,7 +558,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
// is that of the containing namespace, or the translation unit.
// FIXME: This is a hack; extern variables declared locally should have
// a proper semantic declaration context!
- if (isa<FunctionDecl>(DC) && ND->hasLinkage() && !isLambda(ND))
+ if (isLocalContainerContext(DC) && ND->hasLinkage() && !isLambda(ND))
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = getEffectiveParentContext(DC);
else if (GetLocalClassDecl(ND)) {
@@ -573,7 +581,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
return;
}
- if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) {
+ if (isLocalContainerContext(DC)) {
mangleLocalName(ND);
return;
}
@@ -825,6 +833,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier,
switch (type->getTypeClass()) {
case Type::Builtin:
case Type::Complex:
+ case Type::Decayed:
case Type::Pointer:
case Type::BlockPointer:
case Type::LValueReference:
@@ -1053,7 +1062,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// static void foo();
// This naming convention is the same as that followed by GCC,
// though it shouldn't actually matter.
- if (ND && ND->getLinkage() == InternalLinkage &&
+ if (ND && ND->getFormalLinkage() == InternalLinkage &&
getEffectiveDeclContext(ND)->isFileContext())
Out << 'L';
@@ -1129,11 +1138,11 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
}
}
- int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD);
- if (UnnamedMangle != -1) {
+ if (TD->isExternallyVisible()) {
+ unsigned UnnamedMangle = getASTContext().getManglingNumber(TD);
Out << "Ut";
- if (UnnamedMangle != 0)
- Out << llvm::utostr(UnnamedMangle - 1);
+ if (UnnamedMangle > 1)
+ Out << llvm::utostr(UnnamedMangle - 2);
Out << '_';
break;
}
@@ -1231,14 +1240,19 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
Out << 'N';
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) {
- mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers()));
+ Qualifiers MethodQuals =
+ Qualifiers::fromCVRMask(Method->getTypeQualifiers());
+ // We do not consider restrict a distinguishing attribute for overloading
+ // purposes so we must not mangle it.
+ MethodQuals.removeRestrict();
+ mangleQualifiers(MethodQuals);
mangleRefQualifier(Method->getRefQualifier());
}
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
- mangleTemplatePrefix(TD);
+ mangleTemplatePrefix(TD, NoFunction);
mangleTemplateArgs(*TemplateArgs);
}
else {
@@ -1261,36 +1275,37 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
Out << 'E';
}
-void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
+void CXXNameMangler::mangleLocalName(const Decl *D) {
// <local-name> := Z <function encoding> E <entity name> [<discriminator>]
// := Z <function encoding> E s [<discriminator>]
// <local-name> := Z <function encoding> E d [ <parameter number> ]
// _ <entity name>
// <discriminator> := _ <non-negative number>
- const DeclContext *DC = getEffectiveDeclContext(ND);
- if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) {
- // Don't add objc method name mangling to locally declared function
- mangleUnqualifiedName(ND);
- return;
- }
+ assert(isa<NamedDecl>(D) || isa<BlockDecl>(D));
+ const RecordDecl *RD = GetLocalClassDecl(D);
+ const DeclContext *DC = getEffectiveDeclContext(RD ? RD : D);
Out << 'Z';
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
- mangleObjCMethodName(MD);
- } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) {
- mangleFunctionEncoding(cast<FunctionDecl>(getEffectiveDeclContext(RD)));
- Out << 'E';
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC))
+ mangleObjCMethodName(MD);
+ else if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC))
+ mangleBlockForPrefix(BD);
+ else
+ mangleFunctionEncoding(cast<FunctionDecl>(DC));
+
+ Out << 'E';
+ if (RD) {
// The parameter number is omitted for the last parameter, 0 for the
// second-to-last parameter, 1 for the third-to-last parameter, etc. The
// <entity name> will of course contain a <closure-type-name>: Its
// numbering will be local to the particular argument in which it appears
// -- other default arguments do not affect its encoding.
- bool SkipDiscriminator = false;
- if (RD->isLambda()) {
+ const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD);
+ if (CXXRD->isLambda()) {
if (const ParmVarDecl *Parm
- = dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl())) {
+ = dyn_cast_or_null<ParmVarDecl>(CXXRD->getLambdaContextDecl())) {
if (const FunctionDecl *Func
= dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
Out << 'd';
@@ -1298,34 +1313,88 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
if (Num > 1)
mangleNumber(Num - 2);
Out << '_';
- SkipDiscriminator = true;
}
}
}
// Mangle the name relative to the closest enclosing function.
- if (ND == RD) // equality ok because RD derived from ND above
- mangleUnqualifiedName(ND);
- else
- mangleNestedName(ND, DC, true /*NoFunction*/);
-
- if (!SkipDiscriminator) {
- unsigned disc;
- if (Context.getNextDiscriminator(RD, disc)) {
- if (disc < 10)
- Out << '_' << disc;
- else
- Out << "__" << disc << '_';
+ // equality ok because RD derived from ND above
+ if (D == RD) {
+ mangleUnqualifiedName(RD);
+ } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ manglePrefix(getEffectiveDeclContext(BD), true /*NoFunction*/);
+ mangleUnqualifiedBlock(BD);
+ } else {
+ const NamedDecl *ND = cast<NamedDecl>(D);
+ mangleNestedName(ND, getEffectiveDeclContext(ND), true /*NoFunction*/);
+ }
+ } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ // Mangle a block in a default parameter; see above explanation for
+ // lambdas.
+ if (const ParmVarDecl *Parm
+ = dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl())) {
+ if (const FunctionDecl *Func
+ = dyn_cast<FunctionDecl>(Parm->getDeclContext())) {
+ Out << 'd';
+ unsigned Num = Func->getNumParams() - Parm->getFunctionScopeIndex();
+ if (Num > 1)
+ mangleNumber(Num - 2);
+ Out << '_';
}
}
-
+
+ mangleUnqualifiedBlock(BD);
+ } else {
+ mangleUnqualifiedName(cast<NamedDecl>(D));
+ }
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(RD ? RD : D)) {
+ unsigned disc;
+ if (Context.getNextDiscriminator(ND, disc)) {
+ if (disc < 10)
+ Out << '_' << disc;
+ else
+ Out << "__" << disc << '_';
+ }
+ }
+}
+
+void CXXNameMangler::mangleBlockForPrefix(const BlockDecl *Block) {
+ if (GetLocalClassDecl(Block)) {
+ mangleLocalName(Block);
return;
}
- else
- mangleFunctionEncoding(cast<FunctionDecl>(DC));
+ const DeclContext *DC = getEffectiveDeclContext(Block);
+ if (isLocalContainerContext(DC)) {
+ mangleLocalName(Block);
+ return;
+ }
+ manglePrefix(getEffectiveDeclContext(Block));
+ mangleUnqualifiedBlock(Block);
+}
- Out << 'E';
- mangleUnqualifiedName(ND);
+void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
+ if (Decl *Context = Block->getBlockManglingContextDecl()) {
+ if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
+ Context->getDeclContext()->isRecord()) {
+ if (const IdentifierInfo *Name
+ = cast<NamedDecl>(Context)->getIdentifier()) {
+ mangleSourceName(Name);
+ Out << 'M';
+ }
+ }
+ }
+
+ // If we have a block mangling number, use it.
+ unsigned Number = Block->getBlockManglingNumber();
+ // Otherwise, just make up a number. It doesn't matter what it is because
+ // the symbol in question isn't externally visible.
+ if (!Number)
+ Number = Context.getBlockId(Block, false);
+ Out << "Ub";
+ if (Number > 1)
+ Out << Number - 2;
+ Out << '_';
}
void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
@@ -1411,16 +1480,11 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
if (DC->isTranslationUnit())
return;
- if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) {
- manglePrefix(getEffectiveParentContext(DC), NoFunction);
- SmallString<64> Name;
- llvm::raw_svector_ostream NameStream(Name);
- Context.mangleBlock(Block, NameStream);
- NameStream.flush();
- Out << Name.size() << Name;
+ if (NoFunction && isLocalContainerContext(DC))
return;
- }
-
+
+ assert(!isLocalContainerContext(DC));
+
const NamedDecl *ND = cast<NamedDecl>(DC);
if (mangleSubstitution(ND))
return;
@@ -1430,12 +1494,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
mangleTemplateArgs(*TemplateArgs);
- }
- else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND)))
- return;
- else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(ND))
- mangleObjCMethodName(Method);
- else {
+ } else {
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
mangleUnqualifiedName(ND);
}
@@ -1466,7 +1525,8 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
mangleUnscopedTemplateName(Template);
}
-void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
+void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND,
+ bool NoFunction) {
// <template-prefix> ::= <prefix> <template unqualified-name>
// ::= <template-param>
// ::= <substitution>
@@ -1483,7 +1543,7 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
return;
}
- manglePrefix(getEffectiveDeclContext(ND));
+ manglePrefix(getEffectiveDeclContext(ND), NoFunction);
mangleUnqualifiedName(ND->getTemplatedDecl());
addSubstitution(ND);
}
@@ -1671,15 +1731,32 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
Out << 'K';
if (Quals.hasAddressSpace()) {
- // Extension:
+ // Address space extension:
//
- // <type> ::= U <address-space-number>
- //
- // where <address-space-number> is a source name consisting of 'AS'
- // followed by the address space <number>.
+ // <type> ::= U <target-addrspace>
+ // <type> ::= U <OpenCL-addrspace>
+ // <type> ::= U <CUDA-addrspace>
+
SmallString<64> ASString;
- ASString = "AS" + llvm::utostr_32(
- Context.getASTContext().getTargetAddressSpace(Quals.getAddressSpace()));
+ unsigned AS = Quals.getAddressSpace();
+
+ if (Context.getASTContext().addressSpaceMapManglingFor(AS)) {
+ // <target-addrspace> ::= "AS" <address-space-number>
+ unsigned TargetAS = Context.getASTContext().getTargetAddressSpace(AS);
+ ASString = "AS" + llvm::utostr_32(TargetAS);
+ } else {
+ switch (AS) {
+ default: llvm_unreachable("Not a language specific address space");
+ // <OpenCL-addrspace> ::= "CL" [ "global" | "local" | "constant" ]
+ case LangAS::opencl_global: ASString = "CLglobal"; break;
+ case LangAS::opencl_local: ASString = "CLlocal"; break;
+ case LangAS::opencl_constant: ASString = "CLconstant"; break;
+ // <CUDA-addrspace> ::= "CU" [ "device" | "constant" | "shared" ]
+ case LangAS::cuda_device: ASString = "CUdevice"; break;
+ case LangAS::cuda_constant: ASString = "CUconstant"; break;
+ case LangAS::cuda_shared: ASString = "CUshared"; break;
+ }
+ }
Out << 'U' << ASString.size() << ASString;
}
@@ -1722,7 +1799,6 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) {
// <ref-qualifier> ::= R # lvalue reference
// ::= O # rvalue-reference
- // Proposal to Itanium C++ ABI list on 1/26/11
switch (RefQualifier) {
case RQ_None:
break;
@@ -1905,7 +1981,6 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
// <type> ::= <function-type>
// <function-type> ::= [<CV-qualifiers>] F [Y]
// <bare-function-type> [<ref-qualifier>] E
-// (Proposal to cxx-abi-dev, 2012-05-11)
void CXXNameMangler::mangleType(const FunctionProtoType *T) {
// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
// e.g. "const" in "int (A::*)() const".
@@ -2101,7 +2176,9 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
case BuiltinType::LongLong: EltName = "int64_t"; break;
case BuiltinType::ULongLong: EltName = "uint64_t"; break;
case BuiltinType::Float: EltName = "float32_t"; break;
- default: llvm_unreachable("unexpected Neon vector element type");
+ case BuiltinType::Half: EltName = "float16_t";break;
+ default:
+ llvm_unreachable("unexpected Neon vector element type");
}
}
const char *BaseName = 0;
@@ -2117,6 +2194,71 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
Out << BaseName << EltName;
}
+static StringRef mangleAArch64VectorBase(const BuiltinType *EltType) {
+ switch (EltType->getKind()) {
+ case BuiltinType::SChar:
+ return "Int8";
+ case BuiltinType::Short:
+ return "Int16";
+ case BuiltinType::Int:
+ return "Int32";
+ case BuiltinType::LongLong:
+ return "Int64";
+ case BuiltinType::UChar:
+ return "Uint8";
+ case BuiltinType::UShort:
+ return "Uint16";
+ case BuiltinType::UInt:
+ return "Uint32";
+ case BuiltinType::ULongLong:
+ return "Uint64";
+ case BuiltinType::Half:
+ return "Float16";
+ case BuiltinType::Float:
+ return "Float32";
+ case BuiltinType::Double:
+ return "Float64";
+ default:
+ llvm_unreachable("Unexpected vector element base type");
+ }
+}
+
+// AArch64's ABI for Neon vector types specifies that they should be mangled as
+// the equivalent internal name. The vector type must be one of the special
+// types predefined by ARM.
+void CXXNameMangler::mangleAArch64NeonVectorType(const VectorType *T) {
+ QualType EltType = T->getElementType();
+ assert(EltType->isBuiltinType() && "Neon vector element not a BuiltinType");
+ unsigned BitSize =
+ (T->getNumElements() * getASTContext().getTypeSize(EltType));
+ (void)BitSize; // Silence warning.
+
+ assert((BitSize == 64 || BitSize == 128) &&
+ "Neon vector type not 64 or 128 bits");
+
+ StringRef EltName;
+ if (T->getVectorKind() == VectorType::NeonPolyVector) {
+ switch (cast<BuiltinType>(EltType)->getKind()) {
+ case BuiltinType::UChar:
+ EltName = "Poly8";
+ break;
+ case BuiltinType::UShort:
+ EltName = "Poly16";
+ break;
+ case BuiltinType::ULongLong:
+ EltName = "Poly64";
+ break;
+ default:
+ llvm_unreachable("unexpected Neon polynomial vector element type");
+ }
+ } else
+ EltName = mangleAArch64VectorBase(cast<BuiltinType>(EltType));
+
+ std::string TypeName =
+ ("__" + EltName + "x" + llvm::utostr(T->getNumElements()) + "_t").str();
+ Out << TypeName.length() << TypeName;
+}
+
// GNU extension: vector types
// <type> ::= <vector-type>
// <vector-type> ::= Dv <positive dimension number> _
@@ -2128,7 +2270,11 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
void CXXNameMangler::mangleType(const VectorType *T) {
if ((T->getVectorKind() == VectorType::NeonVector ||
T->getVectorKind() == VectorType::NeonPolyVector)) {
- mangleNeonVectorType(T);
+ if (getASTContext().getTargetInfo().getTriple().getArch() ==
+ llvm::Triple::aarch64)
+ mangleAArch64NeonVectorType(T);
+ else
+ mangleNeonVectorType(T);
return;
}
Out << "Dv" << T->getNumElements() << '_';
@@ -2160,8 +2306,19 @@ void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
}
void CXXNameMangler::mangleType(const ObjCObjectType *T) {
- // We don't allow overloading by different protocol qualification,
- // so mangling them isn't necessary.
+ if (!T->qual_empty()) {
+ // Mangle protocol qualifiers.
+ SmallString<64> QualStr;
+ llvm::raw_svector_ostream QualOS(QualStr);
+ QualOS << "objcproto";
+ ObjCObjectType::qual_iterator i = T->qual_begin(), e = T->qual_end();
+ for ( ; i != e; ++i) {
+ StringRef name = (*i)->getName();
+ QualOS << name.size() << name;
+ }
+ QualOS.flush();
+ Out << 'U' << QualStr.size() << QualStr;
+ }
mangleType(T->getBaseType());
}
@@ -2422,6 +2579,7 @@ recurse:
case Expr::OffsetOfExprClass:
case Expr::PredefinedExprClass:
case Expr::ShuffleVectorExprClass:
+ case Expr::ConvertVectorExprClass:
case Expr::StmtExprClass:
case Expr::UnaryTypeTraitExprClass:
case Expr::BinaryTypeTraitExprClass:
@@ -2477,6 +2635,10 @@ recurse:
mangleExpression(cast<CXXDefaultInitExpr>(E)->getExpr(), Arity);
break;
+ case Expr::CXXStdInitializerListExprClass:
+ mangleExpression(cast<CXXStdInitializerListExpr>(E)->getSubExpr(), Arity);
+ break;
+
case Expr::SubstNonTypeTemplateParmExprClass:
mangleExpression(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(),
Arity);
@@ -2676,8 +2838,8 @@ recurse:
case Expr::CXXThrowExprClass: {
const CXXThrowExpr *TE = cast<CXXThrowExpr>(E);
-
- // Proposal from David Vandervoorde, 2010.06.30
+ // <expression> ::= tw <expression> # throw expression
+ // ::= tr # rethrow
if (TE->getSubExpr()) {
Out << "tw";
mangleExpression(TE->getSubExpr());
@@ -2689,11 +2851,11 @@ recurse:
case Expr::CXXTypeidExprClass: {
const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E);
-
- // Proposal from David Vandervoorde, 2010.06.30
+ // <expression> ::= ti <type> # typeid (type)
+ // ::= te <expression> # typeid (expression)
if (TIE->isTypeOperand()) {
Out << "ti";
- mangleType(TIE->getTypeOperand());
+ mangleType(TIE->getTypeOperand(Context.getASTContext()));
} else {
Out << "te";
mangleExpression(TIE->getExprOperand());
@@ -2703,8 +2865,8 @@ recurse:
case Expr::CXXDeleteExprClass: {
const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E);
-
- // Proposal from David Vandervoorde, 2010.06.30
+ // <expression> ::= [gs] dl <expression> # [::] delete expr
+ // ::= [gs] da <expression> # [::] delete [] expr
if (DE->isGlobalDelete()) Out << "gs";
Out << (DE->isArrayForm() ? "da" : "dl");
mangleExpression(DE->getArgument());
@@ -2935,8 +3097,6 @@ recurse:
// fallthrough
case Expr::CXXNullPtrLiteralExprClass: {
- // Proposal from David Vandervoorde, 2010.06.30, as
- // modified by ABI list discussion.
Out << "LDnE";
break;
}
@@ -3101,7 +3261,6 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
// ::= J <template-arg>* E # argument pack
- // ::= sp <expression> # pack expansion of (C++0x)
if (!A.isInstantiationDependent() || A.isDependent())
A = Context.getASTContext().getCanonicalTemplateArgument(A);
@@ -3181,9 +3340,9 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
break;
}
case TemplateArgument::Pack: {
- // Note: proposal by Mike Herrick on 12/20/10
+ // <template-arg> ::= J <template-arg>* E
Out << 'J';
- for (TemplateArgument::pack_iterator PA = A.pack_begin(),
+ for (TemplateArgument::pack_iterator PA = A.pack_begin(),
PAEnd = A.pack_end();
PA != PAEnd; ++PA)
mangleTemplateArg(*PA);
@@ -3452,8 +3611,8 @@ void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
/// and this routine will return false. In this case, the caller should just
/// emit the identifier of the declaration (\c D->getIdentifier()) as its
/// name.
-void ItaniumMangleContext::mangleName(const NamedDecl *D,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXName(const NamedDecl *D,
+ raw_ostream &Out) {
assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
"Invalid mangleName() call, argument is not a variable or function!");
assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
@@ -3467,23 +3626,23 @@ void ItaniumMangleContext::mangleName(const NamedDecl *D,
return Mangler.mangle(D);
}
-void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
- CXXCtorType Type,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out, D, Type);
Mangler.mangle(D);
}
-void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
- CXXDtorType Type,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D,
+ CXXDtorType Type,
+ raw_ostream &Out) {
CXXNameMangler Mangler(*this, Out, D, Type);
Mangler.mangle(D);
}
-void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD,
- const ThunkInfo &Thunk,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
+ raw_ostream &Out) {
// <special-name> ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
// <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
@@ -3499,21 +3658,20 @@ void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD,
Mangler.getStream() << 'c';
// Mangle the 'this' pointer adjustment.
- Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset);
-
+ Mangler.mangleCallOffset(Thunk.This.NonVirtual,
+ Thunk.This.Virtual.Itanium.VCallOffsetOffset);
+
// Mangle the return pointer adjustment if there is one.
if (!Thunk.Return.isEmpty())
Mangler.mangleCallOffset(Thunk.Return.NonVirtual,
- Thunk.Return.VBaseOffsetOffset);
-
+ Thunk.Return.Virtual.Itanium.VBaseOffsetOffset);
+
Mangler.mangleFunctionEncoding(MD);
}
-void
-ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
- CXXDtorType Type,
- const ThisAdjustment &ThisAdjustment,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXDtorThunk(
+ const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment, raw_ostream &Out) {
// <special-name> ::= T <call-offset> <base encoding>
// # base is the nominal target function of thunk
CXXNameMangler Mangler(*this, Out, DD, Type);
@@ -3521,15 +3679,15 @@ ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
// Mangle the 'this' pointer adjustment.
Mangler.mangleCallOffset(ThisAdjustment.NonVirtual,
- ThisAdjustment.VCallOffsetOffset);
+ ThisAdjustment.Virtual.Itanium.VCallOffsetOffset);
Mangler.mangleFunctionEncoding(DD);
}
/// mangleGuardVariable - Returns the mangled name for a guard variable
/// for the passed in VarDecl.
-void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleStaticGuardVariable(const VarDecl *D,
+ raw_ostream &Out) {
// <special-name> ::= GV <object name> # Guard variable for one-time
// # initialization
CXXNameMangler Mangler(*this, Out);
@@ -3537,24 +3695,44 @@ void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D,
Mangler.mangleName(D);
}
-void ItaniumMangleContext::mangleItaniumThreadLocalInit(const VarDecl *D,
+void ItaniumMangleContextImpl::mangleDynamicInitializer(const VarDecl *MD,
raw_ostream &Out) {
+ // These symbols are internal in the Itanium ABI, so the names don't matter.
+ // Clang has traditionally used this symbol and allowed LLVM to adjust it to
+ // avoid duplicate symbols.
+ Out << "__cxx_global_var_init";
+}
+
+void ItaniumMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D,
+ raw_ostream &Out) {
+ // Prefix the mangling of D with __dtor_.
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "__dtor_";
+ if (shouldMangleDeclName(D))
+ Mangler.mangle(D);
+ else
+ Mangler.getStream() << D->getName();
+}
+
+void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D,
+ raw_ostream &Out) {
// <special-name> ::= TH <object name>
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTH";
Mangler.mangleName(D);
}
-void ItaniumMangleContext::mangleItaniumThreadLocalWrapper(const VarDecl *D,
- raw_ostream &Out) {
+void
+ItaniumMangleContextImpl::mangleItaniumThreadLocalWrapper(const VarDecl *D,
+ raw_ostream &Out) {
// <special-name> ::= TW <object name>
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTW";
Mangler.mangleName(D);
}
-void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleReferenceTemporary(const VarDecl *D,
+ raw_ostream &Out) {
// We match the GCC mangling here.
// <special-name> ::= GR <object name>
CXXNameMangler Mangler(*this, Out);
@@ -3562,26 +3740,26 @@ void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D,
Mangler.mangleName(D);
}
-void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXVTable(const CXXRecordDecl *RD,
+ raw_ostream &Out) {
// <special-name> ::= TV <type> # virtual table
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTV";
Mangler.mangleNameOrStandardSubstitution(RD);
}
-void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXVTT(const CXXRecordDecl *RD,
+ raw_ostream &Out) {
// <special-name> ::= TT <type> # VTT structure
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTT";
Mangler.mangleNameOrStandardSubstitution(RD);
}
-void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
- int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXCtorVTable(const CXXRecordDecl *RD,
+ int64_t Offset,
+ const CXXRecordDecl *Type,
+ raw_ostream &Out) {
// <special-name> ::= TC <type> <offset number> _ <base type>
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTC";
@@ -3591,8 +3769,7 @@ void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
Mangler.mangleNameOrStandardSubstitution(Type);
}
-void ItaniumMangleContext::mangleCXXRTTI(QualType Ty,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXRTTI(QualType Ty, raw_ostream &Out) {
// <special-name> ::= TI <type> # typeinfo structure
assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers");
CXXNameMangler Mangler(*this, Out);
@@ -3600,15 +3777,19 @@ void ItaniumMangleContext::mangleCXXRTTI(QualType Ty,
Mangler.mangleType(Ty);
}
-void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty,
- raw_ostream &Out) {
+void ItaniumMangleContextImpl::mangleCXXRTTIName(QualType Ty,
+ raw_ostream &Out) {
// <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
CXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "_ZTS";
Mangler.mangleType(Ty);
}
-MangleContext *clang::createItaniumMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags) {
- return new ItaniumMangleContext(Context, Diags);
+void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out) {
+ mangleCXXRTTIName(Ty, Out);
+}
+
+ItaniumMangleContext *
+ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
+ return new ItaniumMangleContextImpl(Context, Diags);
}
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index eb79412..231ef03 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -10,6 +10,7 @@
// Implements generic name mangling support for blocks and Objective-C.
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Attr.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
@@ -19,6 +20,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
@@ -34,8 +36,6 @@ using namespace clang;
// FIXME: For blocks we currently mimic GCC's mangling scheme, which leaves
// much to be desired. Come up with a better mangling scheme.
-namespace {
-
static void mangleFunctionBlock(MangleContext &Context,
StringRef Outer,
const BlockDecl *BD,
@@ -47,23 +47,131 @@ static void mangleFunctionBlock(MangleContext &Context,
Out << "__" << Outer << "_block_invoke_" << discriminator+1;
}
-static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) {
-#ifndef NDEBUG
- const DeclContext *ExpectedDC = BD->getDeclContext();
- while (isa<BlockDecl>(ExpectedDC) || isa<EnumDecl>(ExpectedDC))
- ExpectedDC = ExpectedDC->getParent();
- // In-class initializers for non-static data members are lexically defined
- // within the class, but are mangled as if they were specified as constructor
- // member initializers.
- if (isa<CXXRecordDecl>(ExpectedDC) && DC != ExpectedDC)
- DC = DC->getParent();
- assert(DC == ExpectedDC && "Given decl context did not match expected!");
-#endif
+void MangleContext::anchor() { }
+
+enum StdOrFastCC {
+ SOF_OTHER,
+ SOF_FAST,
+ SOF_STD
+};
+
+static bool isExternC(const NamedDecl *ND) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+ return FD->isExternC();
+ return cast<VarDecl>(ND)->isExternC();
}
+static StdOrFastCC getStdOrFastCallMangling(const ASTContext &Context,
+ const NamedDecl *ND) {
+ const TargetInfo &TI = Context.getTargetInfo();
+ llvm::Triple Triple = TI.getTriple();
+ if (!Triple.isOSWindows() || Triple.getArch() != llvm::Triple::x86)
+ return SOF_OTHER;
+
+ if (Context.getLangOpts().CPlusPlus && !isExternC(ND) &&
+ TI.getCXXABI() == TargetCXXABI::Microsoft)
+ return SOF_OTHER;
+
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
+ if (!FD)
+ return SOF_OTHER;
+ QualType T = FD->getType();
+
+ const FunctionType *FT = T->castAs<FunctionType>();
+
+ CallingConv CC = FT->getCallConv();
+ switch (CC) {
+ default:
+ return SOF_OTHER;
+ case CC_X86FastCall:
+ return SOF_FAST;
+ case CC_X86StdCall:
+ return SOF_STD;
+ }
}
-void MangleContext::anchor() { }
+bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
+ const ASTContext &ASTContext = getASTContext();
+
+ StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D);
+ if (CC != SOF_OTHER)
+ return true;
+
+ // In C, functions with no attributes never need to be mangled. Fastpath them.
+ if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
+ return false;
+
+ // Any decl can be declared with __asm("foo") on it, and this takes precedence
+ // over all other naming in the .o file.
+ if (D->hasAttr<AsmLabelAttr>())
+ return true;
+
+ return shouldMangleCXXName(D);
+}
+
+void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) {
+ // Any decl can be declared with __asm("foo") on it, and this takes precedence
+ // over all other naming in the .o file.
+ if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
+ // If we have an asm name, then we use it as the mangling.
+
+ // Adding the prefix can cause problems when one file has a "foo" and
+ // another has a "\01foo". That is known to happen on ELF with the
+ // tricks normally used for producing aliases (PR9177). Fortunately the
+ // llvm mangler on ELF is a nop, so we can just avoid adding the \01
+ // marker. We also avoid adding the marker if this is an alias for an
+ // LLVM intrinsic.
+ StringRef UserLabelPrefix =
+ getASTContext().getTargetInfo().getUserLabelPrefix();
+ if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm."))
+ Out << '\01'; // LLVM IR Marker for __asm("foo")
+
+ Out << ALA->getLabel();
+ return;
+ }
+
+ const ASTContext &ASTContext = getASTContext();
+ StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D);
+ bool MCXX = shouldMangleCXXName(D);
+ const TargetInfo &TI = Context.getTargetInfo();
+ if (CC == SOF_OTHER || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) {
+ mangleCXXName(D, Out);
+ return;
+ }
+
+ Out << '\01';
+ if (CC == SOF_STD)
+ Out << '_';
+ else
+ Out << '@';
+
+ if (!MCXX)
+ Out << D->getIdentifier()->getName();
+ else
+ mangleCXXName(D, Out);
+
+ const FunctionDecl *FD = cast<FunctionDecl>(D);
+ const FunctionType *FT = FD->getType()->castAs<FunctionType>();
+ const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT);
+ Out << '@';
+ if (!Proto) {
+ Out << '0';
+ return;
+ }
+ assert(!Proto->isVariadic());
+ unsigned ArgWords = 0;
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
+ if (!MD->isStatic())
+ ++ArgWords;
+ for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+ ArgEnd = Proto->arg_type_end();
+ Arg != ArgEnd; ++Arg) {
+ QualType AT = *Arg;
+ // Size should be aligned to DWORD boundary
+ ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT), 32) / 32;
+ }
+ Out << 4 * ArgWords;
+}
void MangleContext::mangleGlobalBlock(const BlockDecl *BD,
const NamedDecl *ID,
@@ -85,7 +193,6 @@ void MangleContext::mangleGlobalBlock(const BlockDecl *BD,
void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD,
CXXCtorType CT, const BlockDecl *BD,
raw_ostream &ResStream) {
- checkMangleDC(CD, BD);
SmallString<64> Buffer;
llvm::raw_svector_ostream Out(Buffer);
mangleCXXCtor(CD, CT, Out);
@@ -96,7 +203,6 @@ void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD,
void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD,
CXXDtorType DT, const BlockDecl *BD,
raw_ostream &ResStream) {
- checkMangleDC(DD, BD);
SmallString<64> Buffer;
llvm::raw_svector_ostream Out(Buffer);
mangleCXXDtor(DD, DT, Out);
@@ -107,7 +213,6 @@ void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD,
void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD,
raw_ostream &Out) {
assert(!isa<CXXConstructorDecl>(DC) && !isa<CXXDestructorDecl>(DC));
- checkMangleDC(DC, BD);
SmallString<64> Buffer;
llvm::raw_svector_ostream Stream(Buffer);
@@ -145,15 +250,3 @@ void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
Out << OS.str().size() << OS.str();
}
-
-void MangleContext::mangleBlock(const BlockDecl *BD,
- raw_ostream &Out,
- const NamedDecl *ID) {
- const DeclContext *DC = BD->getDeclContext();
- while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC))
- DC = DC->getParent();
- if (DC->isFunctionOrMethod())
- mangleBlock(DC, BD, Out);
- else
- mangleGlobalBlock(BD, ID, Out);
-}
diff --git a/lib/AST/LambdaMangleContext.cpp b/lib/AST/MangleNumberingContext.cpp
index 54f445d..91ef0e2 100644
--- a/lib/AST/LambdaMangleContext.cpp
+++ b/lib/AST/MangleNumberingContext.cpp
@@ -1,4 +1,4 @@
-//===--- LambdaMangleContext.cpp - Context for mangling lambdas -*- C++ -*-===//
+//===--- MangleNumberingContext.cpp - Context for mangling numbers --------===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,22 +12,32 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/LambdaMangleContext.h"
+#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
using namespace clang;
-unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) {
+unsigned
+MangleNumberingContext::getManglingNumber(const CXXMethodDecl *CallOperator) {
const FunctionProtoType *Proto
= CallOperator->getType()->getAs<FunctionProtoType>();
ASTContext &Context = CallOperator->getASTContext();
-
- QualType Key =
- Context.getFunctionType(Context.VoidTy,
- ArrayRef<QualType>(Proto->arg_type_begin(),
- Proto->getNumArgs()),
- FunctionProtoType::ExtProtoInfo());
+
+ QualType Key = Context.getFunctionType(Context.VoidTy, Proto->getArgTypes(),
+ FunctionProtoType::ExtProtoInfo());
Key = Context.getCanonicalType(Key);
return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
}
+
+unsigned
+MangleNumberingContext::getManglingNumber(const BlockDecl *BD) {
+ // FIXME: Compute a BlockPointerType? Not obvious how.
+ const Type *Ty = 0;
+ return ++ManglingNumbers[Ty];
+}
+
+unsigned
+MangleNumberingContext::getManglingNumber(const TagDecl *TD) {
+ return ++TagManglingNumbers[TD->getIdentifier()];
+}
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index fd932f7..4a93ea1 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -16,6 +16,7 @@
#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
@@ -23,6 +24,22 @@
using namespace clang;
namespace {
+
+/// \brief Numbers things which need to correspond across multiple TUs.
+/// Typically these are things like static locals, lambdas, or blocks.
+class MicrosoftNumberingContext : public MangleNumberingContext {
+ unsigned NumStaticLocals;
+
+public:
+ MicrosoftNumberingContext() : NumStaticLocals(0) { }
+
+ /// Static locals are numbered by source order.
+ virtual unsigned getManglingNumber(const VarDecl *VD) {
+ assert(VD->isStaticLocal());
+ return ++NumStaticLocals;
+ }
+};
+
class MicrosoftCXXABI : public CXXABI {
ASTContext &Context;
public:
@@ -51,6 +68,10 @@ public:
return Layout.getNonVirtualSize() == PointerSize ||
Layout.getNonVirtualSize() == PointerSize * 2;
}
+
+ MangleNumberingContext *createMangleNumberingContext() const {
+ return new MicrosoftNumberingContext();
+ }
};
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 1785063..5256501 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -22,12 +23,47 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/DiagnosticOptions.h"
-#include <map>
+#include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringMap.h"
using namespace clang;
namespace {
+/// \brief Retrieve the declaration context that should be used when mangling
+/// the given declaration.
+static const DeclContext *getEffectiveDeclContext(const Decl *D) {
+ // The ABI assumes that lambda closure types that occur within
+ // default arguments live in the context of the function. However, due to
+ // the way in which Clang parses and creates function declarations, this is
+ // not the case: the lambda closure type ends up living in the context
+ // where the function itself resides, because the function declaration itself
+ // had not yet been created. Fix the context here.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (RD->isLambda())
+ if (ParmVarDecl *ContextParam =
+ dyn_cast_or_null<ParmVarDecl>(RD->getLambdaContextDecl()))
+ return ContextParam->getDeclContext();
+ }
+
+ // Perform the same check for block literals.
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
+ if (ParmVarDecl *ContextParam =
+ dyn_cast_or_null<ParmVarDecl>(BD->getBlockManglingContextDecl()))
+ return ContextParam->getDeclContext();
+ }
+
+ const DeclContext *DC = D->getDeclContext();
+ if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC))
+ return getEffectiveDeclContext(CD);
+
+ return DC;
+}
+
+static const DeclContext *getEffectiveParentContext(const DeclContext *DC) {
+ return getEffectiveDeclContext(cast<Decl>(DC));
+}
+
static const FunctionDecl *getStructor(const FunctionDecl *fn) {
if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
return ftd->getTemplatedDecl();
@@ -47,9 +83,7 @@ class MicrosoftCXXNameMangler {
const NamedDecl *Structor;
unsigned StructorType;
- // FIXME: audit the performance of BackRefMap as it might do way too many
- // copying of strings.
- typedef std::map<std::string, unsigned> BackRefMap;
+ typedef llvm::StringMap<unsigned> BackRefMap;
BackRefMap NameBackReferences;
bool UseNameBackReferences;
@@ -58,30 +92,41 @@ class MicrosoftCXXNameMangler {
ASTContext &getASTContext() const { return Context.getASTContext(); }
+ // FIXME: If we add support for __ptr32/64 qualifiers, then we should push
+ // this check into mangleQualifiers().
+ const bool PointersAre64Bit;
+
public:
enum QualifierMangleMode { QMM_Drop, QMM_Mangle, QMM_Escape, QMM_Result };
MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_)
: Context(C), Out(Out_),
Structor(0), StructorType(-1),
- UseNameBackReferences(true) { }
+ UseNameBackReferences(true),
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
+ 64) { }
MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_,
const CXXDestructorDecl *D, CXXDtorType Type)
: Context(C), Out(Out_),
Structor(getStructor(D)), StructorType(Type),
- UseNameBackReferences(true) { }
+ UseNameBackReferences(true),
+ PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) ==
+ 64) { }
raw_ostream &getStream() const { return Out; }
void mangle(const NamedDecl *D, StringRef Prefix = "\01?");
void mangleName(const NamedDecl *ND);
+ void mangleDeclaration(const NamedDecl *ND);
void mangleFunctionEncoding(const FunctionDecl *FD);
void mangleVariableEncoding(const VarDecl *VD);
void mangleNumber(int64_t Number);
- void mangleNumber(const llvm::APSInt &Value);
void mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM = QMM_Mangle);
+ void mangleFunctionType(const FunctionType *T, const FunctionDecl *D = 0,
+ bool ForceInstMethod = false);
+ void manglePostfix(const DeclContext *DC, bool NoFunction = false);
private:
void disableBackReferences() { UseNameBackReferences = false; }
@@ -89,8 +134,7 @@ private:
mangleUnqualifiedName(ND, ND->getDeclName());
}
void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name);
- void mangleSourceName(const IdentifierInfo *II);
- void manglePostfix(const DeclContext *DC, bool NoFunction=false);
+ void mangleSourceName(StringRef Name);
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
void mangleCXXDtorType(CXXDtorType T);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
@@ -114,98 +158,111 @@ private:
#undef NON_CANONICAL_TYPE
#undef TYPE
- void mangleType(const TagType*);
- void mangleFunctionType(const FunctionType *T, const FunctionDecl *D,
- bool IsStructor, bool IsInstMethod);
- void mangleDecayedArrayType(const ArrayType *T, bool IsGlobal);
- void mangleArrayType(const ArrayType *T, Qualifiers Quals);
+ void mangleType(const TagDecl *TD);
+ void mangleDecayedArrayType(const ArrayType *T);
+ void mangleArrayType(const ArrayType *T);
void mangleFunctionClass(const FunctionDecl *FD);
- void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
+ void mangleCallingConvention(const FunctionType *T);
void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
void mangleExpression(const Expr *E);
void mangleThrowSpecification(const FunctionProtoType *T);
void mangleTemplateArgs(const TemplateDecl *TD,
const TemplateArgumentList &TemplateArgs);
-
+ void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA);
};
-/// MicrosoftMangleContext - Overrides the default MangleContext for the
+/// MicrosoftMangleContextImpl - Overrides the default MangleContext for the
/// Microsoft Visual C++ ABI.
-class MicrosoftMangleContext : public MangleContext {
+class MicrosoftMangleContextImpl : public MicrosoftMangleContext {
public:
- MicrosoftMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags) : MangleContext(Context, Diags) { }
- virtual bool shouldMangleDeclName(const NamedDecl *D);
- virtual void mangleName(const NamedDecl *D, raw_ostream &Out);
+ MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
+ : MicrosoftMangleContext(Context, Diags) {}
+ virtual bool shouldMangleCXXName(const NamedDecl *D);
+ virtual void mangleCXXName(const NamedDecl *D, raw_ostream &Out);
+ virtual void mangleVirtualMemPtrThunk(const CXXMethodDecl *MD,
+ uint64_t OffsetInVFTable,
+ raw_ostream &);
virtual void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &);
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
raw_ostream &);
- virtual void mangleCXXVTable(const CXXRecordDecl *RD,
- raw_ostream &);
- virtual void mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &);
- virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &);
+ virtual void mangleCXXVFTable(const CXXRecordDecl *Derived,
+ ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out);
+ virtual void mangleCXXVBTable(const CXXRecordDecl *Derived,
+ ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out);
virtual void mangleCXXRTTI(QualType T, raw_ostream &);
virtual void mangleCXXRTTIName(QualType T, raw_ostream &);
+ virtual void mangleTypeName(QualType T, raw_ostream &);
virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
raw_ostream &);
virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
raw_ostream &);
- virtual void mangleReferenceTemporary(const clang::VarDecl *,
- raw_ostream &);
-};
-
-}
+ virtual void mangleReferenceTemporary(const VarDecl *, raw_ostream &);
+ virtual void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out);
+ virtual void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out);
+ virtual void mangleDynamicAtExitDestructor(const VarDecl *D,
+ raw_ostream &Out);
-static bool isInCLinkageSpecification(const Decl *D) {
- D = D->getCanonicalDecl();
- for (const DeclContext *DC = D->getDeclContext();
- !DC->isTranslationUnit(); DC = DC->getParent()) {
- if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC))
- return Linkage->getLanguage() == LinkageSpecDecl::lang_c;
- }
+private:
+ void mangleInitFiniStub(const VarDecl *D, raw_ostream &Out, char CharCode);
+};
- return false;
}
-bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) {
- // In C, functions with no attributes never need to be mangled. Fastpath them.
- if (!getASTContext().getLangOpts().CPlusPlus && !D->hasAttrs())
- return false;
+bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ LanguageLinkage L = FD->getLanguageLinkage();
+ // Overloadable functions need mangling.
+ if (FD->hasAttr<OverloadableAttr>())
+ return true;
+
+ // The ABI expects that we would never mangle "typical" user-defined entry
+ // points regardless of visibility or freestanding-ness.
+ //
+ // N.B. This is distinct from asking about "main". "main" has a lot of
+ // special rules associated with it in the standard while these
+ // user-defined entry points are outside of the purview of the standard.
+ // For example, there can be only one definition for "main" in a standards
+ // compliant program; however nothing forbids the existence of wmain and
+ // WinMain in the same translation unit.
+ if (FD->isMSVCRTEntryPoint())
+ return false;
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (D->hasAttr<AsmLabelAttr>())
- return true;
+ // C++ functions and those whose names are not a simple identifier need
+ // mangling.
+ if (!FD->getDeclName().isIdentifier() || L == CXXLanguageLinkage)
+ return true;
- // Clang's "overloadable" attribute extension to C/C++ implies name mangling
- // (always) as does passing a C++ member function and a function
- // whose name is not a simple identifier.
- const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
- if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) ||
- !FD->getDeclName().isIdentifier()))
- return true;
+ // C functions are not mangled.
+ if (L == CLanguageLinkage)
+ return false;
+ }
// Otherwise, no mangling is done outside C++ mode.
if (!getASTContext().getLangOpts().CPlusPlus)
return false;
- // Variables at global scope with internal linkage are not mangled.
- if (!FD) {
- const DeclContext *DC = D->getDeclContext();
- if (DC->isTranslationUnit() && D->getLinkage() == InternalLinkage)
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ // C variables are not mangled.
+ if (VD->isExternC())
return false;
- }
- // C functions and "main" are not mangled.
- if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
- return false;
+ // Variables at global scope with non-internal linkage are not mangled.
+ const DeclContext *DC = getEffectiveDeclContext(D);
+ // Check for extern variable declared locally.
+ if (DC->isFunctionOrMethod() && D->hasLinkage())
+ while (!DC->isNamespace() && !DC->isTranslationUnit())
+ DC = getEffectiveParentContext(DC);
+
+ if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage &&
+ !isa<VarTemplateSpecializationDecl>(D))
+ return false;
+ }
return true;
}
@@ -218,14 +275,6 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
// default, we emit an asm marker at the start so we get the name right.
// Callers can override this with a custom prefix.
- // Any decl can be declared with __asm("foo") on it, and this takes precedence
- // over all other naming in the .o file.
- if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
- // If we have an asm name, then we use it as the mangling.
- Out << '\01' << ALA->getLabel();
- return;
- }
-
// <mangled-name> ::= ? <name> <type-encoding>
Out << Prefix;
mangleName(D);
@@ -247,27 +296,25 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
// <type-encoding> ::= <function-class> <function-type>
- // Don't mangle in the type if this isn't a decl we should typically mangle.
- if (!Context.shouldMangleDeclName(FD))
- return;
-
+ // Since MSVC operates on the type as written and not the canonical type, it
+ // actually matters which decl we have here. MSVC appears to choose the
+ // first, since it is most likely to be the declaration in a header file.
+ FD = FD->getFirstDecl();
+
// We should never ever see a FunctionNoProtoType at this point.
// We don't even know how to mangle their types anyway :).
const FunctionProtoType *FT = FD->getType()->castAs<FunctionProtoType>();
- bool InStructor = false, InInstMethod = false;
- const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD);
- if (MD) {
- if (MD->isInstance())
- InInstMethod = true;
- if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
- InStructor = true;
- }
-
- // First, the function class.
- mangleFunctionClass(FD);
+ // extern "C" functions can hold entities that must be mangled.
+ // As it stands, these functions still need to get expressed in the full
+ // external name. They have their class and type omitted, replaced with '9'.
+ if (Context.shouldMangleDeclName(FD)) {
+ // First, the function class.
+ mangleFunctionClass(FD);
- mangleFunctionType(FT, FD, InStructor, InInstMethod);
+ mangleFunctionType(FT, FD);
+ } else
+ Out << '9';
}
void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
@@ -299,12 +346,21 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
// mangled as 'QAHA' instead of 'PAHB', for example.
TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc();
QualType Ty = TL.getType();
- if (Ty->isPointerType() || Ty->isReferenceType()) {
+ if (Ty->isPointerType() || Ty->isReferenceType() ||
+ Ty->isMemberPointerType()) {
mangleType(Ty, TL.getSourceRange(), QMM_Drop);
- mangleQualifiers(Ty->getPointeeType().getQualifiers(), false);
+ if (PointersAre64Bit)
+ Out << 'E';
+ if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()) {
+ mangleQualifiers(MPT->getPointeeType().getQualifiers(), true);
+ // Member pointers are suffixed with a back reference to the member
+ // pointer's class name.
+ mangleName(MPT->getClass()->getAsCXXRecordDecl());
+ } else
+ mangleQualifiers(Ty->getPointeeType().getQualifiers(), false);
} else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) {
// Global arrays are funny, too.
- mangleDecayedArrayType(AT, true);
+ mangleDecayedArrayType(AT);
if (AT->getElementType()->isArrayType())
Out << 'A';
else
@@ -335,39 +391,32 @@ void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
}
void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
- llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false);
- APSNumber = Number;
- mangleNumber(APSNumber);
-}
-
-void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
- // <number> ::= [?] <decimal digit> # 1 <= Number <= 10
- // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc...
- // ::= [?] @ # 0 (alternate mangling, not emitted by VC)
- if (Value.isSigned() && Value.isNegative()) {
+ // <non-negative integer> ::= A@ # when Number == 0
+ // ::= <decimal digit> # when 1 <= Number <= 10
+ // ::= <hex digit>+ @ # when Number >= 10
+ //
+ // <number> ::= [?] <non-negative integer>
+
+ uint64_t Value = static_cast<uint64_t>(Number);
+ if (Number < 0) {
+ Value = -Value;
Out << '?';
- mangleNumber(llvm::APSInt(Value.abs()));
- return;
}
- llvm::APSInt Temp(Value);
- // There's a special shorter mangling for 0, but Microsoft
- // chose not to use it. Instead, 0 gets mangled as "A@". Oh well...
- if (Value.uge(1) && Value.ule(10)) {
- --Temp;
- Temp.print(Out, false);
- } else {
- // We have to build up the encoding in reverse order, so it will come
- // out right when we write it out.
- char Encoding[64];
- char *EndPtr = Encoding+sizeof(Encoding);
- char *CurPtr = EndPtr;
- llvm::APSInt NibbleMask(Value.getBitWidth(), Value.isUnsigned());
- NibbleMask = 0xf;
- do {
- *--CurPtr = 'A' + Temp.And(NibbleMask).getLimitedValue(0xf);
- Temp = Temp.lshr(4);
- } while (Temp != 0);
- Out.write(CurPtr, EndPtr-CurPtr);
+
+ if (Value == 0)
+ Out << "A@";
+ else if (Value >= 1 && Value <= 10)
+ Out << (Value - 1);
+ else {
+ // Numbers that are not encoded as decimal digits are represented as nibbles
+ // in the range of ASCII characters 'A' to 'P'.
+ // The number 0x123450 would be encoded as 'BCDEFA'
+ char EncodedNumberBuffer[sizeof(uint64_t) * 2];
+ llvm::MutableArrayRef<char> BufferRef(EncodedNumberBuffer);
+ llvm::MutableArrayRef<char>::reverse_iterator I = BufferRef.rbegin();
+ for (; Value != 0; Value >>= 4)
+ *I++ = 'A' + (Value & 0xf);
+ Out.write(I.base(), I - BufferRef.rbegin());
Out << '@';
}
}
@@ -403,7 +452,16 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
- // We have a template.
+ // Function templates aren't considered for name back referencing. This
+ // makes sense since function templates aren't likely to occur multiple
+ // times in a symbol.
+ // FIXME: Test alias template mangling with MSVC 2013.
+ if (!isa<ClassTemplateDecl>(TD)) {
+ mangleTemplateInstantiationName(TD, *TemplateArgs);
+ return;
+ }
+
+ // We have a class template.
// Here comes the tricky thing: if we need to mangle something like
// void foo(A::X<Y>, B::X<Y>),
// the X<Y> part is aliased. However, if you need to mangle
@@ -445,7 +503,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
switch (Name.getNameKind()) {
case DeclarationName::Identifier: {
if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
- mangleSourceName(II);
+ mangleSourceName(II->getName());
break;
}
@@ -466,13 +524,22 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
"Typedef should not be in another decl context!");
assert(D->getDeclName().getAsIdentifierInfo() &&
"Typedef was not named!");
- mangleSourceName(D->getDeclName().getAsIdentifierInfo());
+ mangleSourceName(D->getDeclName().getAsIdentifierInfo()->getName());
break;
}
- // When VC encounters an anonymous type with no tag and no typedef,
- // it literally emits '<unnamed-tag>'.
- Out << "<unnamed-tag>";
+ if (TD->hasDeclaratorForAnonDecl()) {
+ // Anonymous types with no tag or typedef get the name of their
+ // declarator mangled in.
+ llvm::SmallString<64> Name("<unnamed-type-");
+ Name += TD->getDeclaratorForAnonDecl()->getName();
+ Name += ">";
+ mangleSourceName(Name.str());
+ } else {
+ // Anonymous types with no tag, no typedef, or declarator get
+ // '<unnamed-tag>'.
+ mangleSourceName("<unnamed-tag>");
+ }
break;
}
@@ -495,9 +562,9 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// use the type we were given.
mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
else
- // Otherwise, use the complete destructor name. This is relevant if a
+ // Otherwise, use the base destructor name. This is relevant if a
// class with a destructor is declared within a destructor.
- mangleCXXDtorType(Dtor_Complete);
+ mangleCXXDtorType(Dtor_Base);
break;
case DeclarationName::CXXConversionFunctionName:
@@ -538,9 +605,20 @@ void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC,
return;
if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
- Context.mangleBlock(BD, Out);
+ DiagnosticsEngine Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "cannot mangle a local inside this block yet");
+ Diags.Report(BD->getLocation(), DiagID);
+
+ // FIXME: This is completely, utterly, wrong; see ItaniumMangle
+ // for how this should be done.
+ Out << "__block_invoke" << Context.getBlockId(BD, false);
Out << '@';
return manglePostfix(DC->getParent(), NoFunction);
+ } else if (isa<CapturedDecl>(DC)) {
+ // Skip CapturedDecl context.
+ manglePostfix(DC->getParent(), NoFunction);
+ return;
}
if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)))
@@ -556,18 +634,19 @@ void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC,
}
void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
+ // Microsoft uses the names on the case labels for these dtor variants. Clang
+ // uses the Itanium terminology internally. Everything in this ABI delegates
+ // towards the base dtor.
switch (T) {
- case Dtor_Deleting:
- Out << "?_G";
- return;
- case Dtor_Base:
- // FIXME: We should be asked to mangle base dtors.
- // However, fixing this would require larger changes to the CodeGenModule.
- // Please put llvm_unreachable here when CGM is changed.
- // For now, just mangle a base dtor the same way as a complete dtor...
- case Dtor_Complete:
- Out << "?1";
- return;
+ // <operator-name> ::= ?1 # destructor
+ case Dtor_Base: Out << "?1"; return;
+ // <operator-name> ::= ?_D # vbase destructor
+ case Dtor_Complete: Out << "?_D"; return;
+ // <operator-name> ::= ?_G # scalar deleting destructor
+ case Dtor_Deleting: Out << "?_G"; return;
+ // <operator-name> ::= ?_E # vector deleting destructor
+ // FIXME: Add a vector deleting dtor type. It goes in the vtable, so we need
+ // it.
}
llvm_unreachable("Unsupported dtor type?");
}
@@ -704,17 +783,16 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
}
}
-void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
+void MicrosoftCXXNameMangler::mangleSourceName(StringRef Name) {
// <source name> ::= <identifier> @
- std::string key = II->getNameStart();
BackRefMap::iterator Found;
if (UseNameBackReferences)
- Found = NameBackReferences.find(key);
+ Found = NameBackReferences.find(Name);
if (!UseNameBackReferences || Found == NameBackReferences.end()) {
- Out << II->getName() << '@';
+ Out << Name << '@';
if (UseNameBackReferences && NameBackReferences.size() < 10) {
size_t Size = NameBackReferences.size();
- NameBackReferences[key] = Size;
+ NameBackReferences[Name] = Size;
}
} else {
Out << Found->second;
@@ -756,7 +834,7 @@ void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) {
// functions. You could have a method baz of class C inside a function bar
// inside a function foo, like so:
// ?baz@C@?3??bar@?1??foo@@YAXXZ@YAXXZ@QAEXXZ
- int NestLevel = getLocalNestingLevel(FD);
+ unsigned NestLevel = getLocalNestingLevel(FD);
Out << '?';
mangleNumber(NestLevel);
Out << '?';
@@ -800,7 +878,7 @@ MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
if (IsBoolean && Value.getBoolValue())
mangleNumber(1);
else
- mangleNumber(Value);
+ mangleNumber(Value.getSExtValue());
}
void
@@ -812,6 +890,33 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
return;
}
+ const CXXUuidofExpr *UE = 0;
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (UO->getOpcode() == UO_AddrOf)
+ UE = dyn_cast<CXXUuidofExpr>(UO->getSubExpr());
+ } else
+ UE = dyn_cast<CXXUuidofExpr>(E);
+
+ if (UE) {
+ // This CXXUuidofExpr is mangled as-if it were actually a VarDecl from
+ // const __s_GUID _GUID_{lower case UUID with underscores}
+ StringRef Uuid = UE->getUuidAsStringRef(Context.getASTContext());
+ std::string Name = "_GUID_" + Uuid.lower();
+ std::replace(Name.begin(), Name.end(), '-', '_');
+
+ // If we had to peek through an address-of operator, treat this like we are
+ // dealing with a pointer type. Otherwise, treat it like a const reference.
+ //
+ // N.B. This matches up with the handling of TemplateArgument::Declaration
+ // in mangleTemplateArg
+ if (UE == E)
+ Out << "$E?";
+ else
+ Out << "$1?";
+ Out << Name << "@@3U__s_GUID@@B";
+ return;
+ }
+
// As bad as this diagnostic is, it's better than crashing.
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
@@ -827,44 +932,51 @@ MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD,
unsigned NumTemplateArgs = TemplateArgs.size();
for (unsigned i = 0; i < NumTemplateArgs; ++i) {
const TemplateArgument &TA = TemplateArgs[i];
- switch (TA.getKind()) {
- case TemplateArgument::Null:
- llvm_unreachable("Can't mangle null template arguments!");
- case TemplateArgument::Type: {
- QualType T = TA.getAsType();
- mangleType(T, SourceRange(), QMM_Escape);
- break;
- }
- case TemplateArgument::Declaration:
- mangle(cast<NamedDecl>(TA.getAsDecl()), "$1?");
- break;
- case TemplateArgument::Integral:
- mangleIntegerLiteral(TA.getAsIntegral(),
- TA.getIntegralType()->isBooleanType());
- break;
- case TemplateArgument::Expression:
- mangleExpression(TA.getAsExpr());
- break;
- case TemplateArgument::Template:
- case TemplateArgument::TemplateExpansion:
- case TemplateArgument::NullPtr:
- case TemplateArgument::Pack: {
- // Issue a diagnostic.
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle template argument %0 of kind %select{ERROR|ERROR|"
- "pointer/reference|nullptr|integral|template|template pack expansion|"
- "ERROR|parameter pack}1 yet");
- Diags.Report(TD->getLocation(), DiagID)
- << i + 1
- << TA.getKind()
- << TD->getSourceRange();
- }
- }
+ mangleTemplateArg(TD, TA);
}
Out << '@';
}
+void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD,
+ const TemplateArgument &TA) {
+ switch (TA.getKind()) {
+ case TemplateArgument::Null:
+ llvm_unreachable("Can't mangle null template arguments!");
+ case TemplateArgument::TemplateExpansion:
+ llvm_unreachable("Can't mangle template expansion arguments!");
+ case TemplateArgument::Type: {
+ QualType T = TA.getAsType();
+ mangleType(T, SourceRange(), QMM_Escape);
+ break;
+ }
+ case TemplateArgument::Declaration: {
+ const NamedDecl *ND = cast<NamedDecl>(TA.getAsDecl());
+ mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?");
+ break;
+ }
+ case TemplateArgument::Integral:
+ mangleIntegerLiteral(TA.getAsIntegral(),
+ TA.getIntegralType()->isBooleanType());
+ break;
+ case TemplateArgument::NullPtr:
+ Out << "$0A@";
+ break;
+ case TemplateArgument::Expression:
+ mangleExpression(TA.getAsExpr());
+ break;
+ case TemplateArgument::Pack:
+ // Unlike Itanium, there is no character code to indicate an argument pack.
+ for (TemplateArgument::pack_iterator I = TA.pack_begin(), E = TA.pack_end();
+ I != E; ++I)
+ mangleTemplateArg(TD, *I);
+ break;
+ case TemplateArgument::Template:
+ mangleType(cast<TagDecl>(
+ TA.getAsTemplate().getAsTemplateDecl()->getTemplatedDecl()));
+ break;
+ }
+}
+
void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
bool IsMember) {
// <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers>
@@ -921,6 +1033,7 @@ void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
// ::= 5 # not really based
bool HasConst = Quals.hasConst(),
HasVolatile = Quals.hasVolatile();
+
if (!IsMember) {
if (HasConst && HasVolatile) {
Out << 'D';
@@ -966,20 +1079,32 @@ void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) {
void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
SourceRange Range) {
- void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr();
+ // MSVC will backreference two canonically equivalent types that have slightly
+ // different manglings when mangled alone.
+
+ // Decayed types do not match up with non-decayed versions of the same type.
+ //
+ // e.g.
+ // void (*x)(void) will not form a backreference with void x(void)
+ void *TypePtr;
+ if (const DecayedType *DT = T->getAs<DecayedType>()) {
+ TypePtr = DT->getOriginalType().getCanonicalType().getAsOpaquePtr();
+ // If the original parameter was textually written as an array,
+ // instead treat the decayed parameter like it's const.
+ //
+ // e.g.
+ // int [] -> int * const
+ if (DT->getOriginalType()->isArrayType())
+ T = T.withConst();
+ } else
+ TypePtr = T.getCanonicalType().getAsOpaquePtr();
+
ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr);
if (Found == TypeBackReferences.end()) {
size_t OutSizeBefore = Out.GetNumBytesInBuffer();
- if (const ArrayType *AT = getASTContext().getAsArrayType(T)) {
- mangleDecayedArrayType(AT, false);
- } else if (const FunctionType *FT = T->getAs<FunctionType>()) {
- Out << "P6";
- mangleFunctionType(FT, 0, false, false);
- } else {
- mangleType(T, Range, QMM_Drop);
- }
+ mangleType(T, Range, QMM_Drop);
// See if it's worth creating a back reference.
// Only types longer than 1 character are considered
@@ -996,16 +1121,18 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T,
void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
QualifierMangleMode QMM) {
- // Only operate on the canonical type!
- T = getASTContext().getCanonicalType(T);
+ // Don't use the canonical types. MSVC includes things like 'const' on
+ // pointer arguments to function pointers that canonicalization strips away.
+ T = T.getDesugaredType(getASTContext());
Qualifiers Quals = T.getLocalQualifiers();
-
- if (const ArrayType *AT = dyn_cast<ArrayType>(T)) {
+ if (const ArrayType *AT = getASTContext().getAsArrayType(T)) {
+ // If there were any Quals, getAsArrayType() pushed them onto the array
+ // element type.
if (QMM == QMM_Mangle)
Out << 'A';
else if (QMM == QMM_Escape || QMM == QMM_Result)
Out << "$$B";
- mangleArrayType(AT, Quals);
+ mangleArrayType(AT);
return;
}
@@ -1018,7 +1145,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range,
case QMM_Mangle:
if (const FunctionType *FT = dyn_cast<FunctionType>(T)) {
Out << '6';
- mangleFunctionType(FT, 0, false, false);
+ mangleFunctionType(FT);
return;
}
mangleQualifiers(Quals, false);
@@ -1151,7 +1278,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T,
// structor type.
// FIXME: This may not be lambda-friendly.
Out << "$$A6";
- mangleFunctionType(T, NULL, false, false);
+ mangleFunctionType(T);
}
void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T,
SourceRange) {
@@ -1160,18 +1287,31 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T,
void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
const FunctionDecl *D,
- bool IsStructor,
- bool IsInstMethod) {
+ bool ForceInstMethod) {
// <function-type> ::= <this-cvr-qualifiers> <calling-convention>
// <return-type> <argument-list> <throw-spec>
const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
+ SourceRange Range;
+ if (D) Range = D->getSourceRange();
+
+ bool IsStructor = false, IsInstMethod = ForceInstMethod;
+ if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(D)) {
+ if (MD->isInstance())
+ IsInstMethod = true;
+ if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD))
+ IsStructor = true;
+ }
+
// If this is a C++ instance method, mangle the CVR qualifiers for the
// this pointer.
- if (IsInstMethod)
+ if (IsInstMethod) {
+ if (PointersAre64Bit)
+ Out << 'E';
mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false);
+ }
- mangleCallingConvention(T, IsInstMethod);
+ mangleCallingConvention(T);
// <return-type> ::= <type>
// ::= @ # structors (they have no declared return type)
@@ -1182,12 +1322,15 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
// However, the FunctionType generated has 0 arguments.
// FIXME: This is a temporary hack.
// Maybe should fix the FunctionType creation instead?
- Out << "PAXI@Z";
+ Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z");
return;
}
Out << '@';
} else {
- mangleType(Proto->getResultType(), SourceRange(), QMM_Result);
+ QualType ResultType = Proto->getResultType();
+ if (ResultType->isVoidType())
+ ResultType = ResultType.getUnqualifiedType();
+ mangleType(ResultType, Range, QMM_Result);
}
// <argument-list> ::= X # void
@@ -1196,23 +1339,11 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
Out << 'X';
} else {
- if (D) {
- // If we got a decl, use the type-as-written to make sure arrays
- // get mangled right. Note that we can't rely on the TSI
- // existing if (for example) the parameter was synthesized.
- for (FunctionDecl::param_const_iterator Parm = D->param_begin(),
- ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) {
- TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo();
- QualType Type = TSI ? TSI->getType() : (*Parm)->getType();
- mangleArgumentType(Type, (*Parm)->getSourceRange());
- }
- } else {
- // Happens for function pointer type arguments for example.
- for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
- ArgEnd = Proto->arg_type_end();
- Arg != ArgEnd; ++Arg)
- mangleArgumentType(*Arg, SourceRange());
- }
+ // Happens for function pointer type arguments for example.
+ for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+ ArgEnd = Proto->arg_type_end();
+ Arg != ArgEnd; ++Arg)
+ mangleArgumentType(*Arg, Range);
// <builtin-type> ::= Z # ellipsis
if (Proto->isVariadic())
Out << 'Z';
@@ -1224,35 +1355,34 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T,
}
void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
- // <function-class> ::= A # private: near
- // ::= B # private: far
- // ::= C # private: static near
- // ::= D # private: static far
- // ::= E # private: virtual near
- // ::= F # private: virtual far
- // ::= G # private: thunk near
- // ::= H # private: thunk far
- // ::= I # protected: near
- // ::= J # protected: far
- // ::= K # protected: static near
- // ::= L # protected: static far
- // ::= M # protected: virtual near
- // ::= N # protected: virtual far
- // ::= O # protected: thunk near
- // ::= P # protected: thunk far
- // ::= Q # public: near
- // ::= R # public: far
- // ::= S # public: static near
- // ::= T # public: static far
- // ::= U # public: virtual near
- // ::= V # public: virtual far
- // ::= W # public: thunk near
- // ::= X # public: thunk far
- // ::= Y # global near
- // ::= Z # global far
+ // <function-class> ::= <member-function> E? # E designates a 64-bit 'this'
+ // # pointer. in 64-bit mode *all*
+ // # 'this' pointers are 64-bit.
+ // ::= <global-function>
+ // <member-function> ::= A # private: near
+ // ::= B # private: far
+ // ::= C # private: static near
+ // ::= D # private: static far
+ // ::= E # private: virtual near
+ // ::= F # private: virtual far
+ // ::= I # protected: near
+ // ::= J # protected: far
+ // ::= K # protected: static near
+ // ::= L # protected: static far
+ // ::= M # protected: virtual near
+ // ::= N # protected: virtual far
+ // ::= Q # public: near
+ // ::= R # public: far
+ // ::= S # public: static near
+ // ::= T # public: static far
+ // ::= U # public: virtual near
+ // ::= V # public: virtual far
+ // <global-function> ::= Y # global near
+ // ::= Z # global far
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
switch (MD->getAccess()) {
- default:
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
case AS_private:
if (MD->isStatic())
Out << 'C';
@@ -1280,8 +1410,7 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) {
} else
Out << 'Y';
}
-void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
- bool IsInstMethod) {
+void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) {
// <calling-convention> ::= A # __cdecl
// ::= B # __export __cdecl
// ::= C # __pascal
@@ -1298,20 +1427,11 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
// that they could be in a DLL and somebody from another module could call
// them.)
CallingConv CC = T->getCallConv();
- if (CC == CC_Default) {
- if (IsInstMethod) {
- const FunctionProtoType *FPT =
- T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>();
- bool isVariadic = FPT->isVariadic();
- CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic);
- } else {
- CC = CC_C;
- }
- }
switch (CC) {
default:
llvm_unreachable("Unsupported CC for mangling");
- case CC_Default:
+ case CC_X86_64Win64:
+ case CC_X86_64SysV:
case CC_C: Out << 'A'; break;
case CC_X86Pascal: Out << 'C'; break;
case CC_X86ThisCall: Out << 'E'; break;
@@ -1347,13 +1467,13 @@ void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T,
// <class-type> ::= V <name>
// <enum-type> ::= W <size> <name>
void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) {
- mangleType(cast<TagType>(T));
+ mangleType(cast<TagType>(T)->getDecl());
}
void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) {
- mangleType(cast<TagType>(T));
+ mangleType(cast<TagType>(T)->getDecl());
}
-void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
- switch (T->getDecl()->getTagKind()) {
+void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) {
+ switch (TD->getTagKind()) {
case TTK_Union:
Out << 'T';
break;
@@ -1367,30 +1487,23 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
case TTK_Enum:
Out << 'W';
Out << getASTContext().getTypeSizeInChars(
- cast<EnumDecl>(T->getDecl())->getIntegerType()).getQuantity();
+ cast<EnumDecl>(TD)->getIntegerType()).getQuantity();
break;
}
- mangleName(T->getDecl());
+ mangleName(TD);
}
// <type> ::= <array-type>
// <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers>
// [Y <dimension-count> <dimension>+]
-// <element-type> # as global
-// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+]
-// <element-type> # as param
+// <element-type> # as global, E is never required
// It's supposed to be the other way around, but for some strange reason, it
// isn't. Today this behavior is retained for the sole purpose of backwards
// compatibility.
-void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T,
- bool IsGlobal) {
+void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T) {
// This isn't a recursive mangling, so now we have to do it all in this
// one call.
- if (IsGlobal) {
- manglePointerQualifiers(T->getElementType().getQualifiers());
- } else {
- Out << 'Q';
- }
+ manglePointerQualifiers(T->getElementType().getQualifiers());
mangleType(T->getElementType(), SourceRange());
}
void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T,
@@ -1409,8 +1522,7 @@ void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T,
SourceRange) {
llvm_unreachable("Should have been special cased");
}
-void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T,
- Qualifiers Quals) {
+void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) {
QualType ElementTy(T, 0);
SmallVector<llvm::APInt, 3> Dimensions;
for (;;) {
@@ -1449,8 +1561,7 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T,
mangleNumber(Dimensions.size());
for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim)
mangleNumber(Dimensions[Dim].getLimitedValue());
- mangleType(getASTContext().getQualifiedType(ElementTy.getTypePtr(), Quals),
- SourceRange(), QMM_Escape);
+ mangleType(ElementTy, SourceRange(), QMM_Escape);
}
// <type> ::= <pointer-to-member-type>
@@ -1462,8 +1573,10 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T,
if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) {
Out << '8';
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
- mangleFunctionType(FPT, NULL, false, true);
+ mangleFunctionType(FPT, 0, true);
} else {
+ if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
+ Out << 'E';
mangleQualifiers(PointeeType.getQualifiers(), true);
mangleName(T->getClass()->castAs<RecordType>()->getDecl());
mangleType(PointeeType, Range, QMM_Drop);
@@ -1490,32 +1603,43 @@ void MicrosoftCXXNameMangler::mangleType(
}
// <type> ::= <pointer-type>
-// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
+// <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
+// # the E is required for 64-bit non static pointers
void MicrosoftCXXNameMangler::mangleType(const PointerType *T,
SourceRange Range) {
QualType PointeeTy = T->getPointeeType();
+ if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
+ Out << 'E';
mangleType(PointeeTy, Range);
}
void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T,
SourceRange Range) {
// Object pointers never have qualifiers.
Out << 'A';
+ if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
+ Out << 'E';
mangleType(T->getPointeeType(), Range);
}
// <type> ::= <reference-type>
-// <reference-type> ::= A <cvr-qualifiers> <type>
+// <reference-type> ::= A E? <cvr-qualifiers> <type>
+// # the E is required for 64-bit non static lvalue references
void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T,
SourceRange Range) {
Out << 'A';
+ if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
+ Out << 'E';
mangleType(T->getPointeeType(), Range);
}
// <type> ::= <r-value-reference-type>
-// <r-value-reference-type> ::= $$Q <cvr-qualifiers> <type>
+// <r-value-reference-type> ::= $$Q E? <cvr-qualifiers> <type>
+// # the E is required for 64-bit non static rvalue references
void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T,
SourceRange Range) {
Out << "$$Q";
+ if (PointersAre64Bit && !T->getPointeeType()->isFunctionType())
+ Out << 'E';
mangleType(T->getPointeeType(), Range);
}
@@ -1598,16 +1722,12 @@ void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T,
Out << "_E";
QualType pointee = T->getPointeeType();
- mangleFunctionType(pointee->castAs<FunctionProtoType>(), NULL, false, false);
+ mangleFunctionType(pointee->castAs<FunctionProtoType>());
}
-void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T,
- SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this injected class name type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
+void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *,
+ SourceRange) {
+ llvm_unreachable("Cannot mangle injected class name type.");
}
void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T,
@@ -1700,8 +1820,8 @@ void MicrosoftCXXNameMangler::mangleType(const AtomicType *T,
<< Range;
}
-void MicrosoftMangleContext::mangleName(const NamedDecl *D,
- raw_ostream &Out) {
+void MicrosoftMangleContextImpl::mangleCXXName(const NamedDecl *D,
+ raw_ostream &Out) {
assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
"Invalid mangleName() call, argument is not a variable or function!");
assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
@@ -1714,85 +1834,265 @@ void MicrosoftMangleContext::mangleName(const NamedDecl *D,
MicrosoftCXXNameMangler Mangler(*this, Out);
return Mangler.mangle(D);
}
-void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD,
- const ThunkInfo &Thunk,
- raw_ostream &) {
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle thunk for this method yet");
- getDiags().Report(MD->getLocation(), DiagID);
+
+// <this-adjustment> ::= <no-adjustment> | <static-adjustment> |
+// <virtual-adjustment>
+// <no-adjustment> ::= A # private near
+// ::= B # private far
+// ::= I # protected near
+// ::= J # protected far
+// ::= Q # public near
+// ::= R # public far
+// <static-adjustment> ::= G <static-offset> # private near
+// ::= H <static-offset> # private far
+// ::= O <static-offset> # protected near
+// ::= P <static-offset> # protected far
+// ::= W <static-offset> # public near
+// ::= X <static-offset> # public far
+// <virtual-adjustment> ::= $0 <virtual-shift> <static-offset> # private near
+// ::= $1 <virtual-shift> <static-offset> # private far
+// ::= $2 <virtual-shift> <static-offset> # protected near
+// ::= $3 <virtual-shift> <static-offset> # protected far
+// ::= $4 <virtual-shift> <static-offset> # public near
+// ::= $5 <virtual-shift> <static-offset> # public far
+// <virtual-shift> ::= <vtordisp-shift> | <vtordispex-shift>
+// <vtordisp-shift> ::= <offset-to-vtordisp>
+// <vtordispex-shift> ::= <offset-to-vbptr> <vbase-offset-offset>
+// <offset-to-vtordisp>
+static void mangleThunkThisAdjustment(const CXXMethodDecl *MD,
+ const ThisAdjustment &Adjustment,
+ MicrosoftCXXNameMangler &Mangler,
+ raw_ostream &Out) {
+ if (!Adjustment.Virtual.isEmpty()) {
+ Out << '$';
+ char AccessSpec;
+ switch (MD->getAccess()) {
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
+ case AS_private:
+ AccessSpec = '0';
+ break;
+ case AS_protected:
+ AccessSpec = '2';
+ break;
+ case AS_public:
+ AccessSpec = '4';
+ }
+ if (Adjustment.Virtual.Microsoft.VBPtrOffset) {
+ Out << 'R' << AccessSpec;
+ Mangler.mangleNumber(
+ static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VBPtrOffset));
+ Mangler.mangleNumber(
+ static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VBOffsetOffset));
+ Mangler.mangleNumber(
+ static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VtordispOffset));
+ Mangler.mangleNumber(static_cast<uint32_t>(Adjustment.NonVirtual));
+ } else {
+ Out << AccessSpec;
+ Mangler.mangleNumber(
+ static_cast<uint32_t>(Adjustment.Virtual.Microsoft.VtordispOffset));
+ Mangler.mangleNumber(-static_cast<uint32_t>(Adjustment.NonVirtual));
+ }
+ } else if (Adjustment.NonVirtual != 0) {
+ switch (MD->getAccess()) {
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
+ case AS_private:
+ Out << 'G';
+ break;
+ case AS_protected:
+ Out << 'O';
+ break;
+ case AS_public:
+ Out << 'W';
+ }
+ Mangler.mangleNumber(-static_cast<uint32_t>(Adjustment.NonVirtual));
+ } else {
+ switch (MD->getAccess()) {
+ case AS_none:
+ llvm_unreachable("Unsupported access specifier");
+ case AS_private:
+ Out << 'A';
+ break;
+ case AS_protected:
+ Out << 'I';
+ break;
+ case AS_public:
+ Out << 'Q';
+ }
+ }
}
-void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
- CXXDtorType Type,
- const ThisAdjustment &,
- raw_ostream &) {
- unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle thunk for this destructor yet");
- getDiags().Report(DD->getLocation(), DiagID);
+
+void MicrosoftMangleContextImpl::mangleVirtualMemPtrThunk(
+ const CXXMethodDecl *MD, uint64_t OffsetInVFTable, raw_ostream &Out) {
+ bool Is64Bit = getASTContext().getTargetInfo().getPointerWidth(0) == 64;
+
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_9";
+ Mangler.mangleName(MD->getParent());
+ Mangler.getStream() << "$B";
+ Mangler.mangleNumber(OffsetInVFTable);
+ Mangler.getStream() << "A";
+ Mangler.getStream() << (Is64Bit ? "A" : "E");
}
-void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
+
+void MicrosoftMangleContextImpl::mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
raw_ostream &Out) {
- // <mangled-name> ::= ? <operator-name> <class-name> <storage-class>
- // <cvr-qualifiers> [<name>] @
- // <operator-name> ::= _7 # vftable
- // ::= _8 # vbtable
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Out << "\01?";
+ Mangler.mangleName(MD);
+ mangleThunkThisAdjustment(MD, Thunk.This, Mangler, Out);
+ if (!Thunk.Return.isEmpty())
+ assert(Thunk.Method != 0 && "Thunk info should hold the overridee decl");
+
+ const CXXMethodDecl *DeclForFPT = Thunk.Method ? Thunk.Method : MD;
+ Mangler.mangleFunctionType(
+ DeclForFPT->getType()->castAs<FunctionProtoType>(), MD);
+}
+
+void MicrosoftMangleContextImpl::mangleCXXDtorThunk(
+ const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &Adjustment, raw_ostream &Out) {
+ // FIXME: Actually, the dtor thunk should be emitted for vector deleting
+ // dtors rather than scalar deleting dtors. Just use the vector deleting dtor
+ // mangling manually until we support both deleting dtor types.
+ assert(Type == Dtor_Deleting);
+ MicrosoftCXXNameMangler Mangler(*this, Out, DD, Type);
+ Out << "\01??_E";
+ Mangler.mangleName(DD->getParent());
+ mangleThunkThisAdjustment(DD, Adjustment, Mangler, Out);
+ Mangler.mangleFunctionType(DD->getType()->castAs<FunctionProtoType>(), DD);
+}
+
+void MicrosoftMangleContextImpl::mangleCXXVFTable(
+ const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out) {
+ // <mangled-name> ::= ?_7 <class-name> <storage-class>
+ // <cvr-qualifiers> [<name>] @
// NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
- // is always '6' for vftables and '7' for vbtables. (The difference is
- // beyond me.)
- // TODO: vbtables.
+ // is always '6' for vftables.
MicrosoftCXXNameMangler Mangler(*this, Out);
Mangler.getStream() << "\01??_7";
- Mangler.mangleName(RD);
- Mangler.getStream() << "6B";
- // TODO: If the class has more than one vtable, mangle in the class it came
- // from.
+ Mangler.mangleName(Derived);
+ Mangler.getStream() << "6B"; // '6' for vftable, 'B' for const.
+ for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(),
+ E = BasePath.end();
+ I != E; ++I) {
+ Mangler.mangleName(*I);
+ }
Mangler.getStream() << '@';
}
-void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
- raw_ostream &) {
- llvm_unreachable("The MS C++ ABI does not have virtual table tables!");
-}
-void MicrosoftMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD,
- int64_t Offset,
- const CXXRecordDecl *Type,
- raw_ostream &) {
- llvm_unreachable("The MS C++ ABI does not have constructor vtables!");
+
+void MicrosoftMangleContextImpl::mangleCXXVBTable(
+ const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath,
+ raw_ostream &Out) {
+ // <mangled-name> ::= ?_8 <class-name> <storage-class>
+ // <cvr-qualifiers> [<name>] @
+ // NOTE: <cvr-qualifiers> here is always 'B' (const). <storage-class>
+ // is always '7' for vbtables.
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??_8";
+ Mangler.mangleName(Derived);
+ Mangler.getStream() << "7B"; // '7' for vbtable, 'B' for const.
+ for (ArrayRef<const CXXRecordDecl *>::iterator I = BasePath.begin(),
+ E = BasePath.end();
+ I != E; ++I) {
+ Mangler.mangleName(*I);
+ }
+ Mangler.getStream() << '@';
}
-void MicrosoftMangleContext::mangleCXXRTTI(QualType T,
- raw_ostream &) {
+
+void MicrosoftMangleContextImpl::mangleCXXRTTI(QualType T, raw_ostream &) {
// FIXME: Give a location...
unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle RTTI descriptors for type %0 yet");
getDiags().Report(DiagID)
<< T.getBaseTypeIdentifier();
}
-void MicrosoftMangleContext::mangleCXXRTTIName(QualType T,
- raw_ostream &) {
+
+void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T, raw_ostream &) {
// FIXME: Give a location...
unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle the name of type %0 into RTTI descriptors yet");
getDiags().Report(DiagID)
<< T.getBaseTypeIdentifier();
}
-void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
- CXXCtorType Type,
- raw_ostream & Out) {
+
+void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
+ // This is just a made up unique string for the purposes of tbaa. undname
+ // does *not* know how to demangle it.
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << '?';
+ Mangler.mangleType(T, SourceRange());
+}
+
+void MicrosoftMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ raw_ostream &Out) {
MicrosoftCXXNameMangler mangler(*this, Out);
mangler.mangle(D);
}
-void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
- CXXDtorType Type,
- raw_ostream & Out) {
+
+void MicrosoftMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D,
+ CXXDtorType Type,
+ raw_ostream &Out) {
MicrosoftCXXNameMangler mangler(*this, Out, D, Type);
mangler.mangle(D);
}
-void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD,
- raw_ostream &) {
+
+void MicrosoftMangleContextImpl::mangleReferenceTemporary(const VarDecl *VD,
+ raw_ostream &) {
unsigned DiagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error,
"cannot mangle this reference temporary yet");
getDiags().Report(VD->getLocation(), DiagID);
}
-MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context,
- DiagnosticsEngine &Diags) {
- return new MicrosoftMangleContext(Context, Diags);
+void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD,
+ raw_ostream &Out) {
+ // <guard-name> ::= ?_B <postfix> @51
+ // ::= ?$S <guard-num> @ <postfix> @4IA
+
+ // The first mangling is what MSVC uses to guard static locals in inline
+ // functions. It uses a different mangling in external functions to support
+ // guarding more than 32 variables. MSVC rejects inline functions with more
+ // than 32 static locals. We don't fully implement the second mangling
+ // because those guards are not externally visible, and instead use LLVM's
+ // default renaming when creating a new guard variable.
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+
+ bool Visible = VD->isExternallyVisible();
+ // <operator-name> ::= ?_B # local static guard
+ Mangler.getStream() << (Visible ? "\01??_B" : "\01?$S1@");
+ Mangler.manglePostfix(VD->getDeclContext());
+ Mangler.getStream() << (Visible ? "@51" : "@4IA");
+}
+
+void MicrosoftMangleContextImpl::mangleInitFiniStub(const VarDecl *D,
+ raw_ostream &Out,
+ char CharCode) {
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "\01??__" << CharCode;
+ Mangler.mangleName(D);
+ // This is the function class mangling. These stubs are global, non-variadic,
+ // cdecl functions that return void and take no args.
+ Mangler.getStream() << "YAXXZ";
+}
+
+void MicrosoftMangleContextImpl::mangleDynamicInitializer(const VarDecl *D,
+ raw_ostream &Out) {
+ // <initializer-name> ::= ?__E <name> YAXXZ
+ mangleInitFiniStub(D, Out, 'E');
+}
+
+void
+MicrosoftMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D,
+ raw_ostream &Out) {
+ // <destructor-name> ::= ?__F <name> YAXXZ
+ mangleInitFiniStub(D, Out, 'F');
+}
+
+MicrosoftMangleContext *
+MicrosoftMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
+ return new MicrosoftMangleContextImpl(Context, Diags);
}
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 79cc21a..b03c4e0 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -566,8 +566,7 @@ void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context,
for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix())
Stack.push_back(NNS);
while (!Stack.empty()) {
- NestedNameSpecifier *NNS = Stack.back();
- Stack.pop_back();
+ NestedNameSpecifier *NNS = Stack.pop_back_val();
switch (NNS->getKind()) {
case NestedNameSpecifier::Identifier:
case NestedNameSpecifier::Namespace:
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index 1135928..ff44d93 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/ParentMap.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "llvm/ADT/DenseMap.h"
using namespace clang;
@@ -33,6 +34,11 @@ static void BuildParentMap(MapTy& M, Stmt* S,
assert(OVMode == OV_Transparent && "Should not appear alongside OVEs");
PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S);
+ // If we are rebuilding the map, clear out any existing state.
+ if (M[POE->getSyntacticForm()])
+ for (Stmt::child_range I = S->children(); I; ++I)
+ M[*I] = 0;
+
M[POE->getSyntacticForm()] = S;
BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent);
@@ -62,13 +68,19 @@ static void BuildParentMap(MapTy& M, Stmt* S,
break;
}
- case Stmt::OpaqueValueExprClass:
- if (OVMode == OV_Transparent) {
- OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S);
+ case Stmt::OpaqueValueExprClass: {
+ // FIXME: This isn't correct; it assumes that multiple OpaqueValueExprs
+ // share a single source expression, but in the AST a single
+ // OpaqueValueExpr is shared among multiple parent expressions.
+ // The right thing to do is to give the OpaqueValueExpr its syntactic
+ // parent, then not reassign that when traversing the semantic expressions.
+ OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S);
+ if (OVMode == OV_Transparent || !M[OVE->getSourceExpr()]) {
M[OVE->getSourceExpr()] = S;
BuildParentMap(M, OVE->getSourceExpr(), OV_Transparent);
}
break;
+ }
default:
for (Stmt::child_range I = S->children(); I; ++I) {
if (*I) {
@@ -98,6 +110,13 @@ void ParentMap::addStmt(Stmt* S) {
}
}
+void ParentMap::setParent(const Stmt *S, const Stmt *Parent) {
+ assert(S);
+ assert(Parent);
+ MapTy *M = reinterpret_cast<MapTy *>(Impl);
+ M->insert(std::make_pair(const_cast<Stmt *>(S), const_cast<Stmt *>(Parent)));
+}
+
Stmt* ParentMap::getParent(Stmt* S) const {
MapTy* M = (MapTy*) Impl;
MapTy::iterator I = M->find(S);
@@ -139,8 +158,9 @@ bool ParentMap::isConsumedExpr(Expr* E) const {
Stmt *P = getParent(E);
Stmt *DirectChild = E;
- // Ignore parents that are parentheses or casts.
- while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P))) {
+ // Ignore parents that don't guarantee consumption.
+ while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P) ||
+ isa<ExprWithCleanups>(P))) {
DirectChild = P;
P = getParent(P);
}
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp
index 92b96dc..1fa7cea 100644
--- a/lib/AST/RawCommentList.cpp
+++ b/lib/AST/RawCommentList.cpp
@@ -68,8 +68,7 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR,
bool Merged, bool ParseAllComments) :
Range(SR), RawTextValid(false), BriefTextValid(false),
IsAttached(false), IsAlmostTrailingComment(false),
- ParseAllComments(ParseAllComments),
- BeginLineValid(false), EndLineValid(false) {
+ ParseAllComments(ParseAllComments) {
// Extract raw comment text, if possible.
if (SR.getBegin() == SR.getEnd() || getRawText(SourceMgr).empty()) {
Kind = RCK_Invalid;
@@ -90,26 +89,6 @@ RawComment::RawComment(const SourceManager &SourceMgr, SourceRange SR,
}
}
-unsigned RawComment::getBeginLine(const SourceManager &SM) const {
- if (BeginLineValid)
- return BeginLine;
-
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Range.getBegin());
- BeginLine = SM.getLineNumber(LocInfo.first, LocInfo.second);
- BeginLineValid = true;
- return BeginLine;
-}
-
-unsigned RawComment::getEndLine(const SourceManager &SM) const {
- if (EndLineValid)
- return EndLine;
-
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Range.getEnd());
- EndLine = SM.getLineNumber(LocInfo.first, LocInfo.second);
- EndLineValid = true;
- return EndLine;
-}
-
StringRef RawComment::getRawTextSlow(const SourceManager &SourceMgr) const {
FileID BeginFileID;
FileID EndFileID;
@@ -184,13 +163,9 @@ comments::FullComment *RawComment::parse(const ASTContext &Context,
return P.parseFullComment();
}
-namespace {
-bool containsOnlyWhitespace(StringRef Str) {
- return Str.find_first_not_of(" \t\f\v\r\n") == StringRef::npos;
-}
-
-bool onlyWhitespaceBetween(SourceManager &SM,
- SourceLocation Loc1, SourceLocation Loc2) {
+static bool onlyWhitespaceBetween(SourceManager &SM,
+ SourceLocation Loc1, SourceLocation Loc2,
+ unsigned MaxNewlinesAllowed) {
std::pair<FileID, unsigned> Loc1Info = SM.getDecomposedLoc(Loc1);
std::pair<FileID, unsigned> Loc2Info = SM.getDecomposedLoc(Loc2);
@@ -203,10 +178,38 @@ bool onlyWhitespaceBetween(SourceManager &SM,
if (Invalid)
return false;
- StringRef Text(Buffer + Loc1Info.second, Loc2Info.second - Loc1Info.second);
- return containsOnlyWhitespace(Text);
+ unsigned NumNewlines = 0;
+ assert(Loc1Info.second <= Loc2Info.second && "Loc1 after Loc2!");
+ // Look for non-whitespace characters and remember any newlines seen.
+ for (unsigned I = Loc1Info.second; I != Loc2Info.second; ++I) {
+ switch (Buffer[I]) {
+ default:
+ return false;
+ case ' ':
+ case '\t':
+ case '\f':
+ case '\v':
+ break;
+ case '\r':
+ case '\n':
+ ++NumNewlines;
+
+ // Check if we have found more than the maximum allowed number of
+ // newlines.
+ if (NumNewlines > MaxNewlinesAllowed)
+ return false;
+
+ // Collapse \r\n and \n\r into a single newline.
+ if (I + 1 != Loc2Info.second &&
+ (Buffer[I + 1] == '\n' || Buffer[I + 1] == '\r') &&
+ Buffer[I] != Buffer[I + 1])
+ ++I;
+ break;
+ }
+ }
+
+ return true;
}
-} // unnamed namespace
void RawCommentList::addComment(const RawComment &RC,
llvm::BumpPtrAllocator &Allocator) {
@@ -215,23 +218,13 @@ void RawCommentList::addComment(const RawComment &RC,
// Check if the comments are not in source order.
while (!Comments.empty() &&
- !SourceMgr.isBeforeInTranslationUnit(
- Comments.back()->getSourceRange().getBegin(),
- RC.getSourceRange().getBegin())) {
+ !SourceMgr.isBeforeInTranslationUnit(Comments.back()->getLocStart(),
+ RC.getLocStart())) {
// If they are, just pop a few last comments that don't fit.
// This happens if an \#include directive contains comments.
Comments.pop_back();
}
- if (OnlyWhitespaceSeen) {
- if (!onlyWhitespaceBetween(SourceMgr,
- PrevCommentEndLoc,
- RC.getSourceRange().getBegin()))
- OnlyWhitespaceSeen = false;
- }
-
- PrevCommentEndLoc = RC.getSourceRange().getEnd();
-
// Ordinary comments are not interesting for us.
if (RC.isOrdinary())
return;
@@ -240,7 +233,6 @@ void RawCommentList::addComment(const RawComment &RC,
// anything to merge it with).
if (Comments.empty()) {
Comments.push_back(new (Allocator) RawComment(RC));
- OnlyWhitespaceSeen = true;
return;
}
@@ -250,21 +242,13 @@ void RawCommentList::addComment(const RawComment &RC,
// Merge comments only if there is only whitespace between them.
// Can't merge trailing and non-trailing comments.
// Merge comments if they are on same or consecutive lines.
- bool Merged = false;
- if (OnlyWhitespaceSeen &&
- (C1.isTrailingComment() == C2.isTrailingComment())) {
- unsigned C1EndLine = C1.getEndLine(SourceMgr);
- unsigned C2BeginLine = C2.getBeginLine(SourceMgr);
- if (C1EndLine + 1 == C2BeginLine || C1EndLine == C2BeginLine) {
- SourceRange MergedRange(C1.getSourceRange().getBegin(),
- C2.getSourceRange().getEnd());
- *Comments.back() = RawComment(SourceMgr, MergedRange, true,
- RC.isParseAllComments());
- Merged = true;
- }
- }
- if (!Merged)
+ if (C1.isTrailingComment() == C2.isTrailingComment() &&
+ onlyWhitespaceBetween(SourceMgr, C1.getLocEnd(), C2.getLocStart(),
+ /*MaxNewlinesAllowed=*/1)) {
+ SourceRange MergedRange(C1.getLocStart(), C2.getLocEnd());
+ *Comments.back() = RawComment(SourceMgr, MergedRange, true,
+ RC.isParseAllComments());
+ } else {
Comments.push_back(new (Allocator) RawComment(RC));
-
- OnlyWhitespaceSeen = true;
+ }
}
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index f6cfe63..71e44ec 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -43,7 +43,8 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
// Constructor for C++ records.
ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CharUnits size, CharUnits alignment,
- bool hasOwnVFPtr, CharUnits vbptroffset,
+ bool hasOwnVFPtr, bool hasExtendableVFPtr,
+ CharUnits vbptroffset,
CharUnits datasize,
const uint64_t *fieldoffsets,
unsigned fieldcount,
@@ -52,6 +53,8 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CharUnits SizeOfLargestEmptySubobject,
const CXXRecordDecl *PrimaryBase,
bool IsPrimaryBaseVirtual,
+ const CXXRecordDecl *BaseSharingVBPtr,
+ bool AlignAfterVBases,
const BaseOffsetsMapTy& BaseOffsets,
const VBaseOffsetsMapTy& VBaseOffsets)
: Size(size), DataSize(datasize), Alignment(alignment), FieldOffsets(0),
@@ -71,6 +74,10 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
CXXInfo->VBaseOffsets = VBaseOffsets;
CXXInfo->HasOwnVFPtr = hasOwnVFPtr;
CXXInfo->VBPtrOffset = vbptroffset;
+ CXXInfo->HasExtendableVFPtr = hasExtendableVFPtr;
+ CXXInfo->BaseSharingVBPtr = BaseSharingVBPtr;
+ CXXInfo->AlignAfterVBases = AlignAfterVBases;
+
#ifndef NDEBUG
if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 42c3ba3..4390e66 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -211,7 +211,7 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD,
if (!RD->isEmpty())
return;
- // If we have empty structures inside an union, we can assign both
+ // If we have empty structures inside a union, we can assign both
// the same offset. Just avoid pushing them twice in the list.
ClassVectorTy& Classes = EmptyClassOffsets[Offset];
if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end())
@@ -573,10 +573,14 @@ protected:
unsigned IsMsStruct : 1;
- /// UnfilledBitsInLastByte - If the last field laid out was a bitfield,
- /// this contains the number of bits in the last byte that can be used for
- /// an adjacent bitfield if necessary.
- unsigned char UnfilledBitsInLastByte;
+ /// UnfilledBitsInLastUnit - If the last field laid out was a bitfield,
+ /// this contains the number of bits in the last unit that can be used for
+ /// an adjacent bitfield if necessary. The unit in question is usually
+ /// a byte, but larger units are used if IsMsStruct.
+ unsigned char UnfilledBitsInLastUnit;
+ /// LastBitfieldTypeSize - If IsMsStruct, represents the size of the type
+ /// of the previous field if it was a bitfield.
+ unsigned char LastBitfieldTypeSize;
/// MaxFieldAlignment - The maximum allowed field alignment. This is set by
/// #pragma pack.
@@ -588,8 +592,6 @@ protected:
CharUnits NonVirtualSize;
CharUnits NonVirtualAlignment;
- FieldDecl *ZeroLengthBitfield;
-
/// PrimaryBase - the primary base class (if one exists) of the class
/// we're laying out.
const CXXRecordDecl *PrimaryBase;
@@ -602,9 +604,6 @@ protected:
/// pointer, as opposed to inheriting one from a primary base class.
bool HasOwnVFPtr;
- /// VBPtrOffset - Virtual base table offset. Only for MS layout.
- CharUnits VBPtrOffset;
-
typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
/// Bases - base classes and their offsets in the record.
@@ -646,13 +645,12 @@ protected:
Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()),
ExternalLayout(false), InferAlignment(false),
Packed(false), IsUnion(false), IsMac68kAlign(false), IsMsStruct(false),
- UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
+ UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0),
+ MaxFieldAlignment(CharUnits::Zero()),
DataSize(0), NonVirtualSize(CharUnits::Zero()),
NonVirtualAlignment(CharUnits::One()),
- ZeroLengthBitfield(0), PrimaryBase(0),
- PrimaryBaseIsVirtual(false),
+ PrimaryBase(0), PrimaryBaseIsVirtual(false),
HasOwnVFPtr(false),
- VBPtrOffset(CharUnits::fromQuantity(-1)),
FirstNearlyEmptyVBase(0) { }
/// Reset this RecordLayoutBuilder to a fresh state, using the given
@@ -680,12 +678,6 @@ protected:
return Context.getTargetInfo().getCXXABI();
}
- bool isMicrosoftCXXABI() const {
- return getCXXABI().isMicrosoft();
- }
-
- void MSLayoutVirtualBases(const CXXRecordDecl *RD);
-
/// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects.
llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator;
@@ -727,21 +719,12 @@ protected:
void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
CharUnits Offset);
- bool needsVFTable(const CXXRecordDecl *RD) const;
- bool hasNewVirtualFunction(const CXXRecordDecl *RD,
- bool IgnoreDestructor = false) const;
- bool isPossiblePrimaryBase(const CXXRecordDecl *Base) const;
-
- void computeVtordisps(const CXXRecordDecl *RD,
- ClassSetTy &VtordispVBases);
-
/// LayoutVirtualBases - Lays out all the virtual bases.
void LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass);
/// LayoutVirtualBase - Lays out a single virtual base.
- void LayoutVirtualBase(const BaseSubobjectInfo *Base,
- bool IsVtordispNeed = false);
+ void LayoutVirtualBase(const BaseSubobjectInfo *Base);
/// LayoutBase - Will lay out a base and return the offset where it was
/// placed, in chars.
@@ -851,7 +834,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (isPossiblePrimaryBase(Base)) {
+ if (Base->isDynamicClass()) {
// We found it.
PrimaryBase = Base;
PrimaryBaseIsVirtual = false;
@@ -859,12 +842,6 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
}
}
- // The Microsoft ABI doesn't have primary virtual bases.
- if (isMicrosoftCXXABI()) {
- assert(!PrimaryBase && "Should not get here with a primary base!");
- return;
- }
-
// Under the Itanium ABI, if there is no non-virtual primary base class,
// try to compute the primary virtual base. The primary virtual base is
// the first nearly empty virtual base that is not an indirect primary
@@ -1043,7 +1020,7 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
// If this class needs a vtable/vf-table and didn't get one from a
// primary base, add it in now.
- } else if (needsVFTable(RD)) {
+ } else if (RD->isDynamicClass()) {
assert(DataSize == 0 && "Vtable pointer must be at offset zero!");
CharUnits PtrWidth =
Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
@@ -1055,26 +1032,17 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
setDataSize(getSize());
}
- bool HasDirectVirtualBases = false;
- bool HasNonVirtualBaseWithVBTable = false;
-
// Now lay out the non-virtual bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- // Ignore virtual bases, but remember that we saw one.
- if (I->isVirtual()) {
- HasDirectVirtualBases = true;
+ // Ignore virtual bases.
+ if (I->isVirtual())
continue;
- }
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl());
- // Remember if this base has virtual bases itself.
- if (BaseDecl->getNumVBases())
- HasNonVirtualBaseWithVBTable = true;
-
// Skip the primary base, because we've already laid it out. The
// !PrimaryBaseIsVirtual check is required because we might have a
// non-virtual base of the same type as a primary virtual base.
@@ -1087,37 +1055,6 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
LayoutNonVirtualBase(BaseInfo);
}
-
- // In the MS ABI, add the vb-table pointer if we need one, which is
- // whenever we have a virtual base and we can't re-use a vb-table
- // pointer from a non-virtual base.
- if (isMicrosoftCXXABI() &&
- HasDirectVirtualBases && !HasNonVirtualBaseWithVBTable) {
- CharUnits PtrWidth =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
- CharUnits PtrAlign =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0));
-
- // MSVC potentially over-aligns the vb-table pointer by giving it
- // the max alignment of all the non-virtual objects in the class.
- // This is completely unnecessary, but we're not here to pass
- // judgment.
- //
- // Note that we've only laid out the non-virtual bases, so on the
- // first pass Alignment won't be set correctly here, but if the
- // vb-table doesn't end up aligned correctly we'll come through
- // and redo the layout from scratch with the right alignment.
- //
- // TODO: Instead of doing this, just lay out the fields as if the
- // vb-table were at offset zero, then retroactively bump the field
- // offsets up.
- PtrAlign = std::max(PtrAlign, Alignment);
-
- EnsureVTablePointerAlignment(PtrAlign);
- VBPtrOffset = getSize();
- setSize(getSize() + PtrWidth);
- setDataSize(getSize());
- }
}
void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) {
@@ -1166,249 +1103,6 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
}
}
-/// needsVFTable - Return true if this class needs a vtable or vf-table
-/// when laid out as a base class. These are treated the same because
-/// they're both always laid out at offset zero.
-///
-/// This function assumes that the class has no primary base.
-bool RecordLayoutBuilder::needsVFTable(const CXXRecordDecl *RD) const {
- assert(!PrimaryBase);
-
- // In the Itanium ABI, every dynamic class needs a vtable: even if
- // this class has no virtual functions as a base class (i.e. it's
- // non-polymorphic or only has virtual functions from virtual
- // bases),x it still needs a vtable to locate its virtual bases.
- if (!isMicrosoftCXXABI())
- return RD->isDynamicClass();
-
- // In the MS ABI, we need a vfptr if the class has virtual functions
- // other than those declared by its virtual bases. The AST doesn't
- // tell us that directly, and checking manually for virtual
- // functions that aren't overrides is expensive, but there are
- // some important shortcuts:
-
- // - Non-polymorphic classes have no virtual functions at all.
- if (!RD->isPolymorphic()) return false;
-
- // - Polymorphic classes with no virtual bases must either declare
- // virtual functions directly or inherit them, but in the latter
- // case we would have a primary base.
- if (RD->getNumVBases() == 0) return true;
-
- return hasNewVirtualFunction(RD);
-}
-
-/// Does the given class inherit non-virtually from any of the classes
-/// in the given set?
-static bool hasNonVirtualBaseInSet(const CXXRecordDecl *RD,
- const ClassSetTy &set) {
- for (CXXRecordDecl::base_class_const_iterator
- I = RD->bases_begin(), E = RD->bases_end(); I != E; ++I) {
- // Ignore virtual links.
- if (I->isVirtual()) continue;
-
- // Check whether the set contains the base.
- const CXXRecordDecl *base = I->getType()->getAsCXXRecordDecl();
- if (set.count(base))
- return true;
-
- // Otherwise, recurse and propagate.
- if (hasNonVirtualBaseInSet(base, set))
- return true;
- }
-
- return false;
-}
-
-/// Does the given method (B::foo()) already override a method (A::foo())
-/// such that A requires a vtordisp in B? If so, we don't need to add a
-/// new vtordisp for B in a yet-more-derived class C providing C::foo().
-static bool overridesMethodRequiringVtorDisp(const ASTContext &Context,
- const CXXMethodDecl *M) {
- CXXMethodDecl::method_iterator
- I = M->begin_overridden_methods(), E = M->end_overridden_methods();
- if (I == E) return false;
-
- const ASTRecordLayout::VBaseOffsetsMapTy &offsets =
- Context.getASTRecordLayout(M->getParent()).getVBaseOffsetsMap();
- do {
- const CXXMethodDecl *overridden = *I;
-
- // If the overridden method's class isn't recognized as a virtual
- // base in the derived class, ignore it.
- ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
- it = offsets.find(overridden->getParent());
- if (it == offsets.end()) continue;
-
- // Otherwise, check if the overridden method's class needs a vtordisp.
- if (it->second.hasVtorDisp()) return true;
-
- } while (++I != E);
- return false;
-}
-
-/// In the Microsoft ABI, decide which of the virtual bases require a
-/// vtordisp field.
-void RecordLayoutBuilder::computeVtordisps(const CXXRecordDecl *RD,
- ClassSetTy &vtordispVBases) {
- // Bail out if we have no virtual bases.
- assert(RD->getNumVBases());
-
- // Build up the set of virtual bases that we haven't decided yet.
- ClassSetTy undecidedVBases;
- for (CXXRecordDecl::base_class_const_iterator
- I = RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *vbase = I->getType()->getAsCXXRecordDecl();
- undecidedVBases.insert(vbase);
- }
- assert(!undecidedVBases.empty());
-
- // A virtual base requires a vtordisp field in a derived class if it
- // requires a vtordisp field in a base class. Walk all the direct
- // bases and collect this information.
- for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
- E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *base = I->getType()->getAsCXXRecordDecl();
- const ASTRecordLayout &baseLayout = Context.getASTRecordLayout(base);
-
- // Iterate over the set of virtual bases provided by this class.
- for (ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
- VI = baseLayout.getVBaseOffsetsMap().begin(),
- VE = baseLayout.getVBaseOffsetsMap().end(); VI != VE; ++VI) {
- // If it doesn't need a vtordisp in this base, ignore it.
- if (!VI->second.hasVtorDisp()) continue;
-
- // If we've already seen it and decided it needs a vtordisp, ignore it.
- if (!undecidedVBases.erase(VI->first))
- continue;
-
- // Add it.
- vtordispVBases.insert(VI->first);
-
- // Quit as soon as we've decided everything.
- if (undecidedVBases.empty())
- return;
- }
- }
-
- // Okay, we have virtual bases that we haven't yet decided about. A
- // virtual base requires a vtordisp if any the non-destructor
- // virtual methods declared in this class directly override a method
- // provided by that virtual base. (If so, we need to emit a thunk
- // for that method, to be used in the construction vftable, which
- // applies an additional 'vtordisp' this-adjustment.)
-
- // Collect the set of bases directly overridden by any method in this class.
- // It's possible that some of these classes won't be virtual bases, or won't be
- // provided by virtual bases, or won't be virtual bases in the overridden
- // instance but are virtual bases elsewhere. Only the last matters for what
- // we're doing, and we can ignore those: if we don't directly override
- // a method provided by a virtual copy of a base class, but we do directly
- // override a method provided by a non-virtual copy of that base class,
- // then we must indirectly override the method provided by the virtual base,
- // and so we should already have collected it in the loop above.
- ClassSetTy overriddenBases;
- for (CXXRecordDecl::method_iterator
- M = RD->method_begin(), E = RD->method_end(); M != E; ++M) {
- // Ignore non-virtual methods and destructors.
- if (isa<CXXDestructorDecl>(*M) || !M->isVirtual())
- continue;
-
- for (CXXMethodDecl::method_iterator I = M->begin_overridden_methods(),
- E = M->end_overridden_methods(); I != E; ++I) {
- const CXXMethodDecl *overriddenMethod = (*I);
-
- // Ignore methods that override methods from vbases that require
- // require vtordisps.
- if (overridesMethodRequiringVtorDisp(Context, overriddenMethod))
- continue;
-
- // As an optimization, check immediately whether we're overriding
- // something from the undecided set.
- const CXXRecordDecl *overriddenBase = overriddenMethod->getParent();
- if (undecidedVBases.erase(overriddenBase)) {
- vtordispVBases.insert(overriddenBase);
- if (undecidedVBases.empty()) return;
-
- // We can't 'continue;' here because one of our undecided
- // vbases might non-virtually inherit from this base.
- // Consider:
- // struct A { virtual void foo(); };
- // struct B : A {};
- // struct C : virtual A, virtual B { virtual void foo(); };
- // We need a vtordisp for B here.
- }
-
- // Otherwise, just collect it.
- overriddenBases.insert(overriddenBase);
- }
- }
-
- // Walk the undecided v-bases and check whether they (non-virtually)
- // provide any of the overridden bases. We don't need to consider
- // virtual links because the vtordisp inheres to the layout
- // subobject containing the base.
- for (ClassSetTy::const_iterator
- I = undecidedVBases.begin(), E = undecidedVBases.end(); I != E; ++I) {
- if (hasNonVirtualBaseInSet(*I, overriddenBases))
- vtordispVBases.insert(*I);
- }
-}
-
-/// hasNewVirtualFunction - Does the given polymorphic class declare a
-/// virtual function that does not override a method from any of its
-/// base classes?
-bool
-RecordLayoutBuilder::hasNewVirtualFunction(const CXXRecordDecl *RD,
- bool IgnoreDestructor) const {
- if (!RD->getNumBases())
- return true;
-
- for (CXXRecordDecl::method_iterator method = RD->method_begin();
- method != RD->method_end();
- ++method) {
- if (method->isVirtual() && !method->size_overridden_methods() &&
- !(IgnoreDestructor && method->getKind() == Decl::CXXDestructor)) {
- return true;
- }
- }
- return false;
-}
-
-/// isPossiblePrimaryBase - Is the given base class an acceptable
-/// primary base class?
-bool
-RecordLayoutBuilder::isPossiblePrimaryBase(const CXXRecordDecl *base) const {
- // In the Itanium ABI, a class can be a primary base class if it has
- // a vtable for any reason.
- if (!isMicrosoftCXXABI())
- return base->isDynamicClass();
-
- // In the MS ABI, a class can only be a primary base class if it
- // provides a vf-table at a static offset. That means it has to be
- // non-virtual base. The existence of a separate vb-table means
- // that it's possible to get virtual functions only from a virtual
- // base, which we have to guard against.
-
- // First off, it has to have virtual functions.
- if (!base->isPolymorphic()) return false;
-
- // If it has no virtual bases, then the vfptr must be at a static offset.
- if (!base->getNumVBases()) return true;
-
- // Otherwise, the necessary information is cached in the layout.
- const ASTRecordLayout &layout = Context.getASTRecordLayout(base);
-
- // If the base has its own vfptr, it can be a primary base.
- if (layout.hasOwnVFPtr()) return true;
-
- // If the base has a primary base class, then it can be a primary base.
- if (layout.getPrimaryBase()) return true;
-
- // Otherwise it can't.
- return false;
-}
-
void
RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
const CXXRecordDecl *MostDerivedClass) {
@@ -1458,39 +1152,7 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
}
}
-void RecordLayoutBuilder::MSLayoutVirtualBases(const CXXRecordDecl *RD) {
- if (!RD->getNumVBases())
- return;
-
- ClassSetTy VtordispVBases;
- computeVtordisps(RD, VtordispVBases);
-
- // This is substantially simplified because there are no virtual
- // primary bases.
- for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
- E = RD->vbases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
- const BaseSubobjectInfo *BaseInfo = VirtualBaseInfo.lookup(BaseDecl);
- assert(BaseInfo && "Did not find virtual base info!");
-
- // If this base requires a vtordisp, add enough space for an int field.
- // This is apparently always 32-bits, even on x64.
- bool vtordispNeeded = false;
- if (VtordispVBases.count(BaseDecl)) {
- CharUnits IntSize =
- CharUnits::fromQuantity(Context.getTargetInfo().getIntWidth() / 8);
-
- setSize(getSize() + IntSize);
- setDataSize(getSize());
- vtordispNeeded = true;
- }
-
- LayoutVirtualBase(BaseInfo, vtordispNeeded);
- }
-}
-
-void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base,
- bool IsVtordispNeed) {
+void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) {
assert(!Base->Derived && "Trying to lay out a primary virtual base!");
// Layout the base.
@@ -1499,10 +1161,9 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base,
// Add its base class offset.
assert(!VBases.count(Base->Class) && "vbase offset already exists!");
VBases.insert(std::make_pair(Base->Class,
- ASTRecordLayout::VBaseInfo(Offset, IsVtordispNeed)));
+ ASTRecordLayout::VBaseInfo(Offset, false)));
- if (!isMicrosoftCXXABI())
- AddPrimaryVirtualBaseOffsets(Base, Offset);
+ AddPrimaryVirtualBaseOffsets(Base, Offset);
}
CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
@@ -1530,18 +1191,19 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
}
}
+ CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign();
+ CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
+
// If we have an empty base class, try to place it at offset 0.
if (Base->Class->isEmpty() &&
(!HasExternalLayout || Offset == CharUnits::Zero()) &&
EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
setSize(std::max(getSize(), Layout.getSize()));
+ UpdateAlignment(BaseAlign, UnpackedBaseAlign);
return CharUnits::Zero();
}
- CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign();
- CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
-
// The maximum field alignment overrides base align.
if (!MaxFieldAlignment.isZero()) {
BaseAlign = std::min(BaseAlign, MaxFieldAlignment);
@@ -1655,24 +1317,8 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
Context.getTargetInfo().getCharAlign()));
NonVirtualAlignment = Alignment;
- if (isMicrosoftCXXABI()) {
- if (NonVirtualSize != NonVirtualSize.RoundUpToAlignment(Alignment)) {
- CharUnits AlignMember =
- NonVirtualSize.RoundUpToAlignment(Alignment) - NonVirtualSize;
-
- setSize(getSize() + AlignMember);
- setDataSize(getSize());
-
- NonVirtualSize = Context.toCharUnitsFromBits(
- llvm::RoundUpToAlignment(getSizeInBits(),
- Context.getTargetInfo().getCharAlign()));
- }
-
- MSLayoutVirtualBases(RD);
- } else {
- // Lay out the virtual bases and add the primary virtual base offsets.
- LayoutVirtualBases(RD, RD);
- }
+ // Lay out the virtual bases and add the primary virtual base offsets.
+ LayoutVirtualBases(RD, RD);
// Finally, round the size of the total struct up to the alignment
// of the struct itself.
@@ -1728,123 +1374,9 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Layout each field, for now, just sequentially, respecting alignment. In
// the future, this will need to be tweakable by targets.
- const FieldDecl *LastFD = 0;
- ZeroLengthBitfield = 0;
- unsigned RemainingInAlignment = 0;
for (RecordDecl::field_iterator Field = D->field_begin(),
- FieldEnd = D->field_end(); Field != FieldEnd; ++Field) {
- if (IsMsStruct) {
- FieldDecl *FD = *Field;
- if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD))
- ZeroLengthBitfield = FD;
- // Zero-length bitfields following non-bitfield members are
- // ignored:
- else if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD))
- continue;
- // FIXME. streamline these conditions into a simple one.
- else if (Context.BitfieldFollowsBitfield(FD, LastFD) ||
- Context.BitfieldFollowsNonBitfield(FD, LastFD) ||
- Context.NonBitfieldFollowsBitfield(FD, LastFD)) {
- // 1) Adjacent bit fields are packed into the same 1-, 2-, or
- // 4-byte allocation unit if the integral types are the same
- // size and if the next bit field fits into the current
- // allocation unit without crossing the boundary imposed by the
- // common alignment requirements of the bit fields.
- // 2) Establish a new alignment for a bitfield following
- // a non-bitfield if size of their types differ.
- // 3) Establish a new alignment for a non-bitfield following
- // a bitfield if size of their types differ.
- std::pair<uint64_t, unsigned> FieldInfo =
- Context.getTypeInfo(FD->getType());
- uint64_t TypeSize = FieldInfo.first;
- unsigned FieldAlign = FieldInfo.second;
- // This check is needed for 'long long' in -m32 mode.
- if (TypeSize > FieldAlign &&
- (Context.hasSameType(FD->getType(),
- Context.UnsignedLongLongTy)
- ||Context.hasSameType(FD->getType(),
- Context.LongLongTy)))
- FieldAlign = TypeSize;
- FieldInfo = Context.getTypeInfo(LastFD->getType());
- uint64_t TypeSizeLastFD = FieldInfo.first;
- unsigned FieldAlignLastFD = FieldInfo.second;
- // This check is needed for 'long long' in -m32 mode.
- if (TypeSizeLastFD > FieldAlignLastFD &&
- (Context.hasSameType(LastFD->getType(),
- Context.UnsignedLongLongTy)
- || Context.hasSameType(LastFD->getType(),
- Context.LongLongTy)))
- FieldAlignLastFD = TypeSizeLastFD;
-
- if (TypeSizeLastFD != TypeSize) {
- if (RemainingInAlignment &&
- LastFD && LastFD->isBitField() &&
- LastFD->getBitWidthValue(Context)) {
- // If previous field was a bitfield with some remaining unfilled
- // bits, pad the field so current field starts on its type boundary.
- uint64_t FieldOffset =
- getDataSizeInBits() - UnfilledBitsInLastByte;
- uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
- RemainingInAlignment = 0;
- }
-
- uint64_t UnpaddedFieldOffset =
- getDataSizeInBits() - UnfilledBitsInLastByte;
- FieldAlign = std::max(FieldAlign, FieldAlignLastFD);
-
- // The maximum field alignment overrides the aligned attribute.
- if (!MaxFieldAlignment.isZero()) {
- unsigned MaxFieldAlignmentInBits =
- Context.toBits(MaxFieldAlignment);
- FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
- }
-
- uint64_t NewSizeInBits =
- llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign);
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
- }
- if (FD->isBitField()) {
- uint64_t FieldSize = FD->getBitWidthValue(Context);
- assert (FieldSize > 0 && "LayoutFields - ms_struct layout");
- if (RemainingInAlignment < FieldSize)
- RemainingInAlignment = TypeSize - FieldSize;
- else
- RemainingInAlignment -= FieldSize;
- }
- }
- else if (FD->isBitField()) {
- uint64_t FieldSize = FD->getBitWidthValue(Context);
- std::pair<uint64_t, unsigned> FieldInfo =
- Context.getTypeInfo(FD->getType());
- uint64_t TypeSize = FieldInfo.first;
- RemainingInAlignment = TypeSize - FieldSize;
- }
- LastFD = FD;
- }
- else if (!Context.getTargetInfo().useBitFieldTypeAlignment() &&
- Context.getTargetInfo().useZeroLengthBitfieldAlignment()) {
- if (Field->isBitField() && Field->getBitWidthValue(Context) == 0)
- ZeroLengthBitfield = *Field;
- }
+ FieldEnd = D->field_end(); Field != FieldEnd; ++Field)
LayoutField(*Field);
- }
- if (IsMsStruct && RemainingInAlignment &&
- LastFD && LastFD->isBitField() && LastFD->getBitWidthValue(Context)) {
- // If we ended a bitfield before the full length of the type then
- // pad the struct out to the full length of the last type.
- uint64_t FieldOffset =
- getDataSizeInBits() - UnfilledBitsInLastByte;
- uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset;
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- setSize(std::max(getSizeInBits(), getDataSizeInBits()));
- }
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
@@ -1878,10 +1410,11 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
CharUnits TypeAlign = Context.getTypeAlignInChars(Type);
// We're not going to use any of the unfilled bits in the last byte.
- UnfilledBitsInLastByte = 0;
+ UnfilledBitsInLastUnit = 0;
+ LastBitfieldTypeSize = 0;
uint64_t FieldOffset;
- uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
if (IsUnion) {
setDataSize(std::max(getDataSizeInBits(), FieldSize));
@@ -1896,7 +1429,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
Context.getTargetInfo().getCharAlign()));
- UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
+ UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits;
}
// Place this field at the current location.
@@ -1914,49 +1447,43 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
- uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
- uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
uint64_t FieldSize = D->getBitWidthValue(Context);
-
std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
uint64_t TypeSize = FieldInfo.first;
unsigned FieldAlign = FieldInfo.second;
-
- // This check is needed for 'long long' in -m32 mode.
- if (IsMsStruct && (TypeSize > FieldAlign) &&
- (Context.hasSameType(D->getType(),
- Context.UnsignedLongLongTy)
- || Context.hasSameType(D->getType(), Context.LongLongTy)))
- FieldAlign = TypeSize;
- if (ZeroLengthBitfield) {
- std::pair<uint64_t, unsigned> FieldInfo;
- unsigned ZeroLengthBitfieldAlignment;
- if (IsMsStruct) {
- // If a zero-length bitfield is inserted after a bitfield,
- // and the alignment of the zero-length bitfield is
- // greater than the member that follows it, `bar', `bar'
- // will be aligned as the type of the zero-length bitfield.
- if (ZeroLengthBitfield != D) {
- FieldInfo = Context.getTypeInfo(ZeroLengthBitfield->getType());
- ZeroLengthBitfieldAlignment = FieldInfo.second;
- // Ignore alignment of subsequent zero-length bitfields.
- if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0))
- FieldAlign = ZeroLengthBitfieldAlignment;
- if (FieldSize)
- ZeroLengthBitfield = 0;
- }
- } else {
- // The alignment of a zero-length bitfield affects the alignment
- // of the next member. The alignment is the max of the zero
- // length bitfield's alignment and a target specific fixed value.
- unsigned ZeroLengthBitfieldBoundary =
- Context.getTargetInfo().getZeroLengthBitfieldBoundary();
- if (ZeroLengthBitfieldBoundary > FieldAlign)
- FieldAlign = ZeroLengthBitfieldBoundary;
+ if (IsMsStruct) {
+ // The field alignment for integer types in ms_struct structs is
+ // always the size.
+ FieldAlign = TypeSize;
+ // Ignore zero-length bitfields after non-bitfields in ms_struct structs.
+ if (!FieldSize && !LastBitfieldTypeSize)
+ FieldAlign = 1;
+ // If a bitfield is followed by a bitfield of a different size, don't
+ // pack the bits together in ms_struct structs.
+ if (LastBitfieldTypeSize != TypeSize) {
+ UnfilledBitsInLastUnit = 0;
+ LastBitfieldTypeSize = 0;
}
}
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
+ uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
+
+ bool ZeroLengthBitfield = false;
+ if (!Context.getTargetInfo().useBitFieldTypeAlignment() &&
+ Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
+ FieldSize == 0) {
+ // The alignment of a zero-length bitfield affects the alignment
+ // of the next member. The alignment is the max of the zero
+ // length bitfield's alignment and a target specific fixed value.
+ ZeroLengthBitfield = true;
+ unsigned ZeroLengthBitfieldBoundary =
+ Context.getTargetInfo().getZeroLengthBitfieldBoundary();
+ if (ZeroLengthBitfieldBoundary > FieldAlign)
+ FieldAlign = ZeroLengthBitfieldBoundary;
+ }
+
if (FieldSize > TypeSize) {
LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D);
return;
@@ -1982,6 +1509,13 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
}
+ // ms_struct bitfields always have to start at a round alignment.
+ if (IsMsStruct && !LastBitfieldTypeSize) {
+ FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
+ UnpackedFieldAlign);
+ }
+
// Check if we need to add padding to give the field the correct alignment.
if (FieldSize == 0 ||
(MaxFieldAlignment.isZero() &&
@@ -1996,12 +1530,11 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// Padding members don't affect overall alignment, unless zero length bitfield
// alignment is enabled.
- if (!D->getIdentifier() && !Context.getTargetInfo().useZeroLengthBitfieldAlignment())
+ if (!D->getIdentifier() &&
+ !Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
+ !IsMsStruct)
FieldAlign = UnpackedFieldAlign = 1;
- if (!IsMsStruct)
- ZeroLengthBitfield = 0;
-
if (ExternalLayout)
FieldOffset = updateExternalFieldOffset(D, FieldOffset);
@@ -2017,11 +1550,29 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
// FIXME: I think FieldSize should be TypeSize here.
setDataSize(std::max(getDataSizeInBits(), FieldSize));
} else {
- uint64_t NewSizeInBits = FieldOffset + FieldSize;
-
- setDataSize(llvm::RoundUpToAlignment(NewSizeInBits,
- Context.getTargetInfo().getCharAlign()));
- UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits;
+ if (IsMsStruct && FieldSize) {
+ // Under ms_struct, a bitfield always takes up space equal to the size
+ // of the type. We can't just change the alignment computation on the
+ // other codepath because of the way this interacts with #pragma pack:
+ // in a packed struct, we need to allocate misaligned space in the
+ // struct to hold the bitfield.
+ if (!UnfilledBitsInLastUnit) {
+ setDataSize(FieldOffset + TypeSize);
+ UnfilledBitsInLastUnit = TypeSize - FieldSize;
+ } else if (UnfilledBitsInLastUnit < FieldSize) {
+ setDataSize(getDataSizeInBits() + TypeSize);
+ UnfilledBitsInLastUnit = TypeSize - FieldSize;
+ } else {
+ UnfilledBitsInLastUnit -= FieldSize;
+ }
+ LastBitfieldTypeSize = TypeSize;
+ } else {
+ uint64_t NewSizeInBits = FieldOffset + FieldSize;
+ uint64_t BitfieldAlignment = Context.getTargetInfo().getCharAlign();
+ setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, BitfieldAlignment));
+ UnfilledBitsInLastUnit = getDataSizeInBits() - NewSizeInBits;
+ LastBitfieldTypeSize = 0;
+ }
}
// Update the size.
@@ -2038,10 +1589,11 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
return;
}
- uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit;
// Reset the unfilled bits.
- UnfilledBitsInLastByte = 0;
+ UnfilledBitsInLastUnit = 0;
+ LastBitfieldTypeSize = 0;
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
CharUnits FieldOffset =
@@ -2069,30 +1621,6 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
- if (ZeroLengthBitfield) {
- CharUnits ZeroLengthBitfieldBoundary =
- Context.toCharUnitsFromBits(
- Context.getTargetInfo().getZeroLengthBitfieldBoundary());
- if (ZeroLengthBitfieldBoundary == CharUnits::Zero()) {
- // If a zero-length bitfield is inserted after a bitfield,
- // and the alignment of the zero-length bitfield is
- // greater than the member that follows it, `bar', `bar'
- // will be aligned as the type of the zero-length bitfield.
- std::pair<CharUnits, CharUnits> FieldInfo =
- Context.getTypeInfoInChars(ZeroLengthBitfield->getType());
- CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second;
- if (ZeroLengthBitfieldAlignment > FieldAlign)
- FieldAlign = ZeroLengthBitfieldAlignment;
- } else if (ZeroLengthBitfieldBoundary > FieldAlign) {
- // Align 'bar' based on a fixed alignment specified by the target.
- assert(Context.getTargetInfo().useZeroLengthBitfieldAlignment() &&
- "ZeroLengthBitfieldBoundary should only be used in conjunction"
- " with useZeroLengthBitfieldAlignment.");
- FieldAlign = ZeroLengthBitfieldBoundary;
- }
- ZeroLengthBitfield = 0;
- }
-
if (IsMsStruct) {
// If MS bitfield layout is required, figure out what type is being
// laid out and align the field to the width of that type.
@@ -2189,7 +1717,7 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// Finally, round the size of the record up to the alignment of the
// record itself.
- uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte;
+ uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastUnit;
uint64_t UnpackedSizeInBits =
llvm::RoundUpToAlignment(getSizeInBits(),
Context.toBits(UnpackedAlignment));
@@ -2209,13 +1737,6 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
return;
}
-
- // MSVC doesn't round up to the alignment of the record with virtual bases.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
- if (isMicrosoftCXXABI() && RD->getNumVBases())
- return;
- }
-
// Set the size to the final size.
setSize(RoundedSize);
@@ -2354,7 +1875,7 @@ static const CXXMethodDecl *computeKeyFunction(ASTContext &Context,
// A class that is not externally visible doesn't have a key function. (Or
// at least, there's no point to assigning a key function to such a class;
// this doesn't affect the ABI.)
- if (RD->getLinkage() != ExternalLinkage)
+ if (!RD->isExternallyVisible())
return 0;
// Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6.
@@ -2453,6 +1974,732 @@ static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) {
llvm_unreachable("bad tail-padding use kind");
}
+static bool isMsLayout(const RecordDecl* D) {
+ return D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft();
+}
+
+// This section contains an implementation of struct layout that is, up to the
+// included tests, compatible with cl.exe (2012). The layout produced is
+// significantly different than those produced by the Itanium ABI. Here we note
+// the most important differences.
+//
+// * The alignment of bitfields in unions is ignored when computing the
+// alignment of the union.
+// * The existance of zero-width bitfield that occurs after anything other than
+// a non-zero length bitfield is ignored.
+// * The Itanium equivalent vtable pointers are split into a vfptr (virtual
+// function pointer) and a vbptr (virtual base pointer). They can each be
+// shared with a, non-virtual bases. These bases need not be the same. vfptrs
+// always occur at offset 0. vbptrs can occur at an
+// arbitrary offset and are placed after non-virtual bases but before fields.
+// * Virtual bases sometimes require a 'vtordisp' field that is laid out before
+// the virtual base and is used in conjunction with virtual overrides during
+// construction and destruction.
+// * vfptrs are allocated in a block of memory equal to the alignment of the
+// fields and non-virtual bases at offset 0 in 32 bit mode and in a pointer
+// sized block of memory in 64 bit mode.
+// * vbptrs are allocated in a block of memory equal to the alignment of the
+// fields and non-virtual bases. This block is at a potentially unaligned
+// offset. If the allocation slot is unaligned and the alignment is less than
+// or equal to the pointer size, additional space is allocated so that the
+// pointer can be aligned properly. This causes very strange effects on the
+// placement of objects after the allocated block. (see the code).
+// * vtordisps are allocated in a block of memory with size and alignment equal
+// to the alignment of the completed structure (before applying __declspec(
+// align())). The vtordisp always occur at the end of the allocation block,
+// immediately prior to the virtual base.
+// * The last zero sized non-virtual base is allocated after the placement of
+// vbptr if one exists and can be placed at the end of the struct, potentially
+// aliasing either the first member or another struct allocated after this
+// one.
+// * The last zero size virtual base may be placed at the end of the struct.
+// and can potentially alias a zero sized type in the next struct.
+// * If the last field is a non-zero length bitfield and we have any virtual
+// bases then some extra padding is added before the virtual bases for no
+// obvious reason.
+// * When laying out empty non-virtual bases, an extra byte of padding is added
+// if the non-virtual base before the empty non-virtual base has a vbptr.
+
+
+namespace {
+struct MicrosoftRecordLayoutBuilder {
+ typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
+ MicrosoftRecordLayoutBuilder(const ASTContext &Context) : Context(Context) {}
+private:
+ MicrosoftRecordLayoutBuilder(const MicrosoftRecordLayoutBuilder &)
+ LLVM_DELETED_FUNCTION;
+ void operator=(const MicrosoftRecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
+public:
+
+ void layout(const RecordDecl *RD);
+ void cxxLayout(const CXXRecordDecl *RD);
+ /// \brief Initializes size and alignment and honors some flags.
+ void initializeLayout(const RecordDecl *RD);
+ /// \brief Initialized C++ layout, compute alignment and virtual alignment and
+ /// existance of vfptrs and vbptrs. Alignment is needed before the vfptr is
+ /// laid out.
+ void initializeCXXLayout(const CXXRecordDecl *RD);
+ void layoutVFPtr(const CXXRecordDecl *RD);
+ void layoutNonVirtualBases(const CXXRecordDecl *RD);
+ void layoutNonVirtualBase(const CXXRecordDecl *RD);
+ void layoutVBPtr(const CXXRecordDecl *RD);
+ /// \brief Lays out the fields of the record. Also rounds size up to
+ /// alignment.
+ void layoutFields(const RecordDecl *RD);
+ void layoutField(const FieldDecl *FD);
+ void layoutBitField(const FieldDecl *FD);
+ /// \brief Lays out a single zero-width bit-field in the record and handles
+ /// special cases associated with zero-width bit-fields.
+ void layoutZeroWidthBitField(const FieldDecl *FD);
+ void layoutVirtualBases(const CXXRecordDecl *RD);
+ void layoutVirtualBase(const CXXRecordDecl *RD, bool HasVtordisp);
+ /// \brief Flushes the lazy virtual base and conditionally rounds up to
+ /// alignment.
+ void finalizeCXXLayout(const CXXRecordDecl *RD);
+ void honorDeclspecAlign(const RecordDecl *RD);
+
+ /// \brief Updates the alignment of the type. This function doesn't take any
+ /// properties (such as packedness) into account. getAdjustedFieldInfo()
+ /// adjustes for packedness.
+ void updateAlignment(CharUnits NewAlignment) {
+ Alignment = std::max(Alignment, NewAlignment);
+ }
+ /// \brief Gets the size and alignment taking attributes into account.
+ std::pair<CharUnits, CharUnits> getAdjustedFieldInfo(const FieldDecl *FD);
+ /// \brief Places a field at offset 0.
+ void placeFieldAtZero() { FieldOffsets.push_back(0); }
+ /// \brief Places a field at an offset in CharUnits.
+ void placeFieldAtOffset(CharUnits FieldOffset) {
+ FieldOffsets.push_back(Context.toBits(FieldOffset));
+ }
+ /// \brief Places a bitfield at a bit offset.
+ void placeFieldAtBitOffset(uint64_t FieldOffset) {
+ FieldOffsets.push_back(FieldOffset);
+ }
+ /// \brief Compute the set of virtual bases for which vtordisps are required.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2>
+ computeVtorDispSet(const CXXRecordDecl *RD);
+
+ const ASTContext &Context;
+ /// \brief The size of the record being laid out.
+ CharUnits Size;
+ /// \brief The current alignment of the record layout.
+ CharUnits Alignment;
+ /// \brief The collection of field offsets.
+ SmallVector<uint64_t, 16> FieldOffsets;
+ /// \brief The maximum allowed field alignment. This is set by #pragma pack.
+ CharUnits MaxFieldAlignment;
+ /// \brief Alignment does not occur for virtual bases unless something
+ /// forces it to by explicitly using __declspec(align())
+ bool AlignAfterVBases : 1;
+ bool IsUnion : 1;
+ /// \brief True if the last field laid out was a bitfield and was not 0
+ /// width.
+ bool LastFieldIsNonZeroWidthBitfield : 1;
+ /// \brief The size of the allocation of the currently active bitfield.
+ /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield
+ /// is true.
+ CharUnits CurrentBitfieldSize;
+ /// \brief The number of remaining bits in our last bitfield allocation.
+ /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is
+ /// true.
+ unsigned RemainingBitsInField;
+
+ /// \brief The data alignment of the record layout.
+ CharUnits DataSize;
+ /// \brief The alignment of the non-virtual portion of the record layout
+ /// without the impact of the virtual pointers.
+ /// Only used for C++ layouts.
+ CharUnits BasesAndFieldsAlignment;
+ /// \brief The alignment of the non-virtual portion of the record layout
+ /// Only used for C++ layouts.
+ CharUnits NonVirtualAlignment;
+ /// \brief The additional alignment imposed by the virtual bases.
+ CharUnits VirtualAlignment;
+ /// \brief The primary base class (if one exists).
+ const CXXRecordDecl *PrimaryBase;
+ /// \brief The class we share our vb-pointer with.
+ const CXXRecordDecl *SharedVBPtrBase;
+ /// \brief True if the class has a vftable pointer that can be extended
+ /// by this class or classes derived from it. Such a vfptr will always occur
+ /// at offset 0.
+ bool HasExtendableVFPtr : 1;
+ /// \brief True if the class has a (not necessarily its own) vbtable pointer.
+ bool HasVBPtr : 1;
+ /// \brief Offset to the virtual base table pointer (if one exists).
+ CharUnits VBPtrOffset;
+ /// \brief Base classes and their offsets in the record.
+ BaseOffsetsMapTy Bases;
+ /// \brief virtual base classes and their offsets in the record.
+ ASTRecordLayout::VBaseOffsetsMapTy VBases;
+ /// \brief The size of a pointer.
+ CharUnits PointerSize;
+ /// \brief The alignment of a pointer.
+ CharUnits PointerAlignment;
+ /// \brief Holds an empty base we haven't yet laid out.
+ const CXXRecordDecl *LazyEmptyBase;
+ /// \brief Lets us know if the last base we laid out was empty. Only used
+ /// when adjusting the placement of a last zero-sized base in 64 bit mode.
+ bool LastBaseWasEmpty;
+ /// \brief Lets us know if we're in 64-bit mode
+ bool Is64BitMode;
+ /// \brief True if the last non-virtual base has a vbptr.
+ bool LastNonVirtualBaseHasVBPtr;
+};
+} // namespace
+
+std::pair<CharUnits, CharUnits>
+MicrosoftRecordLayoutBuilder::getAdjustedFieldInfo(const FieldDecl *FD) {
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(FD->getType());
+
+ // If we're not on win32 and using ms_struct the field alignment will be wrong
+ // for 64 bit types, so we fix that here.
+ if (FD->getASTContext().getTargetInfo().getTriple().getOS() !=
+ llvm::Triple::Win32) {
+ QualType T = Context.getBaseElementType(FD->getType());
+ if (const BuiltinType *BTy = T->getAs<BuiltinType>()) {
+ CharUnits TypeSize = Context.getTypeSizeInChars(BTy);
+ if (TypeSize > FieldInfo.second)
+ FieldInfo.second = TypeSize;
+ }
+ }
+
+ // Respect packed attribute.
+ if (FD->hasAttr<PackedAttr>())
+ FieldInfo.second = CharUnits::One();
+ // Respect pack pragma.
+ else if (!MaxFieldAlignment.isZero())
+ FieldInfo.second = std::min(FieldInfo.second, MaxFieldAlignment);
+ // Respect alignment attributes.
+ if (unsigned fieldAlign = FD->getMaxAlignment()) {
+ CharUnits FieldAlign = Context.toCharUnitsFromBits(fieldAlign);
+ AlignAfterVBases = true;
+ FieldInfo.second = std::max(FieldInfo.second, FieldAlign);
+ }
+ return FieldInfo;
+}
+
+void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) {
+ IsUnion = RD->isUnion();
+ Is64BitMode = Context.getTargetInfo().getPointerWidth(0) == 64;
+
+ Size = CharUnits::Zero();
+ Alignment = CharUnits::One();
+ AlignAfterVBases = false;
+
+ // Compute the maximum field alignment.
+ MaxFieldAlignment = CharUnits::Zero();
+ // Honor the default struct packing maximum alignment flag.
+ if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct)
+ MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment);
+ // Honor the packing attribute.
+ if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>())
+ MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment());
+ // Packed attribute forces max field alignment to be 1.
+ if (RD->hasAttr<PackedAttr>())
+ MaxFieldAlignment = CharUnits::One();
+}
+
+void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) {
+ initializeLayout(RD);
+ layoutFields(RD);
+ honorDeclspecAlign(RD);
+}
+
+void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) {
+ initializeLayout(RD);
+ initializeCXXLayout(RD);
+ layoutVFPtr(RD);
+ layoutNonVirtualBases(RD);
+ layoutVBPtr(RD);
+ layoutFields(RD);
+ DataSize = Size;
+ NonVirtualAlignment = Alignment;
+ layoutVirtualBases(RD);
+ finalizeCXXLayout(RD);
+ honorDeclspecAlign(RD);
+}
+
+void
+MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) {
+ // Calculate pointer size and alignment.
+ PointerSize =
+ Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0));
+ PointerAlignment = PointerSize;
+ if (!MaxFieldAlignment.isZero())
+ PointerAlignment = std::min(PointerAlignment, MaxFieldAlignment);
+
+ // Initialize information about the bases.
+ HasVBPtr = false;
+ HasExtendableVFPtr = false;
+ SharedVBPtrBase = 0;
+ PrimaryBase = 0;
+ VirtualAlignment = CharUnits::One();
+ AlignAfterVBases = Is64BitMode;
+
+ // If the record has a dynamic base class, attempt to choose a primary base
+ // class. It is the first (in direct base class order) non-virtual dynamic
+ // base class, if one exists.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end();
+ i != e; ++i) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
+ // Handle forced alignment.
+ if (Layout.getAlignAfterVBases())
+ AlignAfterVBases = true;
+ // Handle virtual bases.
+ if (i->isVirtual()) {
+ VirtualAlignment = std::max(VirtualAlignment, Layout.getAlignment());
+ HasVBPtr = true;
+ continue;
+ }
+ // We located a primary base class!
+ if (!PrimaryBase && Layout.hasExtendableVFPtr()) {
+ PrimaryBase = BaseDecl;
+ HasExtendableVFPtr = true;
+ }
+ // We located a base to share a VBPtr with!
+ if (!SharedVBPtrBase && Layout.hasVBPtr()) {
+ SharedVBPtrBase = BaseDecl;
+ HasVBPtr = true;
+ }
+ updateAlignment(Layout.getAlignment());
+ }
+
+ // Use LayoutFields to compute the alignment of the fields. The layout
+ // is discarded. This is the simplest way to get all of the bit-field
+ // behavior correct and is not actually very expensive.
+ layoutFields(RD);
+ Size = CharUnits::Zero();
+ BasesAndFieldsAlignment = Alignment;
+ FieldOffsets.clear();
+}
+
+void MicrosoftRecordLayoutBuilder::layoutVFPtr(const CXXRecordDecl *RD) {
+ // If we have a primary base then our VFPtr was already laid out
+ if (PrimaryBase)
+ return;
+
+ // Look at all of our methods to determine if we need a VFPtr. We need a
+ // vfptr if we define a new virtual function.
+ if (!HasExtendableVFPtr && RD->isDynamicClass())
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end();
+ !HasExtendableVFPtr && i != e; ++i)
+ HasExtendableVFPtr = i->isVirtual() && i->size_overridden_methods() == 0;
+ if (!HasExtendableVFPtr)
+ return;
+
+ // MSVC 32 (but not 64) potentially over-aligns the vf-table pointer by giving
+ // it the max alignment of all the non-virtual data in the class. The
+ // resulting layout is essentially { vftbl, { nvdata } }. This is completely
+ // unnecessary, but we're not here to pass judgment.
+ updateAlignment(PointerAlignment);
+ if (Is64BitMode)
+ Size = Size.RoundUpToAlignment(PointerAlignment) + PointerSize;
+ else
+ Size = Size.RoundUpToAlignment(PointerAlignment) + Alignment;
+}
+
+void
+MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) {
+ LazyEmptyBase = 0;
+ LastBaseWasEmpty = false;
+ LastNonVirtualBaseHasVBPtr = false;
+
+ // Lay out the primary base first.
+ if (PrimaryBase)
+ layoutNonVirtualBase(PrimaryBase);
+
+ // Iterate through the bases and lay out the non-virtual ones.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end();
+ i != e; ++i) {
+ if (i->isVirtual())
+ continue;
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(i->getType()->castAs<RecordType>()->getDecl());
+ if (BaseDecl != PrimaryBase)
+ layoutNonVirtualBase(BaseDecl);
+ }
+}
+
+void
+MicrosoftRecordLayoutBuilder::layoutNonVirtualBase(const CXXRecordDecl *RD) {
+ const ASTRecordLayout *Layout = RD ? &Context.getASTRecordLayout(RD) : 0;
+
+ // If we have a lazy empty base we haven't laid out yet, do that now.
+ if (LazyEmptyBase) {
+ const ASTRecordLayout &LazyLayout =
+ Context.getASTRecordLayout(LazyEmptyBase);
+ Size = Size.RoundUpToAlignment(LazyLayout.getAlignment());
+ // If the last non-virtual base has a vbptr we add a byte of padding for no
+ // obvious reason.
+ if (LastNonVirtualBaseHasVBPtr)
+ Size++;
+ Bases.insert(std::make_pair(LazyEmptyBase, Size));
+ // Empty bases only consume space when followed by another empty base.
+ if (RD && Layout->getNonVirtualSize().isZero()) {
+ LastBaseWasEmpty = true;
+ Size++;
+ }
+ LazyEmptyBase = 0;
+ LastNonVirtualBaseHasVBPtr = false;
+ }
+
+ // RD is null when flushing the final lazy base.
+ if (!RD)
+ return;
+
+ if (Layout->getNonVirtualSize().isZero()) {
+ LazyEmptyBase = RD;
+ return;
+ }
+
+ // Insert the base here.
+ CharUnits BaseOffset = Size.RoundUpToAlignment(Layout->getAlignment());
+ Bases.insert(std::make_pair(RD, BaseOffset));
+ Size = BaseOffset + Layout->getDataSize();
+ // Note: we don't update alignment here because it was accounted
+ // for during initalization.
+ LastBaseWasEmpty = false;
+ LastNonVirtualBaseHasVBPtr = Layout->hasVBPtr();
+}
+
+void MicrosoftRecordLayoutBuilder::layoutVBPtr(const CXXRecordDecl *RD) {
+ if (!HasVBPtr)
+ VBPtrOffset = CharUnits::fromQuantity(-1);
+ else if (SharedVBPtrBase) {
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(SharedVBPtrBase);
+ VBPtrOffset = Bases[SharedVBPtrBase] + Layout.getVBPtrOffset();
+ } else {
+ VBPtrOffset = Size.RoundUpToAlignment(PointerAlignment);
+ CharUnits OldSize = Size;
+ Size = VBPtrOffset + PointerSize;
+ if (BasesAndFieldsAlignment <= PointerAlignment) {
+ // Handle strange padding rules for the lazily placed base. I have no
+ // explanation for why the last virtual base is padded in such an odd way.
+ // Two things to note about this padding are that the rules are different
+ // if the alignment of the bases+fields is <= to the alignemnt of a
+ // pointer and that the rule in 64-bit mode behaves differently depending
+ // on if the second to last base was also zero sized.
+ Size += OldSize % BasesAndFieldsAlignment.getQuantity();
+ } else {
+ if (Is64BitMode)
+ Size += LastBaseWasEmpty ? CharUnits::One() : CharUnits::Zero();
+ else
+ Size = OldSize + BasesAndFieldsAlignment;
+ }
+ updateAlignment(PointerAlignment);
+ }
+
+ // Flush the lazy empty base.
+ layoutNonVirtualBase(0);
+}
+
+void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) {
+ LastFieldIsNonZeroWidthBitfield = false;
+ for (RecordDecl::field_iterator Field = RD->field_begin(),
+ FieldEnd = RD->field_end();
+ Field != FieldEnd; ++Field)
+ layoutField(*Field);
+ Size = Size.RoundUpToAlignment(Alignment);
+}
+
+void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) {
+ if (FD->isBitField()) {
+ layoutBitField(FD);
+ return;
+ }
+ LastFieldIsNonZeroWidthBitfield = false;
+
+ std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
+ CharUnits FieldSize = FieldInfo.first;
+ CharUnits FieldAlign = FieldInfo.second;
+
+ updateAlignment(FieldAlign);
+ if (IsUnion) {
+ placeFieldAtZero();
+ Size = std::max(Size, FieldSize);
+ } else {
+ // Round up the current record size to the field's alignment boundary.
+ CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ placeFieldAtOffset(FieldOffset);
+ Size = FieldOffset + FieldSize;
+ }
+}
+
+void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) {
+ unsigned Width = FD->getBitWidthValue(Context);
+ if (Width == 0) {
+ layoutZeroWidthBitField(FD);
+ return;
+ }
+
+ std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
+ CharUnits FieldSize = FieldInfo.first;
+ CharUnits FieldAlign = FieldInfo.second;
+
+ // Clamp the bitfield to a containable size for the sake of being able
+ // to lay them out. Sema will throw an error.
+ if (Width > Context.toBits(FieldSize))
+ Width = Context.toBits(FieldSize);
+
+ // Check to see if this bitfield fits into an existing allocation. Note:
+ // MSVC refuses to pack bitfields of formal types with different sizes
+ // into the same allocation.
+ if (!IsUnion && LastFieldIsNonZeroWidthBitfield &&
+ CurrentBitfieldSize == FieldSize && Width <= RemainingBitsInField) {
+ placeFieldAtBitOffset(Context.toBits(Size) - RemainingBitsInField);
+ RemainingBitsInField -= Width;
+ return;
+ }
+
+ LastFieldIsNonZeroWidthBitfield = true;
+ CurrentBitfieldSize = FieldSize;
+ if (IsUnion) {
+ placeFieldAtZero();
+ Size = std::max(Size, FieldSize);
+ // TODO: Add a Sema warning that MS ignores bitfield alignment in unions.
+ } else {
+ // Allocate a new block of memory and place the bitfield in it.
+ CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ placeFieldAtOffset(FieldOffset);
+ Size = FieldOffset + FieldSize;
+ updateAlignment(FieldAlign);
+ RemainingBitsInField = Context.toBits(FieldSize) - Width;
+ }
+}
+
+void
+MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) {
+ // Zero-width bitfields are ignored unless they follow a non-zero-width
+ // bitfield.
+ std::pair<CharUnits, CharUnits> FieldInfo = getAdjustedFieldInfo(FD);
+ CharUnits FieldSize = FieldInfo.first;
+ CharUnits FieldAlign = FieldInfo.second;
+
+ if (!LastFieldIsNonZeroWidthBitfield) {
+ placeFieldAtOffset(IsUnion ? CharUnits::Zero() : Size);
+ // TODO: Add a Sema warning that MS ignores alignment for zero
+ // sized bitfields that occur after zero-size bitfields or non bitfields.
+ return;
+ }
+
+ LastFieldIsNonZeroWidthBitfield = false;
+ if (IsUnion) {
+ placeFieldAtZero();
+ Size = std::max(Size, FieldSize);
+ } else {
+ // Round up the current record size to the field's alignment boundary.
+ CharUnits FieldOffset = Size.RoundUpToAlignment(FieldAlign);
+ placeFieldAtOffset(FieldOffset);
+ Size = FieldOffset;
+ updateAlignment(FieldAlign);
+ }
+}
+
+void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) {
+ if (!HasVBPtr)
+ return;
+
+ updateAlignment(VirtualAlignment);
+
+ // Zero-sized v-bases obey the alignment attribute so apply it here. The
+ // alignment attribute is normally accounted for in FinalizeLayout.
+ if (unsigned MaxAlign = RD->getMaxAlignment())
+ updateAlignment(Context.toCharUnitsFromBits(MaxAlign));
+
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp =
+ computeVtorDispSet(RD);
+
+ // If the last field we laid out was a non-zero length bitfield then add some
+ // extra padding for no obvious reason.
+ if (LastFieldIsNonZeroWidthBitfield)
+ Size += CurrentBitfieldSize;
+
+ // Iterate through the virtual bases and lay them out.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(),
+ e = RD->vbases_end();
+ i != e; ++i) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(i->getType()->castAs<RecordType>()->getDecl());
+ layoutVirtualBase(BaseDecl, HasVtordisp.count(BaseDecl));
+ }
+}
+
+void MicrosoftRecordLayoutBuilder::layoutVirtualBase(const CXXRecordDecl *RD,
+ bool HasVtordisp) {
+ if (LazyEmptyBase) {
+ const ASTRecordLayout &LazyLayout =
+ Context.getASTRecordLayout(LazyEmptyBase);
+ Size = Size.RoundUpToAlignment(LazyLayout.getAlignment());
+ VBases.insert(
+ std::make_pair(LazyEmptyBase, ASTRecordLayout::VBaseInfo(Size, false)));
+ // Empty bases only consume space when followed by another empty base.
+ // The space consumed is in an Alignment sized/aligned block and the v-base
+ // is placed at its alignment offset into the chunk, unless its alignment
+ // is less than 4 bytes, at which it is placed at 4 byte offset in the
+ // chunk. We have no idea why.
+ if (RD && Context.getASTRecordLayout(RD).getNonVirtualSize().isZero())
+ Size = Size.RoundUpToAlignment(Alignment) + CharUnits::fromQuantity(4);
+ LazyEmptyBase = 0;
+ }
+
+ // RD is null when flushing the final lazy virtual base.
+ if (!RD)
+ return;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ if (Layout.getNonVirtualSize().isZero() && !HasVtordisp) {
+ LazyEmptyBase = RD;
+ return;
+ }
+
+ CharUnits BaseNVSize = Layout.getNonVirtualSize();
+ CharUnits BaseAlign = Layout.getAlignment();
+
+ // vtordisps are always 4 bytes (even in 64-bit mode)
+ if (HasVtordisp)
+ Size = Size.RoundUpToAlignment(Alignment) + CharUnits::fromQuantity(4);
+ Size = Size.RoundUpToAlignment(BaseAlign);
+
+ // Insert the base here.
+ CharUnits BaseOffset = Size.RoundUpToAlignment(BaseAlign);
+ VBases.insert(
+ std::make_pair(RD, ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp)));
+ Size = BaseOffset + BaseNVSize;
+ // Note: we don't update alignment here because it was accounted for in
+ // InitializeLayout.
+}
+
+void MicrosoftRecordLayoutBuilder::finalizeCXXLayout(const CXXRecordDecl *RD) {
+ // Flush the lazy virtual base.
+ layoutVirtualBase(0, false);
+
+ if (RD->vbases_begin() == RD->vbases_end() || AlignAfterVBases)
+ Size = Size.RoundUpToAlignment(Alignment);
+
+ if (Size.isZero())
+ Size = Alignment;
+}
+
+void MicrosoftRecordLayoutBuilder::honorDeclspecAlign(const RecordDecl *RD) {
+ if (unsigned MaxAlign = RD->getMaxAlignment()) {
+ AlignAfterVBases = true;
+ updateAlignment(Context.toCharUnitsFromBits(MaxAlign));
+ Size = Size.RoundUpToAlignment(Alignment);
+ }
+}
+
+static bool
+RequiresVtordisp(const llvm::SmallPtrSet<const CXXRecordDecl *, 2> &HasVtordisp,
+ const CXXRecordDecl *RD) {
+ if (HasVtordisp.count(RD))
+ return true;
+ // If any of a virtual bases non-virtual bases (recursively) requires a
+ // vtordisp than so does this virtual base.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end();
+ i != e; ++i)
+ if (!i->isVirtual() &&
+ RequiresVtordisp(
+ HasVtordisp,
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl())))
+ return true;
+ return false;
+}
+
+llvm::SmallPtrSet<const CXXRecordDecl *, 2>
+MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) {
+ llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordisp;
+
+ // If any of our bases need a vtordisp for this type, so do we. Check our
+ // direct bases for vtordisp requirements.
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end();
+ i != e; ++i) {
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
+ for (ASTRecordLayout::VBaseOffsetsMapTy::const_iterator
+ bi = Layout.getVBaseOffsetsMap().begin(),
+ be = Layout.getVBaseOffsetsMap().end();
+ bi != be; ++bi)
+ if (bi->second.hasVtorDisp())
+ HasVtordisp.insert(bi->first);
+ }
+
+ // If we define a constructor or destructor and override a function that is
+ // defined in a virtual base's vtable, that virtual bases need a vtordisp.
+ // Here we collect a list of classes with vtables for which our virtual bases
+ // actually live. The virtual bases with this property will require
+ // vtordisps. In addition, virtual bases that contain non-virtual bases that
+ // define functions we override also require vtordisps, this case is checked
+ // explicitly below.
+ if (RD->hasUserDeclaredConstructor() || RD->hasUserDeclaredDestructor()) {
+ llvm::SmallPtrSet<const CXXMethodDecl *, 8> Work;
+ // Seed the working set with our non-destructor virtual methods.
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end();
+ i != e; ++i)
+ if ((*i)->isVirtual() && !isa<CXXDestructorDecl>(*i))
+ Work.insert(*i);
+ while (!Work.empty()) {
+ const CXXMethodDecl *MD = *Work.begin();
+ CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
+ e = MD->end_overridden_methods();
+ if (i == e)
+ // If a virtual method has no-overrides it lives in its parent's vtable.
+ HasVtordisp.insert(MD->getParent());
+ else
+ Work.insert(i, e);
+ // We've finished processing this element, remove it from the working set.
+ Work.erase(MD);
+ }
+ }
+
+ // Re-check all of our vbases for vtordisp requirements (in case their
+ // non-virtual bases have vtordisp requirements).
+ for (CXXRecordDecl::base_class_const_iterator i = RD->vbases_begin(),
+ e = RD->vbases_end();
+ i != e; ++i) {
+ const CXXRecordDecl *BaseDecl = i->getType()->getAsCXXRecordDecl();
+ if (!HasVtordisp.count(BaseDecl) && RequiresVtordisp(HasVtordisp, BaseDecl))
+ HasVtordisp.insert(BaseDecl);
+ }
+
+ return HasVtordisp;
+}
+
+/// \brief Get or compute information about the layout of the specified record
+/// (struct/union/class), which indicates its size and field position
+/// information.
+const ASTRecordLayout *
+ASTContext::BuildMicrosoftASTRecordLayout(const RecordDecl *D) const {
+ MicrosoftRecordLayoutBuilder Builder(*this);
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ Builder.cxxLayout(RD);
+ return new (*this) ASTRecordLayout(
+ *this, Builder.Size, Builder.Alignment,
+ Builder.HasExtendableVFPtr && !Builder.PrimaryBase,
+ Builder.HasExtendableVFPtr,
+ Builder.VBPtrOffset, Builder.DataSize, Builder.FieldOffsets.data(),
+ Builder.FieldOffsets.size(), Builder.DataSize,
+ Builder.NonVirtualAlignment, CharUnits::Zero(), Builder.PrimaryBase,
+ false, Builder.SharedVBPtrBase, Builder.AlignAfterVBases, Builder.Bases,
+ Builder.VBases);
+ } else {
+ Builder.layout(D);
+ return new (*this) ASTRecordLayout(
+ *this, Builder.Size, Builder.Alignment, Builder.Size,
+ Builder.FieldOffsets.data(), Builder.FieldOffsets.size());
+ }
+}
+
/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
/// position information.
@@ -2468,6 +2715,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
D = D->getDefinition();
assert(D && "Cannot get layout of forward declarations!");
+ assert(!D->isInvalidDecl() && "Cannot get layout of invalid decl!");
assert(D->isCompleteDefinition() && "Cannot layout type before complete!");
// Look up this layout, if already laid out, return what we have.
@@ -2476,27 +2724,15 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
const ASTRecordLayout *Entry = ASTRecordLayouts[D];
if (Entry) return *Entry;
- const ASTRecordLayout *NewEntry;
+ const ASTRecordLayout *NewEntry = 0;
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (isMsLayout(D) && !D->getASTContext().getExternalSource()) {
+ NewEntry = BuildMicrosoftASTRecordLayout(D);
+ } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
EmptySubobjectMap EmptySubobjects(*this, RD);
RecordLayoutBuilder Builder(*this, &EmptySubobjects);
Builder.Layout(RD);
- // MSVC gives the vb-table pointer an alignment equal to that of
- // the non-virtual part of the structure. That's an inherently
- // multi-pass operation. If our first pass doesn't give us
- // adequate alignment, try again with the specified minimum
- // alignment. This is *much* more maintainable than computing the
- // alignment in advance in a separately-coded pass; it's also
- // significantly more efficient in the common case where the
- // vb-table doesn't need extra padding.
- if (Builder.VBPtrOffset != CharUnits::fromQuantity(-1) &&
- (Builder.VBPtrOffset % Builder.NonVirtualAlignment) != 0) {
- Builder.resetWithTargetAlignment(Builder.NonVirtualAlignment);
- Builder.Layout(RD);
- }
-
// In certain situations, we are allowed to lay out objects in the
// tail-padding of base classes. This is ABI-dependent.
// FIXME: this should be stored in the record layout.
@@ -2508,12 +2744,12 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
skipTailPadding ? Builder.getSize() : Builder.getDataSize();
CharUnits NonVirtualSize =
skipTailPadding ? DataSize : Builder.NonVirtualSize;
-
NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
Builder.Alignment,
Builder.HasOwnVFPtr,
- Builder.VBPtrOffset,
+ RD->isDynamicClass(),
+ CharUnits::fromQuantity(-1),
DataSize,
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size(),
@@ -2522,6 +2758,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
EmptySubobjects.SizeOfLargestEmptySubobject,
Builder.PrimaryBase,
Builder.PrimaryBaseIsVirtual,
+ 0, true,
Builder.Bases, Builder.VBases);
} else {
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
@@ -2538,43 +2775,45 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
ASTRecordLayouts[D] = NewEntry;
if (getLangOpts().DumpRecordLayouts) {
- llvm::errs() << "\n*** Dumping AST Record Layout\n";
- DumpRecordLayout(D, llvm::errs(), getLangOpts().DumpRecordLayoutsSimple);
+ llvm::outs() << "\n*** Dumping AST Record Layout\n";
+ DumpRecordLayout(D, llvm::outs(), getLangOpts().DumpRecordLayoutsSimple);
}
return *NewEntry;
}
const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) {
+ if (!getTargetInfo().getCXXABI().hasKeyFunctions())
+ return 0;
+
assert(RD->getDefinition() && "Cannot get key function for forward decl!");
RD = cast<CXXRecordDecl>(RD->getDefinition());
- const CXXMethodDecl *&entry = KeyFunctions[RD];
- if (!entry) {
- entry = computeKeyFunction(*this, RD);
- }
+ LazyDeclPtr &Entry = KeyFunctions[RD];
+ if (!Entry)
+ Entry = const_cast<CXXMethodDecl*>(computeKeyFunction(*this, RD));
- return entry;
+ return cast_or_null<CXXMethodDecl>(Entry.get(getExternalSource()));
}
-void ASTContext::setNonKeyFunction(const CXXMethodDecl *method) {
- assert(method == method->getFirstDeclaration() &&
+void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) {
+ assert(Method == Method->getFirstDecl() &&
"not working with method declaration from class definition");
// Look up the cache entry. Since we're working with the first
// declaration, its parent must be the class definition, which is
// the correct key for the KeyFunctions hash.
- llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*>::iterator
- i = KeyFunctions.find(method->getParent());
+ llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr>::iterator
+ I = KeyFunctions.find(Method->getParent());
// If it's not cached, there's nothing to do.
- if (i == KeyFunctions.end()) return;
+ if (I == KeyFunctions.end()) return;
// If it is cached, check whether it's the target method, and if so,
// remove it from the cache.
- if (i->second == method) {
+ if (I->second.get(getExternalSource()) == Method) {
// FIXME: remember that we did this for module / chained PCH state?
- KeyFunctions.erase(i);
+ KeyFunctions.erase(I);
}
}
@@ -2676,16 +2915,19 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
IndentLevel++;
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- bool HasVfptr = Layout.hasOwnVFPtr();
- bool HasVbptr = Layout.getVBPtrOffset() != CharUnits::fromQuantity(-1);
+ bool HasOwnVFPtr = Layout.hasOwnVFPtr();
+ bool HasOwnVBPtr = Layout.hasOwnVBPtr();
// Vtable pointer.
- if (RD->isDynamicClass() && !PrimaryBase &&
- !C.getTargetInfo().getCXXABI().isMicrosoft()) {
+ if (RD->isDynamicClass() && !PrimaryBase && !isMsLayout(RD)) {
PrintOffset(OS, Offset, IndentLevel);
OS << '(' << *RD << " vtable pointer)\n";
+ } else if (HasOwnVFPtr) {
+ PrintOffset(OS, Offset, IndentLevel);
+ // vfptr (for Microsoft C++ ABI)
+ OS << '(' << *RD << " vftable pointer)\n";
}
-
+
// Dump (non-virtual) bases
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
@@ -2704,12 +2946,8 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
/*IncludeVirtualBases=*/false);
}
- // vfptr and vbptr (for Microsoft C++ ABI)
- if (HasVfptr) {
- PrintOffset(OS, Offset, IndentLevel);
- OS << '(' << *RD << " vftable pointer)\n";
- }
- if (HasVbptr) {
+ // vbptr (for Microsoft C++ ABI)
+ if (HasOwnVBPtr) {
PrintOffset(OS, Offset + Layout.getVBPtrOffset(), IndentLevel);
OS << '(' << *RD << " vbtable pointer)\n";
}
@@ -2762,7 +3000,8 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
PrintIndentNoOffset(OS, IndentLevel - 1);
OS << "[sizeof=" << Layout.getSize().getQuantity();
- OS << ", dsize=" << Layout.getDataSize().getQuantity();
+ if (!isMsLayout(RD))
+ OS << ", dsize=" << Layout.getDataSize().getQuantity();
OS << ", align=" << Layout.getAlignment().getQuantity() << '\n';
PrintIndentNoOffset(OS, IndentLevel - 1);
@@ -2789,7 +3028,8 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD,
OS << "\nLayout: ";
OS << "<ASTRecordLayout\n";
OS << " Size:" << toBits(Info.getSize()) << "\n";
- OS << " DataSize:" << toBits(Info.getDataSize()) << "\n";
+ if (!isMsLayout(RD))
+ OS << " DataSize:" << toBits(Info.getDataSize()) << "\n";
OS << " Alignment:" << toBits(Info.getAlignment()) << "\n";
OS << " FieldOffsets: [";
for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) {
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 5b29c07..de85161 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
+#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
@@ -48,16 +49,11 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
return StmtClassInfo[E];
}
-void *Stmt::operator new(size_t bytes, ASTContext& C,
- unsigned alignment) throw() {
+void *Stmt::operator new(size_t bytes, const ASTContext& C,
+ unsigned alignment) {
return ::operator new(bytes, C, alignment);
}
-void *Stmt::operator new(size_t bytes, ASTContext* C,
- unsigned alignment) throw() {
- return ::operator new(bytes, *C, alignment);
-}
-
const char *Stmt::getStmtClassName() const {
return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
}
@@ -139,6 +135,7 @@ namespace {
template <class T> good implements_children(children_t T::*) {
return good();
}
+ LLVM_ATTRIBUTE_UNUSED
static inline bad implements_children(children_t Stmt::*) {
return bad();
}
@@ -147,6 +144,7 @@ namespace {
template <class T> good implements_getLocStart(getLocStart_t T::*) {
return good();
}
+ LLVM_ATTRIBUTE_UNUSED
static inline bad implements_getLocStart(getLocStart_t Stmt::*) {
return bad();
}
@@ -155,20 +153,22 @@ namespace {
template <class T> good implements_getLocEnd(getLocEnd_t T::*) {
return good();
}
+ LLVM_ATTRIBUTE_UNUSED
static inline bad implements_getLocEnd(getLocEnd_t Stmt::*) {
return bad();
}
#define ASSERT_IMPLEMENTS_children(type) \
- (void) sizeof(is_good(implements_children(&type::children)))
+ (void) is_good(implements_children(&type::children))
#define ASSERT_IMPLEMENTS_getLocStart(type) \
- (void) sizeof(is_good(implements_getLocStart(&type::getLocStart)))
+ (void) is_good(implements_getLocStart(&type::getLocStart))
#define ASSERT_IMPLEMENTS_getLocEnd(type) \
- (void) sizeof(is_good(implements_getLocEnd(&type::getLocEnd)))
+ (void) is_good(implements_getLocEnd(&type::getLocEnd))
}
/// Check whether the various Stmt classes implement their member
/// functions.
+LLVM_ATTRIBUTE_UNUSED
static inline void check_implementations() {
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
@@ -252,7 +252,7 @@ SourceLocation Stmt::getLocEnd() const {
llvm_unreachable("unknown statement kind");
}
-CompoundStmt::CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts,
+CompoundStmt::CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts,
SourceLocation LB, SourceLocation RB)
: Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) {
CompoundStmtBits.NumStmts = Stmts.size();
@@ -268,7 +268,8 @@ CompoundStmt::CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts,
std::copy(Stmts.begin(), Stmts.end(), Body);
}
-void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
+void CompoundStmt::setStmts(const ASTContext &C, Stmt **Stmts,
+ unsigned NumStmts) {
if (this->Body)
C.Deallocate(Body);
this->CompoundStmtBits.NumStmts = NumStmts;
@@ -281,7 +282,7 @@ const char *LabelStmt::getName() const {
return getDecl()->getIdentifier()->getNameStart();
}
-AttributedStmt *AttributedStmt::Create(ASTContext &C, SourceLocation Loc,
+AttributedStmt *AttributedStmt::Create(const ASTContext &C, SourceLocation Loc,
ArrayRef<const Attr*> Attrs,
Stmt *SubStmt) {
void *Mem = C.Allocate(sizeof(AttributedStmt) +
@@ -290,7 +291,8 @@ AttributedStmt *AttributedStmt::Create(ASTContext &C, SourceLocation Loc,
return new (Mem) AttributedStmt(Loc, Attrs, SubStmt);
}
-AttributedStmt *AttributedStmt::CreateEmpty(ASTContext &C, unsigned NumAttrs) {
+AttributedStmt *AttributedStmt::CreateEmpty(const ASTContext &C,
+ unsigned NumAttrs) {
assert(NumAttrs > 0 && "NumAttrs should be greater than zero");
void *Mem = C.Allocate(sizeof(AttributedStmt) +
sizeof(Attr*) * (NumAttrs - 1),
@@ -298,29 +300,7 @@ AttributedStmt *AttributedStmt::CreateEmpty(ASTContext &C, unsigned NumAttrs) {
return new (Mem) AttributedStmt(EmptyShell(), NumAttrs);
}
-bool Stmt::hasImplicitControlFlow() const {
- switch (StmtBits.sClass) {
- default:
- return false;
-
- case CallExprClass:
- case ConditionalOperatorClass:
- case ChooseExprClass:
- case StmtExprClass:
- case DeclStmtClass:
- return true;
-
- case Stmt::BinaryOperatorClass: {
- const BinaryOperator* B = cast<BinaryOperator>(this);
- if (B->isLogicalOp() || B->getOpcode() == BO_Comma)
- return true;
- else
- return false;
- }
- }
-}
-
-std::string AsmStmt::generateAsmString(ASTContext &C) const {
+std::string AsmStmt::generateAsmString(const ASTContext &C) const {
if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this))
return gccAsmStmt->generateAsmString(C);
if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this))
@@ -406,14 +386,14 @@ StringRef GCCAsmStmt::getInputConstraint(unsigned i) const {
return getInputConstraintLiteral(i)->getString();
}
-void GCCAsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C,
- IdentifierInfo **Names,
- StringLiteral **Constraints,
- Stmt **Exprs,
- unsigned NumOutputs,
- unsigned NumInputs,
- StringLiteral **Clobbers,
- unsigned NumClobbers) {
+void GCCAsmStmt::setOutputsAndInputsAndClobbers(const ASTContext &C,
+ IdentifierInfo **Names,
+ StringLiteral **Constraints,
+ Stmt **Exprs,
+ unsigned NumOutputs,
+ unsigned NumInputs,
+ StringLiteral **Clobbers,
+ unsigned NumClobbers) {
this->NumOutputs = NumOutputs;
this->NumInputs = NumInputs;
this->NumClobbers = NumClobbers;
@@ -461,7 +441,7 @@ int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const {
/// it into pieces. If the asm string is erroneous, emit errors and return
/// true, otherwise return false.
unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
- ASTContext &C, unsigned &DiagOffs) const {
+ const ASTContext &C, unsigned &DiagOffs) const {
StringRef Str = getAsmString()->getString();
const char *StrStart = Str.begin();
const char *StrEnd = Str.end();
@@ -599,7 +579,7 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
}
/// Assemble final IR asm string (GCC-style).
-std::string GCCAsmStmt::generateAsmString(ASTContext &C) const {
+std::string GCCAsmStmt::generateAsmString(const ASTContext &C) const {
// Analyze the asm string to decompose it into its pieces. We know that Sema
// has already done this, so it is guaranteed to be successful.
SmallVector<GCCAsmStmt::AsmStringPiece, 4> Pieces;
@@ -620,7 +600,7 @@ std::string GCCAsmStmt::generateAsmString(ASTContext &C) const {
}
/// Assemble final IR asm string (MS-style).
-std::string MSAsmStmt::generateAsmString(ASTContext &C) const {
+std::string MSAsmStmt::generateAsmString(const ASTContext &C) const {
// FIXME: This needs to be translated into the IR string representation.
return AsmStr;
}
@@ -646,12 +626,12 @@ QualType CXXCatchStmt::getCaughtType() const {
// Constructors
//===----------------------------------------------------------------------===//
-GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
- bool isvolatile, unsigned numoutputs, unsigned numinputs,
- IdentifierInfo **names, StringLiteral **constraints,
- Expr **exprs, StringLiteral *asmstr,
- unsigned numclobbers, StringLiteral **clobbers,
- SourceLocation rparenloc)
+GCCAsmStmt::GCCAsmStmt(const ASTContext &C, SourceLocation asmloc,
+ bool issimple, bool isvolatile, unsigned numoutputs,
+ unsigned numinputs, IdentifierInfo **names,
+ StringLiteral **constraints, Expr **exprs,
+ StringLiteral *asmstr, unsigned numclobbers,
+ StringLiteral **clobbers, SourceLocation rparenloc)
: AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs,
numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) {
@@ -670,7 +650,7 @@ GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple,
std::copy(clobbers, clobbers + NumClobbers, Clobbers);
}
-MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc,
+MSAsmStmt::MSAsmStmt(const ASTContext &C, SourceLocation asmloc,
SourceLocation lbraceloc, bool issimple, bool isvolatile,
ArrayRef<Token> asmtoks, unsigned numoutputs,
unsigned numinputs,
@@ -684,15 +664,14 @@ MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc,
initialize(C, asmstr, asmtoks, constraints, exprs, clobbers);
}
-static StringRef copyIntoContext(ASTContext &C, StringRef str) {
+static StringRef copyIntoContext(const ASTContext &C, StringRef str) {
size_t size = str.size();
char *buffer = new (C) char[size];
memcpy(buffer, str.data(), size);
return StringRef(buffer, size);
}
-void MSAsmStmt::initialize(ASTContext &C,
- StringRef asmstr,
+void MSAsmStmt::initialize(const ASTContext &C, StringRef asmstr,
ArrayRef<Token> asmtoks,
ArrayRef<StringRef> constraints,
ArrayRef<Expr*> exprs,
@@ -731,7 +710,7 @@ ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect,
SourceLocation RPL)
: Stmt(ObjCForCollectionStmtClass) {
SubExprs[ELEM] = Elem;
- SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect);
+ SubExprs[COLLECTION] = Collect;
SubExprs[BODY] = Body;
ForLoc = FCL;
RParenLoc = RPL;
@@ -752,7 +731,7 @@ ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt,
Stmts[NumCatchStmts + 1] = atFinallyStmt;
}
-ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context,
+ObjCAtTryStmt *ObjCAtTryStmt::Create(const ASTContext &Context,
SourceLocation atTryLoc,
Stmt *atTryStmt,
Stmt **CatchStmts,
@@ -765,9 +744,9 @@ ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context,
atFinallyStmt);
}
-ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context,
- unsigned NumCatchStmts,
- bool HasFinally) {
+ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(const ASTContext &Context,
+ unsigned NumCatchStmts,
+ bool HasFinally) {
unsigned Size = sizeof(ObjCAtTryStmt) +
(1 + NumCatchStmts + HasFinally) * sizeof(Stmt *);
void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>());
@@ -782,7 +761,7 @@ SourceLocation ObjCAtTryStmt::getLocEnd() const {
return getTryBody()->getLocEnd();
}
-CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
+CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, SourceLocation tryLoc,
Stmt *tryBlock, ArrayRef<Stmt*> handlers) {
std::size_t Size = sizeof(CXXTryStmt);
Size += ((handlers.size() + 1) * sizeof(Stmt));
@@ -791,7 +770,7 @@ CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers);
}
-CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty,
+CXXTryStmt *CXXTryStmt::Create(const ASTContext &C, EmptyShell Empty,
unsigned numHandlers) {
std::size_t Size = sizeof(CXXTryStmt);
Size += ((numHandlers + 1) * sizeof(Stmt));
@@ -815,8 +794,8 @@ CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
: Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) {
SubExprs[RANGE] = Range;
SubExprs[BEGINEND] = BeginEndStmt;
- SubExprs[COND] = reinterpret_cast<Stmt*>(Cond);
- SubExprs[INC] = reinterpret_cast<Stmt*>(Inc);
+ SubExprs[COND] = Cond;
+ SubExprs[INC] = Inc;
SubExprs[LOOPVAR] = LoopVar;
SubExprs[BODY] = Body;
}
@@ -842,12 +821,12 @@ const VarDecl *CXXForRangeStmt::getLoopVariable() const {
return const_cast<CXXForRangeStmt*>(this)->getLoopVariable();
}
-IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
+IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond,
Stmt *then, SourceLocation EL, Stmt *elsev)
: Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL)
{
setConditionVariable(C, var);
- SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
+ SubExprs[COND] = cond;
SubExprs[THEN] = then;
SubExprs[ELSE] = elsev;
}
@@ -860,7 +839,7 @@ VarDecl *IfStmt::getConditionVariable() const {
return cast<VarDecl>(DS->getSingleDecl());
}
-void IfStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
+void IfStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
SubExprs[VAR] = 0;
return;
@@ -871,15 +850,15 @@ void IfStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
VarRange.getEnd());
}
-ForStmt::ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
+ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar,
Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP,
SourceLocation RP)
: Stmt(ForStmtClass), ForLoc(FL), LParenLoc(LP), RParenLoc(RP)
{
SubExprs[INIT] = Init;
setConditionVariable(C, condVar);
- SubExprs[COND] = reinterpret_cast<Stmt*>(Cond);
- SubExprs[INC] = reinterpret_cast<Stmt*>(Inc);
+ SubExprs[COND] = Cond;
+ SubExprs[INC] = Inc;
SubExprs[BODY] = Body;
}
@@ -891,7 +870,7 @@ VarDecl *ForStmt::getConditionVariable() const {
return cast<VarDecl>(DS->getSingleDecl());
}
-void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
+void ForStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
SubExprs[CONDVAR] = 0;
return;
@@ -902,11 +881,11 @@ void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
VarRange.getEnd());
}
-SwitchStmt::SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond)
+SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond)
: Stmt(SwitchStmtClass), FirstCase(0), AllEnumCasesCovered(0)
{
setConditionVariable(C, Var);
- SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
+ SubExprs[COND] = cond;
SubExprs[BODY] = NULL;
}
@@ -918,7 +897,7 @@ VarDecl *SwitchStmt::getConditionVariable() const {
return cast<VarDecl>(DS->getSingleDecl());
}
-void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
+void SwitchStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
SubExprs[VAR] = 0;
return;
@@ -935,11 +914,11 @@ Stmt *SwitchCase::getSubStmt() {
return cast<DefaultStmt>(this)->getSubStmt();
}
-WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
+WhileStmt::WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
SourceLocation WL)
: Stmt(WhileStmtClass) {
setConditionVariable(C, Var);
- SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
+ SubExprs[COND] = cond;
SubExprs[BODY] = body;
WhileLoc = WL;
}
@@ -952,7 +931,7 @@ VarDecl *WhileStmt::getConditionVariable() const {
return cast<VarDecl>(DS->getSingleDecl());
}
-void WhileStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
+void WhileStmt::setConditionVariable(const ASTContext &C, VarDecl *V) {
if (!V) {
SubExprs[VAR] = 0;
return;
@@ -991,10 +970,8 @@ SEHTryStmt::SEHTryStmt(bool IsCXXTry,
Children[HANDLER] = Handler;
}
-SEHTryStmt* SEHTryStmt::Create(ASTContext &C,
- bool IsCXXTry,
- SourceLocation TryLoc,
- Stmt *TryBlock,
+SEHTryStmt* SEHTryStmt::Create(const ASTContext &C, bool IsCXXTry,
+ SourceLocation TryLoc, Stmt *TryBlock,
Stmt *Handler) {
return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler);
}
@@ -1013,14 +990,12 @@ SEHExceptStmt::SEHExceptStmt(SourceLocation Loc,
: Stmt(SEHExceptStmtClass),
Loc(Loc)
{
- Children[FILTER_EXPR] = reinterpret_cast<Stmt*>(FilterExpr);
+ Children[FILTER_EXPR] = FilterExpr;
Children[BLOCK] = Block;
}
-SEHExceptStmt* SEHExceptStmt::Create(ASTContext &C,
- SourceLocation Loc,
- Expr *FilterExpr,
- Stmt *Block) {
+SEHExceptStmt* SEHExceptStmt::Create(const ASTContext &C, SourceLocation Loc,
+ Expr *FilterExpr, Stmt *Block) {
return new(C) SEHExceptStmt(Loc,FilterExpr,Block);
}
@@ -1031,8 +1006,7 @@ SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc,
Block(Block)
{}
-SEHFinallyStmt* SEHFinallyStmt::Create(ASTContext &C,
- SourceLocation Loc,
+SEHFinallyStmt* SEHFinallyStmt::Create(const ASTContext &C, SourceLocation Loc,
Stmt *Block) {
return new(C)SEHFinallyStmt(Loc,Block);
}
@@ -1079,7 +1053,7 @@ CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures)
getStoredStmts()[NumCaptures] = 0;
}
-CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S,
+CapturedStmt *CapturedStmt::Create(const ASTContext &Context, Stmt *S,
CapturedRegionKind Kind,
ArrayRef<Capture> Captures,
ArrayRef<Expr *> CaptureInits,
@@ -1107,7 +1081,7 @@ CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S,
return new (Mem) CapturedStmt(S, Kind, Captures, CaptureInits, CD, RD);
}
-CapturedStmt *CapturedStmt::CreateDeserialized(ASTContext &Context,
+CapturedStmt *CapturedStmt::CreateDeserialized(const ASTContext &Context,
unsigned NumCaptures) {
unsigned Size = sizeof(CapturedStmt) + sizeof(Stmt *) * (NumCaptures + 1);
if (NumCaptures > 0) {
@@ -1128,7 +1102,7 @@ Stmt::child_range CapturedStmt::children() {
bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
for (const_capture_iterator I = capture_begin(),
E = capture_end(); I != E; ++I) {
- if (I->capturesThis())
+ if (!I->capturesVariable())
continue;
// This does not handle variable redeclarations. This should be
@@ -1140,3 +1114,107 @@ bool CapturedStmt::capturesVariable(const VarDecl *Var) const {
return false;
}
+
+StmtRange OMPClause::children() {
+ switch(getClauseKind()) {
+ default : break;
+#define OPENMP_CLAUSE(Name, Class) \
+ case OMPC_ ## Name : return static_cast<Class *>(this)->children();
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("unknown OMPClause");
+}
+
+OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * VL.size(),
+ llvm::alignOf<OMPPrivateClause>());
+ OMPPrivateClause *Clause = new (Mem) OMPPrivateClause(StartLoc, LParenLoc,
+ EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * N,
+ llvm::alignOf<OMPPrivateClause>());
+ return new (Mem) OMPPrivateClause(N);
+}
+
+OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) +
+ sizeof(Expr *) * VL.size(),
+ llvm::alignOf<OMPFirstprivateClause>());
+ OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc,
+ LParenLoc,
+ EndLoc,
+ VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) + sizeof(Expr *) * N,
+ llvm::alignOf<OMPFirstprivateClause>());
+ return new (Mem) OMPFirstprivateClause(N);
+}
+
+OMPSharedClause *OMPSharedClause::Create(const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc,
+ ArrayRef<Expr *> VL) {
+ void *Mem = C.Allocate(sizeof(OMPSharedClause) + sizeof(Expr *) * VL.size(),
+ llvm::alignOf<OMPSharedClause>());
+ OMPSharedClause *Clause = new (Mem) OMPSharedClause(StartLoc, LParenLoc,
+ EndLoc, VL.size());
+ Clause->setVarRefs(VL);
+ return Clause;
+}
+
+OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C,
+ unsigned N) {
+ void *Mem = C.Allocate(sizeof(OMPSharedClause) + sizeof(Expr *) * N,
+ llvm::alignOf<OMPSharedClause>());
+ return new (Mem) OMPSharedClause(N);
+}
+
+void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) {
+ assert(Clauses.size() == this->Clauses.size() &&
+ "Number of clauses is not the same as the preallocated buffer");
+ std::copy(Clauses.begin(), Clauses.end(), this->Clauses.begin());
+}
+
+OMPParallelDirective *OMPParallelDirective::Create(
+ const ASTContext &C,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ ArrayRef<OMPClause *> Clauses,
+ Stmt *AssociatedStmt) {
+ void *Mem = C.Allocate(sizeof(OMPParallelDirective) +
+ sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *),
+ llvm::alignOf<OMPParallelDirective>());
+ OMPParallelDirective *Dir = new (Mem) OMPParallelDirective(StartLoc, EndLoc,
+ Clauses.size());
+ Dir->setClauses(Clauses);
+ Dir->setAssociatedStmt(AssociatedStmt);
+ return Dir;
+}
+
+OMPParallelDirective *OMPParallelDirective::CreateEmpty(const ASTContext &C,
+ unsigned N,
+ EmptyShell) {
+ void *Mem = C.Allocate(sizeof(OMPParallelDirective) +
+ sizeof(OMPClause *) * N + sizeof(Stmt *),
+ llvm::alignOf<OMPParallelDirective>());
+ return new (Mem) OMPParallelDirective(N);
+}
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
index 9bf4aea..6e85375 100644
--- a/lib/AST/StmtIterator.cpp
+++ b/lib/AST/StmtIterator.cpp
@@ -40,14 +40,7 @@ void StmtIteratorBase::NextVA() {
if (p)
return;
- if (inDecl()) {
- if (VarDecl* VD = dyn_cast<VarDecl>(decl))
- if (VD->Init)
- return;
-
- NextDecl();
- }
- else if (inDeclGroup()) {
+ if (inDeclGroup()) {
if (VarDecl* VD = dyn_cast<VarDecl>(*DGI))
if (VD->Init)
return;
@@ -55,40 +48,26 @@ void StmtIteratorBase::NextVA() {
NextDecl();
}
else {
- assert (inSizeOfTypeVA());
- assert(!decl);
+ assert(inSizeOfTypeVA());
RawVAPtr = 0;
}
}
void StmtIteratorBase::NextDecl(bool ImmediateAdvance) {
assert (getVAPtr() == NULL);
+ assert(inDeclGroup());
- if (inDecl()) {
- assert(decl);
+ if (ImmediateAdvance)
+ ++DGI;
- // FIXME: SIMPLIFY AWAY.
- if (ImmediateAdvance)
- decl = 0;
- else if (HandleDecl(decl))
+ for ( ; DGI != DGE; ++DGI)
+ if (HandleDecl(*DGI))
return;
- }
- else {
- assert(inDeclGroup());
-
- if (ImmediateAdvance)
- ++DGI;
-
- for ( ; DGI != DGE; ++DGI)
- if (HandleDecl(*DGI))
- return;
- }
RawVAPtr = 0;
}
bool StmtIteratorBase::HandleDecl(Decl* D) {
-
if (VarDecl* VD = dyn_cast<VarDecl>(D)) {
if (const VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) {
setVAPtr(VAPtr);
@@ -113,43 +92,23 @@ bool StmtIteratorBase::HandleDecl(Decl* D) {
return false;
}
-StmtIteratorBase::StmtIteratorBase(Decl *d, Stmt **s)
- : stmt(s), decl(d), RawVAPtr(d ? DeclMode : 0) {
- if (decl)
- NextDecl(false);
-}
-
StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge)
: stmt(0), DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) {
NextDecl(false);
}
StmtIteratorBase::StmtIteratorBase(const VariableArrayType* t)
- : stmt(0), decl(0), RawVAPtr(SizeOfTypeVAMode) {
+ : stmt(0), DGI(0), RawVAPtr(SizeOfTypeVAMode) {
RawVAPtr |= reinterpret_cast<uintptr_t>(t);
}
Stmt*& StmtIteratorBase::GetDeclExpr() const {
-
if (const VariableArrayType* VAPtr = getVAPtr()) {
assert (VAPtr->SizeExpr);
return const_cast<Stmt*&>(VAPtr->SizeExpr);
}
- assert (inDecl() || inDeclGroup());
-
- if (inDeclGroup()) {
- VarDecl* VD = cast<VarDecl>(*DGI);
- return *VD->getInitAddress();
- }
-
- assert (inDecl());
-
- if (VarDecl* VD = dyn_cast<VarDecl>(decl)) {
- assert (VD->Init);
- return *VD->getInitAddress();
- }
-
- EnumConstantDecl* ECD = cast<EnumConstantDecl>(decl);
- return ECD->Init;
+ assert (inDeclGroup());
+ VarDecl* VD = cast<VarDecl>(*DGI);
+ return *VD->getInitAddress();
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 9203dc1..0ecb5b5 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -580,6 +580,87 @@ void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) {
}
//===----------------------------------------------------------------------===//
+// OpenMP clauses printing methods
+//===----------------------------------------------------------------------===//
+
+namespace {
+class OMPClausePrinter : public OMPClauseVisitor<OMPClausePrinter> {
+ raw_ostream &OS;
+ /// \brief Process clauses with list of variables.
+ template <typename T>
+ void VisitOMPClauseList(T *Node, char StartSym);
+public:
+ OMPClausePrinter(raw_ostream &OS) : OS(OS) { }
+#define OPENMP_CLAUSE(Name, Class) \
+ void Visit##Class(Class *S);
+#include "clang/Basic/OpenMPKinds.def"
+};
+
+void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) {
+ OS << "default("
+ << getOpenMPSimpleClauseTypeName(OMPC_default, Node->getDefaultKind())
+ << ")";
+}
+
+template<typename T>
+void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) {
+ for (typename T::varlist_iterator I = Node->varlist_begin(),
+ E = Node->varlist_end();
+ I != E; ++I)
+ OS << (I == Node->varlist_begin() ? StartSym : ',')
+ << *cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl());
+}
+
+void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "private";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
+
+void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "firstprivate";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
+
+void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) {
+ if (!Node->varlist_empty()) {
+ OS << "shared";
+ VisitOMPClauseList(Node, '(');
+ OS << ")";
+ }
+}
+
+}
+
+//===----------------------------------------------------------------------===//
+// OpenMP directives printing methods
+//===----------------------------------------------------------------------===//
+
+void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) {
+ Indent() << "#pragma omp parallel ";
+
+ OMPClausePrinter Printer(OS);
+ ArrayRef<OMPClause *> Clauses = Node->clauses();
+ for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
+ I != E; ++I)
+ if (*I && !(*I)->isImplicit()) {
+ Printer.Visit(*I);
+ OS << ' ';
+ }
+ OS << "\n";
+ if (Node->getAssociatedStmt()) {
+ assert(isa<CapturedStmt>(Node->getAssociatedStmt()) &&
+ "Expected captured statement!");
+ Stmt *CS = cast<CapturedStmt>(Node->getAssociatedStmt())->getCapturedStmt();
+ PrintStmt(CS);
+ }
+}
+//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
@@ -657,6 +738,9 @@ void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
case PredefinedExpr::Function:
OS << "__FUNCTION__";
break;
+ case PredefinedExpr::FuncDName:
+ OS << "__FUNCDNAME__";
+ break;
case PredefinedExpr::LFunction:
OS << "L__FUNCTION__";
break;
@@ -1019,6 +1103,14 @@ void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) {
OS << ")";
}
+void StmtPrinter::VisitConvertVectorExpr(ConvertVectorExpr *Node) {
+ OS << "__builtin_convertvector(";
+ PrintExpr(Node->getSrcExpr());
+ OS << ", ";
+ Node->getType().print(OS, Policy);
+ OS << ")";
+}
+
void StmtPrinter::VisitInitListExpr(InitListExpr* Node) {
if (Node->getSyntacticForm()) {
Visit(Node->getSyntacticForm());
@@ -1226,7 +1318,7 @@ void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) {
void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
OS << "typeid(";
if (Node->isTypeOperand()) {
- Node->getTypeOperand().print(OS, Policy);
+ Node->getTypeOperandSourceInfo()->getType().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
@@ -1236,7 +1328,7 @@ void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) {
OS << "__uuidof(";
if (Node->isTypeOperand()) {
- Node->getTypeOperand().print(OS, Policy);
+ Node->getTypeOperandSourceInfo()->getType().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
@@ -1339,6 +1431,8 @@ void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
ArgEnd = Node->arg_end();
Arg != ArgEnd; ++Arg) {
+ if (Arg->isDefaultArgument())
+ break;
if (Arg != Node->arg_begin())
OS << ", ";
PrintExpr(*Arg);
@@ -1377,17 +1471,18 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
break;
case LCK_ByRef:
- if (Node->getCaptureDefault() != LCD_ByRef)
+ if (Node->getCaptureDefault() != LCD_ByRef || C->isInitCapture())
OS << '&';
OS << C->getCapturedVar()->getName();
break;
case LCK_ByCopy:
- if (Node->getCaptureDefault() != LCD_ByCopy)
- OS << '=';
OS << C->getCapturedVar()->getName();
break;
}
+
+ if (C->isInitCapture())
+ PrintExpr(C->getCapturedVar()->getInit());
}
OS << ']';
@@ -1525,6 +1620,10 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
OS << " }";
}
+void StmtPrinter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
+ PrintExpr(E->getSubExpr());
+}
+
void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
// Just forward to the sub expression.
PrintExpr(E->getSubExpr());
@@ -1616,6 +1715,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
case UTT_IsReference: return "__is_reference";
case UTT_IsRvalueReference: return "__is_rvalue_reference";
case UTT_IsScalar: return "__is_scalar";
+ case UTT_IsSealed: return "__is_sealed";
case UTT_IsSigned: return "__is_signed";
case UTT_IsStandardLayout: return "__is_standard_layout";
case UTT_IsTrivial: return "__is_trivial";
@@ -1886,7 +1986,7 @@ void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
// Stmt method implementations
//===----------------------------------------------------------------------===//
-void Stmt::dumpPretty(ASTContext &Context) const {
+void Stmt::dumpPretty(const ASTContext &Context) const {
printPretty(llvm::errs(), 0, PrintingPolicy(Context.getLangOpts()));
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 8ade242..6805e62 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -252,6 +252,52 @@ StmtProfiler::VisitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt *S) {
VisitStmt(S);
}
+namespace {
+class OMPClauseProfiler : public ConstOMPClauseVisitor<OMPClauseProfiler> {
+ StmtProfiler *Profiler;
+ /// \brief Process clauses with list of variables.
+ template <typename T>
+ void VisitOMPClauseList(T *Node);
+public:
+ OMPClauseProfiler(StmtProfiler *P) : Profiler(P) { }
+#define OPENMP_CLAUSE(Name, Class) \
+ void Visit##Class(const Class *C);
+#include "clang/Basic/OpenMPKinds.def"
+};
+
+void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { }
+
+template<typename T>
+void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
+ for (typename T::varlist_const_iterator I = Node->varlist_begin(),
+ E = Node->varlist_end();
+ I != E; ++I)
+ Profiler->VisitStmt(*I);
+}
+
+void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) {
+ VisitOMPClauseList(C);
+}
+void OMPClauseProfiler::VisitOMPFirstprivateClause(
+ const OMPFirstprivateClause *C) {
+ VisitOMPClauseList(C);
+}
+void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) {
+ VisitOMPClauseList(C);
+}
+}
+
+void
+StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) {
+ VisitStmt(S);
+ OMPClauseProfiler P(this);
+ ArrayRef<OMPClause *> Clauses = S->clauses();
+ for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
+ I != E; ++I)
+ if (*I)
+ P.Visit(*I);
+}
+
void StmtProfiler::VisitExpr(const Expr *S) {
VisitStmt(S);
}
@@ -417,6 +463,10 @@ void StmtProfiler::VisitShuffleVectorExpr(const ShuffleVectorExpr *S) {
VisitExpr(S);
}
+void StmtProfiler::VisitConvertVectorExpr(const ConvertVectorExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitChooseExpr(const ChooseExpr *S) {
VisitExpr(S);
}
@@ -758,16 +808,21 @@ void StmtProfiler::VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *S) {
VisitExpr(S);
}
+void StmtProfiler::VisitCXXStdInitializerListExpr(
+ const CXXStdInitializerListExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCXXTypeidExpr(const CXXTypeidExpr *S) {
VisitExpr(S);
if (S->isTypeOperand())
- VisitType(S->getTypeOperand());
+ VisitType(S->getTypeOperandSourceInfo()->getType());
}
void StmtProfiler::VisitCXXUuidofExpr(const CXXUuidofExpr *S) {
VisitExpr(S);
if (S->isTypeOperand())
- VisitType(S->getTypeOperand());
+ VisitType(S->getTypeOperandSourceInfo()->getType());
}
void StmtProfiler::VisitMSPropertyRefExpr(const MSPropertyRefExpr *S) {
@@ -822,9 +877,14 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) {
CEnd = S->explicit_capture_end();
C != CEnd; ++C) {
ID.AddInteger(C->getCaptureKind());
- if (C->capturesVariable()) {
+ switch (C->getCaptureKind()) {
+ case LCK_This:
+ break;
+ case LCK_ByRef:
+ case LCK_ByCopy:
VisitDecl(C->getCapturedVar());
ID.AddBoolean(C->isPackExpansion());
+ break;
}
}
// Note: If we actually needed to be able to match lambda
@@ -863,7 +923,14 @@ StmtProfiler::VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isArrow());
VisitNestedNameSpecifier(S->getQualifier());
- VisitType(S->getDestroyedType());
+ ID.AddBoolean(S->getScopeTypeInfo() != 0);
+ if (S->getScopeTypeInfo())
+ VisitType(S->getScopeTypeInfo()->getType());
+ ID.AddBoolean(S->getDestroyedTypeInfo() != 0);
+ if (S->getDestroyedTypeInfo())
+ VisitType(S->getDestroyedType());
+ else
+ ID.AddPointer(S->getDestroyedTypeIdentifier());
}
void StmtProfiler::VisitOverloadExpr(const OverloadExpr *S) {
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index d68b95e..16efb79 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -55,8 +55,8 @@ static void printIntegral(const TemplateArgument &TemplArg,
//===----------------------------------------------------------------------===//
TemplateArgument::TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value,
- QualType Type)
- : Kind(Integral) {
+ QualType Type) {
+ Integer.Kind = Integral;
// Copy the APSInt value into our decomposed form.
Integer.BitWidth = Value.getBitWidth();
Integer.IsUnsigned = Value.isUnsigned();
@@ -225,7 +225,7 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
}
Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
- assert(Kind == TemplateExpansion);
+ assert(getKind() == TemplateExpansion);
if (TemplateArg.NumExpansions)
return TemplateArg.NumExpansions - 1;
@@ -234,8 +234,8 @@ Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
const ASTContext &Context) const {
- ID.AddInteger(Kind);
- switch (Kind) {
+ ID.AddInteger(getKind());
+ switch (getKind()) {
case Null:
break;
@@ -243,6 +243,10 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
getAsType().Profile(ID);
break;
+ case NullPtr:
+ getNullPtrType().Profile(ID);
+ break;
+
case Declaration:
ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0);
break;
@@ -291,7 +295,7 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
case Template:
case TemplateExpansion:
case NullPtr:
- return TypeOrValue == Other.TypeOrValue;
+ return TypeOrValue.V == Other.TypeOrValue.V;
case Declaration:
return getAsDecl() == Other.getAsDecl() &&
@@ -353,9 +357,10 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
case Declaration: {
NamedDecl *ND = cast<NamedDecl>(getAsDecl());
+ Out << '&';
if (ND->getDeclName()) {
// FIXME: distinguish between pointer and reference args?
- Out << *ND;
+ ND->printQualifiedName(Out);
} else {
Out << "<anonymous>";
}
@@ -449,68 +454,6 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
llvm_unreachable("Invalid TemplateArgument Kind!");
}
-TemplateArgumentLoc TemplateArgumentLoc::getPackExpansionPattern(
- SourceLocation &Ellipsis, Optional<unsigned> &NumExpansions,
- ASTContext &Context) const {
- assert(Argument.isPackExpansion());
-
- switch (Argument.getKind()) {
- case TemplateArgument::Type: {
- // FIXME: We shouldn't ever have to worry about missing
- // type-source info!
- TypeSourceInfo *ExpansionTSInfo = getTypeSourceInfo();
- if (!ExpansionTSInfo)
- ExpansionTSInfo = Context.getTrivialTypeSourceInfo(
- getArgument().getAsType(),
- Ellipsis);
- PackExpansionTypeLoc Expansion =
- ExpansionTSInfo->getTypeLoc().castAs<PackExpansionTypeLoc>();
- Ellipsis = Expansion.getEllipsisLoc();
-
- TypeLoc Pattern = Expansion.getPatternLoc();
- NumExpansions = Expansion.getTypePtr()->getNumExpansions();
-
- // FIXME: This is horrible. We know where the source location data is for
- // the pattern, and we have the pattern's type, but we are forced to copy
- // them into an ASTContext because TypeSourceInfo bundles them together
- // and TemplateArgumentLoc traffics in TypeSourceInfo pointers.
- TypeSourceInfo *PatternTSInfo
- = Context.CreateTypeSourceInfo(Pattern.getType(),
- Pattern.getFullDataSize());
- memcpy(PatternTSInfo->getTypeLoc().getOpaqueData(),
- Pattern.getOpaqueData(), Pattern.getFullDataSize());
- return TemplateArgumentLoc(TemplateArgument(Pattern.getType()),
- PatternTSInfo);
- }
-
- case TemplateArgument::Expression: {
- PackExpansionExpr *Expansion
- = cast<PackExpansionExpr>(Argument.getAsExpr());
- Expr *Pattern = Expansion->getPattern();
- Ellipsis = Expansion->getEllipsisLoc();
- NumExpansions = Expansion->getNumExpansions();
- return TemplateArgumentLoc(Pattern, Pattern);
- }
-
- case TemplateArgument::TemplateExpansion:
- Ellipsis = getTemplateEllipsisLoc();
- NumExpansions = Argument.getNumTemplateExpansions();
- return TemplateArgumentLoc(Argument.getPackExpansionPattern(),
- getTemplateQualifierLoc(),
- getTemplateNameLoc());
-
- case TemplateArgument::Declaration:
- case TemplateArgument::NullPtr:
- case TemplateArgument::Template:
- case TemplateArgument::Integral:
- case TemplateArgument::Pack:
- case TemplateArgument::Null:
- return TemplateArgumentLoc();
- }
-
- llvm_unreachable("Invalid TemplateArgument Kind!");
-}
-
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
const TemplateArgument &Arg) {
switch (Arg.getKind()) {
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index fa16fac..7421bae 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -93,7 +93,7 @@ unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context,
if ((ElementSize >> 32) == 0 && NumElements.getBitWidth() <= 64 &&
(NumElements.getZExtValue() >> 32) == 0) {
uint64_t TotalSize = NumElements.getZExtValue() * ElementSize;
- return 64 - llvm::CountLeadingZeros_64(TotalSize);
+ return 64 - llvm::countLeadingZeros(TotalSize);
}
// Otherwise, use APSInt to handle arbitrary sized values.
@@ -111,11 +111,12 @@ unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context,
unsigned ConstantArrayType::getMaxSizeBits(ASTContext &Context) {
unsigned Bits = Context.getTypeSize(Context.getSizeType());
- // GCC appears to only allow 63 bits worth of address space when compiling
- // for 64-bit, so we do the same.
- if (Bits == 64)
- --Bits;
-
+ // Limit the number of bits in size_t so that maximal bit size fits 64 bit
+ // integer (see PR8256). We can do this as currently there is no hardware
+ // that supports full 64-bit virtual space.
+ if (Bits > 61)
+ Bits = 61;
+
return Bits;
}
@@ -337,6 +338,10 @@ template <> const TemplateSpecializationType *Type::getAs() const {
return getAsSugar<TemplateSpecializationType>(this);
}
+template <> const AttributedType *Type::getAs() const {
+ return getAsSugar<AttributedType>(this);
+}
+
/// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic
/// sugar off the given type. This should produce an object of the
/// same dynamic type as the canonical type.
@@ -357,23 +362,6 @@ const Type *Type::getUnqualifiedDesugaredType() const {
}
}
}
-
-bool Type::isDerivedType() const {
- switch (CanonicalType->getTypeClass()) {
- case Pointer:
- case VariableArray:
- case ConstantArray:
- case IncompleteArray:
- case FunctionProto:
- case FunctionNoProto:
- case LValueReference:
- case RValueReference:
- case Record:
- return true;
- default:
- return false;
- }
-}
bool Type::isClassType() const {
if (const RecordType *RT = getAs<RecordType>())
return RT->getDecl()->isClass();
@@ -750,9 +738,9 @@ bool Type::isSignedIntegerOrEnumerationType() const {
bool Type::hasSignedIntegerRepresentation() const {
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
- return VT->getElementType()->isSignedIntegerType();
+ return VT->getElementType()->isSignedIntegerOrEnumerationType();
else
- return isSignedIntegerType();
+ return isSignedIntegerOrEnumerationType();
}
/// isUnsignedIntegerType - Return true if this is an integer type that is
@@ -790,9 +778,9 @@ bool Type::isUnsignedIntegerOrEnumerationType() const {
bool Type::hasUnsignedIntegerRepresentation() const {
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
- return VT->getElementType()->isUnsignedIntegerType();
+ return VT->getElementType()->isUnsignedIntegerOrEnumerationType();
else
- return isUnsignedIntegerType();
+ return isUnsignedIntegerOrEnumerationType();
}
bool Type::isFloatingType() const {
@@ -1109,15 +1097,18 @@ bool QualType::isTriviallyCopyableType(ASTContext &Context) const {
}
}
- // C++0x [basic.types]p9
+ // C++11 [basic.types]p9
// Scalar types, trivially copyable class types, arrays of such types, and
- // cv-qualified versions of these types are collectively called trivial
- // types.
+ // non-volatile const-qualified versions of these types are collectively
+ // called trivially copyable types.
QualType CanonicalType = getCanonicalType();
if (CanonicalType->isDependentType())
return false;
+ if (CanonicalType.isVolatileQualified())
+ return false;
+
// Return false for incomplete types after skipping any incomplete array types
// which are expressly allowed by the standard and thus our API.
if (CanonicalType->isIncompleteType())
@@ -1142,7 +1133,7 @@ bool QualType::isTriviallyCopyableType(ASTContext &Context) const {
-bool Type::isLiteralType(ASTContext &Ctx) const {
+bool Type::isLiteralType(const ASTContext &Ctx) const {
if (isDependentType())
return false;
@@ -1196,6 +1187,15 @@ bool Type::isLiteralType(ASTContext &Ctx) const {
return true;
}
+ // We treat _Atomic T as a literal type if T is a literal type.
+ if (const AtomicType *AT = BaseTy->getAs<AtomicType>())
+ return AT->getValueType()->isLiteralType(Ctx);
+
+ // If this type hasn't been deduced yet, then conservatively assume that
+ // it'll work out to be a literal type.
+ if (isa<AutoType>(BaseTy->getCanonicalTypeInternal()))
+ return true;
+
return false;
}
@@ -1521,7 +1521,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case Double: return "double";
case LongDouble: return "long double";
case WChar_S:
- case WChar_U: return "wchar_t";
+ case WChar_U: return Policy.MSWChar ? "__wchar_t" : "wchar_t";
case Char16: return "char16_t";
case Char32: return "char32_t";
case NullPtr: return "nullptr_t";
@@ -1548,7 +1548,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
llvm_unreachable("Invalid builtin type.");
}
-QualType QualType::getNonLValueExprType(ASTContext &Context) const {
+QualType QualType::getNonLValueExprType(const ASTContext &Context) const {
if (const ReferenceType *RefType = getTypePtr()->getAs<ReferenceType>())
return RefType->getPointeeType();
@@ -1566,14 +1566,13 @@ QualType QualType::getNonLValueExprType(ASTContext &Context) const {
StringRef FunctionType::getNameForCallConv(CallingConv CC) {
switch (CC) {
- case CC_Default:
- llvm_unreachable("no name for default cc");
-
case CC_C: return "cdecl";
case CC_X86StdCall: return "stdcall";
case CC_X86FastCall: return "fastcall";
case CC_X86ThisCall: return "thiscall";
case CC_X86Pascal: return "pascal";
+ case CC_X86_64Win64: return "ms_abi";
+ case CC_X86_64SysV: return "sysv_abi";
case CC_AAPCS: return "aapcs";
case CC_AAPCS_VFP: return "aapcs-vfp";
case CC_PnaclCall: return "pnaclcall";
@@ -1664,7 +1663,7 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> args,
}
FunctionProtoType::NoexceptResult
-FunctionProtoType::getNoexceptSpec(ASTContext &ctx) const {
+FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const {
ExceptionSpecificationType est = getExceptionSpecType();
if (est == EST_BasicNoexcept)
return NR_Nothrow;
@@ -1849,6 +1848,49 @@ bool TagType::isBeingDefined() const {
return getDecl()->isBeingDefined();
}
+bool AttributedType::isMSTypeSpec() const {
+ switch (getAttrKind()) {
+ default: return false;
+ case attr_ptr32:
+ case attr_ptr64:
+ case attr_sptr:
+ case attr_uptr:
+ return true;
+ }
+ llvm_unreachable("invalid attr kind");
+}
+
+bool AttributedType::isCallingConv() const {
+ switch (getAttrKind()) {
+ case attr_ptr32:
+ case attr_ptr64:
+ case attr_sptr:
+ case attr_uptr:
+ case attr_address_space:
+ case attr_regparm:
+ case attr_vector_size:
+ case attr_neon_vector_type:
+ case attr_neon_polyvector_type:
+ case attr_objc_gc:
+ case attr_objc_ownership:
+ case attr_noreturn:
+ return false;
+ case attr_pcs:
+ case attr_pcs_vfp:
+ case attr_cdecl:
+ case attr_fastcall:
+ case attr_stdcall:
+ case attr_thiscall:
+ case attr_pascal:
+ case attr_ms_abi:
+ case attr_sysv_abi:
+ case attr_pnaclcall:
+ case attr_inteloclbicc:
+ return true;
+ }
+ llvm_unreachable("invalid attr kind");
+}
+
CXXRecordDecl *InjectedClassNameType::getDecl() const {
return cast<CXXRecordDecl>(getInterestingTagDecl(Decl));
}
@@ -1908,7 +1950,8 @@ anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N,
return false;
}
-bool TemplateSpecializationType::
+#ifndef NDEBUG
+static bool
anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N,
bool &InstantiationDependent) {
for (unsigned i = 0; i != N; ++i) {
@@ -1922,6 +1965,7 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N,
}
return false;
}
+#endif
TemplateSpecializationType::
TemplateSpecializationType(TemplateName T,
@@ -1945,8 +1989,8 @@ TemplateSpecializationType(TemplateName T,
(void)InstantiationDependent;
assert((!Canon.isNull() ||
T.isDependent() ||
- anyDependentTemplateArguments(Args, NumArgs,
- InstantiationDependent)) &&
+ ::anyDependentTemplateArguments(Args, NumArgs,
+ InstantiationDependent)) &&
"No canonical type for non-dependent class template specialization");
TemplateArgument *TemplateArgs
@@ -2124,7 +2168,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
// - it is a class or enumeration type that is named (or has a name
// for linkage purposes (7.1.3)) and the name has linkage; or
// - it is a specialization of a class template (14); or
- Linkage L = Tag->getLinkage();
+ Linkage L = Tag->getLinkageInternal();
bool IsLocalOrUnnamed =
Tag->getDeclContext()->isFunctionOrMethod() ||
!Tag->hasNameForLinkage();
@@ -2166,7 +2210,7 @@ static CachedProperties computeCachedProperties(const Type *T) {
return result;
}
case Type::ObjCInterface: {
- Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkage();
+ Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkageInternal();
return CachedProperties(L, false);
}
case Type::ObjCObject:
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 03d4030..22a51bc 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -41,12 +41,30 @@ SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) {
}
namespace {
+ class TypeAligner : public TypeLocVisitor<TypeAligner, unsigned> {
+ public:
+#define ABSTRACT_TYPELOC(CLASS, PARENT)
+#define TYPELOC(CLASS, PARENT) \
+ unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
+ return TyLoc.getLocalDataAlignment(); \
+ }
+#include "clang/AST/TypeLocNodes.def"
+ };
+}
+
+/// \brief Returns the alignment of the type source info data block.
+unsigned TypeLoc::getLocalAlignmentForType(QualType Ty) {
+ if (Ty.isNull()) return 1;
+ return TypeAligner().Visit(TypeLoc(Ty, 0));
+}
+
+namespace {
class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> {
public:
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
- return TyLoc.getFullDataSize(); \
+ return TyLoc.getLocalDataSize(); \
}
#include "clang/AST/TypeLocNodes.def"
};
@@ -54,8 +72,18 @@ namespace {
/// \brief Returns the size of the type source info data block.
unsigned TypeLoc::getFullDataSizeForType(QualType Ty) {
- if (Ty.isNull()) return 0;
- return TypeSizer().Visit(TypeLoc(Ty, 0));
+ unsigned Total = 0;
+ TypeLoc TyLoc(Ty, 0);
+ unsigned MaxAlign = 1;
+ while (!TyLoc.isNull()) {
+ unsigned Align = getLocalAlignmentForType(TyLoc.getType());
+ MaxAlign = std::max(Align, MaxAlign);
+ Total = llvm::RoundUpToAlignment(Total, Align);
+ Total += TypeSizer().Visit(TyLoc);
+ TyLoc = TyLoc.getNextTypeLoc();
+ }
+ Total = llvm::RoundUpToAlignment(Total, MaxAlign);
+ return Total;
}
namespace {
@@ -329,10 +357,13 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
for (unsigned i = 0, e = NumArgs; i != e; ++i) {
switch (Args[i].getKind()) {
case TemplateArgument::Null:
- case TemplateArgument::Declaration:
+ llvm_unreachable("Impossible TemplateArgument");
+
case TemplateArgument::Integral:
+ case TemplateArgument::Declaration:
case TemplateArgument::NullPtr:
- llvm_unreachable("Impossible TemplateArgument");
+ ArgInfos[i] = TemplateArgumentLocInfo();
+ break;
case TemplateArgument::Expression:
ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr());
@@ -347,18 +378,16 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion: {
NestedNameSpecifierLocBuilder Builder;
- TemplateName Template = Args[i].getAsTemplate();
+ TemplateName Template = Args[i].getAsTemplateOrTemplatePattern();
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
Builder.MakeTrivial(Context, DTN->getQualifier(), Loc);
else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
Builder.MakeTrivial(Context, QTN->getQualifier(), Loc);
-
+
ArgInfos[i] = TemplateArgumentLocInfo(
- Builder.getWithLocInContext(Context),
- Loc,
- Args[i].getKind() == TemplateArgument::Template
- ? SourceLocation()
- : Loc);
+ Builder.getWithLocInContext(Context), Loc,
+ Args[i].getKind() == TemplateArgument::Template ? SourceLocation()
+ : Loc);
break;
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 0437076..571e3db 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -36,7 +36,8 @@ namespace {
public:
explicit IncludeStrongLifetimeRAII(PrintingPolicy &Policy)
: Policy(Policy), Old(Policy.SuppressStrongLifetime) {
- Policy.SuppressStrongLifetime = false;
+ if (!Policy.SuppressLifetimeQualifiers)
+ Policy.SuppressStrongLifetime = false;
}
~IncludeStrongLifetimeRAII() {
@@ -81,10 +82,11 @@ namespace {
class TypePrinter {
PrintingPolicy Policy;
bool HasEmptyPlaceHolder;
+ bool InsideCCAttribute;
public:
explicit TypePrinter(const PrintingPolicy &Policy)
- : Policy(Policy), HasEmptyPlaceHolder(false) { }
+ : Policy(Policy), HasEmptyPlaceHolder(false), InsideCCAttribute(false) { }
void print(const Type *ty, Qualifiers qs, raw_ostream &OS,
StringRef PlaceHolder);
@@ -166,6 +168,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
TC = Subst->getReplacementType()->getTypeClass();
switch (TC) {
+ case Type::Auto:
case Type::Builtin:
case Type::Complex:
case Type::UnresolvedUsing:
@@ -201,6 +204,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
NeedARCStrongQualifier = true;
// Fall through
+ case Type::Decayed:
case Type::Pointer:
case Type::BlockPointer:
case Type::LValueReference:
@@ -215,7 +219,6 @@ bool TypePrinter::canPrefixQualifiers(const Type *T,
case Type::Attributed:
case Type::PackExpansion:
case Type::SubstTemplateTypeParm:
- case Type::Auto:
CanPrefixQualifiers = false;
break;
}
@@ -468,6 +471,14 @@ void TypePrinter::printVariableArrayAfter(const VariableArrayType *T,
printAfter(T->getElementType(), OS);
}
+void TypePrinter::printDecayedBefore(const DecayedType *T, raw_ostream &OS) {
+ // Print as though it's a pointer.
+ printBefore(T->getDecayedType(), OS);
+}
+void TypePrinter::printDecayedAfter(const DecayedType *T, raw_ostream &OS) {
+ printAfter(T->getDecayedType(), OS);
+}
+
void TypePrinter::printDependentSizedArrayBefore(
const DependentSizedArrayType *T,
raw_ostream &OS) {
@@ -621,36 +632,51 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
OS << ')';
FunctionType::ExtInfo Info = T->getExtInfo();
- switch(Info.getCC()) {
- case CC_Default: break;
- case CC_C:
- OS << " __attribute__((cdecl))";
- break;
- case CC_X86StdCall:
- OS << " __attribute__((stdcall))";
- break;
- case CC_X86FastCall:
- OS << " __attribute__((fastcall))";
- break;
- case CC_X86ThisCall:
- OS << " __attribute__((thiscall))";
- break;
- case CC_X86Pascal:
- OS << " __attribute__((pascal))";
- break;
- case CC_AAPCS:
- OS << " __attribute__((pcs(\"aapcs\")))";
- break;
- case CC_AAPCS_VFP:
- OS << " __attribute__((pcs(\"aapcs-vfp\")))";
- break;
- case CC_PnaclCall:
- OS << " __attribute__((pnaclcall))";
- break;
- case CC_IntelOclBicc:
- OS << " __attribute__((intel_ocl_bicc))";
- break;
+
+ if (!InsideCCAttribute) {
+ switch (Info.getCC()) {
+ case CC_C:
+ // The C calling convention is the default on the vast majority of platforms
+ // we support. If the user wrote it explicitly, it will usually be printed
+ // while traversing the AttributedType. If the type has been desugared, let
+ // the canonical spelling be the implicit calling convention.
+ // FIXME: It would be better to be explicit in certain contexts, such as a
+ // cdecl function typedef used to declare a member function with the
+ // Microsoft C++ ABI.
+ break;
+ case CC_X86StdCall:
+ OS << " __attribute__((stdcall))";
+ break;
+ case CC_X86FastCall:
+ OS << " __attribute__((fastcall))";
+ break;
+ case CC_X86ThisCall:
+ OS << " __attribute__((thiscall))";
+ break;
+ case CC_X86Pascal:
+ OS << " __attribute__((pascal))";
+ break;
+ case CC_AAPCS:
+ OS << " __attribute__((pcs(\"aapcs\")))";
+ break;
+ case CC_AAPCS_VFP:
+ OS << " __attribute__((pcs(\"aapcs-vfp\")))";
+ break;
+ case CC_PnaclCall:
+ OS << " __attribute__((pnaclcall))";
+ break;
+ case CC_IntelOclBicc:
+ OS << " __attribute__((intel_ocl_bicc))";
+ break;
+ case CC_X86_64Win64:
+ OS << " __attribute__((ms_abi))";
+ break;
+ case CC_X86_64SysV:
+ OS << " __attribute__((sysv_abi))";
+ break;
+ }
}
+
if (Info.getNoReturn())
OS << " __attribute__((noreturn))";
if (Info.getRegParm())
@@ -989,6 +1015,8 @@ void TypePrinter::printInjectedClassNameAfter(const InjectedClassNameType *T,
void TypePrinter::printElaboratedBefore(const ElaboratedType *T,
raw_ostream &OS) {
+ if (Policy.SuppressTag && isa<TagType>(T->getNamedType()))
+ return;
OS << TypeWithKeyword::getKeywordName(T->getKeyword());
if (T->getKeyword() != ETK_None)
OS << " ";
@@ -1072,6 +1100,17 @@ void TypePrinter::printAttributedBefore(const AttributedType *T,
return printBefore(T->getEquivalentType(), OS);
printBefore(T->getModifiedType(), OS);
+
+ if (T->isMSTypeSpec()) {
+ switch (T->getAttrKind()) {
+ default: return;
+ case AttributedType::attr_ptr32: OS << " __ptr32"; break;
+ case AttributedType::attr_ptr64: OS << " __ptr64"; break;
+ case AttributedType::attr_sptr: OS << " __sptr"; break;
+ case AttributedType::attr_uptr: OS << " __uptr"; break;
+ }
+ spaceBeforePlaceHolder(OS);
+ }
}
void TypePrinter::printAttributedAfter(const AttributedType *T,
@@ -1082,8 +1121,18 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
return printAfter(T->getEquivalentType(), OS);
// TODO: not all attributes are GCC-style attributes.
+ if (T->isMSTypeSpec())
+ return;
+
+ // If this is a calling convention attribute, don't print the implicit CC from
+ // the modified type.
+ SaveAndRestore<bool> MaybeSuppressCC(InsideCCAttribute, T->isCallingConv());
+
+ printAfter(T->getModifiedType(), OS);
+
OS << " __attribute__((";
switch (T->getAttrKind()) {
+ default: llvm_unreachable("This attribute should have been handled already");
case AttributedType::attr_address_space:
OS << "address_space(";
OS << T->getEquivalentType().getAddressSpace();
@@ -1115,6 +1164,8 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
}
case AttributedType::attr_regparm: {
+ // FIXME: When Sema learns to form this AttributedType, avoid printing the
+ // attribute again in printFunctionProtoAfter.
OS << "regparm(";
QualType t = T->getEquivalentType();
while (!t->isFunctionType())
@@ -1154,13 +1205,19 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
OS << ')';
break;
+ // FIXME: When Sema learns to form this AttributedType, avoid printing the
+ // attribute again in printFunctionProtoAfter.
case AttributedType::attr_noreturn: OS << "noreturn"; break;
+
case AttributedType::attr_cdecl: OS << "cdecl"; break;
case AttributedType::attr_fastcall: OS << "fastcall"; break;
case AttributedType::attr_stdcall: OS << "stdcall"; break;
case AttributedType::attr_thiscall: OS << "thiscall"; break;
case AttributedType::attr_pascal: OS << "pascal"; break;
- case AttributedType::attr_pcs: {
+ case AttributedType::attr_ms_abi: OS << "ms_abi"; break;
+ case AttributedType::attr_sysv_abi: OS << "sysv_abi"; break;
+ case AttributedType::attr_pcs:
+ case AttributedType::attr_pcs_vfp: {
OS << "pcs(";
QualType t = T->getEquivalentType();
while (!t->isFunctionType())
@@ -1266,18 +1323,19 @@ TemplateSpecializationType::PrintTemplateArgumentList(
bool needSpace = false;
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (Arg > 0)
- OS << ", ";
-
// Print the argument into a string.
SmallString<128> Buf;
llvm::raw_svector_ostream ArgOS(Buf);
if (Args[Arg].getKind() == TemplateArgument::Pack) {
+ if (Args[Arg].pack_size() && Arg > 0)
+ OS << ", ";
PrintTemplateArgumentList(ArgOS,
Args[Arg].pack_begin(),
Args[Arg].pack_size(),
Policy, true);
} else {
+ if (Arg > 0)
+ OS << ", ";
Args[Arg].print(Policy, ArgOS);
}
StringRef ArgString = ArgOS.str();
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index f80232f..5f7ae0f 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -34,7 +34,8 @@ struct BaseOffset {
const CXXRecordDecl *DerivedClass;
/// VirtualBase - If the path from the derived class to the base class
- /// involves a virtual base class, this holds its declaration.
+ /// involves virtual base classes, this holds the declaration of the last
+ /// virtual base in this path (i.e. closest to the base class).
const CXXRecordDecl *VirtualBase;
/// NonVirtualOffset - The offset from the derived class to the base class.
@@ -62,7 +63,7 @@ public:
/// Method - The method decl of the overrider.
const CXXMethodDecl *Method;
- /// Offset - the base offset of the overrider in the layout class.
+ /// Offset - the base offset of the overrider's parent in the layout class.
CharUnits Offset;
OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { }
@@ -146,8 +147,6 @@ public:
};
-#define DUMP_OVERRIDERS 0
-
FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
CharUnits MostDerivedClassOffset,
const CXXRecordDecl *LayoutClass)
@@ -219,16 +218,14 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context,
const CXXRecordDecl *VirtualBase = 0;
// First, look for the virtual base class.
- for (unsigned I = 0, E = Path.size(); I != E; ++I) {
- const CXXBasePathElement &Element = Path[I];
-
+ for (int I = Path.size(), E = 0; I != E; --I) {
+ const CXXBasePathElement &Element = Path[I - 1];
+
if (Element.Base->isVirtual()) {
- // FIXME: Can we break when we find the first virtual base?
- // (If we can't, can't we just iterate over the path in reverse order?)
- NonVirtualStart = I + 1;
+ NonVirtualStart = I;
QualType VBaseType = Element.Base->getType();
- VirtualBase =
- cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
+ VirtualBase = VBaseType->getAsCXXRecordDecl();
+ break;
}
}
@@ -239,8 +236,7 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context,
// Check the base class offset.
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
- const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
- const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
+ const CXXRecordDecl *Base = Element.Base->getType()->getAsCXXRecordDecl();
NonVirtualOffset += Layout.getBaseClassOffset(Base);
}
@@ -343,8 +339,7 @@ FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual,
// Traverse our bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
CharUnits BaseOffset;
CharUnits BaseOffsetInLayoutClass;
@@ -381,8 +376,7 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
// Ignore bases that don't have any virtual member functions.
if (!BaseDecl->isPolymorphic())
@@ -418,7 +412,7 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base,
Out << " " << MD->getQualifiedNameAsString() << " - (";
Out << Overrider.Method->getQualifiedNameAsString();
- Out << ", " << ", " << Overrider.Offset.getQuantity() << ')';
+ Out << ", " << Overrider.Offset.getQuantity() << ')';
BaseOffset Offset;
if (!Overrider.Method->isPure())
@@ -727,8 +721,7 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base,
if (I->isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
if (BaseDecl == PrimaryBase)
continue;
@@ -750,8 +743,7 @@ VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
// Add vbase offsets.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
// Check if this is a virtual base that we haven't visited before.
if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) {
@@ -775,8 +767,8 @@ VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD,
}
}
-/// VTableBuilder - Class for building vtable layout information.
-class VTableBuilder {
+/// ItaniumVTableBuilder - Class for building vtable layout information.
+class ItaniumVTableBuilder {
public:
/// PrimaryBasesSetVectorTy - A set vector of direct and indirect
/// primary bases.
@@ -789,9 +781,11 @@ public:
typedef llvm::DenseMap<BaseSubobject, uint64_t>
AddressPointsMapTy;
+ typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy;
+
private:
/// VTables - Global vtable information.
- VTableContext &VTables;
+ ItaniumVTableContext &VTables;
/// MostDerivedClass - The most derived class for which we're building this
/// vtable.
@@ -861,7 +855,11 @@ private:
/// MethodInfoMap - The information for all methods in the vtable we're
/// currently building.
MethodInfoMapTy MethodInfoMap;
-
+
+ /// MethodVTableIndices - Contains the index (relative to the vtable address
+ /// point) where the function pointer for a virtual function is stored.
+ MethodVTableIndicesTy MethodVTableIndices;
+
typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
/// VTableThunks - The thunks by vtable index in the vtable currently being
@@ -984,24 +982,22 @@ private:
}
public:
- VTableBuilder(VTableContext &VTables, const CXXRecordDecl *MostDerivedClass,
- CharUnits MostDerivedClassOffset,
- bool MostDerivedClassIsVirtual, const
- CXXRecordDecl *LayoutClass)
- : VTables(VTables), MostDerivedClass(MostDerivedClass),
- MostDerivedClassOffset(MostDerivedClassOffset),
- MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
- LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
- Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
+ ItaniumVTableBuilder(ItaniumVTableContext &VTables,
+ const CXXRecordDecl *MostDerivedClass,
+ CharUnits MostDerivedClassOffset,
+ bool MostDerivedClassIsVirtual,
+ const CXXRecordDecl *LayoutClass)
+ : VTables(VTables), MostDerivedClass(MostDerivedClass),
+ MostDerivedClassOffset(MostDerivedClassOffset),
+ MostDerivedClassIsVirtual(MostDerivedClassIsVirtual),
+ LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()),
+ Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
+ assert(!Context.getTargetInfo().getCXXABI().isMicrosoft());
LayoutVTable();
if (Context.getLangOpts().DumpVTableLayouts)
- dumpLayout(llvm::errs());
- }
-
- bool isMicrosoftABI() const {
- return VTables.isMicrosoftABI();
+ dumpLayout(llvm::outs());
}
uint64_t getNumThunks() const {
@@ -1024,6 +1020,14 @@ public:
return AddressPoints;
}
+ MethodVTableIndicesTy::const_iterator vtable_indices_begin() const {
+ return MethodVTableIndices.begin();
+ }
+
+ MethodVTableIndicesTy::const_iterator vtable_indices_end() const {
+ return MethodVTableIndices.end();
+ }
+
/// getNumVTableComponents - Return the number of components in the vtable
/// currently built.
uint64_t getNumVTableComponents() const {
@@ -1058,12 +1062,13 @@ public:
void dumpLayout(raw_ostream&);
};
-void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
+void ItaniumVTableBuilder::AddThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk) {
assert(!isBuildingConstructorVTable() &&
"Can't add thunks for construction vtable");
- SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
-
+ SmallVectorImpl<ThunkInfo> &ThunksVector = Thunks[MD];
+
// Check if we have this thunk already.
if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
ThunksVector.end())
@@ -1074,24 +1079,45 @@ void VTableBuilder::AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
typedef llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverriddenMethodsSetTy;
-/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all
-/// the overridden methods that the function decl overrides.
-static void
-ComputeAllOverriddenMethods(const CXXMethodDecl *MD,
- OverriddenMethodsSetTy& OverriddenMethods) {
+/// Visit all the methods overridden by the given method recursively,
+/// in a depth-first pre-order. The Visitor's visitor method returns a bool
+/// indicating whether to continue the recursion for the given overridden
+/// method (i.e. returning false stops the iteration).
+template <class VisitorTy>
+static void
+visitAllOverriddenMethods(const CXXMethodDecl *MD, VisitorTy &Visitor) {
assert(MD->isVirtual() && "Method is not virtual!");
for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
E = MD->end_overridden_methods(); I != E; ++I) {
const CXXMethodDecl *OverriddenMD = *I;
-
- OverriddenMethods.insert(OverriddenMD);
-
- ComputeAllOverriddenMethods(OverriddenMD, OverriddenMethods);
+ if (!Visitor.visit(OverriddenMD))
+ continue;
+ visitAllOverriddenMethods(OverriddenMD, Visitor);
}
}
-void VTableBuilder::ComputeThisAdjustments() {
+namespace {
+ struct OverriddenMethodsCollector {
+ OverriddenMethodsSetTy *Methods;
+
+ bool visit(const CXXMethodDecl *MD) {
+ // Don't recurse on this method if we've already collected it.
+ return Methods->insert(MD);
+ }
+ };
+}
+
+/// ComputeAllOverriddenMethods - Given a method decl, will return a set of all
+/// the overridden methods that the function decl overrides.
+static void
+ComputeAllOverriddenMethods(const CXXMethodDecl *MD,
+ OverriddenMethodsSetTy& OverriddenMethods) {
+ OverriddenMethodsCollector Collector = { &OverriddenMethods };
+ visitAllOverriddenMethods(MD, Collector);
+}
+
+void ItaniumVTableBuilder::ComputeThisAdjustments() {
// Now go through the method info map and see if any of the methods need
// 'this' pointer adjustments.
for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
@@ -1160,8 +1186,6 @@ void VTableBuilder::ComputeThisAdjustments() {
break;
case VTableComponent::CK_DeletingDtorPointer:
// We've already added the thunk when we saw the complete dtor pointer.
- // FIXME: check how this works in the Microsoft ABI
- // while working on the multiple inheritance patch.
continue;
}
@@ -1170,7 +1194,8 @@ void VTableBuilder::ComputeThisAdjustments() {
}
}
-ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
+ReturnAdjustment
+ItaniumVTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
ReturnAdjustment Adjustment;
if (!Offset.isEmpty()) {
@@ -1178,10 +1203,10 @@ ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
// Get the virtual base offset offset.
if (Offset.DerivedClass == MostDerivedClass) {
// We can get the offset offset directly from our map.
- Adjustment.VBaseOffsetOffset =
+ Adjustment.Virtual.Itanium.VBaseOffsetOffset =
VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity();
} else {
- Adjustment.VBaseOffsetOffset =
+ Adjustment.Virtual.Itanium.VBaseOffsetOffset =
VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass,
Offset.VirtualBase).getQuantity();
}
@@ -1193,9 +1218,8 @@ ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) {
return Adjustment;
}
-BaseOffset
-VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
- BaseSubobject Derived) const {
+BaseOffset ItaniumVTableBuilder::ComputeThisAdjustmentBaseOffset(
+ BaseSubobject Base, BaseSubobject Derived) const {
const CXXRecordDecl *BaseRD = Base.getBase();
const CXXRecordDecl *DerivedRD = Derived.getBase();
@@ -1240,11 +1264,10 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
return BaseOffset();
}
-
-ThisAdjustment
-VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
- CharUnits BaseOffsetInLayoutClass,
- FinalOverriders::OverriderInfo Overrider) {
+
+ThisAdjustment ItaniumVTableBuilder::ComputeThisAdjustment(
+ const CXXMethodDecl *MD, CharUnits BaseOffsetInLayoutClass,
+ FinalOverriders::OverriderInfo Overrider) {
// Ignore adjustments for pure virtual member functions.
if (Overrider.Method->isPure())
return ThisAdjustment();
@@ -1281,7 +1304,7 @@ VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
VCallOffsets = Builder.getVCallOffsets();
}
- Adjustment.VCallOffsetOffset =
+ Adjustment.Virtual.Itanium.VCallOffsetOffset =
VCallOffsets.getVCallOffsetOffset(MD).getQuantity();
}
@@ -1290,23 +1313,16 @@ VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD,
return Adjustment;
}
-
-void
-VTableBuilder::AddMethod(const CXXMethodDecl *MD,
- ReturnAdjustment ReturnAdjustment) {
+
+void ItaniumVTableBuilder::AddMethod(const CXXMethodDecl *MD,
+ ReturnAdjustment ReturnAdjustment) {
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
assert(ReturnAdjustment.isEmpty() &&
"Destructor can't have return adjustment!");
- // FIXME: Should probably add a layer of abstraction for vtable generation.
- if (!isMicrosoftABI()) {
- // Add both the complete destructor and the deleting destructor.
- Components.push_back(VTableComponent::MakeCompleteDtor(DD));
- Components.push_back(VTableComponent::MakeDeletingDtor(DD));
- } else {
- // Add the scalar deleting destructor.
- Components.push_back(VTableComponent::MakeDeletingDtor(DD));
- }
+ // Add both the complete destructor and the deleting destructor.
+ Components.push_back(VTableComponent::MakeCompleteDtor(DD));
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
} else {
// Add the return adjustment if necessary.
if (!ReturnAdjustment.isEmpty())
@@ -1328,9 +1344,9 @@ VTableBuilder::AddMethod(const CXXMethodDecl *MD,
///
/// OverridesIndirectMethodInBase will return true if given C::f as the method
/// and { A } as the set of bases.
-static bool
-OverridesIndirectMethodInBases(const CXXMethodDecl *MD,
- VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
+static bool OverridesIndirectMethodInBases(
+ const CXXMethodDecl *MD,
+ ItaniumVTableBuilder::PrimaryBasesSetVectorTy &Bases) {
if (Bases.count(MD->getParent()))
return true;
@@ -1346,11 +1362,10 @@ OverridesIndirectMethodInBases(const CXXMethodDecl *MD,
return false;
}
-bool
-VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
- CharUnits BaseOffsetInLayoutClass,
- const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- CharUnits FirstBaseOffsetInLayoutClass) const {
+bool ItaniumVTableBuilder::IsOverriderUsed(
+ const CXXMethodDecl *Overrider, CharUnits BaseOffsetInLayoutClass,
+ const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
+ CharUnits FirstBaseOffsetInLayoutClass) const {
// If the base and the first base in the primary base chain have the same
// offsets, then this overrider will be used.
if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass)
@@ -1364,8 +1379,8 @@ VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
// that the overrider will be used.
if (Overrider->getParent() == FirstBaseInPrimaryBaseChain)
return true;
-
- VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
+
+ ItaniumVTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
const CXXRecordDecl *RD = FirstBaseInPrimaryBaseChain;
PrimaryBases.insert(RD);
@@ -1409,18 +1424,21 @@ VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider,
return OverridesIndirectMethodInBases(Overrider, PrimaryBases);
}
+typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> BasesSetVectorTy;
+
/// FindNearestOverriddenMethod - Given a method, returns the overridden method
/// from the nearest base. Returns null if no method was found.
-static const CXXMethodDecl *
+/// The Bases are expected to be sorted in a base-to-derived order.
+static const CXXMethodDecl *
FindNearestOverriddenMethod(const CXXMethodDecl *MD,
- VTableBuilder::PrimaryBasesSetVectorTy &Bases) {
+ BasesSetVectorTy &Bases) {
OverriddenMethodsSetTy OverriddenMethods;
ComputeAllOverriddenMethods(MD, OverriddenMethods);
for (int I = Bases.size(), E = 0; I != E; --I) {
const CXXRecordDecl *PrimaryBase = Bases[I - 1];
- // Now check the overriden methods.
+ // Now check the overridden methods.
for (OverriddenMethodsSetTy::const_iterator I = OverriddenMethods.begin(),
E = OverriddenMethods.end(); I != E; ++I) {
const CXXMethodDecl *OverriddenMD = *I;
@@ -1432,13 +1450,22 @@ FindNearestOverriddenMethod(const CXXMethodDecl *MD,
}
return 0;
-}
+}
+
+void ItaniumVTableBuilder::AddMethods(
+ BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
+ const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
+ CharUnits FirstBaseOffsetInLayoutClass,
+ PrimaryBasesSetVectorTy &PrimaryBases) {
+ // Itanium C++ ABI 2.5.2:
+ // The order of the virtual function pointers in a virtual table is the
+ // order of declaration of the corresponding member functions in the class.
+ //
+ // There is an entry for any virtual function declared in a class,
+ // whether it is a new function or overrides a base class function,
+ // unless it overrides a function from the primary base, and conversion
+ // between their return types does not require an adjustment.
-void
-VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
- const CXXRecordDecl *FirstBaseInPrimaryBaseChain,
- CharUnits FirstBaseOffsetInLayoutClass,
- PrimaryBasesSetVectorTy &PrimaryBases) {
const CXXRecordDecl *RD = Base.getBase();
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -1476,6 +1503,11 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
llvm_unreachable("Found a duplicate primary base!");
}
+ const CXXDestructorDecl *ImplicitVirtualDtor = 0;
+
+ typedef llvm::SmallVector<const CXXMethodDecl *, 8> NewVirtualFunctionsTy;
+ NewVirtualFunctionsTy NewVirtualFunctions;
+
// Now go through all virtual member functions and add them.
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
@@ -1520,7 +1552,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
ComputeThisAdjustment(OverriddenMD, BaseOffsetInLayoutClass,
Overrider);
- if (ThisAdjustment.VCallOffsetOffset &&
+ if (ThisAdjustment.Virtual.Itanium.VCallOffsetOffset &&
Overrider.Method->getParent() == MostDerivedClass) {
// There's no return adjustment from OverriddenMD and MD,
@@ -1541,6 +1573,33 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
}
}
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ if (MD->isImplicit()) {
+ // Itanium C++ ABI 2.5.2:
+ // If a class has an implicitly-defined virtual destructor,
+ // its entries come after the declared virtual function pointers.
+
+ assert(!ImplicitVirtualDtor &&
+ "Did already see an implicit virtual dtor!");
+ ImplicitVirtualDtor = DD;
+ continue;
+ }
+ }
+
+ NewVirtualFunctions.push_back(MD);
+ }
+
+ if (ImplicitVirtualDtor)
+ NewVirtualFunctions.push_back(ImplicitVirtualDtor);
+
+ for (NewVirtualFunctionsTy::const_iterator I = NewVirtualFunctions.begin(),
+ E = NewVirtualFunctions.end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ // Get the final overrider.
+ FinalOverriders::OverriderInfo Overrider =
+ Overriders.getOverrider(MD, Base.getBaseOffset());
+
// Insert the method info for this method.
MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass,
Components.size());
@@ -1557,7 +1616,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
Components.push_back(VTableComponent::MakeUnusedFunction(OverriderMD));
continue;
}
-
+
// Check if this overrider needs a return adjustment.
// We don't want to do this for pure virtual member functions.
BaseOffset ReturnAdjustmentOffset;
@@ -1573,7 +1632,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass,
}
}
-void VTableBuilder::LayoutVTable() {
+void ItaniumVTableBuilder::LayoutVTable() {
LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass,
CharUnits::Zero()),
/*BaseIsMorallyVirtual=*/false,
@@ -1594,12 +1653,10 @@ void VTableBuilder::LayoutVTable() {
if (IsAppleKext)
Components.push_back(VTableComponent::MakeVCallOffset(CharUnits::Zero()));
}
-
-void
-VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
- bool BaseIsVirtualInLayoutClass,
- CharUnits OffsetInLayoutClass) {
+
+void ItaniumVTableBuilder::LayoutPrimaryAndSecondaryVTables(
+ BaseSubobject Base, bool BaseIsMorallyVirtual,
+ bool BaseIsVirtualInLayoutClass, CharUnits OffsetInLayoutClass) {
assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!");
// Add vcall and vbase offsets for this vtable.
@@ -1621,18 +1678,12 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
if (Base.getBase() == MostDerivedClass)
VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
- // FIXME: Should probably add a layer of abstraction for vtable generation.
- if (!isMicrosoftABI()) {
- // Add the offset to top.
- CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
- Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
+ // Add the offset to top.
+ CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
+ Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
- // Next, add the RTTI.
- Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
- } else {
- // FIXME: unclear what to do with RTTI in MS ABI as emitting it anywhere
- // breaks the vftable layout. Just skip RTTI for now, can't mangle anyway.
- }
+ // Next, add the RTTI.
+ Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
uint64_t AddressPoint = Components.size();
@@ -1642,11 +1693,28 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
Base.getBase(), OffsetInLayoutClass,
PrimaryBases);
+ const CXXRecordDecl *RD = Base.getBase();
+ if (RD == MostDerivedClass) {
+ assert(MethodVTableIndices.empty());
+ for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
+ E = MethodInfoMap.end(); I != E; ++I) {
+ const CXXMethodDecl *MD = I->first;
+ const MethodInfo &MI = I->second;
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)]
+ = MI.VTableIndex - AddressPoint;
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)]
+ = MI.VTableIndex + 1 - AddressPoint;
+ } else {
+ MethodVTableIndices[MD] = MI.VTableIndex - AddressPoint;
+ }
+ }
+ }
+
// Compute 'this' pointer adjustments.
ComputeThisAdjustments();
// Add all address points.
- const CXXRecordDecl *RD = Base.getBase();
while (true) {
AddressPoints.insert(std::make_pair(
BaseSubobject(RD, OffsetInLayoutClass),
@@ -1678,9 +1746,10 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
LayoutSecondaryVTables(Base, BaseIsMorallyVirtual, OffsetInLayoutClass);
}
-void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
- bool BaseIsMorallyVirtual,
- CharUnits OffsetInLayoutClass) {
+void
+ItaniumVTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
+ bool BaseIsMorallyVirtual,
+ CharUnits OffsetInLayoutClass) {
// Itanium C++ ABI 2.5.2:
// Following the primary virtual table of a derived class are secondary
// virtual tables for each of its proper base classes, except any primary
@@ -1696,8 +1765,7 @@ void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
if (I->isVirtual())
continue;
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
// Ignore bases that don't have a vtable.
if (!BaseDecl->isDynamicClass())
@@ -1737,10 +1805,9 @@ void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base,
}
}
-void
-VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
- CharUnits OffsetInLayoutClass,
- VisitedVirtualBasesSetTy &VBases) {
+void ItaniumVTableBuilder::DeterminePrimaryVirtualBases(
+ const CXXRecordDecl *RD, CharUnits OffsetInLayoutClass,
+ VisitedVirtualBasesSetTy &VBases) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
// Check if this base has a primary base.
@@ -1773,8 +1840,7 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
// Traverse bases, looking for more primary virtual bases.
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
CharUnits BaseOffsetInLayoutClass;
@@ -1796,17 +1862,15 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD,
}
}
-void
-VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
- VisitedVirtualBasesSetTy &VBases) {
+void ItaniumVTableBuilder::LayoutVTablesForVirtualBases(
+ const CXXRecordDecl *RD, VisitedVirtualBasesSetTy &VBases) {
// Itanium C++ ABI 2.5.2:
// Then come the virtual base virtual tables, also in inheritance graph
// order, and again excluding primary bases (which share virtual tables with
// the classes for which they are primary).
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
E = RD->bases_end(); I != E; ++I) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
// Check if this base needs a vtable. (If it's virtual, not a primary base
// of some other class, and we haven't visited it before).
@@ -1836,8 +1900,25 @@ VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD,
}
}
+struct ItaniumThunkInfoComparator {
+ bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ assert(LHS.Method == 0);
+ assert(RHS.Method == 0);
+
+ if (LHS.This != RHS.This)
+ return LHS.This < RHS.This;
+
+ if (LHS.Return != RHS.Return)
+ return LHS.Return < RHS.Return;
+
+ return false;
+ }
+};
+
/// dumpLayout - Dump the vtable layout.
-void VTableBuilder::dumpLayout(raw_ostream& Out) {
+void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) {
+ // FIXME: write more tests that actually use the dumpLayout output to prevent
+ // ItaniumVTableBuilder regressions.
if (isBuildingConstructorVTable()) {
Out << "Construction vtable for ('";
@@ -1915,8 +1996,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << "\n [return adjustment: ";
Out << Thunk.Return.NonVirtual << " non-virtual";
- if (Thunk.Return.VBaseOffsetOffset) {
- Out << ", " << Thunk.Return.VBaseOffsetOffset;
+ if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) {
+ Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset;
Out << " vbase offset offset";
}
@@ -1928,8 +2009,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << "\n [this adjustment: ";
Out << Thunk.This.NonVirtual << " non-virtual";
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
+ if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
Out << " vcall offset offset";
}
@@ -1950,8 +2031,6 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << DD->getQualifiedNameAsString();
if (IsComplete)
Out << "() [complete]";
- else if (isMicrosoftABI())
- Out << "() [scalar deleting]";
else
Out << "() [deleting]";
@@ -1965,8 +2044,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << "\n [this adjustment: ";
Out << Thunk.This.NonVirtual << " non-virtual";
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
+ if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
Out << " vcall offset offset";
}
@@ -2078,7 +2157,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
const CXXMethodDecl *MD = I->second;
ThunkInfoVectorTy ThunksVector = Thunks[MD];
- std::sort(ThunksVector.begin(), ThunksVector.end());
+ std::sort(ThunksVector.begin(), ThunksVector.end(),
+ ItaniumThunkInfoComparator());
Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
@@ -2090,10 +2170,10 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
// If this function pointer has a return pointer adjustment, dump it.
if (!Thunk.Return.isEmpty()) {
- Out << "return adjustment: " << Thunk.This.NonVirtual;
+ Out << "return adjustment: " << Thunk.Return.NonVirtual;
Out << " non-virtual";
- if (Thunk.Return.VBaseOffsetOffset) {
- Out << ", " << Thunk.Return.VBaseOffsetOffset;
+ if (Thunk.Return.Virtual.Itanium.VBaseOffsetOffset) {
+ Out << ", " << Thunk.Return.Virtual.Itanium.VBaseOffsetOffset;
Out << " vbase offset offset";
}
@@ -2106,8 +2186,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << "this adjustment: ";
Out << Thunk.This.NonVirtual << " non-virtual";
- if (Thunk.This.VCallOffsetOffset) {
- Out << ", " << Thunk.This.VCallOffsetOffset;
+ if (Thunk.This.Virtual.Itanium.VCallOffsetOffset) {
+ Out << ", " << Thunk.This.Virtual.Itanium.VCallOffsetOffset;
Out << " vcall offset offset";
}
}
@@ -2136,18 +2216,14 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
MD);
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- // FIXME: Should add a layer of abstraction for vtable generation.
- if (!isMicrosoftABI()) {
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))]
- = MethodName + " [complete]";
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
- = MethodName + " [deleting]";
- } else {
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
- = MethodName + " [scalar deleting]";
- }
+ GlobalDecl GD(DD, Dtor_Complete);
+ assert(MethodVTableIndices.count(GD));
+ uint64_t VTableIndex = MethodVTableIndices[GD];
+ IndicesMap[VTableIndex] = MethodName + " [complete]";
+ IndicesMap[VTableIndex + 1] = MethodName + " [deleting]";
} else {
- IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
+ assert(MethodVTableIndices.count(MD));
+ IndicesMap[MethodVTableIndices[MD]] = MethodName;
}
}
@@ -2162,14 +2238,24 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
uint64_t VTableIndex = I->first;
const std::string &MethodName = I->second;
- Out << llvm::format(" %4" PRIu64 " | ", VTableIndex) << MethodName
+ Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName
<< '\n';
}
}
Out << '\n';
}
-
+
+struct VTableThunksComparator {
+ bool operator()(const VTableLayout::VTableThunkTy &LHS,
+ const VTableLayout::VTableThunkTy &RHS) {
+ if (LHS.first == RHS.first) {
+ assert(LHS.second == RHS.second &&
+ "Different thunks should have unique indices!");
+ }
+ return LHS.first < RHS.first;
+ }
+};
}
VTableLayout::VTableLayout(uint64_t NumVTableComponents,
@@ -2188,183 +2274,38 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
this->VTableComponents.get());
std::copy(VTableThunks, VTableThunks+NumVTableThunks,
this->VTableThunks.get());
+ std::sort(this->VTableThunks.get(),
+ this->VTableThunks.get() + NumVTableThunks,
+ VTableThunksComparator());
}
VTableLayout::~VTableLayout() { }
-VTableContext::VTableContext(ASTContext &Context)
- : Context(Context),
- IsMicrosoftABI(Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ItaniumVTableContext::ItaniumVTableContext(ASTContext &Context)
+ : IsMicrosoftABI(Context.getTargetInfo().getCXXABI().isMicrosoft()) {
}
-VTableContext::~VTableContext() {
+ItaniumVTableContext::~ItaniumVTableContext() {
llvm::DeleteContainerSeconds(VTableLayouts);
}
-static void
-CollectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,
- VTableBuilder::PrimaryBasesSetVectorTy &PrimaryBases) {
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
-
- if (!PrimaryBase)
- return;
-
- CollectPrimaryBases(PrimaryBase, Context, PrimaryBases);
-
- if (!PrimaryBases.insert(PrimaryBase))
- llvm_unreachable("Found a duplicate primary base!");
-}
-
-void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
-
- // Itanium C++ ABI 2.5.2:
- // The order of the virtual function pointers in a virtual table is the
- // order of declaration of the corresponding member functions in the class.
- //
- // There is an entry for any virtual function declared in a class,
- // whether it is a new function or overrides a base class function,
- // unless it overrides a function from the primary base, and conversion
- // between their return types does not require an adjustment.
-
- int64_t CurrentIndex = 0;
-
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
-
- if (PrimaryBase) {
- assert(PrimaryBase->isCompleteDefinition() &&
- "Should have the definition decl of the primary base!");
-
- // Since the record decl shares its vtable pointer with the primary base
- // we need to start counting at the end of the primary base's vtable.
- CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase);
- }
-
- // Collect all the primary bases, so we can check whether methods override
- // a method from the base.
- VTableBuilder::PrimaryBasesSetVectorTy PrimaryBases;
- CollectPrimaryBases(RD, Context, PrimaryBases);
-
- const CXXDestructorDecl *ImplicitVirtualDtor = 0;
-
- for (CXXRecordDecl::method_iterator i = RD->method_begin(),
- e = RD->method_end(); i != e; ++i) {
- const CXXMethodDecl *MD = *i;
-
- // We only want virtual methods.
- if (!MD->isVirtual())
- continue;
-
- // Check if this method overrides a method in the primary base.
- if (const CXXMethodDecl *OverriddenMD =
- FindNearestOverriddenMethod(MD, PrimaryBases)) {
- // Check if converting from the return type of the method to the
- // return type of the overridden method requires conversion.
- if (ComputeReturnAdjustmentBaseOffset(Context, MD,
- OverriddenMD).isEmpty()) {
- // This index is shared between the index in the vtable of the primary
- // base class.
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- const CXXDestructorDecl *OverriddenDD =
- cast<CXXDestructorDecl>(OverriddenMD);
-
- if (!isMicrosoftABI()) {
- // Add both the complete and deleting entries.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
- } else {
- // Add the scalar deleting destructor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
- }
- } else {
- MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
- }
-
- // We don't need to add an entry for this method.
- continue;
- }
- }
-
- if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- if (MD->isImplicit()) {
- assert(!ImplicitVirtualDtor &&
- "Did already see an implicit virtual dtor!");
- ImplicitVirtualDtor = DD;
- continue;
- }
-
- if (!isMicrosoftABI()) {
- // Add the complete dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
-
- // Add the deleting dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
- } else {
- // Add the scalar deleting dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
- }
- } else {
- // Add the entry.
- MethodVTableIndices[MD] = CurrentIndex++;
- }
- }
-
- if (ImplicitVirtualDtor) {
- // Itanium C++ ABI 2.5.2:
- // If a class has an implicitly-defined virtual destructor,
- // its entries come after the declared virtual function pointers.
-
- if (isMicrosoftABI()) {
- ErrorUnsupported("implicit virtual destructor in the Microsoft ABI",
- ImplicitVirtualDtor->getLocation());
- }
-
- // Add the complete dtor.
- MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
- CurrentIndex++;
-
- // Add the deleting dtor.
- MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
- CurrentIndex++;
- }
-
- NumVirtualFunctionPointers[RD] = CurrentIndex;
-}
-
-uint64_t VTableContext::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
- llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
- NumVirtualFunctionPointers.find(RD);
- if (I != NumVirtualFunctionPointers.end())
- return I->second;
-
- ComputeMethodVTableIndices(RD);
-
- I = NumVirtualFunctionPointers.find(RD);
- assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!");
- return I->second;
-}
-
-uint64_t VTableContext::getMethodVTableIndex(GlobalDecl GD) {
+uint64_t ItaniumVTableContext::getMethodVTableIndex(GlobalDecl GD) {
MethodVTableIndicesTy::iterator I = MethodVTableIndices.find(GD);
if (I != MethodVTableIndices.end())
return I->second;
const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
- ComputeMethodVTableIndices(RD);
+ computeVTableRelatedInformation(RD);
I = MethodVTableIndices.find(GD);
assert(I != MethodVTableIndices.end() && "Did not find index!");
return I->second;
}
-CharUnits
-VTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
- const CXXRecordDecl *VBase) {
+CharUnits
+ItaniumVTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
+ const CXXRecordDecl *VBase) {
ClassPairTy ClassPair(RD, VBase);
VirtualBaseClassOffsetOffsetsMapTy::iterator I =
@@ -2393,30 +2334,35 @@ VTableContext::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
return I->second;
}
-static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) {
+static VTableLayout *CreateVTableLayout(const ItaniumVTableBuilder &Builder) {
SmallVector<VTableLayout::VTableThunkTy, 1>
VTableThunks(Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
- std::sort(VTableThunks.begin(), VTableThunks.end());
return new VTableLayout(Builder.getNumVTableComponents(),
Builder.vtable_component_begin(),
VTableThunks.size(),
VTableThunks.data(),
Builder.getAddressPoints(),
- Builder.isMicrosoftABI());
+ /*IsMicrosoftABI=*/false);
}
-void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
+void
+ItaniumVTableContext::computeVTableRelatedInformation(const CXXRecordDecl *RD) {
+ assert(!IsMicrosoftABI && "Shouldn't be called in this ABI!");
+
const VTableLayout *&Entry = VTableLayouts[RD];
// Check if we've computed this information before.
if (Entry)
return;
- VTableBuilder Builder(*this, RD, CharUnits::Zero(),
- /*MostDerivedClassIsVirtual=*/0, RD);
+ ItaniumVTableBuilder Builder(*this, RD, CharUnits::Zero(),
+ /*MostDerivedClassIsVirtual=*/0, RD);
Entry = CreateVTableLayout(Builder);
+ MethodVTableIndices.insert(Builder.vtable_indices_begin(),
+ Builder.vtable_indices_end());
+
// Add the known thunks.
Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
@@ -2426,16 +2372,16 @@ void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
if (!RD->getNumVBases())
return;
- const RecordType *VBaseRT =
- RD->vbases_begin()->getType()->getAs<RecordType>();
- const CXXRecordDecl *VBase = cast<CXXRecordDecl>(VBaseRT->getDecl());
+ const CXXRecordDecl *VBase =
+ RD->vbases_begin()->getType()->getAsCXXRecordDecl();
if (VirtualBaseClassOffsetOffsets.count(std::make_pair(RD, VBase)))
return;
-
- for (VTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator I =
- Builder.getVBaseOffsetOffsets().begin(),
- E = Builder.getVBaseOffsetOffsets().end(); I != E; ++I) {
+
+ for (ItaniumVTableBuilder::VBaseOffsetOffsetsMapTy::const_iterator
+ I = Builder.getVBaseOffsetOffsets().begin(),
+ E = Builder.getVBaseOffsetOffsets().end();
+ I != E; ++I) {
// Insert all types.
ClassPairTy ClassPair(RD, I->first);
@@ -2443,20 +2389,1040 @@ void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
}
}
-void VTableContext::ErrorUnsupported(StringRef Feature,
- SourceLocation Location) {
- clang::DiagnosticsEngine &Diags = Context.getDiagnostics();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "v-table layout for %0 is not supported yet");
- Diags.Report(Context.getFullLoc(Location), DiagID) << Feature;
+VTableLayout *ItaniumVTableContext::createConstructionVTableLayout(
+ const CXXRecordDecl *MostDerivedClass, CharUnits MostDerivedClassOffset,
+ bool MostDerivedClassIsVirtual, const CXXRecordDecl *LayoutClass) {
+ ItaniumVTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset,
+ MostDerivedClassIsVirtual, LayoutClass);
+ return CreateVTableLayout(Builder);
}
-VTableLayout *VTableContext::createConstructionVTableLayout(
- const CXXRecordDecl *MostDerivedClass,
- CharUnits MostDerivedClassOffset,
- bool MostDerivedClassIsVirtual,
- const CXXRecordDecl *LayoutClass) {
- VTableBuilder Builder(*this, MostDerivedClass, MostDerivedClassOffset,
- MostDerivedClassIsVirtual, LayoutClass);
- return CreateVTableLayout(Builder);
+namespace {
+
+// Vtables in the Microsoft ABI are different from the Itanium ABI.
+//
+// The main differences are:
+// 1. Separate vftable and vbtable.
+//
+// 2. Each subobject with a vfptr gets its own vftable rather than an address
+// point in a single vtable shared between all the subobjects.
+// Each vftable is represented by a separate section and virtual calls
+// must be done using the vftable which has a slot for the function to be
+// called.
+//
+// 3. Virtual method definitions expect their 'this' parameter to point to the
+// first vfptr whose table provides a compatible overridden method. In many
+// cases, this permits the original vf-table entry to directly call
+// the method instead of passing through a thunk.
+//
+// A compatible overridden method is one which does not have a non-trivial
+// covariant-return adjustment.
+//
+// The first vfptr is the one with the lowest offset in the complete-object
+// layout of the defining class, and the method definition will subtract
+// that constant offset from the parameter value to get the real 'this'
+// value. Therefore, if the offset isn't really constant (e.g. if a virtual
+// function defined in a virtual base is overridden in a more derived
+// virtual base and these bases have a reverse order in the complete
+// object), the vf-table may require a this-adjustment thunk.
+//
+// 4. vftables do not contain new entries for overrides that merely require
+// this-adjustment. Together with #3, this keeps vf-tables smaller and
+// eliminates the need for this-adjustment thunks in many cases, at the cost
+// of often requiring redundant work to adjust the "this" pointer.
+//
+// 5. Instead of VTT and constructor vtables, vbtables and vtordisps are used.
+// Vtordisps are emitted into the class layout if a class has
+// a) a user-defined ctor/dtor
+// and
+// b) a method overriding a method in a virtual base.
+
+class VFTableBuilder {
+public:
+ typedef MicrosoftVTableContext::MethodVFTableLocation MethodVFTableLocation;
+
+ typedef llvm::DenseMap<GlobalDecl, MethodVFTableLocation>
+ MethodVFTableLocationsTy;
+
+private:
+ /// VTables - Global vtable information.
+ MicrosoftVTableContext &VTables;
+
+ /// Context - The ASTContext which we will use for layout information.
+ ASTContext &Context;
+
+ /// MostDerivedClass - The most derived class for which we're building this
+ /// vtable.
+ const CXXRecordDecl *MostDerivedClass;
+
+ const ASTRecordLayout &MostDerivedClassLayout;
+
+ VFPtrInfo WhichVFPtr;
+
+ /// FinalOverriders - The final overriders of the most derived class.
+ const FinalOverriders Overriders;
+
+ /// Components - The components of the vftable being built.
+ SmallVector<VTableComponent, 64> Components;
+
+ MethodVFTableLocationsTy MethodVFTableLocations;
+
+ /// MethodInfo - Contains information about a method in a vtable.
+ /// (Used for computing 'this' pointer adjustment thunks.
+ struct MethodInfo {
+ /// VBTableIndex - The nonzero index in the vbtable that
+ /// this method's base has, or zero.
+ const uint64_t VBTableIndex;
+
+ /// VFTableIndex - The index in the vftable that this method has.
+ const uint64_t VFTableIndex;
+
+ /// Shadowed - Indicates if this vftable slot is shadowed by
+ /// a slot for a covariant-return override. If so, it shouldn't be printed
+ /// or used for vcalls in the most derived class.
+ bool Shadowed;
+
+ MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex)
+ : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex),
+ Shadowed(false) {}
+
+ MethodInfo() : VBTableIndex(0), VFTableIndex(0), Shadowed(false) {}
+ };
+
+ typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy;
+
+ /// MethodInfoMap - The information for all methods in the vftable we're
+ /// currently building.
+ MethodInfoMapTy MethodInfoMap;
+
+ typedef llvm::DenseMap<uint64_t, ThunkInfo> VTableThunksMapTy;
+
+ /// VTableThunks - The thunks by vftable index in the vftable currently being
+ /// built.
+ VTableThunksMapTy VTableThunks;
+
+ typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy;
+ typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy;
+
+ /// Thunks - A map that contains all the thunks needed for all methods in the
+ /// most derived class for which the vftable is currently being built.
+ ThunksMapTy Thunks;
+
+ /// AddThunk - Add a thunk for the given method.
+ void AddThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk) {
+ SmallVector<ThunkInfo, 1> &ThunksVector = Thunks[MD];
+
+ // Check if we have this thunk already.
+ if (std::find(ThunksVector.begin(), ThunksVector.end(), Thunk) !=
+ ThunksVector.end())
+ return;
+
+ ThunksVector.push_back(Thunk);
+ }
+
+ /// ComputeThisOffset - Returns the 'this' argument offset for the given
+ /// method in the given subobject, relative to the beginning of the
+ /// MostDerivedClass.
+ CharUnits ComputeThisOffset(const CXXMethodDecl *MD,
+ BaseSubobject Base,
+ FinalOverriders::OverriderInfo Overrider);
+
+ void CalculateVtordispAdjustment(FinalOverriders::OverriderInfo Overrider,
+ CharUnits ThisOffset, ThisAdjustment &TA);
+
+ /// AddMethod - Add a single virtual member function to the vftable
+ /// components vector.
+ void AddMethod(const CXXMethodDecl *MD, ThunkInfo TI) {
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ assert(TI.Return.isEmpty() &&
+ "Destructor can't have return adjustment!");
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
+ } else {
+ if (!TI.isEmpty())
+ VTableThunks[Components.size()] = TI;
+ Components.push_back(VTableComponent::MakeFunction(MD));
+ }
+ }
+
+ /// AddMethods - Add the methods of this base subobject and the relevant
+ /// subbases to the vftable we're currently laying out.
+ void AddMethods(BaseSubobject Base, unsigned BaseDepth,
+ const CXXRecordDecl *LastVBase,
+ BasesSetVectorTy &VisitedBases);
+
+ void LayoutVFTable() {
+ // FIXME: add support for RTTI when we have proper LLVM support for symbols
+ // pointing to the middle of a section.
+
+ BasesSetVectorTy VisitedBases;
+ AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, 0,
+ VisitedBases);
+
+ assert(MethodVFTableLocations.empty());
+ for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(),
+ E = MethodInfoMap.end(); I != E; ++I) {
+ const CXXMethodDecl *MD = I->first;
+ const MethodInfo &MI = I->second;
+ // Skip the methods that the MostDerivedClass didn't override
+ // and the entries shadowed by return adjusting thunks.
+ if (MD->getParent() != MostDerivedClass || MI.Shadowed)
+ continue;
+ MethodVFTableLocation Loc(MI.VBTableIndex, WhichVFPtr.LastVBase,
+ WhichVFPtr.VFPtrOffset, MI.VFTableIndex);
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ MethodVFTableLocations[GlobalDecl(DD, Dtor_Deleting)] = Loc;
+ } else {
+ MethodVFTableLocations[MD] = Loc;
+ }
+ }
+ }
+
+ void ErrorUnsupported(StringRef Feature, SourceLocation Location) {
+ clang::DiagnosticsEngine &Diags = Context.getDiagnostics();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error, "v-table layout for %0 is not supported yet");
+ Diags.Report(Context.getFullLoc(Location), DiagID) << Feature;
+ }
+
+public:
+ VFTableBuilder(MicrosoftVTableContext &VTables,
+ const CXXRecordDecl *MostDerivedClass, VFPtrInfo Which)
+ : VTables(VTables),
+ Context(MostDerivedClass->getASTContext()),
+ MostDerivedClass(MostDerivedClass),
+ MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)),
+ WhichVFPtr(Which),
+ Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) {
+ LayoutVFTable();
+
+ if (Context.getLangOpts().DumpVTableLayouts)
+ dumpLayout(llvm::outs());
+ }
+
+ uint64_t getNumThunks() const { return Thunks.size(); }
+
+ ThunksMapTy::const_iterator thunks_begin() const { return Thunks.begin(); }
+
+ ThunksMapTy::const_iterator thunks_end() const { return Thunks.end(); }
+
+ MethodVFTableLocationsTy::const_iterator vtable_indices_begin() const {
+ return MethodVFTableLocations.begin();
+ }
+
+ MethodVFTableLocationsTy::const_iterator vtable_indices_end() const {
+ return MethodVFTableLocations.end();
+ }
+
+ uint64_t getNumVTableComponents() const { return Components.size(); }
+
+ const VTableComponent *vtable_component_begin() const {
+ return Components.begin();
+ }
+
+ const VTableComponent *vtable_component_end() const {
+ return Components.end();
+ }
+
+ VTableThunksMapTy::const_iterator vtable_thunks_begin() const {
+ return VTableThunks.begin();
+ }
+
+ VTableThunksMapTy::const_iterator vtable_thunks_end() const {
+ return VTableThunks.end();
+ }
+
+ void dumpLayout(raw_ostream &);
+};
+
+/// InitialOverriddenDefinitionCollector - Finds the set of least derived bases
+/// that define the given method.
+struct InitialOverriddenDefinitionCollector {
+ BasesSetVectorTy Bases;
+ OverriddenMethodsSetTy VisitedOverriddenMethods;
+
+ bool visit(const CXXMethodDecl *OverriddenMD) {
+ if (OverriddenMD->size_overridden_methods() == 0)
+ Bases.insert(OverriddenMD->getParent());
+ // Don't recurse on this method if we've already collected it.
+ return VisitedOverriddenMethods.insert(OverriddenMD);
+ }
+};
+
+static bool BaseInSet(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path, void *BasesSet) {
+ BasesSetVectorTy *Bases = (BasesSetVectorTy *)BasesSet;
+ return Bases->count(Specifier->getType()->getAsCXXRecordDecl());
+}
+
+CharUnits
+VFTableBuilder::ComputeThisOffset(const CXXMethodDecl *MD,
+ BaseSubobject Base,
+ FinalOverriders::OverriderInfo Overrider) {
+ InitialOverriddenDefinitionCollector Collector;
+ visitAllOverriddenMethods(MD, Collector);
+
+ CXXBasePaths Paths;
+ Base.getBase()->lookupInBases(BaseInSet, &Collector.Bases, Paths);
+
+ // This will hold the smallest this offset among overridees of MD.
+ // This implies that an offset of a non-virtual base will dominate an offset
+ // of a virtual base to potentially reduce the number of thunks required
+ // in the derived classes that inherit this method.
+ CharUnits Ret;
+ bool First = true;
+
+ for (CXXBasePaths::paths_iterator I = Paths.begin(), E = Paths.end();
+ I != E; ++I) {
+ const CXXBasePath &Path = (*I);
+ CharUnits ThisOffset = Base.getBaseOffset();
+ CharUnits LastVBaseOffset;
+
+ // For each path from the overrider to the parents of the overridden methods,
+ // traverse the path, calculating the this offset in the most derived class.
+ for (int J = 0, F = Path.size(); J != F; ++J) {
+ const CXXBasePathElement &Element = Path[J];
+ QualType CurTy = Element.Base->getType();
+ const CXXRecordDecl *PrevRD = Element.Class,
+ *CurRD = CurTy->getAsCXXRecordDecl();
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(PrevRD);
+
+ if (Element.Base->isVirtual()) {
+ LastVBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(CurRD);
+ if (Overrider.Method->getParent() == PrevRD) {
+ // This one's interesting. If the final overrider is in a vbase B of the
+ // most derived class and it overrides a method of the B's own vbase A,
+ // it uses A* as "this". In its prologue, it can cast A* to B* with
+ // a static offset. This offset is used regardless of the actual
+ // offset of A from B in the most derived class, requiring an
+ // this-adjusting thunk in the vftable if A and B are laid out
+ // differently in the most derived class.
+ ThisOffset += Layout.getVBaseClassOffset(CurRD);
+ } else {
+ ThisOffset = LastVBaseOffset;
+ }
+ } else {
+ ThisOffset += Layout.getBaseClassOffset(CurRD);
+ }
+ }
+
+ if (isa<CXXDestructorDecl>(MD)) {
+ if (LastVBaseOffset.isZero()) {
+ // If a "Base" class has at least one non-virtual base with a virtual
+ // destructor, the "Base" virtual destructor will take the address
+ // of the "Base" subobject as the "this" argument.
+ return Base.getBaseOffset();
+ } else {
+ // A virtual destructor of a virtual base takes the address of the
+ // virtual base subobject as the "this" argument.
+ return LastVBaseOffset;
+ }
+ }
+
+ if (Ret > ThisOffset || First) {
+ First = false;
+ Ret = ThisOffset;
+ }
+ }
+
+ assert(!First && "Method not found in the given subobject?");
+ return Ret;
+}
+
+void VFTableBuilder::CalculateVtordispAdjustment(
+ FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset,
+ ThisAdjustment &TA) {
+ const ASTRecordLayout::VBaseOffsetsMapTy &VBaseMap =
+ MostDerivedClassLayout.getVBaseOffsetsMap();
+ const ASTRecordLayout::VBaseOffsetsMapTy::const_iterator &VBaseMapEntry =
+ VBaseMap.find(WhichVFPtr.LastVBase);
+ assert(VBaseMapEntry != VBaseMap.end());
+
+ // Check if we need a vtordisp adjustment at all.
+ if (!VBaseMapEntry->second.hasVtorDisp())
+ return;
+
+ CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset;
+ // The implicit vtordisp field is located right before the vbase.
+ TA.Virtual.Microsoft.VtordispOffset =
+ (VFPtrVBaseOffset - WhichVFPtr.VFPtrFullOffset).getQuantity() - 4;
+
+ // If the final overrider is defined in either:
+ // - the most derived class or its non-virtual base or
+ // - the same vbase as the initial declaration,
+ // a simple vtordisp thunk will suffice.
+ const CXXRecordDecl *OverriderRD = Overrider.Method->getParent();
+ if (OverriderRD == MostDerivedClass)
+ return;
+
+ const CXXRecordDecl *OverriderVBase =
+ ComputeBaseOffset(Context, OverriderRD, MostDerivedClass).VirtualBase;
+ if (!OverriderVBase || OverriderVBase == WhichVFPtr.LastVBase)
+ return;
+
+ // Otherwise, we need to do use the dynamic offset of the final overrider
+ // in order to get "this" adjustment right.
+ TA.Virtual.Microsoft.VBPtrOffset =
+ (VFPtrVBaseOffset + WhichVFPtr.VFPtrOffset -
+ MostDerivedClassLayout.getVBPtrOffset()).getQuantity();
+ TA.Virtual.Microsoft.VBOffsetOffset =
+ Context.getTypeSizeInChars(Context.IntTy).getQuantity() *
+ VTables.getVBTableIndex(MostDerivedClass, OverriderVBase);
+
+ TA.NonVirtual = (ThisOffset - Overrider.Offset).getQuantity();
+}
+
+static void GroupNewVirtualOverloads(
+ const CXXRecordDecl *RD,
+ SmallVector<const CXXMethodDecl *, 10> &VirtualMethods) {
+ // Put the virtual methods into VirtualMethods in the proper order:
+ // 1) Group overloads by declaration name. New groups are added to the
+ // vftable in the order of their first declarations in this class
+ // (including overrides).
+ // 2) In each group, new overloads appear in the reverse order of declaration.
+ typedef SmallVector<const CXXMethodDecl *, 1> MethodGroup;
+ SmallVector<MethodGroup, 10> Groups;
+ typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy;
+ VisitedGroupIndicesTy VisitedGroupIndices;
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+ if (!MD->isVirtual())
+ continue;
+
+ VisitedGroupIndicesTy::iterator J;
+ bool Inserted;
+ llvm::tie(J, Inserted) = VisitedGroupIndices.insert(
+ std::make_pair(MD->getDeclName(), Groups.size()));
+ if (Inserted)
+ Groups.push_back(MethodGroup(1, MD));
+ else
+ Groups[J->second].push_back(MD);
+ }
+
+ for (unsigned I = 0, E = Groups.size(); I != E; ++I)
+ VirtualMethods.append(Groups[I].rbegin(), Groups[I].rend());
+}
+
+void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth,
+ const CXXRecordDecl *LastVBase,
+ BasesSetVectorTy &VisitedBases) {
+ const CXXRecordDecl *RD = Base.getBase();
+ if (!RD->isPolymorphic())
+ return;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ // See if this class expands a vftable of the base we look at, which is either
+ // the one defined by the vfptr base path or the primary base of the current class.
+ const CXXRecordDecl *NextBase = 0, *NextLastVBase = LastVBase;
+ CharUnits NextBaseOffset;
+ if (BaseDepth < WhichVFPtr.PathToBaseWithVFPtr.size()) {
+ NextBase = WhichVFPtr.PathToBaseWithVFPtr[BaseDepth];
+ if (Layout.getVBaseOffsetsMap().count(NextBase)) {
+ NextLastVBase = NextBase;
+ NextBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(NextBase);
+ } else {
+ NextBaseOffset =
+ Base.getBaseOffset() + Layout.getBaseClassOffset(NextBase);
+ }
+ } else if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
+ assert(!Layout.isPrimaryBaseVirtual() &&
+ "No primary virtual bases in this ABI");
+ NextBase = PrimaryBase;
+ NextBaseOffset = Base.getBaseOffset();
+ }
+
+ if (NextBase) {
+ AddMethods(BaseSubobject(NextBase, NextBaseOffset), BaseDepth + 1,
+ NextLastVBase, VisitedBases);
+ if (!VisitedBases.insert(NextBase))
+ llvm_unreachable("Found a duplicate primary base!");
+ }
+
+ SmallVector<const CXXMethodDecl*, 10> VirtualMethods;
+ // Put virtual methods in the proper order.
+ GroupNewVirtualOverloads(RD, VirtualMethods);
+
+ // Now go through all virtual member functions and add them to the current
+ // vftable. This is done by
+ // - replacing overridden methods in their existing slots, as long as they
+ // don't require return adjustment; calculating This adjustment if needed.
+ // - adding new slots for methods of the current base not present in any
+ // sub-bases;
+ // - adding new slots for methods that require Return adjustment.
+ // We keep track of the methods visited in the sub-bases in MethodInfoMap.
+ for (unsigned I = 0, E = VirtualMethods.size(); I != E; ++I) {
+ const CXXMethodDecl *MD = VirtualMethods[I];
+
+ FinalOverriders::OverriderInfo Overrider =
+ Overriders.getOverrider(MD, Base.getBaseOffset());
+ ThisAdjustment ThisAdjustmentOffset;
+ bool ForceThunk = false;
+
+ // Check if this virtual member function overrides
+ // a method in one of the visited bases.
+ if (const CXXMethodDecl *OverriddenMD =
+ FindNearestOverriddenMethod(MD, VisitedBases)) {
+ MethodInfoMapTy::iterator OverriddenMDIterator =
+ MethodInfoMap.find(OverriddenMD);
+
+ // If the overridden method went to a different vftable, skip it.
+ if (OverriddenMDIterator == MethodInfoMap.end())
+ continue;
+
+ MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second;
+
+ // Create a this-adjusting thunk if needed.
+ CharUnits TI = ComputeThisOffset(MD, Base, Overrider);
+ if (TI != WhichVFPtr.VFPtrFullOffset) {
+ ThisAdjustmentOffset.NonVirtual =
+ (TI - WhichVFPtr.VFPtrFullOffset).getQuantity();
+ }
+
+ if (WhichVFPtr.LastVBase)
+ CalculateVtordispAdjustment(Overrider, TI, ThisAdjustmentOffset);
+
+ if (!ThisAdjustmentOffset.isEmpty()) {
+ VTableThunks[OverriddenMethodInfo.VFTableIndex].This =
+ ThisAdjustmentOffset;
+ AddThunk(MD, VTableThunks[OverriddenMethodInfo.VFTableIndex]);
+ }
+
+ if (MD->getResultType() == OverriddenMD->getResultType()) {
+ // No return adjustment needed - just replace the overridden method info
+ // with the current info.
+ MethodInfo MI(OverriddenMethodInfo.VBTableIndex,
+ OverriddenMethodInfo.VFTableIndex);
+ MethodInfoMap.erase(OverriddenMDIterator);
+
+ assert(!MethodInfoMap.count(MD) &&
+ "Should not have method info for this method yet!");
+ MethodInfoMap.insert(std::make_pair(MD, MI));
+ continue;
+ } else {
+ // In case we need a return adjustment, we'll add a new slot for
+ // the overrider and put a return-adjusting thunk where the overridden
+ // method was in the vftable.
+ // For now, just mark the overriden method as shadowed by a new slot.
+ OverriddenMethodInfo.Shadowed = true;
+ ForceThunk = true;
+
+ // Also apply this adjustment to the shadowed slots.
+ if (!ThisAdjustmentOffset.isEmpty()) {
+ // FIXME: this is O(N^2), can be O(N).
+ const CXXMethodDecl *SubOverride = OverriddenMD;
+ while ((SubOverride =
+ FindNearestOverriddenMethod(SubOverride, VisitedBases))) {
+ MethodInfoMapTy::iterator SubOverrideIterator =
+ MethodInfoMap.find(SubOverride);
+ if (SubOverrideIterator == MethodInfoMap.end())
+ break;
+ MethodInfo &SubOverrideMI = SubOverrideIterator->second;
+ assert(SubOverrideMI.Shadowed);
+ VTableThunks[SubOverrideMI.VFTableIndex].This =
+ ThisAdjustmentOffset;
+ AddThunk(MD, VTableThunks[SubOverrideMI.VFTableIndex]);
+ }
+ }
+ }
+ } else if (Base.getBaseOffset() != WhichVFPtr.VFPtrFullOffset ||
+ MD->size_overridden_methods()) {
+ // Skip methods that don't belong to the vftable of the current class,
+ // e.g. each method that wasn't seen in any of the visited sub-bases
+ // but overrides multiple methods of other sub-bases.
+ continue;
+ }
+
+ // If we got here, MD is a method not seen in any of the sub-bases or
+ // it requires return adjustment. Insert the method info for this method.
+ unsigned VBIndex =
+ LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0;
+ MethodInfo MI(VBIndex, Components.size());
+
+ assert(!MethodInfoMap.count(MD) &&
+ "Should not have method info for this method yet!");
+ MethodInfoMap.insert(std::make_pair(MD, MI));
+
+ const CXXMethodDecl *OverriderMD = Overrider.Method;
+
+ // Check if this overrider needs a return adjustment.
+ // We don't want to do this for pure virtual member functions.
+ BaseOffset ReturnAdjustmentOffset;
+ ReturnAdjustment ReturnAdjustment;
+ if (!OverriderMD->isPure()) {
+ ReturnAdjustmentOffset =
+ ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD);
+ }
+ if (!ReturnAdjustmentOffset.isEmpty()) {
+ ForceThunk = true;
+ ReturnAdjustment.NonVirtual =
+ ReturnAdjustmentOffset.NonVirtualOffset.getQuantity();
+ if (ReturnAdjustmentOffset.VirtualBase) {
+ const ASTRecordLayout &DerivedLayout =
+ Context.getASTRecordLayout(ReturnAdjustmentOffset.DerivedClass);
+ ReturnAdjustment.Virtual.Microsoft.VBPtrOffset =
+ DerivedLayout.getVBPtrOffset().getQuantity();
+ ReturnAdjustment.Virtual.Microsoft.VBIndex =
+ VTables.getVBTableIndex(ReturnAdjustmentOffset.DerivedClass,
+ ReturnAdjustmentOffset.VirtualBase);
+ }
+ }
+
+ AddMethod(OverriderMD, ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment,
+ ForceThunk ? MD : 0));
+ }
+}
+
+void PrintBasePath(const VFPtrInfo::BasePath &Path, raw_ostream &Out) {
+ for (VFPtrInfo::BasePath::const_reverse_iterator I = Path.rbegin(),
+ E = Path.rend(); I != E; ++I) {
+ Out << "'" << (*I)->getQualifiedNameAsString() << "' in ";
+ }
+}
+
+struct MicrosoftThunkInfoStableSortComparator {
+ bool operator() (const ThunkInfo &LHS, const ThunkInfo &RHS) {
+ if (LHS.This != RHS.This)
+ return LHS.This < RHS.This;
+
+ if (LHS.Return != RHS.Return)
+ return LHS.Return < RHS.Return;
+
+ // Keep different thunks with the same adjustments in the order they
+ // were put into the vector.
+ return false;
+ }
+};
+
+static void dumpMicrosoftThunkAdjustment(const ThunkInfo &TI, raw_ostream &Out,
+ bool ContinueFirstLine) {
+ const ReturnAdjustment &R = TI.Return;
+ bool Multiline = false;
+ const char *LinePrefix = "\n ";
+ if (!R.isEmpty()) {
+ if (!ContinueFirstLine)
+ Out << LinePrefix;
+ Out << "[return adjustment: ";
+ if (R.Virtual.Microsoft.VBPtrOffset)
+ Out << "vbptr at offset " << R.Virtual.Microsoft.VBPtrOffset << ", ";
+ if (R.Virtual.Microsoft.VBIndex)
+ Out << "vbase #" << R.Virtual.Microsoft.VBIndex << ", ";
+ Out << R.NonVirtual << " non-virtual]";
+ Multiline = true;
+ }
+
+ const ThisAdjustment &T = TI.This;
+ if (!T.isEmpty()) {
+ if (Multiline || !ContinueFirstLine)
+ Out << LinePrefix;
+ Out << "[this adjustment: ";
+ if (!TI.This.Virtual.isEmpty()) {
+ assert(T.Virtual.Microsoft.VtordispOffset < 0);
+ Out << "vtordisp at " << T.Virtual.Microsoft.VtordispOffset << ", ";
+ if (T.Virtual.Microsoft.VBPtrOffset) {
+ Out << "vbptr at " << T.Virtual.Microsoft.VBPtrOffset
+ << " to the left, ";
+ assert(T.Virtual.Microsoft.VBOffsetOffset > 0);
+ Out << LinePrefix << " vboffset at "
+ << T.Virtual.Microsoft.VBOffsetOffset << " in the vbtable, ";
+ }
+ }
+ Out << T.NonVirtual << " non-virtual]";
+ }
+}
+
+void VFTableBuilder::dumpLayout(raw_ostream &Out) {
+ Out << "VFTable for ";
+ PrintBasePath(WhichVFPtr.PathToBaseWithVFPtr, Out);
+ Out << "'" << MostDerivedClass->getQualifiedNameAsString();
+ Out << "' (" << Components.size() << " entries).\n";
+
+ for (unsigned I = 0, E = Components.size(); I != E; ++I) {
+ Out << llvm::format("%4d | ", I);
+
+ const VTableComponent &Component = Components[I];
+
+ // Dump the component.
+ switch (Component.getKind()) {
+ case VTableComponent::CK_RTTI:
+ Out << Component.getRTTIDecl()->getQualifiedNameAsString() << " RTTI";
+ break;
+
+ case VTableComponent::CK_FunctionPointer: {
+ const CXXMethodDecl *MD = Component.getFunctionDecl();
+
+ std::string Str = PredefinedExpr::ComputeName(
+ PredefinedExpr::PrettyFunctionNoVirtual, MD);
+ Out << Str;
+ if (MD->isPure())
+ Out << " [pure]";
+
+ if (MD->isDeleted()) {
+ ErrorUnsupported("deleted methods", MD->getLocation());
+ Out << " [deleted]";
+ }
+
+ ThunkInfo Thunk = VTableThunks.lookup(I);
+ if (!Thunk.isEmpty())
+ dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
+
+ break;
+ }
+
+ case VTableComponent::CK_DeletingDtorPointer: {
+ const CXXDestructorDecl *DD = Component.getDestructorDecl();
+
+ Out << DD->getQualifiedNameAsString();
+ Out << "() [scalar deleting]";
+
+ if (DD->isPure())
+ Out << " [pure]";
+
+ ThunkInfo Thunk = VTableThunks.lookup(I);
+ if (!Thunk.isEmpty()) {
+ assert(Thunk.Return.isEmpty() &&
+ "No return adjustment needed for destructors!");
+ dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/false);
+ }
+
+ break;
+ }
+
+ default:
+ DiagnosticsEngine &Diags = Context.getDiagnostics();
+ unsigned DiagID = Diags.getCustomDiagID(
+ DiagnosticsEngine::Error,
+ "Unexpected vftable component type %0 for component number %1");
+ Diags.Report(MostDerivedClass->getLocation(), DiagID)
+ << I << Component.getKind();
+ }
+
+ Out << '\n';
+ }
+
+ Out << '\n';
+
+ if (!Thunks.empty()) {
+ // We store the method names in a map to get a stable order.
+ std::map<std::string, const CXXMethodDecl *> MethodNamesAndDecls;
+
+ for (ThunksMapTy::const_iterator I = Thunks.begin(), E = Thunks.end();
+ I != E; ++I) {
+ const CXXMethodDecl *MD = I->first;
+ std::string MethodName = PredefinedExpr::ComputeName(
+ PredefinedExpr::PrettyFunctionNoVirtual, MD);
+
+ MethodNamesAndDecls.insert(std::make_pair(MethodName, MD));
+ }
+
+ for (std::map<std::string, const CXXMethodDecl *>::const_iterator
+ I = MethodNamesAndDecls.begin(),
+ E = MethodNamesAndDecls.end();
+ I != E; ++I) {
+ const std::string &MethodName = I->first;
+ const CXXMethodDecl *MD = I->second;
+
+ ThunkInfoVectorTy ThunksVector = Thunks[MD];
+ std::stable_sort(ThunksVector.begin(), ThunksVector.end(),
+ MicrosoftThunkInfoStableSortComparator());
+
+ Out << "Thunks for '" << MethodName << "' (" << ThunksVector.size();
+ Out << (ThunksVector.size() == 1 ? " entry" : " entries") << ").\n";
+
+ for (unsigned I = 0, E = ThunksVector.size(); I != E; ++I) {
+ const ThunkInfo &Thunk = ThunksVector[I];
+
+ Out << llvm::format("%4d | ", I);
+ dumpMicrosoftThunkAdjustment(Thunk, Out, /*ContinueFirstLine=*/true);
+ Out << '\n';
+ }
+
+ Out << '\n';
+ }
+ }
+}
+}
+
+void MicrosoftVTableContext::enumerateVFPtrs(
+ const CXXRecordDecl *MostDerivedClass,
+ const ASTRecordLayout &MostDerivedClassLayout, BaseSubobject Base,
+ const CXXRecordDecl *LastVBase,
+ const VFPtrInfo::BasePath &PathFromCompleteClass,
+ BasesSetVectorTy &VisitedVBases,
+ VFPtrListTy &Result) {
+ const CXXRecordDecl *CurrentClass = Base.getBase();
+ CharUnits OffsetInCompleteClass = Base.getBaseOffset();
+ const ASTRecordLayout &CurrentClassLayout =
+ Context.getASTRecordLayout(CurrentClass);
+
+ if (CurrentClassLayout.hasOwnVFPtr()) {
+ if (LastVBase) {
+ uint64_t VBIndex = getVBTableIndex(MostDerivedClass, LastVBase);
+ assert(VBIndex > 0 && "vbases must have vbindex!");
+ CharUnits VFPtrOffset =
+ OffsetInCompleteClass -
+ MostDerivedClassLayout.getVBaseClassOffset(LastVBase);
+ Result.push_back(VFPtrInfo(VBIndex, LastVBase, VFPtrOffset,
+ PathFromCompleteClass, OffsetInCompleteClass));
+ } else {
+ Result.push_back(VFPtrInfo(OffsetInCompleteClass, PathFromCompleteClass));
+ }
+ }
+
+ for (CXXRecordDecl::base_class_const_iterator I = CurrentClass->bases_begin(),
+ E = CurrentClass->bases_end(); I != E; ++I) {
+ const CXXRecordDecl *BaseDecl = I->getType()->getAsCXXRecordDecl();
+
+ CharUnits NextBaseOffset;
+ const CXXRecordDecl *NextLastVBase;
+ if (I->isVirtual()) {
+ if (!VisitedVBases.insert(BaseDecl))
+ continue;
+ NextBaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+ NextLastVBase = BaseDecl;
+ } else {
+ NextBaseOffset = OffsetInCompleteClass +
+ CurrentClassLayout.getBaseClassOffset(BaseDecl);
+ NextLastVBase = LastVBase;
+ }
+
+ VFPtrInfo::BasePath NewPath = PathFromCompleteClass;
+ NewPath.push_back(BaseDecl);
+ BaseSubobject NextBase(BaseDecl, NextBaseOffset);
+
+ enumerateVFPtrs(MostDerivedClass, MostDerivedClassLayout, NextBase,
+ NextLastVBase, NewPath, VisitedVBases, Result);
+ }
+}
+
+/// CalculatePathToMangle - Calculate the subset of records that should be used
+/// to mangle the vftable for the given vfptr.
+/// Should only be called if a class has multiple vftables.
+static void
+CalculatePathToMangle(const CXXRecordDecl *RD, VFPtrInfo &VFPtr) {
+ // FIXME: In some rare cases this code produces a slightly incorrect mangling.
+ // It's very likely that the vbtable mangling code can be adjusted to mangle
+ // both vftables and vbtables correctly.
+
+ VFPtrInfo::BasePath &FullPath = VFPtr.PathToBaseWithVFPtr;
+ if (FullPath.empty()) {
+ // Mangle the class's own vftable.
+ assert(RD->getNumVBases() &&
+ "Something's wrong: if the most derived "
+ "class has more than one vftable, it can only have its own "
+ "vftable if it has vbases");
+ VFPtr.PathToMangle.push_back(RD);
+ return;
+ }
+
+ unsigned Begin = 0;
+
+ // First, skip all the bases before the vbase.
+ if (VFPtr.LastVBase) {
+ while (FullPath[Begin] != VFPtr.LastVBase) {
+ Begin++;
+ assert(Begin < FullPath.size());
+ }
+ }
+
+ // Then, put the rest of the base path in the reverse order.
+ for (unsigned I = FullPath.size(); I != Begin; --I) {
+ const CXXRecordDecl *CurBase = FullPath[I - 1],
+ *ItsBase = (I == 1) ? RD : FullPath[I - 2];
+ bool BaseIsVirtual = false;
+ for (CXXRecordDecl::base_class_const_iterator J = ItsBase->bases_begin(),
+ F = ItsBase->bases_end(); J != F; ++J) {
+ if (J->getType()->getAsCXXRecordDecl() == CurBase) {
+ BaseIsVirtual = J->isVirtual();
+ break;
+ }
+ }
+
+ // Should skip the current base if it is a non-virtual base with no siblings.
+ if (BaseIsVirtual || ItsBase->getNumBases() != 1)
+ VFPtr.PathToMangle.push_back(CurBase);
+ }
+}
+
+void MicrosoftVTableContext::enumerateVFPtrs(
+ const CXXRecordDecl *ForClass,
+ MicrosoftVTableContext::VFPtrListTy &Result) {
+ Result.clear();
+ const ASTRecordLayout &ClassLayout = Context.getASTRecordLayout(ForClass);
+ BasesSetVectorTy VisitedVBases;
+ enumerateVFPtrs(ForClass, ClassLayout,
+ BaseSubobject(ForClass, CharUnits::Zero()), 0,
+ VFPtrInfo::BasePath(), VisitedVBases, Result);
+ if (Result.size() > 1) {
+ for (unsigned I = 0, E = Result.size(); I != E; ++I)
+ CalculatePathToMangle(ForClass, Result[I]);
+ }
+}
+
+void MicrosoftVTableContext::computeVTableRelatedInformation(
+ const CXXRecordDecl *RD) {
+ assert(RD->isDynamicClass());
+
+ // Check if we've computed this information before.
+ if (VFPtrLocations.count(RD))
+ return;
+
+ const VTableLayout::AddressPointsMapTy EmptyAddressPointsMap;
+
+ VFPtrListTy &VFPtrs = VFPtrLocations[RD];
+ enumerateVFPtrs(RD, VFPtrs);
+
+ MethodVFTableLocationsTy NewMethodLocations;
+ for (VFPtrListTy::iterator I = VFPtrs.begin(), E = VFPtrs.end();
+ I != E; ++I) {
+ VFTableBuilder Builder(*this, RD, *I);
+
+ VFTableIdTy id(RD, I->VFPtrFullOffset);
+ assert(VFTableLayouts.count(id) == 0);
+ SmallVector<VTableLayout::VTableThunkTy, 1> VTableThunks(
+ Builder.vtable_thunks_begin(), Builder.vtable_thunks_end());
+ VFTableLayouts[id] = new VTableLayout(
+ Builder.getNumVTableComponents(), Builder.vtable_component_begin(),
+ VTableThunks.size(), VTableThunks.data(), EmptyAddressPointsMap, true);
+ NewMethodLocations.insert(Builder.vtable_indices_begin(),
+ Builder.vtable_indices_end());
+ Thunks.insert(Builder.thunks_begin(), Builder.thunks_end());
+ }
+
+ MethodVFTableLocations.insert(NewMethodLocations.begin(),
+ NewMethodLocations.end());
+ if (Context.getLangOpts().DumpVTableLayouts)
+ dumpMethodLocations(RD, NewMethodLocations, llvm::outs());
+}
+
+void MicrosoftVTableContext::dumpMethodLocations(
+ const CXXRecordDecl *RD, const MethodVFTableLocationsTy &NewMethods,
+ raw_ostream &Out) {
+ // Compute the vtable indices for all the member functions.
+ // Store them in a map keyed by the location so we'll get a sorted table.
+ std::map<MethodVFTableLocation, std::string> IndicesMap;
+ bool HasNonzeroOffset = false;
+
+ for (MethodVFTableLocationsTy::const_iterator I = NewMethods.begin(),
+ E = NewMethods.end(); I != E; ++I) {
+ const CXXMethodDecl *MD = cast<const CXXMethodDecl>(I->first.getDecl());
+ assert(MD->isVirtual());
+
+ std::string MethodName = PredefinedExpr::ComputeName(
+ PredefinedExpr::PrettyFunctionNoVirtual, MD);
+
+ if (isa<CXXDestructorDecl>(MD)) {
+ IndicesMap[I->second] = MethodName + " [scalar deleting]";
+ } else {
+ IndicesMap[I->second] = MethodName;
+ }
+
+ if (!I->second.VFPtrOffset.isZero() || I->second.VBTableIndex != 0)
+ HasNonzeroOffset = true;
+ }
+
+ // Print the vtable indices for all the member functions.
+ if (!IndicesMap.empty()) {
+ Out << "VFTable indices for ";
+ Out << "'" << RD->getQualifiedNameAsString();
+ Out << "' (" << IndicesMap.size() << " entries).\n";
+
+ CharUnits LastVFPtrOffset = CharUnits::fromQuantity(-1);
+ uint64_t LastVBIndex = 0;
+ for (std::map<MethodVFTableLocation, std::string>::const_iterator
+ I = IndicesMap.begin(),
+ E = IndicesMap.end();
+ I != E; ++I) {
+ CharUnits VFPtrOffset = I->first.VFPtrOffset;
+ uint64_t VBIndex = I->first.VBTableIndex;
+ if (HasNonzeroOffset &&
+ (VFPtrOffset != LastVFPtrOffset || VBIndex != LastVBIndex)) {
+ assert(VBIndex > LastVBIndex || VFPtrOffset > LastVFPtrOffset);
+ Out << " -- accessible via ";
+ if (VBIndex)
+ Out << "vbtable index " << VBIndex << ", ";
+ Out << "vfptr at offset " << VFPtrOffset.getQuantity() << " --\n";
+ LastVFPtrOffset = VFPtrOffset;
+ LastVBIndex = VBIndex;
+ }
+
+ uint64_t VTableIndex = I->first.Index;
+ const std::string &MethodName = I->second;
+ Out << llvm::format("%4" PRIu64 " | ", VTableIndex) << MethodName << '\n';
+ }
+ Out << '\n';
+ }
+}
+
+void MicrosoftVTableContext::computeVBTableRelatedInformation(
+ const CXXRecordDecl *RD) {
+ if (ComputedVBTableIndices.count(RD))
+ return;
+ ComputedVBTableIndices.insert(RD);
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ BasesSetVectorTy VisitedBases;
+
+ // First, see if the Derived class shared the vbptr with a non-virtual base.
+ if (const CXXRecordDecl *VBPtrBase = Layout.getBaseSharingVBPtr()) {
+ // If the Derived class shares the vbptr with a non-virtual base,
+ // it inherits its vbase indices.
+ computeVBTableRelatedInformation(VBPtrBase);
+ for (CXXRecordDecl::base_class_const_iterator I = VBPtrBase->vbases_begin(),
+ E = VBPtrBase->vbases_end(); I != E; ++I) {
+ const CXXRecordDecl *SubVBase = I->getType()->getAsCXXRecordDecl();
+ assert(VBTableIndices.count(ClassPairTy(VBPtrBase, SubVBase)));
+ VBTableIndices[ClassPairTy(RD, SubVBase)] =
+ VBTableIndices[ClassPairTy(VBPtrBase, SubVBase)];
+ VisitedBases.insert(SubVBase);
+ }
+ }
+
+ // New vbases are added to the end of the vbtable.
+ // Skip the self entry and vbases visited in the non-virtual base, if any.
+ unsigned VBTableIndex = 1 + VisitedBases.size();
+ for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
+ E = RD->vbases_end(); I != E; ++I) {
+ const CXXRecordDecl *CurVBase = I->getType()->getAsCXXRecordDecl();
+ if (VisitedBases.insert(CurVBase))
+ VBTableIndices[ClassPairTy(RD, CurVBase)] = VBTableIndex++;
+ }
+}
+
+const MicrosoftVTableContext::VFPtrListTy &
+MicrosoftVTableContext::getVFPtrOffsets(const CXXRecordDecl *RD) {
+ computeVTableRelatedInformation(RD);
+
+ assert(VFPtrLocations.count(RD) && "Couldn't find vfptr locations");
+ return VFPtrLocations[RD];
+}
+
+const VTableLayout &
+MicrosoftVTableContext::getVFTableLayout(const CXXRecordDecl *RD,
+ CharUnits VFPtrOffset) {
+ computeVTableRelatedInformation(RD);
+
+ VFTableIdTy id(RD, VFPtrOffset);
+ assert(VFTableLayouts.count(id) && "Couldn't find a VFTable at this offset");
+ return *VFTableLayouts[id];
+}
+
+const MicrosoftVTableContext::MethodVFTableLocation &
+MicrosoftVTableContext::getMethodVFTableLocation(GlobalDecl GD) {
+ assert(cast<CXXMethodDecl>(GD.getDecl())->isVirtual() &&
+ "Only use this method for virtual methods or dtors");
+ if (isa<CXXDestructorDecl>(GD.getDecl()))
+ assert(GD.getDtorType() == Dtor_Deleting);
+
+ MethodVFTableLocationsTy::iterator I = MethodVFTableLocations.find(GD);
+ if (I != MethodVFTableLocations.end())
+ return I->second;
+
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
+
+ computeVTableRelatedInformation(RD);
+
+ I = MethodVFTableLocations.find(GD);
+ assert(I != MethodVFTableLocations.end() && "Did not find index!");
+ return I->second;
}
OpenPOWER on IntegriCloud