summaryrefslogtreecommitdiffstats
path: root/lib/AST
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2011-02-20 13:06:31 +0000
committerdim <dim@FreeBSD.org>2011-02-20 13:06:31 +0000
commit39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df (patch)
treea9243275843fbeaa590afc07ee888e006b8d54ea /lib/AST
parent69b4eca4a4255ba43baa5c1d9bbdec3ec17f479e (diff)
downloadFreeBSD-src-39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df.zip
FreeBSD-src-39fcc9a984e2820e4ea0fa2ac4abd17d9f3a31df.tar.gz
Vendor import of clang trunk r126079:
http://llvm.org/svn/llvm-project/cfe/trunk@126079
Diffstat (limited to 'lib/AST')
-rw-r--r--lib/AST/ASTContext.cpp1999
-rw-r--r--lib/AST/ASTDiagnostic.cpp56
-rw-r--r--lib/AST/ASTImporter.cpp1353
-rw-r--r--lib/AST/CMakeLists.txt9
-rw-r--r--lib/AST/CXXABI.h9
-rw-r--r--lib/AST/CXXInheritance.cpp57
-rw-r--r--lib/AST/Decl.cpp927
-rw-r--r--lib/AST/DeclBase.cpp118
-rw-r--r--lib/AST/DeclCXX.cpp719
-rw-r--r--lib/AST/DeclObjC.cpp57
-rw-r--r--lib/AST/DeclPrinter.cpp83
-rw-r--r--lib/AST/DeclTemplate.cpp363
-rw-r--r--lib/AST/DeclarationName.cpp31
-rw-r--r--lib/AST/DumpXML.cpp1028
-rw-r--r--lib/AST/Expr.cpp1336
-rw-r--r--lib/AST/ExprCXX.cpp835
-rw-r--r--lib/AST/ExprClassification.cpp194
-rw-r--r--lib/AST/ExprConstant.cpp727
-rw-r--r--lib/AST/FullExpr.cpp45
-rw-r--r--lib/AST/InheritViz.cpp39
-rw-r--r--lib/AST/ItaniumCXXABI.cpp21
-rw-r--r--lib/AST/ItaniumMangle.cpp2705
-rw-r--r--lib/AST/Mangle.cpp135
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp25
-rw-r--r--lib/AST/MicrosoftMangle.cpp1188
-rw-r--r--lib/AST/NestedNameSpecifier.cpp42
-rw-r--r--lib/AST/ParentMap.cpp17
-rw-r--r--lib/AST/RecordLayout.cpp30
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp649
-rw-r--r--lib/AST/Stmt.cpp256
-rw-r--r--lib/AST/StmtDumper.cpp172
-rw-r--r--lib/AST/StmtIterator.cpp18
-rw-r--r--lib/AST/StmtPrinter.cpp155
-rw-r--r--lib/AST/StmtProfile.cpp99
-rw-r--r--lib/AST/TemplateBase.cpp356
-rw-r--r--lib/AST/TemplateName.cpp57
-rw-r--r--lib/AST/Type.cpp911
-rw-r--r--lib/AST/TypeLoc.cpp53
-rw-r--r--lib/AST/TypePrinter.cpp521
39 files changed, 13462 insertions, 3933 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 4591a0f..945dfb8 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -20,7 +20,9 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Mangle.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -50,7 +52,7 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
TemplateTemplateParmDecl *Parm) {
ID.AddInteger(Parm->getDepth());
ID.AddInteger(Parm->getPosition());
- // FIXME: Parameter pack
+ ID.AddBoolean(Parm->isParameterPack());
TemplateParameterList *Params = Parm->getTemplateParameters();
ID.AddInteger(Params->size());
@@ -65,8 +67,15 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
ID.AddInteger(1);
- // FIXME: Parameter pack
+ ID.AddBoolean(NTTP->isParameterPack());
ID.AddPointer(NTTP->getType().getAsOpaquePtr());
+ if (NTTP->isExpandedParameterPack()) {
+ ID.AddBoolean(true);
+ ID.AddInteger(NTTP->getNumExpansionTypes());
+ for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I)
+ ID.AddPointer(NTTP->getExpansionType(I).getAsOpaquePtr());
+ } else
+ ID.AddBoolean(false);
continue;
}
@@ -78,7 +87,7 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
TemplateTemplateParmDecl *
ASTContext::getCanonicalTemplateTemplateParmDecl(
- TemplateTemplateParmDecl *TTP) {
+ TemplateTemplateParmDecl *TTP) const {
// Check if we already have a canonical template template parameter.
llvm::FoldingSetNodeID ID;
CanonicalTemplateTemplateParm::Profile(ID, TTP);
@@ -102,14 +111,40 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
TTP->getIndex(), 0, false,
TTP->isParameterPack()));
else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(*P))
- CanonParams.push_back(
- NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
- SourceLocation(), NTTP->getDepth(),
- NTTP->getPosition(), 0,
- getCanonicalType(NTTP->getType()),
- 0));
- else
+ = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
+ QualType T = getCanonicalType(NTTP->getType());
+ TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T);
+ NonTypeTemplateParmDecl *Param;
+ if (NTTP->isExpandedParameterPack()) {
+ llvm::SmallVector<QualType, 2> ExpandedTypes;
+ llvm::SmallVector<TypeSourceInfo *, 2> ExpandedTInfos;
+ for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) {
+ ExpandedTypes.push_back(getCanonicalType(NTTP->getExpansionType(I)));
+ ExpandedTInfos.push_back(
+ getTrivialTypeSourceInfo(ExpandedTypes.back()));
+ }
+
+ Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
+ SourceLocation(),
+ NTTP->getDepth(),
+ NTTP->getPosition(), 0,
+ T,
+ TInfo,
+ ExpandedTypes.data(),
+ ExpandedTypes.size(),
+ ExpandedTInfos.data());
+ } else {
+ Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
+ SourceLocation(),
+ NTTP->getDepth(),
+ NTTP->getPosition(), 0,
+ T,
+ NTTP->isParameterPack(),
+ TInfo);
+ }
+ CanonParams.push_back(Param);
+
+ } else
CanonParams.push_back(getCanonicalTemplateTemplateParmDecl(
cast<TemplateTemplateParmDecl>(*P)));
}
@@ -117,7 +152,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
TemplateTemplateParmDecl *CanonTTP
= TemplateTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
SourceLocation(), TTP->getDepth(),
- TTP->getPosition(), 0,
+ TTP->getPosition(),
+ TTP->isParameterPack(),
+ 0,
TemplateParameterList::Create(*this, SourceLocation(),
SourceLocation(),
CanonParams.data(),
@@ -160,12 +197,13 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
CFConstantStringTypeDecl(0), NSConstantStringTypeDecl(0),
ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0),
sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0),
+ cudaConfigureCallDecl(0),
NullTypeSourceInfo(QualType()),
SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), Target(t),
Idents(idents), Selectors(sels),
BuiltinInfo(builtins),
DeclarationNames(*this),
- ExternalSource(0), PrintingPolicy(LOpts),
+ ExternalSource(0), Listener(0), PrintingPolicy(LOpts),
LastSDM(0, 0),
UniqueBlockByRefTypeID(0), UniqueBlockParmTypeID(0) {
ObjCIdRedefinitionType = QualType();
@@ -314,9 +352,12 @@ void ASTContext::InitBuiltinTypes() {
InitBuiltinType(Int128Ty, BuiltinType::Int128);
InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128);
- if (LangOpts.CPlusPlus) // C++ 3.9.1p5
- InitBuiltinType(WCharTy, BuiltinType::WChar);
- else // C99
+ if (LangOpts.CPlusPlus) { // C++ 3.9.1p5
+ if (!LangOpts.ShortWChar)
+ InitBuiltinType(WCharTy, BuiltinType::WChar_S);
+ else // -fshort-wchar makes wchar_t be unsigned.
+ InitBuiltinType(WCharTy, BuiltinType::WChar_U);
+ } else // C99
WCharTy = getFromTargetType(Target.getWCharType());
if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++
@@ -329,9 +370,6 @@ void ASTContext::InitBuiltinTypes() {
else // C99
Char32Ty = getFromTargetType(Target.getChar32Type());
- // Placeholder type for functions.
- InitBuiltinType(OverloadTy, BuiltinType::Overload);
-
// Placeholder type for type-dependent expressions whose type is
// completely unknown. No code should ever check a type against
// DependentTy and users should never see it; however, it is here to
@@ -339,9 +377,8 @@ void ASTContext::InitBuiltinTypes() {
// expressions.
InitBuiltinType(DependentTy, BuiltinType::Dependent);
- // Placeholder type for C++0x auto declarations whose real type has
- // not yet been deduced.
- InitBuiltinType(UndeducedAutoTy, BuiltinType::UndeducedAuto);
+ // Placeholder type for functions.
+ InitBuiltinType(OverloadTy, BuiltinType::Overload);
// C99 6.2.5p11.
FloatComplexTy = getComplexType(FloatTy);
@@ -369,6 +406,10 @@ void ASTContext::InitBuiltinTypes() {
InitBuiltinType(NullPtrTy, BuiltinType::NullPtr);
}
+Diagnostic &ASTContext::getDiagnostics() const {
+ return SourceMgr.getDiagnostics();
+}
+
AttrVec& ASTContext::getDeclAttrs(const Decl *D) {
AttrVec *&Result = DeclAttrs[D];
if (!Result) {
@@ -525,12 +566,33 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
/// 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) {
+CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const {
unsigned Align = Target.getCharWidth();
- Align = std::max(Align, D->getMaxAlignment());
+ bool UseAlignAttrOnly = false;
+ if (unsigned AlignFromAttr = D->getMaxAlignment()) {
+ Align = AlignFromAttr;
+
+ // __attribute__((aligned)) can increase or decrease alignment
+ // *except* on a struct or struct member, where it only increases
+ // alignment unless 'packed' is also specified.
+ //
+ // It is an error for [[align]] to decrease alignment, so we can
+ // ignore that possibility; Sema should diagnose it.
+ if (isa<FieldDecl>(D)) {
+ UseAlignAttrOnly = D->hasAttr<PackedAttr>() ||
+ cast<FieldDecl>(D)->getParent()->hasAttr<PackedAttr>();
+ } else {
+ UseAlignAttrOnly = true;
+ }
+ }
- if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ // If we're using the align attribute only, just ignore everything
+ // else about the declaration and its type.
+ if (UseAlignAttrOnly) {
+ // do nothing
+
+ } else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
QualType T = VD->getType();
if (const ReferenceType* RT = T->getAs<ReferenceType>()) {
if (RefAsPointee)
@@ -539,41 +601,61 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) {
T = getPointerType(RT->getPointeeType());
}
if (!T->isIncompleteType() && !T->isFunctionType()) {
+ // Adjust alignments of declarations with array type by the
+ // large-array alignment on the target.
unsigned MinWidth = Target.getLargeArrayMinWidth();
- unsigned ArrayAlign = Target.getLargeArrayAlign();
- if (isa<VariableArrayType>(T) && MinWidth != 0)
- Align = std::max(Align, ArrayAlign);
- if (ConstantArrayType *CT = dyn_cast<ConstantArrayType>(T)) {
- unsigned Size = getTypeSize(CT);
- if (MinWidth != 0 && MinWidth <= Size)
- Align = std::max(Align, ArrayAlign);
+ 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());
+
+ // Walk through any array types while we're at it.
+ T = getBaseElementType(arrayType);
}
- // Incomplete or function types default to 1.
- while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T))
- T = cast<ArrayType>(T)->getElementType();
-
Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr()));
}
- if (const FieldDecl *FD = dyn_cast<FieldDecl>(VD)) {
- // In the case of a field in a packed struct, we want the minimum
- // of the alignment of the field and the alignment of the struct.
- Align = std::min(Align,
- getPreferredTypeAlign(FD->getParent()->getTypeForDecl()));
+
+ // Fields can be subject to extra alignment constraints, like if
+ // the field is packed, the struct is packed, or the struct has a
+ // 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);
+ }
+
+ Align = std::min(Align, fieldAlign);
}
}
- return CharUnits::fromQuantity(Align / Target.getCharWidth());
+ return toCharUnitsFromBits(Align);
}
std::pair<CharUnits, CharUnits>
-ASTContext::getTypeInfoInChars(const Type *T) {
+ASTContext::getTypeInfoInChars(const Type *T) const {
std::pair<uint64_t, unsigned> Info = getTypeInfo(T);
- return std::make_pair(CharUnits::fromQuantity(Info.first / getCharWidth()),
- CharUnits::fromQuantity(Info.second / getCharWidth()));
+ return std::make_pair(toCharUnitsFromBits(Info.first),
+ toCharUnitsFromBits(Info.second));
}
std::pair<CharUnits, CharUnits>
-ASTContext::getTypeInfoInChars(QualType T) {
+ASTContext::getTypeInfoInChars(QualType T) const {
return getTypeInfoInChars(T.getTypePtr());
}
@@ -584,7 +666,7 @@ ASTContext::getTypeInfoInChars(QualType T) {
/// alignment requirements: getPointerInfo should take an AddrSpace, this
/// should take a QualType, &c.
std::pair<uint64_t, unsigned>
-ASTContext::getTypeInfo(const Type *T) {
+ASTContext::getTypeInfo(const Type *T) const {
uint64_t Width=0;
unsigned Align=8;
switch (T->getTypeClass()) {
@@ -652,7 +734,8 @@ ASTContext::getTypeInfo(const Type *T) {
Width = Target.getCharWidth();
Align = Target.getCharAlign();
break;
- case BuiltinType::WChar:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
Width = Target.getWCharWidth();
Align = Target.getWCharAlign();
break;
@@ -760,8 +843,8 @@ ASTContext::getTypeInfo(const Type *T) {
case Type::ObjCInterface: {
const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T);
const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl());
- Width = Layout.getSize();
- Align = Layout.getAlignment();
+ Width = toBits(Layout.getSize());
+ Align = toBits(Layout.getAlignment());
break;
}
case Type::Record:
@@ -779,8 +862,8 @@ ASTContext::getTypeInfo(const Type *T) {
const RecordType *RT = cast<RecordType>(TT);
const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl());
- Width = Layout.getSize();
- Align = Layout.getAlignment();
+ Width = toBits(Layout.getSize());
+ Align = toBits(Layout.getAlignment());
break;
}
@@ -788,11 +871,26 @@ ASTContext::getTypeInfo(const Type *T) {
return getTypeInfo(cast<SubstTemplateTypeParmType>(T)->
getReplacementType().getTypePtr());
+ case Type::Auto: {
+ const AutoType *A = cast<AutoType>(T);
+ assert(A->isDeduced() && "Cannot request the size of a dependent type");
+ return getTypeInfo(cast<AutoType>(T)->getDeducedType().getTypePtr());
+ }
+
+ case Type::Paren:
+ return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr());
+
case Type::Typedef: {
const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl();
std::pair<uint64_t, unsigned> Info
= getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
- Align = std::max(Typedef->getMaxAlignment(), Info.second);
+ // If the typedef has an aligned attribute on it, it overrides any computed
+ // alignment we have. This violates the GCC documentation (which says that
+ // attribute(aligned) can only round up) but matches its implementation.
+ if (unsigned AttrAlign = Typedef->getMaxAlignment())
+ Align = AttrAlign;
+ else
+ Align = Info.second;
Width = Info.first;
break;
}
@@ -811,6 +909,10 @@ ASTContext::getTypeInfo(const Type *T) {
case Type::Elaborated:
return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr());
+ case Type::Attributed:
+ return getTypeInfo(
+ cast<AttributedType>(T)->getEquivalentType().getTypePtr());
+
case Type::TemplateSpecialization:
assert(getCanonicalType(T) != T &&
"Cannot request the size of a dependent type");
@@ -824,29 +926,39 @@ ASTContext::getTypeInfo(const Type *T) {
return std::make_pair(Width, Align);
}
+/// toCharUnitsFromBits - Convert a size in bits to a size in characters.
+CharUnits ASTContext::toCharUnitsFromBits(int64_t BitSize) const {
+ return CharUnits::fromQuantity(BitSize / getCharWidth());
+}
+
+/// toBits - Convert a size in characters to a size in characters.
+int64_t ASTContext::toBits(CharUnits CharSize) const {
+ return CharSize.getQuantity() * getCharWidth();
+}
+
/// getTypeSizeInChars - Return the size of the specified type, in characters.
/// This method does not work on incomplete types.
-CharUnits ASTContext::getTypeSizeInChars(QualType T) {
- return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth());
+CharUnits ASTContext::getTypeSizeInChars(QualType T) const {
+ return toCharUnitsFromBits(getTypeSize(T));
}
-CharUnits ASTContext::getTypeSizeInChars(const Type *T) {
- return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth());
+CharUnits ASTContext::getTypeSizeInChars(const Type *T) const {
+ return toCharUnitsFromBits(getTypeSize(T));
}
/// getTypeAlignInChars - Return the ABI-specified alignment of a type, in
/// characters. This method does not work on incomplete types.
-CharUnits ASTContext::getTypeAlignInChars(QualType T) {
- return CharUnits::fromQuantity(getTypeAlign(T) / getCharWidth());
+CharUnits ASTContext::getTypeAlignInChars(QualType T) const {
+ return toCharUnitsFromBits(getTypeAlign(T));
}
-CharUnits ASTContext::getTypeAlignInChars(const Type *T) {
- return CharUnits::fromQuantity(getTypeAlign(T) / getCharWidth());
+CharUnits ASTContext::getTypeAlignInChars(const Type *T) const {
+ return toCharUnitsFromBits(getTypeAlign(T));
}
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
/// type for the current target in bits. This can be different than the ABI
/// alignment in cases where it is beneficial for performance to overalign
/// a data type.
-unsigned ASTContext::getPreferredTypeAlign(const Type *T) {
+unsigned ASTContext::getPreferredTypeAlign(const Type *T) const {
unsigned ABIAlign = getTypeAlign(T);
// Double and long long should be naturally aligned if possible.
@@ -863,7 +975,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) {
/// Collect all ivars, including those synthesized, in the current class.
///
void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
- llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
+ llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const {
// FIXME. This need be removed but there are two many places which
// assume const-ness of ObjCInterfaceDecl
ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(OI);
@@ -880,7 +992,7 @@ void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI,
///
void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI,
bool leafClass,
- llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) {
+ llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const {
if (const ObjCInterfaceDecl *SuperClass = OI->getSuperClass())
DeepCollectObjCIvars(SuperClass, false, Ivars);
if (!leafClass) {
@@ -940,7 +1052,7 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
}
}
-unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) {
+unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const {
unsigned count = 0;
// Count ivars declared in class extension.
for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl;
@@ -985,6 +1097,25 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD,
ObjCImpls[CatD] = ImplD;
}
+/// \brief Get the copy initialization expression of VarDecl,or NULL if
+/// none exists.
+Expr *ASTContext::getBlockVarCopyInits(const VarDecl*VD) {
+ assert(VD && "Passed null params");
+ assert(VD->hasAttr<BlocksAttr>() &&
+ "getBlockVarCopyInits - not __block var");
+ llvm::DenseMap<const VarDecl*, Expr*>::iterator
+ I = BlockVarCopyInits.find(VD);
+ return (I != BlockVarCopyInits.end()) ? cast<Expr>(I->second) : 0;
+}
+
+/// \brief Set the copy inialization expression of a block var decl.
+void ASTContext::setBlockVarCopyInits(VarDecl*VD, Expr* Init) {
+ assert(VD && Init && "Passed null params");
+ assert(VD->hasAttr<BlocksAttr>() &&
+ "setBlockVarCopyInits - not __block var");
+ BlockVarCopyInits[VD] = Init;
+}
+
/// \brief Allocate an uninitialized TypeSourceInfo.
///
/// The caller should initialize the memory held by TypeSourceInfo using
@@ -994,7 +1125,7 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD,
/// should refer to how the declarator was written in source code, not to
/// what type semantic analysis resolved the declarator to.
TypeSourceInfo *ASTContext::CreateTypeSourceInfo(QualType T,
- unsigned DataSize) {
+ unsigned DataSize) const {
if (!DataSize)
DataSize = TypeLoc::getFullDataSizeForType(T);
else
@@ -1008,19 +1139,20 @@ TypeSourceInfo *ASTContext::CreateTypeSourceInfo(QualType T,
}
TypeSourceInfo *ASTContext::getTrivialTypeSourceInfo(QualType T,
- SourceLocation L) {
+ SourceLocation L) const {
TypeSourceInfo *DI = CreateTypeSourceInfo(T);
- DI->getTypeLoc().initialize(L);
+ DI->getTypeLoc().initialize(const_cast<ASTContext &>(*this), L);
return DI;
}
const ASTRecordLayout &
-ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) {
+ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) const {
return getObjCLayout(D, 0);
}
const ASTRecordLayout &
-ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) {
+ASTContext::getASTObjCImplementationLayout(
+ const ObjCImplementationDecl *D) const {
return getObjCLayout(D->getClassInterface(), D);
}
@@ -1028,38 +1160,38 @@ ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) {
// Type creation/memoization methods
//===----------------------------------------------------------------------===//
-QualType ASTContext::getExtQualType(const Type *TypeNode, Qualifiers Quals) {
- unsigned Fast = Quals.getFastQualifiers();
- Quals.removeFastQualifiers();
+QualType
+ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const {
+ unsigned fastQuals = quals.getFastQualifiers();
+ quals.removeFastQualifiers();
// Check if we've already instantiated this type.
llvm::FoldingSetNodeID ID;
- ExtQuals::Profile(ID, TypeNode, Quals);
- void *InsertPos = 0;
- if (ExtQuals *EQ = ExtQualNodes.FindNodeOrInsertPos(ID, InsertPos)) {
- assert(EQ->getQualifiers() == Quals);
- QualType T = QualType(EQ, Fast);
- return T;
+ ExtQuals::Profile(ID, baseType, quals);
+ void *insertPos = 0;
+ if (ExtQuals *eq = ExtQualNodes.FindNodeOrInsertPos(ID, insertPos)) {
+ assert(eq->getQualifiers() == quals);
+ return QualType(eq, fastQuals);
}
- ExtQuals *New = new (*this, TypeAlignment) ExtQuals(*this, TypeNode, Quals);
- ExtQualNodes.InsertNode(New, InsertPos);
- QualType T = QualType(New, Fast);
- return T;
-}
-
-QualType ASTContext::getVolatileType(QualType T) {
- QualType CanT = getCanonicalType(T);
- if (CanT.isVolatileQualified()) return T;
+ // If the base type is not canonical, make the appropriate canonical type.
+ QualType canon;
+ if (!baseType->isCanonicalUnqualified()) {
+ SplitQualType canonSplit = baseType->getCanonicalTypeInternal().split();
+ canonSplit.second.addConsistentQualifiers(quals);
+ canon = getExtQualType(canonSplit.first, canonSplit.second);
- QualifierCollector Quals;
- const Type *TypeNode = Quals.strip(T);
- Quals.addVolatile();
+ // Re-find the insert position.
+ (void) ExtQualNodes.FindNodeOrInsertPos(ID, insertPos);
+ }
- return getExtQualType(TypeNode, Quals);
+ ExtQuals *eq = new (*this, TypeAlignment) ExtQuals(baseType, canon, quals);
+ ExtQualNodes.InsertNode(eq, insertPos);
+ return QualType(eq, fastQuals);
}
-QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) {
+QualType
+ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) const {
QualType CanT = getCanonicalType(T);
if (CanT.getAddressSpace() == AddressSpace)
return T;
@@ -1079,13 +1211,13 @@ QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) {
}
QualType ASTContext::getObjCGCQualType(QualType T,
- Qualifiers::GC GCAttr) {
+ Qualifiers::GC GCAttr) const {
QualType CanT = getCanonicalType(T);
if (CanT.getObjCGCAttr() == GCAttr)
return T;
- if (T->isPointerType()) {
- QualType Pointee = T->getAs<PointerType>()->getPointeeType();
+ if (const PointerType *ptr = T->getAs<PointerType>()) {
+ QualType Pointee = ptr->getPointeeType();
if (Pointee->isAnyPointerType()) {
QualType ResultType = getObjCGCQualType(Pointee, GCAttr);
return getPointerType(ResultType);
@@ -1106,79 +1238,28 @@ QualType ASTContext::getObjCGCQualType(QualType T,
return getExtQualType(TypeNode, Quals);
}
-static QualType getExtFunctionType(ASTContext& Context, QualType T,
- const FunctionType::ExtInfo &Info) {
- QualType ResultType;
- if (const PointerType *Pointer = T->getAs<PointerType>()) {
- QualType Pointee = Pointer->getPointeeType();
- ResultType = getExtFunctionType(Context, Pointee, Info);
- if (ResultType == Pointee)
- return T;
-
- ResultType = Context.getPointerType(ResultType);
- } else if (const BlockPointerType *BlockPointer
- = T->getAs<BlockPointerType>()) {
- QualType Pointee = BlockPointer->getPointeeType();
- ResultType = getExtFunctionType(Context, Pointee, Info);
- if (ResultType == Pointee)
- return T;
-
- ResultType = Context.getBlockPointerType(ResultType);
- } else if (const MemberPointerType *MemberPointer
- = T->getAs<MemberPointerType>()) {
- QualType Pointee = MemberPointer->getPointeeType();
- ResultType = getExtFunctionType(Context, Pointee, Info);
- if (ResultType == Pointee)
- return T;
-
- ResultType = Context.getMemberPointerType(ResultType,
- MemberPointer->getClass());
- } else if (const FunctionType *F = T->getAs<FunctionType>()) {
- if (F->getExtInfo() == Info)
- return T;
-
- if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) {
- ResultType = Context.getFunctionNoProtoType(FNPT->getResultType(),
- Info);
- } else {
- const FunctionProtoType *FPT = cast<FunctionProtoType>(F);
- ResultType
- = Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
- FPT->getNumArgs(), FPT->isVariadic(),
- FPT->getTypeQuals(),
- FPT->hasExceptionSpec(),
- FPT->hasAnyExceptionSpec(),
- FPT->getNumExceptions(),
- FPT->exception_begin(),
- Info);
- }
- } else
+const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
+ FunctionType::ExtInfo Info) {
+ if (T->getExtInfo() == Info)
return T;
- return Context.getQualifiedType(ResultType, T.getLocalQualifiers());
-}
-
-QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) {
- FunctionType::ExtInfo Info = getFunctionExtInfo(T);
- return getExtFunctionType(*this, T,
- Info.withNoReturn(AddNoReturn));
-}
-
-QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) {
- FunctionType::ExtInfo Info = getFunctionExtInfo(T);
- return getExtFunctionType(*this, T,
- Info.withCallingConv(CallConv));
-}
+ QualType Result;
+ if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(T)) {
+ Result = getFunctionNoProtoType(FNPT->getResultType(), Info);
+ } else {
+ const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.ExtInfo = Info;
+ Result = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
+ FPT->getNumArgs(), EPI);
+ }
-QualType ASTContext::getRegParmType(QualType T, unsigned RegParm) {
- FunctionType::ExtInfo Info = getFunctionExtInfo(T);
- return getExtFunctionType(*this, T,
- Info.withRegParm(RegParm));
+ return cast<FunctionType>(Result.getTypePtr());
}
/// getComplexType - Return the uniqued reference to the type for a complex
/// number with the specified element type.
-QualType ASTContext::getComplexType(QualType T) {
+QualType ASTContext::getComplexType(QualType T) const {
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1196,7 +1277,7 @@ QualType ASTContext::getComplexType(QualType T) {
// Get the new insert position for the node we care about.
ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
ComplexType *New = new (*this, TypeAlignment) ComplexType(T, Canonical);
Types.push_back(New);
@@ -1206,7 +1287,7 @@ QualType ASTContext::getComplexType(QualType T) {
/// getPointerType - Return the uniqued reference to the type for a pointer to
/// the specified type.
-QualType ASTContext::getPointerType(QualType T) {
+QualType ASTContext::getPointerType(QualType T) const {
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1224,7 +1305,7 @@ QualType ASTContext::getPointerType(QualType T) {
// Get the new insert position for the node we care about.
PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
PointerType *New = new (*this, TypeAlignment) PointerType(T, Canonical);
Types.push_back(New);
@@ -1234,7 +1315,7 @@ QualType ASTContext::getPointerType(QualType T) {
/// getBlockPointerType - Return the uniqued reference to the type for
/// a pointer to the specified block.
-QualType ASTContext::getBlockPointerType(QualType T) {
+QualType ASTContext::getBlockPointerType(QualType T) const {
assert(T->isFunctionType() && "block of function types only");
// Unique pointers, to guarantee there is only one block of a particular
// structure.
@@ -1255,7 +1336,7 @@ QualType ASTContext::getBlockPointerType(QualType T) {
// Get the new insert position for the node we care about.
BlockPointerType *NewIP =
BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
BlockPointerType *New
= new (*this, TypeAlignment) BlockPointerType(T, Canonical);
@@ -1266,7 +1347,8 @@ QualType ASTContext::getBlockPointerType(QualType T) {
/// getLValueReferenceType - Return the uniqued reference to the type for an
/// lvalue reference to the specified type.
-QualType ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) {
+QualType
+ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) const {
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1289,7 +1371,7 @@ QualType ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) {
// Get the new insert position for the node we care about.
LValueReferenceType *NewIP =
LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
LValueReferenceType *New
@@ -1303,7 +1385,7 @@ QualType ASTContext::getLValueReferenceType(QualType T, bool SpelledAsLValue) {
/// getRValueReferenceType - Return the uniqued reference to the type for an
/// rvalue reference to the specified type.
-QualType ASTContext::getRValueReferenceType(QualType T) {
+QualType ASTContext::getRValueReferenceType(QualType T) const {
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1326,7 +1408,7 @@ QualType ASTContext::getRValueReferenceType(QualType T) {
// Get the new insert position for the node we care about.
RValueReferenceType *NewIP =
RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
RValueReferenceType *New
@@ -1338,7 +1420,7 @@ QualType ASTContext::getRValueReferenceType(QualType T) {
/// getMemberPointerType - Return the uniqued reference to the type for a
/// member pointer to the specified type, in the specified class.
-QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) {
+QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) const {
// Unique pointers, to guarantee there is only one pointer of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1358,7 +1440,7 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) {
// Get the new insert position for the node we care about.
MemberPointerType *NewIP =
MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
MemberPointerType *New
= new (*this, TypeAlignment) MemberPointerType(T, Cls, Canonical);
@@ -1372,7 +1454,7 @@ QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) {
QualType ASTContext::getConstantArrayType(QualType EltTy,
const llvm::APInt &ArySizeIn,
ArrayType::ArraySizeModifier ASM,
- unsigned EltTypeQuals) {
+ unsigned IndexTypeQuals) const {
assert((EltTy->isDependentType() ||
EltTy->isIncompleteType() || EltTy->isConstantSizeType()) &&
"Constant array of VLAs is illegal!");
@@ -1380,55 +1462,185 @@ QualType ASTContext::getConstantArrayType(QualType EltTy,
// Convert the array size into a canonical width matching the pointer size for
// the target.
llvm::APInt ArySize(ArySizeIn);
- ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace()));
+ ArySize =
+ ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace()));
llvm::FoldingSetNodeID ID;
- ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, EltTypeQuals);
+ ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals);
void *InsertPos = 0;
if (ConstantArrayType *ATP =
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(ATP, 0);
- // If the element type isn't canonical, this won't be a canonical type either,
- // so fill in the canonical type field.
- QualType Canonical;
- if (!EltTy.isCanonical()) {
- Canonical = getConstantArrayType(getCanonicalType(EltTy), ArySize,
- ASM, EltTypeQuals);
+ // If the element type isn't canonical or has qualifiers, this won't
+ // be a canonical type either, so fill in the canonical type field.
+ QualType Canon;
+ if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
+ SplitQualType canonSplit = getCanonicalType(EltTy).split();
+ Canon = getConstantArrayType(QualType(canonSplit.first, 0), ArySize,
+ ASM, IndexTypeQuals);
+ Canon = getQualifiedType(Canon, canonSplit.second);
+
// Get the new insert position for the node we care about.
ConstantArrayType *NewIP =
ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
ConstantArrayType *New = new(*this,TypeAlignment)
- ConstantArrayType(EltTy, Canonical, ArySize, ASM, EltTypeQuals);
+ ConstantArrayType(EltTy, Canon, ArySize, ASM, IndexTypeQuals);
ConstantArrayTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
}
+/// getVariableArrayDecayedType - Turns the given type, which may be
+/// variably-modified, into the corresponding type with all the known
+/// sizes replaced with [*].
+QualType ASTContext::getVariableArrayDecayedType(QualType type) const {
+ // Vastly most common case.
+ if (!type->isVariablyModifiedType()) return type;
+
+ QualType result;
+
+ SplitQualType split = type.getSplitDesugaredType();
+ const Type *ty = split.first;
+ switch (ty->getTypeClass()) {
+#define TYPE(Class, Base)
+#define ABSTRACT_TYPE(Class, Base)
+#define NON_CANONICAL_TYPE(Class, Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("didn't desugar past all non-canonical types?");
+
+ // These types should never be variably-modified.
+ case Type::Builtin:
+ case Type::Complex:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::DependentSizedExtVector:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ case Type::ObjCObjectPointer:
+ case Type::Record:
+ case Type::Enum:
+ case Type::UnresolvedUsing:
+ case Type::TypeOfExpr:
+ case Type::TypeOf:
+ case Type::Decltype:
+ case Type::DependentName:
+ case Type::InjectedClassName:
+ case Type::TemplateSpecialization:
+ case Type::DependentTemplateSpecialization:
+ case Type::TemplateTypeParm:
+ case Type::SubstTemplateTypeParmPack:
+ case Type::Auto:
+ case Type::PackExpansion:
+ llvm_unreachable("type should never be variably-modified");
+
+ // These types can be variably-modified but should never need to
+ // further decay.
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
+ case Type::BlockPointer:
+ case Type::MemberPointer:
+ return type;
+
+ // These types can be variably-modified. All these modifications
+ // preserve structure except as noted by comments.
+ // TODO: if we ever care about optimizing VLAs, there are no-op
+ // optimizations available here.
+ case Type::Pointer:
+ result = getPointerType(getVariableArrayDecayedType(
+ cast<PointerType>(ty)->getPointeeType()));
+ break;
+
+ case Type::LValueReference: {
+ const LValueReferenceType *lv = cast<LValueReferenceType>(ty);
+ result = getLValueReferenceType(
+ getVariableArrayDecayedType(lv->getPointeeType()),
+ lv->isSpelledAsLValue());
+ break;
+ }
+
+ case Type::RValueReference: {
+ const RValueReferenceType *lv = cast<RValueReferenceType>(ty);
+ result = getRValueReferenceType(
+ getVariableArrayDecayedType(lv->getPointeeType()));
+ break;
+ }
+
+ case Type::ConstantArray: {
+ const ConstantArrayType *cat = cast<ConstantArrayType>(ty);
+ result = getConstantArrayType(
+ getVariableArrayDecayedType(cat->getElementType()),
+ cat->getSize(),
+ cat->getSizeModifier(),
+ cat->getIndexTypeCVRQualifiers());
+ break;
+ }
+
+ case Type::DependentSizedArray: {
+ const DependentSizedArrayType *dat = cast<DependentSizedArrayType>(ty);
+ result = getDependentSizedArrayType(
+ getVariableArrayDecayedType(dat->getElementType()),
+ dat->getSizeExpr(),
+ dat->getSizeModifier(),
+ dat->getIndexTypeCVRQualifiers(),
+ dat->getBracketsRange());
+ break;
+ }
+
+ // Turn incomplete types into [*] types.
+ case Type::IncompleteArray: {
+ const IncompleteArrayType *iat = cast<IncompleteArrayType>(ty);
+ result = getVariableArrayType(
+ getVariableArrayDecayedType(iat->getElementType()),
+ /*size*/ 0,
+ ArrayType::Normal,
+ iat->getIndexTypeCVRQualifiers(),
+ SourceRange());
+ break;
+ }
+
+ // Turn VLA types into [*] types.
+ case Type::VariableArray: {
+ const VariableArrayType *vat = cast<VariableArrayType>(ty);
+ result = getVariableArrayType(
+ getVariableArrayDecayedType(vat->getElementType()),
+ /*size*/ 0,
+ ArrayType::Star,
+ vat->getIndexTypeCVRQualifiers(),
+ vat->getBracketsRange());
+ break;
+ }
+ }
+
+ // Apply the top-level qualifiers from the original.
+ return getQualifiedType(result, split.second);
+}
+
/// getVariableArrayType - Returns a non-unique reference to the type for a
/// variable array of the specified element type.
QualType ASTContext::getVariableArrayType(QualType EltTy,
Expr *NumElts,
ArrayType::ArraySizeModifier ASM,
- unsigned EltTypeQuals,
- SourceRange Brackets) {
+ unsigned IndexTypeQuals,
+ SourceRange Brackets) const {
// Since we don't unique expressions, it isn't possible to unique VLA's
// that have an expression provided for their size.
- QualType CanonType;
+ QualType Canon;
- if (!EltTy.isCanonical()) {
- if (NumElts)
- NumElts->Retain();
- CanonType = getVariableArrayType(getCanonicalType(EltTy), NumElts, ASM,
- EltTypeQuals, Brackets);
+ // Be sure to pull qualifiers off the element type.
+ if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) {
+ SplitQualType canonSplit = getCanonicalType(EltTy).split();
+ Canon = getVariableArrayType(QualType(canonSplit.first, 0), NumElts, ASM,
+ IndexTypeQuals, Brackets);
+ Canon = getQualifiedType(Canon, canonSplit.second);
}
VariableArrayType *New = new(*this, TypeAlignment)
- VariableArrayType(EltTy, CanonType, NumElts, ASM, EltTypeQuals, Brackets);
+ VariableArrayType(EltTy, Canon, NumElts, ASM, IndexTypeQuals, Brackets);
VariableArrayTypes.push_back(New);
Types.push_back(New);
@@ -1438,109 +1650,118 @@ QualType ASTContext::getVariableArrayType(QualType EltTy,
/// getDependentSizedArrayType - Returns a non-unique reference to
/// the type for a dependently-sized array of the specified element
/// type.
-QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
- Expr *NumElts,
+QualType ASTContext::getDependentSizedArrayType(QualType elementType,
+ Expr *numElements,
ArrayType::ArraySizeModifier ASM,
- unsigned EltTypeQuals,
- SourceRange Brackets) {
- assert((!NumElts || NumElts->isTypeDependent() ||
- NumElts->isValueDependent()) &&
+ unsigned elementTypeQuals,
+ SourceRange brackets) const {
+ assert((!numElements || numElements->isTypeDependent() ||
+ numElements->isValueDependent()) &&
"Size must be type- or value-dependent!");
- void *InsertPos = 0;
- DependentSizedArrayType *Canon = 0;
- llvm::FoldingSetNodeID ID;
-
- if (NumElts) {
- // Dependently-sized array types that do not have a specified
- // number of elements will have their sizes deduced from an
- // initializer.
- DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM,
- EltTypeQuals, NumElts);
-
- Canon = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+ // Dependently-sized array types that do not have a specified number
+ // of elements will have their sizes deduced from a dependent
+ // initializer. We do no canonicalization here at all, which is okay
+ // because they can't be used in most locations.
+ if (!numElements) {
+ DependentSizedArrayType *newType
+ = new (*this, TypeAlignment)
+ DependentSizedArrayType(*this, elementType, QualType(),
+ numElements, ASM, elementTypeQuals,
+ brackets);
+ Types.push_back(newType);
+ return QualType(newType, 0);
}
- DependentSizedArrayType *New;
- if (Canon) {
- // We already have a canonical version of this array type; use it as
- // the canonical type for a newly-built type.
- New = new (*this, TypeAlignment)
- DependentSizedArrayType(*this, EltTy, QualType(Canon, 0),
- NumElts, ASM, EltTypeQuals, Brackets);
- } else {
- QualType CanonEltTy = getCanonicalType(EltTy);
- if (CanonEltTy == EltTy) {
- New = new (*this, TypeAlignment)
- DependentSizedArrayType(*this, EltTy, QualType(),
- NumElts, ASM, EltTypeQuals, Brackets);
-
- if (NumElts) {
- DependentSizedArrayType *CanonCheck
- = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(!CanonCheck && "Dependent-sized canonical array type broken");
- (void)CanonCheck;
- DependentSizedArrayTypes.InsertNode(New, InsertPos);
- }
- } else {
- QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts,
- ASM, EltTypeQuals,
- SourceRange());
- New = new (*this, TypeAlignment)
- DependentSizedArrayType(*this, EltTy, Canon,
- NumElts, ASM, EltTypeQuals, Brackets);
- }
- }
+ // Otherwise, we actually build a new type every time, but we
+ // also build a canonical type.
- Types.push_back(New);
- return QualType(New, 0);
-}
+ SplitQualType canonElementType = getCanonicalType(elementType).split();
-QualType ASTContext::getIncompleteArrayType(QualType EltTy,
+ void *insertPos = 0;
+ llvm::FoldingSetNodeID ID;
+ DependentSizedArrayType::Profile(ID, *this,
+ QualType(canonElementType.first, 0),
+ ASM, elementTypeQuals, numElements);
+
+ // Look for an existing type with these properties.
+ DependentSizedArrayType *canonTy =
+ DependentSizedArrayTypes.FindNodeOrInsertPos(ID, insertPos);
+
+ // If we don't have one, build one.
+ if (!canonTy) {
+ canonTy = new (*this, TypeAlignment)
+ DependentSizedArrayType(*this, QualType(canonElementType.first, 0),
+ QualType(), numElements, ASM, elementTypeQuals,
+ brackets);
+ DependentSizedArrayTypes.InsertNode(canonTy, insertPos);
+ Types.push_back(canonTy);
+ }
+
+ // Apply qualifiers from the element type to the array.
+ QualType canon = getQualifiedType(QualType(canonTy,0),
+ canonElementType.second);
+
+ // If we didn't need extra canonicalization for the element type,
+ // then just use that as our result.
+ if (QualType(canonElementType.first, 0) == elementType)
+ return canon;
+
+ // Otherwise, we need to build a type which follows the spelling
+ // of the element type.
+ DependentSizedArrayType *sugaredType
+ = new (*this, TypeAlignment)
+ DependentSizedArrayType(*this, elementType, canon, numElements,
+ ASM, elementTypeQuals, brackets);
+ Types.push_back(sugaredType);
+ return QualType(sugaredType, 0);
+}
+
+QualType ASTContext::getIncompleteArrayType(QualType elementType,
ArrayType::ArraySizeModifier ASM,
- unsigned EltTypeQuals) {
+ unsigned elementTypeQuals) const {
llvm::FoldingSetNodeID ID;
- IncompleteArrayType::Profile(ID, EltTy, ASM, EltTypeQuals);
+ IncompleteArrayType::Profile(ID, elementType, ASM, elementTypeQuals);
- void *InsertPos = 0;
- if (IncompleteArrayType *ATP =
- IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos))
- return QualType(ATP, 0);
+ void *insertPos = 0;
+ if (IncompleteArrayType *iat =
+ IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos))
+ return QualType(iat, 0);
// If the element type isn't canonical, this won't be a canonical type
- // either, so fill in the canonical type field.
- QualType Canonical;
+ // either, so fill in the canonical type field. We also have to pull
+ // qualifiers off the element type.
+ QualType canon;
- if (!EltTy.isCanonical()) {
- Canonical = getIncompleteArrayType(getCanonicalType(EltTy),
- ASM, EltTypeQuals);
+ if (!elementType.isCanonical() || elementType.hasLocalQualifiers()) {
+ SplitQualType canonSplit = getCanonicalType(elementType).split();
+ canon = getIncompleteArrayType(QualType(canonSplit.first, 0),
+ ASM, elementTypeQuals);
+ canon = getQualifiedType(canon, canonSplit.second);
// Get the new insert position for the node we care about.
- IncompleteArrayType *NewIP =
- IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ IncompleteArrayType *existing =
+ IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos);
+ assert(!existing && "Shouldn't be in the map!"); (void) existing;
}
- IncompleteArrayType *New = new (*this, TypeAlignment)
- IncompleteArrayType(EltTy, Canonical, ASM, EltTypeQuals);
+ IncompleteArrayType *newType = new (*this, TypeAlignment)
+ IncompleteArrayType(elementType, canon, ASM, elementTypeQuals);
- IncompleteArrayTypes.InsertNode(New, InsertPos);
- Types.push_back(New);
- return QualType(New, 0);
+ IncompleteArrayTypes.InsertNode(newType, insertPos);
+ Types.push_back(newType);
+ return QualType(newType, 0);
}
/// getVectorType - Return the unique reference to a vector type of
/// the specified element type and size. VectorType must be a built-in type.
QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
- VectorType::AltiVecSpecific AltiVecSpec) {
- BuiltinType *baseType;
-
- baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
- assert(baseType != 0 && "getVectorType(): Expecting a built-in type");
+ VectorType::VectorKind VecKind) const {
+ assert(vecType->isBuiltinType());
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
- VectorType::Profile(ID, vecType, NumElts, Type::Vector, AltiVecSpec);
+ VectorType::Profile(ID, vecType, NumElts, Type::Vector, VecKind);
void *InsertPos = 0;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
@@ -1550,15 +1771,14 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
// so fill in the canonical type field.
QualType Canonical;
if (!vecType.isCanonical()) {
- Canonical = getVectorType(getCanonicalType(vecType), NumElts,
- VectorType::NotAltiVec);
+ Canonical = getVectorType(getCanonicalType(vecType), NumElts, VecKind);
// Get the new insert position for the node we care about.
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
VectorType *New = new (*this, TypeAlignment)
- VectorType(vecType, NumElts, Canonical, AltiVecSpec);
+ VectorType(vecType, NumElts, Canonical, VecKind);
VectorTypes.InsertNode(New, InsertPos);
Types.push_back(New);
return QualType(New, 0);
@@ -1566,16 +1786,14 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
/// getExtVectorType - Return the unique reference to an extended vector type of
/// the specified element type and size. VectorType must be a built-in type.
-QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) {
- BuiltinType *baseType;
-
- baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr());
- assert(baseType != 0 && "getExtVectorType(): Expecting a built-in type");
+QualType
+ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) const {
+ assert(vecType->isBuiltinType());
// Check if we've already instantiated a vector of this type.
llvm::FoldingSetNodeID ID;
VectorType::Profile(ID, vecType, NumElts, Type::ExtVector,
- VectorType::NotAltiVec);
+ VectorType::GenericVector);
void *InsertPos = 0;
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
@@ -1588,7 +1806,7 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) {
// Get the new insert position for the node we care about.
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
ExtVectorType *New = new (*this, TypeAlignment)
ExtVectorType(vecType, NumElts, Canonical);
@@ -1597,9 +1815,10 @@ QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) {
return QualType(New, 0);
}
-QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
- Expr *SizeExpr,
- SourceLocation AttrLoc) {
+QualType
+ASTContext::getDependentSizedExtVectorType(QualType vecType,
+ Expr *SizeExpr,
+ SourceLocation AttrLoc) const {
llvm::FoldingSetNodeID ID;
DependentSizedExtVectorType::Profile(ID, *this, getCanonicalType(vecType),
SizeExpr);
@@ -1640,8 +1859,9 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
///
-QualType ASTContext::getFunctionNoProtoType(QualType ResultTy,
- const FunctionType::ExtInfo &Info) {
+QualType
+ASTContext::getFunctionNoProtoType(QualType ResultTy,
+ const FunctionType::ExtInfo &Info) const {
const CallingConv CallConv = Info.getCC();
// Unique functions, to guarantee there is only one function of a particular
// structure.
@@ -1663,7 +1883,7 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy,
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
FunctionNoProtoType *New = new (*this, TypeAlignment)
@@ -1675,19 +1895,14 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy,
/// getFunctionType - Return a normal function type with a typed argument
/// list. isVariadic indicates whether the argument list includes '...'.
-QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
- unsigned NumArgs, bool isVariadic,
- unsigned TypeQuals, bool hasExceptionSpec,
- bool hasAnyExceptionSpec, unsigned NumExs,
- const QualType *ExArray,
- const FunctionType::ExtInfo &Info) {
- const CallingConv CallConv= Info.getCC();
+QualType
+ASTContext::getFunctionType(QualType ResultTy,
+ const QualType *ArgArray, unsigned NumArgs,
+ const FunctionProtoType::ExtProtoInfo &EPI) const {
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic,
- TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
- NumExs, ExArray, Info);
+ FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI);
void *InsertPos = 0;
if (FunctionProtoType *FTP =
@@ -1695,11 +1910,13 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
return QualType(FTP, 0);
// Determine whether the type being created is already canonical or not.
- bool isCanonical = !hasExceptionSpec && ResultTy.isCanonical();
+ bool isCanonical = !EPI.HasExceptionSpec && ResultTy.isCanonical();
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
if (!ArgArray[i].isCanonicalAsParam())
isCanonical = false;
+ const CallingConv CallConv = EPI.ExtInfo.getCC();
+
// If this type isn't canonical, get the canonical version of it.
// The exception spec is not part of the canonical type.
QualType Canonical;
@@ -1709,28 +1926,33 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
for (unsigned i = 0; i != NumArgs; ++i)
CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i]));
+ FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI;
+ if (CanonicalEPI.HasExceptionSpec) {
+ CanonicalEPI.HasExceptionSpec = false;
+ CanonicalEPI.HasAnyExceptionSpec = false;
+ CanonicalEPI.NumExceptions = 0;
+ }
+ CanonicalEPI.ExtInfo
+ = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv));
+
Canonical = getFunctionType(getCanonicalType(ResultTy),
CanonicalArgs.data(), NumArgs,
- isVariadic, TypeQuals, false,
- false, 0, 0,
- Info.withCallingConv(getCanonicalCallConv(CallConv)));
+ CanonicalEPI);
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+ assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP;
}
// FunctionProtoType objects are allocated with extra bytes after them
// for two variable size arrays (for parameter and exception types) at the
// end of them.
- FunctionProtoType *FTP =
- (FunctionProtoType*)Allocate(sizeof(FunctionProtoType) +
- NumArgs*sizeof(QualType) +
- NumExs*sizeof(QualType), TypeAlignment);
- new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic,
- TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
- ExArray, NumExs, Canonical, Info);
+ size_t Size = sizeof(FunctionProtoType) +
+ NumArgs * sizeof(QualType) +
+ EPI.NumExceptions * sizeof(QualType);
+ FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
+ new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, EPI);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
@@ -1752,7 +1974,7 @@ static bool NeedsInjectedClassNameType(const RecordDecl *D) {
/// getInjectedClassNameType - Return the unique reference to the
/// injected class name type for the specified templated declaration.
QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl,
- QualType TST) {
+ QualType TST) const {
assert(NeedsInjectedClassNameType(Decl));
if (Decl->TypeForDecl) {
assert(isa<InjectedClassNameType>(Decl->TypeForDecl));
@@ -1761,16 +1983,17 @@ QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl,
Decl->TypeForDecl = PrevDecl->TypeForDecl;
assert(isa<InjectedClassNameType>(Decl->TypeForDecl));
} else {
- Decl->TypeForDecl =
+ Type *newType =
new (*this, TypeAlignment) InjectedClassNameType(Decl, TST);
- Types.push_back(Decl->TypeForDecl);
+ Decl->TypeForDecl = newType;
+ Types.push_back(newType);
}
return QualType(Decl->TypeForDecl, 0);
}
/// getTypeDeclType - Return the unique reference to the type for the
/// specified type declaration.
-QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) {
+QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const {
assert(Decl && "Passed null for Decl param");
assert(!Decl->TypeForDecl && "TypeForDecl present in slow case");
@@ -1791,56 +2014,81 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) {
return getEnumType(Enum);
} else if (const UnresolvedUsingTypenameDecl *Using =
dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) {
- Decl->TypeForDecl = new (*this, TypeAlignment) UnresolvedUsingType(Using);
+ Type *newType = new (*this, TypeAlignment) UnresolvedUsingType(Using);
+ Decl->TypeForDecl = newType;
+ Types.push_back(newType);
} else
llvm_unreachable("TypeDecl without a type?");
- Types.push_back(Decl->TypeForDecl);
return QualType(Decl->TypeForDecl, 0);
}
/// getTypedefType - Return the unique reference to the type for the
/// specified typename decl.
QualType
-ASTContext::getTypedefType(const TypedefDecl *Decl, QualType Canonical) {
+ASTContext::getTypedefType(const TypedefDecl *Decl, QualType Canonical) const {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
if (Canonical.isNull())
Canonical = getCanonicalType(Decl->getUnderlyingType());
- Decl->TypeForDecl = new(*this, TypeAlignment)
+ TypedefType *newType = new(*this, TypeAlignment)
TypedefType(Type::Typedef, Decl, Canonical);
- Types.push_back(Decl->TypeForDecl);
- return QualType(Decl->TypeForDecl, 0);
+ Decl->TypeForDecl = newType;
+ Types.push_back(newType);
+ return QualType(newType, 0);
}
-QualType ASTContext::getRecordType(const RecordDecl *Decl) {
+QualType ASTContext::getRecordType(const RecordDecl *Decl) const {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
if (const RecordDecl *PrevDecl = Decl->getPreviousDeclaration())
if (PrevDecl->TypeForDecl)
return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0);
- Decl->TypeForDecl = new (*this, TypeAlignment) RecordType(Decl);
- Types.push_back(Decl->TypeForDecl);
- return QualType(Decl->TypeForDecl, 0);
+ RecordType *newType = new (*this, TypeAlignment) RecordType(Decl);
+ Decl->TypeForDecl = newType;
+ Types.push_back(newType);
+ return QualType(newType, 0);
}
-QualType ASTContext::getEnumType(const EnumDecl *Decl) {
+QualType ASTContext::getEnumType(const EnumDecl *Decl) const {
if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0);
if (const EnumDecl *PrevDecl = Decl->getPreviousDeclaration())
if (PrevDecl->TypeForDecl)
return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0);
- Decl->TypeForDecl = new (*this, TypeAlignment) EnumType(Decl);
- Types.push_back(Decl->TypeForDecl);
- return QualType(Decl->TypeForDecl, 0);
+ EnumType *newType = new (*this, TypeAlignment) EnumType(Decl);
+ Decl->TypeForDecl = newType;
+ Types.push_back(newType);
+ return QualType(newType, 0);
}
+QualType ASTContext::getAttributedType(AttributedType::Kind attrKind,
+ QualType modifiedType,
+ QualType equivalentType) {
+ llvm::FoldingSetNodeID id;
+ AttributedType::Profile(id, attrKind, modifiedType, equivalentType);
+
+ void *insertPos = 0;
+ AttributedType *type = AttributedTypes.FindNodeOrInsertPos(id, insertPos);
+ if (type) return QualType(type, 0);
+
+ QualType canon = getCanonicalType(equivalentType);
+ type = new (*this, TypeAlignment)
+ AttributedType(canon, attrKind, modifiedType, equivalentType);
+
+ Types.push_back(type);
+ AttributedTypes.InsertNode(type, insertPos);
+
+ return QualType(type, 0);
+}
+
+
/// \brief Retrieve a substitution-result type.
QualType
ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
- QualType Replacement) {
+ QualType Replacement) const {
assert(Replacement.isCanonical()
&& "replacement types must always be canonical");
@@ -1860,12 +2108,48 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm,
return QualType(SubstParm, 0);
}
+/// \brief Retrieve a
+QualType ASTContext::getSubstTemplateTypeParmPackType(
+ const TemplateTypeParmType *Parm,
+ const TemplateArgument &ArgPack) {
+#ifndef NDEBUG
+ for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(),
+ PEnd = ArgPack.pack_end();
+ P != PEnd; ++P) {
+ assert(P->getKind() == TemplateArgument::Type &&"Pack contains a non-type");
+ assert(P->getAsType().isCanonical() && "Pack contains non-canonical type");
+ }
+#endif
+
+ llvm::FoldingSetNodeID ID;
+ SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack);
+ void *InsertPos = 0;
+ if (SubstTemplateTypeParmPackType *SubstParm
+ = SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(SubstParm, 0);
+
+ QualType Canon;
+ if (!Parm->isCanonicalUnqualified()) {
+ Canon = getCanonicalType(QualType(Parm, 0));
+ Canon = getSubstTemplateTypeParmPackType(cast<TemplateTypeParmType>(Canon),
+ ArgPack);
+ SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos);
+ }
+
+ SubstTemplateTypeParmPackType *SubstParm
+ = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon,
+ ArgPack);
+ Types.push_back(SubstParm);
+ SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos);
+ return QualType(SubstParm, 0);
+}
+
/// \brief Retrieve the template type parameter type for a template
/// parameter or parameter pack with the given depth, index, and (optionally)
/// name.
QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
bool ParameterPack,
- IdentifierInfo *Name) {
+ IdentifierInfo *Name) const {
llvm::FoldingSetNodeID ID;
TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, Name);
void *InsertPos = 0;
@@ -1898,7 +2182,7 @@ TypeSourceInfo *
ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
SourceLocation NameLoc,
const TemplateArgumentListInfo &Args,
- QualType CanonType) {
+ QualType CanonType) const {
QualType TST = getTemplateSpecializationType(Name, Args, CanonType);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
@@ -1915,7 +2199,7 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgumentListInfo &Args,
- QualType Canon) {
+ QualType Canon) const {
unsigned NumArgs = Args.size();
llvm::SmallVector<TemplateArgument, 4> ArgVec;
@@ -1931,7 +2215,7 @@ QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
unsigned NumArgs,
- QualType Canon) {
+ QualType Canon) const {
if (!Canon.isNull())
Canon = getCanonicalType(Canon);
else
@@ -1955,7 +2239,7 @@ ASTContext::getTemplateSpecializationType(TemplateName Template,
QualType
ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
const TemplateArgument *Args,
- unsigned NumArgs) {
+ unsigned NumArgs) const {
// Build the canonical template specialization type.
TemplateName CanonTemplate = getCanonicalTemplateName(Template);
llvm::SmallVector<TemplateArgument, 4> CanonArgs;
@@ -1993,7 +2277,7 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template,
QualType
ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
- QualType NamedType) {
+ QualType NamedType) const {
llvm::FoldingSetNodeID ID;
ElaboratedType::Profile(ID, Keyword, NNS, NamedType);
@@ -2016,10 +2300,34 @@ ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword,
return QualType(T, 0);
}
+QualType
+ASTContext::getParenType(QualType InnerType) const {
+ llvm::FoldingSetNodeID ID;
+ ParenType::Profile(ID, InnerType);
+
+ void *InsertPos = 0;
+ ParenType *T = ParenTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (T)
+ return QualType(T, 0);
+
+ QualType Canon = InnerType;
+ if (!Canon.isCanonical()) {
+ Canon = getCanonicalType(InnerType);
+ ParenType *CheckT = ParenTypes.FindNodeOrInsertPos(ID, InsertPos);
+ assert(!CheckT && "Paren canonical type broken");
+ (void)CheckT;
+ }
+
+ T = new (*this) ParenType(InnerType, Canon);
+ Types.push_back(T);
+ ParenTypes.InsertNode(T, InsertPos);
+ return QualType(T, 0);
+}
+
QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
- QualType Canon) {
+ QualType Canon) const {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
if (Canon.isNull()) {
@@ -2052,7 +2360,7 @@ ASTContext::getDependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
- const TemplateArgumentListInfo &Args) {
+ const TemplateArgumentListInfo &Args) const {
// TODO: avoid this copy
llvm::SmallVector<TemplateArgument, 16> ArgCopy;
for (unsigned I = 0, E = Args.size(); I != E; ++I)
@@ -2068,7 +2376,7 @@ ASTContext::getDependentTemplateSpecializationType(
NestedNameSpecifier *NNS,
const IdentifierInfo *Name,
unsigned NumArgs,
- const TemplateArgument *Args) {
+ const TemplateArgument *Args) const {
assert(NNS->isDependent() && "nested-name-specifier must be dependent");
llvm::FoldingSetNodeID ID;
@@ -2114,6 +2422,33 @@ ASTContext::getDependentTemplateSpecializationType(
return QualType(T, 0);
}
+QualType ASTContext::getPackExpansionType(QualType Pattern,
+ llvm::Optional<unsigned> NumExpansions) {
+ llvm::FoldingSetNodeID ID;
+ PackExpansionType::Profile(ID, Pattern, NumExpansions);
+
+ assert(Pattern->containsUnexpandedParameterPack() &&
+ "Pack expansions must expand one or more parameter packs");
+ void *InsertPos = 0;
+ PackExpansionType *T
+ = PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (T)
+ return QualType(T, 0);
+
+ QualType Canon;
+ if (!Pattern.isCanonical()) {
+ Canon = getPackExpansionType(getCanonicalType(Pattern), NumExpansions);
+
+ // Find the insert position again.
+ PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos);
+ }
+
+ T = new (*this) PackExpansionType(Pattern, Canon, NumExpansions);
+ Types.push_back(T);
+ PackExpansionTypes.InsertNode(T, InsertPos);
+ return QualType(T, 0);
+}
+
/// CmpProtocolNames - Comparison predicate for sorting protocols
/// alphabetically.
static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
@@ -2145,7 +2480,7 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols,
QualType ASTContext::getObjCObjectType(QualType BaseType,
ObjCProtocolDecl * const *Protocols,
- unsigned NumProtocols) {
+ unsigned NumProtocols) const {
// If the base type is an interface and there aren't any protocols
// to add, then the interface type will do just fine.
if (!NumProtocols && isa<ObjCInterfaceType>(BaseType))
@@ -2193,7 +2528,7 @@ QualType ASTContext::getObjCObjectType(QualType BaseType,
/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for
/// the given object type.
-QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) {
+QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) const {
llvm::FoldingSetNodeID ID;
ObjCObjectPointerType::Profile(ID, ObjectT);
@@ -2223,7 +2558,7 @@ QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) {
/// getObjCInterfaceType - Return the unique reference to the type for the
/// specified ObjC interface decl. The list of protocols is optional.
-QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) {
+QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) const {
if (Decl->TypeForDecl)
return QualType(Decl->TypeForDecl, 0);
@@ -2240,7 +2575,7 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) {
/// multiple declarations that refer to "typeof(x)" all contain different
/// DeclRefExpr's. This doesn't effect the type checker, since it operates
/// on canonical type's (which are always unique).
-QualType ASTContext::getTypeOfExprType(Expr *tofExpr) {
+QualType ASTContext::getTypeOfExprType(Expr *tofExpr) const {
TypeOfExprType *toe;
if (tofExpr->isTypeDependent()) {
llvm::FoldingSetNodeID ID;
@@ -2275,7 +2610,7 @@ QualType ASTContext::getTypeOfExprType(Expr *tofExpr) {
/// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be
/// an issue. This doesn't effect the type checker, since it operates
/// on canonical type's (which are always unique).
-QualType ASTContext::getTypeOfType(QualType tofType) {
+QualType ASTContext::getTypeOfType(QualType tofType) const {
QualType Canonical = getCanonicalType(tofType);
TypeOfType *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical);
Types.push_back(tot);
@@ -2284,7 +2619,7 @@ QualType ASTContext::getTypeOfType(QualType tofType) {
/// getDecltypeForExpr - Given an expr, will return the decltype for that
/// expression, according to the rules in C++0x [dcl.type.simple]p4
-static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) {
+static QualType getDecltypeForExpr(const Expr *e, const ASTContext &Context) {
if (e->isTypeDependent())
return Context.DependentTy;
@@ -2308,7 +2643,7 @@ static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) {
// Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is
// defined as T&, otherwise decltype(e) is defined as T.
- if (e->isLvalue(Context) == Expr::LV_Valid)
+ if (e->isLValue())
T = Context.getLValueReferenceType(T);
return T;
@@ -2319,7 +2654,7 @@ static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) {
/// memory savings. Since decltype(t) is fairly uncommon, space shouldn't be
/// an issue. This doesn't effect the type checker, since it operates
/// on canonical type's (which are always unique).
-QualType ASTContext::getDecltypeType(Expr *e) {
+QualType ASTContext::getDecltypeType(Expr *e) const {
DecltypeType *dt;
if (e->isTypeDependent()) {
llvm::FoldingSetNodeID ID;
@@ -2348,9 +2683,17 @@ QualType ASTContext::getDecltypeType(Expr *e) {
return QualType(dt, 0);
}
+/// getAutoType - Unlike many "get<Type>" functions, we don't unique
+/// AutoType AST's.
+QualType ASTContext::getAutoType(QualType DeducedType) const {
+ AutoType *at = new (*this, TypeAlignment) AutoType(DeducedType);
+ Types.push_back(at);
+ return QualType(at, 0);
+}
+
/// getTagDeclType - Return the unique reference to the type for the
/// specified TagDecl (struct/union/class/enum) decl.
-QualType ASTContext::getTagDeclType(const TagDecl *Decl) {
+QualType ASTContext::getTagDeclType(const TagDecl *Decl) const {
assert (Decl);
// FIXME: What is the design on getTagDeclType when it requires casting
// away const? mutable?
@@ -2388,12 +2731,12 @@ QualType ASTContext::getPointerDiffType() const {
// Type Operators
//===----------------------------------------------------------------------===//
-CanQualType ASTContext::getCanonicalParamType(QualType T) {
+CanQualType ASTContext::getCanonicalParamType(QualType T) const {
// Push qualifiers into arrays, and then discard any remaining
// qualifiers.
T = getCanonicalType(T);
+ T = getVariableArrayDecayedType(T);
const Type *Ty = T.getTypePtr();
-
QualType Result;
if (isa<ArrayType>(Ty)) {
Result = getArrayDecayedType(QualType(Ty,0));
@@ -2406,97 +2749,59 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) {
return CanQualType::CreateUnsafe(Result);
}
-/// getCanonicalType - Return the canonical (structural) type corresponding to
-/// the specified potentially non-canonical type. The non-canonical version
-/// of a type may have many "decorated" versions of types. Decorators can
-/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed
-/// to be free of any of these, allowing two canonical types to be compared
-/// for exact equality with a simple pointer comparison.
-CanQualType ASTContext::getCanonicalType(QualType T) {
- QualifierCollector Quals;
- const Type *Ptr = Quals.strip(T);
- QualType CanType = Ptr->getCanonicalTypeInternal();
-
- // The canonical internal type will be the canonical type *except*
- // that we push type qualifiers down through array types.
-
- // If there are no new qualifiers to push down, stop here.
- if (!Quals.hasQualifiers())
- return CanQualType::CreateUnsafe(CanType);
-
- // If the type qualifiers are on an array type, get the canonical
- // type of the array with the qualifiers applied to the element
- // type.
- ArrayType *AT = dyn_cast<ArrayType>(CanType);
- if (!AT)
- return CanQualType::CreateUnsafe(getQualifiedType(CanType, Quals));
-
- // Get the canonical version of the element with the extra qualifiers on it.
- // This can recursively sink qualifiers through multiple levels of arrays.
- QualType NewEltTy = getQualifiedType(AT->getElementType(), Quals);
- NewEltTy = getCanonicalType(NewEltTy);
-
- if (ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT))
- return CanQualType::CreateUnsafe(
- getConstantArrayType(NewEltTy, CAT->getSize(),
- CAT->getSizeModifier(),
- CAT->getIndexTypeCVRQualifiers()));
- if (IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT))
- return CanQualType::CreateUnsafe(
- getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(),
- IAT->getIndexTypeCVRQualifiers()));
-
- if (DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(AT))
- return CanQualType::CreateUnsafe(
- getDependentSizedArrayType(NewEltTy,
- DSAT->getSizeExpr() ?
- DSAT->getSizeExpr()->Retain() : 0,
- DSAT->getSizeModifier(),
- DSAT->getIndexTypeCVRQualifiers(),
- DSAT->getBracketsRange())->getCanonicalTypeInternal());
-
- VariableArrayType *VAT = cast<VariableArrayType>(AT);
- return CanQualType::CreateUnsafe(getVariableArrayType(NewEltTy,
- VAT->getSizeExpr() ?
- VAT->getSizeExpr()->Retain() : 0,
- VAT->getSizeModifier(),
- VAT->getIndexTypeCVRQualifiers(),
- VAT->getBracketsRange()));
-}
-QualType ASTContext::getUnqualifiedArrayType(QualType T,
- Qualifiers &Quals) {
- Quals = T.getQualifiers();
- const ArrayType *AT = getAsArrayType(T);
+QualType ASTContext::getUnqualifiedArrayType(QualType type,
+ Qualifiers &quals) {
+ SplitQualType splitType = type.getSplitUnqualifiedType();
+
+ // FIXME: getSplitUnqualifiedType() actually walks all the way to
+ // the unqualified desugared type and then drops it on the floor.
+ // We then have to strip that sugar back off with
+ // getUnqualifiedDesugaredType(), which is silly.
+ const ArrayType *AT =
+ dyn_cast<ArrayType>(splitType.first->getUnqualifiedDesugaredType());
+
+ // If we don't have an array, just use the results in splitType.
if (!AT) {
- return T.getUnqualifiedType();
+ quals = splitType.second;
+ return QualType(splitType.first, 0);
}
- QualType Elt = AT->getElementType();
- QualType UnqualElt = getUnqualifiedArrayType(Elt, Quals);
- if (Elt == UnqualElt)
- return T;
+ // Otherwise, recurse on the array's element type.
+ QualType elementType = AT->getElementType();
+ QualType unqualElementType = getUnqualifiedArrayType(elementType, quals);
+
+ // If that didn't change the element type, AT has no qualifiers, so we
+ // can just use the results in splitType.
+ if (elementType == unqualElementType) {
+ assert(quals.empty()); // from the recursive call
+ quals = splitType.second;
+ return QualType(splitType.first, 0);
+ }
+
+ // Otherwise, add in the qualifiers from the outermost type, then
+ // build the type back up.
+ quals.addConsistentQualifiers(splitType.second);
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) {
- return getConstantArrayType(UnqualElt, CAT->getSize(),
+ return getConstantArrayType(unqualElementType, CAT->getSize(),
CAT->getSizeModifier(), 0);
}
if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) {
- return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0);
+ return getIncompleteArrayType(unqualElementType, IAT->getSizeModifier(), 0);
}
if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT)) {
- return getVariableArrayType(UnqualElt,
- VAT->getSizeExpr() ?
- VAT->getSizeExpr()->Retain() : 0,
+ return getVariableArrayType(unqualElementType,
+ VAT->getSizeExpr(),
VAT->getSizeModifier(),
VAT->getIndexTypeCVRQualifiers(),
VAT->getBracketsRange());
}
const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(AT);
- return getDependentSizedArrayType(UnqualElt, DSAT->getSizeExpr()->Retain(),
+ return getDependentSizedArrayType(unqualElementType, DSAT->getSizeExpr(),
DSAT->getSizeModifier(), 0,
SourceRange());
}
@@ -2543,8 +2848,9 @@ bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) {
return false;
}
-DeclarationNameInfo ASTContext::getNameForTemplate(TemplateName Name,
- SourceLocation NameLoc) {
+DeclarationNameInfo
+ASTContext::getNameForTemplate(TemplateName Name,
+ SourceLocation NameLoc) const {
if (TemplateDecl *TD = Name.getAsTemplateDecl())
// DNInfo work in progress: CHECKME: what about DNLoc?
return DeclarationNameInfo(TD->getDeclName(), NameLoc);
@@ -2570,7 +2876,7 @@ DeclarationNameInfo ASTContext::getNameForTemplate(TemplateName Name,
return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc);
}
-TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
+TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const {
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(Template))
@@ -2580,6 +2886,15 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
return TemplateName(cast<TemplateDecl>(Template->getCanonicalDecl()));
}
+ if (SubstTemplateTemplateParmPackStorage *SubstPack
+ = Name.getAsSubstTemplateTemplateParmPack()) {
+ TemplateTemplateParmDecl *CanonParam
+ = getCanonicalTemplateTemplateParmDecl(SubstPack->getParameterPack());
+ TemplateArgument CanonArgPack
+ = getCanonicalTemplateArgument(SubstPack->getArgumentPack());
+ return getSubstTemplateTemplateParmPack(CanonParam, CanonArgPack);
+ }
+
assert(!Name.getAsOverloadedTemplate());
DependentTemplateName *DTN = Name.getAsDependentTemplateName();
@@ -2594,7 +2909,7 @@ bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) {
}
TemplateArgument
-ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) {
+ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const {
switch (Arg.getKind()) {
case TemplateArgument::Null:
return Arg;
@@ -2607,7 +2922,12 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) {
case TemplateArgument::Template:
return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate()));
-
+
+ case TemplateArgument::TemplateExpansion:
+ return TemplateArgument(getCanonicalTemplateName(
+ Arg.getAsTemplateOrTemplatePattern()),
+ Arg.getNumTemplateExpansions());
+
case TemplateArgument::Integral:
return TemplateArgument(*Arg.getAsIntegral(),
getCanonicalType(Arg.getIntegralType()));
@@ -2616,17 +2936,18 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) {
return TemplateArgument(getCanonicalType(Arg.getAsType()));
case TemplateArgument::Pack: {
- // FIXME: Allocate in ASTContext
- TemplateArgument *CanonArgs = new TemplateArgument[Arg.pack_size()];
+ if (Arg.pack_size() == 0)
+ return Arg;
+
+ TemplateArgument *CanonArgs
+ = new (*this) TemplateArgument[Arg.pack_size()];
unsigned Idx = 0;
for (TemplateArgument::pack_iterator A = Arg.pack_begin(),
AEnd = Arg.pack_end();
A != AEnd; (void)++A, ++Idx)
CanonArgs[Idx] = getCanonicalTemplateArgument(*A);
- TemplateArgument Result;
- Result.setArgumentPack(CanonArgs, Arg.pack_size(), false);
- return Result;
+ return TemplateArgument(CanonArgs, Arg.pack_size());
}
}
@@ -2636,7 +2957,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) {
}
NestedNameSpecifier *
-ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
+ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
if (!NNS)
return 0;
@@ -2655,9 +2976,35 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate: {
QualType T = getCanonicalType(QualType(NNS->getAsType(), 0));
- return NestedNameSpecifier::Create(*this, 0,
- NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
- T.getTypePtr());
+
+ // If we have some kind of dependent-named type (e.g., "typename T::type"),
+ // break it apart into its prefix and identifier, then reconsititute those
+ // as the canonical nested-name-specifier. This is required to canonicalize
+ // a dependent nested-name-specifier involving typedefs of dependent-name
+ // types, e.g.,
+ // typedef typename T::type T1;
+ // typedef typename T1::type T2;
+ if (const DependentNameType *DNT = T->getAs<DependentNameType>()) {
+ NestedNameSpecifier *Prefix
+ = getCanonicalNestedNameSpecifier(DNT->getQualifier());
+ return NestedNameSpecifier::Create(*this, Prefix,
+ const_cast<IdentifierInfo *>(DNT->getIdentifier()));
+ }
+
+ // Do the same thing as above, but with dependent-named specializations.
+ if (const DependentTemplateSpecializationType *DTST
+ = T->getAs<DependentTemplateSpecializationType>()) {
+ NestedNameSpecifier *Prefix
+ = getCanonicalNestedNameSpecifier(DTST->getQualifier());
+ TemplateName Name
+ = getDependentTemplateName(Prefix, DTST->getIdentifier());
+ T = getTemplateSpecializationType(Name,
+ DTST->getArgs(), DTST->getNumArgs());
+ T = getCanonicalType(T);
+ }
+
+ return NestedNameSpecifier::Create(*this, 0, false,
+ const_cast<Type*>(T.getTypePtr()));
}
case NestedNameSpecifier::Global:
@@ -2670,7 +3017,7 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
}
-const ArrayType *ASTContext::getAsArrayType(QualType T) {
+const ArrayType *ASTContext::getAsArrayType(QualType T) const {
// Handle the non-qualified case efficiently.
if (!T.hasLocalQualifiers()) {
// Handle the common positive case fast.
@@ -2679,8 +3026,7 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) {
}
// Handle the common negative case fast.
- QualType CType = T->getCanonicalTypeInternal();
- if (!isa<ArrayType>(CType))
+ if (!isa<ArrayType>(T.getCanonicalType()))
return 0;
// Apply any qualifiers from the array type to the element type. This
@@ -2691,19 +3037,17 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) {
// sugar such as a typedef in the way. If we have type qualifiers on the type
// we must propagate them down into the element type.
- QualifierCollector Qs;
- const Type *Ty = Qs.strip(T.getDesugaredType());
+ SplitQualType split = T.getSplitDesugaredType();
+ Qualifiers qs = split.second;
// If we have a simple case, just return now.
- const ArrayType *ATy = dyn_cast<ArrayType>(Ty);
- if (ATy == 0 || Qs.empty())
+ const ArrayType *ATy = dyn_cast<ArrayType>(split.first);
+ if (ATy == 0 || qs.empty())
return ATy;
// Otherwise, we have an array and we have qualifiers on it. Push the
// qualifiers into the array element type and return a new array type.
- // Get the canonical version of the element with the extra qualifiers on it.
- // This can recursively sink qualifiers through multiple levels of arrays.
- QualType NewEltTy = getQualifiedType(ATy->getElementType(), Qs);
+ QualType NewEltTy = getQualifiedType(ATy->getElementType(), qs);
if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy))
return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(),
@@ -2718,29 +3062,26 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) {
= dyn_cast<DependentSizedArrayType>(ATy))
return cast<ArrayType>(
getDependentSizedArrayType(NewEltTy,
- DSAT->getSizeExpr() ?
- DSAT->getSizeExpr()->Retain() : 0,
+ DSAT->getSizeExpr(),
DSAT->getSizeModifier(),
DSAT->getIndexTypeCVRQualifiers(),
DSAT->getBracketsRange()));
const VariableArrayType *VAT = cast<VariableArrayType>(ATy);
return cast<ArrayType>(getVariableArrayType(NewEltTy,
- VAT->getSizeExpr() ?
- VAT->getSizeExpr()->Retain() : 0,
+ VAT->getSizeExpr(),
VAT->getSizeModifier(),
VAT->getIndexTypeCVRQualifiers(),
VAT->getBracketsRange()));
}
-
/// getArrayDecayedType - Return the properly qualified result of decaying the
/// specified array type to a pointer. This operation is non-trivial when
/// handling typedefs etc. The canonical type of "T" must be an array type,
/// this returns a pointer to a properly qualified element of the array.
///
/// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
-QualType ASTContext::getArrayDecayedType(QualType Ty) {
+QualType ASTContext::getArrayDecayedType(QualType Ty) const {
// Get the element type with 'getAsArrayType' so that we don't lose any
// typedefs in the element type of the array. This also handles propagation
// of type qualifiers from the array type into the element type if present
@@ -2754,20 +3095,22 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) {
return getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers());
}
-QualType ASTContext::getBaseElementType(QualType QT) {
- QualifierCollector Qs;
- while (const ArrayType *AT = getAsArrayType(QualType(Qs.strip(QT), 0)))
- QT = AT->getElementType();
- return Qs.apply(QT);
+QualType ASTContext::getBaseElementType(const ArrayType *array) const {
+ return getBaseElementType(array->getElementType());
}
-QualType ASTContext::getBaseElementType(const ArrayType *AT) {
- QualType ElemTy = AT->getElementType();
+QualType ASTContext::getBaseElementType(QualType type) const {
+ Qualifiers qs;
+ while (true) {
+ SplitQualType split = type.getSplitDesugaredType();
+ const ArrayType *array = split.first->getAsArrayTypeUnsafe();
+ if (!array) break;
- if (const ArrayType *AT = getAsArrayType(ElemTy))
- return getBaseElementType(AT);
+ type = array->getElementType();
+ qs.addConsistentQualifiers(split.second);
+ }
- return ElemTy;
+ return getQualifiedType(type, qs);
}
/// getConstantArrayElementCount - Returns number of constant array elements.
@@ -2825,7 +3168,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
/// point types, ignoring the domain of the type (i.e. 'double' ==
/// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If
/// LHS < RHS, return -1.
-int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) {
+int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) const {
FloatingRank LHSR = getFloatingRank(LHS);
FloatingRank RHSR = getFloatingRank(RHS);
@@ -2839,12 +3182,13 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) {
/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This
/// routine will assert if passed a built-in type that isn't an integer or enum,
/// or if it is not canonicalized.
-unsigned ASTContext::getIntegerRank(Type *T) {
+unsigned ASTContext::getIntegerRank(const Type *T) const {
assert(T->isCanonicalUnqualified() && "T should be canonicalized");
- if (EnumType* ET = dyn_cast<EnumType>(T))
+ if (const EnumType* ET = dyn_cast<EnumType>(T))
T = ET->getDecl()->getPromotionType().getTypePtr();
- if (T->isSpecificBuiltinType(BuiltinType::WChar))
+ if (T->isSpecificBuiltinType(BuiltinType::WChar_S) ||
+ T->isSpecificBuiltinType(BuiltinType::WChar_U))
T = getFromTargetType(Target.getWCharType()).getTypePtr();
if (T->isSpecificBuiltinType(BuiltinType::Char16))
@@ -2885,7 +3229,7 @@ unsigned ASTContext::getIntegerRank(Type *T) {
///
/// \returns the type this bit-field will promote to, or NULL if no
/// promotion occurs.
-QualType ASTContext::isPromotableBitField(Expr *E) {
+QualType ASTContext::isPromotableBitField(Expr *E) const {
if (E->isTypeDependent() || E->isValueDependent())
return QualType();
@@ -2917,7 +3261,7 @@ QualType ASTContext::isPromotableBitField(Expr *E) {
/// getPromotedIntegerType - Returns the type that Promotable will
/// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable
/// integer type.
-QualType ASTContext::getPromotedIntegerType(QualType Promotable) {
+QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
assert(!Promotable.isNull());
assert(Promotable->isPromotableIntegerType());
if (const EnumType *ET = Promotable->getAs<EnumType>())
@@ -2933,9 +3277,9 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) {
/// 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) {
- Type *LHSC = getCanonicalType(LHS).getTypePtr();
- Type *RHSC = getCanonicalType(RHS).getTypePtr();
+int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) const {
+ const Type *LHSC = getCanonicalType(LHS).getTypePtr();
+ const Type *RHSC = getCanonicalType(RHS).getTypePtr();
if (LHSC == RHSC) return 0;
bool LHSUnsigned = LHSC->isUnsignedIntegerType();
@@ -2972,7 +3316,7 @@ int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) {
}
static RecordDecl *
-CreateRecordDecl(ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC,
+CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id) {
if (Ctx.getLangOptions().CPlusPlus)
return CXXRecordDecl::Create(Ctx, TK, DC, L, Id);
@@ -2981,7 +3325,7 @@ CreateRecordDecl(ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC,
}
// getCFConstantStringType - Return the type used for constant CFStrings.
-QualType ASTContext::getCFConstantStringType() {
+QualType ASTContext::getCFConstantStringType() const {
if (!CFConstantStringTypeDecl) {
CFConstantStringTypeDecl =
CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
@@ -3023,7 +3367,7 @@ void ASTContext::setCFConstantStringType(QualType T) {
}
// getNSConstantStringType - Return the type used for constant NSStrings.
-QualType ASTContext::getNSConstantStringType() {
+QualType ASTContext::getNSConstantStringType() const {
if (!NSConstantStringTypeDecl) {
NSConstantStringTypeDecl =
CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
@@ -3062,7 +3406,7 @@ void ASTContext::setNSConstantStringType(QualType T) {
NSConstantStringTypeDecl = Rec->getDecl();
}
-QualType ASTContext::getObjCFastEnumerationStateType() {
+QualType ASTContext::getObjCFastEnumerationStateType() const {
if (!ObjCFastEnumerationStateTypeDecl) {
ObjCFastEnumerationStateTypeDecl =
CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(),
@@ -3087,10 +3431,6 @@ QualType ASTContext::getObjCFastEnumerationStateType() {
Field->setAccess(AS_public);
ObjCFastEnumerationStateTypeDecl->addDecl(Field);
}
- if (getLangOptions().CPlusPlus)
- if (CXXRecordDecl *CXXRD =
- dyn_cast<CXXRecordDecl>(ObjCFastEnumerationStateTypeDecl))
- CXXRD->setEmpty(false);
ObjCFastEnumerationStateTypeDecl->completeDefinition();
}
@@ -3098,7 +3438,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() {
return getTagDeclType(ObjCFastEnumerationStateTypeDecl);
}
-QualType ASTContext::getBlockDescriptorType() {
+QualType ASTContext::getBlockDescriptorType() const {
if (BlockDescriptorType)
return getTagDeclType(BlockDescriptorType);
@@ -3143,7 +3483,7 @@ void ASTContext::setBlockDescriptorType(QualType T) {
BlockDescriptorType = Rec->getDecl();
}
-QualType ASTContext::getBlockDescriptorExtendedType() {
+QualType ASTContext::getBlockDescriptorExtendedType() const {
if (BlockDescriptorExtendedType)
return getTagDeclType(BlockDescriptorExtendedType);
@@ -3192,17 +3532,25 @@ void ASTContext::setBlockDescriptorExtendedType(QualType T) {
BlockDescriptorExtendedType = Rec->getDecl();
}
-bool ASTContext::BlockRequiresCopying(QualType Ty) {
+bool ASTContext::BlockRequiresCopying(QualType Ty) const {
if (Ty->isBlockPointerType())
return true;
if (isObjCNSObjectType(Ty))
return true;
if (Ty->isObjCObjectPointerType())
return true;
+ if (getLangOptions().CPlusPlus) {
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ return RD->hasConstCopyConstructor(*this);
+
+ }
+ }
return false;
}
-QualType ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) {
+QualType
+ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const {
// type = struct __Block_byref_1_X {
// void *__isa;
// struct __Block_byref_1_X *__forwarding;
@@ -3264,7 +3612,7 @@ QualType ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) {
QualType ASTContext::getBlockParmType(
bool BlockHasCopyDispose,
- llvm::SmallVectorImpl<const Expr *> &Layout) {
+ llvm::SmallVectorImpl<const Expr *> &Layout) const {
// FIXME: Move up
llvm::SmallString<36> Name;
@@ -3351,7 +3699,7 @@ static bool isTypeTypedefedAsBOOL(QualType T) {
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
/// purpose.
-CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) {
+CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) const {
CharUnits sz = getTypeSizeInChars(type);
// Make all integer and enum types at least as large as an int
@@ -3368,10 +3716,11 @@ std::string charUnitsToString(const CharUnits &CU) {
return llvm::itostr(CU.getQuantity());
}
-/// getObjCEncodingForBlockDecl - Return the encoded type for this block
+/// getObjCEncodingForBlock - Return the encoded type for this block
/// declaration.
-void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
- std::string& S) {
+std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const {
+ std::string S;
+
const BlockDecl *Decl = Expr->getBlockDecl();
QualType BlockTy =
Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
@@ -3414,12 +3763,50 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
S += charUnitsToString(ParmOffset);
ParmOffset += getObjCEncodingTypeSize(PType);
}
+
+ return S;
+}
+
+void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl,
+ std::string& S) {
+ // Encode result type.
+ getObjCEncodingForType(Decl->getResultType(), S);
+ CharUnits ParmOffset;
+ // Compute size of all parameters.
+ for (FunctionDecl::param_const_iterator PI = Decl->param_begin(),
+ E = Decl->param_end(); PI != E; ++PI) {
+ QualType PType = (*PI)->getType();
+ CharUnits sz = getObjCEncodingTypeSize(PType);
+ assert (sz.isPositive() &&
+ "getObjCEncodingForMethodDecl - Incomplete param type");
+ ParmOffset += sz;
+ }
+ S += charUnitsToString(ParmOffset);
+ ParmOffset = CharUnits::Zero();
+
+ // Argument types.
+ for (FunctionDecl::param_const_iterator PI = Decl->param_begin(),
+ E = Decl->param_end(); PI != E; ++PI) {
+ ParmVarDecl *PVDecl = *PI;
+ QualType PType = PVDecl->getOriginalType();
+ if (const ArrayType *AT =
+ dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
+ // Use array's original type only if it has known number of
+ // elements.
+ if (!isa<ConstantArrayType>(AT))
+ PType = PVDecl->getType();
+ } else if (PType->isFunctionType())
+ PType = PVDecl->getType();
+ getObjCEncodingForType(PType, S);
+ S += charUnitsToString(ParmOffset);
+ ParmOffset += getObjCEncodingTypeSize(PType);
+ }
}
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
/// declaration.
void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
- std::string& S) {
+ std::string& S) const {
// FIXME: This is not very efficient.
// Encode type qualifer, 'in', 'inout', etc. for the return type.
getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S);
@@ -3495,7 +3882,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
/// @endcode
void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
const Decl *Container,
- std::string& S) {
+ std::string& S) const {
// Collect information from the property implementation decl(s).
bool Dynamic = false;
ObjCPropertyImplDecl *SynthesizePID = 0;
@@ -3588,19 +3975,17 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD,
void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const {
if (isa<TypedefType>(PointeeTy.getTypePtr())) {
if (const BuiltinType *BT = PointeeTy->getAs<BuiltinType>()) {
- if (BT->getKind() == BuiltinType::ULong &&
- ((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32))
+ if (BT->getKind() == BuiltinType::ULong && getIntWidth(PointeeTy) == 32)
PointeeTy = UnsignedIntTy;
else
- if (BT->getKind() == BuiltinType::Long &&
- ((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32))
+ if (BT->getKind() == BuiltinType::Long && getIntWidth(PointeeTy) == 32)
PointeeTy = IntTy;
}
}
}
void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
- const FieldDecl *Field) {
+ const FieldDecl *Field) const {
// We follow the behavior of gcc, expanding structures which are
// directly pointed to, and expanding embedded structures. Note that
// these rules are sufficient to prevent recursive encoding of the
@@ -3619,31 +4004,29 @@ static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) {
case BuiltinType::UShort: return 'S';
case BuiltinType::UInt: return 'I';
case BuiltinType::ULong:
- return
- (const_cast<ASTContext *>(C))->getIntWidth(T) == 32 ? 'L' : 'Q';
+ return C->getIntWidth(T) == 32 ? 'L' : 'Q';
case BuiltinType::UInt128: return 'T';
case BuiltinType::ULongLong: return 'Q';
case BuiltinType::Char_S:
case BuiltinType::SChar: return 'c';
case BuiltinType::Short: return 's';
- case BuiltinType::WChar:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
case BuiltinType::Int: return 'i';
case BuiltinType::Long:
- return
- (const_cast<ASTContext *>(C))->getIntWidth(T) == 32 ? 'l' : 'q';
+ return C->getIntWidth(T) == 32 ? 'l' : 'q';
case BuiltinType::LongLong: return 'q';
case BuiltinType::Int128: return 't';
case BuiltinType::Float: return 'f';
case BuiltinType::Double: return 'd';
- case BuiltinType::LongDouble: return 'd';
+ case BuiltinType::LongDouble: return 'D';
}
}
-static void EncodeBitField(const ASTContext *Context, std::string& S,
+static void EncodeBitField(const ASTContext *Ctx, std::string& S,
QualType T, const FieldDecl *FD) {
const Expr *E = FD->getBitWidth();
assert(E && "bitfield width not there - getObjCEncodingForTypeImpl");
- ASTContext *Ctx = const_cast<ASTContext*>(Context);
S += 'b';
// The NeXT runtime encodes bit fields as b followed by the number of bits.
// The GNU runtime requires more information; bitfields are encoded as b,
@@ -3674,7 +4057,10 @@ static void EncodeBitField(const ASTContext *Context, std::string& S,
break;
}
S += llvm::utostr(RL.getFieldOffset(i));
- S += ObjCEncodingForPrimitiveKind(Context, T);
+ if (T->isEnumeralType())
+ S += 'i';
+ else
+ S += ObjCEncodingForPrimitiveKind(Ctx, T);
}
unsigned N = E->EvaluateAsInt(*Ctx).getZExtValue();
S += llvm::utostr(N);
@@ -3686,7 +4072,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
bool ExpandStructures,
const FieldDecl *FD,
bool OutermostType,
- bool EncodingProperty) {
+ bool EncodingProperty) const {
if (T->getAs<BuiltinType>()) {
if (FD && FD->isBitField())
return EncodeBitField(this, S, T, FD);
@@ -3811,8 +4197,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.getFlatArgumentList(),
- TemplateArgs.flat_size(),
+ TemplateArgs.data(),
+ TemplateArgs.size(),
(*this).PrintingPolicy);
S += TemplateArgsStr;
@@ -3846,7 +4232,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S += RDecl->isUnion() ? ')' : '}';
return;
}
-
+
if (T->isEnumeralType()) {
if (FD && FD->isBitField())
EncodeBitField(this, S, T, FD);
@@ -3949,7 +4335,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
// TODO: maybe there should be a mangling for these
if (T->getAs<MemberPointerType>())
return;
-
+
+ if (T->isVectorType()) {
+ // This matches gcc's encoding, even though technically it is
+ // insufficient.
+ // FIXME. We should do a better job than gcc.
+ return;
+ }
+
assert(0 && "@encode for type not implemented!");
}
@@ -4000,8 +4393,9 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
/// \brief Retrieve the template name that corresponds to a non-empty
/// lookup.
-TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin,
- UnresolvedSetIterator End) {
+TemplateName
+ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End) const {
unsigned size = End - Begin;
assert(size > 1 && "set is not overloaded!");
@@ -4023,9 +4417,10 @@ TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin,
/// \brief Retrieve the template name that represents a qualified
/// template name such as \c std::vector.
-TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
- bool TemplateKeyword,
- TemplateDecl *Template) {
+TemplateName
+ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
+ bool TemplateKeyword,
+ TemplateDecl *Template) const {
// FIXME: Canonicalization?
llvm::FoldingSetNodeID ID;
QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template);
@@ -4043,8 +4438,9 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS,
/// \brief Retrieve the template name that represents a dependent
/// template name such as \c MetaFun::template apply.
-TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
- const IdentifierInfo *Name) {
+TemplateName
+ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
+ const IdentifierInfo *Name) const {
assert((!NNS || NNS->isDependent()) &&
"Nested name specifier must be dependent");
@@ -4078,7 +4474,7 @@ TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
/// template name such as \c MetaFun::template operator+.
TemplateName
ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
- OverloadedOperatorKind Operator) {
+ OverloadedOperatorKind Operator) const {
assert((!NNS || NNS->isDependent()) &&
"Nested name specifier must be dependent");
@@ -4109,6 +4505,27 @@ ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
return TemplateName(QTN);
}
+TemplateName
+ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param,
+ const TemplateArgument &ArgPack) const {
+ ASTContext &Self = const_cast<ASTContext &>(*this);
+ llvm::FoldingSetNodeID ID;
+ SubstTemplateTemplateParmPackStorage::Profile(ID, Self, Param, ArgPack);
+
+ void *InsertPos = 0;
+ SubstTemplateTemplateParmPackStorage *Subst
+ = SubstTemplateTemplateParmPacks.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (!Subst) {
+ Subst = new (*this) SubstTemplateTemplateParmPackStorage(Self, Param,
+ ArgPack.pack_size(),
+ ArgPack.pack_begin());
+ SubstTemplateTemplateParmPacks.InsertNode(Subst, InsertPos);
+ }
+
+ return TemplateName(Subst);
+}
+
/// getFromTargetType - Given one of the integer types provided by
/// TargetInfo, produce the corresponding type. The unsigned @p Type
/// is actually a value of type @c TargetInfo::IntType.
@@ -4139,7 +4556,7 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const {
/// FIXME: Move to Type.
///
bool ASTContext::isObjCNSObjectType(QualType Ty) const {
- if (TypedefType *TDT = dyn_cast<TypedefType>(Ty)) {
+ if (const TypedefType *TDT = dyn_cast<TypedefType>(Ty)) {
if (TypedefDecl *TD = TDT->getDecl())
if (TD->getAttr<ObjCNSObjectAttr>())
return true;
@@ -4150,24 +4567,30 @@ bool ASTContext::isObjCNSObjectType(QualType Ty) const {
/// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's
/// garbage collection attribute.
///
-Qualifiers::GC ASTContext::getObjCGCAttrKind(const QualType &Ty) const {
- Qualifiers::GC GCAttrs = Qualifiers::GCNone;
- if (getLangOptions().ObjC1 &&
- getLangOptions().getGCMode() != LangOptions::NonGC) {
- GCAttrs = Ty.getObjCGCAttr();
- // Default behavious under objective-c's gc is for objective-c pointers
- // (or pointers to them) be treated as though they were declared
- // as __strong.
- if (GCAttrs == Qualifiers::GCNone) {
- if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType())
- GCAttrs = Qualifiers::Strong;
- else if (Ty->isPointerType())
- return getObjCGCAttrKind(Ty->getAs<PointerType>()->getPointeeType());
- }
- // Non-pointers have none gc'able attribute regardless of the attribute
- // set on them.
- else if (!Ty->isAnyPointerType() && !Ty->isBlockPointerType())
- return Qualifiers::GCNone;
+Qualifiers::GC ASTContext::getObjCGCAttrKind(QualType Ty) const {
+ if (getLangOptions().getGCMode() == LangOptions::NonGC)
+ return Qualifiers::GCNone;
+
+ assert(getLangOptions().ObjC1);
+ Qualifiers::GC GCAttrs = Ty.getObjCGCAttr();
+
+ // Default behaviour under objective-C's gc is for ObjC pointers
+ // (or pointers to them) be treated as though they were declared
+ // as __strong.
+ if (GCAttrs == Qualifiers::GCNone) {
+ if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType())
+ return Qualifiers::Strong;
+ else if (Ty->isPointerType())
+ return getObjCGCAttrKind(Ty->getAs<PointerType>()->getPointeeType());
+ } else {
+ // It's not valid to set GC attributes on anything that isn't a
+ // pointer.
+#ifndef NDEBUG
+ QualType CT = Ty->getCanonicalTypeInternal();
+ while (const ArrayType *AT = dyn_cast<ArrayType>(CT))
+ CT = AT->getElementType();
+ assert(CT->isAnyPointerType() || CT->isBlockPointerType());
+#endif
}
return GCAttrs;
}
@@ -4193,15 +4616,16 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
if (hasSameUnqualifiedType(FirstVec, SecondVec))
return true;
- // AltiVec vectors types are identical to equivalent GCC vector types
+ // Treat Neon vector types and most AltiVec vector types as if they are the
+ // equivalent GCC vector types.
const VectorType *First = FirstVec->getAs<VectorType>();
const VectorType *Second = SecondVec->getAs<VectorType>();
- if ((((First->getAltiVecSpecific() == VectorType::AltiVec) &&
- (Second->getAltiVecSpecific() == VectorType::NotAltiVec)) ||
- ((First->getAltiVecSpecific() == VectorType::NotAltiVec) &&
- (Second->getAltiVecSpecific() == VectorType::AltiVec))) &&
+ if (First->getNumElements() == Second->getNumElements() &&
hasSameType(First->getElementType(), Second->getElementType()) &&
- (First->getNumElements() == Second->getNumElements()))
+ First->getVectorKind() != VectorType::AltiVecPixel &&
+ First->getVectorKind() != VectorType::AltiVecBool &&
+ Second->getVectorKind() != VectorType::AltiVecPixel &&
+ Second->getVectorKind() != VectorType::AltiVecBool)
return true;
return false;
@@ -4213,8 +4637,9 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec,
/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the
/// inheritance hierarchy of 'rProto'.
-bool ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
- ObjCProtocolDecl *rProto) {
+bool
+ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
+ ObjCProtocolDecl *rProto) const {
if (lProto == rProto)
return true;
for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(),
@@ -4336,33 +4761,17 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
if (const ObjCObjectPointerType *lhsOPT =
lhs->getAsObjCInterfacePointerType()) {
- if (lhsOPT->qual_empty()) {
- bool match = false;
- if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) {
- for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(),
- E = rhsQID->qual_end(); I != E; ++I) {
- // when comparing an id<P> on rhs with a static type on lhs,
- // static class must implement all of id's protocols directly or
- // indirectly through its super class.
- if (lhsID->ClassImplementsProtocol(*I, true)) {
- match = true;
- break;
- }
- }
- if (!match)
- return false;
- }
- return true;
- }
- // Both the right and left sides have qualifiers.
+ // If both the right and left sides have qualifiers.
for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(),
E = lhsOPT->qual_end(); I != E; ++I) {
ObjCProtocolDecl *lhsProto = *I;
bool match = false;
- // when comparing an id<P> on lhs with a static type on rhs,
+ // when comparing an id<P> on rhs with a static type on lhs,
// see if static class implements all of id's protocols, directly or
// through its super class and categories.
+ // First, lhs protocols in the qualifier list must be found, direct
+ // or indirect in rhs's qualifier list or it is a mismatch.
for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(),
E = rhsQID->qual_end(); J != E; ++J) {
ObjCProtocolDecl *rhsProto = *J;
@@ -4375,6 +4784,35 @@ bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
if (!match)
return false;
}
+
+ // Static class's protocols, or its super class or category protocols
+ // must be found, direct or indirect in rhs's qualifier list or it is a mismatch.
+ if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) {
+ llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols;
+ CollectInheritedProtocols(lhsID, LHSInheritedProtocols);
+ // This is rather dubious but matches gcc's behavior. If lhs has
+ // no type qualifier and its class has no static protocol(s)
+ // assume that it is mismatch.
+ if (LHSInheritedProtocols.empty() && lhsOPT->qual_empty())
+ return false;
+ for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I =
+ LHSInheritedProtocols.begin(),
+ E = LHSInheritedProtocols.end(); I != E; ++I) {
+ bool match = false;
+ ObjCProtocolDecl *lhsProto = (*I);
+ for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(),
+ E = rhsQID->qual_end(); J != E; ++J) {
+ ObjCProtocolDecl *rhsProto = *J;
+ if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
+ (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
+ match = true;
+ break;
+ }
+ }
+ if (!match)
+ return false;
+ }
+ }
return true;
}
return false;
@@ -4600,6 +5038,49 @@ bool ASTContext::typesAreBlockPointerCompatible(QualType LHS, QualType RHS) {
return !mergeTypes(LHS, RHS, true).isNull();
}
+/// mergeTransparentUnionType - if T is a transparent union type and a member
+/// of T is compatible with SubType, return the merged type, else return
+/// QualType()
+QualType ASTContext::mergeTransparentUnionType(QualType T, QualType SubType,
+ bool OfBlockPointer,
+ bool Unqualified) {
+ if (const RecordType *UT = T->getAsUnionType()) {
+ RecordDecl *UD = UT->getDecl();
+ if (UD->hasAttr<TransparentUnionAttr>()) {
+ for (RecordDecl::field_iterator it = UD->field_begin(),
+ itend = UD->field_end(); it != itend; ++it) {
+ QualType ET = it->getType().getUnqualifiedType();
+ QualType MT = mergeTypes(ET, SubType, OfBlockPointer, Unqualified);
+ if (!MT.isNull())
+ return MT;
+ }
+ }
+ }
+
+ return QualType();
+}
+
+/// mergeFunctionArgumentTypes - merge two types which appear as function
+/// argument types
+QualType ASTContext::mergeFunctionArgumentTypes(QualType lhs, QualType rhs,
+ bool OfBlockPointer,
+ bool Unqualified) {
+ // GNU extension: two types are compatible if they appear as a function
+ // argument, one of the types is a transparent union type and the other
+ // type is compatible with a union member
+ QualType lmerge = mergeTransparentUnionType(lhs, rhs, OfBlockPointer,
+ Unqualified);
+ if (!lmerge.isNull())
+ return lmerge;
+
+ QualType rmerge = mergeTransparentUnionType(rhs, lhs, OfBlockPointer,
+ Unqualified);
+ if (!rmerge.isNull())
+ return rmerge;
+
+ return mergeTypes(lhs, rhs, OfBlockPointer, Unqualified);
+}
+
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
bool OfBlockPointer,
bool Unqualified) {
@@ -4612,12 +5093,17 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
// Check return type
QualType retType;
- if (OfBlockPointer)
- retType = mergeTypes(rbase->getResultType(), lbase->getResultType(), true,
- Unqualified);
+ if (OfBlockPointer) {
+ QualType RHS = rbase->getResultType();
+ QualType LHS = lbase->getResultType();
+ bool UnqualifiedResult = Unqualified;
+ if (!UnqualifiedResult)
+ UnqualifiedResult = (!RHS.hasQualifiers() && LHS.hasQualifiers());
+ retType = mergeTypes(RHS, LHS, true, UnqualifiedResult);
+ }
else
- retType = mergeTypes(lbase->getResultType(), rbase->getResultType(),
- false, Unqualified);
+ retType = mergeTypes(lbase->getResultType(), rbase->getResultType(), false,
+ Unqualified);
if (retType.isNull()) return QualType();
if (Unqualified)
@@ -4634,26 +5120,33 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
allLTypes = false;
if (getCanonicalType(retType) != RRetType)
allRTypes = false;
+
// FIXME: double check this
// FIXME: should we error if lbase->getRegParmAttr() != 0 &&
// rbase->getRegParmAttr() != 0 &&
// lbase->getRegParmAttr() != rbase->getRegParmAttr()?
FunctionType::ExtInfo lbaseInfo = lbase->getExtInfo();
FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo();
- unsigned RegParm = lbaseInfo.getRegParm() == 0 ? rbaseInfo.getRegParm() :
- lbaseInfo.getRegParm();
+
+ // Compatible functions must have compatible calling conventions
+ if (!isSameCallConv(lbaseInfo.getCC(), rbaseInfo.getCC()))
+ return QualType();
+
+ // Regparm is part of the calling convention.
+ if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm())
+ return QualType();
+
+ // It's noreturn if either type is.
+ // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
- if (NoReturn != lbaseInfo.getNoReturn() ||
- RegParm != lbaseInfo.getRegParm())
+ if (NoReturn != lbaseInfo.getNoReturn())
allLTypes = false;
- if (NoReturn != rbaseInfo.getNoReturn() ||
- RegParm != rbaseInfo.getRegParm())
+ if (NoReturn != rbaseInfo.getNoReturn())
allRTypes = false;
- CallingConv lcc = lbaseInfo.getCC();
- CallingConv rcc = rbaseInfo.getCC();
- // Compatible functions must have compatible calling conventions
- if (!isSameCallConv(lcc, rcc))
- return QualType();
+
+ FunctionType::ExtInfo einfo(NoReturn,
+ lbaseInfo.getRegParm(),
+ lbaseInfo.getCC());
if (lproto && rproto) { // two C99 style function prototypes
assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() &&
@@ -4677,8 +5170,9 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
for (unsigned i = 0; i < lproto_nargs; i++) {
QualType largtype = lproto->getArgType(i).getUnqualifiedType();
QualType rargtype = rproto->getArgType(i).getUnqualifiedType();
- QualType argtype = mergeTypes(largtype, rargtype, OfBlockPointer,
- Unqualified);
+ QualType argtype = mergeFunctionArgumentTypes(largtype, rargtype,
+ OfBlockPointer,
+ Unqualified);
if (argtype.isNull()) return QualType();
if (Unqualified)
@@ -4697,10 +5191,10 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
}
if (allLTypes) return lhs;
if (allRTypes) return rhs;
- return getFunctionType(retType, types.begin(), types.size(),
- lproto->isVariadic(), lproto->getTypeQuals(),
- false, false, 0, 0,
- FunctionType::ExtInfo(NoReturn, RegParm, lcc));
+
+ FunctionProtoType::ExtProtoInfo EPI = lproto->getExtProtoInfo();
+ EPI.ExtInfo = einfo;
+ return getFunctionType(retType, types.begin(), types.size(), EPI);
}
if (lproto) allRTypes = false;
@@ -4731,17 +5225,16 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (allLTypes) return lhs;
if (allRTypes) return rhs;
+
+ FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo();
+ EPI.ExtInfo = einfo;
return getFunctionType(retType, proto->arg_type_begin(),
- proto->getNumArgs(), proto->isVariadic(),
- proto->getTypeQuals(),
- false, false, 0, 0,
- FunctionType::ExtInfo(NoReturn, RegParm, lcc));
+ proto->getNumArgs(), EPI);
}
if (allLTypes) return lhs;
if (allRTypes) return rhs;
- FunctionType::ExtInfo Info(NoReturn, RegParm, lcc);
- return getFunctionNoProtoType(retType, Info);
+ return getFunctionNoProtoType(retType, einfo);
}
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
@@ -5020,16 +5513,11 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
// In either case, use OldReturnType to build the new function type.
const FunctionType *F = LHS->getAs<FunctionType>();
if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) {
- FunctionType::ExtInfo Info = getFunctionExtInfo(LHS);
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.ExtInfo = getFunctionExtInfo(LHS);
QualType ResultType
= getFunctionType(OldReturnType, FPT->arg_type_begin(),
- FPT->getNumArgs(), FPT->isVariadic(),
- FPT->getTypeQuals(),
- FPT->hasExceptionSpec(),
- FPT->hasAnyExceptionSpec(),
- FPT->getNumExceptions(),
- FPT->exception_begin(),
- Info);
+ FPT->getNumArgs(), EPI);
return ResultType;
}
}
@@ -5080,11 +5568,11 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
// Integer Predicates
//===----------------------------------------------------------------------===//
-unsigned ASTContext::getIntWidth(QualType T) {
+unsigned ASTContext::getIntWidth(QualType T) const {
+ if (const EnumType *ET = dyn_cast<EnumType>(T))
+ T = ET->getDecl()->getIntegerType();
if (T->isBooleanType())
return 1;
- if (EnumType *ET = dyn_cast<EnumType>(T))
- T = ET->getDecl()->getIntegerType();
// For builtin types, just use the standard type sizing method
return (unsigned)getTypeSize(T);
}
@@ -5095,7 +5583,7 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) {
// Turn <4 x signed int> -> <4 x unsigned int>
if (const VectorType *VTy = T->getAs<VectorType>())
return getVectorType(getCorrespondingUnsignedType(VTy->getElementType()),
- VTy->getNumElements(), VTy->getAltiVecSpecific());
+ VTy->getNumElements(), VTy->getVectorKind());
// For enums, we return the unsigned version of the base type.
if (const EnumType *ETy = T->getAs<EnumType>())
@@ -5127,25 +5615,38 @@ ExternalASTSource::~ExternalASTSource() { }
void ExternalASTSource::PrintStats() { }
+ASTMutationListener::~ASTMutationListener() { }
+
//===----------------------------------------------------------------------===//
// Builtin Type Computation
//===----------------------------------------------------------------------===//
/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the
-/// pointer over the consumed characters. This returns the resultant type.
-static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
+/// pointer over the consumed characters. This returns the resultant type. If
+/// AllowTypeModifiers is false then modifier like * are not parsed, just basic
+/// types. This allows "v2i*" to be parsed as a pointer to a v2i instead of
+/// a vector of "i*".
+///
+/// RequiresICE is filled in on return to indicate whether the value is required
+/// to be an Integer Constant Expression.
+static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
ASTContext::GetBuiltinTypeError &Error,
- bool AllowTypeModifiers = true) {
+ bool &RequiresICE,
+ bool AllowTypeModifiers) {
// Modifiers.
int HowLong = 0;
bool Signed = false, Unsigned = false;
-
- // Read the modifiers first.
+ RequiresICE = false;
+
+ // Read the prefixed modifiers first.
bool Done = false;
while (!Done) {
switch (*Str++) {
default: Done = true; --Str; break;
+ case 'I':
+ RequiresICE = true;
+ break;
case 'S':
assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!");
assert(!Signed && "Can't use 'S' modifier multiple times!");
@@ -5223,6 +5724,12 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
case 'F':
Type = Context.getCFConstantStringType();
break;
+ case 'G':
+ Type = Context.getObjCIdType();
+ break;
+ case 'H':
+ Type = Context.getObjCSelType();
+ break;
case 'a':
Type = Context.getBuiltinVaListType();
assert(!Type.isNull() && "builtin va list type not initialized!");
@@ -5238,27 +5745,30 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
// it to be a __va_list_tag*.
Type = Context.getBuiltinVaListType();
assert(!Type.isNull() && "builtin va list type not initialized!");
- if (Type->isArrayType()) {
+ if (Type->isArrayType())
Type = Context.getArrayDecayedType(Type);
- } else {
+ else
Type = Context.getLValueReferenceType(Type);
- }
break;
case 'V': {
char *End;
unsigned NumElements = strtoul(Str, &End, 10);
assert(End != Str && "Missing vector size");
-
Str = End;
- QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false);
- // FIXME: Don't know what to do about AltiVec.
+ QualType ElementType = DecodeTypeFromStr(Str, Context, Error,
+ RequiresICE, false);
+ assert(!RequiresICE && "Can't require vector ICE");
+
+ // TODO: No way to make AltiVec vectors in builtins yet.
Type = Context.getVectorType(ElementType, NumElements,
- VectorType::NotAltiVec);
+ VectorType::GenericVector);
break;
}
case 'X': {
- QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false);
+ QualType ElementType = DecodeTypeFromStr(Str, Context, Error, RequiresICE,
+ false);
+ assert(!RequiresICE && "Can't require complex ICE");
Type = Context.getComplexType(ElementType);
break;
}
@@ -5282,59 +5792,70 @@ static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context,
break;
}
- if (!AllowTypeModifiers)
- return Type;
-
- Done = false;
+ // If there are modifiers and if we're allowed to parse them, go for it.
+ Done = !AllowTypeModifiers;
while (!Done) {
switch (char c = *Str++) {
- default: Done = true; --Str; break;
- case '*':
- case '&':
- {
- // Both pointers and references can have their pointee types
- // qualified with an address space.
- char *End;
- unsigned AddrSpace = strtoul(Str, &End, 10);
- if (End != Str && AddrSpace != 0) {
- Type = Context.getAddrSpaceQualType(Type, AddrSpace);
- Str = End;
- }
- }
- if (c == '*')
- Type = Context.getPointerType(Type);
- else
- Type = Context.getLValueReferenceType(Type);
- break;
- // FIXME: There's no way to have a built-in with an rvalue ref arg.
- case 'C':
- Type = Type.withConst();
- break;
- case 'D':
- Type = Context.getVolatileType(Type);
- break;
+ default: Done = true; --Str; break;
+ case '*':
+ case '&': {
+ // Both pointers and references can have their pointee types
+ // qualified with an address space.
+ char *End;
+ unsigned AddrSpace = strtoul(Str, &End, 10);
+ if (End != Str && AddrSpace != 0) {
+ Type = Context.getAddrSpaceQualType(Type, AddrSpace);
+ Str = End;
+ }
+ if (c == '*')
+ Type = Context.getPointerType(Type);
+ else
+ Type = Context.getLValueReferenceType(Type);
+ break;
+ }
+ // FIXME: There's no way to have a built-in with an rvalue ref arg.
+ case 'C':
+ Type = Type.withConst();
+ break;
+ case 'D':
+ Type = Context.getVolatileType(Type);
+ break;
}
}
+
+ assert((!RequiresICE || Type->isIntegralOrEnumerationType()) &&
+ "Integer constant 'I' type must be an integer");
return Type;
}
/// GetBuiltinType - Return the type for the specified builtin.
-QualType ASTContext::GetBuiltinType(unsigned id,
- GetBuiltinTypeError &Error) {
- const char *TypeStr = BuiltinInfo.GetTypeString(id);
+QualType ASTContext::GetBuiltinType(unsigned Id,
+ GetBuiltinTypeError &Error,
+ unsigned *IntegerConstantArgs) const {
+ const char *TypeStr = BuiltinInfo.GetTypeString(Id);
llvm::SmallVector<QualType, 8> ArgTypes;
+ bool RequiresICE = false;
Error = GE_None;
- QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error);
+ QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error,
+ RequiresICE, true);
if (Error != GE_None)
return QualType();
+
+ assert(!RequiresICE && "Result of intrinsic cannot be required to be an ICE");
+
while (TypeStr[0] && TypeStr[0] != '.') {
- QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error);
+ QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error, RequiresICE, true);
if (Error != GE_None)
return QualType();
+ // If this argument is required to be an IntegerConstantExpression and the
+ // caller cares, fill in the bitmask we return.
+ if (RequiresICE && IntegerConstantArgs)
+ *IntegerConstantArgs |= 1 << ArgTypes.size();
+
// Do array -> pointer decay. The builtin should use the decayed type.
if (Ty->isArrayType())
Ty = getArrayDecayedType(Ty);
@@ -5345,164 +5866,26 @@ QualType ASTContext::GetBuiltinType(unsigned id,
assert((TypeStr[0] != '.' || TypeStr[1] == 0) &&
"'.' should only occur at end of builtin type list!");
- // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);".
- if (ArgTypes.size() == 0 && TypeStr[0] == '.')
- return getFunctionNoProtoType(ResType);
-
- // FIXME: Should we create noreturn types?
- return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(),
- TypeStr[0] == '.', 0, false, false, 0, 0,
- FunctionType::ExtInfo());
-}
-
-QualType
-ASTContext::UsualArithmeticConversionsType(QualType lhs, QualType rhs) {
- // Perform the usual unary conversions. We do this early so that
- // integral promotions to "int" can allow us to exit early, in the
- // lhs == rhs check. Also, for conversion purposes, we ignore any
- // qualifiers. For example, "const float" and "float" are
- // equivalent.
- if (lhs->isPromotableIntegerType())
- lhs = getPromotedIntegerType(lhs);
- else
- lhs = lhs.getUnqualifiedType();
- if (rhs->isPromotableIntegerType())
- rhs = getPromotedIntegerType(rhs);
- else
- rhs = rhs.getUnqualifiedType();
+ FunctionType::ExtInfo EI;
+ if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true);
- // If both types are identical, no conversion is needed.
- if (lhs == rhs)
- return lhs;
+ bool Variadic = (TypeStr[0] == '.');
- // If either side is a non-arithmetic type (e.g. a pointer), we are done.
- // The caller can deal with this (e.g. pointer + int).
- if (!lhs->isArithmeticType() || !rhs->isArithmeticType())
- return lhs;
+ // We really shouldn't be making a no-proto type here, especially in C++.
+ if (ArgTypes.empty() && Variadic)
+ return getFunctionNoProtoType(ResType, EI);
- // At this point, we have two different arithmetic types.
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.ExtInfo = EI;
+ EPI.Variadic = Variadic;
- // Handle complex types first (C99 6.3.1.8p1).
- if (lhs->isComplexType() || rhs->isComplexType()) {
- // if we have an integer operand, the result is the complex type.
- if (rhs->isIntegerType() || rhs->isComplexIntegerType()) {
- // convert the rhs to the lhs complex type.
- return lhs;
- }
- if (lhs->isIntegerType() || lhs->isComplexIntegerType()) {
- // convert the lhs to the rhs complex type.
- return rhs;
- }
- // This handles complex/complex, complex/float, or float/complex.
- // When both operands are complex, the shorter operand is converted to the
- // type of the longer, and that is the type of the result. This corresponds
- // to what is done when combining two real floating-point operands.
- // The fun begins when size promotion occur across type domains.
- // From H&S 6.3.4: When one operand is complex and the other is a real
- // floating-point type, the less precise type is converted, within it's
- // real or complex domain, to the precision of the other type. For example,
- // when combining a "long double" with a "double _Complex", the
- // "double _Complex" is promoted to "long double _Complex".
- int result = getFloatingTypeOrder(lhs, rhs);
-
- if (result > 0) { // The left side is bigger, convert rhs.
- rhs = getFloatingTypeOfSizeWithinDomain(lhs, rhs);
- } else if (result < 0) { // The right side is bigger, convert lhs.
- lhs = getFloatingTypeOfSizeWithinDomain(rhs, lhs);
- }
- // At this point, lhs and rhs have the same rank/size. Now, make sure the
- // domains match. This is a requirement for our implementation, C99
- // does not require this promotion.
- if (lhs != rhs) { // Domains don't match, we have complex/float mix.
- if (lhs->isRealFloatingType()) { // handle "double, _Complex double".
- return rhs;
- } else { // handle "_Complex double, double".
- return lhs;
- }
- }
- return lhs; // The domain/size match exactly.
- }
- // Now handle "real" floating types (i.e. float, double, long double).
- if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) {
- // if we have an integer operand, the result is the real floating type.
- if (rhs->isIntegerType()) {
- // convert rhs to the lhs floating point type.
- return lhs;
- }
- if (rhs->isComplexIntegerType()) {
- // convert rhs to the complex floating point type.
- return getComplexType(lhs);
- }
- if (lhs->isIntegerType()) {
- // convert lhs to the rhs floating point type.
- return rhs;
- }
- if (lhs->isComplexIntegerType()) {
- // convert lhs to the complex floating point type.
- return getComplexType(rhs);
- }
- // We have two real floating types, float/complex combos were handled above.
- // Convert the smaller operand to the bigger result.
- int result = getFloatingTypeOrder(lhs, rhs);
- if (result > 0) // convert the rhs
- return lhs;
- assert(result < 0 && "illegal float comparison");
- return rhs; // convert the lhs
- }
- if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) {
- // Handle GCC complex int extension.
- const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType();
- const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType();
-
- if (lhsComplexInt && rhsComplexInt) {
- if (getIntegerTypeOrder(lhsComplexInt->getElementType(),
- rhsComplexInt->getElementType()) >= 0)
- return lhs; // convert the rhs
- return rhs;
- } else if (lhsComplexInt && rhs->isIntegerType()) {
- // convert the rhs to the lhs complex type.
- return lhs;
- } else if (rhsComplexInt && lhs->isIntegerType()) {
- // convert the lhs to the rhs complex type.
- return rhs;
- }
- }
- // Finally, we have two differing integer types.
- // The rules for this case are in C99 6.3.1.8
- int compare = getIntegerTypeOrder(lhs, rhs);
- bool lhsSigned = lhs->hasSignedIntegerRepresentation(),
- rhsSigned = rhs->hasSignedIntegerRepresentation();
- QualType destType;
- if (lhsSigned == rhsSigned) {
- // Same signedness; use the higher-ranked type
- destType = compare >= 0 ? lhs : rhs;
- } else if (compare != (lhsSigned ? 1 : -1)) {
- // The unsigned type has greater than or equal rank to the
- // signed type, so use the unsigned type
- destType = lhsSigned ? rhs : lhs;
- } else if (getIntWidth(lhs) != getIntWidth(rhs)) {
- // The two types are different widths; if we are here, that
- // means the signed type is larger than the unsigned type, so
- // use the signed type.
- destType = lhsSigned ? lhs : rhs;
- } else {
- // The signed type is higher-ranked than the unsigned type,
- // but isn't actually any bigger (like unsigned int and long
- // on most 32-bit systems). Use the unsigned type corresponding
- // to the signed type.
- destType = getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
- }
- return destType;
+ return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), EPI);
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
GVALinkage External = GVA_StrongExternal;
Linkage L = FD->getLinkage();
- if (L == ExternalLinkage && getLangOptions().CPlusPlus &&
- FD->getType()->getLinkage() == UniqueExternalLinkage)
- L = UniqueExternalLinkage;
-
switch (L) {
case NoLinkage:
case InternalLinkage:
@@ -5663,4 +6046,26 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
return true;
}
+CallingConv ASTContext::getDefaultMethodCallConv() {
+ // Pass through to the C++ ABI object
+ return ABI->getDefaultMethodCallConv();
+}
+
+bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
+ // Pass through to the C++ ABI object
+ return ABI->isNearlyEmpty(RD);
+}
+
+MangleContext *ASTContext::createMangleContext() {
+ switch (Target.getCXXABI()) {
+ case CXXABI_ARM:
+ case CXXABI_Itanium:
+ return createItaniumMangleContext(*this, getDiagnostics());
+ case CXXABI_Microsoft:
+ return createMicrosoftMangleContext(*this, getDiagnostics());
+ }
+ assert(0 && "Unsupported ABI");
+ return 0;
+}
+
CXXABI::~CXXABI() {}
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 23f323d..5bf8a38 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -28,14 +28,26 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
const Type *Ty = QC.strip(QT);
// Don't aka just because we saw an elaborated type...
- if (isa<ElaboratedType>(Ty)) {
- QT = cast<ElaboratedType>(Ty)->desugar();
+ if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Ty)) {
+ QT = ET->desugar();
continue;
}
-
- // ...or a substituted template type parameter.
- if (isa<SubstTemplateTypeParmType>(Ty)) {
- QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
+ // ... or a paren type ...
+ if (const ParenType *PT = dyn_cast<ParenType>(Ty)) {
+ QT = PT->desugar();
+ continue;
+ }
+ // ...or a substituted template type parameter ...
+ if (const SubstTemplateTypeParmType *ST =
+ dyn_cast<SubstTemplateTypeParmType>(Ty)) {
+ QT = ST->desugar();
+ continue;
+ }
+ // ... or an auto type.
+ if (const AutoType *AT = dyn_cast<AutoType>(Ty)) {
+ if (!AT->isSugared())
+ break;
+ QT = AT->desugar();
continue;
}
@@ -81,10 +93,10 @@ break; \
break;
// Don't desugar through the primary typedef of an anonymous type.
- if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
- if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
- cast<TypedefType>(QT)->getDecl())
- break;
+ if (const TagType *UTT = Underlying->getAs<TagType>())
+ if (const TypedefType *QTT = dyn_cast<TypedefType>(QT))
+ if (UTT->getDecl()->getTypedefForAnonDecl() == QTT->getDecl())
+ break;
// Record that we actually looked through an opaque type here.
ShouldAKA = true;
@@ -94,14 +106,17 @@ break; \
// If we have a pointer-like type, desugar the pointee as well.
// FIXME: Handle other pointer-like types.
if (const PointerType *Ty = QT->getAs<PointerType>()) {
- QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(),
- ShouldAKA));
+ QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(),
+ ShouldAKA));
} else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) {
- QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(),
- ShouldAKA));
+ QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(),
+ ShouldAKA));
+ } else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) {
+ QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(),
+ ShouldAKA));
}
- return QC.apply(QT);
+ return QC.apply(Context, QT);
}
/// \brief Convert the given type to a string suitable for printing as part of
@@ -151,13 +166,10 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
bool ShouldAKA = false;
QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA);
if (ShouldAKA) {
- std::string D = DesugaredTy.getAsString(Context.PrintingPolicy);
- if (D != S) {
- S = "'" + S + "' (aka '";
- S += D;
- S += "')";
- return S;
- }
+ S = "'" + S + "' (aka '";
+ S += DesugaredTy.getAsString(Context.PrintingPolicy);
+ S += "')";
+ return S;
}
}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 2edd09c..65c0a3b 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -41,41 +41,42 @@ namespace {
using StmtVisitor<ASTNodeImporter, Stmt *>::Visit;
// Importing types
- QualType VisitType(Type *T);
- QualType VisitBuiltinType(BuiltinType *T);
- QualType VisitComplexType(ComplexType *T);
- QualType VisitPointerType(PointerType *T);
- QualType VisitBlockPointerType(BlockPointerType *T);
- QualType VisitLValueReferenceType(LValueReferenceType *T);
- QualType VisitRValueReferenceType(RValueReferenceType *T);
- QualType VisitMemberPointerType(MemberPointerType *T);
- QualType VisitConstantArrayType(ConstantArrayType *T);
- QualType VisitIncompleteArrayType(IncompleteArrayType *T);
- QualType VisitVariableArrayType(VariableArrayType *T);
+ QualType VisitType(const Type *T);
+ QualType VisitBuiltinType(const BuiltinType *T);
+ QualType VisitComplexType(const ComplexType *T);
+ QualType VisitPointerType(const PointerType *T);
+ QualType VisitBlockPointerType(const BlockPointerType *T);
+ QualType VisitLValueReferenceType(const LValueReferenceType *T);
+ QualType VisitRValueReferenceType(const RValueReferenceType *T);
+ QualType VisitMemberPointerType(const MemberPointerType *T);
+ QualType VisitConstantArrayType(const ConstantArrayType *T);
+ QualType VisitIncompleteArrayType(const IncompleteArrayType *T);
+ QualType VisitVariableArrayType(const VariableArrayType *T);
// FIXME: DependentSizedArrayType
// FIXME: DependentSizedExtVectorType
- QualType VisitVectorType(VectorType *T);
- QualType VisitExtVectorType(ExtVectorType *T);
- QualType VisitFunctionNoProtoType(FunctionNoProtoType *T);
- QualType VisitFunctionProtoType(FunctionProtoType *T);
+ QualType VisitVectorType(const VectorType *T);
+ QualType VisitExtVectorType(const ExtVectorType *T);
+ QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T);
+ QualType VisitFunctionProtoType(const FunctionProtoType *T);
// FIXME: UnresolvedUsingType
- QualType VisitTypedefType(TypedefType *T);
- QualType VisitTypeOfExprType(TypeOfExprType *T);
+ QualType VisitTypedefType(const TypedefType *T);
+ QualType VisitTypeOfExprType(const TypeOfExprType *T);
// FIXME: DependentTypeOfExprType
- QualType VisitTypeOfType(TypeOfType *T);
- QualType VisitDecltypeType(DecltypeType *T);
+ QualType VisitTypeOfType(const TypeOfType *T);
+ QualType VisitDecltypeType(const DecltypeType *T);
+ QualType VisitAutoType(const AutoType *T);
// FIXME: DependentDecltypeType
- QualType VisitRecordType(RecordType *T);
- QualType VisitEnumType(EnumType *T);
+ QualType VisitRecordType(const RecordType *T);
+ QualType VisitEnumType(const EnumType *T);
// FIXME: TemplateTypeParmType
// FIXME: SubstTemplateTypeParmType
- // FIXME: TemplateSpecializationType
- QualType VisitElaboratedType(ElaboratedType *T);
+ QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T);
+ QualType VisitElaboratedType(const ElaboratedType *T);
// FIXME: DependentNameType
// FIXME: DependentTemplateSpecializationType
- QualType VisitObjCInterfaceType(ObjCInterfaceType *T);
- QualType VisitObjCObjectType(ObjCObjectType *T);
- QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
+ QualType VisitObjCInterfaceType(const ObjCInterfaceType *T);
+ QualType VisitObjCObjectType(const ObjCObjectType *T);
+ QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T);
// Importing declarations
bool ImportDeclParts(NamedDecl *D, DeclContext *&DC,
@@ -83,9 +84,17 @@ namespace {
SourceLocation &Loc);
void ImportDeclarationNameLoc(const DeclarationNameInfo &From,
DeclarationNameInfo& To);
- void ImportDeclContext(DeclContext *FromDC);
+ void ImportDeclContext(DeclContext *FromDC, bool ForceImport = false);
+ bool ImportDefinition(RecordDecl *From, RecordDecl *To);
+ TemplateParameterList *ImportTemplateParameterList(
+ TemplateParameterList *Params);
+ TemplateArgument ImportTemplateArgument(const TemplateArgument &From);
+ bool ImportTemplateArguments(const TemplateArgument *FromArgs,
+ unsigned NumFromArgs,
+ llvm::SmallVectorImpl<TemplateArgument> &ToArgs);
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord);
bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
+ bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
Decl *VisitDecl(Decl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
Decl *VisitTypedefDecl(TypedefDecl *D);
@@ -98,6 +107,7 @@ namespace {
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
Decl *VisitFieldDecl(FieldDecl *D);
+ Decl *VisitIndirectFieldDecl(IndirectFieldDecl *D);
Decl *VisitObjCIvarDecl(ObjCIvarDecl *D);
Decl *VisitVarDecl(VarDecl *D);
Decl *VisitImplicitParamDecl(ImplicitParamDecl *D);
@@ -106,9 +116,18 @@ namespace {
Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D);
Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D);
Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D);
+ Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D);
+ Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D);
Decl *VisitObjCPropertyDecl(ObjCPropertyDecl *D);
+ Decl *VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
Decl *VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D);
Decl *VisitObjCClassDecl(ObjCClassDecl *D);
+ Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
+ Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
+ Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
+ Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
+ Decl *VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *D);
// Importing statements
Stmt *VisitStmt(Stmt *S);
@@ -137,9 +156,6 @@ namespace {
/// \brief AST contexts for which we are checking structural equivalence.
ASTContext &C1, &C2;
- /// \brief Diagnostic object used to emit diagnostics.
- Diagnostic &Diags;
-
/// \brief The set of "tentative" equivalences between two canonical
/// declarations, mapping from a declaration in the first context to the
/// declaration in the second context that we believe to be equivalent.
@@ -158,10 +174,9 @@ namespace {
bool StrictTypeSpelling;
StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2,
- Diagnostic &Diags,
llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls,
bool StrictTypeSpelling = false)
- : C1(C1), C2(C2), Diags(Diags), NonEquivalentDecls(NonEquivalentDecls),
+ : C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls),
StrictTypeSpelling(StrictTypeSpelling) { }
/// \brief Determine whether the two declarations are structurally
@@ -179,11 +194,11 @@ namespace {
public:
DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) {
- return Diags.Report(FullSourceLoc(Loc, C1.getSourceManager()), DiagID);
+ return C1.getDiagnostics().Report(Loc, DiagID);
}
DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) {
- return Diags.Report(FullSourceLoc(Loc, C2.getSourceManager()), DiagID);
+ return C2.getDiagnostics().Report(Loc, DiagID);
}
};
}
@@ -200,9 +215,9 @@ static bool IsSameValue(const llvm::APInt &I1, const llvm::APInt &I2) {
return I1 == I2;
if (I1.getBitWidth() > I2.getBitWidth())
- return I1 == llvm::APInt(I2).zext(I1.getBitWidth());
+ return I1 == I2.zext(I1.getBitWidth());
- return llvm::APInt(I1).zext(I2.getBitWidth()) == I2;
+ return I1.zext(I2.getBitWidth()) == I2;
}
/// \brief Determine if two APSInts have the same value, zero- or sign-extending
@@ -213,9 +228,9 @@ static bool IsSameValue(const llvm::APSInt &I1, const llvm::APSInt &I2) {
// Check for a bit-width mismatch.
if (I1.getBitWidth() > I2.getBitWidth())
- return IsSameValue(I1, llvm::APSInt(I2).extend(I1.getBitWidth()));
+ return IsSameValue(I1, I2.extend(I1.getBitWidth()));
else if (I2.getBitWidth() > I1.getBitWidth())
- return IsSameValue(llvm::APSInt(I1).extend(I2.getBitWidth()), I2);
+ return IsSameValue(I1.extend(I2.getBitWidth()), I2);
// We have a signedness mismatch. Turn the signed value into an unsigned
// value.
@@ -263,7 +278,54 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
const TemplateArgument &Arg1,
const TemplateArgument &Arg2) {
- // FIXME: Implement!
+ if (Arg1.getKind() != Arg2.getKind())
+ return false;
+
+ switch (Arg1.getKind()) {
+ case TemplateArgument::Null:
+ return true;
+
+ case TemplateArgument::Type:
+ return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType());
+
+ case TemplateArgument::Integral:
+ if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(),
+ Arg2.getIntegralType()))
+ return false;
+
+ return IsSameValue(*Arg1.getAsIntegral(), *Arg2.getAsIntegral());
+
+ case TemplateArgument::Declaration:
+ return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl());
+
+ case TemplateArgument::Template:
+ return IsStructurallyEquivalent(Context,
+ Arg1.getAsTemplate(),
+ Arg2.getAsTemplate());
+
+ case TemplateArgument::TemplateExpansion:
+ return IsStructurallyEquivalent(Context,
+ Arg1.getAsTemplateOrTemplatePattern(),
+ Arg2.getAsTemplateOrTemplatePattern());
+
+ case TemplateArgument::Expression:
+ return IsStructurallyEquivalent(Context,
+ Arg1.getAsExpr(), Arg2.getAsExpr());
+
+ case TemplateArgument::Pack:
+ if (Arg1.pack_size() != Arg2.pack_size())
+ return false;
+
+ for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I)
+ if (!IsStructurallyEquivalent(Context,
+ Arg1.pack_begin()[I],
+ Arg2.pack_begin()[I]))
+ return false;
+
+ return true;
+ }
+
+ llvm_unreachable("Invalid template argument kind");
return true;
}
@@ -441,7 +503,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
if (Vec1->getNumElements() != Vec2->getNumElements())
return false;
- if (Vec1->getAltiVecSpecific() != Vec2->getAltiVecSpecific())
+ if (Vec1->getVectorKind() != Vec2->getVectorKind())
return false;
break;
}
@@ -496,7 +558,25 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
+
+ case Type::Attributed:
+ if (!IsStructurallyEquivalent(Context,
+ cast<AttributedType>(T1)->getModifiedType(),
+ cast<AttributedType>(T2)->getModifiedType()))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ cast<AttributedType>(T1)->getEquivalentType(),
+ cast<AttributedType>(T2)->getEquivalentType()))
+ return false;
+ break;
+ case Type::Paren:
+ if (!IsStructurallyEquivalent(Context,
+ cast<ParenType>(T1)->getInnerType(),
+ cast<ParenType>(T2)->getInnerType()))
+ return false;
+ break;
+
case Type::Typedef:
if (!IsStructurallyEquivalent(Context,
cast<TypedefType>(T1)->getDecl(),
@@ -525,6 +605,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
break;
+ case Type::Auto:
+ if (!IsStructurallyEquivalent(Context,
+ cast<AutoType>(T1)->getDeducedType(),
+ cast<AutoType>(T2)->getDeducedType()))
+ return false;
+ break;
+
case Type::Record:
case Type::Enum:
if (!IsStructurallyEquivalent(Context,
@@ -563,6 +650,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
break;
}
+ case Type::SubstTemplateTypeParmPack: {
+ const SubstTemplateTypeParmPackType *Subst1
+ = cast<SubstTemplateTypeParmPackType>(T1);
+ const SubstTemplateTypeParmPackType *Subst2
+ = cast<SubstTemplateTypeParmPackType>(T2);
+ if (!IsStructurallyEquivalent(Context,
+ QualType(Subst1->getReplacedParameter(), 0),
+ QualType(Subst2->getReplacedParameter(), 0)))
+ return false;
+ if (!IsStructurallyEquivalent(Context,
+ Subst1->getArgumentPack(),
+ Subst2->getArgumentPack()))
+ return false;
+ break;
+ }
case Type::TemplateSpecialization: {
const TemplateSpecializationType *Spec1
= cast<TemplateSpecializationType>(T1);
@@ -644,7 +746,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
}
break;
}
-
+
+ case Type::PackExpansion:
+ if (!IsStructurallyEquivalent(Context,
+ cast<PackExpansionType>(T1)->getPattern(),
+ cast<PackExpansionType>(T2)->getPattern()))
+ return false;
+ break;
+
case Type::ObjCInterface: {
const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1);
const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2);
@@ -698,6 +807,33 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return false;
}
+ // If both declarations are class template specializations, we know
+ // the ODR applies, so check the template and template arguments.
+ ClassTemplateSpecializationDecl *Spec1
+ = dyn_cast<ClassTemplateSpecializationDecl>(D1);
+ ClassTemplateSpecializationDecl *Spec2
+ = dyn_cast<ClassTemplateSpecializationDecl>(D2);
+ if (Spec1 && Spec2) {
+ // Check that the specialized templates are the same.
+ if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(),
+ Spec2->getSpecializedTemplate()))
+ return false;
+
+ // Check that the template arguments are the same.
+ if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size())
+ return false;
+
+ for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I)
+ if (!IsStructurallyEquivalent(Context,
+ Spec1->getTemplateArgs().get(I),
+ Spec2->getTemplateArgs().get(I)))
+ return false;
+ }
+ // If one is a class template specialization and the other is not, these
+ // structures are diferent.
+ else if (Spec1 || Spec2)
+ return false;
+
// Compare the definitions of these two records. If either or both are
// incomplete, we assume that they are equivalent.
D1 = D1->getDefinition();
@@ -709,11 +845,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
- << Context.C2.getTypeDeclType(D2);
+ << Context.C2.getTypeDeclType(D2);
Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases)
- << D2CXX->getNumBases();
+ << D2CXX->getNumBases();
Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases)
- << D1CXX->getNumBases();
+ << D1CXX->getNumBases();
return false;
}
@@ -892,7 +1028,112 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
return true;
}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ TemplateParameterList *Params1,
+ TemplateParameterList *Params2) {
+ if (Params1->size() != Params2->size()) {
+ Context.Diag2(Params2->getTemplateLoc(),
+ diag::err_odr_different_num_template_parameters)
+ << Params1->size() << Params2->size();
+ Context.Diag1(Params1->getTemplateLoc(),
+ diag::note_odr_template_parameter_list);
+ return false;
+ }
+ for (unsigned I = 0, N = Params1->size(); I != N; ++I) {
+ if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) {
+ Context.Diag2(Params2->getParam(I)->getLocation(),
+ diag::err_odr_different_template_parameter_kind);
+ Context.Diag1(Params1->getParam(I)->getLocation(),
+ diag::note_odr_template_parameter_here);
+ return false;
+ }
+
+ if (!Context.IsStructurallyEquivalent(Params1->getParam(I),
+ Params2->getParam(I))) {
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ TemplateTypeParmDecl *D1,
+ TemplateTypeParmDecl *D2) {
+ if (D1->isParameterPack() != D2->isParameterPack()) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ return false;
+ }
+
+ return true;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ NonTypeTemplateParmDecl *D1,
+ NonTypeTemplateParmDecl *D2) {
+ // FIXME: Enable once we have variadic templates.
+#if 0
+ if (D1->isParameterPack() != D2->isParameterPack()) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ return false;
+ }
+#endif
+
+ // Check types.
+ if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) {
+ Context.Diag2(D2->getLocation(),
+ diag::err_odr_non_type_parameter_type_inconsistent)
+ << D2->getType() << D1->getType();
+ Context.Diag1(D1->getLocation(), diag::note_odr_value_here)
+ << D1->getType();
+ return false;
+ }
+
+ return true;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ TemplateTemplateParmDecl *D1,
+ TemplateTemplateParmDecl *D2) {
+ // FIXME: Enable once we have variadic templates.
+#if 0
+ if (D1->isParameterPack() != D2->isParameterPack()) {
+ Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack)
+ << D2->isParameterPack();
+ Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack)
+ << D1->isParameterPack();
+ return false;
+ }
+#endif
+
+ // Check template parameter lists.
+ return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
+ D2->getTemplateParameters());
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+ ClassTemplateDecl *D1,
+ ClassTemplateDecl *D2) {
+ // Check template parameters.
+ if (!IsStructurallyEquivalent(Context,
+ D1->getTemplateParameters(),
+ D2->getTemplateParameters()))
+ return false;
+
+ // Check the templated declaration.
+ return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(),
+ D2->getTemplatedDecl());
+}
+
/// \brief Determine structural equivalence of two declarations.
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
Decl *D1, Decl *D2) {
@@ -988,8 +1229,47 @@ bool StructuralEquivalenceContext::Finish() {
// Typedef/non-typedef mismatch.
Equivalent = false;
}
- }
-
+ } else if (ClassTemplateDecl *ClassTemplate1
+ = dyn_cast<ClassTemplateDecl>(D1)) {
+ if (ClassTemplateDecl *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(),
+ ClassTemplate2->getIdentifier()) ||
+ !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2))
+ Equivalent = false;
+ } else {
+ // Class template/non-class-template mismatch.
+ Equivalent = false;
+ }
+ } else if (TemplateTypeParmDecl *TTP1= dyn_cast<TemplateTypeParmDecl>(D1)) {
+ if (TemplateTypeParmDecl *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
+ Equivalent = false;
+ } else {
+ // Kind mismatch.
+ Equivalent = false;
+ }
+ } else if (NonTypeTemplateParmDecl *NTTP1
+ = dyn_cast<NonTypeTemplateParmDecl>(D1)) {
+ if (NonTypeTemplateParmDecl *NTTP2
+ = dyn_cast<NonTypeTemplateParmDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2))
+ Equivalent = false;
+ } else {
+ // Kind mismatch.
+ Equivalent = false;
+ }
+ } else if (TemplateTemplateParmDecl *TTP1
+ = dyn_cast<TemplateTemplateParmDecl>(D1)) {
+ if (TemplateTemplateParmDecl *TTP2
+ = dyn_cast<TemplateTemplateParmDecl>(D2)) {
+ if (!::IsStructurallyEquivalent(*this, TTP1, TTP2))
+ Equivalent = false;
+ } else {
+ // Kind mismatch.
+ Equivalent = false;
+ }
+ }
+
if (!Equivalent) {
// Note that these two declarations are not equivalent (and we already
// know about it).
@@ -1007,13 +1287,13 @@ bool StructuralEquivalenceContext::Finish() {
// Import Types
//----------------------------------------------------------------------------
-QualType ASTNodeImporter::VisitType(Type *T) {
+QualType ASTNodeImporter::VisitType(const Type *T) {
Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node)
<< T->getTypeClassName();
return QualType();
}
-QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) {
+QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) {
switch (T->getKind()) {
case BuiltinType::Void: return Importer.getToContext().VoidTy;
case BuiltinType::Bool: return Importer.getToContext().BoolTy;
@@ -1054,7 +1334,8 @@ QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) {
return Importer.getToContext().CharTy;
case BuiltinType::SChar: return Importer.getToContext().SignedCharTy;
- case BuiltinType::WChar:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
// FIXME: If not in C++, shall we translate to the C equivalent of
// wchar_t?
return Importer.getToContext().WCharTy;
@@ -1074,9 +1355,6 @@ QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) {
case BuiltinType::Overload: return Importer.getToContext().OverloadTy;
case BuiltinType::Dependent: return Importer.getToContext().DependentTy;
- case BuiltinType::UndeducedAuto:
- // FIXME: Make sure that the "to" context supports C++0x!
- return Importer.getToContext().UndeducedAutoTy;
case BuiltinType::ObjCId:
// FIXME: Make sure that the "to" context supports Objective-C!
@@ -1092,7 +1370,7 @@ QualType ASTNodeImporter::VisitBuiltinType(BuiltinType *T) {
return QualType();
}
-QualType ASTNodeImporter::VisitComplexType(ComplexType *T) {
+QualType ASTNodeImporter::VisitComplexType(const ComplexType *T) {
QualType ToElementType = Importer.Import(T->getElementType());
if (ToElementType.isNull())
return QualType();
@@ -1100,7 +1378,7 @@ QualType ASTNodeImporter::VisitComplexType(ComplexType *T) {
return Importer.getToContext().getComplexType(ToElementType);
}
-QualType ASTNodeImporter::VisitPointerType(PointerType *T) {
+QualType ASTNodeImporter::VisitPointerType(const PointerType *T) {
QualType ToPointeeType = Importer.Import(T->getPointeeType());
if (ToPointeeType.isNull())
return QualType();
@@ -1108,7 +1386,7 @@ QualType ASTNodeImporter::VisitPointerType(PointerType *T) {
return Importer.getToContext().getPointerType(ToPointeeType);
}
-QualType ASTNodeImporter::VisitBlockPointerType(BlockPointerType *T) {
+QualType ASTNodeImporter::VisitBlockPointerType(const BlockPointerType *T) {
// FIXME: Check for blocks support in "to" context.
QualType ToPointeeType = Importer.Import(T->getPointeeType());
if (ToPointeeType.isNull())
@@ -1117,7 +1395,8 @@ QualType ASTNodeImporter::VisitBlockPointerType(BlockPointerType *T) {
return Importer.getToContext().getBlockPointerType(ToPointeeType);
}
-QualType ASTNodeImporter::VisitLValueReferenceType(LValueReferenceType *T) {
+QualType
+ASTNodeImporter::VisitLValueReferenceType(const LValueReferenceType *T) {
// FIXME: Check for C++ support in "to" context.
QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten());
if (ToPointeeType.isNull())
@@ -1126,7 +1405,8 @@ QualType ASTNodeImporter::VisitLValueReferenceType(LValueReferenceType *T) {
return Importer.getToContext().getLValueReferenceType(ToPointeeType);
}
-QualType ASTNodeImporter::VisitRValueReferenceType(RValueReferenceType *T) {
+QualType
+ASTNodeImporter::VisitRValueReferenceType(const RValueReferenceType *T) {
// FIXME: Check for C++0x support in "to" context.
QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten());
if (ToPointeeType.isNull())
@@ -1135,7 +1415,7 @@ QualType ASTNodeImporter::VisitRValueReferenceType(RValueReferenceType *T) {
return Importer.getToContext().getRValueReferenceType(ToPointeeType);
}
-QualType ASTNodeImporter::VisitMemberPointerType(MemberPointerType *T) {
+QualType ASTNodeImporter::VisitMemberPointerType(const MemberPointerType *T) {
// FIXME: Check for C++ support in "to" context.
QualType ToPointeeType = Importer.Import(T->getPointeeType());
if (ToPointeeType.isNull())
@@ -1146,7 +1426,7 @@ QualType ASTNodeImporter::VisitMemberPointerType(MemberPointerType *T) {
ClassType.getTypePtr());
}
-QualType ASTNodeImporter::VisitConstantArrayType(ConstantArrayType *T) {
+QualType ASTNodeImporter::VisitConstantArrayType(const ConstantArrayType *T) {
QualType ToElementType = Importer.Import(T->getElementType());
if (ToElementType.isNull())
return QualType();
@@ -1157,7 +1437,8 @@ QualType ASTNodeImporter::VisitConstantArrayType(ConstantArrayType *T) {
T->getIndexTypeCVRQualifiers());
}
-QualType ASTNodeImporter::VisitIncompleteArrayType(IncompleteArrayType *T) {
+QualType
+ASTNodeImporter::VisitIncompleteArrayType(const IncompleteArrayType *T) {
QualType ToElementType = Importer.Import(T->getElementType());
if (ToElementType.isNull())
return QualType();
@@ -1167,7 +1448,7 @@ QualType ASTNodeImporter::VisitIncompleteArrayType(IncompleteArrayType *T) {
T->getIndexTypeCVRQualifiers());
}
-QualType ASTNodeImporter::VisitVariableArrayType(VariableArrayType *T) {
+QualType ASTNodeImporter::VisitVariableArrayType(const VariableArrayType *T) {
QualType ToElementType = Importer.Import(T->getElementType());
if (ToElementType.isNull())
return QualType();
@@ -1183,17 +1464,17 @@ QualType ASTNodeImporter::VisitVariableArrayType(VariableArrayType *T) {
Brackets);
}
-QualType ASTNodeImporter::VisitVectorType(VectorType *T) {
+QualType ASTNodeImporter::VisitVectorType(const VectorType *T) {
QualType ToElementType = Importer.Import(T->getElementType());
if (ToElementType.isNull())
return QualType();
return Importer.getToContext().getVectorType(ToElementType,
T->getNumElements(),
- T->getAltiVecSpecific());
+ T->getVectorKind());
}
-QualType ASTNodeImporter::VisitExtVectorType(ExtVectorType *T) {
+QualType ASTNodeImporter::VisitExtVectorType(const ExtVectorType *T) {
QualType ToElementType = Importer.Import(T->getElementType());
if (ToElementType.isNull())
return QualType();
@@ -1202,7 +1483,8 @@ QualType ASTNodeImporter::VisitExtVectorType(ExtVectorType *T) {
T->getNumElements());
}
-QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) {
+QualType
+ASTNodeImporter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
// FIXME: What happens if we're importing a function without a prototype
// into C++? Should we make it variadic?
QualType ToResultType = Importer.Import(T->getResultType());
@@ -1213,7 +1495,7 @@ QualType ASTNodeImporter::VisitFunctionNoProtoType(FunctionNoProtoType *T) {
T->getExtInfo());
}
-QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) {
+QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
QualType ToResultType = Importer.Import(T->getResultType());
if (ToResultType.isNull())
return QualType();
@@ -1239,19 +1521,15 @@ QualType ASTNodeImporter::VisitFunctionProtoType(FunctionProtoType *T) {
return QualType();
ExceptionTypes.push_back(ExceptionType);
}
+
+ FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo();
+ EPI.Exceptions = ExceptionTypes.data();
return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(),
- ArgTypes.size(),
- T->isVariadic(),
- T->getTypeQuals(),
- T->hasExceptionSpec(),
- T->hasAnyExceptionSpec(),
- ExceptionTypes.size(),
- ExceptionTypes.data(),
- T->getExtInfo());
+ ArgTypes.size(), EPI);
}
-QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) {
+QualType ASTNodeImporter::VisitTypedefType(const TypedefType *T) {
TypedefDecl *ToDecl
= dyn_cast_or_null<TypedefDecl>(Importer.Import(T->getDecl()));
if (!ToDecl)
@@ -1260,7 +1538,7 @@ QualType ASTNodeImporter::VisitTypedefType(TypedefType *T) {
return Importer.getToContext().getTypeDeclType(ToDecl);
}
-QualType ASTNodeImporter::VisitTypeOfExprType(TypeOfExprType *T) {
+QualType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) {
Expr *ToExpr = Importer.Import(T->getUnderlyingExpr());
if (!ToExpr)
return QualType();
@@ -1268,7 +1546,7 @@ QualType ASTNodeImporter::VisitTypeOfExprType(TypeOfExprType *T) {
return Importer.getToContext().getTypeOfExprType(ToExpr);
}
-QualType ASTNodeImporter::VisitTypeOfType(TypeOfType *T) {
+QualType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) {
QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType());
if (ToUnderlyingType.isNull())
return QualType();
@@ -1276,7 +1554,8 @@ QualType ASTNodeImporter::VisitTypeOfType(TypeOfType *T) {
return Importer.getToContext().getTypeOfType(ToUnderlyingType);
}
-QualType ASTNodeImporter::VisitDecltypeType(DecltypeType *T) {
+QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) {
+ // FIXME: Make sure that the "to" context supports C++0x!
Expr *ToExpr = Importer.Import(T->getUnderlyingExpr());
if (!ToExpr)
return QualType();
@@ -1284,7 +1563,20 @@ QualType ASTNodeImporter::VisitDecltypeType(DecltypeType *T) {
return Importer.getToContext().getDecltypeType(ToExpr);
}
-QualType ASTNodeImporter::VisitRecordType(RecordType *T) {
+QualType ASTNodeImporter::VisitAutoType(const AutoType *T) {
+ // FIXME: Make sure that the "to" context supports C++0x!
+ QualType FromDeduced = T->getDeducedType();
+ QualType ToDeduced;
+ if (!FromDeduced.isNull()) {
+ ToDeduced = Importer.Import(FromDeduced);
+ if (ToDeduced.isNull())
+ return QualType();
+ }
+
+ return Importer.getToContext().getAutoType(ToDeduced);
+}
+
+QualType ASTNodeImporter::VisitRecordType(const RecordType *T) {
RecordDecl *ToDecl
= dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl()));
if (!ToDecl)
@@ -1293,7 +1585,7 @@ QualType ASTNodeImporter::VisitRecordType(RecordType *T) {
return Importer.getToContext().getTagDeclType(ToDecl);
}
-QualType ASTNodeImporter::VisitEnumType(EnumType *T) {
+QualType ASTNodeImporter::VisitEnumType(const EnumType *T) {
EnumDecl *ToDecl
= dyn_cast_or_null<EnumDecl>(Importer.Import(T->getDecl()));
if (!ToDecl)
@@ -1302,7 +1594,31 @@ QualType ASTNodeImporter::VisitEnumType(EnumType *T) {
return Importer.getToContext().getTagDeclType(ToDecl);
}
-QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) {
+QualType ASTNodeImporter::VisitTemplateSpecializationType(
+ const TemplateSpecializationType *T) {
+ TemplateName ToTemplate = Importer.Import(T->getTemplateName());
+ if (ToTemplate.isNull())
+ return QualType();
+
+ llvm::SmallVector<TemplateArgument, 2> ToTemplateArgs;
+ if (ImportTemplateArguments(T->getArgs(), T->getNumArgs(), ToTemplateArgs))
+ return QualType();
+
+ QualType ToCanonType;
+ if (!QualType(T, 0).isCanonical()) {
+ QualType FromCanonType
+ = Importer.getFromContext().getCanonicalType(QualType(T, 0));
+ ToCanonType =Importer.Import(FromCanonType);
+ if (ToCanonType.isNull())
+ return QualType();
+ }
+ return Importer.getToContext().getTemplateSpecializationType(ToTemplate,
+ ToTemplateArgs.data(),
+ ToTemplateArgs.size(),
+ ToCanonType);
+}
+
+QualType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) {
NestedNameSpecifier *ToQualifier = 0;
// Note: the qualifier in an ElaboratedType is optional.
if (T->getQualifier()) {
@@ -1319,7 +1635,7 @@ QualType ASTNodeImporter::VisitElaboratedType(ElaboratedType *T) {
ToQualifier, ToNamedType);
}
-QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) {
+QualType ASTNodeImporter::VisitObjCInterfaceType(const ObjCInterfaceType *T) {
ObjCInterfaceDecl *Class
= dyn_cast_or_null<ObjCInterfaceDecl>(Importer.Import(T->getDecl()));
if (!Class)
@@ -1328,7 +1644,7 @@ QualType ASTNodeImporter::VisitObjCInterfaceType(ObjCInterfaceType *T) {
return Importer.getToContext().getObjCInterfaceType(Class);
}
-QualType ASTNodeImporter::VisitObjCObjectType(ObjCObjectType *T) {
+QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) {
QualType ToBaseType = Importer.Import(T->getBaseType());
if (ToBaseType.isNull())
return QualType();
@@ -1349,7 +1665,8 @@ QualType ASTNodeImporter::VisitObjCObjectType(ObjCObjectType *T) {
Protocols.size());
}
-QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) {
+QualType
+ASTNodeImporter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) {
QualType ToPointeeType = Importer.Import(T->getPointeeType());
if (ToPointeeType.isNull())
return QualType();
@@ -1420,7 +1737,15 @@ ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From,
}
}
-void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC) {
+void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) {
+ if (Importer.isMinimalImport() && !ForceImport) {
+ if (DeclContext *ToDC = Importer.ImportContext(FromDC)) {
+ ToDC->setHasExternalLexicalStorage();
+ ToDC->setHasExternalVisibleStorage();
+ }
+ return;
+ }
+
for (DeclContext::decl_iterator From = FromDC->decls_begin(),
FromEnd = FromDC->decls_end();
From != FromEnd;
@@ -1428,11 +1753,151 @@ void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC) {
Importer.Import(*From);
}
+bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) {
+ if (To->getDefinition())
+ return false;
+
+ To->startDefinition();
+
+ // Add base classes.
+ if (CXXRecordDecl *ToCXX = dyn_cast<CXXRecordDecl>(To)) {
+ CXXRecordDecl *FromCXX = cast<CXXRecordDecl>(From);
+
+ llvm::SmallVector<CXXBaseSpecifier *, 4> Bases;
+ for (CXXRecordDecl::base_class_iterator
+ Base1 = FromCXX->bases_begin(),
+ FromBaseEnd = FromCXX->bases_end();
+ Base1 != FromBaseEnd;
+ ++Base1) {
+ QualType T = Importer.Import(Base1->getType());
+ if (T.isNull())
+ return true;
+
+ SourceLocation EllipsisLoc;
+ if (Base1->isPackExpansion())
+ EllipsisLoc = Importer.Import(Base1->getEllipsisLoc());
+
+ Bases.push_back(
+ new (Importer.getToContext())
+ CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()),
+ Base1->isVirtual(),
+ Base1->isBaseOfClass(),
+ Base1->getAccessSpecifierAsWritten(),
+ Importer.Import(Base1->getTypeSourceInfo()),
+ EllipsisLoc));
+ }
+ if (!Bases.empty())
+ ToCXX->setBases(Bases.data(), Bases.size());
+ }
+
+ ImportDeclContext(From);
+ To->completeDefinition();
+ return false;
+}
+
+TemplateParameterList *ASTNodeImporter::ImportTemplateParameterList(
+ TemplateParameterList *Params) {
+ llvm::SmallVector<NamedDecl *, 4> ToParams;
+ ToParams.reserve(Params->size());
+ for (TemplateParameterList::iterator P = Params->begin(),
+ PEnd = Params->end();
+ P != PEnd; ++P) {
+ Decl *To = Importer.Import(*P);
+ if (!To)
+ return 0;
+
+ ToParams.push_back(cast<NamedDecl>(To));
+ }
+
+ return TemplateParameterList::Create(Importer.getToContext(),
+ Importer.Import(Params->getTemplateLoc()),
+ Importer.Import(Params->getLAngleLoc()),
+ ToParams.data(), ToParams.size(),
+ Importer.Import(Params->getRAngleLoc()));
+}
+
+TemplateArgument
+ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) {
+ switch (From.getKind()) {
+ case TemplateArgument::Null:
+ return TemplateArgument();
+
+ case TemplateArgument::Type: {
+ QualType ToType = Importer.Import(From.getAsType());
+ if (ToType.isNull())
+ return TemplateArgument();
+ return TemplateArgument(ToType);
+ }
+
+ case TemplateArgument::Integral: {
+ QualType ToType = Importer.Import(From.getIntegralType());
+ if (ToType.isNull())
+ return TemplateArgument();
+ return TemplateArgument(*From.getAsIntegral(), ToType);
+ }
+
+ case TemplateArgument::Declaration:
+ if (Decl *To = Importer.Import(From.getAsDecl()))
+ return TemplateArgument(To);
+ return TemplateArgument();
+
+ case TemplateArgument::Template: {
+ TemplateName ToTemplate = Importer.Import(From.getAsTemplate());
+ if (ToTemplate.isNull())
+ return TemplateArgument();
+
+ return TemplateArgument(ToTemplate);
+ }
+
+ case TemplateArgument::TemplateExpansion: {
+ TemplateName ToTemplate
+ = Importer.Import(From.getAsTemplateOrTemplatePattern());
+ if (ToTemplate.isNull())
+ return TemplateArgument();
+
+ return TemplateArgument(ToTemplate, From.getNumTemplateExpansions());
+ }
+
+ case TemplateArgument::Expression:
+ if (Expr *ToExpr = Importer.Import(From.getAsExpr()))
+ return TemplateArgument(ToExpr);
+ return TemplateArgument();
+
+ case TemplateArgument::Pack: {
+ llvm::SmallVector<TemplateArgument, 2> ToPack;
+ ToPack.reserve(From.pack_size());
+ if (ImportTemplateArguments(From.pack_begin(), From.pack_size(), ToPack))
+ return TemplateArgument();
+
+ TemplateArgument *ToArgs
+ = new (Importer.getToContext()) TemplateArgument[ToPack.size()];
+ std::copy(ToPack.begin(), ToPack.end(), ToArgs);
+ return TemplateArgument(ToArgs, ToPack.size());
+ }
+ }
+
+ llvm_unreachable("Invalid template argument kind");
+ return TemplateArgument();
+}
+
+bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs,
+ unsigned NumFromArgs,
+ llvm::SmallVectorImpl<TemplateArgument> &ToArgs) {
+ for (unsigned I = 0; I != NumFromArgs; ++I) {
+ TemplateArgument To = ImportTemplateArgument(FromArgs[I]);
+ if (To.isNull() && !FromArgs[I].isNull())
+ return true;
+
+ ToArgs.push_back(To);
+ }
+
+ return false;
+}
+
bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
RecordDecl *ToRecord) {
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
Importer.getToContext(),
- Importer.getDiags(),
Importer.getNonEquivalentDecls());
return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord);
}
@@ -1440,11 +1905,18 @@ bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
Importer.getToContext(),
- Importer.getDiags(),
Importer.getNonEquivalentDecls());
return Ctx.IsStructurallyEquivalent(FromEnum, ToEnum);
}
+bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
+ ClassTemplateDecl *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();
@@ -1620,9 +2092,10 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
// Create the enum declaration.
EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, Loc,
- Name.getAsIdentifierInfo(),
- Importer.Import(D->getTagKeywordLoc()),
- 0);
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getTagKeywordLoc()), 0,
+ D->isScoped(), D->isScopedUsingClassTag(),
+ D->isFixed());
// Import the qualifier, if any.
if (D->getQualifier()) {
NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
@@ -1764,38 +2237,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
Importer.Imported(D, D2);
- if (D->isDefinition()) {
- D2->startDefinition();
-
- // Add base classes.
- if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
- CXXRecordDecl *D1CXX = cast<CXXRecordDecl>(D);
-
- llvm::SmallVector<CXXBaseSpecifier *, 4> Bases;
- for (CXXRecordDecl::base_class_iterator
- Base1 = D1CXX->bases_begin(),
- FromBaseEnd = D1CXX->bases_end();
- Base1 != FromBaseEnd;
- ++Base1) {
- QualType T = Importer.Import(Base1->getType());
- if (T.isNull())
- return 0;
-
- Bases.push_back(
- new (Importer.getToContext())
- CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()),
- Base1->isVirtual(),
- Base1->isBaseOfClass(),
- Base1->getAccessSpecifierAsWritten(),
- Importer.Import(Base1->getTypeSourceInfo())));
- }
- if (!Bases.empty())
- D2CXX->setBases(Bases.data(), Bases.size());
- }
-
- ImportDeclContext(D);
- D2->completeDefinition();
- }
+ if (D->isDefinition() && ImportDefinition(D, D2))
+ return 0;
return D2;
}
@@ -1939,7 +2382,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
} else if (isa<CXXDestructorDecl>(D)) {
ToFunction = CXXDestructorDecl::Create(Importer.getToContext(),
cast<CXXRecordDecl>(DC),
- NameInfo, T,
+ NameInfo, T, TInfo,
D->isInlineSpecified(),
D->isImplicit());
} else if (CXXConversionDecl *FromConversion
@@ -1949,6 +2392,13 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
NameInfo, T, TInfo,
D->isInlineSpecified(),
FromConversion->isExplicit());
+ } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ ToFunction = CXXMethodDecl::Create(Importer.getToContext(),
+ cast<CXXRecordDecl>(DC),
+ NameInfo, T, TInfo,
+ Method->isStatic(),
+ Method->getStorageClassAsWritten(),
+ Method->isInlineSpecified());
} else {
ToFunction = FunctionDecl::Create(Importer.getToContext(), DC,
NameInfo, T, TInfo, D->getStorageClass(),
@@ -1965,8 +2415,10 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
}
ToFunction->setAccess(D->getAccess());
ToFunction->setLexicalDeclContext(LexicalDC);
+ ToFunction->setVirtualAsWritten(D->isVirtualAsWritten());
+ ToFunction->setTrivial(D->isTrivial());
+ ToFunction->setPure(D->isPure());
Importer.Imported(D, ToFunction);
- LexicalDC->addDecl(ToFunction);
// Set the parameters.
for (unsigned I = 0, N = Parameters.size(); I != N; ++I) {
@@ -1976,7 +2428,10 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToFunction->setParams(Parameters.data(), Parameters.size());
// FIXME: Other bits to merge?
-
+
+ // Add this function to the lexical context.
+ LexicalDC->addDecl(ToFunction);
+
return ToFunction;
}
@@ -2024,6 +2479,42 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
return ToField;
}
+Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
+ // Import the major distinguishing characteristics of a variable.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // Import the type.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ NamedDecl **NamedChain =
+ new (Importer.getToContext())NamedDecl*[D->getChainingSize()];
+
+ unsigned i = 0;
+ for (IndirectFieldDecl::chain_iterator PI = D->chain_begin(),
+ PE = D->chain_end(); PI != PE; ++PI) {
+ Decl* D = Importer.Import(*PI);
+ if (!D)
+ return 0;
+ NamedChain[i++] = cast<NamedDecl>(D);
+ }
+
+ IndirectFieldDecl *ToIndirectField = IndirectFieldDecl::Create(
+ Importer.getToContext(), DC,
+ Loc, Name.getAsIdentifierInfo(), T,
+ NamedChain, D->getChainingSize());
+ ToIndirectField->setAccess(D->getAccess());
+ ToIndirectField->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToIndirectField);
+ LexicalDC->addDecl(ToIndirectField);
+ return ToIndirectField;
+}
+
Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
// Import the major distinguishing characteristics of an ivar.
DeclContext *DC, *LexicalDC;
@@ -2434,7 +2925,8 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
// If we have an implementation, import it as well.
if (D->getImplementation()) {
ObjCCategoryImplDecl *Impl
- = cast<ObjCCategoryImplDecl>(Importer.Import(D->getImplementation()));
+ = cast_or_null<ObjCCategoryImplDecl>(
+ Importer.Import(D->getImplementation()));
if (!Impl)
return 0;
@@ -2615,8 +3107,8 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
// If we have an @implementation, import it as well.
if (D->getImplementation()) {
- ObjCImplementationDecl *Impl
- = cast<ObjCImplementationDecl>(Importer.Import(D->getImplementation()));
+ ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>(
+ Importer.Import(D->getImplementation()));
if (!Impl)
return 0;
@@ -2626,6 +3118,114 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
return ToIface;
}
+Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) {
+ ObjCCategoryDecl *Category = cast_or_null<ObjCCategoryDecl>(
+ Importer.Import(D->getCategoryDecl()));
+ if (!Category)
+ return 0;
+
+ ObjCCategoryImplDecl *ToImpl = Category->getImplementation();
+ if (!ToImpl) {
+ DeclContext *DC = Importer.ImportContext(D->getDeclContext());
+ if (!DC)
+ return 0;
+
+ ToImpl = ObjCCategoryImplDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getLocation()),
+ Importer.Import(D->getIdentifier()),
+ Category->getClassInterface());
+
+ DeclContext *LexicalDC = DC;
+ if (D->getDeclContext() != D->getLexicalDeclContext()) {
+ LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
+ if (!LexicalDC)
+ return 0;
+
+ ToImpl->setLexicalDeclContext(LexicalDC);
+ }
+
+ LexicalDC->addDecl(ToImpl);
+ Category->setImplementation(ToImpl);
+ }
+
+ Importer.Imported(D, ToImpl);
+ ImportDeclContext(D);
+ return ToImpl;
+}
+
+Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) {
+ // Find the corresponding interface.
+ ObjCInterfaceDecl *Iface = cast_or_null<ObjCInterfaceDecl>(
+ Importer.Import(D->getClassInterface()));
+ if (!Iface)
+ return 0;
+
+ // Import the superclass, if any.
+ ObjCInterfaceDecl *Super = 0;
+ if (D->getSuperClass()) {
+ Super = cast_or_null<ObjCInterfaceDecl>(
+ Importer.Import(D->getSuperClass()));
+ if (!Super)
+ return 0;
+ }
+
+ ObjCImplementationDecl *Impl = Iface->getImplementation();
+ if (!Impl) {
+ // We haven't imported an implementation yet. Create a new @implementation
+ // now.
+ Impl = ObjCImplementationDecl::Create(Importer.getToContext(),
+ Importer.ImportContext(D->getDeclContext()),
+ Importer.Import(D->getLocation()),
+ Iface, Super);
+
+ if (D->getDeclContext() != D->getLexicalDeclContext()) {
+ DeclContext *LexicalDC
+ = Importer.ImportContext(D->getLexicalDeclContext());
+ if (!LexicalDC)
+ return 0;
+ Impl->setLexicalDeclContext(LexicalDC);
+ }
+
+ // Associate the implementation with the class it implements.
+ Iface->setImplementation(Impl);
+ Importer.Imported(D, Iface->getImplementation());
+ } else {
+ Importer.Imported(D, Iface->getImplementation());
+
+ // Verify that the existing @implementation has the same superclass.
+ if ((Super && !Impl->getSuperClass()) ||
+ (!Super && Impl->getSuperClass()) ||
+ (Super && Impl->getSuperClass() &&
+ Super->getCanonicalDecl() != Impl->getSuperClass())) {
+ Importer.ToDiag(Impl->getLocation(),
+ diag::err_odr_objc_superclass_inconsistent)
+ << Iface->getDeclName();
+ // FIXME: It would be nice to have the location of the superclass
+ // below.
+ if (Impl->getSuperClass())
+ Importer.ToDiag(Impl->getLocation(),
+ diag::note_odr_objc_superclass)
+ << Impl->getSuperClass()->getDeclName();
+ else
+ Importer.ToDiag(Impl->getLocation(),
+ diag::note_odr_objc_missing_superclass);
+ if (D->getSuperClass())
+ Importer.FromDiag(D->getLocation(),
+ diag::note_odr_objc_superclass)
+ << D->getSuperClass()->getDeclName();
+ else
+ Importer.FromDiag(D->getLocation(),
+ diag::note_odr_objc_missing_superclass);
+ return 0;
+ }
+ }
+
+ // Import all of the members of this @implementation.
+ ImportDeclContext(D);
+
+ return Impl;
+}
+
Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
// Import the major distinguishing characteristics of an @property.
DeclContext *DC, *LexicalDC;
@@ -2688,6 +3288,87 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
return ToProperty;
}
+Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) {
+ ObjCPropertyDecl *Property = cast_or_null<ObjCPropertyDecl>(
+ Importer.Import(D->getPropertyDecl()));
+ if (!Property)
+ return 0;
+
+ DeclContext *DC = Importer.ImportContext(D->getDeclContext());
+ if (!DC)
+ return 0;
+
+ // Import the lexical declaration context.
+ DeclContext *LexicalDC = DC;
+ if (D->getDeclContext() != D->getLexicalDeclContext()) {
+ LexicalDC = Importer.ImportContext(D->getLexicalDeclContext());
+ if (!LexicalDC)
+ return 0;
+ }
+
+ ObjCImplDecl *InImpl = dyn_cast<ObjCImplDecl>(LexicalDC);
+ if (!InImpl)
+ return 0;
+
+ // Import the ivar (for an @synthesize).
+ ObjCIvarDecl *Ivar = 0;
+ if (D->getPropertyIvarDecl()) {
+ Ivar = cast_or_null<ObjCIvarDecl>(
+ Importer.Import(D->getPropertyIvarDecl()));
+ if (!Ivar)
+ return 0;
+ }
+
+ ObjCPropertyImplDecl *ToImpl
+ = InImpl->FindPropertyImplDecl(Property->getIdentifier());
+ if (!ToImpl) {
+ ToImpl = ObjCPropertyImplDecl::Create(Importer.getToContext(), DC,
+ Importer.Import(D->getLocStart()),
+ Importer.Import(D->getLocation()),
+ Property,
+ D->getPropertyImplementation(),
+ Ivar,
+ Importer.Import(D->getPropertyIvarDeclLoc()));
+ ToImpl->setLexicalDeclContext(LexicalDC);
+ Importer.Imported(D, ToImpl);
+ LexicalDC->addDecl(ToImpl);
+ } else {
+ // Check that we have the same kind of property implementation (@synthesize
+ // vs. @dynamic).
+ if (D->getPropertyImplementation() != ToImpl->getPropertyImplementation()) {
+ Importer.ToDiag(ToImpl->getLocation(),
+ diag::err_odr_objc_property_impl_kind_inconsistent)
+ << Property->getDeclName()
+ << (ToImpl->getPropertyImplementation()
+ == ObjCPropertyImplDecl::Dynamic);
+ Importer.FromDiag(D->getLocation(),
+ diag::note_odr_objc_property_impl_kind)
+ << D->getPropertyDecl()->getDeclName()
+ << (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic);
+ return 0;
+ }
+
+ // For @synthesize, check that we have the same
+ if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize &&
+ Ivar != ToImpl->getPropertyIvarDecl()) {
+ Importer.ToDiag(ToImpl->getPropertyIvarDeclLoc(),
+ diag::err_odr_objc_synthesize_ivar_inconsistent)
+ << Property->getDeclName()
+ << ToImpl->getPropertyIvarDecl()->getDeclName()
+ << Ivar->getDeclName();
+ Importer.FromDiag(D->getPropertyIvarDeclLoc(),
+ diag::note_odr_objc_synthesize_ivar_here)
+ << D->getPropertyIvarDecl()->getDeclName();
+ return 0;
+ }
+
+ // Merge the existing implementation with the new implementation.
+ Importer.Imported(D, ToImpl);
+ }
+
+ return ToImpl;
+}
+
Decl *
ASTNodeImporter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
// Import the context of this declaration.
@@ -2772,6 +3453,275 @@ Decl *ASTNodeImporter::VisitObjCClassDecl(ObjCClassDecl *D) {
return ToClass;
}
+Decl *ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
+ // For template arguments, we adopt the translation unit as our declaration
+ // context. This context will be fixed when the actual template declaration
+ // is created.
+
+ // FIXME: Import default argument.
+ return TemplateTypeParmDecl::Create(Importer.getToContext(),
+ Importer.getToContext().getTranslationUnitDecl(),
+ Importer.Import(D->getLocation()),
+ D->getDepth(),
+ D->getIndex(),
+ Importer.Import(D->getIdentifier()),
+ D->wasDeclaredWithTypename(),
+ D->isParameterPack());
+}
+
+Decl *
+ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
+ // Import the name of this declaration.
+ DeclarationName Name = Importer.Import(D->getDeclName());
+ if (D->getDeclName() && !Name)
+ return 0;
+
+ // Import the location of this declaration.
+ SourceLocation Loc = Importer.Import(D->getLocation());
+
+ // Import the type of this declaration.
+ QualType T = Importer.Import(D->getType());
+ if (T.isNull())
+ return 0;
+
+ // Import type-source information.
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ if (D->getTypeSourceInfo() && !TInfo)
+ return 0;
+
+ // FIXME: Import default argument.
+
+ return NonTypeTemplateParmDecl::Create(Importer.getToContext(),
+ Importer.getToContext().getTranslationUnitDecl(),
+ Loc, D->getDepth(), D->getPosition(),
+ Name.getAsIdentifierInfo(),
+ T, D->isParameterPack(), TInfo);
+}
+
+Decl *
+ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
+ // Import the name of this declaration.
+ DeclarationName Name = Importer.Import(D->getDeclName());
+ if (D->getDeclName() && !Name)
+ return 0;
+
+ // Import the location of this declaration.
+ SourceLocation Loc = Importer.Import(D->getLocation());
+
+ // Import template parameters.
+ TemplateParameterList *TemplateParams
+ = ImportTemplateParameterList(D->getTemplateParameters());
+ if (!TemplateParams)
+ return 0;
+
+ // FIXME: Import default argument.
+
+ return TemplateTemplateParmDecl::Create(Importer.getToContext(),
+ Importer.getToContext().getTranslationUnitDecl(),
+ Loc, D->getDepth(), D->getPosition(),
+ D->isParameterPack(),
+ Name.getAsIdentifierInfo(),
+ TemplateParams);
+}
+
+Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *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.
+ CXXRecordDecl *Definition
+ = cast_or_null<CXXRecordDecl>(D->getTemplatedDecl()->getDefinition());
+ if (Definition && Definition != D->getTemplatedDecl()) {
+ Decl *ImportedDef
+ = Importer.Import(Definition->getDescribedClassTemplate());
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ // Import the major distinguishing characteristics of this class 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.
+ if (!DC->isFunctionOrMethod()) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary))
+ continue;
+
+ Decl *Found = *Lookup.first;
+ if (ClassTemplateDecl *FoundTemplate
+ = dyn_cast<ClassTemplateDecl>(Found)) {
+ if (IsStructuralMatch(D, FoundTemplate)) {
+ // The class templates structurally match; call it the same template.
+ // FIXME: We may be filling in a forward declaration here. Handle
+ // this case!
+ Importer.Imported(D->getTemplatedDecl(),
+ FoundTemplate->getTemplatedDecl());
+ return Importer.Imported(D, FoundTemplate);
+ }
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ }
+
+ if (!Name)
+ return 0;
+ }
+
+ CXXRecordDecl *DTemplated = D->getTemplatedDecl();
+
+ // Create the declaration that is being templated.
+ CXXRecordDecl *D2Templated = CXXRecordDecl::Create(Importer.getToContext(),
+ DTemplated->getTagKind(),
+ DC,
+ Importer.Import(DTemplated->getLocation()),
+ Name.getAsIdentifierInfo(),
+ Importer.Import(DTemplated->getTagKeywordLoc()));
+ D2Templated->setAccess(DTemplated->getAccess());
+
+
+ // Import the qualifier, if any.
+ if (DTemplated->getQualifier()) {
+ NestedNameSpecifier *NNS = Importer.Import(DTemplated->getQualifier());
+ SourceRange NNSRange = Importer.Import(DTemplated->getQualifierRange());
+ D2Templated->setQualifierInfo(NNS, NNSRange);
+ }
+ D2Templated->setLexicalDeclContext(LexicalDC);
+
+ // Create the class template declaration itself.
+ TemplateParameterList *TemplateParams
+ = ImportTemplateParameterList(D->getTemplateParameters());
+ if (!TemplateParams)
+ return 0;
+
+ ClassTemplateDecl *D2 = ClassTemplateDecl::Create(Importer.getToContext(), DC,
+ Loc, Name, TemplateParams,
+ D2Templated,
+ /*PrevDecl=*/0);
+ D2Templated->setDescribedClassTemplate(D2);
+
+ D2->setAccess(D->getAccess());
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDecl(D2);
+
+ // Note the relationship between the class templates.
+ Importer.Imported(D, D2);
+ Importer.Imported(DTemplated, D2Templated);
+
+ if (DTemplated->isDefinition() && !D2Templated->isDefinition()) {
+ // FIXME: Import definition!
+ }
+
+ return D2;
+}
+
+Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl(
+ ClassTemplateSpecializationDecl *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.
+ TagDecl *Definition = D->getDefinition();
+ if (Definition && Definition != D) {
+ Decl *ImportedDef = Importer.Import(Definition);
+ if (!ImportedDef)
+ return 0;
+
+ return Importer.Imported(D, ImportedDef);
+ }
+
+ ClassTemplateDecl *ClassTemplate
+ = cast_or_null<ClassTemplateDecl>(Importer.Import(
+ D->getSpecializedTemplate()));
+ if (!ClassTemplate)
+ return 0;
+
+ // Import the context of this declaration.
+ DeclContext *DC = ClassTemplate->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 Loc = Importer.Import(D->getLocation());
+
+ // Import template arguments.
+ llvm::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;
+ ClassTemplateSpecializationDecl *D2
+ = ClassTemplate->findSpecialization(TemplateArgs.data(),
+ TemplateArgs.size(), InsertPos);
+ if (D2) {
+ // We already have a class template specialization with these template
+ // arguments.
+
+ // FIXME: Check for specialization vs. instantiation errors.
+
+ if (RecordDecl *FoundDef = D2->getDefinition()) {
+ if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) {
+ // The record types structurally match, or the "from" translation
+ // unit only had a forward declaration anyway; call it the same
+ // function.
+ return Importer.Imported(D, FoundDef);
+ }
+ }
+ } else {
+ // Create a new specialization.
+ D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(),
+ D->getTagKind(), DC,
+ Loc, ClassTemplate,
+ TemplateArgs.data(),
+ TemplateArgs.size(),
+ /*PrevDecl=*/0);
+ D2->setSpecializationKind(D->getSpecializationKind());
+
+ // Add this specialization to the class template.
+ ClassTemplate->AddSpecialization(D2, InsertPos);
+
+ // Import the qualifier, if any.
+ if (D->getQualifier()) {
+ NestedNameSpecifier *NNS = Importer.Import(D->getQualifier());
+ SourceRange NNSRange = Importer.Import(D->getQualifierRange());
+ D2->setQualifierInfo(NNS, NNSRange);
+ }
+
+
+ // Add the specialization to this context.
+ D2->setLexicalDeclContext(LexicalDC);
+ LexicalDC->addDecl(D2);
+ }
+ Importer.Imported(D, D2);
+
+ if (D->isDefinition() && ImportDefinition(D, D2))
+ return 0;
+
+ return D2;
+}
+
//----------------------------------------------------------------------------
// Import Statements
//----------------------------------------------------------------------------
@@ -2811,7 +3761,7 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
Importer.Import(E->getQualifierRange()),
ToD,
Importer.Import(E->getLocation()),
- T,
+ T, E->getValueKind(),
/*FIXME:TemplateArgs=*/0);
}
@@ -2856,7 +3806,8 @@ Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) {
return 0;
return new (Importer.getToContext()) UnaryOperator(SubExpr, E->getOpcode(),
- T,
+ T, E->getValueKind(),
+ E->getObjectKind(),
Importer.Import(E->getOperatorLoc()));
}
@@ -2898,7 +3849,8 @@ Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) {
return 0;
return new (Importer.getToContext()) BinaryOperator(LHS, RHS, E->getOpcode(),
- T,
+ T, E->getValueKind(),
+ E->getObjectKind(),
Importer.Import(E->getOperatorLoc()));
}
@@ -2925,7 +3877,9 @@ Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
return new (Importer.getToContext())
CompoundAssignOperator(LHS, RHS, E->getOpcode(),
- T, CompLHSType, CompResultType,
+ T, E->getValueKind(),
+ E->getObjectKind(),
+ CompLHSType, CompResultType,
Importer.Import(E->getOperatorLoc()));
}
@@ -2970,18 +3924,20 @@ Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) {
if (ImportCastPath(E, BasePath))
return 0;
- return CStyleCastExpr::Create(Importer.getToContext(), T, E->getCastKind(),
+ return CStyleCastExpr::Create(Importer.getToContext(), T,
+ E->getValueKind(), E->getCastKind(),
SubExpr, &BasePath, TInfo,
Importer.Import(E->getLParenLoc()),
Importer.Import(E->getRParenLoc()));
}
-ASTImporter::ASTImporter(Diagnostic &Diags,
- ASTContext &ToContext, FileManager &ToFileManager,
- ASTContext &FromContext, FileManager &FromFileManager)
+ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
+ ASTContext &FromContext, FileManager &FromFileManager,
+ bool MinimalImport)
: ToContext(ToContext), FromContext(FromContext),
ToFileManager(ToFileManager), FromFileManager(FromFileManager),
- Diags(Diags) {
+ Minimal(MinimalImport)
+{
ImportedDecls[FromContext.getTranslationUnitDecl()]
= ToContext.getTranslationUnitDecl();
}
@@ -2991,23 +3947,25 @@ ASTImporter::~ASTImporter() { }
QualType ASTImporter::Import(QualType FromT) {
if (FromT.isNull())
return QualType();
+
+ const Type *fromTy = FromT.getTypePtr();
// Check whether we've already imported this type.
- llvm::DenseMap<Type *, Type *>::iterator Pos
- = ImportedTypes.find(FromT.getTypePtr());
+ llvm::DenseMap<const Type *, const Type *>::iterator Pos
+ = ImportedTypes.find(fromTy);
if (Pos != ImportedTypes.end())
- return ToContext.getQualifiedType(Pos->second, FromT.getQualifiers());
+ return ToContext.getQualifiedType(Pos->second, FromT.getLocalQualifiers());
// Import the type
ASTNodeImporter Importer(*this);
- QualType ToT = Importer.Visit(FromT.getTypePtr());
+ QualType ToT = Importer.Visit(fromTy);
if (ToT.isNull())
return ToT;
// Record the imported type.
- ImportedTypes[FromT.getTypePtr()] = ToT.getTypePtr();
+ ImportedTypes[fromTy] = ToT.getTypePtr();
- return ToContext.getQualifiedType(ToT, FromT.getQualifiers());
+ return ToContext.getQualifiedType(ToT, FromT.getLocalQualifiers());
}
TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) {
@@ -3109,6 +4067,82 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
return 0;
}
+TemplateName ASTImporter::Import(TemplateName From) {
+ switch (From.getKind()) {
+ case TemplateName::Template:
+ if (TemplateDecl *ToTemplate
+ = cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl())))
+ return TemplateName(ToTemplate);
+
+ return TemplateName();
+
+ case TemplateName::OverloadedTemplate: {
+ OverloadedTemplateStorage *FromStorage = From.getAsOverloadedTemplate();
+ UnresolvedSet<2> ToTemplates;
+ for (OverloadedTemplateStorage::iterator I = FromStorage->begin(),
+ E = FromStorage->end();
+ I != E; ++I) {
+ if (NamedDecl *To = cast_or_null<NamedDecl>(Import(*I)))
+ ToTemplates.addDecl(To);
+ else
+ return TemplateName();
+ }
+ return ToContext.getOverloadedTemplateName(ToTemplates.begin(),
+ ToTemplates.end());
+ }
+
+ case TemplateName::QualifiedTemplate: {
+ QualifiedTemplateName *QTN = From.getAsQualifiedTemplateName();
+ NestedNameSpecifier *Qualifier = Import(QTN->getQualifier());
+ if (!Qualifier)
+ return TemplateName();
+
+ if (TemplateDecl *ToTemplate
+ = cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl())))
+ return ToContext.getQualifiedTemplateName(Qualifier,
+ QTN->hasTemplateKeyword(),
+ ToTemplate);
+
+ return TemplateName();
+ }
+
+ case TemplateName::DependentTemplate: {
+ DependentTemplateName *DTN = From.getAsDependentTemplateName();
+ NestedNameSpecifier *Qualifier = Import(DTN->getQualifier());
+ if (!Qualifier)
+ return TemplateName();
+
+ if (DTN->isIdentifier()) {
+ return ToContext.getDependentTemplateName(Qualifier,
+ Import(DTN->getIdentifier()));
+ }
+
+ return ToContext.getDependentTemplateName(Qualifier, DTN->getOperator());
+ }
+
+ case TemplateName::SubstTemplateTemplateParmPack: {
+ SubstTemplateTemplateParmPackStorage *SubstPack
+ = From.getAsSubstTemplateTemplateParmPack();
+ TemplateTemplateParmDecl *Param
+ = cast_or_null<TemplateTemplateParmDecl>(
+ Import(SubstPack->getParameterPack()));
+ if (!Param)
+ return TemplateName();
+
+ ASTNodeImporter Importer(*this);
+ TemplateArgument ArgPack
+ = Importer.ImportTemplateArgument(SubstPack->getArgumentPack());
+ if (ArgPack.isNull())
+ return TemplateName();
+
+ return ToContext.getSubstTemplateTemplateParmPack(Param, ArgPack);
+ }
+ }
+
+ llvm_unreachable("Invalid template name kind");
+ return TemplateName();
+}
+
SourceLocation ASTImporter::Import(SourceLocation FromLoc) {
if (FromLoc.isInvalid())
return SourceLocation();
@@ -3130,8 +4164,8 @@ SourceRange ASTImporter::Import(SourceRange FromRange) {
}
FileID ASTImporter::Import(FileID FromID) {
- llvm::DenseMap<unsigned, FileID>::iterator Pos
- = ImportedFileIDs.find(FromID.getHashValue());
+ llvm::DenseMap<FileID, FileID>::iterator Pos
+ = ImportedFileIDs.find(FromID);
if (Pos != ImportedFileIDs.end())
return Pos->second;
@@ -3156,7 +4190,8 @@ FileID ASTImporter::Import(FileID FromID) {
FromSLoc.getFile().getFileCharacteristic());
} else {
// FIXME: We want to re-use the existing MemoryBuffer!
- const llvm::MemoryBuffer *FromBuf = Cache->getBuffer(getDiags(), FromSM);
+ const llvm::MemoryBuffer *
+ FromBuf = Cache->getBuffer(FromContext.getDiagnostics(), FromSM);
llvm::MemoryBuffer *ToBuf
= llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(),
FromBuf->getBufferIdentifier());
@@ -3164,10 +4199,21 @@ FileID ASTImporter::Import(FileID FromID) {
}
- ImportedFileIDs[FromID.getHashValue()] = ToID;
+ ImportedFileIDs[FromID] = ToID;
return ToID;
}
+void ASTImporter::ImportDefinition(Decl *From) {
+ Decl *To = Import(From);
+ if (!To)
+ return;
+
+ if (DeclContext *FromDC = cast<DeclContext>(From)) {
+ ASTNodeImporter Importer(*this);
+ Importer.ImportDeclContext(FromDC, true);
+ }
+}
+
DeclarationName ASTImporter::Import(DeclarationName FromName) {
if (!FromName)
return DeclarationName();
@@ -3225,7 +4271,7 @@ DeclarationName ASTImporter::Import(DeclarationName FromName) {
return DeclarationName();
}
-IdentifierInfo *ASTImporter::Import(IdentifierInfo *FromId) {
+IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) {
if (!FromId)
return 0;
@@ -3252,13 +4298,11 @@ DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name,
}
DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) {
- return Diags.Report(FullSourceLoc(Loc, ToContext.getSourceManager()),
- DiagID);
+ return ToContext.getDiagnostics().Report(Loc, DiagID);
}
DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) {
- return Diags.Report(FullSourceLoc(Loc, FromContext.getSourceManager()),
- DiagID);
+ return FromContext.getDiagnostics().Report(Loc, DiagID);
}
Decl *ASTImporter::Imported(Decl *From, Decl *To) {
@@ -3267,12 +4311,11 @@ Decl *ASTImporter::Imported(Decl *From, Decl *To) {
}
bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To) {
- llvm::DenseMap<Type *, Type *>::iterator Pos
+ llvm::DenseMap<const Type *, const Type *>::iterator Pos
= ImportedTypes.find(From.getTypePtr());
if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To))
return true;
- StructuralEquivalenceContext Ctx(FromContext, ToContext, Diags,
- NonEquivalentDecls);
+ StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls);
return Ctx.IsStructurallyEquivalent(From, To);
}
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 82a81ec..9fe1840 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -1,4 +1,6 @@
-set(LLVM_NO_RTTI 1)
+set(LLVM_LINK_COMPONENTS support)
+
+set(LLVM_USED_LIBS clangBasic)
add_clang_library(clangAST
APValue.cpp
@@ -17,14 +19,17 @@ add_clang_library(clangAST
DeclObjC.cpp
DeclPrinter.cpp
DeclTemplate.cpp
+ DumpXML.cpp
Expr.cpp
ExprClassification.cpp
ExprConstant.cpp
ExprCXX.cpp
- FullExpr.cpp
InheritViz.cpp
ItaniumCXXABI.cpp
+ ItaniumMangle.cpp
+ Mangle.cpp
MicrosoftCXXABI.cpp
+ MicrosoftMangle.cpp
NestedNameSpecifier.cpp
ParentMap.cpp
RecordLayout.cpp
diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h
index 4b38d7a..943c43e 100644
--- a/lib/AST/CXXABI.h
+++ b/lib/AST/CXXABI.h
@@ -15,6 +15,8 @@
#ifndef LLVM_CLANG_AST_CXXABI_H
#define LLVM_CLANG_AST_CXXABI_H
+#include "clang/AST/Type.h"
+
namespace clang {
class ASTContext;
@@ -28,6 +30,13 @@ public:
/// Returns the size of a member pointer in multiples of the target
/// pointer size.
virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0;
+
+ /// Returns the default calling convention for C++ methods.
+ virtual CallingConv getDefaultMethodCallConv() const = 0;
+
+ // 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;
};
/// Creates an instance of a C++ ABI class.
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index c563c37..ca9ec18 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -11,6 +11,7 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/DeclCXX.h"
#include <algorithm>
#include <set>
@@ -75,18 +76,21 @@ void CXXBasePaths::swap(CXXBasePaths &Other) {
std::swap(DetectedVirtual, Other.DetectedVirtual);
}
-bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) const {
+bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base) const {
CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
/*DetectVirtual=*/false);
return isDerivedFrom(Base, Paths);
}
-bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const {
+bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base,
+ CXXBasePaths &Paths) const {
if (getCanonicalDecl() == Base->getCanonicalDecl())
return false;
Paths.setOrigin(const_cast<CXXRecordDecl*>(this));
- return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths);
+ return lookupInBases(&FindBaseClass,
+ const_cast<CXXRecordDecl*>(Base->getCanonicalDecl()),
+ Paths);
}
bool CXXRecordDecl::isVirtuallyDerivedFrom(CXXRecordDecl *Base) const {
@@ -662,3 +666,50 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
}
}
}
+
+static void
+AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,
+ CXXIndirectPrimaryBaseSet& Bases) {
+ // If the record has a virtual primary base class, add it to our set.
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ if (Layout.isPrimaryBaseVirtual())
+ Bases.insert(Layout.getPrimaryBase());
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ assert(!I->getType()->isDependentType() &&
+ "Cannot get indirect primary bases for class with dependent bases.");
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Only bases with virtual bases participate in computing the
+ // indirect primary virtual base classes.
+ if (BaseDecl->getNumVBases())
+ AddIndirectPrimaryBases(BaseDecl, Context, Bases);
+ }
+
+}
+
+void
+CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const {
+ ASTContext &Context = getASTContext();
+
+ if (!getNumVBases())
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator I = bases_begin(),
+ E = bases_end(); I != E; ++I) {
+ assert(!I->getType()->isDependentType() &&
+ "Cannot get indirect primary bases for class with dependent bases.");
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+
+ // Only bases with virtual bases participate in computing the
+ // indirect primary virtual base classes.
+ if (BaseDecl->getNumVBases())
+ AddIndirectPrimaryBases(BaseDecl, Context, Bases);
+ }
+}
+
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index b7be02d..56db8c7 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Specifiers.h"
@@ -32,35 +33,140 @@ using namespace clang;
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
+static const VisibilityAttr *GetExplicitVisibility(const Decl *d) {
+ // Use the most recent declaration of a variable.
+ if (const VarDecl *var = dyn_cast<VarDecl>(d))
+ return var->getMostRecentDeclaration()->getAttr<VisibilityAttr>();
+
+ // Use the most recent declaration of a function, and also handle
+ // function template specializations.
+ if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(d)) {
+ if (const VisibilityAttr *attr
+ = fn->getMostRecentDeclaration()->getAttr<VisibilityAttr>())
+ return attr;
+
+ // If the function is a specialization of a template with an
+ // explicit visibility attribute, use that.
+ if (FunctionTemplateSpecializationInfo *templateInfo
+ = fn->getTemplateSpecializationInfo())
+ return templateInfo->getTemplate()->getTemplatedDecl()
+ ->getAttr<VisibilityAttr>();
+
+ return 0;
+ }
+
+ // Otherwise, just check the declaration itself first.
+ if (const VisibilityAttr *attr = d->getAttr<VisibilityAttr>())
+ return attr;
+
+ // If there wasn't explicit visibility there, and this is a
+ // specialization of a class template, check for visibility
+ // on the pattern.
+ if (const ClassTemplateSpecializationDecl *spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(d))
+ return spec->getSpecializedTemplate()->getTemplatedDecl()
+ ->getAttr<VisibilityAttr>();
+
+ return 0;
+}
+
+static Visibility GetVisibilityFromAttr(const VisibilityAttr *A) {
+ switch (A->getVisibility()) {
+ case VisibilityAttr::Default:
+ return DefaultVisibility;
+ case VisibilityAttr::Hidden:
+ return HiddenVisibility;
+ case VisibilityAttr::Protected:
+ return ProtectedVisibility;
+ }
+ return DefaultVisibility;
+}
+
+typedef NamedDecl::LinkageInfo LinkageInfo;
+typedef std::pair<Linkage,Visibility> LVPair;
+
+static LVPair merge(LVPair L, LVPair R) {
+ return LVPair(minLinkage(L.first, R.first),
+ minVisibility(L.second, R.second));
+}
+
+static LVPair merge(LVPair L, LinkageInfo R) {
+ return LVPair(minLinkage(L.first, R.linkage()),
+ minVisibility(L.second, R.visibility()));
+}
+
+namespace {
+/// Flags controlling the computation of linkage and visibility.
+struct LVFlags {
+ bool ConsiderGlobalVisibility;
+ bool ConsiderVisibilityAttributes;
+
+ LVFlags() : ConsiderGlobalVisibility(true),
+ ConsiderVisibilityAttributes(true) {
+ }
+
+ /// \brief Returns a set of flags that is only useful for computing the
+ /// linkage, not the visibility, of a declaration.
+ static LVFlags CreateOnlyDeclLinkage() {
+ LVFlags F;
+ F.ConsiderGlobalVisibility = false;
+ F.ConsiderVisibilityAttributes = false;
+ return F;
+ }
+
+ /// Returns a set of flags, otherwise based on these, which ignores
+ /// off all sources of visibility except template arguments.
+ LVFlags onlyTemplateVisibility() const {
+ LVFlags F = *this;
+ F.ConsiderGlobalVisibility = false;
+ F.ConsiderVisibilityAttributes = false;
+ return F;
+ }
+};
+} // end anonymous namespace
+
/// \brief Get the most restrictive linkage for the types in the given
/// template parameter list.
-static Linkage
-getLinkageForTemplateParameterList(const TemplateParameterList *Params) {
- Linkage L = ExternalLinkage;
+static LVPair
+getLVForTemplateParameterList(const TemplateParameterList *Params) {
+ LVPair LV(ExternalLinkage, DefaultVisibility);
for (TemplateParameterList::const_iterator P = Params->begin(),
PEnd = Params->end();
P != PEnd; ++P) {
- if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P))
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
+ if (NTTP->isExpandedParameterPack()) {
+ for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) {
+ QualType T = NTTP->getExpansionType(I);
+ if (!T->isDependentType())
+ LV = merge(LV, T->getLinkageAndVisibility());
+ }
+ continue;
+ }
+
if (!NTTP->getType()->isDependentType()) {
- L = minLinkage(L, NTTP->getType()->getLinkage());
+ LV = merge(LV, NTTP->getType()->getLinkageAndVisibility());
continue;
}
+ }
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(*P)) {
- L = minLinkage(L,
- getLinkageForTemplateParameterList(TTP->getTemplateParameters()));
+ LV = merge(LV, getLVForTemplateParameterList(TTP->getTemplateParameters()));
}
}
- return L;
+ return LV;
}
+/// getLVForDecl - Get the linkage and visibility for the given declaration.
+static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags F);
+
/// \brief Get the most restrictive linkage for the types and
/// declarations in the given template argument list.
-static Linkage getLinkageForTemplateArgumentList(const TemplateArgument *Args,
- unsigned NumArgs) {
- Linkage L = ExternalLinkage;
+static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args,
+ unsigned NumArgs,
+ LVFlags &F) {
+ LVPair LV(ExternalLinkage, DefaultVisibility);
for (unsigned I = 0; I != NumArgs; ++I) {
switch (Args[I].getKind()) {
@@ -70,40 +176,43 @@ static Linkage getLinkageForTemplateArgumentList(const TemplateArgument *Args,
break;
case TemplateArgument::Type:
- L = minLinkage(L, Args[I].getAsType()->getLinkage());
+ LV = merge(LV, Args[I].getAsType()->getLinkageAndVisibility());
break;
case TemplateArgument::Declaration:
- if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl()))
- L = minLinkage(L, ND->getLinkage());
- if (ValueDecl *VD = dyn_cast<ValueDecl>(Args[I].getAsDecl()))
- L = minLinkage(L, VD->getType()->getLinkage());
+ // The decl can validly be null as the representation of nullptr
+ // arguments, valid only in C++0x.
+ if (Decl *D = Args[I].getAsDecl()) {
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(D))
+ LV = merge(LV, getLVForDecl(ND, F));
+ }
break;
case TemplateArgument::Template:
- if (TemplateDecl *Template
- = Args[I].getAsTemplate().getAsTemplateDecl())
- L = minLinkage(L, Template->getLinkage());
+ case TemplateArgument::TemplateExpansion:
+ if (TemplateDecl *Template
+ = Args[I].getAsTemplateOrTemplatePattern().getAsTemplateDecl())
+ LV = merge(LV, getLVForDecl(Template, F));
break;
case TemplateArgument::Pack:
- L = minLinkage(L,
- getLinkageForTemplateArgumentList(Args[I].pack_begin(),
- Args[I].pack_size()));
+ LV = merge(LV, getLVForTemplateArgumentList(Args[I].pack_begin(),
+ Args[I].pack_size(),
+ F));
break;
}
}
- return L;
+ return LV;
}
-static Linkage
-getLinkageForTemplateArgumentList(const TemplateArgumentList &TArgs) {
- return getLinkageForTemplateArgumentList(TArgs.getFlatArgumentList(),
- TArgs.flat_size());
+static LVPair
+getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
+ LVFlags &F) {
+ return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), F);
}
-static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
+static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
"Not a name having namespace scope");
ASTContext &Context = D->getASTContext();
@@ -117,7 +226,7 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
// Explicitly declared static.
if (Var->getStorageClass() == SC_Static)
- return InternalLinkage;
+ return LinkageInfo::internal();
// - an object or reference that is explicitly declared const
// and neither explicitly declared extern nor previously
@@ -135,7 +244,7 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
FoundExtern = true;
if (!FoundExtern)
- return InternalLinkage;
+ return LinkageInfo::internal();
}
} else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
// C++ [temp]p4:
@@ -150,23 +259,88 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// Explicitly declared static.
if (Function->getStorageClass() == SC_Static)
- return InternalLinkage;
+ 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 InternalLinkage;
+ return LinkageInfo::internal();
+ }
+
+ if (D->isInAnonymousNamespace())
+ return LinkageInfo::uniqueExternal();
+
+ // Set up the defaults.
+
+ // C99 6.2.2p5:
+ // If the declaration of an identifier for an object has file
+ // scope and no storage-class specifier, its linkage is
+ // external.
+ LinkageInfo LV;
+
+ if (F.ConsiderVisibilityAttributes) {
+ if (const VisibilityAttr *VA = GetExplicitVisibility(D)) {
+ LV.setVisibility(GetVisibilityFromAttr(VA), true);
+ F.ConsiderGlobalVisibility = false;
+ } else {
+ // If we're declared in a namespace with a visibility attribute,
+ // use that namespace's visibility, but don't call it explicit.
+ for (const DeclContext *DC = D->getDeclContext();
+ !isa<TranslationUnitDecl>(DC);
+ DC = DC->getParent()) {
+ if (!isa<NamespaceDecl>(DC)) continue;
+ if (const VisibilityAttr *VA =
+ cast<NamespaceDecl>(DC)->getAttr<VisibilityAttr>()) {
+ LV.setVisibility(GetVisibilityFromAttr(VA), false);
+ F.ConsiderGlobalVisibility = false;
+ break;
+ }
+ }
+ }
}
// C++ [basic.link]p4:
-
+
// A name having namespace scope has external linkage if it is the
// name of
//
// - an object or reference, unless it has internal linkage; or
if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ // GCC applies the following optimization to variables and static
+ // data members, but not to functions:
+ //
+ // Modify the variable's LV by the LV of its type unless this is
+ // C or extern "C". This follows from [basic.link]p9:
+ // A type without linkage shall not be used as the type of a
+ // variable or function with external linkage unless
+ // - the entity has C language linkage, or
+ // - the entity is declared within an unnamed namespace, or
+ // - the entity is not used or is defined in the same
+ // translation unit.
+ // and [basic.link]p10:
+ // ...the types specified by all declarations referring to a
+ // given variable or function shall be identical...
+ // C does not have an equivalent rule.
+ //
+ // Ignore this if we've got an explicit attribute; the user
+ // probably knows what they're doing.
+ //
+ // Note that we don't want to make the variable non-external
+ // because of this, but unique-external linkage suits us.
+ if (Context.getLangOptions().CPlusPlus && !Var->isExternC()) {
+ LVPair TypeLV = Var->getType()->getLinkageAndVisibility();
+ if (TypeLV.first != ExternalLinkage)
+ return LinkageInfo::uniqueExternal();
+ if (!LV.visibilityExplicit())
+ LV.mergeVisibility(TypeLV.second);
+ }
+
+ if (Var->getStorageClass() == SC_PrivateExtern)
+ LV.setVisibility(HiddenVisibility, true);
+
if (!Context.getLangOptions().CPlusPlus &&
(Var->getStorageClass() == SC_Extern ||
Var->getStorageClass() == SC_PrivateExtern)) {
+
// C99 6.2.2p4:
// For an identifier declared with the storage-class specifier
// extern in a scope in which a prior declaration of that
@@ -177,23 +351,22 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage.
if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) {
- if (Linkage L = PrevVar->getLinkage())
- return L;
+ LinkageInfo PrevLV = getLVForDecl(PrevVar, F);
+ if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
+ LV.mergeVisibility(PrevLV);
}
}
- // C99 6.2.2p5:
- // If the declaration of an identifier for an object has file
- // scope and no storage-class specifier, its linkage is
- // external.
- if (Var->isInAnonymousNamespace())
- return UniqueExternalLinkage;
+ // - a function, unless it has internal linkage; or
+ } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ // In theory, we can modify the function's LV by the LV of its
+ // type unless it has C linkage (see comment above about variables
+ // for justification). In practice, GCC doesn't do this, so it's
+ // just too painful to make work.
- return ExternalLinkage;
- }
+ if (Function->getStorageClass() == SC_PrivateExtern)
+ LV.setVisibility(HiddenVisibility, true);
- // - a function, unless it has internal linkage; or
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
// C99 6.2.2p5:
// If the declaration of an identifier for a function has no
// storage-class specifier, its linkage is determined exactly
@@ -213,141 +386,300 @@ static Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
// is visible, or if the prior declaration specifies no
// linkage, then the identifier has external linkage.
if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) {
- if (Linkage L = PrevFunc->getLinkage())
- return L;
+ LinkageInfo PrevLV = getLVForDecl(PrevFunc, F);
+ if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
+ LV.mergeVisibility(PrevLV);
}
}
- if (Function->isInAnonymousNamespace())
- return UniqueExternalLinkage;
+ // In C++, then if the type of the function uses a type with
+ // unique-external linkage, it's not legally usable from outside
+ // this translation unit. However, we should use the C linkage
+ // rules instead for extern "C" declarations.
+ if (Context.getLangOptions().CPlusPlus && !Function->isExternC() &&
+ Function->getType()->getLinkage() == UniqueExternalLinkage)
+ return LinkageInfo::uniqueExternal();
if (FunctionTemplateSpecializationInfo *SpecInfo
= Function->getTemplateSpecializationInfo()) {
- Linkage L = SpecInfo->getTemplate()->getLinkage();
+ LV.merge(getLVForDecl(SpecInfo->getTemplate(),
+ F.onlyTemplateVisibility()));
const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments;
- L = minLinkage(L, getLinkageForTemplateArgumentList(TemplateArgs));
- return L;
+ LV.merge(getLVForTemplateArgumentList(TemplateArgs, F));
}
- return ExternalLinkage;
- }
-
// - a named class (Clause 9), or an unnamed class defined in a
// typedef declaration in which the class has the typedef name
// for linkage purposes (7.1.3); or
// - a named enumeration (7.2), or an unnamed enumeration
// defined in a typedef declaration in which the enumeration
// has the typedef name for linkage purposes (7.1.3); or
- if (const TagDecl *Tag = dyn_cast<TagDecl>(D))
- if (Tag->getDeclName() || Tag->getTypedefForAnonDecl()) {
- if (Tag->isInAnonymousNamespace())
- return UniqueExternalLinkage;
-
- // If this is a class template specialization, consider the
- // linkage of the template and template arguments.
- if (const ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
- const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- Linkage L = getLinkageForTemplateArgumentList(TemplateArgs);
- return minLinkage(L, Spec->getSpecializedTemplate()->getLinkage());
- }
+ } else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) {
+ // Unnamed tags have no linkage.
+ if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl())
+ return LinkageInfo::none();
+
+ // If this is a class template specialization, consider the
+ // linkage of the template and template arguments.
+ if (const ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
+ // From the template.
+ LV.merge(getLVForDecl(Spec->getSpecializedTemplate(),
+ F.onlyTemplateVisibility()));
- return ExternalLinkage;
+ // The arguments at which the template was instantiated.
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ LV.merge(getLVForTemplateArgumentList(TemplateArgs, F));
}
+ // Consider -fvisibility unless the type has C linkage.
+ if (F.ConsiderGlobalVisibility)
+ F.ConsiderGlobalVisibility =
+ (Context.getLangOptions().CPlusPlus &&
+ !Tag->getDeclContext()->isExternCContext());
+
// - an enumerator belonging to an enumeration with external linkage;
- if (isa<EnumConstantDecl>(D)) {
- Linkage L = cast<NamedDecl>(D->getDeclContext())->getLinkage();
- if (isExternalLinkage(L))
- return L;
- }
+ } else if (isa<EnumConstantDecl>(D)) {
+ LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), F);
+ if (!isExternalLinkage(EnumLV.linkage()))
+ return LinkageInfo::none();
+ LV.merge(EnumLV);
// - a template, unless it is a function template that has
// internal linkage (Clause 14);
- if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
- if (D->isInAnonymousNamespace())
- return UniqueExternalLinkage;
-
- return getLinkageForTemplateParameterList(
- Template->getTemplateParameters());
- }
+ } else if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) {
+ LV.merge(getLVForTemplateParameterList(Template->getTemplateParameters()));
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
- if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace())
- return ExternalLinkage;
+ } else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) {
+ return LV;
+
+ // By extension, we assign external linkage to Objective-C
+ // interfaces.
+ } else if (isa<ObjCInterfaceDecl>(D)) {
+ // fallout
- return NoLinkage;
+ // Everything not covered here has no linkage.
+ } else {
+ return LinkageInfo::none();
+ }
+
+ // If we ended up with non-external linkage, visibility should
+ // always be default.
+ if (LV.linkage() != ExternalLinkage)
+ return LinkageInfo(LV.linkage(), DefaultVisibility, false);
+
+ // If we didn't end up with hidden visibility, consider attributes
+ // and -fvisibility.
+ if (F.ConsiderGlobalVisibility)
+ LV.mergeVisibility(Context.getLangOptions().getVisibilityMode());
+
+ return LV;
}
-static Linkage getLinkageForClassMember(const NamedDecl *D) {
+static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
+ // Only certain class members have linkage. Note that fields don't
+ // really have linkage, but it's convenient to say they do for the
+ // purposes of calculating linkage of pointer-to-data-member
+ // template arguments.
if (!(isa<CXXMethodDecl>(D) ||
isa<VarDecl>(D) ||
+ isa<FieldDecl>(D) ||
(isa<TagDecl>(D) &&
(D->getDeclName() || cast<TagDecl>(D)->getTypedefForAnonDecl()))))
- return NoLinkage;
+ return LinkageInfo::none();
+
+ LinkageInfo LV;
- // Class members only have linkage if their class has external linkage.
- Linkage L = cast<RecordDecl>(D->getDeclContext())->getLinkage();
- if (!isExternalLinkage(L)) return NoLinkage;
+ // The flags we're going to use to compute the class's visibility.
+ LVFlags ClassF = F;
+
+ // If we have an explicit visibility attribute, merge that in.
+ if (F.ConsiderVisibilityAttributes) {
+ if (const VisibilityAttr *VA = GetExplicitVisibility(D)) {
+ LV.mergeVisibility(GetVisibilityFromAttr(VA), true);
+
+ // Ignore global visibility later, but not this attribute.
+ F.ConsiderGlobalVisibility = false;
+
+ // Ignore both global visibility and attributes when computing our
+ // parent's visibility.
+ ClassF = F.onlyTemplateVisibility();
+ }
+ }
+
+ // Class members only have linkage if their class has external
+ // linkage.
+ LV.merge(getLVForDecl(cast<RecordDecl>(D->getDeclContext()), ClassF));
+ if (!isExternalLinkage(LV.linkage()))
+ return LinkageInfo::none();
// If the class already has unique-external linkage, we can't improve.
- if (L == UniqueExternalLinkage) return UniqueExternalLinkage;
+ if (LV.linkage() == UniqueExternalLinkage)
+ return LinkageInfo::uniqueExternal();
- // If this is a method template specialization, use the linkage for
- // the template parameters and arguments.
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- if (FunctionTemplateSpecializationInfo *SpecInfo
+ // 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();
+
+ TemplateSpecializationKind TSK = TSK_Undeclared;
+
+ // If this is a method template specialization, use the linkage for
+ // the template parameters and arguments.
+ if (FunctionTemplateSpecializationInfo *Spec
= MD->getTemplateSpecializationInfo()) {
- Linkage ArgLinkage =
- getLinkageForTemplateArgumentList(*SpecInfo->TemplateArguments);
- Linkage ParamLinkage =
- getLinkageForTemplateParameterList(
- SpecInfo->getTemplate()->getTemplateParameters());
- return minLinkage(ArgLinkage, ParamLinkage);
+ LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments, F));
+ LV.merge(getLVForTemplateParameterList(
+ Spec->getTemplate()->getTemplateParameters()));
+
+ TSK = Spec->getTemplateSpecializationKind();
+ } else if (MemberSpecializationInfo *MSI =
+ MD->getMemberSpecializationInfo()) {
+ TSK = MSI->getTemplateSpecializationKind();
+ }
+
+ // If we're paying attention to global visibility, apply
+ // -finline-visibility-hidden if this is an inline method.
+ //
+ // Note that ConsiderGlobalVisibility doesn't yet have information
+ // about whether containing classes have visibility attributes,
+ // and that's intentional.
+ if (TSK != TSK_ExplicitInstantiationDeclaration &&
+ F.ConsiderGlobalVisibility &&
+ MD->getASTContext().getLangOptions().InlineVisibilityHidden) {
+ // InlineVisibilityHidden only applies to definitions, and
+ // isInlined() only gives meaningful answers on definitions
+ // anyway.
+ const FunctionDecl *Def = 0;
+ if (MD->hasBody(Def) && Def->isInlined())
+ LV.setVisibility(HiddenVisibility);
+ }
+
+ // Note that in contrast to basically every other situation, we
+ // *do* apply -fvisibility to method declarations.
+
+ } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ if (const ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+ // Merge template argument/parameter information for member
+ // class template specializations.
+ LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs(), F));
+ LV.merge(getLVForTemplateParameterList(
+ Spec->getSpecializedTemplate()->getTemplateParameters()));
}
- // Similarly for member class template specializations.
- } else if (const ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
- Linkage ArgLinkage =
- getLinkageForTemplateArgumentList(Spec->getTemplateArgs());
- Linkage ParamLinkage =
- getLinkageForTemplateParameterList(
- Spec->getSpecializedTemplate()->getTemplateParameters());
- return minLinkage(ArgLinkage, ParamLinkage);
+ // Static data members.
+ } 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.
+ LVPair TypeLV = VD->getType()->getLinkageAndVisibility();
+ if (TypeLV.first != ExternalLinkage)
+ LV.mergeLinkage(UniqueExternalLinkage);
+ if (!LV.visibilityExplicit())
+ LV.mergeVisibility(TypeLV.second);
}
- return ExternalLinkage;
+ F.ConsiderGlobalVisibility &= !LV.visibilityExplicit();
+
+ // Apply -fvisibility if desired.
+ if (F.ConsiderGlobalVisibility && LV.visibility() != HiddenVisibility) {
+ LV.mergeVisibility(D->getASTContext().getLangOptions().getVisibilityMode());
+ }
+
+ return LV;
+}
+
+static void clearLinkageForClass(const CXXRecordDecl *record) {
+ for (CXXRecordDecl::decl_iterator
+ i = record->decls_begin(), e = record->decls_end(); i != e; ++i) {
+ Decl *child = *i;
+ if (isa<NamedDecl>(child))
+ cast<NamedDecl>(child)->ClearLinkageCache();
+ }
+}
+
+void NamedDecl::ClearLinkageCache() {
+ // Note that we can't skip clearing the linkage of children just
+ // because the parent doesn't have cached linkage: we don't cache
+ // when computing linkage for parent contexts.
+
+ HasCachedLinkage = 0;
+
+ // If we're changing the linkage of a class, we need to reset the
+ // linkage of child declarations, too.
+ if (const CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(this))
+ clearLinkageForClass(record);
+
+ if (ClassTemplateDecl *temp =
+ dyn_cast<ClassTemplateDecl>(const_cast<NamedDecl*>(this))) {
+ // Clear linkage for the template pattern.
+ CXXRecordDecl *record = temp->getTemplatedDecl();
+ record->HasCachedLinkage = 0;
+ clearLinkageForClass(record);
+
+ // We need to clear linkage for specializations, too.
+ for (ClassTemplateDecl::spec_iterator
+ i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i)
+ i->ClearLinkageCache();
+ }
+
+ // Clear cached linkage for function template decls, too.
+ if (FunctionTemplateDecl *temp =
+ dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this)))
+ for (FunctionTemplateDecl::spec_iterator
+ i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i)
+ i->ClearLinkageCache();
+
}
Linkage NamedDecl::getLinkage() const {
+ if (HasCachedLinkage) {
+ assert(Linkage(CachedLinkage) ==
+ getLVForDecl(this, LVFlags::CreateOnlyDeclLinkage()).linkage());
+ return Linkage(CachedLinkage);
+ }
+
+ CachedLinkage = getLVForDecl(this,
+ LVFlags::CreateOnlyDeclLinkage()).linkage();
+ HasCachedLinkage = 1;
+ return Linkage(CachedLinkage);
+}
+LinkageInfo NamedDecl::getLinkageAndVisibility() const {
+ LinkageInfo LI = getLVForDecl(this, LVFlags());
+ assert(!HasCachedLinkage || Linkage(CachedLinkage) == LI.linkage());
+ HasCachedLinkage = 1;
+ CachedLinkage = LI.linkage();
+ return LI;
+}
+
+static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
// Objective-C: treat all Objective-C declarations as having external
// linkage.
- switch (getKind()) {
+ switch (D->getKind()) {
default:
break;
+ case Decl::TemplateTemplateParm: // count these as external
+ case Decl::NonTypeTemplateParm:
case Decl::ObjCAtDefsField:
case Decl::ObjCCategory:
case Decl::ObjCCategoryImpl:
- case Decl::ObjCClass:
case Decl::ObjCCompatibleAlias:
case Decl::ObjCForwardProtocol:
case Decl::ObjCImplementation:
- case Decl::ObjCInterface:
- case Decl::ObjCIvar:
case Decl::ObjCMethod:
case Decl::ObjCProperty:
case Decl::ObjCPropertyImpl:
case Decl::ObjCProtocol:
- return ExternalLinkage;
+ return LinkageInfo::external();
}
// Handle linkage for namespace-scope names.
- if (getDeclContext()->getRedeclContext()->isFileContext())
- if (Linkage L = getLinkageForNamespaceScopeDecl(this))
- return L;
+ if (D->getDeclContext()->getRedeclContext()->isFileContext())
+ return getLVForNamespaceScopeDecl(D, Flags);
// C++ [basic.link]p5:
// In addition, a member function, static data member, a named
@@ -356,8 +688,8 @@ Linkage NamedDecl::getLinkage() const {
// that the class or enumeration has the typedef name for linkage
// purposes (7.1.3), has external linkage if the name of the class
// has external linkage.
- if (getDeclContext()->isRecord())
- return getLinkageForClassMember(this);
+ if (D->getDeclContext()->isRecord())
+ return getLVForClassMember(D, Flags);
// C++ [basic.link]p6:
// The name of a function declared in block scope and the name of
@@ -370,36 +702,54 @@ Linkage NamedDecl::getLinkage() const {
// one such matching entity, the program is ill-formed. Otherwise,
// if no matching entity is found, the block scope entity receives
// external linkage.
- if (getLexicalDeclContext()->isFunctionOrMethod()) {
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
- if (Function->getPreviousDeclaration())
- if (Linkage L = Function->getPreviousDeclaration()->getLinkage())
- return L;
-
+ if (D->getLexicalDeclContext()->isFunctionOrMethod()) {
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
if (Function->isInAnonymousNamespace())
- return UniqueExternalLinkage;
+ return LinkageInfo::uniqueExternal();
- return ExternalLinkage;
+ LinkageInfo LV;
+ if (Flags.ConsiderVisibilityAttributes) {
+ if (const VisibilityAttr *VA = GetExplicitVisibility(Function))
+ LV.setVisibility(GetVisibilityFromAttr(VA));
+ }
+
+ if (const FunctionDecl *Prev = Function->getPreviousDeclaration()) {
+ LinkageInfo PrevLV = getLVForDecl(Prev, Flags);
+ if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
+ LV.mergeVisibility(PrevLV);
+ }
+
+ return LV;
}
- if (const VarDecl *Var = dyn_cast<VarDecl>(this))
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D))
if (Var->getStorageClass() == SC_Extern ||
Var->getStorageClass() == SC_PrivateExtern) {
- if (Var->getPreviousDeclaration())
- if (Linkage L = Var->getPreviousDeclaration()->getLinkage())
- return L;
-
if (Var->isInAnonymousNamespace())
- return UniqueExternalLinkage;
+ return LinkageInfo::uniqueExternal();
+
+ LinkageInfo LV;
+ if (Var->getStorageClass() == SC_PrivateExtern)
+ LV.setVisibility(HiddenVisibility);
+ else if (Flags.ConsiderVisibilityAttributes) {
+ if (const VisibilityAttr *VA = GetExplicitVisibility(Var))
+ LV.setVisibility(GetVisibilityFromAttr(VA));
+ }
+
+ if (const VarDecl *Prev = Var->getPreviousDeclaration()) {
+ LinkageInfo PrevLV = getLVForDecl(Prev, Flags);
+ if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
+ LV.mergeVisibility(PrevLV);
+ }
- return ExternalLinkage;
+ return LV;
}
}
// C++ [basic.link]p6:
// Names not covered by these rules have no linkage.
- return NoLinkage;
- }
+ return LinkageInfo::none();
+}
std::string NamedDecl::getQualifiedNameAsString() const {
return getQualifiedNameAsString(getASTContext().getLangOptions());
@@ -430,8 +780,8 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.getFlatArgumentList(),
- TemplateArgs.flat_size(),
+ TemplateArgs.data(),
+ TemplateArgs.size(),
P);
OS << Spec->getName() << TemplateArgsStr;
} else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(*I)) {
@@ -514,6 +864,10 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
return cast<UsingShadowDecl>(this)->getTargetDecl() ==
cast<UsingShadowDecl>(OldD)->getTargetDecl();
+ if (isa<UsingDecl>(this) && isa<UsingDecl>(OldD))
+ return cast<UsingDecl>(this)->getTargetNestedNameDecl() ==
+ cast<UsingDecl>(OldD)->getTargetNestedNameDecl();
+
// For non-function declarations, if the declarations are of the
// same kind then this must be a redeclaration, or semantic analysis
// would not have given us the new declaration.
@@ -545,7 +899,7 @@ bool NamedDecl::isCXXInstanceMember() const {
if (isa<UsingShadowDecl>(D))
D = cast<UsingShadowDecl>(D)->getTargetDecl();
- if (isa<FieldDecl>(D))
+ if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D))
return true;
if (isa<CXXMethodDecl>(D))
return cast<CXXMethodDecl>(D)->isInstance();
@@ -655,6 +1009,14 @@ VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten);
}
+void VarDecl::setStorageClass(StorageClass SC) {
+ assert(isLegalForVariable(SC));
+ if (getStorageClass() != SC)
+ ClearLinkageCache();
+
+ SClass = SC;
+}
+
SourceLocation VarDecl::getInnerLocStart() const {
SourceLocation Start = getTypeSpecStartLoc();
if (Start.isInvalid())
@@ -785,6 +1147,17 @@ VarDecl *VarDecl::getDefinition() {
return 0;
}
+VarDecl::DefinitionKind VarDecl::hasDefinition() const {
+ DefinitionKind Kind = DeclarationOnly;
+
+ const VarDecl *First = getFirstDeclaration();
+ for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end();
+ I != E; ++I)
+ Kind = std::max(Kind, (*I)->isThisDeclarationADefinition());
+
+ return Kind;
+}
+
const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const {
redecl_iterator I = redecls_begin(), E = redecls_end();
while (I != E && !I->getInit())
@@ -883,15 +1256,14 @@ Expr *ParmVarDecl::getDefaultArg() {
"Default argument is not yet instantiated!");
Expr *Arg = getInit();
- if (CXXExprWithTemporaries *E = dyn_cast_or_null<CXXExprWithTemporaries>(Arg))
+ if (ExprWithCleanups *E = dyn_cast_or_null<ExprWithCleanups>(Arg))
return E->getSubExpr();
return Arg;
}
unsigned ParmVarDecl::getNumDefaultArgTemporaries() const {
- if (const CXXExprWithTemporaries *E =
- dyn_cast<CXXExprWithTemporaries>(getInit()))
+ if (const ExprWithCleanups *E = dyn_cast<ExprWithCleanups>(getInit()))
return E->getNumTemporaries();
return 0;
@@ -901,7 +1273,7 @@ CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) {
assert(getNumDefaultArgTemporaries() &&
"Default arguments does not have any temporaries!");
- CXXExprWithTemporaries *E = cast<CXXExprWithTemporaries>(getInit());
+ ExprWithCleanups *E = cast<ExprWithCleanups>(getInit());
return E->getTemporary(i);
}
@@ -915,6 +1287,10 @@ SourceRange ParmVarDecl::getDefaultArgRange() const {
return SourceRange();
}
+bool ParmVarDecl::isParameterPack() const {
+ return isa<PackExpansionType>(getType());
+}
+
//===----------------------------------------------------------------------===//
// FunctionDecl Implementation
//===----------------------------------------------------------------------===//
@@ -926,8 +1302,8 @@ void FunctionDecl::getNameForDiagnostic(std::string &S,
const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs();
if (TemplateArgs)
S += TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs->getFlatArgumentList(),
- TemplateArgs->flat_size(),
+ TemplateArgs->data(),
+ TemplateArgs->size(),
Policy);
}
@@ -966,6 +1342,13 @@ void FunctionDecl::setBody(Stmt *B) {
EndRangeLoc = B->getLocEnd();
}
+void FunctionDecl::setPure(bool P) {
+ IsPure = P;
+ if (P)
+ if (CXXRecordDecl *Parent = dyn_cast<CXXRecordDecl>(getDeclContext()))
+ Parent->markedVirtualFunctionPure();
+}
+
bool FunctionDecl::isMain() const {
ASTContext &Context = getASTContext();
return !Context.getLangOptions().Freestanding &&
@@ -994,7 +1377,7 @@ bool FunctionDecl::isExternC() const {
break;
}
- return false;
+ return isMain();
}
bool FunctionDecl::isGlobal() const {
@@ -1027,6 +1410,9 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
FunTmpl->setPreviousDeclaration(PrevFunTmpl);
}
+
+ if (PrevDecl->IsInline)
+ IsInline = true;
}
const FunctionDecl *FunctionDecl::getCanonicalDecl() const {
@@ -1037,6 +1423,14 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() {
return getFirstDeclaration();
}
+void FunctionDecl::setStorageClass(StorageClass SC) {
+ assert(isLegalForFunction(SC));
+ if (getStorageClass() != SC)
+ ClearLinkageCache();
+
+ SClass = SC;
+}
+
/// \brief Returns a value indicating whether this function
/// corresponds to a builtin function.
///
@@ -1083,7 +1477,7 @@ unsigned FunctionDecl::getBuiltinID() const {
/// getNumParams - Return the number of parameters this function must have
-/// based on its FunctionType. This is the length of the PararmInfo array
+/// based on its FunctionType. This is the length of the ParamInfo array
/// after it has been created.
unsigned FunctionDecl::getNumParams() const {
const FunctionType *FT = getType()->getAs<FunctionType>();
@@ -1093,13 +1487,14 @@ unsigned FunctionDecl::getNumParams() const {
}
-void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) {
+void FunctionDecl::setParams(ASTContext &C,
+ ParmVarDecl **NewParamInfo, unsigned NumParams) {
assert(ParamInfo == 0 && "Already has param info!");
assert(NumParams == getNumParams() && "Parameter count mismatch!");
// Zero params -> null pointer.
if (NumParams) {
- void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams);
+ void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams);
ParamInfo = new (Mem) ParmVarDecl*[NumParams];
memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams);
@@ -1113,25 +1508,40 @@ void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) {
/// getMinRequiredArguments - Returns the minimum number of arguments
/// needed to call this function. This may be fewer than the number of
/// function parameters, if some of the parameters have default
-/// arguments (in C++).
+/// arguments (in C++) or the last parameter is a parameter pack.
unsigned FunctionDecl::getMinRequiredArguments() const {
- unsigned NumRequiredArgs = getNumParams();
- while (NumRequiredArgs > 0
- && getParamDecl(NumRequiredArgs-1)->hasDefaultArg())
+ if (!getASTContext().getLangOptions().CPlusPlus)
+ return getNumParams();
+
+ unsigned NumRequiredArgs = getNumParams();
+
+ // If the last parameter is a parameter pack, we don't need an argument for
+ // it.
+ if (NumRequiredArgs > 0 &&
+ getParamDecl(NumRequiredArgs - 1)->isParameterPack())
+ --NumRequiredArgs;
+
+ // If this parameter has a default argument, we don't need an argument for
+ // it.
+ while (NumRequiredArgs > 0 &&
+ getParamDecl(NumRequiredArgs-1)->hasDefaultArg())
--NumRequiredArgs;
+ // We might have parameter packs before the end. These can't be deduced,
+ // but they can still handle multiple arguments.
+ unsigned ArgIdx = NumRequiredArgs;
+ while (ArgIdx > 0) {
+ if (getParamDecl(ArgIdx - 1)->isParameterPack())
+ NumRequiredArgs = ArgIdx;
+
+ --ArgIdx;
+ }
+
return NumRequiredArgs;
}
bool FunctionDecl::isInlined() const {
- // FIXME: This is not enough. Consider:
- //
- // inline void f();
- // void f() { }
- //
- // f is inlined, but does not have inline specified.
- // To fix this we should add an 'inline' flag to FunctionDecl.
- if (isInlineSpecified())
+ if (IsInline)
return true;
if (isa<CXXMethodDecl>(this)) {
@@ -1185,20 +1595,22 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
ASTContext &Context = getASTContext();
if (!Context.getLangOptions().C99 || hasAttr<GNUInlineAttr>()) {
- // GNU inline semantics. Based on a number of examples, we came up with the
- // following heuristic: if the "inline" keyword is present on a
- // declaration of the function but "extern" is not present on that
- // declaration, then the symbol is externally visible. Otherwise, the GNU
- // "extern inline" semantics applies and the symbol is not externally
- // visible.
+ // If it's not the case that both 'inline' and 'extern' are
+ // specified on the definition, then this inline definition is
+ // externally visible.
+ if (!(isInlineSpecified() && getStorageClassAsWritten() == SC_Extern))
+ return true;
+
+ // If any declaration is 'inline' but not 'extern', then this definition
+ // is externally visible.
for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end();
Redecl != RedeclEnd;
++Redecl) {
- if (Redecl->isInlineSpecified() && Redecl->getStorageClass() != SC_Extern)
+ if (Redecl->isInlineSpecified() &&
+ Redecl->getStorageClassAsWritten() != SC_Extern)
return true;
- }
+ }
- // GNU "extern inline" semantics; no externally visible symbol.
return false;
}
@@ -1271,12 +1683,13 @@ MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
}
void
-FunctionDecl::setInstantiationOfMemberFunction(FunctionDecl *FD,
+FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C,
+ FunctionDecl *FD,
TemplateSpecializationKind TSK) {
assert(TemplateOrSpecialization.isNull() &&
"Member function is already a specialization");
MemberSpecializationInfo *Info
- = new (getASTContext()) MemberSpecializationInfo(FD, TSK);
+ = new (C) MemberSpecializationInfo(FD, TSK);
TemplateOrSpecialization = Info;
}
@@ -1362,7 +1775,8 @@ FunctionDecl::getTemplateSpecializationArgsAsWritten() const {
}
void
-FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
+FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C,
+ FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
void *InsertPos,
TemplateSpecializationKind TSK,
@@ -1373,14 +1787,10 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
if (!Info)
- Info = new (getASTContext()) FunctionTemplateSpecializationInfo;
-
- Info->Function = this;
- Info->Template.setPointer(Template);
- Info->Template.setInt(TSK - 1);
- Info->TemplateArguments = TemplateArgs;
- Info->TemplateArgumentsAsWritten = TemplateArgsAsWritten;
- Info->PointOfInstantiation = PointOfInstantiation;
+ Info = FunctionTemplateSpecializationInfo::Create(C, this, Template, TSK,
+ TemplateArgs,
+ TemplateArgsAsWritten,
+ PointOfInstantiation);
TemplateOrSpecialization = Info;
// Insert this function template specialization into the set of known
@@ -1401,28 +1811,6 @@ FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
}
void
-FunctionDecl::setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
- unsigned NumTemplateArgs,
- const TemplateArgument *TemplateArgs,
- TemplateSpecializationKind TSK,
- unsigned NumTemplateArgsAsWritten,
- TemplateArgumentLoc *TemplateArgsAsWritten,
- SourceLocation LAngleLoc,
- SourceLocation RAngleLoc,
- SourceLocation PointOfInstantiation) {
- ASTContext &Ctx = getASTContext();
- TemplateArgumentList *TemplArgs
- = new (Ctx) TemplateArgumentList(Ctx, TemplateArgs, NumTemplateArgs);
- TemplateArgumentListInfo *TemplArgsInfo
- = new (Ctx) TemplateArgumentListInfo(LAngleLoc, RAngleLoc);
- for (unsigned i=0; i != NumTemplateArgsAsWritten; ++i)
- TemplArgsInfo->addArgument(TemplateArgsAsWritten[i]);
-
- setFunctionTemplateSpecialization(Template, TemplArgs, /*InsertPos=*/0, TSK,
- TemplArgsInfo, PointOfInstantiation);
-}
-
-void
FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context,
const UnresolvedSetImpl &Templates,
const TemplateArgumentListInfo &TemplateArgs) {
@@ -1533,8 +1921,8 @@ bool FunctionDecl::isOutOfLine() const {
// FieldDecl Implementation
//===----------------------------------------------------------------------===//
-FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
- IdentifierInfo *Id, QualType T,
+FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, Expr *BW, bool Mutable) {
return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable);
}
@@ -1549,6 +1937,25 @@ bool FieldDecl::isAnonymousStructOrUnion() const {
return false;
}
+unsigned FieldDecl::getFieldIndex() const {
+ if (CachedFieldIndex) return CachedFieldIndex - 1;
+
+ unsigned index = 0;
+ RecordDecl::field_iterator
+ i = getParent()->field_begin(), e = getParent()->field_end();
+ while (true) {
+ assert(i != e && "failed to find field in parent!");
+ if (*i == this)
+ break;
+
+ ++i;
+ ++index;
+ }
+
+ CachedFieldIndex = index + 1;
+ return index;
+}
+
//===----------------------------------------------------------------------===//
// TagDecl Implementation
//===----------------------------------------------------------------------===//
@@ -1569,7 +1976,8 @@ TagDecl* TagDecl::getCanonicalDecl() {
void TagDecl::setTypedefForAnonDecl(TypedefDecl *TDD) {
TypedefDeclOrQualifier = TDD;
if (TypeForDecl)
- TypeForDecl->ClearLinkageCache();
+ const_cast<Type*>(TypeForDecl)->ClearLinkageCache();
+ ClearLinkageCache();
}
void TagDecl::startDefinition() {
@@ -1591,11 +1999,16 @@ void TagDecl::completeDefinition() {
IsDefinition = true;
IsBeingDefined = false;
+
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->CompletedTagDefinition(this);
}
TagDecl* TagDecl::getDefinition() const {
if (isDefinition())
return const_cast<TagDecl *>(this);
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this))
+ return CXXRD->getDefinition();
for (redecl_iterator R = redecls_begin(), REnd = redecls_end();
R != REnd; ++R)
@@ -1631,14 +2044,17 @@ void TagDecl::setQualifierInfo(NestedNameSpecifier *Qualifier,
EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
IdentifierInfo *Id, SourceLocation TKL,
- EnumDecl *PrevDecl) {
- EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL);
+ EnumDecl *PrevDecl, bool IsScoped,
+ bool IsScopedUsingClassTag, bool IsFixed) {
+ EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL,
+ IsScoped, IsScopedUsingClassTag, IsFixed);
C.getTypeDeclType(Enum, PrevDecl);
return Enum;
}
EnumDecl *EnumDecl::Create(ASTContext &C, EmptyShell Empty) {
- return new (C) EnumDecl(0, SourceLocation(), 0, 0, SourceLocation());
+ return new (C) EnumDecl(0, SourceLocation(), 0, 0, SourceLocation(),
+ false, false, false);
}
void EnumDecl::completeDefinition(QualType NewType,
@@ -1646,7 +2062,8 @@ void EnumDecl::completeDefinition(QualType NewType,
unsigned NumPositiveBits,
unsigned NumNegativeBits) {
assert(!isDefinition() && "Cannot redefine enums!");
- IntegerType = NewType;
+ if (!IntegerType)
+ IntegerType = NewType.getTypePtr();
PromotionType = NewPromotionType;
setNumPositiveBits(NumPositiveBits);
setNumNegativeBits(NumNegativeBits);
@@ -1664,10 +2081,11 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L,
HasFlexibleArrayMember = false;
AnonymousStructOrUnion = false;
HasObjectMember = false;
+ LoadedFieldsFromExternalStorage = false;
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
}
-RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
+RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
SourceLocation TKL, RecordDecl* PrevDecl) {
@@ -1676,7 +2094,7 @@ RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
return R;
}
-RecordDecl *RecordDecl::Create(ASTContext &C, EmptyShell Empty) {
+RecordDecl *RecordDecl::Create(const ASTContext &C, EmptyShell Empty) {
return new (C) RecordDecl(Record, TTK_Struct, 0, SourceLocation(), 0, 0,
SourceLocation());
}
@@ -1686,6 +2104,13 @@ bool RecordDecl::isInjectedClassName() const {
cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName();
}
+RecordDecl::field_iterator RecordDecl::field_begin() const {
+ if (hasExternalLexicalStorage() && !LoadedFieldsFromExternalStorage)
+ LoadFieldsFromExternalStorage();
+
+ return field_iterator(decl_iterator(FirstDecl));
+}
+
/// completeDefinition - Notes that the definition of this type is now
/// complete.
void RecordDecl::completeDefinition() {
@@ -1693,15 +2118,29 @@ void RecordDecl::completeDefinition() {
TagDecl::completeDefinition();
}
-ValueDecl *RecordDecl::getAnonymousStructOrUnionObject() {
- // Force the decl chain to come into existence properly.
- if (!getNextDeclInContext()) getParent()->decls_begin();
+void RecordDecl::LoadFieldsFromExternalStorage() const {
+ ExternalASTSource *Source = getASTContext().getExternalSource();
+ assert(hasExternalLexicalStorage() && Source && "No external storage?");
+
+ // Notify that we have a RecordDecl doing some initialization.
+ ExternalASTSource::Deserializing TheFields(Source);
- assert(isAnonymousStructOrUnion());
- ValueDecl *D = cast<ValueDecl>(getNextDeclInContext());
- assert(D->getType()->isRecordType());
- assert(D->getType()->getAs<RecordType>()->getDecl() == this);
- return D;
+ llvm::SmallVector<Decl*, 64> Decls;
+ if (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls))
+ return;
+
+#ifndef NDEBUG
+ // Check that all decls we got were FieldDecls.
+ for (unsigned i=0, e=Decls.size(); i != e; ++i)
+ assert(isa<FieldDecl>(Decls[i]));
+#endif
+
+ LoadedFieldsFromExternalStorage = true;
+
+ if (Decls.empty())
+ return;
+
+ llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls);
}
//===----------------------------------------------------------------------===//
@@ -1721,10 +2160,31 @@ void BlockDecl::setParams(ParmVarDecl **NewParamInfo,
}
}
-unsigned BlockDecl::getNumParams() const {
- return NumParams;
+void BlockDecl::setCaptures(ASTContext &Context,
+ const Capture *begin,
+ const Capture *end,
+ bool capturesCXXThis) {
+ CapturesCXXThis = capturesCXXThis;
+
+ if (begin == end) {
+ NumCaptures = 0;
+ Captures = 0;
+ return;
+ }
+
+ NumCaptures = end - begin;
+
+ // Avoid new Capture[] because we don't want to provide a default
+ // constructor.
+ size_t allocationSize = NumCaptures * sizeof(Capture);
+ void *buffer = Context.Allocate(allocationSize, /*alignment*/sizeof(void*));
+ memcpy(buffer, begin, allocationSize);
+ Captures = static_cast<Capture*>(buffer);
}
+SourceRange BlockDecl::getSourceRange() const {
+ return SourceRange(getLocation(), Body? Body->getLocEnd() : getLocation());
+}
//===----------------------------------------------------------------------===//
// Other Decl Allocation/Deallocation Method Implementations
@@ -1734,11 +2194,22 @@ TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) {
return new (C) TranslationUnitDecl(C);
}
+LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *II) {
+ return new (C) LabelDecl(DC, L, II, 0);
+}
+
+
NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id) {
return new (C) NamespaceDecl(DC, L, Id);
}
+NamespaceDecl *NamespaceDecl::getNextNamespace() {
+ return dyn_cast_or_null<NamespaceDecl>(
+ NextNamespace.get(getASTContext().getExternalSource()));
+}
+
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id, QualType T) {
return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T);
@@ -1748,9 +2219,10 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
StorageClass S, StorageClass SCAsWritten,
- bool isInline, bool hasWrittenPrototype) {
+ bool isInlineSpecified,
+ bool hasWrittenPrototype) {
FunctionDecl *New = new (C) FunctionDecl(Function, DC, NameInfo, T, TInfo,
- S, SCAsWritten, isInline);
+ S, SCAsWritten, isInlineSpecified);
New->HasWrittenPrototype = hasWrittenPrototype;
return New;
}
@@ -1766,6 +2238,13 @@ EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD,
return new (C) EnumConstantDecl(CD, L, Id, T, E, V);
}
+IndirectFieldDecl *
+IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, QualType T, NamedDecl **CH,
+ unsigned CHS) {
+ return new (C) IndirectFieldDecl(DC, L, Id, T, CH, CHS);
+}
+
SourceRange EnumConstantDecl::getSourceRange() const {
SourceLocation End = getLocation();
if (Init)
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 0b958fe..be379d5 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
+#include "clang/AST/ASTMutationListener.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -109,10 +110,22 @@ void Decl::add(Kind k) {
bool Decl::isTemplateParameterPack() const {
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this))
return TTP->isParameterPack();
-
+ if (const NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(this))
+ return NTTP->isParameterPack();
+ if (const TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(this))
+ return TTP->isParameterPack();
return false;
}
+bool Decl::isParameterPack() const {
+ if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(this))
+ return Parm->isParameterPack();
+
+ return isTemplateParameterPack();
+}
+
bool Decl::isFunctionOrFunctionTemplate() const {
if (const UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(this))
return UD->getTargetDecl()->isFunctionOrFunctionTemplate();
@@ -210,6 +223,10 @@ ASTContext &Decl::getASTContext() const {
return getTranslationUnitDecl()->getASTContext();
}
+ASTMutationListener *Decl::getASTMutationListener() const {
+ return getASTContext().getASTMutationListener();
+}
+
bool Decl::isUsed(bool CheckUsedAttr) const {
if (Used)
return true;
@@ -243,6 +260,10 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCMethod:
case ObjCProperty:
return IDNS_Ordinary;
+ case Label:
+ return IDNS_Label;
+ case IndirectField:
+ return IDNS_Ordinary | IDNS_Member;
case ObjCCompatibleAlias:
case ObjCInterface:
@@ -416,27 +437,34 @@ SourceLocation Decl::getBodyRBrace() const {
return SourceLocation();
}
-#ifndef NDEBUG
void Decl::CheckAccessDeclContext() const {
- // FIXME: Disable this until rdar://8146294 "access specifier for inner class
- // templates is not set or checked" is fixed.
- return;
+#ifndef NDEBUG
// Suppress this check if any of the following hold:
// 1. this is the translation unit (and thus has no parent)
// 2. this is a template parameter (and thus doesn't belong to its context)
- // 3. the context is not a record
- // 4. it's invalid
+ // 3. this is a non-type template parameter
+ // 4. the context is not a record
+ // 5. it's invalid
+ // 6. it's a C++0x static_assert.
if (isa<TranslationUnitDecl>(this) ||
isa<TemplateTypeParmDecl>(this) ||
+ isa<NonTypeTemplateParmDecl>(this) ||
!isa<CXXRecordDecl>(getDeclContext()) ||
- isInvalidDecl())
+ isInvalidDecl() ||
+ isa<StaticAssertDecl>(this) ||
+ // FIXME: a ParmVarDecl can have ClassTemplateSpecialization
+ // as DeclContext (?).
+ isa<ParmVarDecl>(this) ||
+ // FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have
+ // AS_none as access specifier.
+ isa<CXXRecordDecl>(this))
return;
assert(Access != AS_none &&
"Access specifier is AS_none inside a record decl");
+#endif
}
-#endif
//===----------------------------------------------------------------------===//
// DeclContext Implementation
@@ -509,15 +537,24 @@ bool DeclContext::isDependentContext() const {
bool DeclContext::isTransparentContext() const {
if (DeclKind == Decl::Enum)
- return true; // FIXME: Check for C++0x scoped enums
+ return !cast<EnumDecl>(this)->isScoped();
else if (DeclKind == Decl::LinkageSpec)
return true;
- else if (DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord)
- return cast<RecordDecl>(this)->isAnonymousStructOrUnion();
return false;
}
+bool DeclContext::isExternCContext() const {
+ const DeclContext *DC = this;
+ while (DC->DeclKind != Decl::TranslationUnit) {
+ if (DC->DeclKind == Decl::LinkageSpec)
+ return cast<LinkageSpecDecl>(DC)->getLanguage()
+ == LinkageSpecDecl::lang_c;
+ DC = DC->getParent();
+ }
+ return false;
+}
+
bool DeclContext::Encloses(const DeclContext *DC) const {
if (getPrimaryContext() != this)
return getPrimaryContext()->Encloses(DC);
@@ -592,6 +629,24 @@ DeclContext *DeclContext::getNextContext() {
}
}
+std::pair<Decl *, Decl *>
+DeclContext::BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls) {
+ // Build up a chain of declarations via the Decl::NextDeclInContext field.
+ Decl *FirstNewDecl = 0;
+ Decl *PrevDecl = 0;
+ for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+ Decl *D = Decls[I];
+ if (PrevDecl)
+ PrevDecl->NextDeclInContext = D;
+ else
+ FirstNewDecl = D;
+
+ PrevDecl = D;
+ }
+
+ return std::make_pair(FirstNewDecl, PrevDecl);
+}
+
/// \brief Load the declarations within this lexical storage from an
/// external source.
void
@@ -612,26 +667,22 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const {
if (Decls.empty())
return;
- // Resolve all of the declaration IDs into declarations, building up
- // a chain of declarations via the Decl::NextDeclInContext field.
- Decl *FirstNewDecl = 0;
- Decl *PrevDecl = 0;
- for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
- Decl *D = Decls[I];
- if (PrevDecl)
- PrevDecl->NextDeclInContext = D;
- else
- FirstNewDecl = D;
-
- PrevDecl = D;
- }
+ // We may have already loaded just the fields of this record, in which case
+ // don't add the decls, just replace the FirstDecl/LastDecl chain.
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(this))
+ if (RD->LoadedFieldsFromExternalStorage) {
+ llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls);
+ return;
+ }
// Splice the newly-read declarations into the beginning of the list
// of declarations.
- PrevDecl->NextDeclInContext = FirstDecl;
- FirstDecl = FirstNewDecl;
+ Decl *ExternalFirst, *ExternalLast;
+ llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls);
+ ExternalLast->NextDeclInContext = FirstDecl;
+ FirstDecl = ExternalFirst;
if (!LastDecl)
- LastDecl = PrevDecl;
+ LastDecl = ExternalLast;
}
DeclContext::lookup_result
@@ -771,6 +822,11 @@ void DeclContext::addHiddenDecl(Decl *D) {
} else {
FirstDecl = LastDecl = D;
}
+
+ // Notify a C++ record declaration that we've added a member, so it can
+ // update it's class-specific state.
+ if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this))
+ Record->addedMember(D);
}
void DeclContext::addDecl(Decl *D) {
@@ -911,6 +967,12 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) {
// parent context, too. This operation is recursive.
if (isTransparentContext() || isInlineNamespace())
getParent()->makeDeclVisibleInContext(D, Recoverable);
+
+ Decl *DCAsDecl = cast<Decl>(this);
+ // Notify that a decl was made visible unless it's a Tag being defined.
+ if (!(isa<TagDecl>(DCAsDecl) && cast<TagDecl>(DCAsDecl)->isBeingDefined()))
+ if (ASTMutationListener *L = DCAsDecl->getASTMutationListener())
+ L->AddedVisibleDecl(this, D);
}
void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index f2f0694..fba73f5 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -14,6 +14,8 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Expr.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/IdentifierTable.h"
@@ -34,8 +36,8 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
HasTrivialDestructor(true), ComputedVisibleConversions(false),
DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
DeclaredCopyAssignment(false), DeclaredDestructor(false),
- Bases(0), NumBases(0), VBases(0), NumVBases(0),
- Definition(D), FirstFriend(0) {
+ NumBases(0), NumVBases(0), Bases(), VBases(),
+ Definition(D), FirstFriend(0) {
}
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
@@ -46,9 +48,9 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0),
TemplateOrInstantiation() { }
-CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- SourceLocation TKL,
+CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
+ DeclContext *DC, SourceLocation L,
+ IdentifierInfo *Id, SourceLocation TKL,
CXXRecordDecl* PrevDecl,
bool DelayTypeCreation) {
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id,
@@ -60,7 +62,7 @@ CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
return R;
}
-CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, EmptyShell Empty) {
+CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, EmptyShell Empty) {
return new (C) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(), 0, 0,
SourceLocation());
}
@@ -75,8 +77,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// no base classes [...].
data().Aggregate = false;
- if (data().Bases)
- C.Deallocate(data().Bases);
+ if (!data().Bases.isOffset() && data().NumBases > 0)
+ C.Deallocate(data().getBases());
// The set of seen virtual base types.
llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes;
@@ -87,7 +89,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
data().Bases = new(C) CXXBaseSpecifier [NumBases];
data().NumBases = NumBases;
for (unsigned i = 0; i < NumBases; ++i) {
- data().Bases[i] = *Bases[i];
+ data().getBases()[i] = *Bases[i];
// Keep track of inherited vbases for this base class.
const CXXBaseSpecifier *Base = Bases[i];
QualType BaseType = Base->getType();
@@ -97,6 +99,25 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
+ // C++ [dcl.init.aggr]p1:
+ // An aggregate is [...] a class with [...] no base classes [...].
+ data().Aggregate = false;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class...
+ data().PlainOldData = false;
+
+ // A class with a non-empty base class is not empty.
+ // FIXME: Standard ref?
+ if (!BaseClassDecl->isEmpty())
+ data().Empty = false;
+
+ // C++ [class.virtual]p1:
+ // A class that declares or inherits a virtual function is called a
+ // polymorphic class.
+ if (BaseClassDecl->isPolymorphic())
+ data().Polymorphic = true;
+
// Now go through all virtual bases of this base and add them.
for (CXXRecordDecl::base_class_iterator VBase =
BaseClassDecl->vbases_begin(),
@@ -110,8 +131,50 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// Add this base if it's not already in the list.
if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
VBases.push_back(Base);
+
+ // C++0x [meta.unary.prop] is_empty:
+ // T is a class type, but not a union type, with ... no virtual base
+ // classes
+ data().Empty = false;
+
+ // C++ [class.ctor]p5:
+ // A constructor is trivial if its class has no virtual base classes.
+ data().HasTrivialConstructor = false;
+
+ // C++ [class.copy]p6:
+ // A copy constructor is trivial if its class has no virtual base
+ // classes.
+ data().HasTrivialCopyConstructor = false;
+
+ // C++ [class.copy]p11:
+ // A copy assignment operator is trivial if its class has no virtual
+ // base classes.
+ data().HasTrivialCopyAssignment = false;
+ } else {
+ // C++ [class.ctor]p5:
+ // A constructor is trivial if all the direct base classes of its
+ // class have trivial constructors.
+ if (!BaseClassDecl->hasTrivialConstructor())
+ data().HasTrivialConstructor = false;
+
+ // C++ [class.copy]p6:
+ // A copy constructor is trivial if all the direct base classes of its
+ // class have trivial copy constructors.
+ if (!BaseClassDecl->hasTrivialCopyConstructor())
+ data().HasTrivialCopyConstructor = false;
+
+ // C++ [class.copy]p11:
+ // A copy assignment operator is trivial if all the direct base classes
+ // of its class have trivial copy assignment operators.
+ if (!BaseClassDecl->hasTrivialCopyAssignment())
+ data().HasTrivialCopyAssignment = false;
}
-
+
+ // C++ [class.ctor]p3:
+ // A destructor is trivial if all the direct base classes of its class
+ // have trivial destructors.
+ if (!BaseClassDecl->hasTrivialDestructor())
+ data().HasTrivialDestructor = false;
}
if (VBases.empty())
@@ -130,10 +193,11 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>(
VBaseTypeInfo->getType()->getAs<RecordType>()->getDecl());
- data().VBases[I] =
+ data().getVBases()[I] =
CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true,
VBaseClassDecl->getTagKind() == TTK_Class,
- VBases[I]->getAccessSpecifier(), VBaseTypeInfo);
+ VBases[I]->getAccessSpecifier(), VBaseTypeInfo,
+ SourceLocation());
}
}
@@ -150,7 +214,7 @@ bool CXXRecordDecl::hasAnyDependentBases() const {
return !forallBases(SawBase, 0);
}
-bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
+bool CXXRecordDecl::hasConstCopyConstructor(const ASTContext &Context) const {
return getCopyConstructor(Context, Qualifiers::Const) != 0;
}
@@ -177,7 +241,7 @@ GetBestOverloadCandidateSimple(
return Cands[Best].first;
}
-CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(ASTContext &Context,
+CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(const ASTContext &Context,
unsigned TypeQuals) const{
QualType ClassType
= Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
@@ -258,84 +322,268 @@ CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
return GetBestOverloadCandidateSimple(Found);
}
-void
-CXXRecordDecl::addedConstructor(ASTContext &Context,
- CXXConstructorDecl *ConDecl) {
- assert(!ConDecl->isImplicit() && "addedConstructor - not for implicit decl");
- // Note that we have a user-declared constructor.
- data().UserDeclaredConstructor = true;
-
- // Note that we have no need of an implicitly-declared default constructor.
- data().DeclaredDefaultConstructor = true;
+void CXXRecordDecl::markedVirtualFunctionPure() {
+ // C++ [class.abstract]p2:
+ // A class is abstract if it has at least one pure virtual function.
+ data().Abstract = true;
+}
+
+void CXXRecordDecl::addedMember(Decl *D) {
+ // Ignore friends and invalid declarations.
+ if (D->getFriendObjectKind() || D->isInvalidDecl())
+ return;
- // C++ [dcl.init.aggr]p1:
- // An aggregate is an array or a class (clause 9) with no
- // user-declared constructors (12.1) [...].
- data().Aggregate = false;
+ FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D);
+ if (FunTmpl)
+ D = FunTmpl->getTemplatedDecl();
+
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ if (Method->isVirtual()) {
+ // C++ [dcl.init.aggr]p1:
+ // An aggregate is an array or a class with [...] no virtual functions.
+ data().Aggregate = false;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class...
+ data().PlainOldData = false;
+
+ // Virtual functions make the class non-empty.
+ // FIXME: Standard ref?
+ data().Empty = false;
+
+ // C++ [class.virtual]p1:
+ // A class that declares or inherits a virtual function is called a
+ // polymorphic class.
+ data().Polymorphic = true;
+
+ // None of the special member functions are trivial.
+ data().HasTrivialConstructor = false;
+ data().HasTrivialCopyConstructor = false;
+ data().HasTrivialCopyAssignment = false;
+ // FIXME: Destructor?
+ }
+ }
+
+ if (D->isImplicit()) {
+ // Notify that an implicit member was added after the definition
+ // was completed.
+ if (!isBeingDefined())
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXImplicitMember(data().Definition, D);
+
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ // If this is the implicit default constructor, note that we have now
+ // declared it.
+ if (Constructor->isDefaultConstructor())
+ data().DeclaredDefaultConstructor = true;
+ // If this is the implicit copy constructor, note that we have now
+ // declared it.
+ else if (Constructor->isCopyConstructor())
+ data().DeclaredCopyConstructor = true;
+ return;
+ }
- // C++ [class]p4:
- // A POD-struct is an aggregate class [...]
- data().PlainOldData = false;
+ if (isa<CXXDestructorDecl>(D)) {
+ data().DeclaredDestructor = true;
+ return;
+ }
+
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ // If this is the implicit copy constructor, note that we have now
+ // declared it.
+ // FIXME: Move constructors
+ if (Method->getOverloadedOperator() == OO_Equal)
+ data().DeclaredCopyAssignment = true;
+ return;
+ }
- // C++ [class.ctor]p5:
- // A constructor is trivial if it is an implicitly-declared default
- // constructor.
- // FIXME: C++0x: don't do this for "= default" default constructors.
- data().HasTrivialConstructor = false;
-
- // Note when we have a user-declared copy constructor, which will
- // suppress the implicit declaration of a copy constructor.
- if (ConDecl->isCopyConstructor()) {
- data().UserDeclaredCopyConstructor = true;
- data().DeclaredCopyConstructor = true;
+ // Any other implicit declarations are handled like normal declarations.
+ }
+
+ // Handle (user-declared) constructors.
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ // Note that we have a user-declared constructor.
+ data().UserDeclaredConstructor = true;
+
+ // Note that we have no need of an implicitly-declared default constructor.
+ data().DeclaredDefaultConstructor = true;
- // C++ [class.copy]p6:
- // A copy constructor is trivial if it is implicitly declared.
- // FIXME: C++0x: don't do this for "= default" copy constructors.
- data().HasTrivialCopyConstructor = false;
+ // C++ [dcl.init.aggr]p1:
+ // An aggregate is an array or a class (clause 9) with no
+ // user-declared constructors (12.1) [...].
+ data().Aggregate = false;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ data().PlainOldData = false;
+
+ // C++ [class.ctor]p5:
+ // A constructor is trivial if it is an implicitly-declared default
+ // constructor.
+ // FIXME: C++0x: don't do this for "= default" default constructors.
+ data().HasTrivialConstructor = false;
+
+ // Note when we have a user-declared copy constructor, which will
+ // suppress the implicit declaration of a copy constructor.
+ if (!FunTmpl && Constructor->isCopyConstructor()) {
+ data().UserDeclaredCopyConstructor = true;
+ data().DeclaredCopyConstructor = true;
+
+ // C++ [class.copy]p6:
+ // A copy constructor is trivial if it is implicitly declared.
+ // FIXME: C++0x: don't do this for "= default" copy constructors.
+ data().HasTrivialCopyConstructor = false;
+ }
+ return;
}
-}
-void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
- CXXMethodDecl *OpDecl) {
- // We're interested specifically in copy assignment operators.
- const FunctionProtoType *FnType = OpDecl->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Overloaded operator has no proto function type.");
- assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
-
- // Copy assignment operators must be non-templates.
- if (OpDecl->getPrimaryTemplate() || OpDecl->getDescribedFunctionTemplate())
+ // Handle (user-declared) destructors.
+ if (isa<CXXDestructorDecl>(D)) {
+ data().DeclaredDestructor = true;
+ data().UserDeclaredDestructor = true;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class that has [...] no user-defined
+ // destructor.
+ data().PlainOldData = false;
+
+ // C++ [class.dtor]p3:
+ // A destructor is trivial if it is an implicitly-declared destructor and
+ // [...].
+ //
+ // FIXME: C++0x: don't do this for "= default" destructors
+ data().HasTrivialDestructor = false;
+
return;
+ }
- QualType ArgType = FnType->getArgType(0);
- if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>())
- ArgType = Ref->getPointeeType();
-
- ArgType = ArgType.getUnqualifiedType();
- QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
- const_cast<CXXRecordDecl*>(this)));
+ // Handle (user-declared) member functions.
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+ if (Method->getOverloadedOperator() == OO_Equal) {
+ // We're interested specifically in copy assignment operators.
+ const FunctionProtoType *FnType
+ = Method->getType()->getAs<FunctionProtoType>();
+ assert(FnType && "Overloaded operator has no proto function type.");
+ assert(FnType->getNumArgs() == 1 && !FnType->isVariadic());
+
+ // Copy assignment operators must be non-templates.
+ if (Method->getPrimaryTemplate() || FunTmpl)
+ return;
+
+ ASTContext &Context = getASTContext();
+ QualType ArgType = FnType->getArgType(0);
+ if (const LValueReferenceType *Ref =ArgType->getAs<LValueReferenceType>())
+ ArgType = Ref->getPointeeType();
+
+ ArgType = ArgType.getUnqualifiedType();
+ QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
+ const_cast<CXXRecordDecl*>(this)));
+
+ if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
+ return;
+
+ // This is a copy assignment operator.
+ // FIXME: Move assignment operators.
+
+ // Suppress the implicit declaration of a copy constructor.
+ data().UserDeclaredCopyAssignment = true;
+ data().DeclaredCopyAssignment = true;
+
+ // C++ [class.copy]p11:
+ // A copy assignment operator is trivial if it is implicitly declared.
+ // FIXME: C++0x: don't do this for "= default" copy operators.
+ data().HasTrivialCopyAssignment = false;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class that [...] has no user-defined copy
+ // assignment operator [...].
+ data().PlainOldData = false;
+ }
+
+ // Keep the list of conversion functions up-to-date.
+ if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
+ // We don't record specializations.
+ if (Conversion->getPrimaryTemplate())
+ return;
+
+ // FIXME: We intentionally don't use the decl's access here because it
+ // hasn't been set yet. That's really just a misdesign in Sema.
- if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
+ if (FunTmpl) {
+ if (FunTmpl->getPreviousDeclaration())
+ data().Conversions.replace(FunTmpl->getPreviousDeclaration(),
+ FunTmpl);
+ else
+ data().Conversions.addDecl(FunTmpl);
+ } else {
+ if (Conversion->getPreviousDeclaration())
+ data().Conversions.replace(Conversion->getPreviousDeclaration(),
+ Conversion);
+ else
+ data().Conversions.addDecl(Conversion);
+ }
+ }
+
return;
-
- // This is a copy assignment operator.
- // Note on the decl that it is a copy assignment operator.
- OpDecl->setCopyAssignment(true);
-
- // Suppress the implicit declaration of a copy constructor.
- data().UserDeclaredCopyAssignment = true;
- data().DeclaredCopyAssignment = true;
+ }
- // C++ [class.copy]p11:
- // A copy assignment operator is trivial if it is implicitly declared.
- // FIXME: C++0x: don't do this for "= default" copy operators.
- data().HasTrivialCopyAssignment = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class that [...] has no user-defined copy
- // assignment operator [...].
- data().PlainOldData = false;
+ // Handle non-static data members.
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
+ // C++ [dcl.init.aggr]p1:
+ // An aggregate is an array or a class (clause 9) with [...] no
+ // private or protected non-static data members (clause 11).
+ //
+ // A POD must be an aggregate.
+ if (D->getAccess() == AS_private || D->getAccess() == AS_protected) {
+ data().Aggregate = false;
+ data().PlainOldData = false;
+ }
+
+ // C++ [class]p9:
+ // A POD struct is a class that is both a trivial class and a
+ // standard-layout class, and has no non-static data members of type
+ // non-POD struct, non-POD union (or array of such types).
+ ASTContext &Context = getASTContext();
+ QualType T = Context.getBaseElementType(Field->getType());
+ if (!T->isPODType())
+ data().PlainOldData = false;
+ if (T->isReferenceType())
+ data().HasTrivialConstructor = false;
+
+ if (const RecordType *RecordTy = T->getAs<RecordType>()) {
+ CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
+ if (FieldRec->getDefinition()) {
+ if (!FieldRec->hasTrivialConstructor())
+ data().HasTrivialConstructor = false;
+ if (!FieldRec->hasTrivialCopyConstructor())
+ data().HasTrivialCopyConstructor = false;
+ if (!FieldRec->hasTrivialCopyAssignment())
+ data().HasTrivialCopyAssignment = false;
+ if (!FieldRec->hasTrivialDestructor())
+ data().HasTrivialDestructor = false;
+ }
+ }
+
+ // If this is not a zero-length bit-field, then the class is not empty.
+ if (data().Empty) {
+ if (!Field->getBitWidth())
+ data().Empty = false;
+ else if (!Field->getBitWidth()->isTypeDependent() &&
+ !Field->getBitWidth()->isValueDependent()) {
+ llvm::APSInt Bits;
+ if (Field->getBitWidth()->isIntegerConstantExpr(Bits, Context))
+ if (!!Bits)
+ data().Empty = false;
+ }
+ }
+ }
+
+ // Handle using declarations of conversion functions.
+ if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D))
+ if (Shadow->getDeclName().getNameKind()
+ == DeclarationName::CXXConversionFunctionName)
+ data().Conversions.addDecl(Shadow, Shadow->getAccess());
}
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) {
@@ -479,20 +727,6 @@ const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
return &data().VisibleConversions;
}
-#ifndef NDEBUG
-void CXXRecordDecl::CheckConversionFunction(NamedDecl *ConvDecl) {
- assert(ConvDecl->getDeclContext() == this &&
- "conversion function does not belong to this record");
-
- ConvDecl = ConvDecl->getUnderlyingDecl();
- if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(ConvDecl)) {
- assert(isa<CXXConversionDecl>(Temp->getTemplatedDecl()));
- } else {
- assert(isa<CXXConversionDecl>(ConvDecl));
- }
-}
-#endif
-
void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
// This operation is O(N) but extremely rare. Sema only uses it to
// remove UsingShadowDecls in a class that were followed by a direct
@@ -518,17 +752,6 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
llvm_unreachable("conversion not found in set!");
}
-void CXXRecordDecl::setMethodAsVirtual(FunctionDecl *Method) {
- Method->setVirtualAsWritten(true);
- setAggregate(false);
- setPOD(false);
- setEmpty(false);
- setPolymorphic(true);
- setHasTrivialConstructor(false);
- setHasTrivialCopyConstructor(false);
- setHasTrivialCopyAssignment(false);
-}
-
CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo())
return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom());
@@ -577,28 +800,6 @@ CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) {
assert(false && "Not a class template or member class specialization");
}
-CXXConstructorDecl *
-CXXRecordDecl::getDefaultConstructor() {
- ASTContext &Context = getASTContext();
- QualType ClassType = Context.getTypeDeclType(this);
- DeclarationName ConstructorName
- = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(ClassType.getUnqualifiedType()));
-
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- // FIXME: In C++0x, a constructor template can be a default constructor.
- if (isa<FunctionTemplateDecl>(*Con))
- continue;
-
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
- if (Constructor->isDefaultConstructor())
- return Constructor;
- }
- return 0;
-}
-
CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
ASTContext &Context = getASTContext();
QualType ClassType = Context.getTypeDeclType(this);
@@ -618,6 +819,69 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
return Dtor;
}
+void CXXRecordDecl::completeDefinition() {
+ completeDefinition(0);
+}
+
+void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
+ RecordDecl::completeDefinition();
+
+ // If the class may be abstract (but hasn't been marked as such), check for
+ // any pure final overriders.
+ if (mayBeAbstract()) {
+ CXXFinalOverriderMap MyFinalOverriders;
+ if (!FinalOverriders) {
+ getFinalOverriders(MyFinalOverriders);
+ FinalOverriders = &MyFinalOverriders;
+ }
+
+ bool Done = false;
+ for (CXXFinalOverriderMap::iterator M = FinalOverriders->begin(),
+ MEnd = FinalOverriders->end();
+ M != MEnd && !Done; ++M) {
+ for (OverridingMethods::iterator SO = M->second.begin(),
+ SOEnd = M->second.end();
+ SO != SOEnd && !Done; ++SO) {
+ assert(SO->second.size() > 0 &&
+ "All virtual functions have overridding virtual functions");
+
+ // C++ [class.abstract]p4:
+ // A class is abstract if it contains or inherits at least one
+ // pure virtual function for which the final overrider is pure
+ // virtual.
+ if (SO->second.front().Method->isPure()) {
+ data().Abstract = true;
+ Done = true;
+ break;
+ }
+ }
+ }
+ }
+
+ // Set access bits correctly on the directly-declared conversions.
+ for (UnresolvedSetIterator I = data().Conversions.begin(),
+ E = data().Conversions.end();
+ I != E; ++I)
+ data().Conversions.setAccess(I, (*I)->getAccess());
+}
+
+bool CXXRecordDecl::mayBeAbstract() const {
+ if (data().Abstract || isInvalidDecl() || !data().Polymorphic ||
+ isDependentContext())
+ return false;
+
+ for (CXXRecordDecl::base_class_const_iterator B = bases_begin(),
+ BEnd = bases_end();
+ B != BEnd; ++B) {
+ CXXRecordDecl *BaseDecl
+ = cast<CXXRecordDecl>(B->getType()->getAs<RecordType>()->getDecl());
+ if (BaseDecl->isAbstract())
+ return true;
+ }
+
+ return false;
+}
+
CXXMethodDecl *
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
const DeclarationNameInfo &NameInfo,
@@ -735,85 +999,90 @@ bool CXXMethodDecl::hasInlineBody() const {
return CheckFn->hasBody(fn) && !fn->isOutOfLine();
}
-CXXBaseOrMemberInitializer::
-CXXBaseOrMemberInitializer(ASTContext &Context,
- TypeSourceInfo *TInfo, bool IsVirtual,
- SourceLocation L, Expr *Init, SourceLocation R)
- : BaseOrMember(TInfo), Init(Init), AnonUnionMember(0),
+CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
+ TypeSourceInfo *TInfo, bool IsVirtual,
+ SourceLocation L, Expr *Init,
+ SourceLocation R,
+ SourceLocation EllipsisLoc)
+ : Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init),
LParenLoc(L), RParenLoc(R), IsVirtual(IsVirtual), IsWritten(false),
SourceOrderOrNumArrayIndices(0)
{
}
-CXXBaseOrMemberInitializer::
-CXXBaseOrMemberInitializer(ASTContext &Context,
- FieldDecl *Member, SourceLocation MemberLoc,
- SourceLocation L, Expr *Init, SourceLocation R)
- : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
- AnonUnionMember(0), LParenLoc(L), RParenLoc(R), IsVirtual(false),
+CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
+ FieldDecl *Member,
+ SourceLocation MemberLoc,
+ SourceLocation L, Expr *Init,
+ SourceLocation R)
+ : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
+ LParenLoc(L), RParenLoc(R), IsVirtual(false),
+ IsWritten(false), SourceOrderOrNumArrayIndices(0)
+{
+}
+
+CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
+ IndirectFieldDecl *Member,
+ SourceLocation MemberLoc,
+ SourceLocation L, Expr *Init,
+ SourceLocation R)
+ : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
+ LParenLoc(L), RParenLoc(R), IsVirtual(false),
IsWritten(false), SourceOrderOrNumArrayIndices(0)
{
}
-CXXBaseOrMemberInitializer::
-CXXBaseOrMemberInitializer(ASTContext &Context,
- FieldDecl *Member, SourceLocation MemberLoc,
- SourceLocation L, Expr *Init, SourceLocation R,
- VarDecl **Indices,
- unsigned NumIndices)
- : BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
- AnonUnionMember(0), LParenLoc(L), RParenLoc(R), IsVirtual(false),
+CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context,
+ FieldDecl *Member,
+ SourceLocation MemberLoc,
+ SourceLocation L, Expr *Init,
+ SourceLocation R,
+ VarDecl **Indices,
+ unsigned NumIndices)
+ : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
+ LParenLoc(L), RParenLoc(R), IsVirtual(false),
IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices)
{
VarDecl **MyIndices = reinterpret_cast<VarDecl **> (this + 1);
memcpy(MyIndices, Indices, NumIndices * sizeof(VarDecl *));
}
-CXXBaseOrMemberInitializer *
-CXXBaseOrMemberInitializer::Create(ASTContext &Context,
- FieldDecl *Member,
- SourceLocation MemberLoc,
- SourceLocation L,
- Expr *Init,
- SourceLocation R,
- VarDecl **Indices,
- unsigned NumIndices) {
- void *Mem = Context.Allocate(sizeof(CXXBaseOrMemberInitializer) +
+CXXCtorInitializer *CXXCtorInitializer::Create(ASTContext &Context,
+ FieldDecl *Member,
+ SourceLocation MemberLoc,
+ SourceLocation L, Expr *Init,
+ SourceLocation R,
+ VarDecl **Indices,
+ unsigned NumIndices) {
+ void *Mem = Context.Allocate(sizeof(CXXCtorInitializer) +
sizeof(VarDecl *) * NumIndices,
- llvm::alignof<CXXBaseOrMemberInitializer>());
- return new (Mem) CXXBaseOrMemberInitializer(Context, Member, MemberLoc,
- L, Init, R, Indices, NumIndices);
+ llvm::alignOf<CXXCtorInitializer>());
+ return new (Mem) CXXCtorInitializer(Context, Member, MemberLoc, L, Init, R,
+ Indices, NumIndices);
}
-TypeLoc CXXBaseOrMemberInitializer::getBaseClassLoc() const {
+TypeLoc CXXCtorInitializer::getBaseClassLoc() const {
if (isBaseInitializer())
- return BaseOrMember.get<TypeSourceInfo*>()->getTypeLoc();
+ return Initializee.get<TypeSourceInfo*>()->getTypeLoc();
else
return TypeLoc();
}
-Type *CXXBaseOrMemberInitializer::getBaseClass() {
- if (isBaseInitializer())
- return BaseOrMember.get<TypeSourceInfo*>()->getType().getTypePtr();
- else
- return 0;
-}
-
-const Type *CXXBaseOrMemberInitializer::getBaseClass() const {
+const Type *CXXCtorInitializer::getBaseClass() const {
if (isBaseInitializer())
- return BaseOrMember.get<TypeSourceInfo*>()->getType().getTypePtr();
+ return Initializee.get<TypeSourceInfo*>()->getType().getTypePtr();
else
return 0;
}
-SourceLocation CXXBaseOrMemberInitializer::getSourceLocation() const {
- if (isMemberInitializer())
+SourceLocation CXXCtorInitializer::getSourceLocation() const {
+ if (isAnyMemberInitializer())
return getMemberLocation();
return getBaseClassLoc().getLocalSourceRange().getBegin();
}
-SourceRange CXXBaseOrMemberInitializer::getSourceRange() const {
+SourceRange CXXCtorInitializer::getSourceRange() const {
return SourceRange(getSourceLocation(), getRParenLoc());
}
@@ -847,25 +1116,40 @@ bool CXXConstructorDecl::isDefaultConstructor() const {
bool
CXXConstructorDecl::isCopyConstructor(unsigned &TypeQuals) const {
+ return isCopyOrMoveConstructor(TypeQuals) &&
+ getParamDecl(0)->getType()->isLValueReferenceType();
+}
+
+bool CXXConstructorDecl::isMoveConstructor(unsigned &TypeQuals) const {
+ return isCopyOrMoveConstructor(TypeQuals) &&
+ getParamDecl(0)->getType()->isRValueReferenceType();
+}
+
+/// \brief Determine whether this is a copy or move constructor.
+bool CXXConstructorDecl::isCopyOrMoveConstructor(unsigned &TypeQuals) const {
// C++ [class.copy]p2:
// A non-template constructor for class X is a copy constructor
// if its first parameter is of type X&, const X&, volatile X& or
// const volatile X&, and either there are no other parameters
// or else all other parameters have default arguments (8.3.6).
+ // C++0x [class.copy]p3:
+ // A non-template constructor for class X is a move constructor if its
+ // first parameter is of type X&&, const X&&, volatile X&&, or
+ // const volatile X&&, and either there are no other parameters or else
+ // all other parameters have default arguments.
if ((getNumParams() < 1) ||
(getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
(getPrimaryTemplate() != 0) ||
(getDescribedFunctionTemplate() != 0))
return false;
-
+
const ParmVarDecl *Param = getParamDecl(0);
-
- // Do we have a reference type? Rvalue references don't count.
- const LValueReferenceType *ParamRefType =
- Param->getType()->getAs<LValueReferenceType>();
+
+ // Do we have a reference type?
+ const ReferenceType *ParamRefType = Param->getType()->getAs<ReferenceType>();
if (!ParamRefType)
return false;
-
+
// Is it a reference to our class type?
ASTContext &Context = getASTContext();
@@ -875,12 +1159,12 @@ CXXConstructorDecl::isCopyConstructor(unsigned &TypeQuals) const {
= Context.getCanonicalType(Context.getTagDeclType(getParent()));
if (PointeeType.getUnqualifiedType() != ClassTy)
return false;
-
+
// FIXME: other qualifiers?
-
- // We have a copy constructor.
+
+ // We have a copy or move constructor.
TypeQuals = PointeeType.getCVRQualifiers();
- return true;
+ return true;
}
bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const {
@@ -899,7 +1183,7 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const {
(getNumParams() > 1 && getParamDecl(1)->hasDefaultArg());
}
-bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const {
+bool CXXConstructorDecl::isSpecializationCopyingObject() const {
if ((getNumParams() < 1) ||
(getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
(getPrimaryTemplate() == 0) ||
@@ -911,12 +1195,6 @@ bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const {
ASTContext &Context = getASTContext();
CanQualType ParamType = Context.getCanonicalType(Param->getType());
- // Strip off the lvalue reference, if any.
- if (CanQual<LValueReferenceType> ParamRefType
- = ParamType->getAs<LValueReferenceType>())
- ParamType = ParamRefType->getPointeeType();
-
-
// Is it the same as our our class type?
CanQualType ClassTy
= Context.getCanonicalType(Context.getTagDeclType(getParent()));
@@ -926,21 +1204,38 @@ bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const {
return true;
}
+const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const {
+ // Hack: we store the inherited constructor in the overridden method table
+ method_iterator It = begin_overridden_methods();
+ if (It == end_overridden_methods())
+ return 0;
+
+ return cast<CXXConstructorDecl>(*It);
+}
+
+void
+CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){
+ // Hack: we store the inherited constructor in the overridden method table
+ assert(size_overridden_methods() == 0 && "Base ctor already set.");
+ addOverriddenMethod(BaseCtor);
+}
+
CXXDestructorDecl *
CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) {
return new (C) CXXDestructorDecl(0, DeclarationNameInfo(),
- QualType(), false, false);
+ QualType(), 0, false, false);
}
CXXDestructorDecl *
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
const DeclarationNameInfo &NameInfo,
- QualType T, bool isInline,
+ QualType T, TypeSourceInfo *TInfo,
+ bool isInline,
bool isImplicitlyDeclared) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXDestructorName &&
"Name must refer to a destructor");
- return new (C) CXXDestructorDecl(RD, NameInfo, T, isInline,
+ return new (C) CXXDestructorDecl(RD, NameInfo, T, TInfo, isInline,
isImplicitlyDeclared);
}
@@ -1004,6 +1299,44 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
Qualifier, IdentLoc, Namespace);
}
+UsingDecl *UsingShadowDecl::getUsingDecl() const {
+ const UsingShadowDecl *Shadow = this;
+ while (const UsingShadowDecl *NextShadow =
+ dyn_cast<UsingShadowDecl>(Shadow->UsingOrNextShadow))
+ Shadow = NextShadow;
+ return cast<UsingDecl>(Shadow->UsingOrNextShadow);
+}
+
+void UsingDecl::addShadowDecl(UsingShadowDecl *S) {
+ assert(std::find(shadow_begin(), shadow_end(), S) == shadow_end() &&
+ "declaration already in set");
+ assert(S->getUsingDecl() == this);
+
+ if (FirstUsingShadow)
+ S->UsingOrNextShadow = FirstUsingShadow;
+ FirstUsingShadow = S;
+}
+
+void UsingDecl::removeShadowDecl(UsingShadowDecl *S) {
+ assert(std::find(shadow_begin(), shadow_end(), S) != shadow_end() &&
+ "declaration not in set");
+ assert(S->getUsingDecl() == this);
+
+ // Remove S from the shadow decl chain. This is O(n) but hopefully rare.
+
+ if (FirstUsingShadow == S) {
+ FirstUsingShadow = dyn_cast<UsingShadowDecl>(S->UsingOrNextShadow);
+ S->UsingOrNextShadow = this;
+ return;
+ }
+
+ UsingShadowDecl *Prev = FirstUsingShadow;
+ while (Prev->UsingOrNextShadow != S)
+ Prev = cast<UsingShadowDecl>(Prev->UsingOrNextShadow);
+ Prev->UsingOrNextShadow = S->UsingOrNextShadow;
+ S->UsingOrNextShadow = this;
+}
+
UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC,
SourceRange NNR, SourceLocation UL,
NestedNameSpecifier* TargetNNS,
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index d952cc3..45f5188 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -153,6 +153,9 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
ObjCPropertyDecl *
ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
IdentifierInfo *PropertyId) const {
+ if (ExternallyCompleted)
+ LoadExternalDefinition();
+
if (ObjCPropertyDecl *PD =
ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
return PD;
@@ -171,6 +174,9 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
ASTContext &C)
{
+ if (ExternallyCompleted)
+ LoadExternalDefinition();
+
if (AllReferencedProtocols.empty() && ReferencedProtocols.empty()) {
AllReferencedProtocols.set(ExtList, ExtNum, C);
return;
@@ -270,6 +276,9 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
const ObjCInterfaceDecl* ClassDecl = this;
ObjCMethodDecl *MethodDecl = 0;
+ if (ExternallyCompleted)
+ LoadExternalDefinition();
+
while (ClassDecl != NULL) {
if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance)))
return MethodDecl;
@@ -302,14 +311,16 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
return NULL;
}
-ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateInstanceMethod(
- const Selector &Sel) {
+ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod(
+ const Selector &Sel,
+ bool Instance) {
ObjCMethodDecl *Method = 0;
if (ObjCImplementationDecl *ImpDecl = getImplementation())
- Method = ImpDecl->getInstanceMethod(Sel);
+ Method = Instance ? ImpDecl->getInstanceMethod(Sel)
+ : ImpDecl->getClassMethod(Sel);
if (!Method && getSuperClass())
- return getSuperClass()->lookupPrivateInstanceMethod(Sel);
+ return getSuperClass()->lookupPrivateMethod(Sel, Instance);
return Method;
}
@@ -443,11 +454,29 @@ ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id,
: ObjCContainerDecl(ObjCInterface, DC, atLoc, Id),
TypeForDecl(0), SuperClass(0),
CategoryList(0), IvarList(0),
- ForwardDecl(FD), InternalInterface(isInternal),
+ ForwardDecl(FD), InternalInterface(isInternal), ExternallyCompleted(false),
ClassLoc(CLoc) {
}
+void ObjCInterfaceDecl::LoadExternalDefinition() const {
+ assert(ExternallyCompleted && "Class is not externally completed");
+ ExternallyCompleted = false;
+ getASTContext().getExternalSource()->CompleteType(
+ const_cast<ObjCInterfaceDecl *>(this));
+}
+
+void ObjCInterfaceDecl::setExternallyCompleted() {
+ assert(getASTContext().getExternalSource() &&
+ "Class can't be externally completed without an external source");
+ assert(!ForwardDecl &&
+ "Forward declarations can't be externally completed");
+ ExternallyCompleted = true;
+}
+
ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const {
+ if (ExternallyCompleted)
+ LoadExternalDefinition();
+
return getASTContext().getObjCImplementation(
const_cast<ObjCInterfaceDecl*>(this));
}
@@ -506,6 +535,9 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
///
ObjCCategoryDecl *
ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
+ if (ExternallyCompleted)
+ LoadExternalDefinition();
+
for (ObjCCategoryDecl *Category = getCategoryList();
Category; Category = Category->getNextClassCategory())
if (Category->getIdentifier() == CategoryId)
@@ -711,7 +743,7 @@ ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L,
void ObjCClassDecl::setClassList(ASTContext &C, ObjCInterfaceDecl*const*List,
const SourceLocation *Locs, unsigned Num) {
ForwardDecls = (ObjCClassRef*) C.Allocate(sizeof(ObjCClassRef)*Num,
- llvm::alignof<ObjCClassRef>());
+ llvm::alignOf<ObjCClassRef>());
for (unsigned i = 0; i < Num; ++i)
new (&ForwardDecls[i]) ObjCClassRef(List[i], Locs[i]);
@@ -896,7 +928,6 @@ ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) ObjCPropertyDecl(DC, L, Id, AtLoc, T);
}
-
//===----------------------------------------------------------------------===//
// ObjCPropertyImplDecl
//===----------------------------------------------------------------------===//
@@ -907,8 +938,16 @@ ObjCPropertyImplDecl *ObjCPropertyImplDecl::Create(ASTContext &C,
SourceLocation L,
ObjCPropertyDecl *property,
Kind PK,
- ObjCIvarDecl *ivar) {
- return new (C) ObjCPropertyImplDecl(DC, atLoc, L, property, PK, ivar);
+ ObjCIvarDecl *ivar,
+ SourceLocation ivarLoc) {
+ return new (C) ObjCPropertyImplDecl(DC, atLoc, L, property, PK, ivar,
+ ivarLoc);
}
+SourceRange ObjCPropertyImplDecl::getSourceRange() const {
+ SourceLocation EndLoc = getLocation();
+ if (IvarLoc.isValid())
+ EndLoc = IvarLoc;
+ return SourceRange(AtLoc, EndLoc);
+}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index f18d2f0..77b4257 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -51,6 +51,7 @@ namespace {
void VisitFunctionDecl(FunctionDecl *D);
void VisitFieldDecl(FieldDecl *D);
void VisitVarDecl(VarDecl *D);
+ void VisitLabelDecl(LabelDecl *D);
void VisitParmVarDecl(ParmVarDecl *D);
void VisitFileScopeAsmDecl(FileScopeAsmDecl *D);
void VisitNamespaceDecl(NamespaceDecl *D);
@@ -307,9 +308,26 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) {
}
void DeclPrinter::VisitEnumDecl(EnumDecl *D) {
- Out << "enum " << D << " {\n";
- VisitDeclContext(D);
- Indent() << "}";
+ Out << "enum ";
+ if (D->isScoped()) {
+ if (D->isScopedUsingClassTag())
+ Out << "class ";
+ else
+ Out << "struct ";
+ }
+ Out << D;
+
+ if (D->isFixed()) {
+ std::string Underlying;
+ D->getIntegerType().getAsStringInternal(Underlying, Policy);
+ Out << " : " << Underlying;
+ }
+
+ if (D->isDefinition()) {
+ Out << " {\n";
+ VisitDeclContext(D);
+ Indent() << "}";
+ }
}
void DeclPrinter::VisitRecordDecl(RecordDecl *D) {
@@ -349,9 +367,15 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
PrintingPolicy SubPolicy(Policy);
SubPolicy.SuppressSpecifiers = false;
std::string Proto = D->getNameInfo().getAsString();
- if (isa<FunctionType>(D->getType().getTypePtr())) {
- const FunctionType *AFT = D->getType()->getAs<FunctionType>();
+ QualType Ty = D->getType();
+ while (const ParenType *PT = dyn_cast<ParenType>(Ty)) {
+ Proto = '(' + Proto + ')';
+ Ty = PT->getInnerType();
+ }
+
+ if (isa<FunctionType>(Ty)) {
+ const FunctionType *AFT = Ty->getAs<FunctionType>();
const FunctionProtoType *FT = 0;
if (D->hasWrittenPrototype())
FT = dyn_cast<FunctionProtoType>(AFT);
@@ -379,6 +403,16 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Proto += ")";
+ if (FT && FT->getTypeQuals()) {
+ unsigned TypeQuals = FT->getTypeQuals();
+ if (TypeQuals & Qualifiers::Const)
+ Proto += " const";
+ if (TypeQuals & Qualifiers::Volatile)
+ Proto += " volatile";
+ if (TypeQuals & Qualifiers::Restrict)
+ Proto += " restrict";
+ }
+
if (FT && FT->hasExceptionSpec()) {
Proto += " throw(";
if (FT->hasAnyExceptionSpec())
@@ -399,18 +433,18 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->hasAttr<NoReturnAttr>())
Proto += " __attribute((noreturn))";
if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
- if (CDecl->getNumBaseOrMemberInitializers() > 0) {
+ if (CDecl->getNumCtorInitializers() > 0) {
Proto += " : ";
Out << Proto;
Proto.clear();
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
E = CDecl->init_end();
B != E; ++B) {
- CXXBaseOrMemberInitializer * BMInitializer = (*B);
+ CXXCtorInitializer * BMInitializer = (*B);
if (B != CDecl->init_begin())
Out << ", ";
- if (BMInitializer->isMemberInitializer()) {
- FieldDecl *FD = BMInitializer->getMember();
+ if (BMInitializer->isAnyMemberInitializer()) {
+ FieldDecl *FD = BMInitializer->getAnyMember();
Out << FD;
} else {
Out << QualType(BMInitializer->getBaseClass(),
@@ -422,8 +456,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
// Nothing to print
} else {
Expr *Init = BMInitializer->getInit();
- if (CXXExprWithTemporaries *Tmp
- = dyn_cast<CXXExprWithTemporaries>(Init))
+ if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init))
Init = Tmp->getSubExpr();
Init = Init->IgnoreParens();
@@ -461,7 +494,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
else
AFT->getResultType().getAsStringInternal(Proto, Policy);
} else {
- D->getType().getAsStringInternal(Proto, Policy);
+ Ty.getAsStringInternal(Proto, Policy);
}
Out << Proto;
@@ -505,6 +538,11 @@ void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
}
}
+void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
+ Out << D->getNameAsString() << ":";
+}
+
+
void DeclPrinter::VisitVarDecl(VarDecl *D) {
if (!Policy.SuppressSpecifiers && D->getStorageClass() != SC_None)
Out << VarDecl::getStorageClassSpecifierString(D->getStorageClass()) << " ";
@@ -518,12 +556,15 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
T = Parm->getOriginalType();
T.getAsStringInternal(Name, Policy);
Out << Name;
- if (D->getInit()) {
+ if (Expr *Init = D->getInit()) {
if (D->hasCXXDirectInitializer())
Out << "(";
- else
- Out << " = ";
- D->getInit()->printPretty(Out, Context, 0, Policy, Indentation);
+ else {
+ CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init);
+ if (!CCE || CCE->getConstructor()->isCopyConstructor())
+ Out << " = ";
+ }
+ Init->printPretty(Out, Context, 0, Policy, Indentation);
if (D->hasCXXDirectInitializer())
Out << ")";
}
@@ -646,6 +687,9 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
dyn_cast<NonTypeTemplateParmDecl>(Param)) {
Out << NTTP->getType().getAsString(Policy);
+ if (NTTP->isParameterPack() && !isa<PackExpansionType>(NTTP->getType()))
+ Out << "...";
+
if (IdentifierInfo *Name = NTTP->getIdentifier()) {
Out << ' ';
Out << Name->getName();
@@ -661,8 +705,11 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
Out << "> ";
- if (isa<TemplateTemplateParmDecl>(D)) {
- Out << "class " << D->getName();
+ if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
+ Out << "class ";
+ if (TTP->isParameterPack())
+ Out << "...";
+ Out << D->getName();
} else {
Visit(D->getTemplatedDecl());
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index e69338a..a73deea 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -14,10 +14,13 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/AST/ASTMutationListener.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
+#include <memory>
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -35,7 +38,7 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
}
TemplateParameterList *
-TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc,
+TemplateParameterList::Create(const ASTContext &C, SourceLocation TemplateLoc,
SourceLocation LAngleLoc, NamedDecl **Params,
unsigned NumParams, SourceLocation RAngleLoc) {
unsigned Size = sizeof(TemplateParameterList)
@@ -47,24 +50,33 @@ TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc,
}
unsigned TemplateParameterList::getMinRequiredArguments() const {
- unsigned NumRequiredArgs = size();
- iterator Param = const_cast<TemplateParameterList *>(this)->end(),
- ParamBegin = const_cast<TemplateParameterList *>(this)->begin();
- while (Param != ParamBegin) {
- --Param;
-
- if (!(*Param)->isTemplateParameterPack() &&
- !(isa<TemplateTypeParmDecl>(*Param) &&
- cast<TemplateTypeParmDecl>(*Param)->hasDefaultArgument()) &&
- !(isa<NonTypeTemplateParmDecl>(*Param) &&
- cast<NonTypeTemplateParmDecl>(*Param)->hasDefaultArgument()) &&
- !(isa<TemplateTemplateParmDecl>(*Param) &&
- cast<TemplateTemplateParmDecl>(*Param)->hasDefaultArgument()))
+ unsigned NumRequiredArgs = 0;
+ for (iterator P = const_cast<TemplateParameterList *>(this)->begin(),
+ PEnd = const_cast<TemplateParameterList *>(this)->end();
+ P != PEnd; ++P) {
+ if ((*P)->isTemplateParameterPack()) {
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P))
+ if (NTTP->isExpandedParameterPack()) {
+ NumRequiredArgs += NTTP->getNumExpansionTypes();
+ continue;
+ }
+
break;
-
- --NumRequiredArgs;
+ }
+
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) {
+ if (TTP->hasDefaultArgument())
+ break;
+ } else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
+ if (NTTP->hasDefaultArgument())
+ break;
+ } else if (cast<TemplateTemplateParmDecl>(*P)->hasDefaultArgument())
+ break;
+
+ ++NumRequiredArgs;
}
-
+
return NumRequiredArgs;
}
@@ -92,7 +104,7 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() {
RedeclarableTemplateDecl *First = getCanonicalDecl();
if (First->CommonOrPrev.isNull()) {
- CommonBase *CommonPtr = First->newCommon();
+ CommonBase *CommonPtr = First->newCommon(getASTContext());
First->CommonOrPrev = CommonPtr;
CommonPtr->Latest = First;
}
@@ -156,9 +168,10 @@ FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C,
return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl);
}
-RedeclarableTemplateDecl::CommonBase *FunctionTemplateDecl::newCommon() {
- Common *CommonPtr = new (getASTContext()) Common;
- getASTContext().AddDeallocation(DeallocateCommon, CommonPtr);
+RedeclarableTemplateDecl::CommonBase *
+FunctionTemplateDecl::newCommon(ASTContext &C) {
+ Common *CommonPtr = new (C) Common;
+ C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
}
@@ -188,9 +201,33 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C,
return New;
}
-RedeclarableTemplateDecl::CommonBase *ClassTemplateDecl::newCommon() {
- Common *CommonPtr = new (getASTContext()) Common;
- getASTContext().AddDeallocation(DeallocateCommon, CommonPtr);
+void ClassTemplateDecl::LoadLazySpecializations() {
+ 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::FoldingSet<ClassTemplateSpecializationDecl> &
+ClassTemplateDecl::getSpecializations() {
+ LoadLazySpecializations();
+ return getCommonPtr()->Specializations;
+}
+
+llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &
+ClassTemplateDecl::getPartialSpecializations() {
+ LoadLazySpecializations();
+ return getCommonPtr()->PartialSpecializations;
+}
+
+RedeclarableTemplateDecl::CommonBase *
+ClassTemplateDecl::newCommon(ASTContext &C) {
+ Common *CommonPtr = new (C) Common;
+ C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
}
@@ -200,6 +237,13 @@ ClassTemplateDecl::findSpecialization(const TemplateArgument *Args,
return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos);
}
+void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D,
+ void *InsertPos) {
+ getSpecializations().InsertNode(D, InsertPos);
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, D);
+}
+
ClassTemplatePartialSpecializationDecl *
ClassTemplateDecl::findPartialSpecialization(const TemplateArgument *Args,
unsigned NumArgs,
@@ -208,6 +252,14 @@ ClassTemplateDecl::findPartialSpecialization(const TemplateArgument *Args,
InsertPos);
}
+void ClassTemplateDecl::AddPartialSpecialization(
+ ClassTemplatePartialSpecializationDecl *D,
+ void *InsertPos) {
+ getPartialSpecializations().InsertNode(D, InsertPos);
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXTemplateSpecialization(this, D);
+}
+
void ClassTemplateDecl::getPartialSpecializations(
llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) {
llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &PartialSpecs
@@ -258,10 +310,13 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
if (!CommonPtr->InjectedClassNameType.isNull())
return CommonPtr->InjectedClassNameType;
- // FIXME: n2800 14.6.1p1 should say how the template arguments
- // corresponding to template parameter packs should be pack
- // expansions. We already say that in 14.6.2.1p2, so it would be
- // better to fix that redundancy.
+ // C++0x [temp.dep.type]p2:
+ // The template argument list of a primary template is a template argument
+ // list in which the nth template argument has the value of the nth template
+ // parameter of the class template. If the nth template parameter is a
+ // template parameter pack (14.5.3), the nth template argument is a pack
+ // expansion (14.5.3) whose pattern is the name of the template parameter
+ // pack.
ASTContext &Context = getASTContext();
TemplateParameterList *Params = getTemplateParameters();
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
@@ -269,19 +324,38 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
for (TemplateParameterList::iterator Param = Params->begin(),
ParamEnd = Params->end();
Param != ParamEnd; ++Param) {
- if (isa<TemplateTypeParmDecl>(*Param)) {
- QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param));
- TemplateArgs.push_back(TemplateArgument(ParamType));
+ TemplateArgument Arg;
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
+ QualType ArgType = Context.getTypeDeclType(TTP);
+ if (TTP->isParameterPack())
+ ArgType = Context.getPackExpansionType(ArgType,
+ llvm::Optional<unsigned>());
+
+ Arg = TemplateArgument(ArgType);
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
Expr *E = new (Context) DeclRefExpr(NTTP,
NTTP->getType().getNonLValueExprType(Context),
+ Expr::getValueKindForType(NTTP->getType()),
NTTP->getLocation());
- TemplateArgs.push_back(TemplateArgument(E));
+
+ if (NTTP->isParameterPack())
+ E = new (Context) PackExpansionExpr(Context.DependentTy, E,
+ NTTP->getLocation(),
+ llvm::Optional<unsigned>());
+ Arg = TemplateArgument(E);
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
- TemplateArgs.push_back(TemplateArgument(TemplateName(TTP)));
+ if (TTP->isParameterPack())
+ Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>());
+ else
+ Arg = TemplateArgument(TemplateName(TTP));
}
+
+ if ((*Param)->isTemplateParameterPack())
+ Arg = TemplateArgument::CreatePackCopy(Context, &Arg, 1);
+
+ TemplateArgs.push_back(Arg);
}
CommonPtr->InjectedClassNameType
@@ -296,7 +370,7 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
//===----------------------------------------------------------------------===//
TemplateTypeParmDecl *
-TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC,
+TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id, bool Typename,
bool ParameterPack) {
@@ -305,7 +379,7 @@ TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC,
}
TemplateTypeParmDecl *
-TemplateTypeParmDecl::Create(ASTContext &C, EmptyShell Empty) {
+TemplateTypeParmDecl::Create(const ASTContext &C, EmptyShell Empty) {
return new (C) TemplateTypeParmDecl(0, SourceLocation(), 0, false,
QualType(), false);
}
@@ -326,12 +400,62 @@ unsigned TemplateTypeParmDecl::getIndex() const {
// NonTypeTemplateParmDecl Method Implementations
//===----------------------------------------------------------------------===//
+NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC,
+ SourceLocation L, unsigned D,
+ unsigned P, IdentifierInfo *Id,
+ QualType T,
+ TypeSourceInfo *TInfo,
+ const QualType *ExpandedTypes,
+ unsigned NumExpandedTypes,
+ TypeSourceInfo **ExpandedTInfos)
+ : DeclaratorDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo),
+ TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false),
+ ParameterPack(true), ExpandedParameterPack(true),
+ NumExpandedTypes(NumExpandedTypes)
+{
+ if (ExpandedTypes && ExpandedTInfos) {
+ void **TypesAndInfos = reinterpret_cast<void **>(this + 1);
+ for (unsigned I = 0; I != NumExpandedTypes; ++I) {
+ TypesAndInfos[2*I] = ExpandedTypes[I].getAsOpaquePtr();
+ TypesAndInfos[2*I + 1] = ExpandedTInfos[I];
+ }
+ }
+}
+
NonTypeTemplateParmDecl *
-NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
+NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id, QualType T,
- TypeSourceInfo *TInfo) {
- return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo);
+ bool ParameterPack, TypeSourceInfo *TInfo) {
+ return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, ParameterPack,
+ TInfo);
+}
+
+NonTypeTemplateParmDecl *
+NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
+ SourceLocation L, unsigned D, unsigned P,
+ IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo,
+ const QualType *ExpandedTypes,
+ unsigned NumExpandedTypes,
+ TypeSourceInfo **ExpandedTInfos) {
+ unsigned Size = sizeof(NonTypeTemplateParmDecl)
+ + NumExpandedTypes * 2 * sizeof(void*);
+ void *Mem = C.Allocate(Size);
+ return new (Mem) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo,
+ ExpandedTypes, NumExpandedTypes,
+ ExpandedTInfos);
+}
+
+SourceLocation NonTypeTemplateParmDecl::getInnerLocStart() const {
+ SourceLocation Start = getTypeSpecStartLoc();
+ if (Start.isInvalid())
+ Start = getLocation();
+ return Start;
+}
+
+SourceRange NonTypeTemplateParmDecl::getSourceRange() const {
+ return SourceRange(getOuterLocStart(), getLocation());
}
SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
@@ -345,128 +469,29 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
//===----------------------------------------------------------------------===//
TemplateTemplateParmDecl *
-TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
+TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
- IdentifierInfo *Id,
+ bool ParameterPack, IdentifierInfo *Id,
TemplateParameterList *Params) {
- return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params);
-}
-
-//===----------------------------------------------------------------------===//
-// TemplateArgumentListBuilder Implementation
-//===----------------------------------------------------------------------===//
-
-void TemplateArgumentListBuilder::Append(const TemplateArgument &Arg) {
- assert((Arg.getKind() != TemplateArgument::Type ||
- Arg.getAsType().isCanonical()) && "Type must be canonical!");
- assert(FlatArgs.size() < MaxFlatArgs && "Argument list builder is full!");
- assert(!StructuredArgs &&
- "Can't append arguments when an argument pack has been added!");
-
- FlatArgs.push_back(Arg);
-}
-
-void TemplateArgumentListBuilder::BeginPack() {
- assert(!AddingToPack && "Already adding to pack!");
- assert(!StructuredArgs && "Argument list already contains a pack!");
-
- AddingToPack = true;
- PackBeginIndex = FlatArgs.size();
-}
-
-void TemplateArgumentListBuilder::EndPack() {
- assert(AddingToPack && "Not adding to pack!");
- assert(!StructuredArgs && "Argument list already contains a pack!");
-
- AddingToPack = false;
-
- // FIXME: This is a memory leak!
- StructuredArgs = new TemplateArgument[MaxStructuredArgs];
-
- // First copy the flat entries over to the list (if any)
- for (unsigned I = 0; I != PackBeginIndex; ++I) {
- NumStructuredArgs++;
- StructuredArgs[I] = FlatArgs[I];
- }
-
- // Next, set the pack.
- TemplateArgument *PackArgs = 0;
- unsigned NumPackArgs = NumFlatArgs - PackBeginIndex;
- // FIXME: NumPackArgs shouldn't be negative here???
- if (NumPackArgs)
- PackArgs = FlatArgs.data()+PackBeginIndex;
-
- StructuredArgs[NumStructuredArgs++].setArgumentPack(PackArgs, NumPackArgs,
- /*CopyArgs=*/false);
+ return new (C) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id,
+ Params);
}
//===----------------------------------------------------------------------===//
// TemplateArgumentList Implementation
//===----------------------------------------------------------------------===//
-TemplateArgumentList::TemplateArgumentList(ASTContext &Context,
- TemplateArgumentListBuilder &Builder,
- bool TakeArgs)
- : FlatArguments(Builder.getFlatArguments(), TakeArgs),
- NumFlatArguments(Builder.flatSize()),
- StructuredArguments(Builder.getStructuredArguments(), TakeArgs),
- NumStructuredArguments(Builder.structuredSize()) {
-
- if (!TakeArgs)
- return;
-
- // If this does take ownership of the arguments, then we have to new them
- // and copy over.
- TemplateArgument *NewArgs =
- new (Context) TemplateArgument[Builder.flatSize()];
- std::copy(Builder.getFlatArguments(),
- Builder.getFlatArguments()+Builder.flatSize(), NewArgs);
- FlatArguments.setPointer(NewArgs);
-
- // Just reuse the structured and flat arguments array if possible.
- if (Builder.getStructuredArguments() == Builder.getFlatArguments()) {
- StructuredArguments.setPointer(NewArgs);
- StructuredArguments.setInt(0);
- } else {
- TemplateArgument *NewSArgs =
- new (Context) TemplateArgument[Builder.flatSize()];
- std::copy(Builder.getFlatArguments(),
- Builder.getFlatArguments()+Builder.flatSize(), NewSArgs);
- StructuredArguments.setPointer(NewSArgs);
- }
-}
-
-TemplateArgumentList::TemplateArgumentList(ASTContext &Context,
- const TemplateArgument *Args,
- unsigned NumArgs)
- : NumFlatArguments(0), NumStructuredArguments(0) {
- init(Context, Args, NumArgs);
-}
-
-/// Produces a shallow copy of the given template argument list. This
-/// assumes that the input argument list outlives it. This takes the list as
-/// a pointer to avoid looking like a copy constructor, since this really
-/// really isn't safe to use that way.
-TemplateArgumentList::TemplateArgumentList(const TemplateArgumentList *Other)
- : FlatArguments(Other->FlatArguments.getPointer(), false),
- NumFlatArguments(Other->flat_size()),
- StructuredArguments(Other->StructuredArguments.getPointer(), false),
- NumStructuredArguments(Other->NumStructuredArguments) { }
-
-void TemplateArgumentList::init(ASTContext &Context,
- const TemplateArgument *Args,
- unsigned NumArgs) {
-assert(NumFlatArguments == 0 && NumStructuredArguments == 0 &&
- "Already initialized!");
-
-NumFlatArguments = NumStructuredArguments = NumArgs;
-TemplateArgument *NewArgs = new (Context) TemplateArgument[NumArgs];
-std::copy(Args, Args+NumArgs, NewArgs);
-FlatArguments.setPointer(NewArgs);
-FlatArguments.setInt(1); // Owns the pointer.
-
-// Just reuse the flat arguments array.
-StructuredArguments.setPointer(NewArgs);
-StructuredArguments.setInt(0); // Doesn't own the pointer.
+TemplateArgumentList *
+TemplateArgumentList::CreateCopy(ASTContext &Context,
+ const TemplateArgument *Args,
+ unsigned NumArgs) {
+ std::size_t Size = sizeof(TemplateArgumentList)
+ + NumArgs * sizeof(TemplateArgument);
+ void *Mem = Context.Allocate(Size);
+ TemplateArgument *StoredArgs
+ = reinterpret_cast<TemplateArgument *>(
+ static_cast<TemplateArgumentList *>(Mem) + 1);
+ std::uninitialized_copy(Args, Args + NumArgs, StoredArgs);
+ return new (Mem) TemplateArgumentList(StoredArgs, NumArgs, true);
}
//===----------------------------------------------------------------------===//
@@ -476,14 +501,15 @@ ClassTemplateSpecializationDecl::
ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
- TemplateArgumentListBuilder &Builder,
+ const TemplateArgument *Args,
+ unsigned NumArgs,
ClassTemplateSpecializationDecl *PrevDecl)
: CXXRecordDecl(DK, TK, DC, L,
SpecializedTemplate->getIdentifier(),
PrevDecl),
SpecializedTemplate(SpecializedTemplate),
ExplicitInfo(0),
- TemplateArgs(Context, Builder, /*TakeArgs=*/true),
+ TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)),
SpecializationKind(TSK_Undeclared) {
}
@@ -497,14 +523,15 @@ ClassTemplateSpecializationDecl *
ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
- TemplateArgumentListBuilder &Builder,
+ const TemplateArgument *Args,
+ unsigned NumArgs,
ClassTemplateSpecializationDecl *PrevDecl) {
ClassTemplateSpecializationDecl *Result
= new (Context)ClassTemplateSpecializationDecl(Context,
ClassTemplateSpecialization,
TK, DC, L,
SpecializedTemplate,
- Builder,
+ Args, NumArgs,
PrevDecl);
Context.getTypeDeclType(Result, PrevDecl);
return Result;
@@ -524,8 +551,8 @@ ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S,
const TemplateArgumentList &TemplateArgs = getTemplateArgs();
S += TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.getFlatArgumentList(),
- TemplateArgs.flat_size(),
+ TemplateArgs.data(),
+ TemplateArgs.size(),
Policy);
}
@@ -545,7 +572,8 @@ ClassTemplatePartialSpecializationDecl::
Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
- TemplateArgumentListBuilder &Builder,
+ const TemplateArgument *Args,
+ unsigned NumArgs,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
ClassTemplatePartialSpecializationDecl *PrevDecl,
@@ -559,7 +587,7 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L,
= new (Context)ClassTemplatePartialSpecializationDecl(Context, TK,
DC, L, Params,
SpecializedTemplate,
- Builder,
+ Args, NumArgs,
ClonedArgs, N,
PrevDecl,
SequenceNumber);
@@ -575,19 +603,6 @@ ClassTemplatePartialSpecializationDecl::Create(ASTContext &Context,
return new (Context)ClassTemplatePartialSpecializationDecl();
}
-void ClassTemplatePartialSpecializationDecl::
-initTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgInfos) {
- assert(ArgsAsWritten == 0 && "ArgsAsWritten already set");
- unsigned N = ArgInfos.size();
- TemplateArgumentLoc *ClonedArgs
- = new (getASTContext()) TemplateArgumentLoc[N];
- for (unsigned I = 0; I != N; ++I)
- ClonedArgs[I] = ArgInfos[I];
-
- ArgsAsWritten = ClonedArgs;
- NumArgsAsWritten = N;
-}
-
//===----------------------------------------------------------------------===//
// FriendTemplateDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 860a0b2..cef54e9 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -20,6 +20,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -93,10 +94,8 @@ int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) {
Selector RHSSelector = RHS.getObjCSelector();
unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs();
for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) {
- IdentifierInfo *LHSId = LHSSelector.getIdentifierInfoForSlot(I);
- IdentifierInfo *RHSId = RHSSelector.getIdentifierInfoForSlot(I);
-
- switch (LHSId->getName().compare(RHSId->getName())) {
+ switch (LHSSelector.getNameForSlot(I).compare(
+ RHSSelector.getNameForSlot(I))) {
case -1: return true;
case 1: return false;
default: break;
@@ -385,7 +384,7 @@ void DeclarationName::dump() const {
llvm::errs() << '\n';
}
-DeclarationNameTable::DeclarationNameTable(ASTContext &C) : Ctx(C) {
+DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) {
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>;
@@ -512,6 +511,28 @@ DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) {
}
}
+bool DeclarationNameInfo::containsUnexpandedParameterPack() const {
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier:
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXLiteralOperatorName:
+ case DeclarationName::CXXUsingDirective:
+ return false;
+
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo)
+ return TInfo->getType()->containsUnexpandedParameterPack();
+
+ return Name.getCXXNameType()->containsUnexpandedParameterPack();
+ }
+ llvm_unreachable("All name kinds handled.");
+}
+
std::string DeclarationNameInfo::getAsString() const {
std::string Result;
llvm::raw_string_ostream OS(Result);
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
new file mode 100644
index 0000000..9d828fc
--- /dev/null
+++ b/lib/AST/DumpXML.cpp
@@ -0,0 +1,1028 @@
+//===--- DumpXML.cpp - Detailed XML dumping ---------------------*- C++ -*-===//
+//
+// 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/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 "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace clang;
+
+#ifndef NDEBUG
+
+namespace {
+
+enum NodeState {
+ NS_Attrs, NS_LazyChildren, NS_Children
+};
+
+struct Node {
+ llvm::StringRef Name;
+ NodeState State;
+ Node(llvm::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) {
+ switch (D->getKind()) {
+ default: llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
+#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()) {
+ default: llvm_unreachable("Type that isn't part of TypeNodes.inc!");
+#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 llvm::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!");
+ return "unknown_type";
+}
+
+struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
+ public XMLTypeVisitor<XMLDumper> {
+ llvm::raw_ostream &out;
+ ASTContext &Context;
+ llvm::SmallVector<Node, 16> Stack;
+ unsigned Indent;
+ explicit XMLDumper(llvm::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(llvm::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(llvm::StringRef attr, llvm::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(llvm::StringRef prop, const void *p) {
+ llvm::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(llvm::StringRef prop, const llvm::APSInt &v) {
+ set(prop, v.toString(10));
+ }
+
+ void setInteger(llvm::StringRef prop, unsigned n) {
+ llvm::SmallString<10> buffer;
+ llvm::raw_svector_ostream os(buffer);
+ os << n;
+ os.flush();
+ set(prop, buffer);
+ }
+
+ void setFlag(llvm::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, llvm::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(llvm::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:
+ // 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->getPreviousDeclaration())
+ setPointer("previous", Prev);
+ }
+
+
+ // TranslationUnitDecl
+ void visitTranslationUnitDeclAsContext(TranslationUnitDecl *D) {
+ visitDeclContext(D);
+ }
+
+ // LinkageSpecDecl
+ void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) {
+ llvm::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()));
+ setFlag("directinit", D->hasCXXDirectInitializer());
+ 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->isDeleted());
+ if (D->getStorageClass() != SC_None)
+ set("storage",
+ VarDecl::getStorageClassSpecifierString(D->getStorageClass()));
+ setFlag("inline", D->isInlineSpecified());
+ // TODO: instantiation, etc.
+ }
+ void visitFunctionDeclChildren(FunctionDecl *D) {
+ for (FunctionDecl::param_iterator
+ I = D->param_begin(), E = D->param_end(); I != E; ++I)
+ dispatch(*I);
+ if (D->isThisDeclarationADefinition())
+ 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(D);
+ }
+ void visitTypedefDeclChildren(TypedefDecl *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());
+ 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);
+ }
+
+ // ObjCClassDecl
+ void visitObjCClassDeclChildren(ObjCClassDecl *D) {
+ for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); I != E; ++I)
+ visitDeclRef(I->getInterface());
+ }
+
+ // ObjCInterfaceDecl
+ void visitCategoryList(ObjCCategoryDecl *D) {
+ if (!D) return;
+
+ TemporaryContainer C(*this, "categories");
+ for (; D; D = D->getNextClassCategory())
+ visitDeclRef(D);
+ }
+ void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) {
+ setPointer("typeptr", D->getTypeForDecl());
+ setFlag("forward_decl", D->isForwardDecl());
+ 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);
+ }
+ visitCategoryList(D->getCategoryList());
+ }
+ void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) {
+ visitDeclContext(D);
+ }
+
+ // ObjCCategoryDecl
+ void visitObjCCategoryDeclAttrs(ObjCCategoryDecl *D) {
+ setFlag("extension", D->IsClassExtension());
+ setFlag("synth_bitfield", D->hasSynthBitfield());
+ }
+ 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) {
+ setFlag("synth_bitfield", D->hasSynthBitfield());
+ 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);
+ }
+ }
+
+ // ObjCForwardProtocolDecl
+ void visitObjCForwardProtocolDeclChildren(ObjCForwardProtocolDecl *D) {
+ for (ObjCForwardProtocolDecl::protocol_iterator
+ I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
+ visitDeclRef(*I);
+ }
+
+ // ObjCProtocolDecl
+ void visitObjCProtocolDeclAttrs(ObjCProtocolDecl *D) {
+ setFlag("forward_decl", D->isForwardDecl());
+ }
+ void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) {
+ 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) {
+ visitDeclContext(D);
+ }
+
+ // ObjCMethodDecl
+ void visitObjCMethodDeclAttrs(ObjCMethodDecl *D) {
+ // decl qualifier?
+ // implementation control?
+
+ setFlag("instance", D->isInstanceMethod());
+ setFlag("variadic", D->isVariadic());
+ setFlag("synthesized", D->isSynthesized());
+ setFlag("defined", D->isDefined());
+ }
+ 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(llvm::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");
+ }
+ }
+
+ 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->getRegParmType()) setInteger("regparm", T->getRegParmType());
+ }
+ void visitFunctionTypeChildren(FunctionType *T) {
+ dispatch(T->getResultType());
+ }
+
+ void visitFunctionProtoTypeAttrs(FunctionProtoType *T) {
+ setFlag("const", T->getTypeQuals() & Qualifiers::Const);
+ setFlag("volatile", T->getTypeQuals() & Qualifiers::Volatile);
+ setFlag("restrict", T->getTypeQuals() & Qualifiers::Restrict);
+ }
+ 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->hasExceptionSpec()) {
+ push("exception_specifiers");
+ setFlag("any", T->hasAnyExceptionSpec());
+ completeAttrs();
+ for (FunctionProtoType::exception_iterator
+ I = T->exception_begin(), E = T->exception_end(); I != E; ++I)
+ dispatch(*I);
+ pop();
+ }
+ }
+
+ 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(llvm::raw_ostream &out) const {
+ XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this));
+}
+
+#else /* ifndef NDEBUG */
+
+void Decl::dumpXML() const {}
+void Decl::dumpXML(llvm::raw_ostream &out) const {}
+
+#endif
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 5feef1c..391b26a 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -20,15 +20,16 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Lex/Lexer.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace clang;
-void Expr::ANCHOR() {} // key function for Expr class.
-
/// isKnownToHaveBooleanValue - Return true if this is an integer expression
/// that is known to return 0 or 1. This happens for _Bool/bool expressions
/// but also int expressions which are produced by things like comparisons in
@@ -90,6 +91,42 @@ bool Expr::isKnownToHaveBooleanValue() const {
return false;
}
+// Amusing macro metaprogramming hack: check whether a class provides
+// a more specific implementation of getExprLoc().
+namespace {
+ /// This implementation is used when a class provides a custom
+ /// implementation of getExprLoc.
+ template <class E, class T>
+ SourceLocation getExprLocImpl(const Expr *expr,
+ SourceLocation (T::*v)() const) {
+ return static_cast<const E*>(expr)->getExprLoc();
+ }
+
+ /// This implementation is used when a class doesn't provide
+ /// a custom implementation of getExprLoc. Overload resolution
+ /// should pick it over the implementation above because it's
+ /// more specialized according to function template partial ordering.
+ template <class E>
+ SourceLocation getExprLocImpl(const Expr *expr,
+ SourceLocation (Expr::*v)() const) {
+ return static_cast<const E*>(expr)->getSourceRange().getBegin();
+ }
+}
+
+SourceLocation Expr::getExprLoc() const {
+ switch (getStmtClass()) {
+ case Stmt::NoStmtClass: llvm_unreachable("statement without class");
+#define ABSTRACT_STMT(type)
+#define STMT(type, base) \
+ case Stmt::type##Class: llvm_unreachable(#type " is not an Expr"); break;
+#define EXPR(type, base) \
+ case Stmt::type##Class: return getExprLocImpl<type>(this, &type::getExprLoc);
+#include "clang/AST/StmtNodes.inc"
+ }
+ llvm_unreachable("unknown statement kind");
+ return SourceLocation();
+}
+
//===----------------------------------------------------------------------===//
// Primary Expressions.
//===----------------------------------------------------------------------===//
@@ -105,6 +142,25 @@ void ExplicitTemplateArgumentList::initializeFrom(
new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
}
+void ExplicitTemplateArgumentList::initializeFrom(
+ const TemplateArgumentListInfo &Info,
+ bool &Dependent,
+ bool &ContainsUnexpandedParameterPack) {
+ LAngleLoc = Info.getLAngleLoc();
+ RAngleLoc = Info.getRAngleLoc();
+ NumTemplateArgs = Info.size();
+
+ TemplateArgumentLoc *ArgBuffer = getTemplateArgs();
+ for (unsigned i = 0; i != NumTemplateArgs; ++i) {
+ Dependent = Dependent || Info[i].getArgument().isDependent();
+ ContainsUnexpandedParameterPack
+ = ContainsUnexpandedParameterPack ||
+ Info[i].getArgument().containsUnexpandedParameterPack();
+
+ new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
+ }
+}
+
void ExplicitTemplateArgumentList::copyInto(
TemplateArgumentListInfo &Info) const {
Info.setLAngleLoc(LAngleLoc);
@@ -123,11 +179,14 @@ std::size_t ExplicitTemplateArgumentList::sizeFor(
return sizeFor(Info.size());
}
-void DeclRefExpr::computeDependence() {
+/// \brief Compute the type- and value-dependence of a declaration reference
+/// based on the declaration being referenced.
+static void computeDeclRefDependence(NamedDecl *D, QualType T,
+ bool &TypeDependent,
+ bool &ValueDependent) {
TypeDependent = false;
ValueDependent = false;
- NamedDecl *D = getDecl();
// (TD) C++ [temp.dep.expr]p3:
// An id-expression is type-dependent if it contains:
@@ -136,63 +195,93 @@ void DeclRefExpr::computeDependence() {
//
// (VD) C++ [temp.dep.constexpr]p2:
// An identifier is value-dependent if it is:
-
+
// (TD) - an identifier that was declared with dependent type
// (VD) - a name declared with a dependent type,
- if (getType()->isDependentType()) {
+ if (T->isDependentType()) {
TypeDependent = true;
ValueDependent = true;
+ return;
}
+
// (TD) - a conversion-function-id that specifies a dependent type
- else if (D->getDeclName().getNameKind()
- == DeclarationName::CXXConversionFunctionName &&
+ if (D->getDeclName().getNameKind()
+ == DeclarationName::CXXConversionFunctionName &&
D->getDeclName().getCXXNameType()->isDependentType()) {
TypeDependent = true;
ValueDependent = true;
- }
- // (TD) - a template-id that is dependent,
- else if (hasExplicitTemplateArgs() &&
- TemplateSpecializationType::anyDependentTemplateArguments(
- getTemplateArgs(),
- getNumTemplateArgs())) {
- TypeDependent = true;
- ValueDependent = true;
+ return;
}
// (VD) - the name of a non-type template parameter,
- else if (isa<NonTypeTemplateParmDecl>(D))
+ if (isa<NonTypeTemplateParmDecl>(D)) {
ValueDependent = true;
+ return;
+ }
+
// (VD) - a constant with integral or enumeration type and is
// initialized with an expression that is value-dependent.
- else if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
if (Var->getType()->isIntegralOrEnumerationType() &&
Var->getType().getCVRQualifiers() == Qualifiers::Const) {
if (const Expr *Init = Var->getAnyInitializer())
if (Init->isValueDependent())
ValueDependent = true;
}
+
// (VD) - FIXME: Missing from the standard:
// - a member function or a static data member of the current
// instantiation
else if (Var->isStaticDataMember() &&
Var->getDeclContext()->isDependentContext())
ValueDependent = true;
- }
+
+ return;
+ }
+
// (VD) - FIXME: Missing from the standard:
// - a member function or a static data member of the current
// instantiation
- else if (isa<CXXMethodDecl>(D) && D->getDeclContext()->isDependentContext())
+ if (isa<CXXMethodDecl>(D) && D->getDeclContext()->isDependentContext()) {
ValueDependent = true;
- // (TD) - a nested-name-specifier or a qualified-id that names a
- // member of an unknown specialization.
- // (handled by DependentScopeDeclRefExpr)
+ return;
+ }
+}
+
+void DeclRefExpr::computeDependence() {
+ bool TypeDependent = false;
+ bool ValueDependent = false;
+ computeDeclRefDependence(getDecl(), getType(), TypeDependent, ValueDependent);
+
+ // (TD) C++ [temp.dep.expr]p3:
+ // An id-expression is type-dependent if it contains:
+ //
+ // and
+ //
+ // (VD) C++ [temp.dep.constexpr]p2:
+ // An identifier is value-dependent if it is:
+ if (!TypeDependent && !ValueDependent &&
+ hasExplicitTemplateArgs() &&
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ getTemplateArgs(),
+ getNumTemplateArgs())) {
+ TypeDependent = true;
+ ValueDependent = true;
+ }
+
+ ExprBits.TypeDependent = TypeDependent;
+ ExprBits.ValueDependent = ValueDependent;
+
+ // Is the declaration a parameter pack?
+ if (getDecl()->isParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
}
DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
ValueDecl *D, SourceLocation NameLoc,
const TemplateArgumentListInfo *TemplateArgs,
- QualType T)
- : Expr(DeclRefExprClass, T, false, false),
+ QualType T, ExprValueKind VK)
+ : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false),
DecoratedD(D,
(Qualifier? HasQualifierFlag : 0) |
(TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)),
@@ -213,8 +302,8 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
ValueDecl *D, const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs,
- QualType T)
- : Expr(DeclRefExprClass, T, false, false),
+ QualType T, ExprValueKind VK)
+ : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false),
DecoratedD(D,
(Qualifier? HasQualifierFlag : 0) |
(TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)),
@@ -237,10 +326,11 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
ValueDecl *D,
SourceLocation NameLoc,
QualType T,
+ ExprValueKind VK,
const TemplateArgumentListInfo *TemplateArgs) {
return Create(Context, Qualifier, QualifierRange, D,
DeclarationNameInfo(D->getDeclName(), NameLoc),
- T, TemplateArgs);
+ T, VK, TemplateArgs);
}
DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
@@ -249,6 +339,7 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
ValueDecl *D,
const DeclarationNameInfo &NameInfo,
QualType T,
+ ExprValueKind VK,
const TemplateArgumentListInfo *TemplateArgs) {
std::size_t Size = sizeof(DeclRefExpr);
if (Qualifier != 0)
@@ -257,21 +348,23 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
if (TemplateArgs)
Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
- void *Mem = Context.Allocate(Size, llvm::alignof<DeclRefExpr>());
+ void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameInfo,
- TemplateArgs, T);
+ TemplateArgs, T, VK);
}
-DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, bool HasQualifier,
+DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
+ bool HasQualifier,
+ bool HasExplicitTemplateArgs,
unsigned NumTemplateArgs) {
std::size_t Size = sizeof(DeclRefExpr);
if (HasQualifier)
Size += sizeof(NameQualifier);
- if (NumTemplateArgs)
+ if (HasExplicitTemplateArgs)
Size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
- void *Mem = Context.Allocate(Size, llvm::alignof<DeclRefExpr>());
+ void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
return new (Mem) DeclRefExpr(EmptyShell());
}
@@ -432,7 +525,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData,
// any concatenated string tokens.
void *Mem = C.Allocate(sizeof(StringLiteral)+
sizeof(SourceLocation)*(NumStrs-1),
- llvm::alignof<StringLiteral>());
+ llvm::alignOf<StringLiteral>());
StringLiteral *SL = new (Mem) StringLiteral(Ty);
// OPTIMIZE: could allocate this appended to the StringLiteral.
@@ -452,7 +545,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData,
StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) {
void *Mem = C.Allocate(sizeof(StringLiteral)+
sizeof(SourceLocation)*(NumStrs-1),
- llvm::alignof<StringLiteral>());
+ llvm::alignOf<StringLiteral>());
StringLiteral *SL = new (Mem) StringLiteral(QualType());
SL->StrData = 0;
SL->ByteLength = 0;
@@ -467,6 +560,72 @@ void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) {
ByteLength = Str.size();
}
+/// getLocationOfByte - Return a source location that points to the specified
+/// byte of this string literal.
+///
+/// Strings are amazingly complex. They can be formed from multiple tokens and
+/// can have escape sequences in them in addition to the usual trigraph and
+/// escaped newline business. This routine handles this complexity.
+///
+SourceLocation StringLiteral::
+getLocationOfByte(unsigned ByteNo, const SourceManager &SM,
+ const LangOptions &Features, const TargetInfo &Target) const {
+ assert(!isWide() && "This doesn't work for wide strings yet");
+
+ // Loop over all of the tokens in this string until we find the one that
+ // contains the byte we're looking for.
+ unsigned TokNo = 0;
+ while (1) {
+ assert(TokNo < getNumConcatenated() && "Invalid byte number!");
+ SourceLocation StrTokLoc = getStrTokenLoc(TokNo);
+
+ // Get the spelling of the string so that we can get the data that makes up
+ // the string literal, not the identifier for the macro it is potentially
+ // expanded through.
+ SourceLocation StrTokSpellingLoc = SM.getSpellingLoc(StrTokLoc);
+
+ // Re-lex the token to get its length and original spelling.
+ std::pair<FileID, unsigned> LocInfo =SM.getDecomposedLoc(StrTokSpellingLoc);
+ bool Invalid = false;
+ llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid);
+ if (Invalid)
+ return StrTokSpellingLoc;
+
+ const char *StrData = Buffer.data()+LocInfo.second;
+
+ // Create a langops struct and enable trigraphs. This is sufficient for
+ // relexing tokens.
+ LangOptions LangOpts;
+ LangOpts.Trigraphs = true;
+
+ // Create a lexer starting at the beginning of this token.
+ Lexer TheLexer(StrTokSpellingLoc, Features, Buffer.begin(), StrData,
+ Buffer.end());
+ Token TheTok;
+ TheLexer.LexFromRawLexer(TheTok);
+
+ // Use the StringLiteralParser to compute the length of the string in bytes.
+ StringLiteralParser SLP(&TheTok, 1, SM, Features, Target);
+ unsigned TokNumBytes = SLP.GetStringLength();
+
+ // If the byte is in this token, return the location of the byte.
+ if (ByteNo < TokNumBytes ||
+ (ByteNo == TokNumBytes && TokNo == getNumConcatenated())) {
+ unsigned Offset = SLP.getOffsetOfStringByte(TheTok, ByteNo);
+
+ // Now that we know the offset of the token in the spelling, use the
+ // preprocessor to get the offset in the original source.
+ return Lexer::AdvanceToTokenCharacter(StrTokLoc, Offset, SM, Features);
+ }
+
+ // Move to the next string token.
+ ++TokNo;
+ ByteNo -= TokNumBytes;
+ }
+}
+
+
+
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "sizeof" or "[pre]++".
const char *UnaryOperator::getOpcodeStr(Opcode Op) {
@@ -522,43 +681,82 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
// Postfix Operators.
//===----------------------------------------------------------------------===//
-CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, Expr **args,
- unsigned numargs, QualType t, SourceLocation rparenloc)
- : Expr(SC, t,
- fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs),
- fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)),
+CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
+ Expr **args, unsigned numargs, QualType t, ExprValueKind VK,
+ SourceLocation rparenloc)
+ : Expr(SC, t, VK, OK_Ordinary,
+ fn->isTypeDependent(),
+ fn->isValueDependent(),
+ fn->containsUnexpandedParameterPack()),
NumArgs(numargs) {
- SubExprs = new (C) Stmt*[numargs+1];
+ SubExprs = new (C) Stmt*[numargs+PREARGS_START+NumPreArgs];
SubExprs[FN] = fn;
- for (unsigned i = 0; i != numargs; ++i)
- SubExprs[i+ARGS_START] = args[i];
+ for (unsigned i = 0; i != numargs; ++i) {
+ if (args[i]->isTypeDependent())
+ ExprBits.TypeDependent = true;
+ if (args[i]->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (args[i]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
+ SubExprs[i+PREARGS_START+NumPreArgs] = args[i];
+ }
+ CallExprBits.NumPreArgs = NumPreArgs;
RParenLoc = rparenloc;
}
CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs,
- QualType t, SourceLocation rparenloc)
- : Expr(CallExprClass, t,
- fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs),
- fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)),
+ QualType t, ExprValueKind VK, SourceLocation rparenloc)
+ : Expr(CallExprClass, t, VK, OK_Ordinary,
+ fn->isTypeDependent(),
+ fn->isValueDependent(),
+ fn->containsUnexpandedParameterPack()),
NumArgs(numargs) {
- SubExprs = new (C) Stmt*[numargs+1];
+ SubExprs = new (C) Stmt*[numargs+PREARGS_START];
SubExprs[FN] = fn;
- for (unsigned i = 0; i != numargs; ++i)
- SubExprs[i+ARGS_START] = args[i];
+ for (unsigned i = 0; i != numargs; ++i) {
+ if (args[i]->isTypeDependent())
+ ExprBits.TypeDependent = true;
+ if (args[i]->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (args[i]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
+ SubExprs[i+PREARGS_START] = args[i];
+ }
+ CallExprBits.NumPreArgs = 0;
RParenLoc = rparenloc;
}
CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty)
: Expr(SC, Empty), SubExprs(0), NumArgs(0) {
- SubExprs = new (C) Stmt*[1];
+ // FIXME: Why do we allocate this?
+ SubExprs = new (C) Stmt*[PREARGS_START];
+ CallExprBits.NumPreArgs = 0;
+}
+
+CallExpr::CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs,
+ EmptyShell Empty)
+ : Expr(SC, Empty), SubExprs(0), NumArgs(0) {
+ // FIXME: Why do we allocate this?
+ SubExprs = new (C) Stmt*[PREARGS_START+NumPreArgs];
+ CallExprBits.NumPreArgs = NumPreArgs;
}
Decl *CallExpr::getCalleeDecl() {
Expr *CEE = getCallee()->IgnoreParenCasts();
+ // If we're calling a dereference, look at the pointer instead.
+ if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) {
+ if (BO->isPtrMemOp())
+ CEE = BO->getRHS()->IgnoreParenCasts();
+ } else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) {
+ if (UO->getOpcode() == UO_Deref)
+ CEE = UO->getSubExpr()->IgnoreParenCasts();
+ }
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE))
return DRE->getDecl();
if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE))
@@ -585,12 +783,14 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) {
}
// Otherwise, we are growing the # arguments. New an bigger argument array.
- Stmt **NewSubExprs = new (C) Stmt*[NumArgs+1];
+ unsigned NumPreArgs = getNumPreArgs();
+ Stmt **NewSubExprs = new (C) Stmt*[NumArgs+PREARGS_START+NumPreArgs];
// Copy over args.
- for (unsigned i = 0; i != getNumArgs()+ARGS_START; ++i)
+ for (unsigned i = 0; i != getNumArgs()+PREARGS_START+NumPreArgs; ++i)
NewSubExprs[i] = SubExprs[i];
// Null out new args.
- for (unsigned i = getNumArgs()+ARGS_START; i != NumArgs+ARGS_START; ++i)
+ for (unsigned i = getNumArgs()+PREARGS_START+NumPreArgs;
+ i != NumArgs+PREARGS_START+NumPreArgs; ++i)
NewSubExprs[i] = 0;
if (SubExprs) C.Deallocate(SubExprs);
@@ -600,7 +800,7 @@ void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) {
/// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If
/// not, return 0.
-unsigned CallExpr::isBuiltinCall(ASTContext &Context) const {
+unsigned CallExpr::isBuiltinCall(const ASTContext &Context) const {
// All simple function calls (e.g. func()) are implicitly cast to pointer to
// function. As a result, we try and obtain the DeclRefExpr from the
// ImplicitCastExpr.
@@ -663,10 +863,10 @@ OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type,
OffsetOfNode* compsPtr, unsigned numComps,
Expr** exprsPtr, unsigned numExprs,
SourceLocation RParenLoc)
- : Expr(OffsetOfExprClass, type, /*TypeDependent=*/false,
- /*ValueDependent=*/tsi->getType()->isDependentType() ||
- hasAnyTypeDependentArguments(exprsPtr, numExprs) ||
- hasAnyValueDependentArguments(exprsPtr, numExprs)),
+ : Expr(OffsetOfExprClass, type, VK_RValue, OK_Ordinary,
+ /*TypeDependent=*/false,
+ /*ValueDependent=*/tsi->getType()->isDependentType(),
+ tsi->getType()->containsUnexpandedParameterPack()),
OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi),
NumComps(numComps), NumExprs(numExprs)
{
@@ -675,6 +875,11 @@ OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type,
}
for(unsigned i = 0; i < numExprs; ++i) {
+ if (exprsPtr[i]->isTypeDependent() || exprsPtr[i]->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (exprsPtr[i]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
setIndexExpr(i, exprsPtr[i]);
}
}
@@ -694,7 +899,9 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
DeclAccessPair founddecl,
DeclarationNameInfo nameinfo,
const TemplateArgumentListInfo *targs,
- QualType ty) {
+ QualType ty,
+ ExprValueKind vk,
+ ExprObjectKind ok) {
std::size_t Size = sizeof(MemberExpr);
bool hasQualOrFound = (qual != 0 ||
@@ -706,8 +913,9 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
if (targs)
Size += ExplicitTemplateArgumentList::sizeFor(*targs);
- void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>());
- MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, nameinfo, ty);
+ void *Mem = C.Allocate(Size, llvm::alignOf<MemberExpr>());
+ MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, nameinfo,
+ ty, vk, ok);
if (hasQualOrFound) {
if (qual && qual->isDependent()) {
@@ -732,12 +940,16 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
const char *CastExpr::getCastKindName() const {
switch (getCastKind()) {
- case CK_Unknown:
- return "Unknown";
+ case CK_Dependent:
+ return "Dependent";
case CK_BitCast:
return "BitCast";
case CK_LValueBitCast:
return "LValueBitCast";
+ case CK_LValueToRValue:
+ return "LValueToRValue";
+ case CK_GetObjCProperty:
+ return "GetObjCProperty";
case CK_NoOp:
return "NoOp";
case CK_BaseToDerived:
@@ -756,6 +968,8 @@ const char *CastExpr::getCastKindName() const {
return "FunctionToPointerDecay";
case CK_NullToMemberPointer:
return "NullToMemberPointer";
+ case CK_NullToPointer:
+ return "NullToPointer";
case CK_BaseToDerivedMemberPointer:
return "BaseToDerivedMemberPointer";
case CK_DerivedToBaseMemberPointer:
@@ -768,18 +982,24 @@ const char *CastExpr::getCastKindName() const {
return "IntegralToPointer";
case CK_PointerToIntegral:
return "PointerToIntegral";
+ case CK_PointerToBoolean:
+ return "PointerToBoolean";
case CK_ToVoid:
return "ToVoid";
case CK_VectorSplat:
return "VectorSplat";
case CK_IntegralCast:
return "IntegralCast";
+ case CK_IntegralToBoolean:
+ return "IntegralToBoolean";
case CK_IntegralToFloating:
return "IntegralToFloating";
case CK_FloatingToIntegral:
return "FloatingToIntegral";
case CK_FloatingCast:
return "FloatingCast";
+ case CK_FloatingToBoolean:
+ return "FloatingToBoolean";
case CK_MemberPointerToBoolean:
return "MemberPointerToBoolean";
case CK_AnyPointerToObjCPointerCast:
@@ -788,9 +1008,29 @@ const char *CastExpr::getCastKindName() const {
return "AnyPointerToBlockPointerCast";
case CK_ObjCObjectLValueCast:
return "ObjCObjectLValueCast";
+ case CK_FloatingRealToComplex:
+ return "FloatingRealToComplex";
+ case CK_FloatingComplexToReal:
+ return "FloatingComplexToReal";
+ case CK_FloatingComplexToBoolean:
+ return "FloatingComplexToBoolean";
+ case CK_FloatingComplexCast:
+ return "FloatingComplexCast";
+ case CK_FloatingComplexToIntegralComplex:
+ return "FloatingComplexToIntegralComplex";
+ case CK_IntegralRealToComplex:
+ return "IntegralRealToComplex";
+ case CK_IntegralComplexToReal:
+ return "IntegralComplexToReal";
+ case CK_IntegralComplexToBoolean:
+ return "IntegralComplexToBoolean";
+ case CK_IntegralComplexCast:
+ return "IntegralComplexCast";
+ case CK_IntegralComplexToFloatingComplex:
+ return "IntegralComplexToFloatingComplex";
}
- assert(0 && "Unhandled cast kind!");
+ llvm_unreachable("Unhandled cast kind!");
return 0;
}
@@ -859,7 +1099,7 @@ ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C,
CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T,
- CastKind K, Expr *Op,
+ ExprValueKind VK, CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
SourceLocation L, SourceLocation R) {
@@ -867,7 +1107,7 @@ CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T,
void *Buffer =
C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
CStyleCastExpr *E =
- new (Buffer) CStyleCastExpr(T, K, Op, PathSize, WrittenTy, L, R);
+ new (Buffer) CStyleCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, R);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -984,16 +1224,19 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc,
Expr **initExprs, unsigned numInits,
SourceLocation rbraceloc)
- : Expr(InitListExprClass, QualType(), false, false),
+ : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false,
+ false),
InitExprs(C, numInits),
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
UnionFieldInit(0), HadArrayRangeDesignator(false)
{
for (unsigned I = 0; I != numInits; ++I) {
if (initExprs[I]->isTypeDependent())
- TypeDependent = true;
+ ExprBits.TypeDependent = true;
if (initExprs[I]->isValueDependent())
- ValueDependent = true;
+ ExprBits.ValueDependent = true;
+ if (initExprs[I]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
}
InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits);
@@ -1020,6 +1263,35 @@ Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) {
return Result;
}
+SourceRange InitListExpr::getSourceRange() const {
+ if (SyntacticForm)
+ return SyntacticForm->getSourceRange();
+ SourceLocation Beg = LBraceLoc, End = RBraceLoc;
+ if (Beg.isInvalid()) {
+ // Find the first non-null initializer.
+ for (InitExprsTy::const_iterator I = InitExprs.begin(),
+ E = InitExprs.end();
+ I != E; ++I) {
+ if (Stmt *S = *I) {
+ Beg = S->getLocStart();
+ break;
+ }
+ }
+ }
+ if (End.isInvalid()) {
+ // Find the first non-null initializer from the end.
+ for (InitExprsTy::const_reverse_iterator I = InitExprs.rbegin(),
+ E = InitExprs.rend();
+ I != E; ++I) {
+ if (Stmt *S = *I) {
+ End = S->getSourceRange().getEnd();
+ break;
+ }
+ }
+ }
+ return SourceRange(Beg, End);
+}
+
/// getFunctionType - Return the underlying function type for this block.
///
const FunctionType *BlockExpr::getFunctionType() const {
@@ -1195,21 +1467,11 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
return false;
}
- case ObjCImplicitSetterGetterRefExprClass: { // Dot syntax for message send.
-#if 0
- const ObjCImplicitSetterGetterRefExpr *Ref =
- cast<ObjCImplicitSetterGetterRefExpr>(this);
- // FIXME: We really want the location of the '.' here.
- Loc = Ref->getLocation();
- R1 = SourceRange(Ref->getLocation(), Ref->getLocation());
- if (Ref->getBase())
- R2 = Ref->getBase()->getSourceRange();
-#else
+ case ObjCPropertyRefExprClass:
Loc = getExprLoc();
R1 = getSourceRange();
-#endif
return true;
- }
+
case StmtExprClass: {
// Statement exprs don't logically have side effects themselves, but are
// sometimes used in macros in ways that give them a type that is unused.
@@ -1217,9 +1479,13 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
// however, if the result of the stmt expr is dead, we don't want to emit a
// warning.
const CompoundStmt *CS = cast<StmtExpr>(this)->getSubStmt();
- if (!CS->body_empty())
+ if (!CS->body_empty()) {
if (const Expr *E = dyn_cast<Expr>(CS->body_back()))
return E->isUnusedResultAWarning(Loc, R1, R2, Ctx);
+ if (const LabelStmt *Label = dyn_cast<LabelStmt>(CS->body_back()))
+ if (const Expr *E = dyn_cast<Expr>(Label->getSubStmt()))
+ return E->isUnusedResultAWarning(Loc, R1, R2, Ctx);
+ }
if (getType()->isVoidType())
return false;
@@ -1268,8 +1534,8 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case CXXBindTemporaryExprClass:
return (cast<CXXBindTemporaryExpr>(this)
->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
- case CXXExprWithTemporariesClass:
- return (cast<CXXExprWithTemporaries>(this)
+ case ExprWithCleanupsClass:
+ return (cast<ExprWithCleanups>(this)
->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx));
}
}
@@ -1311,12 +1577,254 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
return cast<ArraySubscriptExpr>(this)->getBase()->isOBJCGCCandidate(Ctx);
}
}
+
+bool Expr::isBoundMemberFunction(ASTContext &Ctx) const {
+ if (isTypeDependent())
+ return false;
+ return ClassifyLValue(Ctx) == Expr::LV_MemberFunction;
+}
+
+static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1,
+ Expr::CanThrowResult CT2) {
+ // CanThrowResult constants are ordered so that the maximum is the correct
+ // merge result.
+ return CT1 > CT2 ? CT1 : CT2;
+}
+
+static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) {
+ Expr *E = const_cast<Expr*>(CE);
+ Expr::CanThrowResult R = Expr::CT_Cannot;
+ for (Expr::child_range I = E->children(); I && R != Expr::CT_Can; ++I) {
+ R = MergeCanThrow(R, cast<Expr>(*I)->CanThrow(C));
+ }
+ return R;
+}
+
+static Expr::CanThrowResult CanCalleeThrow(const Decl *D,
+ bool NullThrows = true) {
+ if (!D)
+ return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
+
+ // See if we can get a function type from the decl somehow.
+ const ValueDecl *VD = dyn_cast<ValueDecl>(D);
+ if (!VD) // If we have no clue what we're calling, assume the worst.
+ return Expr::CT_Can;
+
+ // As an extension, we assume that __attribute__((nothrow)) functions don't
+ // throw.
+ if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
+ return Expr::CT_Cannot;
+
+ QualType T = VD->getType();
+ const FunctionProtoType *FT;
+ if ((FT = T->getAs<FunctionProtoType>())) {
+ } else if (const PointerType *PT = T->getAs<PointerType>())
+ FT = PT->getPointeeType()->getAs<FunctionProtoType>();
+ else if (const ReferenceType *RT = T->getAs<ReferenceType>())
+ FT = RT->getPointeeType()->getAs<FunctionProtoType>();
+ else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
+ FT = MT->getPointeeType()->getAs<FunctionProtoType>();
+ else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
+ FT = BT->getPointeeType()->getAs<FunctionProtoType>();
+
+ if (!FT)
+ return Expr::CT_Can;
+
+ return FT->hasEmptyExceptionSpec() ? Expr::CT_Cannot : Expr::CT_Can;
+}
+
+static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) {
+ if (DC->isTypeDependent())
+ return Expr::CT_Dependent;
+
+ if (!DC->getTypeAsWritten()->isReferenceType())
+ return Expr::CT_Cannot;
+
+ return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot;
+}
+
+static Expr::CanThrowResult CanTypeidThrow(ASTContext &C,
+ const CXXTypeidExpr *DC) {
+ if (DC->isTypeOperand())
+ return Expr::CT_Cannot;
+
+ Expr *Op = DC->getExprOperand();
+ if (Op->isTypeDependent())
+ return Expr::CT_Dependent;
+
+ const RecordType *RT = Op->getType()->getAs<RecordType>();
+ if (!RT)
+ return Expr::CT_Cannot;
+
+ if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
+ return Expr::CT_Cannot;
+
+ if (Op->Classify(C).isPRValue())
+ return Expr::CT_Cannot;
+
+ return Expr::CT_Can;
+}
+
+Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
+ // C++ [expr.unary.noexcept]p3:
+ // [Can throw] if in a potentially-evaluated context the expression would
+ // contain:
+ switch (getStmtClass()) {
+ case CXXThrowExprClass:
+ // - a potentially evaluated throw-expression
+ return CT_Can;
+
+ case CXXDynamicCastExprClass: {
+ // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
+ // where T is a reference type, that requires a run-time check
+ CanThrowResult CT = CanDynamicCastThrow(cast<CXXDynamicCastExpr>(this));
+ if (CT == CT_Can)
+ return CT;
+ return MergeCanThrow(CT, CanSubExprsThrow(C, this));
+ }
+
+ case CXXTypeidExprClass:
+ // - a potentially evaluated typeid expression applied to a glvalue
+ // expression whose type is a polymorphic class type
+ return CanTypeidThrow(C, cast<CXXTypeidExpr>(this));
+
+ // - a potentially evaluated call to a function, member function, function
+ // pointer, or member function pointer that does not have a non-throwing
+ // exception-specification
+ case CallExprClass:
+ case CXXOperatorCallExprClass:
+ case CXXMemberCallExprClass: {
+ CanThrowResult CT = CanCalleeThrow(cast<CallExpr>(this)->getCalleeDecl());
+ if (CT == CT_Can)
+ return CT;
+ return MergeCanThrow(CT, CanSubExprsThrow(C, this));
+ }
+
+ case CXXConstructExprClass:
+ case CXXTemporaryObjectExprClass: {
+ CanThrowResult CT = CanCalleeThrow(
+ cast<CXXConstructExpr>(this)->getConstructor());
+ if (CT == CT_Can)
+ return CT;
+ return MergeCanThrow(CT, CanSubExprsThrow(C, this));
+ }
+
+ case CXXNewExprClass: {
+ CanThrowResult CT = MergeCanThrow(
+ CanCalleeThrow(cast<CXXNewExpr>(this)->getOperatorNew()),
+ CanCalleeThrow(cast<CXXNewExpr>(this)->getConstructor(),
+ /*NullThrows*/false));
+ if (CT == CT_Can)
+ return CT;
+ return MergeCanThrow(CT, CanSubExprsThrow(C, this));
+ }
+
+ case CXXDeleteExprClass: {
+ CanThrowResult CT = CanCalleeThrow(
+ cast<CXXDeleteExpr>(this)->getOperatorDelete());
+ if (CT == CT_Can)
+ return CT;
+ const Expr *Arg = cast<CXXDeleteExpr>(this)->getArgument();
+ // Unwrap exactly one implicit cast, which converts all pointers to void*.
+ if (const ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg))
+ Arg = Cast->getSubExpr();
+ if (const PointerType *PT = Arg->getType()->getAs<PointerType>()) {
+ if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) {
+ CanThrowResult CT2 = CanCalleeThrow(
+ cast<CXXRecordDecl>(RT->getDecl())->getDestructor());
+ if (CT2 == CT_Can)
+ return CT2;
+ CT = MergeCanThrow(CT, CT2);
+ }
+ }
+ return MergeCanThrow(CT, CanSubExprsThrow(C, this));
+ }
+
+ case CXXBindTemporaryExprClass: {
+ // The bound temporary has to be destroyed again, which might throw.
+ CanThrowResult CT = CanCalleeThrow(
+ cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());
+ if (CT == CT_Can)
+ return CT;
+ return MergeCanThrow(CT, CanSubExprsThrow(C, this));
+ }
+
+ // ObjC message sends are like function calls, but never have exception
+ // specs.
+ case ObjCMessageExprClass:
+ case ObjCPropertyRefExprClass:
+ return CT_Can;
+
+ // Many other things have subexpressions, so we have to test those.
+ // Some are simple:
+ case ParenExprClass:
+ case MemberExprClass:
+ case CXXReinterpretCastExprClass:
+ case CXXConstCastExprClass:
+ case ConditionalOperatorClass:
+ case CompoundLiteralExprClass:
+ case ExtVectorElementExprClass:
+ case InitListExprClass:
+ case DesignatedInitExprClass:
+ case ParenListExprClass:
+ case VAArgExprClass:
+ case CXXDefaultArgExprClass:
+ case ExprWithCleanupsClass:
+ case ObjCIvarRefExprClass:
+ case ObjCIsaExprClass:
+ case ShuffleVectorExprClass:
+ return CanSubExprsThrow(C, this);
+
+ // Some might be dependent for other reasons.
+ case UnaryOperatorClass:
+ case ArraySubscriptExprClass:
+ case ImplicitCastExprClass:
+ case CStyleCastExprClass:
+ case CXXStaticCastExprClass:
+ case CXXFunctionalCastExprClass:
+ case BinaryOperatorClass:
+ case CompoundAssignOperatorClass: {
+ CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot;
+ return MergeCanThrow(CT, CanSubExprsThrow(C, this));
+ }
+
+ // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.
+ case StmtExprClass:
+ return CT_Can;
+
+ case ChooseExprClass:
+ if (isTypeDependent() || isValueDependent())
+ return CT_Dependent;
+ return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C);
+
+ // Some expressions are always dependent.
+ case DependentScopeDeclRefExprClass:
+ case CXXUnresolvedConstructExprClass:
+ case CXXDependentScopeMemberExprClass:
+ return CT_Dependent;
+
+ default:
+ // All other expressions don't have subexpressions, or else they are
+ // unevaluated.
+ return CT_Cannot;
+ }
+}
+
Expr* Expr::IgnoreParens() {
Expr* E = this;
- while (ParenExpr* P = dyn_cast<ParenExpr>(E))
- E = P->getSubExpr();
-
- return E;
+ while (true) {
+ if (ParenExpr* P = dyn_cast<ParenExpr>(E)) {
+ E = P->getSubExpr();
+ continue;
+ }
+ if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
+ if (P->getOpcode() == UO_Extension) {
+ E = P->getSubExpr();
+ continue;
+ }
+ }
+ return E;
+ }
}
/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr
@@ -1324,24 +1832,68 @@ Expr* Expr::IgnoreParens() {
Expr *Expr::IgnoreParenCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E))
+ if (ParenExpr* P = dyn_cast<ParenExpr>(E)) {
E = P->getSubExpr();
- else if (CastExpr *P = dyn_cast<CastExpr>(E))
+ continue;
+ }
+ if (CastExpr *P = dyn_cast<CastExpr>(E)) {
E = P->getSubExpr();
- else
- return E;
+ continue;
+ }
+ if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
+ if (P->getOpcode() == UO_Extension) {
+ E = P->getSubExpr();
+ continue;
+ }
+ }
+ return E;
}
}
+/// IgnoreParenLValueCasts - Ignore parentheses and lvalue-to-rvalue
+/// casts. This is intended purely as a temporary workaround for code
+/// that hasn't yet been rewritten to do the right thing about those
+/// casts, and may disappear along with the last internal use.
+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)) {
+ 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;
+ }
+ }
+ break;
+ }
+ return E;
+}
+
Expr *Expr::IgnoreParenImpCasts() {
Expr *E = this;
while (true) {
- if (ParenExpr *P = dyn_cast<ParenExpr>(E))
+ if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
E = P->getSubExpr();
- else if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E))
+ continue;
+ }
+ if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) {
E = P->getSubExpr();
- else
- return E;
+ continue;
+ }
+ if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
+ if (P->getOpcode() == UO_Extension) {
+ E = P->getSubExpr();
+ continue;
+ }
+ }
+ return E;
}
}
@@ -1366,9 +1918,9 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
continue;
}
- if ((E->getType()->isPointerType() ||
+ if ((E->getType()->isPointerType() ||
E->getType()->isIntegralType(Ctx)) &&
- (SE->getType()->isPointerType() ||
+ (SE->getType()->isPointerType() ||
SE->getType()->isIntegralType(Ctx)) &&
Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SE->getType())) {
E = SE;
@@ -1376,6 +1928,13 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
}
}
+ if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) {
+ if (P->getOpcode() == UO_Extension) {
+ E = P->getSubExpr();
+ continue;
+ }
+ }
+
return E;
}
}
@@ -1390,7 +1949,7 @@ bool Expr::isDefaultArgument() const {
/// \brief Skip over any no-op casts and any temporary-binding
/// expressions.
-static const Expr *skipTemporaryBindingsAndNoOpCasts(const Expr *E) {
+static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) {
while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() == CK_NoOp)
E = ICE->getSubExpr();
@@ -1407,50 +1966,48 @@ static const Expr *skipTemporaryBindingsAndNoOpCasts(const Expr *E) {
else
break;
}
-
- return E;
-}
-const Expr *Expr::getTemporaryObject() const {
- const Expr *E = skipTemporaryBindingsAndNoOpCasts(this);
+ return E->IgnoreParens();
+}
- // A cast can produce a temporary object. The object's construction
- // is represented as a CXXConstructExpr.
- if (const CastExpr *Cast = dyn_cast<CastExpr>(E)) {
- // Only user-defined and constructor conversions can produce
- // temporary objects.
- if (Cast->getCastKind() != CK_ConstructorConversion &&
- Cast->getCastKind() != CK_UserDefinedConversion)
- return 0;
+/// isTemporaryObject - Determines if this expression produces a
+/// temporary of the given class type.
+bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const {
+ if (!C.hasSameUnqualifiedType(getType(), C.getTypeDeclType(TempTy)))
+ return false;
- // Strip off temporary bindings and no-op casts.
- const Expr *Sub = skipTemporaryBindingsAndNoOpCasts(Cast->getSubExpr());
+ const Expr *E = skipTemporaryBindingsNoOpCastsAndParens(this);
- // If this is a constructor conversion, see if we have an object
- // construction.
- if (Cast->getCastKind() == CK_ConstructorConversion)
- return dyn_cast<CXXConstructExpr>(Sub);
+ // Temporaries are by definition pr-values of class type.
+ if (!E->Classify(C).isPRValue()) {
+ // In this context, property reference is a message call and is pr-value.
+ if (!isa<ObjCPropertyRefExpr>(E))
+ return false;
+ }
- // If this is a user-defined conversion, see if we have a call to
- // a function that itself returns a temporary object.
- if (Cast->getCastKind() == CK_UserDefinedConversion)
- if (const CallExpr *CE = dyn_cast<CallExpr>(Sub))
- if (CE->getCallReturnType()->isRecordType())
- return CE;
+ // Black-list a few cases which yield pr-values of class type that don't
+ // refer to temporaries of that type:
- return 0;
+ // - implicit derived-to-base conversions
+ if (isa<ImplicitCastExpr>(E)) {
+ switch (cast<ImplicitCastExpr>(E)->getCastKind()) {
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ return false;
+ default:
+ break;
+ }
}
- // A call returning a class type returns a temporary.
- if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
- if (CE->getCallReturnType()->isRecordType())
- return CE;
+ // - member expressions (all)
+ if (isa<MemberExpr>(E))
+ return false;
- return 0;
- }
+ // - opaque values (all)
+ if (isa<OpaqueValueExpr>(E))
+ return false;
- // Explicit temporary object constructors create temporaries.
- return dyn_cast<CXXTemporaryObjectExpr>(E);
+ return true;
}
/// hasAnyTypeDependentArguments - Determines if any of the expressions
@@ -1533,6 +2090,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()
->isConstantInitializer(Ctx, IsForRef);
+ case ChooseExprClass:
+ return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)
+ ->isConstantInitializer(Ctx, IsForRef);
case UnaryOperatorClass: {
const UnaryOperator* Exp = cast<UnaryOperator>(this);
if (Exp->getOpcode() == UO_Extension)
@@ -1572,11 +2132,14 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
return isEvaluatable(Ctx);
}
-/// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an
-/// integer constant expression with the value zero, or if this is one that is
-/// cast to void*.
-bool Expr::isNullPointerConstant(ASTContext &Ctx,
- NullPointerConstantValueDependence NPC) const {
+/// isNullPointerConstant - C99 6.3.2.3p3 - Return whether this is a null
+/// pointer constant or not, as well as the specific kind of constant detected.
+/// Null pointer constants can be integer constant expressions with the
+/// value zero, casts of zero to void*, nullptr (C++0X), or __null
+/// (a GNU extension).
+Expr::NullPointerConstantKind
+Expr::isNullPointerConstant(ASTContext &Ctx,
+ NullPointerConstantValueDependence NPC) const {
if (isValueDependent()) {
switch (NPC) {
case NPC_NeverValueDependent:
@@ -1584,10 +2147,13 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx,
// If the unthinkable happens, fall through to the safest alternative.
case NPC_ValueDependentIsNull:
- return isTypeDependent() || getType()->isIntegralType(Ctx);
+ if (isTypeDependent() || getType()->isIntegralType(Ctx))
+ return NPCK_ZeroInteger;
+ else
+ return NPCK_NotNull;
case NPC_ValueDependentIsNotNull:
- return false;
+ return NPCK_NotNull;
}
}
@@ -1616,30 +2182,61 @@ bool Expr::isNullPointerConstant(ASTContext &Ctx,
return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC);
} else if (isa<GNUNullExpr>(this)) {
// The GNU __null extension is always a null pointer constant.
- return true;
+ return NPCK_GNUNull;
}
// C++0x nullptr_t is always a null pointer constant.
if (getType()->isNullPtrType())
- return true;
-
+ return NPCK_CXX0X_nullptr;
+
+ if (const RecordType *UT = getType()->getAsUnionType())
+ if (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))
+ return ILE->getInit(0)->isNullPointerConstant(Ctx, NPC);
+ }
// This expression must be an integer type.
if (!getType()->isIntegerType() ||
(Ctx.getLangOptions().CPlusPlus && getType()->isEnumeralType()))
- return false;
+ return NPCK_NotNull;
// If we have an integer constant expression, we need to *evaluate* it and
// test for the value 0.
llvm::APSInt Result;
- return isIntegerConstantExpr(Result, Ctx) && Result == 0;
+ bool IsNull = isIntegerConstantExpr(Result, Ctx) && Result == 0;
+
+ return (IsNull ? NPCK_ZeroInteger : NPCK_NotNull);
+}
+
+/// \brief If this expression is an l-value for an Objective C
+/// property, find the underlying property reference expression.
+const ObjCPropertyRefExpr *Expr::getObjCProperty() const {
+ const Expr *E = this;
+ while (true) {
+ assert((E->getValueKind() == VK_LValue &&
+ E->getObjectKind() == OK_ObjCProperty) &&
+ "expression is not a property reference");
+ E = E->IgnoreParenCasts();
+ if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (BO->getOpcode() == BO_Comma) {
+ E = BO->getRHS();
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ return cast<ObjCPropertyRefExpr>(E);
}
FieldDecl *Expr::getBitField() {
Expr *E = this->IgnoreParens();
while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
- if (ICE->getValueKind() != VK_RValue &&
- ICE->getCastKind() == CK_NoOp)
+ if (ICE->getCastKind() == CK_LValueToRValue ||
+ (ICE->getValueKind() != VK_RValue && ICE->getCastKind() == CK_NoOp))
E = ICE->getSubExpr()->IgnoreParens();
else
break;
@@ -1650,6 +2247,11 @@ FieldDecl *Expr::getBitField() {
if (Field->isBitField())
return Field;
+ if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E))
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(DeclRef->getDecl()))
+ if (Field->isBitField())
+ return Field;
+
if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E))
if (BinOp->isAssignmentOp() && BinOp->getLHS())
return BinOp->getLHS()->getBitField();
@@ -1741,21 +2343,24 @@ void ExtVectorElementExpr::getEncodedElementAccess(
}
ObjCMessageExpr::ObjCMessageExpr(QualType T,
+ ExprValueKind VK,
SourceLocation LBracLoc,
SourceLocation SuperLoc,
bool IsInstanceSuper,
QualType SuperType,
Selector Sel,
+ SourceLocation SelLoc,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc)
- : Expr(ObjCMessageExprClass, T, /*TypeDependent=*/false,
- /*ValueDependent=*/false),
+ : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary,
+ /*TypeDependent=*/false, /*ValueDependent=*/false,
+ /*ContainsUnexpandedParameterPack=*/false),
NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass),
HasMethod(Method != 0), SuperLoc(SuperLoc),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
- LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+ SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
setReceiverPointer(SuperType.getAsOpaquePtr());
if (NumArgs)
@@ -1763,88 +2368,115 @@ ObjCMessageExpr::ObjCMessageExpr(QualType T,
}
ObjCMessageExpr::ObjCMessageExpr(QualType T,
+ ExprValueKind VK,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
- Selector Sel,
+ Selector Sel,
+ SourceLocation SelLoc,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc)
- : Expr(ObjCMessageExprClass, T, T->isDependentType(),
- (T->isDependentType() ||
- hasAnyValueDependentArguments(Args, NumArgs))),
+ : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, T->isDependentType(),
+ T->isDependentType(), T->containsUnexpandedParameterPack()),
NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
- LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+ SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
setReceiverPointer(Receiver);
- if (NumArgs)
- memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
+ Expr **MyArgs = getArgs();
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ if (Args[I]->isTypeDependent())
+ ExprBits.TypeDependent = true;
+ if (Args[I]->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (Args[I]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
+ MyArgs[I] = Args[I];
+ }
}
ObjCMessageExpr::ObjCMessageExpr(QualType T,
+ ExprValueKind VK,
SourceLocation LBracLoc,
Expr *Receiver,
Selector Sel,
+ SourceLocation SelLoc,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc)
- : Expr(ObjCMessageExprClass, T, Receiver->isTypeDependent(),
- (Receiver->isTypeDependent() ||
- hasAnyValueDependentArguments(Args, NumArgs))),
+ : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, Receiver->isTypeDependent(),
+ Receiver->isTypeDependent(),
+ Receiver->containsUnexpandedParameterPack()),
NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0),
SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method
: Sel.getAsOpaquePtr())),
- LBracLoc(LBracLoc), RBracLoc(RBracLoc)
+ SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc)
{
setReceiverPointer(Receiver);
- if (NumArgs)
- memcpy(getArgs(), Args, NumArgs * sizeof(Expr *));
+ Expr **MyArgs = getArgs();
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ if (Args[I]->isTypeDependent())
+ ExprBits.TypeDependent = true;
+ if (Args[I]->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (Args[I]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
+ MyArgs[I] = Args[I];
+ }
}
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ ExprValueKind VK,
SourceLocation LBracLoc,
SourceLocation SuperLoc,
bool IsInstanceSuper,
QualType SuperType,
Selector Sel,
+ SourceLocation SelLoc,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc) {
unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
NumArgs * sizeof(Expr *);
void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
- return new (Mem) ObjCMessageExpr(T, LBracLoc, SuperLoc, IsInstanceSuper,
- SuperType, Sel, Method, Args, NumArgs,
+ return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, SuperLoc, IsInstanceSuper,
+ SuperType, Sel, SelLoc, Method, Args,NumArgs,
RBracLoc);
}
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ ExprValueKind VK,
SourceLocation LBracLoc,
TypeSourceInfo *Receiver,
Selector Sel,
+ SourceLocation SelLoc,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc) {
unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
NumArgs * sizeof(Expr *);
void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
- return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args,
- NumArgs, RBracLoc);
+ return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLoc,
+ Method, Args, NumArgs, RBracLoc);
}
ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T,
+ ExprValueKind VK,
SourceLocation LBracLoc,
Expr *Receiver,
- Selector Sel,
+ Selector Sel,
+ SourceLocation SelLoc,
ObjCMethodDecl *Method,
Expr **Args, unsigned NumArgs,
SourceLocation RBracLoc) {
unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) +
NumArgs * sizeof(Expr *);
void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
- return new (Mem) ObjCMessageExpr(T, LBracLoc, Receiver, Sel, Method, Args,
- NumArgs, RBracLoc);
+ return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLoc,
+ Method, Args, NumArgs, RBracLoc);
}
ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context,
@@ -1854,7 +2486,23 @@ ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context,
void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment);
return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs);
}
-
+
+SourceRange ObjCMessageExpr::getReceiverRange() const {
+ switch (getReceiverKind()) {
+ case Instance:
+ return getInstanceReceiver()->getSourceRange();
+
+ case Class:
+ return getClassReceiverTypeInfo()->getTypeLoc().getSourceRange();
+
+ case SuperInstance:
+ case SuperClass:
+ return getSuperLoc();
+ }
+
+ return SourceLocation();
+}
+
Selector ObjCMessageExpr::getSelector() const {
if (HasMethod)
return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod)
@@ -1883,19 +2531,40 @@ ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const {
break;
case SuperClass:
- if (const ObjCObjectPointerType *Iface
- = getSuperType()->getAs<ObjCObjectPointerType>())
- return Iface->getInterfaceDecl();
+ if (const ObjCObjectType *Iface
+ = getSuperType()->getAs<ObjCObjectType>())
+ return Iface->getInterface();
break;
}
return 0;
}
-bool ChooseExpr::isConditionTrue(ASTContext &C) const {
+bool ChooseExpr::isConditionTrue(const ASTContext &C) const {
return getCond()->EvaluateAsInt(C) != 0;
}
+ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr,
+ QualType Type, SourceLocation BLoc,
+ SourceLocation RP)
+ : Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary,
+ Type->isDependentType(), Type->isDependentType(),
+ Type->containsUnexpandedParameterPack()),
+ BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(nexpr)
+{
+ SubExprs = new (C) Stmt*[nexpr];
+ for (unsigned i = 0; i < nexpr; i++) {
+ if (args[i]->isTypeDependent())
+ ExprBits.TypeDependent = true;
+ if (args[i]->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (args[i]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
+ SubExprs[i] = args[i];
+ }
+}
+
void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs,
unsigned NumExprs) {
if (SubExprs) C.Deallocate(SubExprs);
@@ -1926,13 +2595,15 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
unsigned NumIndexExprs,
Expr *Init)
: Expr(DesignatedInitExprClass, Ty,
- Init->isTypeDependent(), Init->isValueDependent()),
+ Init->getValueKind(), Init->getObjectKind(),
+ Init->isTypeDependent(), Init->isValueDependent(),
+ Init->containsUnexpandedParameterPack()),
EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) {
this->Designators = new (C) Designator[NumDesignators];
// Record the initializer itself.
- child_iterator Child = child_begin();
+ child_range Child = children();
*Child++ = Init;
// Copy the designators and their subexpressions, computing
@@ -1944,8 +2615,12 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
if (this->Designators[I].isArrayDesignator()) {
// Compute type- and value-dependence.
Expr *Index = IndexExprs[IndexIdx];
- ValueDependent = ValueDependent ||
- Index->isTypeDependent() || Index->isValueDependent();
+ if (Index->isTypeDependent() || Index->isValueDependent())
+ ExprBits.ValueDependent = true;
+
+ // Propagate unexpanded parameter packs.
+ if (Index->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
// Copy the index expressions into permanent storage.
*Child++ = IndexExprs[IndexIdx++];
@@ -1953,9 +2628,14 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
// Compute type- and value-dependence.
Expr *Start = IndexExprs[IndexIdx];
Expr *End = IndexExprs[IndexIdx + 1];
- ValueDependent = ValueDependent ||
- Start->isTypeDependent() || Start->isValueDependent() ||
- End->isTypeDependent() || End->isValueDependent();
+ if (Start->isTypeDependent() || Start->isValueDependent() ||
+ End->isTypeDependent() || End->isValueDependent())
+ ExprBits.ValueDependent = true;
+
+ // Propagate unexpanded parameter packs.
+ if (Start->containsUnexpandedParameterPack() ||
+ End->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
// Copy the start/end expressions into permanent storage.
*Child++ = IndexExprs[IndexIdx++];
@@ -2066,14 +2746,30 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
Expr **exprs, unsigned nexprs,
SourceLocation rparenloc)
-: Expr(ParenListExprClass, QualType(),
- hasAnyTypeDependentArguments(exprs, nexprs),
- hasAnyValueDependentArguments(exprs, nexprs)),
- NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) {
+ : Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary,
+ false, false, false),
+ NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) {
Exprs = new (C) Stmt*[nexprs];
- for (unsigned i = 0; i != nexprs; ++i)
+ for (unsigned i = 0; i != nexprs; ++i) {
+ if (exprs[i]->isTypeDependent())
+ ExprBits.TypeDependent = true;
+ if (exprs[i]->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (exprs[i]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
Exprs[i] = exprs[i];
+ }
+}
+
+const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) {
+ if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e))
+ e = ewc->getSubExpr();
+ e = cast<CXXConstructExpr>(e)->getArg(0);
+ while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e))
+ e = ice->getSubExpr();
+ return cast<OpaqueValueExpr>(e);
}
//===----------------------------------------------------------------------===//
@@ -2093,257 +2789,43 @@ const Expr* ConstExprIterator::operator->() const { return cast<Expr>(*I); }
// Child Iterators for iterating over subexpressions/substatements
//===----------------------------------------------------------------------===//
-// DeclRefExpr
-Stmt::child_iterator DeclRefExpr::child_begin() { return child_iterator(); }
-Stmt::child_iterator DeclRefExpr::child_end() { return child_iterator(); }
-
-// ObjCIvarRefExpr
-Stmt::child_iterator ObjCIvarRefExpr::child_begin() { return &Base; }
-Stmt::child_iterator ObjCIvarRefExpr::child_end() { return &Base+1; }
-
-// ObjCPropertyRefExpr
-Stmt::child_iterator ObjCPropertyRefExpr::child_begin() { return &Base; }
-Stmt::child_iterator ObjCPropertyRefExpr::child_end() { return &Base+1; }
-
-// ObjCImplicitSetterGetterRefExpr
-Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_begin() {
- // If this is accessing a class member, skip that entry.
- if (Base) return &Base;
- return &Base+1;
-}
-Stmt::child_iterator ObjCImplicitSetterGetterRefExpr::child_end() {
- return &Base+1;
-}
-
-// ObjCSuperExpr
-Stmt::child_iterator ObjCSuperExpr::child_begin() { return child_iterator(); }
-Stmt::child_iterator ObjCSuperExpr::child_end() { return child_iterator(); }
-
-// ObjCIsaExpr
-Stmt::child_iterator ObjCIsaExpr::child_begin() { return &Base; }
-Stmt::child_iterator ObjCIsaExpr::child_end() { return &Base+1; }
-
-// PredefinedExpr
-Stmt::child_iterator PredefinedExpr::child_begin() { return child_iterator(); }
-Stmt::child_iterator PredefinedExpr::child_end() { return child_iterator(); }
-
-// IntegerLiteral
-Stmt::child_iterator IntegerLiteral::child_begin() { return child_iterator(); }
-Stmt::child_iterator IntegerLiteral::child_end() { return child_iterator(); }
-
-// CharacterLiteral
-Stmt::child_iterator CharacterLiteral::child_begin() { return child_iterator();}
-Stmt::child_iterator CharacterLiteral::child_end() { return child_iterator(); }
-
-// FloatingLiteral
-Stmt::child_iterator FloatingLiteral::child_begin() { return child_iterator(); }
-Stmt::child_iterator FloatingLiteral::child_end() { return child_iterator(); }
-
-// ImaginaryLiteral
-Stmt::child_iterator ImaginaryLiteral::child_begin() { return &Val; }
-Stmt::child_iterator ImaginaryLiteral::child_end() { return &Val+1; }
-
-// StringLiteral
-Stmt::child_iterator StringLiteral::child_begin() { return child_iterator(); }
-Stmt::child_iterator StringLiteral::child_end() { return child_iterator(); }
-
-// ParenExpr
-Stmt::child_iterator ParenExpr::child_begin() { return &Val; }
-Stmt::child_iterator ParenExpr::child_end() { return &Val+1; }
-
-// UnaryOperator
-Stmt::child_iterator UnaryOperator::child_begin() { return &Val; }
-Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; }
-
-// OffsetOfExpr
-Stmt::child_iterator OffsetOfExpr::child_begin() {
- return reinterpret_cast<Stmt **> (reinterpret_cast<OffsetOfNode *> (this + 1)
- + NumComps);
-}
-Stmt::child_iterator OffsetOfExpr::child_end() {
- return child_iterator(&*child_begin() + NumExprs);
-}
-
// SizeOfAlignOfExpr
-Stmt::child_iterator SizeOfAlignOfExpr::child_begin() {
+Stmt::child_range SizeOfAlignOfExpr::children() {
// If this is of a type and the type is a VLA type (and not a typedef), the
// size expression of the VLA needs to be treated as an executable expression.
// Why isn't this weirdness documented better in StmtIterator?
if (isArgumentType()) {
- if (VariableArrayType* T = dyn_cast<VariableArrayType>(
+ if (const VariableArrayType* T = dyn_cast<VariableArrayType>(
getArgumentType().getTypePtr()))
- return child_iterator(T);
- return child_iterator();
+ return child_range(child_iterator(T), child_iterator());
+ return child_range();
}
- return child_iterator(&Argument.Ex);
-}
-Stmt::child_iterator SizeOfAlignOfExpr::child_end() {
- if (isArgumentType())
- return child_iterator();
- return child_iterator(&Argument.Ex + 1);
-}
-
-// ArraySubscriptExpr
-Stmt::child_iterator ArraySubscriptExpr::child_begin() {
- return &SubExprs[0];
-}
-Stmt::child_iterator ArraySubscriptExpr::child_end() {
- return &SubExprs[0]+END_EXPR;
-}
-
-// CallExpr
-Stmt::child_iterator CallExpr::child_begin() {
- return &SubExprs[0];
-}
-Stmt::child_iterator CallExpr::child_end() {
- return &SubExprs[0]+NumArgs+ARGS_START;
-}
-
-// MemberExpr
-Stmt::child_iterator MemberExpr::child_begin() { return &Base; }
-Stmt::child_iterator MemberExpr::child_end() { return &Base+1; }
-
-// ExtVectorElementExpr
-Stmt::child_iterator ExtVectorElementExpr::child_begin() { return &Base; }
-Stmt::child_iterator ExtVectorElementExpr::child_end() { return &Base+1; }
-
-// CompoundLiteralExpr
-Stmt::child_iterator CompoundLiteralExpr::child_begin() { return &Init; }
-Stmt::child_iterator CompoundLiteralExpr::child_end() { return &Init+1; }
-
-// CastExpr
-Stmt::child_iterator CastExpr::child_begin() { return &Op; }
-Stmt::child_iterator CastExpr::child_end() { return &Op+1; }
-
-// BinaryOperator
-Stmt::child_iterator BinaryOperator::child_begin() {
- return &SubExprs[0];
-}
-Stmt::child_iterator BinaryOperator::child_end() {
- return &SubExprs[0]+END_EXPR;
-}
-
-// ConditionalOperator
-Stmt::child_iterator ConditionalOperator::child_begin() {
- return &SubExprs[0];
-}
-Stmt::child_iterator ConditionalOperator::child_end() {
- return &SubExprs[0]+END_EXPR;
-}
-
-// AddrLabelExpr
-Stmt::child_iterator AddrLabelExpr::child_begin() { return child_iterator(); }
-Stmt::child_iterator AddrLabelExpr::child_end() { return child_iterator(); }
-
-// StmtExpr
-Stmt::child_iterator StmtExpr::child_begin() { return &SubStmt; }
-Stmt::child_iterator StmtExpr::child_end() { return &SubStmt+1; }
-
-// TypesCompatibleExpr
-Stmt::child_iterator TypesCompatibleExpr::child_begin() {
- return child_iterator();
-}
-
-Stmt::child_iterator TypesCompatibleExpr::child_end() {
- return child_iterator();
-}
-
-// ChooseExpr
-Stmt::child_iterator ChooseExpr::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator ChooseExpr::child_end() { return &SubExprs[0]+END_EXPR; }
-
-// GNUNullExpr
-Stmt::child_iterator GNUNullExpr::child_begin() { return child_iterator(); }
-Stmt::child_iterator GNUNullExpr::child_end() { return child_iterator(); }
-
-// ShuffleVectorExpr
-Stmt::child_iterator ShuffleVectorExpr::child_begin() {
- return &SubExprs[0];
-}
-Stmt::child_iterator ShuffleVectorExpr::child_end() {
- return &SubExprs[0]+NumExprs;
-}
-
-// VAArgExpr
-Stmt::child_iterator VAArgExpr::child_begin() { return &Val; }
-Stmt::child_iterator VAArgExpr::child_end() { return &Val+1; }
-
-// InitListExpr
-Stmt::child_iterator InitListExpr::child_begin() {
- return InitExprs.size() ? &InitExprs[0] : 0;
-}
-Stmt::child_iterator InitListExpr::child_end() {
- return InitExprs.size() ? &InitExprs[0] + InitExprs.size() : 0;
-}
-
-// DesignatedInitExpr
-Stmt::child_iterator DesignatedInitExpr::child_begin() {
- char* Ptr = static_cast<char*>(static_cast<void *>(this));
- Ptr += sizeof(DesignatedInitExpr);
- return reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
-}
-Stmt::child_iterator DesignatedInitExpr::child_end() {
- return child_iterator(&*child_begin() + NumSubExprs);
-}
-
-// ImplicitValueInitExpr
-Stmt::child_iterator ImplicitValueInitExpr::child_begin() {
- return child_iterator();
-}
-
-Stmt::child_iterator ImplicitValueInitExpr::child_end() {
- return child_iterator();
-}
-
-// ParenListExpr
-Stmt::child_iterator ParenListExpr::child_begin() {
- return &Exprs[0];
-}
-Stmt::child_iterator ParenListExpr::child_end() {
- return &Exprs[0]+NumExprs;
-}
-
-// ObjCStringLiteral
-Stmt::child_iterator ObjCStringLiteral::child_begin() {
- return &String;
-}
-Stmt::child_iterator ObjCStringLiteral::child_end() {
- return &String+1;
-}
-
-// ObjCEncodeExpr
-Stmt::child_iterator ObjCEncodeExpr::child_begin() { return child_iterator(); }
-Stmt::child_iterator ObjCEncodeExpr::child_end() { return child_iterator(); }
-
-// ObjCSelectorExpr
-Stmt::child_iterator ObjCSelectorExpr::child_begin() {
- return child_iterator();
-}
-Stmt::child_iterator ObjCSelectorExpr::child_end() {
- return child_iterator();
-}
-
-// ObjCProtocolExpr
-Stmt::child_iterator ObjCProtocolExpr::child_begin() {
- return child_iterator();
-}
-Stmt::child_iterator ObjCProtocolExpr::child_end() {
- return child_iterator();
+ return child_range(&Argument.Ex, &Argument.Ex + 1);
}
// ObjCMessageExpr
-Stmt::child_iterator ObjCMessageExpr::child_begin() {
+Stmt::child_range ObjCMessageExpr::children() {
+ Stmt **begin;
if (getReceiverKind() == Instance)
- return reinterpret_cast<Stmt **>(this + 1);
- return getArgs();
-}
-Stmt::child_iterator ObjCMessageExpr::child_end() {
- return getArgs() + getNumArgs();
+ begin = reinterpret_cast<Stmt **>(this + 1);
+ else
+ begin = reinterpret_cast<Stmt **>(getArgs());
+ return child_range(begin,
+ reinterpret_cast<Stmt **>(getArgs() + getNumArgs()));
}
// Blocks
-Stmt::child_iterator BlockExpr::child_begin() { return child_iterator(); }
-Stmt::child_iterator BlockExpr::child_end() { return child_iterator(); }
+BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK,
+ SourceLocation l, bool ByRef,
+ bool constAdded)
+ : Expr(BlockDeclRefExprClass, t, VK, OK_Ordinary, false, false,
+ d->isParameterPack()),
+ D(d), Loc(l), IsByRef(ByRef), ConstQualAdded(constAdded)
+{
+ bool TypeDependent = false;
+ bool ValueDependent = false;
+ computeDeclRefDependence(D, getType(), TypeDependent, ValueDependent);
+ ExprBits.TypeDependent = TypeDependent;
+ ExprBits.ValueDependent = ValueDependent;
+}
-Stmt::child_iterator BlockDeclRefExpr::child_begin() { return child_iterator();}
-Stmt::child_iterator BlockDeclRefExpr::child_end() { return child_iterator(); }
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 0a10130..28ff9fb 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -29,57 +29,18 @@ QualType CXXTypeidExpr::getTypeOperand() const {
.getUnqualifiedType();
}
-// CXXTypeidExpr - has child iterators if the operand is an expression
-Stmt::child_iterator CXXTypeidExpr::child_begin() {
- return isTypeOperand() ? child_iterator()
- : reinterpret_cast<Stmt **>(&Operand);
-}
-Stmt::child_iterator CXXTypeidExpr::child_end() {
- return isTypeOperand() ? child_iterator()
- : reinterpret_cast<Stmt **>(&Operand) + 1;
-}
-
-// CXXBoolLiteralExpr
-Stmt::child_iterator CXXBoolLiteralExpr::child_begin() {
- return child_iterator();
-}
-Stmt::child_iterator CXXBoolLiteralExpr::child_end() {
- return child_iterator();
-}
-
-// CXXNullPtrLiteralExpr
-Stmt::child_iterator CXXNullPtrLiteralExpr::child_begin() {
- return child_iterator();
-}
-Stmt::child_iterator CXXNullPtrLiteralExpr::child_end() {
- return child_iterator();
-}
-
-// CXXThisExpr
-Stmt::child_iterator CXXThisExpr::child_begin() { return child_iterator(); }
-Stmt::child_iterator CXXThisExpr::child_end() { return child_iterator(); }
-
-// CXXThrowExpr
-Stmt::child_iterator CXXThrowExpr::child_begin() { return &Op; }
-Stmt::child_iterator CXXThrowExpr::child_end() {
- // If Op is 0, we are processing throw; which has no children.
- return Op ? &Op+1 : &Op;
-}
-
-// CXXDefaultArgExpr
-Stmt::child_iterator CXXDefaultArgExpr::child_begin() {
- return child_iterator();
-}
-Stmt::child_iterator CXXDefaultArgExpr::child_end() {
- return child_iterator();
+QualType CXXUuidofExpr::getTypeOperand() const {
+ assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)");
+ return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType()
+ .getUnqualifiedType();
}
// CXXScalarValueInitExpr
-Stmt::child_iterator CXXScalarValueInitExpr::child_begin() {
- return child_iterator();
-}
-Stmt::child_iterator CXXScalarValueInitExpr::child_end() {
- return child_iterator();
+SourceRange CXXScalarValueInitExpr::getSourceRange() const {
+ SourceLocation Start = RParenLoc;
+ if (TypeInfo)
+ Start = TypeInfo->getTypeLoc().getBeginLoc();
+ return SourceRange(Start, RParenLoc);
}
// CXXNewExpr
@@ -88,22 +49,44 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
SourceRange TypeIdParens, Expr *arraySize,
CXXConstructorDecl *constructor, bool initializer,
Expr **constructorArgs, unsigned numConsArgs,
- FunctionDecl *operatorDelete, QualType ty,
- SourceLocation startLoc, SourceLocation endLoc)
- : Expr(CXXNewExprClass, ty, ty->isDependentType(), ty->isDependentType()),
- GlobalNew(globalNew),
- Initializer(initializer), SubExprs(0), OperatorNew(operatorNew),
+ FunctionDecl *operatorDelete,
+ bool usualArrayDeleteWantsSize, QualType ty,
+ TypeSourceInfo *AllocatedTypeInfo,
+ SourceLocation startLoc, SourceLocation endLoc,
+ SourceLocation constructorLParen,
+ SourceLocation constructorRParen)
+ : Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary,
+ ty->isDependentType(), ty->isDependentType(),
+ ty->containsUnexpandedParameterPack()),
+ GlobalNew(globalNew), Initializer(initializer),
+ UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize),
+ SubExprs(0), OperatorNew(operatorNew),
OperatorDelete(operatorDelete), Constructor(constructor),
- TypeIdParens(TypeIdParens), StartLoc(startLoc), EndLoc(endLoc) {
-
+ AllocatedTypeInfo(AllocatedTypeInfo), TypeIdParens(TypeIdParens),
+ StartLoc(startLoc), EndLoc(endLoc), ConstructorLParen(constructorLParen),
+ ConstructorRParen(constructorRParen) {
AllocateArgsArray(C, arraySize != 0, numPlaceArgs, numConsArgs);
unsigned i = 0;
- if (Array)
+ if (Array) {
+ if (arraySize->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
SubExprs[i++] = arraySize;
- for (unsigned j = 0; j < NumPlacementArgs; ++j)
+ }
+
+ for (unsigned j = 0; j < NumPlacementArgs; ++j) {
+ if (placementArgs[j]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
SubExprs[i++] = placementArgs[j];
- for (unsigned j = 0; j < NumConstructorArgs; ++j)
+ }
+
+ for (unsigned j = 0; j < NumConstructorArgs; ++j) {
+ if (constructorArgs[j]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
SubExprs[i++] = constructorArgs[j];
+ }
}
void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
@@ -118,27 +101,59 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
}
-Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator CXXNewExpr::child_end() {
- return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs();
-}
-
// CXXDeleteExpr
-Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; }
-Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; }
+QualType CXXDeleteExpr::getDestroyedType() const {
+ const Expr *Arg = getArgument();
+ while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
+ if (ICE->getCastKind() != CK_UserDefinedConversion &&
+ ICE->getType()->isVoidPointerType())
+ Arg = ICE->getSubExpr();
+ else
+ break;
+ }
+ // The type-to-delete may not be a pointer if it's a dependent type.
+ const QualType ArgType = Arg->getType();
-// CXXPseudoDestructorExpr
-Stmt::child_iterator CXXPseudoDestructorExpr::child_begin() { return &Base; }
-Stmt::child_iterator CXXPseudoDestructorExpr::child_end() {
- return &Base + 1;
+ if (ArgType->isDependentType() && !ArgType->isPointerType())
+ return QualType();
+
+ return ArgType->getAs<PointerType>()->getPointeeType();
}
+// CXXPseudoDestructorExpr
PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info)
: Type(Info)
{
Location = Info->getTypeLoc().getLocalSourceRange().getBegin();
}
+CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
+ Expr *Base, bool isArrow, SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier, SourceRange QualifierRange,
+ TypeSourceInfo *ScopeType, SourceLocation ColonColonLoc,
+ SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType)
+ : Expr(CXXPseudoDestructorExprClass,
+ Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
+ FunctionProtoType::ExtProtoInfo())),
+ VK_RValue, OK_Ordinary,
+ /*isTypeDependent=*/(Base->isTypeDependent() ||
+ (DestroyedType.getTypeSourceInfo() &&
+ DestroyedType.getTypeSourceInfo()->getType()->isDependentType())),
+ /*isValueDependent=*/Base->isValueDependent(),
+ // ContainsUnexpandedParameterPack
+ (Base->containsUnexpandedParameterPack() ||
+ (Qualifier && Qualifier->containsUnexpandedParameterPack()) ||
+ (ScopeType &&
+ ScopeType->getType()->containsUnexpandedParameterPack()) ||
+ (DestroyedType.getTypeSourceInfo() &&
+ DestroyedType.getTypeSourceInfo()->getType()
+ ->containsUnexpandedParameterPack()))),
+ Base(static_cast<Stmt *>(Base)), IsArrow(isArrow),
+ OperatorLoc(OperatorLoc), Qualifier(Qualifier),
+ QualifierRange(QualifierRange),
+ ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), TildeLoc(TildeLoc),
+ DestroyedType(DestroyedType) { }
+
QualType CXXPseudoDestructorExpr::getDestroyedType() const {
if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo())
return TInfo->getType();
@@ -156,7 +171,7 @@ SourceRange CXXPseudoDestructorExpr::getSourceRange() const {
// UnresolvedLookupExpr
UnresolvedLookupExpr *
-UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
+UnresolvedLookupExpr::Create(ASTContext &C,
CXXRecordDecl *NamingClass,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -168,73 +183,94 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
{
void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) +
ExplicitTemplateArgumentList::sizeFor(Args));
- UnresolvedLookupExpr *ULE
- = new (Mem) UnresolvedLookupExpr(C,
- Dependent ? C.DependentTy : C.OverloadTy,
- Dependent, NamingClass,
- Qualifier, QualifierRange, NameInfo,
- ADL,
- /*Overload*/ true,
- /*ExplicitTemplateArgs*/ true,
- Begin, End);
-
- reinterpret_cast<ExplicitTemplateArgumentList*>(ULE+1)->initializeFrom(Args);
-
- return ULE;
+ return new (Mem) UnresolvedLookupExpr(C, NamingClass,
+ Qualifier, QualifierRange, NameInfo,
+ ADL, /*Overload*/ true, &Args,
+ Begin, End);
}
UnresolvedLookupExpr *
-UnresolvedLookupExpr::CreateEmpty(ASTContext &C, unsigned NumTemplateArgs) {
+UnresolvedLookupExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs,
+ unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedLookupExpr);
- if (NumTemplateArgs != 0)
+ if (HasExplicitTemplateArgs)
size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
- void *Mem = C.Allocate(size, llvm::alignof<UnresolvedLookupExpr>());
+ void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedLookupExpr>());
UnresolvedLookupExpr *E = new (Mem) UnresolvedLookupExpr(EmptyShell());
- E->HasExplicitTemplateArgs = NumTemplateArgs != 0;
+ E->HasExplicitTemplateArgs = HasExplicitTemplateArgs;
return E;
}
-OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, QualType T,
- bool Dependent, NestedNameSpecifier *Qualifier,
- SourceRange QRange,
+OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C,
+ NestedNameSpecifier *Qualifier, SourceRange QRange,
const DeclarationNameInfo &NameInfo,
- bool HasTemplateArgs,
+ const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin,
- UnresolvedSetIterator End)
- : Expr(K, T, Dependent, Dependent),
- Results(0), NumResults(0), NameInfo(NameInfo), Qualifier(Qualifier),
- QualifierRange(QRange), HasExplicitTemplateArgs(HasTemplateArgs)
+ UnresolvedSetIterator End,
+ bool KnownDependent,
+ bool KnownContainsUnexpandedParameterPack)
+ : Expr(K, C.OverloadTy, VK_LValue, OK_Ordinary, KnownDependent,
+ KnownDependent,
+ (KnownContainsUnexpandedParameterPack ||
+ NameInfo.containsUnexpandedParameterPack() ||
+ (Qualifier && Qualifier->containsUnexpandedParameterPack()))),
+ Results(0), NumResults(End - Begin), NameInfo(NameInfo),
+ Qualifier(Qualifier), QualifierRange(QRange),
+ HasExplicitTemplateArgs(TemplateArgs != 0)
{
- initializeResults(C, Begin, End);
-}
-
-void OverloadExpr::initializeResults(ASTContext &C,
- UnresolvedSetIterator Begin,
- UnresolvedSetIterator End) {
- assert(Results == 0 && "Results already initialized!");
NumResults = End - Begin;
if (NumResults) {
+ // Determine whether this expression is type-dependent.
+ for (UnresolvedSetImpl::const_iterator I = Begin; I != End; ++I) {
+ if ((*I)->getDeclContext()->isDependentContext() ||
+ isa<UnresolvedUsingValueDecl>(*I)) {
+ ExprBits.TypeDependent = true;
+ ExprBits.ValueDependent = true;
+ }
+ }
+
Results = static_cast<DeclAccessPair *>(
C.Allocate(sizeof(DeclAccessPair) * NumResults,
- llvm::alignof<DeclAccessPair>()));
+ llvm::alignOf<DeclAccessPair>()));
memcpy(Results, &*Begin.getIterator(),
NumResults * sizeof(DeclAccessPair));
}
-}
-
-bool OverloadExpr::ComputeDependence(UnresolvedSetIterator Begin,
- UnresolvedSetIterator End,
- const TemplateArgumentListInfo *Args) {
- for (UnresolvedSetImpl::const_iterator I = Begin; I != End; ++I)
- if ((*I)->getDeclContext()->isDependentContext())
- return true;
+ // If we have explicit template arguments, check for dependent
+ // template arguments and whether they contain any unexpanded pack
+ // expansions.
+ if (TemplateArgs) {
+ bool Dependent = false;
+ bool ContainsUnexpandedParameterPack = false;
+ getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent,
+ ContainsUnexpandedParameterPack);
+
+ if (Dependent) {
+ ExprBits.TypeDependent = true;
+ ExprBits.ValueDependent = true;
+ }
+ if (ContainsUnexpandedParameterPack)
+ ExprBits.ContainsUnexpandedParameterPack = true;
+ }
- if (Args && TemplateSpecializationType::anyDependentTemplateArguments(*Args))
- return true;
+ if (isTypeDependent())
+ setType(C.DependentTy);
+}
- return false;
+void OverloadExpr::initializeResults(ASTContext &C,
+ UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End) {
+ assert(Results == 0 && "Results already initialized!");
+ NumResults = End - Begin;
+ if (NumResults) {
+ Results = static_cast<DeclAccessPair *>(
+ C.Allocate(sizeof(DeclAccessPair) * NumResults,
+
+ llvm::alignOf<DeclAccessPair>()));
+ memcpy(Results, &*Begin.getIterator(),
+ NumResults * sizeof(DeclAccessPair));
+ }
}
CXXRecordDecl *OverloadExpr::getNamingClass() const {
@@ -244,21 +280,30 @@ CXXRecordDecl *OverloadExpr::getNamingClass() const {
return cast<UnresolvedMemberExpr>(this)->getNamingClass();
}
-Stmt::child_iterator UnresolvedLookupExpr::child_begin() {
- return child_iterator();
-}
-Stmt::child_iterator UnresolvedLookupExpr::child_end() {
- return child_iterator();
-}
-// UnaryTypeTraitExpr
-Stmt::child_iterator UnaryTypeTraitExpr::child_begin() {
- return child_iterator();
-}
-Stmt::child_iterator UnaryTypeTraitExpr::child_end() {
- return child_iterator();
+// DependentScopeDeclRefExpr
+DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ const DeclarationNameInfo &NameInfo,
+ const TemplateArgumentListInfo *Args)
+ : Expr(DependentScopeDeclRefExprClass, T, VK_LValue, OK_Ordinary,
+ true, true,
+ (NameInfo.containsUnexpandedParameterPack() ||
+ (Qualifier && Qualifier->containsUnexpandedParameterPack()))),
+ NameInfo(NameInfo), QualifierRange(QualifierRange), Qualifier(Qualifier),
+ HasExplicitTemplateArgs(Args != 0)
+{
+ if (Args) {
+ bool Dependent = true;
+ bool ContainsUnexpandedParameterPack
+ = ExprBits.ContainsUnexpandedParameterPack;
+
+ reinterpret_cast<ExplicitTemplateArgumentList*>(this+1)
+ ->initializeFrom(*Args, Dependent, ContainsUnexpandedParameterPack);
+ ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
+ }
}
-// DependentScopeDeclRefExpr
DependentScopeDeclRefExpr *
DependentScopeDeclRefExpr::Create(ASTContext &C,
NestedNameSpecifier *Qualifier,
@@ -266,251 +311,46 @@ DependentScopeDeclRefExpr::Create(ASTContext &C,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *Args) {
std::size_t size = sizeof(DependentScopeDeclRefExpr);
- if (Args) size += ExplicitTemplateArgumentList::sizeFor(*Args);
- void *Mem = C.Allocate(size);
-
- DependentScopeDeclRefExpr *DRE
- = new (Mem) DependentScopeDeclRefExpr(C.DependentTy,
- Qualifier, QualifierRange,
- NameInfo, Args != 0);
-
if (Args)
- reinterpret_cast<ExplicitTemplateArgumentList*>(DRE+1)
- ->initializeFrom(*Args);
-
- return DRE;
+ size += ExplicitTemplateArgumentList::sizeFor(*Args);
+ void *Mem = C.Allocate(size);
+ return new (Mem) DependentScopeDeclRefExpr(C.DependentTy,
+ Qualifier, QualifierRange,
+ NameInfo, Args);
}
DependentScopeDeclRefExpr *
DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C,
+ bool HasExplicitTemplateArgs,
unsigned NumTemplateArgs) {
std::size_t size = sizeof(DependentScopeDeclRefExpr);
- if (NumTemplateArgs)
+ if (HasExplicitTemplateArgs)
size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
void *Mem = C.Allocate(size);
-
- return new (Mem) DependentScopeDeclRefExpr(QualType(), 0, SourceRange(),
- DeclarationNameInfo(),
- NumTemplateArgs != 0);
-}
-
-StmtIterator DependentScopeDeclRefExpr::child_begin() {
- return child_iterator();
+ DependentScopeDeclRefExpr *E
+ = new (Mem) DependentScopeDeclRefExpr(QualType(), 0, SourceRange(),
+ DeclarationNameInfo(), 0);
+ E->HasExplicitTemplateArgs = HasExplicitTemplateArgs;
+ return E;
}
-StmtIterator DependentScopeDeclRefExpr::child_end() {
- return child_iterator();
-}
+SourceRange CXXConstructExpr::getSourceRange() const {
+ if (ParenRange.isValid())
+ return SourceRange(Loc, ParenRange.getEnd());
-bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
- switch(UTT) {
- default: assert(false && "Unknown type trait or not implemented");
- case UTT_IsPOD: return QueriedType->isPODType();
- case UTT_IsLiteral: return QueriedType->isLiteralType();
- case UTT_IsClass: // Fallthrough
- case UTT_IsUnion:
- if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
- bool Union = Record->getDecl()->isUnion();
- return UTT == UTT_IsUnion ? Union : !Union;
- }
- return false;
- case UTT_IsEnum: return QueriedType->isEnumeralType();
- case UTT_IsPolymorphic:
- if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
- // Type traits are only parsed in C++, so we've got CXXRecords.
- return cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic();
- }
- return false;
- case UTT_IsAbstract:
- if (const RecordType *RT = QueriedType->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->isAbstract();
- return false;
- case UTT_IsEmpty:
- if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
- return !Record->getDecl()->isUnion()
- && cast<CXXRecordDecl>(Record->getDecl())->isEmpty();
- }
- return false;
- case UTT_HasTrivialConstructor:
- // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
- // If __is_pod (type) is true then the trait is true, else if type is
- // a cv class or union type (or array thereof) with a trivial default
- // constructor ([class.ctor]) then the trait is true, else it is false.
- if (QueriedType->isPODType())
- return true;
- if (const RecordType *RT =
- C.getBaseElementType(QueriedType)->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor();
- return false;
- case UTT_HasTrivialCopy:
- // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
- // If __is_pod (type) is true or type is a reference type then
- // the trait is true, else if type is a cv class or union type
- // with a trivial copy constructor ([class.copy]) then the trait
- // is true, else it is false.
- if (QueriedType->isPODType() || QueriedType->isReferenceType())
- return true;
- if (const RecordType *RT = QueriedType->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyConstructor();
- return false;
- case UTT_HasTrivialAssign:
- // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
- // If type is const qualified or is a reference type then the
- // trait is false. Otherwise if __is_pod (type) is true then the
- // trait is true, else if type is a cv class or union type with
- // a trivial copy assignment ([class.copy]) then the trait is
- // true, else it is false.
- // Note: the const and reference restrictions are interesting,
- // given that const and reference members don't prevent a class
- // from having a trivial copy assignment operator (but do cause
- // errors if the copy assignment operator is actually used, q.v.
- // [class.copy]p12).
-
- if (C.getBaseElementType(QueriedType).isConstQualified())
- return false;
- if (QueriedType->isPODType())
- return true;
- if (const RecordType *RT = QueriedType->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialCopyAssignment();
- return false;
- case UTT_HasTrivialDestructor:
- // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
- // If __is_pod (type) is true or type is a reference type
- // then the trait is true, else if type is a cv class or union
- // type (or array thereof) with a trivial destructor
- // ([class.dtor]) then the trait is true, else it is
- // false.
- if (QueriedType->isPODType() || QueriedType->isReferenceType())
- return true;
- if (const RecordType *RT =
- C.getBaseElementType(QueriedType)->getAs<RecordType>())
- return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor();
- return false;
- // TODO: Propagate nothrowness for implicitly declared special members.
- case UTT_HasNothrowAssign:
- // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
- // If type is const qualified or is a reference type then the
- // trait is false. Otherwise if __has_trivial_assign (type)
- // is true then the trait is true, else if type is a cv class
- // or union type with copy assignment operators that are known
- // not to throw an exception then the trait is true, else it is
- // false.
- if (C.getBaseElementType(QueriedType).isConstQualified())
- return false;
- if (QueriedType->isReferenceType())
- return false;
- if (QueriedType->isPODType())
- return true;
- if (const RecordType *RT = QueriedType->getAs<RecordType>()) {
- CXXRecordDecl* RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialCopyAssignment())
- return true;
-
- bool FoundAssign = false;
- bool AllNoThrow = true;
- DeclarationName Name = C.DeclarationNames.getCXXOperatorName(OO_Equal);
- DeclContext::lookup_const_iterator Op, OpEnd;
- for (llvm::tie(Op, OpEnd) = RD->lookup(Name);
- Op != OpEnd; ++Op) {
- CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op);
- if (Operator->isCopyAssignmentOperator()) {
- FoundAssign = true;
- const FunctionProtoType *CPT
- = Operator->getType()->getAs<FunctionProtoType>();
- if (!CPT->hasEmptyExceptionSpec()) {
- AllNoThrow = false;
- break;
- }
- }
+ SourceLocation End = Loc;
+ for (unsigned I = getNumArgs(); I > 0; --I) {
+ const Expr *Arg = getArg(I-1);
+ if (!Arg->isDefaultArgument()) {
+ SourceLocation NewEnd = Arg->getLocEnd();
+ if (NewEnd.isValid()) {
+ End = NewEnd;
+ break;
}
-
- return FoundAssign && AllNoThrow;
}
- return false;
- case UTT_HasNothrowCopy:
- // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
- // If __has_trivial_copy (type) is true then the trait is true, else
- // if type is a cv class or union type with copy constructors that are
- // known not to throw an exception then the trait is true, else it is
- // false.
- if (QueriedType->isPODType() || QueriedType->isReferenceType())
- return true;
- if (const RecordType *RT = QueriedType->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialCopyConstructor())
- return true;
-
- bool FoundConstructor = false;
- bool AllNoThrow = true;
- unsigned FoundTQs;
- DeclarationName ConstructorName
- = C.DeclarationNames.getCXXConstructorName(
- C.getCanonicalType(QueriedType));
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = RD->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
- if (Constructor->isCopyConstructor(FoundTQs)) {
- FoundConstructor = true;
- const FunctionProtoType *CPT
- = Constructor->getType()->getAs<FunctionProtoType>();
- if (!CPT->hasEmptyExceptionSpec()) {
- AllNoThrow = false;
- break;
- }
- }
- }
-
- return FoundConstructor && AllNoThrow;
- }
- return false;
- case UTT_HasNothrowConstructor:
- // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
- // If __has_trivial_constructor (type) is true then the trait is
- // true, else if type is a cv class or union type (or array
- // thereof) with a default constructor that is known not to
- // throw an exception then the trait is true, else it is false.
- if (QueriedType->isPODType())
- return true;
- if (const RecordType *RT =
- C.getBaseElementType(QueriedType)->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->hasTrivialConstructor())
- return true;
-
- if (CXXConstructorDecl *Constructor = RD->getDefaultConstructor()) {
- const FunctionProtoType *CPT
- = Constructor->getType()->getAs<FunctionProtoType>();
- // TODO: check whether evaluating default arguments can throw.
- // For now, we'll be conservative and assume that they can throw.
- if (CPT->hasEmptyExceptionSpec() && CPT->getNumArgs() == 0)
- return true;
- }
- }
- return false;
- case UTT_HasVirtualDestructor:
- // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
- // If type is a class type with a virtual destructor ([class.dtor])
- // then the trait is true, else it is false.
- if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- if (CXXDestructorDecl *Destructor = RD->getDestructor())
- return Destructor->isVirtual();
- }
- return false;
}
-}
-SourceRange CXXConstructExpr::getSourceRange() const {
- // FIXME: Should we know where the parentheses are, if there are any?
- for (std::reverse_iterator<Stmt**> I(&Args[NumArgs]), E(&Args[0]); I!=E;++I) {
- // Ignore CXXDefaultExprs when computing the range, as they don't
- // have a range.
- if (!isa<CXXDefaultArgExpr>(*I))
- return SourceRange(Loc, (*I)->getLocEnd());
- }
-
- return SourceRange(Loc);
+ return SourceRange(Loc, End);
}
SourceRange CXXOperatorCallExpr::getSourceRange() const {
@@ -546,6 +386,17 @@ Expr *CXXMemberCallExpr::getImplicitObjectArgument() {
return 0;
}
+CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() {
+ Expr* ThisArg = getImplicitObjectArgument();
+ if (!ThisArg)
+ return 0;
+
+ if (ThisArg->getType()->isAnyPointerType())
+ return ThisArg->getType()->getPointeeType()->getAsCXXRecordDecl();
+
+ return ThisArg->getType()->getAsCXXRecordDecl();
+}
+
SourceRange CXXMemberCallExpr::getSourceRange() const {
SourceLocation LocStart = getCallee()->getLocStart();
if (LocStart.isInvalid() && getNumArgs() > 0)
@@ -572,15 +423,18 @@ const char *CXXNamedCastExpr::getCastName() const {
}
CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T,
+ ExprValueKind VK,
CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
- SourceLocation L) {
+ SourceLocation L,
+ SourceLocation RParenLoc) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(sizeof(CXXStaticCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXStaticCastExpr *E =
- new (Buffer) CXXStaticCastExpr(T, K, Op, PathSize, WrittenTy, L);
+ new (Buffer) CXXStaticCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
+ RParenLoc);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -593,15 +447,18 @@ CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(ASTContext &C,
}
CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T,
+ ExprValueKind VK,
CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
- SourceLocation L) {
+ SourceLocation L,
+ SourceLocation RParenLoc) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(sizeof(CXXDynamicCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXDynamicCastExpr *E =
- new (Buffer) CXXDynamicCastExpr(T, K, Op, PathSize, WrittenTy, L);
+ new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
+ RParenLoc);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -614,14 +471,17 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C,
}
CXXReinterpretCastExpr *
-CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, CastKind K, Expr *Op,
+CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
+ CastKind K, Expr *Op,
const CXXCastPath *BasePath,
- TypeSourceInfo *WrittenTy, SourceLocation L) {
+ TypeSourceInfo *WrittenTy, SourceLocation L,
+ SourceLocation RParenLoc) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer =
C.Allocate(sizeof(CXXReinterpretCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
CXXReinterpretCastExpr *E =
- new (Buffer) CXXReinterpretCastExpr(T, K, Op, PathSize, WrittenTy, L);
+ new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
+ RParenLoc);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -633,10 +493,12 @@ CXXReinterpretCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) {
return new (Buffer) CXXReinterpretCastExpr(EmptyShell(), PathSize);
}
-CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T, Expr *Op,
+CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T,
+ ExprValueKind VK, Expr *Op,
TypeSourceInfo *WrittenTy,
- SourceLocation L) {
- return new (C) CXXConstCastExpr(T, Op, WrittenTy, L);
+ SourceLocation L,
+ SourceLocation RParenLoc) {
+ return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc);
}
CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) {
@@ -644,7 +506,7 @@ CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) {
}
CXXFunctionalCastExpr *
-CXXFunctionalCastExpr::Create(ASTContext &C, QualType T,
+CXXFunctionalCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
TypeSourceInfo *Written, SourceLocation L,
CastKind K, Expr *Op, const CXXCastPath *BasePath,
SourceLocation R) {
@@ -652,7 +514,7 @@ CXXFunctionalCastExpr::Create(ASTContext &C, QualType T,
void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXFunctionalCastExpr *E =
- new (Buffer) CXXFunctionalCastExpr(T, Written, L, K, Op, PathSize, R);
+ new (Buffer) CXXFunctionalCastExpr(T, VK, Written, L, K, Op, PathSize, R);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -689,15 +551,22 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C,
CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
CXXConstructorDecl *Cons,
- QualType writtenTy,
- SourceLocation tyBeginLoc,
+ TypeSourceInfo *Type,
Expr **Args,
unsigned NumArgs,
- SourceLocation rParenLoc,
+ SourceRange parenRange,
bool ZeroInitialization)
- : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, tyBeginLoc,
- Cons, false, Args, NumArgs, ZeroInitialization),
- TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {
+ : CXXConstructExpr(C, CXXTemporaryObjectExprClass,
+ Type->getType().getNonReferenceType(),
+ Type->getTypeLoc().getBeginLoc(),
+ Cons, false, Args, NumArgs, ZeroInitialization,
+ CXXConstructExpr::CK_Complete, parenRange),
+ Type(Type) {
+}
+
+SourceRange CXXTemporaryObjectExpr::getSourceRange() const {
+ return SourceRange(Type->getTypeLoc().getBeginLoc(),
+ getParenRange().getEnd());
}
CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
@@ -705,10 +574,11 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
CXXConstructorDecl *D, bool Elidable,
Expr **Args, unsigned NumArgs,
bool ZeroInitialization,
- ConstructionKind ConstructKind) {
+ ConstructionKind ConstructKind,
+ SourceRange ParenRange) {
return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D,
Elidable, Args, NumArgs, ZeroInitialization,
- ConstructKind);
+ ConstructKind, ParenRange);
}
CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
@@ -716,31 +586,39 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T,
CXXConstructorDecl *D, bool elidable,
Expr **args, unsigned numargs,
bool ZeroInitialization,
- ConstructionKind ConstructKind)
-: Expr(SC, T,
- T->isDependentType(),
- (T->isDependentType() ||
- CallExpr::hasAnyValueDependentArguments(args, numargs))),
- Constructor(D), Loc(Loc), Elidable(elidable),
- ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind),
- Args(0), NumArgs(numargs)
+ ConstructionKind ConstructKind,
+ SourceRange ParenRange)
+ : Expr(SC, T, VK_RValue, OK_Ordinary,
+ T->isDependentType(), T->isDependentType(),
+ T->containsUnexpandedParameterPack()),
+ Constructor(D), Loc(Loc), ParenRange(ParenRange), Elidable(elidable),
+ ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind),
+ Args(0), NumArgs(numargs)
{
if (NumArgs) {
Args = new (C) Stmt*[NumArgs];
for (unsigned i = 0; i != NumArgs; ++i) {
assert(args[i] && "NULL argument in CXXConstructExpr");
+
+ if (args[i]->isValueDependent())
+ ExprBits.ValueDependent = true;
+ if (args[i]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
Args[i] = args[i];
}
}
}
-CXXExprWithTemporaries::CXXExprWithTemporaries(ASTContext &C,
- Expr *subexpr,
- CXXTemporary **temps,
- unsigned numtemps)
- : Expr(CXXExprWithTemporariesClass, subexpr->getType(),
- subexpr->isTypeDependent(), subexpr->isValueDependent()),
+ExprWithCleanups::ExprWithCleanups(ASTContext &C,
+ Expr *subexpr,
+ CXXTemporary **temps,
+ unsigned numtemps)
+ : Expr(ExprWithCleanupsClass, subexpr->getType(),
+ subexpr->getValueKind(), subexpr->getObjectKind(),
+ subexpr->isTypeDependent(), subexpr->isValueDependent(),
+ subexpr->containsUnexpandedParameterPack()),
SubExpr(subexpr), Temps(0), NumTemps(0) {
if (numtemps) {
setNumTemporaries(C, numtemps);
@@ -749,75 +627,53 @@ CXXExprWithTemporaries::CXXExprWithTemporaries(ASTContext &C,
}
}
-void CXXExprWithTemporaries::setNumTemporaries(ASTContext &C, unsigned N) {
+void ExprWithCleanups::setNumTemporaries(ASTContext &C, unsigned N) {
assert(Temps == 0 && "Cannot resize with this");
NumTemps = N;
Temps = new (C) CXXTemporary*[NumTemps];
}
-CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C,
- Expr *SubExpr,
- CXXTemporary **Temps,
- unsigned NumTemps) {
- return new (C) CXXExprWithTemporaries(C, SubExpr, Temps, NumTemps);
+ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C,
+ Expr *SubExpr,
+ CXXTemporary **Temps,
+ unsigned NumTemps) {
+ return new (C) ExprWithCleanups(C, SubExpr, Temps, NumTemps);
}
-// CXXBindTemporaryExpr
-Stmt::child_iterator CXXBindTemporaryExpr::child_begin() {
- return &SubExpr;
-}
-
-Stmt::child_iterator CXXBindTemporaryExpr::child_end() {
- return &SubExpr + 1;
-}
-
-// CXXConstructExpr
-Stmt::child_iterator CXXConstructExpr::child_begin() {
- return &Args[0];
-}
-Stmt::child_iterator CXXConstructExpr::child_end() {
- return &Args[0]+NumArgs;
-}
-
-// CXXExprWithTemporaries
-Stmt::child_iterator CXXExprWithTemporaries::child_begin() {
- return &SubExpr;
-}
-
-Stmt::child_iterator CXXExprWithTemporaries::child_end() {
- return &SubExpr + 1;
-}
-
-CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(
- SourceLocation TyBeginLoc,
- QualType T,
+CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type,
SourceLocation LParenLoc,
Expr **Args,
unsigned NumArgs,
SourceLocation RParenLoc)
- : Expr(CXXUnresolvedConstructExprClass, T.getNonReferenceType(),
- T->isDependentType(), true),
- TyBeginLoc(TyBeginLoc),
- Type(T),
+ : Expr(CXXUnresolvedConstructExprClass,
+ Type->getType().getNonReferenceType(),
+ VK_LValue, OK_Ordinary,
+ Type->getType()->isDependentType(), true,
+ Type->getType()->containsUnexpandedParameterPack()),
+ Type(Type),
LParenLoc(LParenLoc),
RParenLoc(RParenLoc),
NumArgs(NumArgs) {
Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1);
- memcpy(StoredArgs, Args, sizeof(Expr *) * NumArgs);
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ if (Args[I]->containsUnexpandedParameterPack())
+ ExprBits.ContainsUnexpandedParameterPack = true;
+
+ StoredArgs[I] = Args[I];
+ }
}
CXXUnresolvedConstructExpr *
CXXUnresolvedConstructExpr::Create(ASTContext &C,
- SourceLocation TyBegin,
- QualType T,
+ TypeSourceInfo *Type,
SourceLocation LParenLoc,
Expr **Args,
unsigned NumArgs,
SourceLocation RParenLoc) {
void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) +
sizeof(Expr *) * NumArgs);
- return new (Mem) CXXUnresolvedConstructExpr(TyBegin, T, LParenLoc,
+ return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc,
Args, NumArgs, RParenLoc);
}
@@ -829,12 +685,8 @@ CXXUnresolvedConstructExpr::CreateEmpty(ASTContext &C, unsigned NumArgs) {
return new (Mem) CXXUnresolvedConstructExpr(Empty, NumArgs);
}
-Stmt::child_iterator CXXUnresolvedConstructExpr::child_begin() {
- return child_iterator(reinterpret_cast<Stmt **>(this + 1));
-}
-
-Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() {
- return child_iterator(reinterpret_cast<Stmt **>(this + 1) + NumArgs);
+SourceRange CXXUnresolvedConstructExpr::getSourceRange() const {
+ return SourceRange(Type->getTypeLoc().getBeginLoc(), RParenLoc);
}
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
@@ -846,17 +698,46 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
NamedDecl *FirstQualifierFoundInScope,
DeclarationNameInfo MemberNameInfo,
const TemplateArgumentListInfo *TemplateArgs)
- : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true),
+ : Expr(CXXDependentScopeMemberExprClass, C.DependentTy,
+ VK_LValue, OK_Ordinary, true, true,
+ ((Base && Base->containsUnexpandedParameterPack()) ||
+ (Qualifier && Qualifier->containsUnexpandedParameterPack()) ||
+ MemberNameInfo.containsUnexpandedParameterPack())),
Base(Base), BaseType(BaseType), IsArrow(IsArrow),
HasExplicitTemplateArgs(TemplateArgs != 0),
OperatorLoc(OperatorLoc),
Qualifier(Qualifier), QualifierRange(QualifierRange),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
MemberNameInfo(MemberNameInfo) {
- if (TemplateArgs)
- getExplicitTemplateArgs().initializeFrom(*TemplateArgs);
+ if (TemplateArgs) {
+ bool Dependent = true;
+ bool ContainsUnexpandedParameterPack = false;
+ getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent,
+ ContainsUnexpandedParameterPack);
+ if (ContainsUnexpandedParameterPack)
+ ExprBits.ContainsUnexpandedParameterPack = true;
+ }
}
+CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
+ Expr *Base, QualType BaseType,
+ bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ NamedDecl *FirstQualifierFoundInScope,
+ DeclarationNameInfo MemberNameInfo)
+ : Expr(CXXDependentScopeMemberExprClass, C.DependentTy,
+ VK_LValue, OK_Ordinary, true, true,
+ ((Base && Base->containsUnexpandedParameterPack()) ||
+ (Qualifier && Qualifier->containsUnexpandedParameterPack()) ||
+ MemberNameInfo.containsUnexpandedParameterPack())),
+ Base(Base), BaseType(BaseType), IsArrow(IsArrow),
+ HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc),
+ Qualifier(Qualifier), QualifierRange(QualifierRange),
+ FirstQualifierFoundInScope(FirstQualifierFoundInScope),
+ MemberNameInfo(MemberNameInfo) { }
+
CXXDependentScopeMemberExpr *
CXXDependentScopeMemberExpr::Create(ASTContext &C,
Expr *Base, QualType BaseType, bool IsArrow,
@@ -877,7 +758,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
if (TemplateArgs)
size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
- void *Mem = C.Allocate(size, llvm::alignof<CXXDependentScopeMemberExpr>());
+ void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType,
IsArrow, OperatorLoc,
Qualifier, QualifierRange,
@@ -887,8 +768,9 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
CXXDependentScopeMemberExpr *
CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
+ bool HasExplicitTemplateArgs,
unsigned NumTemplateArgs) {
- if (NumTemplateArgs == 0)
+ if (!HasExplicitTemplateArgs)
return new (C) CXXDependentScopeMemberExpr(C, 0, QualType(),
0, SourceLocation(), 0,
SourceRange(), 0,
@@ -896,7 +778,7 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
std::size_t size = sizeof(CXXDependentScopeMemberExpr) +
ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
- void *Mem = C.Allocate(size, llvm::alignof<CXXDependentScopeMemberExpr>());
+ void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>());
CXXDependentScopeMemberExpr *E
= new (Mem) CXXDependentScopeMemberExpr(C, 0, QualType(),
0, SourceLocation(), 0,
@@ -906,18 +788,7 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C,
return E;
}
-Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() {
- return child_iterator(&Base);
-}
-
-Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() {
- if (isImplicitAccess())
- return child_iterator(&Base);
- return child_iterator(&Base + 1);
-}
-
-UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, QualType T,
- bool Dependent,
+UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType,
bool IsArrow,
@@ -928,17 +799,21 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, QualType T,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin,
UnresolvedSetIterator End)
- : OverloadExpr(UnresolvedMemberExprClass, C, T, Dependent,
+ : OverloadExpr(UnresolvedMemberExprClass, C,
Qualifier, QualifierRange, MemberNameInfo,
- TemplateArgs != 0, Begin, End),
+ TemplateArgs, Begin, End,
+ // Dependent
+ ((Base && Base->isTypeDependent()) ||
+ BaseType->isDependentType()),
+ // Contains unexpanded parameter pack
+ ((Base && Base->containsUnexpandedParameterPack()) ||
+ BaseType->containsUnexpandedParameterPack())),
IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) {
- if (TemplateArgs)
- getExplicitTemplateArgs().initializeFrom(*TemplateArgs);
}
UnresolvedMemberExpr *
-UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
+UnresolvedMemberExpr::Create(ASTContext &C,
bool HasUnresolvedUsing,
Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
@@ -952,23 +827,23 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
if (TemplateArgs)
size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
- void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>());
+ void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>());
return new (Mem) UnresolvedMemberExpr(C,
- Dependent ? C.DependentTy : C.OverloadTy,
- Dependent, HasUnresolvedUsing, Base, BaseType,
+ HasUnresolvedUsing, Base, BaseType,
IsArrow, OperatorLoc, Qualifier, QualifierRange,
MemberNameInfo, TemplateArgs, Begin, End);
}
UnresolvedMemberExpr *
-UnresolvedMemberExpr::CreateEmpty(ASTContext &C, unsigned NumTemplateArgs) {
+UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs,
+ unsigned NumTemplateArgs) {
std::size_t size = sizeof(UnresolvedMemberExpr);
- if (NumTemplateArgs != 0)
+ if (HasExplicitTemplateArgs)
size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
- void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>());
+ void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>());
UnresolvedMemberExpr *E = new (Mem) UnresolvedMemberExpr(EmptyShell());
- E->HasExplicitTemplateArgs = NumTemplateArgs != 0;
+ E->HasExplicitTemplateArgs = HasExplicitTemplateArgs;
return E;
}
@@ -980,7 +855,7 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
// lookup.
CXXRecordDecl *Record = 0;
if (getQualifier()) {
- Type *T = getQualifier()->getAsType();
+ const Type *T = getQualifier()->getAsType();
assert(T && "qualifier in member expression does not name type");
Record = T->getAsCXXRecordDecl();
assert(Record && "qualifier in member expression does not name record");
@@ -1001,12 +876,18 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const {
return Record;
}
-Stmt::child_iterator UnresolvedMemberExpr::child_begin() {
- return child_iterator(&Base);
-}
+SubstNonTypeTemplateParmPackExpr::
+SubstNonTypeTemplateParmPackExpr(QualType T,
+ NonTypeTemplateParmDecl *Param,
+ SourceLocation NameLoc,
+ const TemplateArgument &ArgPack)
+ : Expr(SubstNonTypeTemplateParmPackExprClass, T, VK_RValue, OK_Ordinary,
+ true, false, true),
+ Param(Param), Arguments(ArgPack.pack_begin()),
+ NumArguments(ArgPack.pack_size()), NameLoc(NameLoc) { }
-Stmt::child_iterator UnresolvedMemberExpr::child_end() {
- if (isImplicitAccess())
- return child_iterator(&Base);
- return child_iterator(&Base + 1);
+TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const {
+ return TemplateArgument(Arguments, NumArguments);
}
+
+
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index d7e38eb..890898a 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -29,10 +29,27 @@ static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T);
static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E);
static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E);
static Cl::Kinds ClassifyConditional(ASTContext &Ctx,
- const ConditionalOperator *E);
+ const Expr *trueExpr,
+ const Expr *falseExpr);
static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
Cl::Kinds Kind, SourceLocation &Loc);
+static Cl::Kinds ClassifyExprValueKind(const LangOptions &Lang,
+ const Expr *E,
+ ExprValueKind Kind) {
+ switch (Kind) {
+ case VK_RValue:
+ return Lang.CPlusPlus && E->getType()->isRecordType() ?
+ Cl::CL_ClassTemporary : Cl::CL_PRValue;
+ case VK_LValue:
+ return Cl::CL_LValue;
+ case VK_XValue:
+ return Cl::CL_XValue;
+ }
+ llvm_unreachable("Invalid value category of implicit cast.");
+ return Cl::CL_PRValue;
+}
+
Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
assert(!TR->isReferenceType() && "Expressions can't have reference type.");
@@ -48,6 +65,19 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
kind = Cl::CL_Void;
}
+ // Enable this assertion for testing.
+ switch (kind) {
+ case Cl::CL_LValue: assert(getValueKind() == VK_LValue); break;
+ case Cl::CL_XValue: assert(getValueKind() == VK_XValue); break;
+ case Cl::CL_Function:
+ case Cl::CL_Void:
+ case Cl::CL_DuplicateVectorComponents:
+ case Cl::CL_MemberFunction:
+ case Cl::CL_SubObjCPropertySetting:
+ case Cl::CL_ClassTemporary:
+ case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break;
+ }
+
Cl::ModifiableType modifiable = Cl::CM_Untested;
if (Loc)
modifiable = IsModifiable(Ctx, this, kind, *Loc);
@@ -60,7 +90,13 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
switch (E->getStmtClass()) {
// First come the expressions that are always lvalues, unconditionally.
-
+ case Stmt::NoStmtClass:
+#define ABSTRACT_STMT(Kind)
+#define STMT(Kind, Base) case Expr::Kind##Class:
+#define EXPR(Kind, Base)
+#include "clang/AST/StmtNodes.inc"
+ llvm_unreachable("cannot classify a statement");
+ break;
case Expr::ObjCIsaExprClass:
// C++ [expr.prim.general]p1: A string literal is an lvalue.
case Expr::StringLiteralClass:
@@ -70,20 +106,56 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::PredefinedExprClass:
// Property references are lvalues
case Expr::ObjCPropertyRefExprClass:
- case Expr::ObjCImplicitSetterGetterRefExprClass:
// C++ [expr.typeid]p1: The result of a typeid expression is an lvalue of...
case Expr::CXXTypeidExprClass:
// Unresolved lookups get classified as lvalues.
// FIXME: Is this wise? Should they get their own kind?
case Expr::UnresolvedLookupExprClass:
case Expr::UnresolvedMemberExprClass:
+ case Expr::CXXDependentScopeMemberExprClass:
+ case Expr::CXXUnresolvedConstructExprClass:
+ case Expr::DependentScopeDeclRefExprClass:
// ObjC instance variables are lvalues
// FIXME: ObjC++0x might have different rules
case Expr::ObjCIvarRefExprClass:
+ return Cl::CL_LValue;
// C99 6.5.2.5p5 says that compound literals are lvalues.
- // FIXME: C++ might have a different opinion.
+ // In C++, they're class temporaries.
case Expr::CompoundLiteralExprClass:
- return Cl::CL_LValue;
+ return Ctx.getLangOptions().CPlusPlus? Cl::CL_ClassTemporary
+ : Cl::CL_LValue;
+
+ // Expressions that are prvalues.
+ case Expr::CXXBoolLiteralExprClass:
+ case Expr::CXXPseudoDestructorExprClass:
+ case Expr::SizeOfAlignOfExprClass:
+ case Expr::CXXNewExprClass:
+ case Expr::CXXThisExprClass:
+ case Expr::CXXNullPtrLiteralExprClass:
+ case Expr::ImaginaryLiteralClass:
+ case Expr::GNUNullExprClass:
+ case Expr::OffsetOfExprClass:
+ case Expr::CXXThrowExprClass:
+ case Expr::ShuffleVectorExprClass:
+ case Expr::IntegerLiteralClass:
+ case Expr::CharacterLiteralClass:
+ case Expr::AddrLabelExprClass:
+ case Expr::CXXDeleteExprClass:
+ case Expr::ImplicitValueInitExprClass:
+ case Expr::BlockExprClass:
+ case Expr::FloatingLiteralClass:
+ case Expr::CXXNoexceptExprClass:
+ case Expr::CXXScalarValueInitExprClass:
+ case Expr::UnaryTypeTraitExprClass:
+ case Expr::BinaryTypeTraitExprClass:
+ case Expr::ObjCSelectorExprClass:
+ case Expr::ObjCProtocolExprClass:
+ case Expr::ObjCStringLiteralClass:
+ case Expr::ParenListExprClass:
+ case Expr::InitListExprClass:
+ case Expr::SizeOfPackExprClass:
+ case Expr::SubstNonTypeTemplateParmPackExprClass:
+ return Cl::CL_PRValue;
// Next come the complicated cases.
@@ -115,11 +187,22 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return Cl::CL_LValue;
// GNU extensions, simply look through them.
- case UO_Real:
- case UO_Imag:
case UO_Extension:
return ClassifyInternal(Ctx, cast<UnaryOperator>(E)->getSubExpr());
+ // Treat _Real and _Imag basically as if they were member
+ // expressions: l-value only if the operand is a true l-value.
+ case UO_Real:
+ case UO_Imag: {
+ const Expr *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens();
+ Cl::Kinds K = ClassifyInternal(Ctx, Op);
+ if (K != Cl::CL_LValue) return K;
+
+ if (isa<ObjCPropertyRefExpr>(Op))
+ return Cl::CL_SubObjCPropertySetting;
+ return Cl::CL_LValue;
+ }
+
// C++ [expr.pre.incr]p1: The result is the updated operand; it is an
// lvalue, [...]
// Not so in C.
@@ -131,19 +214,15 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
return Cl::CL_PRValue;
}
+ case Expr::OpaqueValueExprClass:
+ return ClassifyExprValueKind(Lang, E,
+ cast<OpaqueValueExpr>(E)->getValueKind());
+
// Implicit casts are lvalues if they're lvalue casts. Other than that, we
// only specifically record class temporaries.
case Expr::ImplicitCastExprClass:
- switch (cast<ImplicitCastExpr>(E)->getValueKind()) {
- case VK_RValue:
- return Lang.CPlusPlus && E->getType()->isRecordType() ?
- Cl::CL_ClassTemporary : Cl::CL_PRValue;
- case VK_LValue:
- return Cl::CL_LValue;
- case VK_XValue:
- return Cl::CL_XValue;
- }
- llvm_unreachable("Invalid value category of implicit cast.");
+ return ClassifyExprValueKind(Lang, E,
+ cast<ImplicitCastExpr>(E)->getValueKind());
// C++ [expr.prim.general]p4: The presence of parentheses does not affect
// whether the expression is an lvalue.
@@ -160,6 +239,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CallExprClass:
case Expr::CXXOperatorCallExprClass:
case Expr::CXXMemberCallExprClass:
+ case Expr::CUDAKernelCallExprClass:
return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType());
// __builtin_choose_expr is equivalent to the chosen expression.
@@ -180,9 +260,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXBindTemporaryExprClass:
return ClassifyInternal(Ctx, cast<CXXBindTemporaryExpr>(E)->getSubExpr());
- // And the temporary lifetime guard.
- case Expr::CXXExprWithTemporariesClass:
- return ClassifyInternal(Ctx, cast<CXXExprWithTemporaries>(E)->getSubExpr());
+ // And the cleanups guard.
+ case Expr::ExprWithCleanupsClass:
+ return ClassifyInternal(Ctx, cast<ExprWithCleanups>(E)->getSubExpr());
// Casts depend completely on the target type. All casts work the same.
case Expr::CStyleCastExprClass:
@@ -195,10 +275,18 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
if (!Lang.CPlusPlus) return Cl::CL_PRValue;
return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten());
- case Expr::ConditionalOperatorClass:
+ case Expr::BinaryConditionalOperatorClass: {
+ if (!Lang.CPlusPlus) return Cl::CL_PRValue;
+ const BinaryConditionalOperator *co = cast<BinaryConditionalOperator>(E);
+ return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr());
+ }
+
+ case Expr::ConditionalOperatorClass: {
// Once again, only C++ is interesting.
if (!Lang.CPlusPlus) return Cl::CL_PRValue;
- return ClassifyConditional(Ctx, cast<ConditionalOperator>(E));
+ const ConditionalOperator *co = cast<ConditionalOperator>(E);
+ return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr());
+ }
// ObjC message sends are effectively function calls, if the target function
// is known.
@@ -207,17 +295,35 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
cast<ObjCMessageExpr>(E)->getMethodDecl()) {
return ClassifyUnnamed(Ctx, Method->getResultType());
}
-
+ return Cl::CL_PRValue;
+
// Some C++ expressions are always class temporaries.
case Expr::CXXConstructExprClass:
case Expr::CXXTemporaryObjectExprClass:
- case Expr::CXXScalarValueInitExprClass:
return Cl::CL_ClassTemporary;
- // Everything we haven't handled is a prvalue.
- default:
+ case Expr::VAArgExprClass:
+ return ClassifyUnnamed(Ctx, E->getType());
+
+ case Expr::DesignatedInitExprClass:
+ return ClassifyInternal(Ctx, cast<DesignatedInitExpr>(E)->getInit());
+
+ case Expr::StmtExprClass: {
+ const CompoundStmt *S = cast<StmtExpr>(E)->getSubStmt();
+ if (const Expr *LastExpr = dyn_cast_or_null<Expr>(S->body_back()))
+ return ClassifyUnnamed(Ctx, LastExpr->getType());
return Cl::CL_PRValue;
}
+
+ case Expr::CXXUuidofExprClass:
+ return Cl::CL_LValue;
+
+ case Expr::PackExpansionExprClass:
+ return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
+ }
+
+ llvm_unreachable("unhandled expression kind in classification");
+ return Cl::CL_LValue;
}
/// ClassifyDecl - Return the classification of an expression referencing the
@@ -239,6 +345,7 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) {
islvalue = NTTParm->getType()->isReferenceType();
else
islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) ||
+ isa<IndirectFieldDecl>(D) ||
(Ctx.getLangOptions().CPlusPlus &&
(isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)));
@@ -274,9 +381,8 @@ static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) {
if (E->isArrow())
return Cl::CL_LValue;
// ObjC property accesses are not lvalues, but get special treatment.
- Expr *Base = E->getBase();
- if (isa<ObjCPropertyRefExpr>(Base) ||
- isa<ObjCImplicitSetterGetterRefExpr>(Base))
+ Expr *Base = E->getBase()->IgnoreParens();
+ if (isa<ObjCPropertyRefExpr>(Base))
return Cl::CL_SubObjCPropertySetting;
return ClassifyInternal(Ctx, Base);
}
@@ -301,6 +407,9 @@ static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) {
// *E1 is an lvalue
if (E->isArrow())
return Cl::CL_LValue;
+ Expr *Base = E->getBase()->IgnoreParenImpCasts();
+ if (isa<ObjCPropertyRefExpr>(Base))
+ return Cl::CL_SubObjCPropertySetting;
return ClassifyInternal(Ctx, E->getBase());
}
@@ -320,8 +429,10 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) {
assert(Ctx.getLangOptions().CPlusPlus &&
"This is only relevant for C++.");
// C++ [expr.ass]p1: All [...] return an lvalue referring to the left operand.
+ // Except we override this for writes to ObjC properties.
if (E->isAssignmentOp())
- return Cl::CL_LValue;
+ return (E->getLHS()->getObjectKind() == OK_ObjCProperty
+ ? Cl::CL_PRValue : Cl::CL_LValue);
// C++ [expr.comma]p1: the result is of the same value category as its right
// operand, [...].
@@ -345,13 +456,11 @@ static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) {
return Cl::CL_PRValue;
}
-static Cl::Kinds ClassifyConditional(ASTContext &Ctx,
- const ConditionalOperator *E) {
+static Cl::Kinds ClassifyConditional(ASTContext &Ctx, const Expr *True,
+ const Expr *False) {
assert(Ctx.getLangOptions().CPlusPlus &&
"This is only relevant for C++.");
- Expr *True = E->getTrueExpr();
- Expr *False = E->getFalseExpr();
// C++ [expr.cond]p2
// If either the second or the third operand has type (cv) void, [...]
// the result [...] is a prvalue.
@@ -375,9 +484,10 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
if (Kind == Cl::CL_PRValue) {
// For the sake of better diagnostics, we want to specifically recognize
// use of the GCC cast-as-lvalue extension.
- if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E->IgnoreParens())){
- if (CE->getSubExpr()->Classify(Ctx).isLValue()) {
- Loc = CE->getLParenLoc();
+ if (const ExplicitCastExpr *CE =
+ dyn_cast<ExplicitCastExpr>(E->IgnoreParens())) {
+ if (CE->getSubExpr()->IgnoreParenImpCasts()->isLValue()) {
+ Loc = CE->getExprLoc();
return Cl::CM_LValueCast;
}
}
@@ -401,9 +511,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
// Assignment to a property in ObjC is an implicit setter access. But a
// setter might not exist.
- if (const ObjCImplicitSetterGetterRefExpr *Expr =
- dyn_cast<ObjCImplicitSetterGetterRefExpr>(E)) {
- if (Expr->getSetterMethod() == 0)
+ if (const ObjCPropertyRefExpr *Expr = dyn_cast<ObjCPropertyRefExpr>(E)) {
+ if (Expr->isImplicitProperty() && Expr->getImplicitPropertySetter() == 0)
return Cl::CM_NoSetterProperty;
}
@@ -420,7 +529,8 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
// Records with any const fields (recursively) are not modifiable.
if (const RecordType *R = CT->getAs<RecordType>()) {
- assert(!Ctx.getLangOptions().CPlusPlus &&
+ assert((E->getObjectKind() == OK_ObjCProperty ||
+ !Ctx.getLangOptions().CPlusPlus) &&
"C++ struct assignment should be resolved by the "
"copy assignment operator.");
if (R->hasConstFields())
@@ -430,7 +540,7 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E,
return Cl::CM_Modifiable;
}
-Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
+Expr::LValueClassification Expr::ClassifyLValue(ASTContext &Ctx) const {
Classification VC = Classify(Ctx);
switch (VC.getKind()) {
case Cl::CL_LValue: return LV_Valid;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 7347f5a..656bb99 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -43,12 +43,20 @@ using llvm::APFloat;
/// evaluate the expression regardless of what the RHS is, but C only allows
/// certain things in certain situations.
struct EvalInfo {
- ASTContext &Ctx;
+ const ASTContext &Ctx;
/// EvalResult - Contains information about the evaluation.
Expr::EvalResult &EvalResult;
- EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult)
+ llvm::DenseMap<const OpaqueValueExpr*, APValue> OpaqueValues;
+ const APValue *getOpaqueValue(const OpaqueValueExpr *e) {
+ llvm::DenseMap<const OpaqueValueExpr*, APValue>::iterator
+ i = OpaqueValues.find(e);
+ if (i == OpaqueValues.end()) return 0;
+ return &i->second;
+ }
+
+ EvalInfo(const ASTContext &ctx, Expr::EvalResult& evalresult)
: Ctx(ctx), EvalResult(evalresult) {}
};
@@ -73,12 +81,24 @@ namespace {
APSInt &getComplexIntReal() { return IntReal; }
APSInt &getComplexIntImag() { return IntImag; }
- void moveInto(APValue &v) {
+ void moveInto(APValue &v) const {
if (isComplexFloat())
v = APValue(FloatReal, FloatImag);
else
v = APValue(IntReal, IntImag);
}
+ void setFrom(const APValue &v) {
+ assert(v.isComplexFloat() || v.isComplexInt());
+ if (v.isComplexFloat()) {
+ makeComplexFloat();
+ FloatReal = v.getComplexFloatReal();
+ FloatImag = v.getComplexFloatImag();
+ } else {
+ makeComplexInt();
+ IntReal = v.getComplexIntReal();
+ IntImag = v.getComplexIntImag();
+ }
+ }
};
struct LValue {
@@ -88,12 +108,18 @@ namespace {
Expr *getLValueBase() { return Base; }
CharUnits getLValueOffset() { return Offset; }
- void moveInto(APValue &v) {
+ void moveInto(APValue &v) const {
v = APValue(Base, Offset);
}
+ void setFrom(const APValue &v) {
+ assert(v.isLValue());
+ Base = v.getLValueBase();
+ Offset = v.getLValueOffset();
+ }
};
}
+static bool Evaluate(EvalInfo &info, const Expr *E);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info);
@@ -192,7 +218,7 @@ static bool HandleConversionToBool(const Expr* E, bool& Result,
}
static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
- APFloat &Value, ASTContext &Ctx) {
+ APFloat &Value, const ASTContext &Ctx) {
unsigned DestWidth = Ctx.getIntWidth(DestType);
// Determine whether we are converting to unsigned or signed.
bool DestSigned = DestType->isSignedIntegerType();
@@ -206,7 +232,7 @@ static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
}
static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType,
- APFloat &Value, ASTContext &Ctx) {
+ APFloat &Value, const ASTContext &Ctx) {
bool ignored;
APFloat Result = Value;
Result.convert(Ctx.getFloatTypeSemantics(DestType),
@@ -215,18 +241,18 @@ static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType,
}
static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType,
- APSInt &Value, ASTContext &Ctx) {
+ APSInt &Value, const ASTContext &Ctx) {
unsigned DestWidth = Ctx.getIntWidth(DestType);
APSInt Result = Value;
// Figure out if this is a truncate, extend or noop cast.
// If the input is signed, do a sign extend, noop, or truncate.
- Result.extOrTrunc(DestWidth);
+ Result = Result.extOrTrunc(DestWidth);
Result.setIsUnsigned(DestType->isUnsignedIntegerType());
return Result;
}
static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
- APSInt &Value, ASTContext &Ctx) {
+ APSInt &Value, const ASTContext &Ctx) {
APFloat Result(Ctx.getFloatTypeSemantics(DestType), 1);
Result.convertFromAPInt(Value, Value.isSigned(),
@@ -291,8 +317,34 @@ public:
if (Visit(E->getInit(i))) return true;
return false;
}
+
+ bool VisitSizeOfPackExpr(SizeOfPackExpr *) { return false; }
};
+class OpaqueValueEvaluation {
+ EvalInfo &info;
+ OpaqueValueExpr *opaqueValue;
+
+public:
+ OpaqueValueEvaluation(EvalInfo &info, OpaqueValueExpr *opaqueValue,
+ Expr *value)
+ : info(info), opaqueValue(opaqueValue) {
+
+ // If evaluation fails, fail immediately.
+ if (!Evaluate(info, value)) {
+ this->opaqueValue = 0;
+ return;
+ }
+ info.OpaqueValues[opaqueValue] = info.EvalResult.Val;
+ }
+
+ bool hasError() const { return opaqueValue == 0; }
+
+ ~OpaqueValueEvaluation() {
+ if (opaqueValue) info.OpaqueValues.erase(opaqueValue);
+ }
+};
+
} // end anonymous namespace
//===----------------------------------------------------------------------===//
@@ -402,7 +454,7 @@ bool LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
break;
}
- Result.Offset += CharUnits::fromQuantity(RL.getFieldOffset(i) / 8);
+ Result.Offset += Info.Ctx.toCharUnitsFromBits(RL.getFieldOffset(i));
return true;
}
@@ -460,17 +512,20 @@ public:
{ return Success(E); }
bool VisitCallExpr(CallExpr *E);
bool VisitBlockExpr(BlockExpr *E) {
- if (!E->hasBlockDeclRefExprs())
+ if (!E->getBlockDecl()->hasCaptures())
return Success(E);
return false;
}
bool VisitImplicitValueInitExpr(ImplicitValueInitExpr *E)
{ return Success((Expr*)0); }
+ bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
bool VisitConditionalOperator(ConditionalOperator *E);
bool VisitChooseExpr(ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
bool VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E)
{ return Success((Expr*)0); }
+
+ bool VisitOpaqueValueExpr(OpaqueValueExpr *E);
// FIXME: Missing: @protocol, @selector
};
} // end anonymous namespace
@@ -532,35 +587,6 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
default:
break;
- case CK_Unknown: {
- // FIXME: The handling for CK_Unknown is ugly/shouldn't be necessary!
-
- // Check for pointer->pointer cast
- if (SubExpr->getType()->isPointerType() ||
- SubExpr->getType()->isObjCObjectPointerType() ||
- SubExpr->getType()->isNullPtrType() ||
- SubExpr->getType()->isBlockPointerType())
- return Visit(SubExpr);
-
- if (SubExpr->getType()->isIntegralOrEnumerationType()) {
- APValue Value;
- if (!EvaluateIntegerOrLValue(SubExpr, Value, Info))
- break;
-
- if (Value.isInt()) {
- Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
- Result.Base = 0;
- Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue());
- return true;
- } else {
- Result.Base = Value.getLValueBase();
- Result.Offset = Value.getLValueOffset();
- return true;
- }
- }
- break;
- }
-
case CK_NoOp:
case CK_BitCast:
case CK_LValueBitCast:
@@ -568,13 +594,54 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
case CK_AnyPointerToBlockPointerCast:
return Visit(SubExpr);
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase: {
+ LValue BaseLV;
+ if (!EvaluatePointer(E->getSubExpr(), BaseLV, Info))
+ return false;
+
+ // Now figure out the necessary offset to add to the baseLV to get from
+ // the derived class to the base class.
+ CharUnits Offset = CharUnits::Zero();
+
+ QualType Ty = E->getSubExpr()->getType();
+ const CXXRecordDecl *DerivedDecl =
+ Ty->getAs<PointerType>()->getPointeeType()->getAsCXXRecordDecl();
+
+ for (CastExpr::path_const_iterator PathI = E->path_begin(),
+ PathE = E->path_end(); PathI != PathE; ++PathI) {
+ const CXXBaseSpecifier *Base = *PathI;
+
+ // FIXME: If the base is virtual, we'd need to determine the type of the
+ // most derived class and we don't support that right now.
+ if (Base->isVirtual())
+ return false;
+
+ const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl();
+ const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl);
+
+ Offset += Layout.getBaseClassOffset(BaseDecl);
+ DerivedDecl = BaseDecl;
+ }
+
+ Result.Base = BaseLV.getLValueBase();
+ Result.Offset = BaseLV.getLValueOffset() + Offset;
+ return true;
+ }
+
+ case CK_NullToPointer: {
+ Result.Base = 0;
+ Result.Offset = CharUnits::Zero();
+ return true;
+ }
+
case CK_IntegralToPointer: {
APValue Value;
if (!EvaluateIntegerOrLValue(SubExpr, Value, Info))
break;
if (Value.isInt()) {
- Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
+ Value.getInt() = Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
Result.Base = 0;
Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue());
return true;
@@ -602,6 +669,26 @@ bool PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
return false;
}
+bool PointerExprEvaluator::VisitOpaqueValueExpr(OpaqueValueExpr *e) {
+ const APValue *value = Info.getOpaqueValue(e);
+ if (!value)
+ return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
+ Result.setFrom(*value);
+ return true;
+}
+
+bool PointerExprEvaluator::
+VisitBinaryConditionalOperator(BinaryConditionalOperator *e) {
+ OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
+ if (opaque.hasError()) return false;
+
+ bool cond;
+ if (!HandleConversionToBool(e->getCond(), cond, Info))
+ return false;
+
+ return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
+}
+
bool PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
bool BoolResult;
if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
@@ -718,8 +805,7 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
llvm::SmallVector<APValue, 4> Elts;
for (unsigned i = 0; i != NElts; ++i) {
- APSInt Tmp = Init;
- Tmp.extOrTrunc(EltWidth);
+ APSInt Tmp = Init.extOrTrunc(EltWidth);
if (EltTy->isIntegerType())
Elts.push_back(APValue(Tmp));
@@ -898,15 +984,14 @@ public:
bool VisitCharacterLiteral(const CharacterLiteral *E) {
return Success(E->getValue(), E);
}
- bool VisitTypesCompatibleExpr(const TypesCompatibleExpr *E) {
- // Per gcc docs "this built-in function ignores top level
- // qualifiers". We need to use the canonical version to properly
- // be able to strip CRV qualifiers from the type.
- QualType T0 = Info.Ctx.getCanonicalType(E->getArgType1());
- QualType T1 = Info.Ctx.getCanonicalType(E->getArgType2());
- return Success(Info.Ctx.typesAreCompatible(T0.getUnqualifiedType(),
- T1.getUnqualifiedType()),
- E);
+
+ bool VisitOpaqueValueExpr(OpaqueValueExpr *e) {
+ const APValue *value = Info.getOpaqueValue(e);
+ if (!value) {
+ if (e->getSourceExpr()) return Visit(e->getSourceExpr());
+ return Error(e->getExprLoc(), diag::note_invalid_subexpr_in_ice, e);
+ }
+ return Success(value->getInt(), e);
}
bool CheckReferencedDecl(const Expr *E, const Decl *D);
@@ -927,6 +1012,7 @@ public:
bool VisitOffsetOfExpr(const OffsetOfExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitConditionalOperator(const ConditionalOperator *E);
+ bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E);
bool VisitCastExpr(CastExpr* E);
bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
@@ -948,7 +1034,11 @@ public:
}
bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) {
- return Success(E->EvaluateTrait(Info.Ctx), E);
+ return Success(E->getValue(), E);
+ }
+
+ bool VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *E) {
+ return Success(E->getValue(), E);
}
bool VisitChooseExpr(const ChooseExpr *E) {
@@ -958,6 +1048,9 @@ public:
bool VisitUnaryReal(const UnaryOperator *E);
bool VisitUnaryImag(const UnaryOperator *E);
+ bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
+ bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
+
private:
CharUnits GetAlignOfExpr(const Expr *E);
CharUnits GetAlignOfType(QualType T);
@@ -1018,7 +1111,6 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
}
VD->setEvaluatedValue(APValue());
- return false;
}
}
}
@@ -1160,6 +1252,24 @@ bool IntExprEvaluator::VisitCallExpr(CallExpr *E) {
case Builtin::BI__builtin_expect:
return Visit(E->getArg(0));
+
+ case Builtin::BIstrlen:
+ 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 (StringLiteral *S
+ = dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) {
+ // The string literal may have embedded null characters. Find the first
+ // one and truncate there.
+ llvm::StringRef Str = S->getString();
+ llvm::StringRef::size_type Pos = Str.find(0);
+ if (Pos != llvm::StringRef::npos)
+ Str = Str.substr(0, Pos);
+
+ return Success(Str.size(), E);
+ }
+
+ return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E);
}
}
@@ -1403,12 +1513,25 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E);
return Success(Result.getInt() % RHS, E);
case BO_Shl: {
- // FIXME: Warn about out of range shift amounts!
- unsigned SA =
- (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
+ // During constant-folding, a negative shift is an opposite shift.
+ if (RHS.isSigned() && RHS.isNegative()) {
+ RHS = -RHS;
+ goto shift_right;
+ }
+
+ shift_left:
+ unsigned SA
+ = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
return Success(Result.getInt() << SA, E);
}
case BO_Shr: {
+ // During constant-folding, a negative shift is an opposite shift.
+ if (RHS.isSigned() && RHS.isNegative()) {
+ RHS = -RHS;
+ goto shift_left;
+ }
+
+ shift_right:
unsigned SA =
(unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
return Success(Result.getInt() >> SA, E);
@@ -1423,6 +1546,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
}
}
+bool IntExprEvaluator::
+VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) {
+ OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
+ if (opaque.hasError()) return false;
+
+ bool cond;
+ if (!HandleConversionToBool(e->getCond(), cond, Info))
+ return false;
+
+ return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
+}
+
bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
bool Cond;
if (!HandleConversionToBool(E->getCond(), Cond, Info))
@@ -1439,12 +1574,9 @@ CharUnits IntExprEvaluator::GetAlignOfType(QualType T) {
if (const ReferenceType *Ref = T->getAs<ReferenceType>())
T = Ref->getPointeeType();
- // Get information about the alignment.
- unsigned CharSize = Info.Ctx.Target.getCharWidth();
-
// __alignof is defined to return the preferred alignment.
- return CharUnits::fromQuantity(
- Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize);
+ return Info.Ctx.toCharUnitsFromBits(
+ Info.Ctx.getPreferredTypeAlign(T.getTypePtr()));
}
CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
@@ -1527,17 +1659,9 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
return false;
RecordDecl *RD = RT->getDecl();
const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD);
- unsigned i = 0;
- // FIXME: It would be nice if we didn't have to loop here!
- for (RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end();
- Field != FieldEnd; (void)++Field, ++i) {
- if (*Field == MemberDecl)
- break;
- }
+ unsigned i = MemberDecl->getFieldIndex();
assert(i < RL.getFieldCount() && "offsetof field in wrong type");
- Result += CharUnits::fromQuantity(
- RL.getFieldOffset(i) / Info.Ctx.getCharWidth());
+ Result += Info.Ctx.toCharUnitsFromBits(RL.getFieldOffset(i));
CurrentType = MemberDecl->getType().getNonReferenceType();
break;
}
@@ -1565,9 +1689,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) {
return false;
// Add the offset to the base.
- Result += CharUnits::fromQuantity(
- RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl()))
- / Info.Ctx.getCharWidth());
+ Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl()));
break;
}
}
@@ -1723,6 +1845,14 @@ bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
return Success(0, E);
}
+bool IntExprEvaluator::VisitSizeOfPackExpr(const SizeOfPackExpr *E) {
+ return Success(E->getPackLength(), E);
+}
+
+bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
+ return Success(E->getValue(), E);
+}
+
//===----------------------------------------------------------------------===//
// Float Evaluation
//===----------------------------------------------------------------------===//
@@ -1749,6 +1879,7 @@ public:
bool VisitCastExpr(CastExpr *E);
bool VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E);
bool VisitConditionalOperator(ConditionalOperator *E);
+ bool VisitBinaryConditionalOperator(BinaryConditionalOperator *E);
bool VisitChooseExpr(const ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
@@ -1757,6 +1888,16 @@ public:
bool VisitUnaryReal(const UnaryOperator *E);
bool VisitUnaryImag(const UnaryOperator *E);
+ bool VisitDeclRefExpr(const DeclRefExpr *E);
+
+ bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) {
+ const APValue *value = Info.getOpaqueValue(e);
+ if (!value)
+ return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
+ Result = value->getFloat();
+ return true;
+ }
+
// FIXME: Missing: array subscript of vector, member of vector,
// ImplicitValueInitExpr
};
@@ -1767,7 +1908,7 @@ static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E));
}
-static bool TryEvaluateBuiltinNaN(ASTContext &Context,
+static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
QualType ResultTy,
const Expr *Arg,
bool SNaN,
@@ -1844,6 +1985,45 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
}
+bool FloatExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
+ const Decl *D = E->getDecl();
+ if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D)) return false;
+ const VarDecl *VD = cast<VarDecl>(D);
+
+ // Require the qualifiers to be const and not volatile.
+ CanQualType T = Info.Ctx.getCanonicalType(E->getType());
+ if (!T.isConstQualified() || T.isVolatileQualified())
+ return false;
+
+ const Expr *Init = VD->getAnyInitializer();
+ if (!Init) return false;
+
+ if (APValue *V = VD->getEvaluatedValue()) {
+ if (V->isFloat()) {
+ Result = V->getFloat();
+ return true;
+ }
+ return false;
+ }
+
+ if (VD->isEvaluatingValue())
+ return false;
+
+ VD->setEvaluatingValue();
+
+ Expr::EvalResult InitResult;
+ if (Init->Evaluate(InitResult, Info.Ctx) && !InitResult.HasSideEffects &&
+ InitResult.Val.isFloat()) {
+ // Cache the evaluated value in the variable declaration.
+ Result = InitResult.Val.getFloat();
+ VD->setEvaluatedValue(InitResult.Val);
+ return true;
+ }
+
+ VD->setEvaluatedValue(APValue());
+ return false;
+}
+
bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
if (E->getSubExpr()->getType()->isAnyComplexType()) {
ComplexValue CV;
@@ -1902,6 +2082,10 @@ bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
return true;
}
+ // We can't evaluate pointer-to-member operations.
+ if (E->isPtrMemOp())
+ return false;
+
// FIXME: Diagnostics? I really don't understand how the warnings
// and errors are supposed to work.
APFloat RHS(0.0);
@@ -1950,7 +2134,14 @@ bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) {
Result, Info.Ctx);
return true;
}
- // FIXME: Handle complex types
+
+ if (E->getCastKind() == CK_FloatingComplexToReal) {
+ ComplexValue V;
+ if (!EvaluateComplex(SubExpr, V, Info))
+ return false;
+ Result = V.getComplexFloatReal();
+ return true;
+ }
return false;
}
@@ -1960,6 +2151,18 @@ bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E)
return true;
}
+bool FloatExprEvaluator::
+VisitBinaryConditionalOperator(BinaryConditionalOperator *e) {
+ OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
+ if (opaque.hasError()) return false;
+
+ bool cond;
+ if (!HandleConversionToBool(e->getCond(), cond, Info))
+ return false;
+
+ return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
+}
+
bool FloatExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
bool Cond;
if (!HandleConversionToBool(E->getCond(), Cond, Info))
@@ -1997,12 +2200,21 @@ public:
bool VisitCastExpr(CastExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
+ bool VisitUnaryOperator(const UnaryOperator *E);
+ bool VisitConditionalOperator(const ConditionalOperator *E);
+ bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E);
bool VisitChooseExpr(const ChooseExpr *E)
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
bool VisitUnaryExtension(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
- // FIXME Missing: unary +/-/~, binary div, ImplicitValueInitExpr,
- // conditional ?:, comma
+ bool VisitOpaqueValueExpr(const OpaqueValueExpr *e) {
+ const APValue *value = Info.getOpaqueValue(e);
+ if (!value)
+ return (e->getSourceExpr() ? Visit(e->getSourceExpr()) : false);
+ Result.setFrom(*value);
+ return true;
+ }
+ // FIXME Missing: ImplicitValueInitExpr
};
} // end anonymous namespace
@@ -2038,99 +2250,143 @@ bool ComplexExprEvaluator::VisitImaginaryLiteral(ImaginaryLiteral *E) {
}
bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) {
- Expr* SubExpr = E->getSubExpr();
- QualType EltType = E->getType()->getAs<ComplexType>()->getElementType();
- QualType SubType = SubExpr->getType();
- if (SubType->isRealFloatingType()) {
+ switch (E->getCastKind()) {
+ case CK_BitCast:
+ case CK_LValueBitCast:
+ case CK_BaseToDerived:
+ case CK_DerivedToBase:
+ case CK_UncheckedDerivedToBase:
+ case CK_Dynamic:
+ case CK_ToUnion:
+ case CK_ArrayToPointerDecay:
+ case CK_FunctionToPointerDecay:
+ case CK_NullToPointer:
+ case CK_NullToMemberPointer:
+ case CK_BaseToDerivedMemberPointer:
+ case CK_DerivedToBaseMemberPointer:
+ case CK_MemberPointerToBoolean:
+ case CK_ConstructorConversion:
+ case CK_IntegralToPointer:
+ case CK_PointerToIntegral:
+ case CK_PointerToBoolean:
+ case CK_ToVoid:
+ case CK_VectorSplat:
+ case CK_IntegralCast:
+ case CK_IntegralToBoolean:
+ case CK_IntegralToFloating:
+ case CK_FloatingToIntegral:
+ case CK_FloatingToBoolean:
+ case CK_FloatingCast:
+ case CK_AnyPointerToObjCPointerCast:
+ case CK_AnyPointerToBlockPointerCast:
+ case CK_ObjCObjectLValueCast:
+ case CK_FloatingComplexToReal:
+ case CK_FloatingComplexToBoolean:
+ case CK_IntegralComplexToReal:
+ case CK_IntegralComplexToBoolean:
+ llvm_unreachable("invalid cast kind for complex value");
+
+ case CK_LValueToRValue:
+ case CK_NoOp:
+ return Visit(E->getSubExpr());
+
+ case CK_Dependent:
+ case CK_GetObjCProperty:
+ case CK_UserDefinedConversion:
+ return false;
+
+ case CK_FloatingRealToComplex: {
APFloat &Real = Result.FloatReal;
- if (!EvaluateFloat(SubExpr, Real, Info))
+ if (!EvaluateFloat(E->getSubExpr(), Real, Info))
return false;
- if (EltType->isRealFloatingType()) {
- Result.makeComplexFloat();
- Real = HandleFloatToFloatCast(EltType, SubType, Real, Info.Ctx);
- Result.FloatImag = APFloat(Real.getSemantics());
- return true;
- } else {
- Result.makeComplexInt();
- Result.IntReal = HandleFloatToIntCast(EltType, SubType, Real, Info.Ctx);
- Result.IntImag = APSInt(Result.IntReal.getBitWidth(),
- !Result.IntReal.isSigned());
- return true;
- }
- } else if (SubType->isIntegerType()) {
+ Result.makeComplexFloat();
+ Result.FloatImag = APFloat(Real.getSemantics());
+ return true;
+ }
+
+ case CK_FloatingComplexCast: {
+ if (!Visit(E->getSubExpr()))
+ return false;
+
+ QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType From
+ = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
+
+ Result.FloatReal
+ = HandleFloatToFloatCast(To, From, Result.FloatReal, Info.Ctx);
+ Result.FloatImag
+ = HandleFloatToFloatCast(To, From, Result.FloatImag, Info.Ctx);
+ return true;
+ }
+
+ case CK_FloatingComplexToIntegralComplex: {
+ if (!Visit(E->getSubExpr()))
+ return false;
+
+ QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType From
+ = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
+ Result.makeComplexInt();
+ Result.IntReal = HandleFloatToIntCast(To, From, Result.FloatReal, Info.Ctx);
+ Result.IntImag = HandleFloatToIntCast(To, From, Result.FloatImag, Info.Ctx);
+ return true;
+ }
+
+ case CK_IntegralRealToComplex: {
APSInt &Real = Result.IntReal;
- if (!EvaluateInteger(SubExpr, Real, Info))
+ if (!EvaluateInteger(E->getSubExpr(), Real, Info))
return false;
- if (EltType->isRealFloatingType()) {
- Result.makeComplexFloat();
- Result.FloatReal
- = HandleIntToFloatCast(EltType, SubType, Real, Info.Ctx);
- Result.FloatImag = APFloat(Result.FloatReal.getSemantics());
- return true;
- } else {
- Result.makeComplexInt();
- Real = HandleIntToIntCast(EltType, SubType, Real, Info.Ctx);
- Result.IntImag = APSInt(Real.getBitWidth(), !Real.isSigned());
- return true;
- }
- } else if (const ComplexType *CT = SubType->getAs<ComplexType>()) {
- if (!Visit(SubExpr))
+ Result.makeComplexInt();
+ Result.IntImag = APSInt(Real.getBitWidth(), !Real.isSigned());
+ return true;
+ }
+
+ case CK_IntegralComplexCast: {
+ if (!Visit(E->getSubExpr()))
return false;
- QualType SrcType = CT->getElementType();
+ QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType From
+ = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
- if (Result.isComplexFloat()) {
- if (EltType->isRealFloatingType()) {
- Result.makeComplexFloat();
- Result.FloatReal = HandleFloatToFloatCast(EltType, SrcType,
- Result.FloatReal,
- Info.Ctx);
- Result.FloatImag = HandleFloatToFloatCast(EltType, SrcType,
- Result.FloatImag,
- Info.Ctx);
- return true;
- } else {
- Result.makeComplexInt();
- Result.IntReal = HandleFloatToIntCast(EltType, SrcType,
- Result.FloatReal,
- Info.Ctx);
- Result.IntImag = HandleFloatToIntCast(EltType, SrcType,
- Result.FloatImag,
- Info.Ctx);
- return true;
- }
- } else {
- assert(Result.isComplexInt() && "Invalid evaluate result.");
- if (EltType->isRealFloatingType()) {
- Result.makeComplexFloat();
- Result.FloatReal = HandleIntToFloatCast(EltType, SrcType,
- Result.IntReal,
- Info.Ctx);
- Result.FloatImag = HandleIntToFloatCast(EltType, SrcType,
- Result.IntImag,
- Info.Ctx);
- return true;
- } else {
- Result.makeComplexInt();
- Result.IntReal = HandleIntToIntCast(EltType, SrcType,
- Result.IntReal,
- Info.Ctx);
- Result.IntImag = HandleIntToIntCast(EltType, SrcType,
- Result.IntImag,
- Info.Ctx);
- return true;
- }
- }
+ Result.IntReal = HandleIntToIntCast(To, From, Result.IntReal, Info.Ctx);
+ Result.IntImag = HandleIntToIntCast(To, From, Result.IntImag, Info.Ctx);
+ return true;
+ }
+
+ case CK_IntegralComplexToFloatingComplex: {
+ if (!Visit(E->getSubExpr()))
+ return false;
+
+ QualType To = E->getType()->getAs<ComplexType>()->getElementType();
+ QualType From
+ = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType();
+ Result.makeComplexFloat();
+ Result.FloatReal = HandleIntToFloatCast(To, From, Result.IntReal, Info.Ctx);
+ Result.FloatImag = HandleIntToFloatCast(To, From, Result.IntImag, Info.Ctx);
+ return true;
+ }
}
- // FIXME: Handle more casts.
+ llvm_unreachable("unknown cast resulting in complex value");
return false;
}
bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+ if (E->getOpcode() == BO_Comma) {
+ if (!Visit(E->getRHS()))
+ return false;
+
+ // If we can't evaluate the LHS, it might have side effects;
+ // conservatively mark it.
+ if (!E->getLHS()->isEvaluatable(Info.Ctx))
+ Info.EvalResult.HasSideEffects = true;
+
+ return true;
+ }
if (!Visit(E->getLHS()))
return false;
@@ -2195,29 +2451,122 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
LHS.getComplexIntImag() * RHS.getComplexIntReal());
}
break;
+ case BO_Div:
+ if (Result.isComplexFloat()) {
+ ComplexValue LHS = Result;
+ APFloat &LHS_r = LHS.getComplexFloatReal();
+ APFloat &LHS_i = LHS.getComplexFloatImag();
+ APFloat &RHS_r = RHS.getComplexFloatReal();
+ APFloat &RHS_i = RHS.getComplexFloatImag();
+ APFloat &Res_r = Result.getComplexFloatReal();
+ APFloat &Res_i = Result.getComplexFloatImag();
+
+ APFloat Den = RHS_r;
+ Den.multiply(RHS_r, APFloat::rmNearestTiesToEven);
+ APFloat Tmp = RHS_i;
+ Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
+ Den.add(Tmp, APFloat::rmNearestTiesToEven);
+
+ Res_r = LHS_r;
+ Res_r.multiply(RHS_r, APFloat::rmNearestTiesToEven);
+ Tmp = LHS_i;
+ Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
+ Res_r.add(Tmp, APFloat::rmNearestTiesToEven);
+ Res_r.divide(Den, APFloat::rmNearestTiesToEven);
+
+ Res_i = LHS_i;
+ Res_i.multiply(RHS_r, APFloat::rmNearestTiesToEven);
+ Tmp = LHS_r;
+ Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven);
+ Res_i.subtract(Tmp, APFloat::rmNearestTiesToEven);
+ Res_i.divide(Den, APFloat::rmNearestTiesToEven);
+ } else {
+ if (RHS.getComplexIntReal() == 0 && RHS.getComplexIntImag() == 0) {
+ // FIXME: what about diagnostics?
+ return false;
+ }
+ ComplexValue LHS = Result;
+ APSInt Den = RHS.getComplexIntReal() * RHS.getComplexIntReal() +
+ RHS.getComplexIntImag() * RHS.getComplexIntImag();
+ Result.getComplexIntReal() =
+ (LHS.getComplexIntReal() * RHS.getComplexIntReal() +
+ LHS.getComplexIntImag() * RHS.getComplexIntImag()) / Den;
+ Result.getComplexIntImag() =
+ (LHS.getComplexIntImag() * RHS.getComplexIntReal() -
+ LHS.getComplexIntReal() * RHS.getComplexIntImag()) / Den;
+ }
+ break;
}
return true;
}
+bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
+ // Get the operand value into 'Result'.
+ if (!Visit(E->getSubExpr()))
+ return false;
+
+ switch (E->getOpcode()) {
+ default:
+ // FIXME: what about diagnostics?
+ return false;
+ case UO_Extension:
+ return true;
+ case UO_Plus:
+ // The result is always just the subexpr.
+ return true;
+ case UO_Minus:
+ if (Result.isComplexFloat()) {
+ Result.getComplexFloatReal().changeSign();
+ Result.getComplexFloatImag().changeSign();
+ }
+ else {
+ Result.getComplexIntReal() = -Result.getComplexIntReal();
+ Result.getComplexIntImag() = -Result.getComplexIntImag();
+ }
+ return true;
+ case UO_Not:
+ if (Result.isComplexFloat())
+ Result.getComplexFloatImag().changeSign();
+ else
+ Result.getComplexIntImag() = -Result.getComplexIntImag();
+ return true;
+ }
+}
+
+bool ComplexExprEvaluator::
+VisitBinaryConditionalOperator(const BinaryConditionalOperator *e) {
+ OpaqueValueEvaluation opaque(Info, e->getOpaqueValue(), e->getCommon());
+ if (opaque.hasError()) return false;
+
+ bool cond;
+ if (!HandleConversionToBool(e->getCond(), cond, Info))
+ return false;
+
+ return Visit(cond ? e->getTrueExpr() : e->getFalseExpr());
+}
+
+bool ComplexExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
+ bool Cond;
+ if (!HandleConversionToBool(E->getCond(), Cond, Info))
+ return false;
+
+ return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr());
+}
+
//===----------------------------------------------------------------------===//
// Top level Expr::Evaluate method.
//===----------------------------------------------------------------------===//
-/// Evaluate - Return true if this is a constant which we can fold using
-/// any crazy technique (that has nothing to do with language standards) that
-/// we want to. If this function returns true, it returns the folded constant
-/// in Result.
-bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const {
- const Expr *E = this;
- EvalInfo Info(Ctx, Result);
+static bool Evaluate(EvalInfo &Info, const Expr *E) {
if (E->getType()->isVectorType()) {
if (!EvaluateVector(E, Info.EvalResult.Val, Info))
return false;
} else if (E->getType()->isIntegerType()) {
if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(const_cast<Expr*>(E)))
return false;
- if (Result.Val.isLValue() && !IsGlobalLValue(Result.Val.getLValueBase()))
+ if (Info.EvalResult.Val.isLValue() &&
+ !IsGlobalLValue(Info.EvalResult.Val.getLValueBase()))
return false;
} else if (E->getType()->hasPointerRepresentation()) {
LValue LV;
@@ -2243,14 +2592,24 @@ bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const {
return true;
}
-bool Expr::EvaluateAsBooleanCondition(bool &Result, ASTContext &Ctx) const {
+/// Evaluate - Return true if this is a constant which we can fold using
+/// any crazy technique (that has nothing to do with language standards) that
+/// we want to. If this function returns true, it returns the folded constant
+/// in Result.
+bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const {
+ EvalInfo Info(Ctx, Result);
+ return ::Evaluate(Info, this);
+}
+
+bool Expr::EvaluateAsBooleanCondition(bool &Result,
+ const ASTContext &Ctx) const {
EvalResult Scratch;
EvalInfo Info(Ctx, Scratch);
return HandleConversionToBool(this, Result, Info);
}
-bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const {
+bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
EvalInfo Info(Ctx, Result);
LValue LV;
@@ -2263,7 +2622,8 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const {
return false;
}
-bool Expr::EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const {
+bool Expr::EvaluateAsAnyLValue(EvalResult &Result,
+ const ASTContext &Ctx) const {
EvalInfo Info(Ctx, Result);
LValue LV;
@@ -2276,21 +2636,21 @@ bool Expr::EvaluateAsAnyLValue(EvalResult &Result, ASTContext &Ctx) const {
/// isEvaluatable - Call Evaluate to see if this expression can be constant
/// folded, but discard the result.
-bool Expr::isEvaluatable(ASTContext &Ctx) const {
+bool Expr::isEvaluatable(const ASTContext &Ctx) const {
EvalResult Result;
return Evaluate(Result, Ctx) && !Result.HasSideEffects;
}
-bool Expr::HasSideEffects(ASTContext &Ctx) const {
+bool Expr::HasSideEffects(const ASTContext &Ctx) const {
Expr::EvalResult Result;
EvalInfo Info(Ctx, Result);
return HasSideEffect(Info).Visit(const_cast<Expr*>(this));
}
-APSInt Expr::EvaluateAsInt(ASTContext &Ctx) const {
+APSInt Expr::EvaluateAsInt(const ASTContext &Ctx) const {
EvalResult EvalResult;
bool Result = Evaluate(EvalResult, Ctx);
- Result = Result;
+ (void)Result;
assert(Result && "Could not evaluate expression");
assert(EvalResult.Val.isInt() && "Expression did not evaluate to integer");
@@ -2358,6 +2718,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
switch (E->getStmtClass()) {
+#define ABSTRACT_STMT(Node)
#define STMT(Node, Base) case Expr::Node##Class:
#define EXPR(Node, Base)
#include "clang/AST/StmtNodes.inc"
@@ -2378,8 +2739,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::AddrLabelExprClass:
case Expr::StmtExprClass:
case Expr::CXXMemberCallExprClass:
+ case Expr::CUDAKernelCallExprClass:
case Expr::CXXDynamicCastExprClass:
case Expr::CXXTypeidExprClass:
+ case Expr::CXXUuidofExprClass:
case Expr::CXXNullPtrLiteralExprClass:
case Expr::CXXThisExprClass:
case Expr::CXXThrowExprClass:
@@ -2390,7 +2753,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
case Expr::CXXBindTemporaryExprClass:
- case Expr::CXXExprWithTemporariesClass:
+ case Expr::ExprWithCleanupsClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::CXXUnresolvedConstructExprClass:
case Expr::CXXDependentScopeMemberExprClass:
@@ -2402,15 +2765,17 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::ObjCProtocolExprClass:
case Expr::ObjCIvarRefExprClass:
case Expr::ObjCPropertyRefExprClass:
- case Expr::ObjCImplicitSetterGetterRefExprClass:
- case Expr::ObjCSuperExprClass:
case Expr::ObjCIsaExprClass:
case Expr::ShuffleVectorExprClass:
case Expr::BlockExprClass:
case Expr::BlockDeclRefExprClass:
case Expr::NoStmtClass:
+ case Expr::OpaqueValueExprClass:
+ case Expr::PackExpansionExprClass:
+ case Expr::SubstNonTypeTemplateParmPackExprClass:
return ICEDiag(2, E->getLocStart());
+ case Expr::SizeOfPackExprClass:
case Expr::GNUNullExprClass:
// GCC considers the GNU __null value to be an integral constant expression.
return NoDiag();
@@ -2421,8 +2786,9 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CharacterLiteralClass:
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXScalarValueInitExprClass:
- case Expr::TypesCompatibleExprClass:
case Expr::UnaryTypeTraitExprClass:
+ case Expr::BinaryTypeTraitExprClass:
+ case Expr::CXXNoexceptExprClass:
return NoDiag();
case Expr::CallExprClass:
case Expr::CXXOperatorCallExprClass: {
@@ -2619,6 +2985,17 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
return NoDiag();
return ICEDiag(2, E->getLocStart());
}
+ case Expr::BinaryConditionalOperatorClass: {
+ const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E);
+ ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx);
+ if (CommonResult.Val == 2) return CommonResult;
+ ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
+ if (FalseResult.Val == 2) return FalseResult;
+ if (CommonResult.Val == 1) return CommonResult;
+ if (FalseResult.Val == 1 &&
+ Exp->getCommon()->EvaluateAsInt(Ctx) == 0) return NoDiag();
+ return FalseResult;
+ }
case Expr::ConditionalOperatorClass: {
const ConditionalOperator *Exp = cast<ConditionalOperator>(E);
// If the condition (ignoring parens) is a __builtin_constant_p call,
diff --git a/lib/AST/FullExpr.cpp b/lib/AST/FullExpr.cpp
deleted file mode 100644
index 93ee8d1..0000000
--- a/lib/AST/FullExpr.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-//===--- FullExpr.cpp - C++ full expression class ---------------*- C++ -*-===//
-//
-// 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 FullExpr interface, to be used for type safe handling
-// of full expressions.
-//
-// Full expressions are described in C++ [intro.execution]p12.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/FullExpr.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "llvm/Support/AlignOf.h"
-using namespace clang;
-
-FullExpr FullExpr::Create(ASTContext &Context, Expr *SubExpr,
- CXXTemporary **Temporaries, unsigned NumTemporaries) {
- FullExpr E;
-
- if (!NumTemporaries) {
- E.SubExpr = SubExpr;
- return E;
- }
-
- unsigned Size = sizeof(FullExpr)
- + sizeof(CXXTemporary *) * NumTemporaries;
-
- unsigned Align = llvm::AlignOf<ExprAndTemporaries>::Alignment;
- ExprAndTemporaries *ET =
- static_cast<ExprAndTemporaries *>(Context.Allocate(Size, Align));
-
- ET->SubExpr = SubExpr;
- std::copy(Temporaries, Temporaries + NumTemporaries, ET->temps_begin());
-
- return E;
-}
-
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index c47a9da..533a232 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -17,6 +17,7 @@
#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>
@@ -135,34 +136,28 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
/// class using GraphViz.
void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(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";
+ // Create temp directory
+ SmallString<128> Filename;
+ int FileFD = 0;
+ if (error_code ec = sys::fs::unique_file(
+ "clang-class-inheritance-hierarchy-%%-%%-%%-%%-" +
+ Self.getAsString() + ".dot",
+ FileFD, Filename)) {
+ errs() << "Error creating temporary output file: " << 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(FileFD, true);
+ InheritanceHierarchyWriter Writer(Context, O);
+ Writer.WriteGraph(Self);
- if (ErrMsg.empty()) {
- InheritanceHierarchyWriter Writer(Context, O);
- Writer.WriteGraph(Self);
- llvm::errs() << " done. \n";
+ 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(sys::Path(Filename));
}
}
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index c3fa466..bed02b4 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -19,7 +19,10 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/Type.h"
+#include "clang/Basic/TargetInfo.h"
using namespace clang;
@@ -35,6 +38,24 @@ public:
if (Pointee->isFunctionType()) return 2;
return 1;
}
+
+ CallingConv getDefaultMethodCallConv() const {
+ return CC_C;
+ }
+
+ // We cheat and just check that the class has a vtable pointer, and that it's
+ // only big enough to have a vtable pointer and nothing more (or less).
+ bool isNearlyEmpty(const CXXRecordDecl *RD) const {
+
+ // Check that the class has a vtable pointer.
+ if (!RD->isDynamicClass())
+ return false;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ CharUnits PointerSize =
+ Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
+ return Layout.getNonVirtualSize() == PointerSize;
+ }
};
class ARMCXXABI : public ItaniumCXXABI {
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
new file mode 100644
index 0000000..d66c374
--- /dev/null
+++ b/lib/AST/ItaniumMangle.cpp
@@ -0,0 +1,2705 @@
+//===--- ItaniumMangle.cpp - Itanium C++ Name Mangling ----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements C++ name mangling according to the Itanium C++ ABI,
+// which is used in GCC 3.2 and newer (and many compilers that are
+// ABI-compatible with GCC):
+//
+// http://www.codesourcery.com/public/cxx-abi/abi.html
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/Mangle.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#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/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#define MANGLE_CHECKER 0
+
+#if MANGLE_CHECKER
+#include <cxxabi.h>
+#endif
+
+using namespace clang;
+
+namespace {
+
+static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) {
+ const DeclContext *DC = dyn_cast<DeclContext>(ND);
+ if (!DC)
+ DC = ND->getDeclContext();
+ while (!DC->isNamespace() && !DC->isTranslationUnit()) {
+ if (isa<FunctionDecl>(DC->getParent()))
+ return dyn_cast<CXXRecordDecl>(DC);
+ DC = DC->getParent();
+ }
+ return 0;
+}
+
+static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) {
+ assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
+ "Passed in decl is not a ctor or dtor!");
+
+ if (const TemplateDecl *TD = MD->getPrimaryTemplate()) {
+ MD = cast<CXXMethodDecl>(TD->getTemplatedDecl());
+
+ assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
+ "Templated decl is not a ctor or dtor!");
+ }
+
+ return MD;
+}
+
+static const unsigned UnknownArity = ~0U;
+
+class ItaniumMangleContext : public MangleContext {
+ llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
+ unsigned Discriminator;
+ llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier;
+
+public:
+ explicit ItaniumMangleContext(ASTContext &Context,
+ Diagnostic &Diags)
+ : MangleContext(Context, Diags) { }
+
+ uint64_t getAnonymousStructId(const TagDecl *TD) {
+ std::pair<llvm::DenseMap<const TagDecl *,
+ uint64_t>::iterator, bool> Result =
+ AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size()));
+ return Result.first->second;
+ }
+
+ void startNewFunction() {
+ MangleContext::startNewFunction();
+ mangleInitDiscriminator();
+ }
+
+ /// @name Mangler Entry Points
+ /// @{
+
+ bool shouldMangleDeclName(const NamedDecl *D);
+ void mangleName(const NamedDecl *D, llvm::raw_ostream &);
+ void mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
+ llvm::raw_ostream &);
+ void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment,
+ llvm::raw_ostream &);
+ void mangleReferenceTemporary(const VarDecl *D,
+ llvm::raw_ostream &);
+ void mangleCXXVTable(const CXXRecordDecl *RD,
+ llvm::raw_ostream &);
+ void mangleCXXVTT(const CXXRecordDecl *RD,
+ llvm::raw_ostream &);
+ void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type,
+ llvm::raw_ostream &);
+ void mangleCXXRTTI(QualType T, llvm::raw_ostream &);
+ void mangleCXXRTTIName(QualType T, llvm::raw_ostream &);
+ void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ llvm::raw_ostream &);
+ void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ llvm::raw_ostream &);
+
+ void mangleItaniumGuardVariable(const VarDecl *D, llvm::raw_ostream &);
+
+ void mangleInitDiscriminator() {
+ Discriminator = 0;
+ }
+
+ bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
+ unsigned &discriminator = Uniquifier[ND];
+ if (!discriminator)
+ discriminator = ++Discriminator;
+ if (discriminator == 1)
+ return false;
+ disc = discriminator-2;
+ return true;
+ }
+ /// @}
+};
+
+/// CXXNameMangler - Manage the mangling of a single name.
+class CXXNameMangler {
+ ItaniumMangleContext &Context;
+ llvm::raw_ostream &Out;
+
+ const CXXMethodDecl *Structor;
+ unsigned StructorType;
+
+ /// SeqID - The next subsitution sequence number.
+ unsigned SeqID;
+
+ llvm::DenseMap<uintptr_t, unsigned> Substitutions;
+
+ ASTContext &getASTContext() const { return Context.getASTContext(); }
+
+public:
+ CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_)
+ : Context(C), Out(Out_), Structor(0), StructorType(0), SeqID(0) { }
+ CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
+ const CXXConstructorDecl *D, CXXCtorType Type)
+ : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
+ SeqID(0) { }
+ CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_,
+ const CXXDestructorDecl *D, CXXDtorType Type)
+ : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type),
+ SeqID(0) { }
+
+#if MANGLE_CHECKER
+ ~CXXNameMangler() {
+ if (Out.str()[0] == '\01')
+ return;
+
+ int status = 0;
+ char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status);
+ assert(status == 0 && "Could not demangle mangled name!");
+ free(result);
+ }
+#endif
+ llvm::raw_ostream &getStream() { return Out; }
+
+ void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z");
+ void mangleCallOffset(int64_t NonVirtual, int64_t Virtual);
+ void mangleNumber(const llvm::APSInt &I);
+ void mangleNumber(int64_t Number);
+ void mangleFloat(const llvm::APFloat &F);
+ void mangleFunctionEncoding(const FunctionDecl *FD);
+ void mangleName(const NamedDecl *ND);
+ void mangleType(QualType T);
+ void mangleNameOrStandardSubstitution(const NamedDecl *ND);
+
+private:
+ bool mangleSubstitution(const NamedDecl *ND);
+ bool mangleSubstitution(QualType T);
+ bool mangleSubstitution(TemplateName Template);
+ bool mangleSubstitution(uintptr_t Ptr);
+
+ bool mangleStandardSubstitution(const NamedDecl *ND);
+
+ void addSubstitution(const NamedDecl *ND) {
+ ND = cast<NamedDecl>(ND->getCanonicalDecl());
+
+ addSubstitution(reinterpret_cast<uintptr_t>(ND));
+ }
+ void addSubstitution(QualType T);
+ void addSubstitution(TemplateName Template);
+ void addSubstitution(uintptr_t Ptr);
+
+ void mangleUnresolvedScope(NestedNameSpecifier *Qualifier);
+ void mangleUnresolvedName(NestedNameSpecifier *Qualifier,
+ DeclarationName Name,
+ unsigned KnownArity = UnknownArity);
+
+ void mangleName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void mangleUnqualifiedName(const NamedDecl *ND) {
+ mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity);
+ }
+ void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name,
+ unsigned KnownArity);
+ void mangleUnscopedName(const NamedDecl *ND);
+ void mangleUnscopedTemplateName(const TemplateDecl *ND);
+ void mangleUnscopedTemplateName(TemplateName);
+ void mangleSourceName(const IdentifierInfo *II);
+ void mangleLocalName(const NamedDecl *ND);
+ void mangleNestedName(const NamedDecl *ND, const DeclContext *DC,
+ bool NoFunction=false);
+ void mangleNestedName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void manglePrefix(const DeclContext *DC, bool NoFunction=false);
+ void mangleTemplatePrefix(const TemplateDecl *ND);
+ void mangleTemplatePrefix(TemplateName Template);
+ void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
+ void mangleQualifiers(Qualifiers Quals);
+ void mangleRefQualifier(RefQualifierKind RefQualifier);
+
+ void mangleObjCMethodName(const ObjCMethodDecl *MD);
+
+ // Declare manglers for every type class.
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define NON_CANONICAL_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T);
+#include "clang/AST/TypeNodes.def"
+
+ void mangleType(const TagType*);
+ void mangleType(TemplateName);
+ void mangleBareFunctionType(const FunctionType *T,
+ bool MangleReturnType);
+ void mangleNeonVectorType(const VectorType *T);
+
+ void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value);
+ void mangleMemberExpr(const Expr *Base, bool IsArrow,
+ NestedNameSpecifier *Qualifier,
+ DeclarationName Name,
+ unsigned KnownArity);
+ void mangleExpression(const Expr *E, unsigned Arity = UnknownArity);
+ void mangleCXXCtorType(CXXCtorType T);
+ void mangleCXXDtorType(CXXDtorType T);
+
+ void mangleTemplateArgs(const ExplicitTemplateArgumentList &TemplateArgs);
+ void mangleTemplateArgs(TemplateName Template,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void mangleTemplateArgs(const TemplateParameterList &PL,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void mangleTemplateArgs(const TemplateParameterList &PL,
+ const TemplateArgumentList &AL);
+ void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A);
+
+ void mangleTemplateParameter(unsigned Index);
+};
+
+}
+
+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;
+ }
+
+ return false;
+}
+
+bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
+ // In C, functions with no attributes never need to be mangled. Fastpath them.
+ if (!getASTContext().getLangOptions().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;
+
+ // 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;
+
+ // Otherwise, no mangling is done outside C++ mode.
+ if (!getASTContext().getLangOptions().CPlusPlus)
+ return false;
+
+ // Variables at global scope with non-internal linkage are not mangled
+ if (!FD) {
+ const DeclContext *DC = D->getDeclContext();
+ // Check for extern variable declared locally.
+ if (DC->isFunctionOrMethod() && D->hasLinkage())
+ while (!DC->isNamespace() && !DC->isTranslationUnit())
+ DC = DC->getParent();
+ if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage)
+ return false;
+ }
+
+ // Class members are always mangled.
+ if (D->getDeclContext()->isRecord())
+ return true;
+
+ // C functions and "main" are not mangled.
+ if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
+ return false;
+
+ return true;
+}
+
+void CXXNameMangler::mangle(const NamedDecl *D, llvm::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.
+ llvm::StringRef UserLabelPrefix =
+ getASTContext().Target.getUserLabelPrefix();
+ if (!UserLabelPrefix.empty())
+ Out << '\01'; // LLVM IR Marker for __asm("foo")
+
+ Out << ALA->getLabel();
+ return;
+ }
+
+ // <mangled-name> ::= _Z <encoding>
+ // ::= <data name>
+ // ::= <special-name>
+ Out << Prefix;
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ mangleFunctionEncoding(FD);
+ else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ mangleName(VD);
+ else
+ mangleName(cast<FieldDecl>(D));
+}
+
+void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
+ // <encoding> ::= <function name> <bare-function-type>
+ mangleName(FD);
+
+ // Don't mangle in the type if this isn't a decl we should typically mangle.
+ if (!Context.shouldMangleDeclName(FD))
+ return;
+
+ // Whether the mangling of a function type includes the return type depends on
+ // the context and the nature of the function. The rules for deciding whether
+ // the return type is included are:
+ //
+ // 1. Template functions (names or types) have return types encoded, with
+ // the exceptions listed below.
+ // 2. Function types not appearing as part of a function name mangling,
+ // e.g. parameters, pointer types, etc., have return type encoded, with the
+ // exceptions listed below.
+ // 3. Non-template function names do not have return types encoded.
+ //
+ // The exceptions mentioned in (1) and (2) above, for which the return type is
+ // never included, are
+ // 1. Constructors.
+ // 2. Destructors.
+ // 3. Conversion operator functions, e.g. operator int.
+ bool MangleReturnType = false;
+ if (FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate()) {
+ if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
+ isa<CXXConversionDecl>(FD)))
+ MangleReturnType = true;
+
+ // Mangle the type of the primary template.
+ FD = PrimaryTemplate->getTemplatedDecl();
+ }
+
+ // Do the canonicalization out here because parameter types can
+ // undergo additional canonicalization (e.g. array decay).
+ const FunctionType *FT
+ = cast<FunctionType>(Context.getASTContext()
+ .getCanonicalType(FD->getType()));
+
+ mangleBareFunctionType(FT, MangleReturnType);
+}
+
+static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) {
+ while (isa<LinkageSpecDecl>(DC)) {
+ DC = DC->getParent();
+ }
+
+ return DC;
+}
+
+/// isStd - Return whether a given namespace is the 'std' namespace.
+static bool isStd(const NamespaceDecl *NS) {
+ if (!IgnoreLinkageSpecDecls(NS->getParent())->isTranslationUnit())
+ return false;
+
+ const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
+ return II && II->isStr("std");
+}
+
+// isStdNamespace - Return whether a given decl context is a toplevel 'std'
+// namespace.
+static bool isStdNamespace(const DeclContext *DC) {
+ if (!DC->isNamespace())
+ return false;
+
+ return isStd(cast<NamespaceDecl>(DC));
+}
+
+static const TemplateDecl *
+isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
+ // Check if we have a function template.
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){
+ if (const TemplateDecl *TD = FD->getPrimaryTemplate()) {
+ TemplateArgs = FD->getTemplateSpecializationArgs();
+ return TD;
+ }
+ }
+
+ // Check if we have a class template.
+ if (const ClassTemplateSpecializationDecl *Spec =
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ TemplateArgs = &Spec->getTemplateArgs();
+ return Spec->getSpecializedTemplate();
+ }
+
+ return 0;
+}
+
+void CXXNameMangler::mangleName(const NamedDecl *ND) {
+ // <name> ::= <nested-name>
+ // ::= <unscoped-name>
+ // ::= <unscoped-template-name> <template-args>
+ // ::= <local-name>
+ //
+ const DeclContext *DC = ND->getDeclContext();
+
+ // If this is an extern variable declared locally, the relevant DeclContext
+ // is that of the containing namespace, or the translation unit.
+ if (isa<FunctionDecl>(DC) && ND->hasLinkage())
+ while (!DC->isNamespace() && !DC->isTranslationUnit())
+ DC = DC->getParent();
+ else if (GetLocalClassDecl(ND)) {
+ mangleLocalName(ND);
+ return;
+ }
+
+ while (isa<LinkageSpecDecl>(DC))
+ DC = DC->getParent();
+
+ if (DC->isTranslationUnit() || isStdNamespace(DC)) {
+ // Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
+ if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
+ mangleUnscopedTemplateName(TD);
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
+ return;
+ }
+
+ mangleUnscopedName(ND);
+ return;
+ }
+
+ if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) {
+ mangleLocalName(ND);
+ return;
+ }
+
+ mangleNestedName(ND, DC);
+}
+void CXXNameMangler::mangleName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ const DeclContext *DC = IgnoreLinkageSpecDecls(TD->getDeclContext());
+
+ if (DC->isTranslationUnit() || isStdNamespace(DC)) {
+ mangleUnscopedTemplateName(TD);
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs);
+ } else {
+ mangleNestedName(TD, TemplateArgs, NumTemplateArgs);
+ }
+}
+
+void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) {
+ // <unscoped-name> ::= <unqualified-name>
+ // ::= St <unqualified-name> # ::std::
+ if (isStdNamespace(ND->getDeclContext()))
+ Out << "St";
+
+ mangleUnqualifiedName(ND);
+}
+
+void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
+ // <unscoped-template-name> ::= <unscoped-name>
+ // ::= <substitution>
+ if (mangleSubstitution(ND))
+ return;
+
+ // <template-template-param> ::= <template-param>
+ if (const TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ mangleTemplateParameter(TTP->getIndex());
+ return;
+ }
+
+ mangleUnscopedName(ND->getTemplatedDecl());
+ addSubstitution(ND);
+}
+
+void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) {
+ // <unscoped-template-name> ::= <unscoped-name>
+ // ::= <substitution>
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleUnscopedTemplateName(TD);
+
+ if (mangleSubstitution(Template))
+ return;
+
+ // FIXME: How to cope with operators here?
+ DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
+ assert(Dependent && "Not a dependent template name?");
+ if (!Dependent->isIdentifier()) {
+ // FIXME: We can't possibly know the arity of the operator here!
+ Diagnostic &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ "cannot mangle dependent operator name");
+ Diags.Report(DiagID);
+ return;
+ }
+
+ mangleSourceName(Dependent->getIdentifier());
+ addSubstitution(Template);
+}
+
+void CXXNameMangler::mangleFloat(const llvm::APFloat &F) {
+ // TODO: avoid this copy with careful stream management.
+ llvm::SmallString<20> Buffer;
+ F.bitcastToAPInt().toString(Buffer, 16, false);
+ Out.write(Buffer.data(), Buffer.size());
+}
+
+void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
+ if (Value.isSigned() && Value.isNegative()) {
+ Out << 'n';
+ Value.abs().print(Out, true);
+ } else
+ Value.print(Out, Value.isSigned());
+}
+
+void CXXNameMangler::mangleNumber(int64_t Number) {
+ // <number> ::= [n] <non-negative decimal integer>
+ if (Number < 0) {
+ Out << 'n';
+ Number = -Number;
+ }
+
+ Out << Number;
+}
+
+void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) {
+ // <call-offset> ::= h <nv-offset> _
+ // ::= v <v-offset> _
+ // <nv-offset> ::= <offset number> # non-virtual base override
+ // <v-offset> ::= <offset number> _ <virtual offset number>
+ // # virtual base override, with vcall offset
+ if (!Virtual) {
+ Out << 'h';
+ mangleNumber(NonVirtual);
+ Out << '_';
+ return;
+ }
+
+ Out << 'v';
+ mangleNumber(NonVirtual);
+ Out << '_';
+ mangleNumber(Virtual);
+ Out << '_';
+}
+
+void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) {
+ Qualifier = getASTContext().getCanonicalNestedNameSpecifier(Qualifier);
+ switch (Qualifier->getKind()) {
+ case NestedNameSpecifier::Global:
+ // nothing
+ break;
+ case NestedNameSpecifier::Namespace:
+ mangleName(Qualifier->getAsNamespace());
+ break;
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate: {
+ const Type *QTy = Qualifier->getAsType();
+
+ if (const TemplateSpecializationType *TST =
+ dyn_cast<TemplateSpecializationType>(QTy)) {
+ if (!mangleSubstitution(QualType(TST, 0))) {
+ mangleTemplatePrefix(TST->getTemplateName());
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(),
+ TST->getNumArgs());
+ addSubstitution(QualType(TST, 0));
+ }
+ } else {
+ // We use the QualType mangle type variant here because it handles
+ // substitutions.
+ mangleType(QualType(QTy, 0));
+ }
+ }
+ break;
+ case NestedNameSpecifier::Identifier:
+ // Member expressions can have these without prefixes.
+ if (Qualifier->getPrefix())
+ mangleUnresolvedScope(Qualifier->getPrefix());
+ mangleSourceName(Qualifier->getAsIdentifier());
+ break;
+ }
+}
+
+/// Mangles a name which was not resolved to a specific entity.
+void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *Qualifier,
+ DeclarationName Name,
+ unsigned KnownArity) {
+ if (Qualifier)
+ mangleUnresolvedScope(Qualifier);
+ // FIXME: ambiguity of unqualified lookup with ::
+
+ mangleUnqualifiedName(0, Name, KnownArity);
+}
+
+static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) {
+ assert(RD->isAnonymousStructOrUnion() &&
+ "Expected anonymous struct or union!");
+
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I) {
+ const FieldDecl *FD = *I;
+
+ if (FD->getIdentifier())
+ return FD;
+
+ if (const RecordType *RT = FD->getType()->getAs<RecordType>()) {
+ if (const FieldDecl *NamedDataMember =
+ FindFirstNamedDataMember(RT->getDecl()))
+ return NamedDataMember;
+ }
+ }
+
+ // We didn't find a named data member.
+ return 0;
+}
+
+void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
+ DeclarationName Name,
+ unsigned KnownArity) {
+ // <unqualified-name> ::= <operator-name>
+ // ::= <ctor-dtor-name>
+ // ::= <source-name>
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier: {
+ if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
+ // We must avoid conflicts between internally- and externally-
+ // linked variable declaration names in the same TU.
+ // This naming convention is the same as that followed by GCC, though it
+ // shouldn't actually matter.
+ if (ND && isa<VarDecl>(ND) && ND->getLinkage() == InternalLinkage &&
+ ND->getDeclContext()->isFileContext())
+ Out << 'L';
+
+ mangleSourceName(II);
+ break;
+ }
+
+ // Otherwise, an anonymous entity. We must have a declaration.
+ assert(ND && "mangling empty name without declaration");
+
+ if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
+ if (NS->isAnonymousNamespace()) {
+ // This is how gcc mangles these names.
+ Out << "12_GLOBAL__N_1";
+ break;
+ }
+ }
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+ // We must have an anonymous union or struct declaration.
+ const RecordDecl *RD =
+ cast<RecordDecl>(VD->getType()->getAs<RecordType>()->getDecl());
+
+ // Itanium C++ ABI 5.1.2:
+ //
+ // For the purposes of mangling, the name of an anonymous union is
+ // considered to be the name of the first named data member found by a
+ // pre-order, depth-first, declaration-order walk of the data members of
+ // the anonymous union. If there is no such data member (i.e., if all of
+ // the data members in the union are unnamed), then there is no way for
+ // a program to refer to the anonymous union, and there is therefore no
+ // need to mangle its name.
+ const FieldDecl *FD = FindFirstNamedDataMember(RD);
+
+ // It's actually possible for various reasons for us to get here
+ // with an empty anonymous struct / union. Fortunately, it
+ // doesn't really matter what name we generate.
+ if (!FD) break;
+ assert(FD->getIdentifier() && "Data member name isn't an identifier!");
+
+ mangleSourceName(FD->getIdentifier());
+ break;
+ }
+
+ // We must have an anonymous struct.
+ const TagDecl *TD = cast<TagDecl>(ND);
+ if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
+ assert(TD->getDeclContext() == D->getDeclContext() &&
+ "Typedef should not be in another decl context!");
+ assert(D->getDeclName().getAsIdentifierInfo() &&
+ "Typedef was not named!");
+ mangleSourceName(D->getDeclName().getAsIdentifierInfo());
+ break;
+ }
+
+ // Get a unique id for the anonymous struct.
+ uint64_t AnonStructId = Context.getAnonymousStructId(TD);
+
+ // Mangle it as a source name in the form
+ // [n] $_<id>
+ // where n is the length of the string.
+ llvm::SmallString<8> Str;
+ Str += "$_";
+ Str += llvm::utostr(AnonStructId);
+
+ Out << Str.size();
+ Out << Str.str();
+ break;
+ }
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ assert(false && "Can't mangle Objective-C selector names here!");
+ break;
+
+ case DeclarationName::CXXConstructorName:
+ if (ND == Structor)
+ // If the named decl is the C++ constructor we're mangling, use the type
+ // we were given.
+ mangleCXXCtorType(static_cast<CXXCtorType>(StructorType));
+ else
+ // Otherwise, use the complete constructor name. This is relevant if a
+ // class with a constructor is declared within a constructor.
+ mangleCXXCtorType(Ctor_Complete);
+ break;
+
+ case DeclarationName::CXXDestructorName:
+ if (ND == Structor)
+ // If the named decl is the C++ destructor we're mangling, use the type we
+ // were given.
+ mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
+ else
+ // Otherwise, use the complete destructor name. This is relevant if a
+ // class with a destructor is declared within a destructor.
+ mangleCXXDtorType(Dtor_Complete);
+ break;
+
+ case DeclarationName::CXXConversionFunctionName:
+ // <operator-name> ::= cv <type> # (cast)
+ Out << "cv";
+ mangleType(Context.getASTContext().getCanonicalType(Name.getCXXNameType()));
+ break;
+
+ case DeclarationName::CXXOperatorName: {
+ unsigned Arity;
+ if (ND) {
+ Arity = cast<FunctionDecl>(ND)->getNumParams();
+
+ // If we have a C++ member function, we need to include the 'this' pointer.
+ // FIXME: This does not make sense for operators that are static, but their
+ // names stay the same regardless of the arity (operator new for instance).
+ if (isa<CXXMethodDecl>(ND))
+ Arity++;
+ } else
+ Arity = KnownArity;
+
+ mangleOperatorName(Name.getCXXOverloadedOperator(), Arity);
+ break;
+ }
+
+ case DeclarationName::CXXLiteralOperatorName:
+ // FIXME: This mangling is not yet official.
+ Out << "li";
+ mangleSourceName(Name.getCXXLiteralIdentifier());
+ break;
+
+ case DeclarationName::CXXUsingDirective:
+ assert(false && "Can't mangle a using directive name!");
+ break;
+ }
+}
+
+void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
+ // <source-name> ::= <positive length number> <identifier>
+ // <number> ::= [n] <non-negative decimal integer>
+ // <identifier> ::= <unqualified source code identifier>
+ Out << II->getLength() << II->getName();
+}
+
+void CXXNameMangler::mangleNestedName(const NamedDecl *ND,
+ const DeclContext *DC,
+ bool NoFunction) {
+ // <nested-name>
+ // ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E
+ // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix>
+ // <template-args> E
+
+ Out << 'N';
+ if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) {
+ mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers()));
+ mangleRefQualifier(Method->getRefQualifier());
+ }
+
+ // Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
+ if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
+ mangleTemplatePrefix(TD);
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
+ }
+ else {
+ manglePrefix(DC, NoFunction);
+ mangleUnqualifiedName(ND);
+ }
+
+ Out << 'E';
+}
+void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ // <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+
+ Out << 'N';
+
+ mangleTemplatePrefix(TD);
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs);
+
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleLocalName(const NamedDecl *ND) {
+ // <local-name> := Z <function encoding> E <entity name> [<discriminator>]
+ // := Z <function encoding> E s [<discriminator>]
+ // <discriminator> := _ <non-negative number>
+ const DeclContext *DC = ND->getDeclContext();
+ Out << 'Z';
+
+ if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) {
+ mangleObjCMethodName(MD);
+ } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) {
+ mangleFunctionEncoding(cast<FunctionDecl>(RD->getDeclContext()));
+ Out << 'E';
+
+ // 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*/);
+
+ unsigned disc;
+ if (Context.getNextDiscriminator(RD, disc)) {
+ if (disc < 10)
+ Out << '_' << disc;
+ else
+ Out << "__" << disc << '_';
+ }
+
+ return;
+ }
+ else
+ mangleFunctionEncoding(cast<FunctionDecl>(DC));
+
+ Out << 'E';
+ mangleUnqualifiedName(ND);
+}
+
+void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
+ // <prefix> ::= <prefix> <unqualified-name>
+ // ::= <template-prefix> <template-args>
+ // ::= <template-param>
+ // ::= # empty
+ // ::= <substitution>
+
+ while (isa<LinkageSpecDecl>(DC))
+ DC = DC->getParent();
+
+ if (DC->isTranslationUnit())
+ return;
+
+ if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) {
+ manglePrefix(DC->getParent(), NoFunction);
+ llvm::SmallString<64> Name;
+ llvm::raw_svector_ostream NameStream(Name);
+ Context.mangleBlock(Block, NameStream);
+ NameStream.flush();
+ Out << Name.size() << Name;
+ return;
+ }
+
+ if (mangleSubstitution(cast<NamedDecl>(DC)))
+ return;
+
+ // Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
+ if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
+ mangleTemplatePrefix(TD);
+ TemplateParameterList *TemplateParameters = TD->getTemplateParameters();
+ mangleTemplateArgs(*TemplateParameters, *TemplateArgs);
+ }
+ else if(NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)))
+ return;
+ else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC))
+ mangleObjCMethodName(Method);
+ else {
+ manglePrefix(DC->getParent(), NoFunction);
+ mangleUnqualifiedName(cast<NamedDecl>(DC));
+ }
+
+ addSubstitution(cast<NamedDecl>(DC));
+}
+
+void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) {
+ // <template-prefix> ::= <prefix> <template unqualified-name>
+ // ::= <template-param>
+ // ::= <substitution>
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleTemplatePrefix(TD);
+
+ if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName())
+ mangleUnresolvedScope(Qualified->getQualifier());
+
+ if (OverloadedTemplateStorage *Overloaded
+ = Template.getAsOverloadedTemplate()) {
+ mangleUnqualifiedName(0, (*Overloaded->begin())->getDeclName(),
+ UnknownArity);
+ return;
+ }
+
+ DependentTemplateName *Dependent = Template.getAsDependentTemplateName();
+ assert(Dependent && "Unknown template name kind?");
+ mangleUnresolvedScope(Dependent->getQualifier());
+ mangleUnscopedTemplateName(Template);
+}
+
+void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
+ // <template-prefix> ::= <prefix> <template unqualified-name>
+ // ::= <template-param>
+ // ::= <substitution>
+ // <template-template-param> ::= <template-param>
+ // <substitution>
+
+ if (mangleSubstitution(ND))
+ return;
+
+ // <template-template-param> ::= <template-param>
+ if (const TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(ND)) {
+ mangleTemplateParameter(TTP->getIndex());
+ return;
+ }
+
+ manglePrefix(ND->getDeclContext());
+ mangleUnqualifiedName(ND->getTemplatedDecl());
+ addSubstitution(ND);
+}
+
+/// Mangles a template name under the production <type>. Required for
+/// template template arguments.
+/// <type> ::= <class-enum-type>
+/// ::= <template-param>
+/// ::= <substitution>
+void CXXNameMangler::mangleType(TemplateName TN) {
+ if (mangleSubstitution(TN))
+ return;
+
+ TemplateDecl *TD = 0;
+
+ switch (TN.getKind()) {
+ case TemplateName::QualifiedTemplate:
+ TD = TN.getAsQualifiedTemplateName()->getTemplateDecl();
+ goto HaveDecl;
+
+ case TemplateName::Template:
+ TD = TN.getAsTemplateDecl();
+ goto HaveDecl;
+
+ HaveDecl:
+ if (isa<TemplateTemplateParmDecl>(TD))
+ mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex());
+ else
+ mangleName(TD);
+ break;
+
+ case TemplateName::OverloadedTemplate:
+ llvm_unreachable("can't mangle an overloaded template name as a <type>");
+ break;
+
+ case TemplateName::DependentTemplate: {
+ const DependentTemplateName *Dependent = TN.getAsDependentTemplateName();
+ assert(Dependent->isIdentifier());
+
+ // <class-enum-type> ::= <name>
+ // <name> ::= <nested-name>
+ mangleUnresolvedScope(Dependent->getQualifier());
+ mangleSourceName(Dependent->getIdentifier());
+ break;
+ }
+
+ case TemplateName::SubstTemplateTemplateParmPack: {
+ SubstTemplateTemplateParmPackStorage *SubstPack
+ = TN.getAsSubstTemplateTemplateParmPack();
+ mangleTemplateParameter(SubstPack->getParameterPack()->getIndex());
+ break;
+ }
+ }
+
+ addSubstitution(TN);
+}
+
+void
+CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
+ switch (OO) {
+ // <operator-name> ::= nw # new
+ case OO_New: Out << "nw"; break;
+ // ::= na # new[]
+ case OO_Array_New: Out << "na"; break;
+ // ::= dl # delete
+ case OO_Delete: Out << "dl"; break;
+ // ::= da # delete[]
+ case OO_Array_Delete: Out << "da"; break;
+ // ::= ps # + (unary)
+ // ::= pl # + (binary or unknown)
+ case OO_Plus:
+ Out << (Arity == 1? "ps" : "pl"); break;
+ // ::= ng # - (unary)
+ // ::= mi # - (binary or unknown)
+ case OO_Minus:
+ Out << (Arity == 1? "ng" : "mi"); break;
+ // ::= ad # & (unary)
+ // ::= an # & (binary or unknown)
+ case OO_Amp:
+ Out << (Arity == 1? "ad" : "an"); break;
+ // ::= de # * (unary)
+ // ::= ml # * (binary or unknown)
+ case OO_Star:
+ // Use binary when unknown.
+ Out << (Arity == 1? "de" : "ml"); break;
+ // ::= co # ~
+ case OO_Tilde: Out << "co"; break;
+ // ::= dv # /
+ case OO_Slash: Out << "dv"; break;
+ // ::= rm # %
+ case OO_Percent: Out << "rm"; break;
+ // ::= or # |
+ case OO_Pipe: Out << "or"; break;
+ // ::= eo # ^
+ case OO_Caret: Out << "eo"; break;
+ // ::= aS # =
+ case OO_Equal: Out << "aS"; break;
+ // ::= pL # +=
+ case OO_PlusEqual: Out << "pL"; break;
+ // ::= mI # -=
+ case OO_MinusEqual: Out << "mI"; break;
+ // ::= mL # *=
+ case OO_StarEqual: Out << "mL"; break;
+ // ::= dV # /=
+ case OO_SlashEqual: Out << "dV"; break;
+ // ::= rM # %=
+ case OO_PercentEqual: Out << "rM"; break;
+ // ::= aN # &=
+ case OO_AmpEqual: Out << "aN"; break;
+ // ::= oR # |=
+ case OO_PipeEqual: Out << "oR"; break;
+ // ::= eO # ^=
+ case OO_CaretEqual: Out << "eO"; break;
+ // ::= ls # <<
+ case OO_LessLess: Out << "ls"; break;
+ // ::= rs # >>
+ case OO_GreaterGreater: Out << "rs"; break;
+ // ::= lS # <<=
+ case OO_LessLessEqual: Out << "lS"; break;
+ // ::= rS # >>=
+ case OO_GreaterGreaterEqual: Out << "rS"; break;
+ // ::= eq # ==
+ case OO_EqualEqual: Out << "eq"; break;
+ // ::= ne # !=
+ case OO_ExclaimEqual: Out << "ne"; break;
+ // ::= lt # <
+ case OO_Less: Out << "lt"; break;
+ // ::= gt # >
+ case OO_Greater: Out << "gt"; break;
+ // ::= le # <=
+ case OO_LessEqual: Out << "le"; break;
+ // ::= ge # >=
+ case OO_GreaterEqual: Out << "ge"; break;
+ // ::= nt # !
+ case OO_Exclaim: Out << "nt"; break;
+ // ::= aa # &&
+ case OO_AmpAmp: Out << "aa"; break;
+ // ::= oo # ||
+ case OO_PipePipe: Out << "oo"; break;
+ // ::= pp # ++
+ case OO_PlusPlus: Out << "pp"; break;
+ // ::= mm # --
+ case OO_MinusMinus: Out << "mm"; break;
+ // ::= cm # ,
+ case OO_Comma: Out << "cm"; break;
+ // ::= pm # ->*
+ case OO_ArrowStar: Out << "pm"; break;
+ // ::= pt # ->
+ case OO_Arrow: Out << "pt"; break;
+ // ::= cl # ()
+ case OO_Call: Out << "cl"; break;
+ // ::= ix # []
+ case OO_Subscript: Out << "ix"; break;
+
+ // ::= qu # ?
+ // The conditional operator can't be overloaded, but we still handle it when
+ // mangling expressions.
+ case OO_Conditional: Out << "qu"; break;
+
+ case OO_None:
+ case NUM_OVERLOADED_OPERATORS:
+ assert(false && "Not an overloaded operator");
+ break;
+ }
+}
+
+void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
+ // <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const
+ if (Quals.hasRestrict())
+ Out << 'r';
+ if (Quals.hasVolatile())
+ Out << 'V';
+ if (Quals.hasConst())
+ Out << 'K';
+
+ if (Quals.hasAddressSpace()) {
+ // Extension:
+ //
+ // <type> ::= U <address-space-number>
+ //
+ // where <address-space-number> is a source name consisting of 'AS'
+ // followed by the address space <number>.
+ llvm::SmallString<64> ASString;
+ ASString = "AS" + llvm::utostr_32(Quals.getAddressSpace());
+ Out << 'U' << ASString.size() << ASString;
+ }
+
+ // FIXME: For now, just drop all extension qualifiers on the floor.
+}
+
+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;
+
+ case RQ_LValue:
+ Out << 'R';
+ break;
+
+ case RQ_RValue:
+ Out << 'O';
+ break;
+ }
+}
+
+void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
+ Context.mangleObjCMethodName(MD, Out);
+}
+
+void CXXNameMangler::mangleType(QualType nonCanon) {
+ // Only operate on the canonical type!
+ QualType canon = nonCanon.getCanonicalType();
+
+ SplitQualType split = canon.split();
+ Qualifiers quals = split.second;
+ const Type *ty = split.first;
+
+ bool isSubstitutable = quals || !isa<BuiltinType>(ty);
+ if (isSubstitutable && mangleSubstitution(canon))
+ return;
+
+ // If we're mangling a qualified array type, push the qualifiers to
+ // the element type.
+ if (quals && isa<ArrayType>(ty)) {
+ ty = Context.getASTContext().getAsArrayType(canon);
+ quals = Qualifiers();
+
+ // Note that we don't update canon: we want to add the
+ // substitution at the canonical type.
+ }
+
+ if (quals) {
+ mangleQualifiers(quals);
+ // Recurse: even if the qualified type isn't yet substitutable,
+ // the unqualified type might be.
+ mangleType(QualType(ty, 0));
+ } else {
+ switch (ty->getTypeClass()) {
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define NON_CANONICAL_TYPE(CLASS, PARENT) \
+ case Type::CLASS: \
+ llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
+ return;
+#define TYPE(CLASS, PARENT) \
+ case Type::CLASS: \
+ mangleType(static_cast<const CLASS##Type*>(ty)); \
+ break;
+#include "clang/AST/TypeNodes.def"
+ }
+ }
+
+ // Add the substitution.
+ if (isSubstitutable)
+ addSubstitution(canon);
+}
+
+void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) {
+ if (!mangleStandardSubstitution(ND))
+ mangleName(ND);
+}
+
+void CXXNameMangler::mangleType(const BuiltinType *T) {
+ // <type> ::= <builtin-type>
+ // <builtin-type> ::= v # void
+ // ::= w # wchar_t
+ // ::= b # bool
+ // ::= c # char
+ // ::= a # signed char
+ // ::= h # unsigned char
+ // ::= s # short
+ // ::= t # unsigned short
+ // ::= i # int
+ // ::= j # unsigned int
+ // ::= l # long
+ // ::= m # unsigned long
+ // ::= x # long long, __int64
+ // ::= y # unsigned long long, __int64
+ // ::= n # __int128
+ // UNSUPPORTED: ::= o # unsigned __int128
+ // ::= f # float
+ // ::= d # double
+ // ::= e # long double, __float80
+ // UNSUPPORTED: ::= g # __float128
+ // UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits)
+ // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits)
+ // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits)
+ // UNSUPPORTED: ::= Dh # IEEE 754r half-precision floating point (16 bits)
+ // ::= Di # char32_t
+ // ::= Ds # char16_t
+ // ::= Dn # std::nullptr_t (i.e., decltype(nullptr))
+ // ::= u <source-name> # vendor extended type
+ switch (T->getKind()) {
+ case BuiltinType::Void: Out << 'v'; break;
+ case BuiltinType::Bool: Out << 'b'; break;
+ case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'c'; break;
+ case BuiltinType::UChar: Out << 'h'; break;
+ case BuiltinType::UShort: Out << 't'; break;
+ case BuiltinType::UInt: Out << 'j'; break;
+ case BuiltinType::ULong: Out << 'm'; break;
+ case BuiltinType::ULongLong: Out << 'y'; break;
+ case BuiltinType::UInt128: Out << 'o'; break;
+ case BuiltinType::SChar: Out << 'a'; break;
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U: Out << 'w'; break;
+ case BuiltinType::Char16: Out << "Ds"; break;
+ case BuiltinType::Char32: Out << "Di"; break;
+ case BuiltinType::Short: Out << 's'; break;
+ case BuiltinType::Int: Out << 'i'; break;
+ case BuiltinType::Long: Out << 'l'; break;
+ case BuiltinType::LongLong: Out << 'x'; break;
+ case BuiltinType::Int128: Out << 'n'; break;
+ case BuiltinType::Float: Out << 'f'; break;
+ case BuiltinType::Double: Out << 'd'; break;
+ case BuiltinType::LongDouble: Out << 'e'; break;
+ case BuiltinType::NullPtr: Out << "Dn"; break;
+
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ assert(false &&
+ "Overloaded and dependent types shouldn't get to name mangling");
+ break;
+ case BuiltinType::ObjCId: Out << "11objc_object"; break;
+ case BuiltinType::ObjCClass: Out << "10objc_class"; break;
+ case BuiltinType::ObjCSel: Out << "13objc_selector"; break;
+ }
+}
+
+// <type> ::= <function-type>
+// <function-type> ::= F [Y] <bare-function-type> E
+void CXXNameMangler::mangleType(const FunctionProtoType *T) {
+ Out << 'F';
+ // FIXME: We don't have enough information in the AST to produce the 'Y'
+ // encoding for extern "C" function types.
+ mangleBareFunctionType(T, /*MangleReturnType=*/true);
+ Out << 'E';
+}
+void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
+ llvm_unreachable("Can't mangle K&R function prototypes");
+}
+void CXXNameMangler::mangleBareFunctionType(const FunctionType *T,
+ bool MangleReturnType) {
+ // We should never be mangling something without a prototype.
+ const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
+
+ // <bare-function-type> ::= <signature type>+
+ if (MangleReturnType)
+ mangleType(Proto->getResultType());
+
+ if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
+ // <builtin-type> ::= v # void
+ Out << 'v';
+ return;
+ }
+
+ for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+ ArgEnd = Proto->arg_type_end();
+ Arg != ArgEnd; ++Arg)
+ mangleType(*Arg);
+
+ // <builtin-type> ::= z # ellipsis
+ if (Proto->isVariadic())
+ Out << 'z';
+}
+
+// <type> ::= <class-enum-type>
+// <class-enum-type> ::= <name>
+void CXXNameMangler::mangleType(const UnresolvedUsingType *T) {
+ mangleName(T->getDecl());
+}
+
+// <type> ::= <class-enum-type>
+// <class-enum-type> ::= <name>
+void CXXNameMangler::mangleType(const EnumType *T) {
+ mangleType(static_cast<const TagType*>(T));
+}
+void CXXNameMangler::mangleType(const RecordType *T) {
+ mangleType(static_cast<const TagType*>(T));
+}
+void CXXNameMangler::mangleType(const TagType *T) {
+ mangleName(T->getDecl());
+}
+
+// <type> ::= <array-type>
+// <array-type> ::= A <positive dimension number> _ <element type>
+// ::= A [<dimension expression>] _ <element type>
+void CXXNameMangler::mangleType(const ConstantArrayType *T) {
+ Out << 'A' << T->getSize() << '_';
+ mangleType(T->getElementType());
+}
+void CXXNameMangler::mangleType(const VariableArrayType *T) {
+ Out << 'A';
+ // decayed vla types (size 0) will just be skipped.
+ if (T->getSizeExpr())
+ mangleExpression(T->getSizeExpr());
+ Out << '_';
+ mangleType(T->getElementType());
+}
+void CXXNameMangler::mangleType(const DependentSizedArrayType *T) {
+ Out << 'A';
+ mangleExpression(T->getSizeExpr());
+ Out << '_';
+ mangleType(T->getElementType());
+}
+void CXXNameMangler::mangleType(const IncompleteArrayType *T) {
+ Out << "A_";
+ mangleType(T->getElementType());
+}
+
+// <type> ::= <pointer-to-member-type>
+// <pointer-to-member-type> ::= M <class type> <member type>
+void CXXNameMangler::mangleType(const MemberPointerType *T) {
+ Out << 'M';
+ mangleType(QualType(T->getClass(), 0));
+ QualType PointeeType = T->getPointeeType();
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) {
+ mangleQualifiers(Qualifiers::fromCVRMask(FPT->getTypeQuals()));
+ mangleRefQualifier(FPT->getRefQualifier());
+ mangleType(FPT);
+
+ // Itanium C++ ABI 5.1.8:
+ //
+ // The type of a non-static member function is considered to be different,
+ // for the purposes of substitution, from the type of a namespace-scope or
+ // static member function whose type appears similar. The types of two
+ // non-static member functions are considered to be different, for the
+ // purposes of substitution, if the functions are members of different
+ // classes. In other words, for the purposes of substitution, the class of
+ // which the function is a member is considered part of the type of
+ // function.
+
+ // We increment the SeqID here to emulate adding an entry to the
+ // substitution table. We can't actually add it because we don't want this
+ // particular function type to be substituted.
+ ++SeqID;
+ } else
+ mangleType(PointeeType);
+}
+
+// <type> ::= <template-param>
+void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
+ mangleTemplateParameter(T->getIndex());
+}
+
+// <type> ::= <template-param>
+void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) {
+ mangleTemplateParameter(T->getReplacedParameter()->getIndex());
+}
+
+// <type> ::= P <type> # pointer-to
+void CXXNameMangler::mangleType(const PointerType *T) {
+ Out << 'P';
+ mangleType(T->getPointeeType());
+}
+void CXXNameMangler::mangleType(const ObjCObjectPointerType *T) {
+ Out << 'P';
+ mangleType(T->getPointeeType());
+}
+
+// <type> ::= R <type> # reference-to
+void CXXNameMangler::mangleType(const LValueReferenceType *T) {
+ Out << 'R';
+ mangleType(T->getPointeeType());
+}
+
+// <type> ::= O <type> # rvalue reference-to (C++0x)
+void CXXNameMangler::mangleType(const RValueReferenceType *T) {
+ Out << 'O';
+ mangleType(T->getPointeeType());
+}
+
+// <type> ::= C <type> # complex pair (C 2000)
+void CXXNameMangler::mangleType(const ComplexType *T) {
+ Out << 'C';
+ mangleType(T->getElementType());
+}
+
+// ARM's ABI for Neon vector types specifies that they should be mangled as
+// if they are structs (to match ARM's initial implementation). The
+// vector type must be one of the special types predefined by ARM.
+void CXXNameMangler::mangleNeonVectorType(const VectorType *T) {
+ QualType EltType = T->getElementType();
+ assert(EltType->isBuiltinType() && "Neon vector element not a BuiltinType");
+ const char *EltName = 0;
+ if (T->getVectorKind() == VectorType::NeonPolyVector) {
+ switch (cast<BuiltinType>(EltType)->getKind()) {
+ case BuiltinType::SChar: EltName = "poly8_t"; break;
+ case BuiltinType::Short: EltName = "poly16_t"; break;
+ default: llvm_unreachable("unexpected Neon polynomial vector element type");
+ }
+ } else {
+ switch (cast<BuiltinType>(EltType)->getKind()) {
+ case BuiltinType::SChar: EltName = "int8_t"; break;
+ case BuiltinType::UChar: EltName = "uint8_t"; break;
+ case BuiltinType::Short: EltName = "int16_t"; break;
+ case BuiltinType::UShort: EltName = "uint16_t"; break;
+ case BuiltinType::Int: EltName = "int32_t"; break;
+ case BuiltinType::UInt: EltName = "uint32_t"; break;
+ 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");
+ }
+ }
+ const char *BaseName = 0;
+ unsigned BitSize = (T->getNumElements() *
+ getASTContext().getTypeSize(EltType));
+ if (BitSize == 64)
+ BaseName = "__simd64_";
+ else {
+ assert(BitSize == 128 && "Neon vector type not 64 or 128 bits");
+ BaseName = "__simd128_";
+ }
+ Out << strlen(BaseName) + strlen(EltName);
+ Out << BaseName << EltName;
+}
+
+// GNU extension: vector types
+// <type> ::= <vector-type>
+// <vector-type> ::= Dv <positive dimension number> _
+// <extended element type>
+// ::= Dv [<dimension expression>] _ <element type>
+// <extended element type> ::= <element type>
+// ::= p # AltiVec vector pixel
+void CXXNameMangler::mangleType(const VectorType *T) {
+ if ((T->getVectorKind() == VectorType::NeonVector ||
+ T->getVectorKind() == VectorType::NeonPolyVector)) {
+ mangleNeonVectorType(T);
+ return;
+ }
+ Out << "Dv" << T->getNumElements() << '_';
+ if (T->getVectorKind() == VectorType::AltiVecPixel)
+ Out << 'p';
+ else if (T->getVectorKind() == VectorType::AltiVecBool)
+ Out << 'b';
+ else
+ mangleType(T->getElementType());
+}
+void CXXNameMangler::mangleType(const ExtVectorType *T) {
+ mangleType(static_cast<const VectorType*>(T));
+}
+void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) {
+ Out << "Dv";
+ mangleExpression(T->getSizeExpr());
+ Out << '_';
+ mangleType(T->getElementType());
+}
+
+void CXXNameMangler::mangleType(const PackExpansionType *T) {
+ // <type> ::= Dp <type> # pack expansion (C++0x)
+ Out << "Dp";
+ mangleType(T->getPattern());
+}
+
+void CXXNameMangler::mangleType(const ObjCInterfaceType *T) {
+ mangleSourceName(T->getDecl()->getIdentifier());
+}
+
+void CXXNameMangler::mangleType(const ObjCObjectType *T) {
+ // We don't allow overloading by different protocol qualification,
+ // so mangling them isn't necessary.
+ mangleType(T->getBaseType());
+}
+
+void CXXNameMangler::mangleType(const BlockPointerType *T) {
+ Out << "U13block_pointer";
+ mangleType(T->getPointeeType());
+}
+
+void CXXNameMangler::mangleType(const InjectedClassNameType *T) {
+ // Mangle injected class name types as if the user had written the
+ // specialization out fully. It may not actually be possible to see
+ // this mangling, though.
+ mangleType(T->getInjectedSpecializationType());
+}
+
+void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
+ if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) {
+ mangleName(TD, T->getArgs(), T->getNumArgs());
+ } else {
+ if (mangleSubstitution(QualType(T, 0)))
+ return;
+
+ mangleTemplatePrefix(T->getTemplateName());
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs());
+ addSubstitution(QualType(T, 0));
+ }
+}
+
+void CXXNameMangler::mangleType(const DependentNameType *T) {
+ // Typename types are always nested
+ Out << 'N';
+ mangleUnresolvedScope(T->getQualifier());
+ mangleSourceName(T->getIdentifier());
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) {
+ // Dependently-scoped template types are always nested
+ Out << 'N';
+
+ // TODO: avoid making this TemplateName.
+ TemplateName Prefix =
+ getASTContext().getDependentTemplateName(T->getQualifier(),
+ T->getIdentifier());
+ mangleTemplatePrefix(Prefix);
+
+ // FIXME: GCC does not appear to mangle the template arguments when
+ // the template in question is a dependent template name. Should we
+ // emulate that badness?
+ mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs());
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleType(const TypeOfType *T) {
+ // FIXME: this is pretty unsatisfactory, but there isn't an obvious
+ // "extension with parameters" mangling.
+ Out << "u6typeof";
+}
+
+void CXXNameMangler::mangleType(const TypeOfExprType *T) {
+ // FIXME: this is pretty unsatisfactory, but there isn't an obvious
+ // "extension with parameters" mangling.
+ Out << "u6typeof";
+}
+
+void CXXNameMangler::mangleType(const DecltypeType *T) {
+ Expr *E = T->getUnderlyingExpr();
+
+ // type ::= Dt <expression> E # decltype of an id-expression
+ // # or class member access
+ // ::= DT <expression> E # decltype of an expression
+
+ // This purports to be an exhaustive list of id-expressions and
+ // class member accesses. Note that we do not ignore parentheses;
+ // parentheses change the semantics of decltype for these
+ // expressions (and cause the mangler to use the other form).
+ if (isa<DeclRefExpr>(E) ||
+ isa<MemberExpr>(E) ||
+ isa<UnresolvedLookupExpr>(E) ||
+ isa<DependentScopeDeclRefExpr>(E) ||
+ isa<CXXDependentScopeMemberExpr>(E) ||
+ isa<UnresolvedMemberExpr>(E))
+ Out << "Dt";
+ else
+ Out << "DT";
+ mangleExpression(E);
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleType(const AutoType *T) {
+ QualType D = T->getDeducedType();
+ assert(!D.isNull() && "can't mangle undeduced auto type");
+ mangleType(D);
+}
+
+void CXXNameMangler::mangleIntegerLiteral(QualType T,
+ const llvm::APSInt &Value) {
+ // <expr-primary> ::= L <type> <value number> E # integer literal
+ Out << 'L';
+
+ mangleType(T);
+ if (T->isBooleanType()) {
+ // Boolean values are encoded as 0/1.
+ Out << (Value.getBoolValue() ? '1' : '0');
+ } else {
+ mangleNumber(Value);
+ }
+ Out << 'E';
+
+}
+
+/// Mangles a member expression. Implicit accesses are not handled,
+/// but that should be okay, because you shouldn't be able to
+/// make an implicit access in a function template declaration.
+void CXXNameMangler::mangleMemberExpr(const Expr *Base,
+ bool IsArrow,
+ NestedNameSpecifier *Qualifier,
+ DeclarationName Member,
+ unsigned Arity) {
+ // gcc-4.4 uses 'dt' for dot expressions, which is reasonable.
+ // OTOH, gcc also mangles the name as an expression.
+ Out << (IsArrow ? "pt" : "dt");
+ mangleExpression(Base);
+ mangleUnresolvedName(Qualifier, Member, Arity);
+}
+
+void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
+ // <expression> ::= <unary operator-name> <expression>
+ // ::= <binary operator-name> <expression> <expression>
+ // ::= <trinary operator-name> <expression> <expression> <expression>
+ // ::= cl <expression>* E # call
+ // ::= cv <type> expression # conversion with one argument
+ // ::= cv <type> _ <expression>* E # conversion with a different number of arguments
+ // ::= st <type> # sizeof (a type)
+ // ::= at <type> # alignof (a type)
+ // ::= <template-param>
+ // ::= <function-param>
+ // ::= sr <type> <unqualified-name> # dependent name
+ // ::= sr <type> <unqualified-name> <template-args> # dependent template-id
+ // ::= sZ <template-param> # size of a parameter pack
+ // ::= sZ <function-param> # size of a function parameter pack
+ // ::= <expr-primary>
+ // <expr-primary> ::= L <type> <value number> E # integer literal
+ // ::= L <type <value float> E # floating literal
+ // ::= L <mangled-name> E # external name
+ switch (E->getStmtClass()) {
+ case Expr::NoStmtClass:
+#define ABSTRACT_STMT(Type)
+#define EXPR(Type, Base)
+#define STMT(Type, Base) \
+ case Expr::Type##Class:
+#include "clang/AST/StmtNodes.inc"
+ // fallthrough
+
+ // These all can only appear in local or variable-initialization
+ // contexts and so should never appear in a mangling.
+ case Expr::AddrLabelExprClass:
+ case Expr::BlockDeclRefExprClass:
+ case Expr::CXXThisExprClass:
+ case Expr::DesignatedInitExprClass:
+ case Expr::ImplicitValueInitExprClass:
+ case Expr::InitListExprClass:
+ case Expr::ParenListExprClass:
+ case Expr::CXXScalarValueInitExprClass:
+ llvm_unreachable("unexpected statement kind");
+ break;
+
+ // FIXME: invent manglings for all these.
+ case Expr::BlockExprClass:
+ case Expr::CXXPseudoDestructorExprClass:
+ case Expr::ChooseExprClass:
+ case Expr::CompoundLiteralExprClass:
+ case Expr::ExtVectorElementExprClass:
+ case Expr::ObjCEncodeExprClass:
+ case Expr::ObjCIsaExprClass:
+ case Expr::ObjCIvarRefExprClass:
+ case Expr::ObjCMessageExprClass:
+ case Expr::ObjCPropertyRefExprClass:
+ case Expr::ObjCProtocolExprClass:
+ case Expr::ObjCSelectorExprClass:
+ case Expr::ObjCStringLiteralClass:
+ case Expr::OffsetOfExprClass:
+ case Expr::PredefinedExprClass:
+ case Expr::ShuffleVectorExprClass:
+ case Expr::StmtExprClass:
+ case Expr::UnaryTypeTraitExprClass:
+ case Expr::BinaryTypeTraitExprClass:
+ case Expr::VAArgExprClass:
+ case Expr::CXXUuidofExprClass:
+ case Expr::CXXNoexceptExprClass:
+ case Expr::CUDAKernelCallExprClass: {
+ // As bad as this diagnostic is, it's better than crashing.
+ Diagnostic &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ "cannot yet mangle expression type %0");
+ Diags.Report(E->getExprLoc(), DiagID)
+ << E->getStmtClassName() << E->getSourceRange();
+ break;
+ }
+
+ // Even gcc-4.5 doesn't mangle this.
+ case Expr::BinaryConditionalOperatorClass: {
+ Diagnostic &Diags = Context.getDiags();
+ unsigned DiagID =
+ Diags.getCustomDiagID(Diagnostic::Error,
+ "?: operator with omitted middle operand cannot be mangled");
+ Diags.Report(E->getExprLoc(), DiagID)
+ << E->getStmtClassName() << E->getSourceRange();
+ break;
+ }
+
+ // These are used for internal purposes and cannot be meaningfully mangled.
+ case Expr::OpaqueValueExprClass:
+ llvm_unreachable("cannot mangle opaque value; mangling wrong thing?");
+
+ case Expr::CXXDefaultArgExprClass:
+ mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity);
+ break;
+
+ case Expr::CXXMemberCallExprClass: // fallthrough
+ case Expr::CallExprClass: {
+ const CallExpr *CE = cast<CallExpr>(E);
+ Out << "cl";
+ mangleExpression(CE->getCallee(), CE->getNumArgs());
+ for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I)
+ mangleExpression(CE->getArg(I));
+ Out << 'E';
+ break;
+ }
+
+ case Expr::CXXNewExprClass: {
+ // Proposal from David Vandervoorde, 2010.06.30
+ const CXXNewExpr *New = cast<CXXNewExpr>(E);
+ if (New->isGlobalNew()) Out << "gs";
+ Out << (New->isArray() ? "na" : "nw");
+ for (CXXNewExpr::const_arg_iterator I = New->placement_arg_begin(),
+ E = New->placement_arg_end(); I != E; ++I)
+ mangleExpression(*I);
+ Out << '_';
+ mangleType(New->getAllocatedType());
+ if (New->hasInitializer()) {
+ Out << "pi";
+ for (CXXNewExpr::const_arg_iterator I = New->constructor_arg_begin(),
+ E = New->constructor_arg_end(); I != E; ++I)
+ mangleExpression(*I);
+ }
+ Out << 'E';
+ break;
+ }
+
+ case Expr::MemberExprClass: {
+ const MemberExpr *ME = cast<MemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), ME->getMemberDecl()->getDeclName(),
+ Arity);
+ break;
+ }
+
+ case Expr::UnresolvedMemberExprClass: {
+ const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), ME->getMemberName(),
+ Arity);
+ if (ME->hasExplicitTemplateArgs())
+ mangleTemplateArgs(ME->getExplicitTemplateArgs());
+ break;
+ }
+
+ case Expr::CXXDependentScopeMemberExprClass: {
+ const CXXDependentScopeMemberExpr *ME
+ = cast<CXXDependentScopeMemberExpr>(E);
+ mangleMemberExpr(ME->getBase(), ME->isArrow(),
+ ME->getQualifier(), ME->getMember(),
+ Arity);
+ if (ME->hasExplicitTemplateArgs())
+ mangleTemplateArgs(ME->getExplicitTemplateArgs());
+ break;
+ }
+
+ case Expr::UnresolvedLookupExprClass: {
+ // The ABI doesn't cover how to mangle overload sets, so we mangle
+ // using something as close as possible to the original lookup
+ // expression.
+ const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E);
+ mangleUnresolvedName(ULE->getQualifier(), ULE->getName(), Arity);
+ if (ULE->hasExplicitTemplateArgs())
+ mangleTemplateArgs(ULE->getExplicitTemplateArgs());
+ break;
+ }
+
+ case Expr::CXXUnresolvedConstructExprClass: {
+ const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E);
+ unsigned N = CE->arg_size();
+
+ Out << "cv";
+ mangleType(CE->getType());
+ if (N != 1) Out << '_';
+ for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
+ if (N != 1) Out << 'E';
+ break;
+ }
+
+ case Expr::CXXTemporaryObjectExprClass:
+ case Expr::CXXConstructExprClass: {
+ const CXXConstructExpr *CE = cast<CXXConstructExpr>(E);
+ unsigned N = CE->getNumArgs();
+
+ Out << "cv";
+ mangleType(CE->getType());
+ if (N != 1) Out << '_';
+ for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I));
+ if (N != 1) Out << 'E';
+ break;
+ }
+
+ case Expr::SizeOfAlignOfExprClass: {
+ const SizeOfAlignOfExpr *SAE = cast<SizeOfAlignOfExpr>(E);
+ if (SAE->isSizeOf()) Out << 's';
+ else Out << 'a';
+ if (SAE->isArgumentType()) {
+ Out << 't';
+ mangleType(SAE->getArgumentType());
+ } else {
+ Out << 'z';
+ mangleExpression(SAE->getArgumentExpr());
+ }
+ break;
+ }
+
+ case Expr::CXXThrowExprClass: {
+ const CXXThrowExpr *TE = cast<CXXThrowExpr>(E);
+
+ // Proposal from David Vandervoorde, 2010.06.30
+ if (TE->getSubExpr()) {
+ Out << "tw";
+ mangleExpression(TE->getSubExpr());
+ } else {
+ Out << "tr";
+ }
+ break;
+ }
+
+ case Expr::CXXTypeidExprClass: {
+ const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E);
+
+ // Proposal from David Vandervoorde, 2010.06.30
+ if (TIE->isTypeOperand()) {
+ Out << "ti";
+ mangleType(TIE->getTypeOperand());
+ } else {
+ Out << "te";
+ mangleExpression(TIE->getExprOperand());
+ }
+ break;
+ }
+
+ case Expr::CXXDeleteExprClass: {
+ const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E);
+
+ // Proposal from David Vandervoorde, 2010.06.30
+ if (DE->isGlobalDelete()) Out << "gs";
+ Out << (DE->isArrayForm() ? "da" : "dl");
+ mangleExpression(DE->getArgument());
+ break;
+ }
+
+ case Expr::UnaryOperatorClass: {
+ const UnaryOperator *UO = cast<UnaryOperator>(E);
+ mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()),
+ /*Arity=*/1);
+ mangleExpression(UO->getSubExpr());
+ break;
+ }
+
+ case Expr::ArraySubscriptExprClass: {
+ const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E);
+
+ // Array subscript is treated as a syntactically wierd form of
+ // binary operator.
+ Out << "ix";
+ mangleExpression(AE->getLHS());
+ mangleExpression(AE->getRHS());
+ break;
+ }
+
+ case Expr::CompoundAssignOperatorClass: // fallthrough
+ case Expr::BinaryOperatorClass: {
+ const BinaryOperator *BO = cast<BinaryOperator>(E);
+ mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()),
+ /*Arity=*/2);
+ mangleExpression(BO->getLHS());
+ mangleExpression(BO->getRHS());
+ break;
+ }
+
+ case Expr::ConditionalOperatorClass: {
+ const ConditionalOperator *CO = cast<ConditionalOperator>(E);
+ mangleOperatorName(OO_Conditional, /*Arity=*/3);
+ mangleExpression(CO->getCond());
+ mangleExpression(CO->getLHS(), Arity);
+ mangleExpression(CO->getRHS(), Arity);
+ break;
+ }
+
+ case Expr::ImplicitCastExprClass: {
+ mangleExpression(cast<ImplicitCastExpr>(E)->getSubExpr(), Arity);
+ break;
+ }
+
+ case Expr::CStyleCastExprClass:
+ case Expr::CXXStaticCastExprClass:
+ case Expr::CXXDynamicCastExprClass:
+ case Expr::CXXReinterpretCastExprClass:
+ case Expr::CXXConstCastExprClass:
+ case Expr::CXXFunctionalCastExprClass: {
+ const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E);
+ Out << "cv";
+ mangleType(ECE->getType());
+ mangleExpression(ECE->getSubExpr());
+ break;
+ }
+
+ case Expr::CXXOperatorCallExprClass: {
+ const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E);
+ unsigned NumArgs = CE->getNumArgs();
+ mangleOperatorName(CE->getOperator(), /*Arity=*/NumArgs);
+ // Mangle the arguments.
+ for (unsigned i = 0; i != NumArgs; ++i)
+ mangleExpression(CE->getArg(i));
+ break;
+ }
+
+ case Expr::ParenExprClass:
+ mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity);
+ break;
+
+ case Expr::DeclRefExprClass: {
+ const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
+
+ switch (D->getKind()) {
+ default:
+ // <expr-primary> ::= L <mangled-name> E # external name
+ Out << 'L';
+ mangle(D, "_Z");
+ Out << 'E';
+ break;
+
+ case Decl::EnumConstant: {
+ const EnumConstantDecl *ED = cast<EnumConstantDecl>(D);
+ mangleIntegerLiteral(ED->getType(), ED->getInitVal());
+ break;
+ }
+
+ case Decl::NonTypeTemplateParm: {
+ const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
+ mangleTemplateParameter(PD->getIndex());
+ break;
+ }
+
+ }
+
+ break;
+ }
+
+ case Expr::SubstNonTypeTemplateParmPackExprClass:
+ mangleTemplateParameter(
+ cast<SubstNonTypeTemplateParmPackExpr>(E)->getParameterPack()->getIndex());
+ break;
+
+ case Expr::DependentScopeDeclRefExprClass: {
+ const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
+ NestedNameSpecifier *NNS = DRE->getQualifier();
+ const Type *QTy = NNS->getAsType();
+
+ // When we're dealing with a nested-name-specifier that has just a
+ // dependent identifier in it, mangle that as a typename. FIXME:
+ // It isn't clear that we ever actually want to have such a
+ // nested-name-specifier; why not just represent it as a typename type?
+ if (!QTy && NNS->getAsIdentifier() && NNS->getPrefix()) {
+ QTy = getASTContext().getDependentNameType(ETK_Typename,
+ NNS->getPrefix(),
+ NNS->getAsIdentifier())
+ .getTypePtr();
+ }
+ assert(QTy && "Qualifier was not type!");
+
+ // ::= sr <type> <unqualified-name> # dependent name
+ // ::= sr <type> <unqualified-name> <template-args> # dependent template-id
+ Out << "sr";
+ mangleType(QualType(QTy, 0));
+ mangleUnqualifiedName(0, DRE->getDeclName(), Arity);
+ if (DRE->hasExplicitTemplateArgs())
+ mangleTemplateArgs(DRE->getExplicitTemplateArgs());
+
+ break;
+ }
+
+ case Expr::CXXBindTemporaryExprClass:
+ mangleExpression(cast<CXXBindTemporaryExpr>(E)->getSubExpr());
+ break;
+
+ case Expr::ExprWithCleanupsClass:
+ mangleExpression(cast<ExprWithCleanups>(E)->getSubExpr(), Arity);
+ break;
+
+ case Expr::FloatingLiteralClass: {
+ const FloatingLiteral *FL = cast<FloatingLiteral>(E);
+ Out << 'L';
+ mangleType(FL->getType());
+ mangleFloat(FL->getValue());
+ Out << 'E';
+ break;
+ }
+
+ case Expr::CharacterLiteralClass:
+ Out << 'L';
+ mangleType(E->getType());
+ Out << cast<CharacterLiteral>(E)->getValue();
+ Out << 'E';
+ break;
+
+ case Expr::CXXBoolLiteralExprClass:
+ Out << "Lb";
+ Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0');
+ Out << 'E';
+ break;
+
+ case Expr::IntegerLiteralClass: {
+ llvm::APSInt Value(cast<IntegerLiteral>(E)->getValue());
+ if (E->getType()->isSignedIntegerType())
+ Value.setIsSigned(true);
+ mangleIntegerLiteral(E->getType(), Value);
+ break;
+ }
+
+ case Expr::ImaginaryLiteralClass: {
+ const ImaginaryLiteral *IE = cast<ImaginaryLiteral>(E);
+ // Mangle as if a complex literal.
+ // Proposal from David Vandevoorde, 2010.06.30.
+ Out << 'L';
+ mangleType(E->getType());
+ if (const FloatingLiteral *Imag =
+ dyn_cast<FloatingLiteral>(IE->getSubExpr())) {
+ // Mangle a floating-point zero of the appropriate type.
+ mangleFloat(llvm::APFloat(Imag->getValue().getSemantics()));
+ Out << '_';
+ mangleFloat(Imag->getValue());
+ } else {
+ Out << "0_";
+ llvm::APSInt Value(cast<IntegerLiteral>(IE->getSubExpr())->getValue());
+ if (IE->getSubExpr()->getType()->isSignedIntegerType())
+ Value.setIsSigned(true);
+ mangleNumber(Value);
+ }
+ Out << 'E';
+ break;
+ }
+
+ case Expr::StringLiteralClass: {
+ // Revised proposal from David Vandervoorde, 2010.07.15.
+ Out << 'L';
+ assert(isa<ConstantArrayType>(E->getType()));
+ mangleType(E->getType());
+ Out << 'E';
+ break;
+ }
+
+ case Expr::GNUNullExprClass:
+ // FIXME: should this really be mangled the same as nullptr?
+ // fallthrough
+
+ case Expr::CXXNullPtrLiteralExprClass: {
+ // Proposal from David Vandervoorde, 2010.06.30, as
+ // modified by ABI list discussion.
+ Out << "LDnE";
+ break;
+ }
+
+ case Expr::PackExpansionExprClass:
+ Out << "sp";
+ mangleExpression(cast<PackExpansionExpr>(E)->getPattern());
+ break;
+
+ case Expr::SizeOfPackExprClass: {
+ Out << "sZ";
+ const NamedDecl *Pack = cast<SizeOfPackExpr>(E)->getPack();
+ if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
+ mangleTemplateParameter(TTP->getIndex());
+ else if (const NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Pack))
+ mangleTemplateParameter(NTTP->getIndex());
+ else if (const TemplateTemplateParmDecl *TempTP
+ = dyn_cast<TemplateTemplateParmDecl>(Pack))
+ mangleTemplateParameter(TempTP->getIndex());
+ else {
+ // Note: proposed by Mike Herrick on 11/30/10
+ // <expression> ::= sZ <function-param> # size of function parameter pack
+ Diagnostic &Diags = Context.getDiags();
+ unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
+ "cannot mangle sizeof...(function parameter pack)");
+ Diags.Report(DiagID);
+ return;
+ }
+ }
+ }
+}
+
+void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
+ // <ctor-dtor-name> ::= C1 # complete object constructor
+ // ::= C2 # base object constructor
+ // ::= C3 # complete object allocating constructor
+ //
+ switch (T) {
+ case Ctor_Complete:
+ Out << "C1";
+ break;
+ case Ctor_Base:
+ Out << "C2";
+ break;
+ case Ctor_CompleteAllocating:
+ Out << "C3";
+ break;
+ }
+}
+
+void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
+ // <ctor-dtor-name> ::= D0 # deleting destructor
+ // ::= D1 # complete object destructor
+ // ::= D2 # base object destructor
+ //
+ switch (T) {
+ case Dtor_Deleting:
+ Out << "D0";
+ break;
+ case Dtor_Complete:
+ Out << "D1";
+ break;
+ case Dtor_Base:
+ Out << "D2";
+ break;
+ }
+}
+
+void CXXNameMangler::mangleTemplateArgs(
+ const ExplicitTemplateArgumentList &TemplateArgs) {
+ // <template-args> ::= I <template-arg>+ E
+ Out << 'I';
+ for (unsigned I = 0, E = TemplateArgs.NumTemplateArgs; I != E; ++I)
+ mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[I].getArgument());
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleTemplateArgs(TemplateName Template,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs,
+ NumTemplateArgs);
+
+ // <template-args> ::= I <template-arg>+ E
+ Out << 'I';
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ mangleTemplateArg(0, TemplateArgs[i]);
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
+ const TemplateArgumentList &AL) {
+ // <template-args> ::= I <template-arg>+ E
+ Out << 'I';
+ for (unsigned i = 0, e = AL.size(); i != e; ++i)
+ mangleTemplateArg(PL.getParam(i), AL[i]);
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs) {
+ // <template-args> ::= I <template-arg>+ E
+ Out << 'I';
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ mangleTemplateArg(PL.getParam(i), TemplateArgs[i]);
+ Out << 'E';
+}
+
+void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
+ const TemplateArgument &A) {
+ // <template-arg> ::= <type> # type or template
+ // ::= X <expression> E # expression
+ // ::= <expr-primary> # simple expressions
+ // ::= J <template-arg>* E # argument pack
+ // ::= sp <expression> # pack expansion of (C++0x)
+ switch (A.getKind()) {
+ case TemplateArgument::Null:
+ llvm_unreachable("Cannot mangle NULL template argument");
+
+ case TemplateArgument::Type:
+ mangleType(A.getAsType());
+ break;
+ case TemplateArgument::Template:
+ // This is mangled as <type>.
+ mangleType(A.getAsTemplate());
+ break;
+ case TemplateArgument::TemplateExpansion:
+ // <type> ::= Dp <type> # pack expansion (C++0x)
+ Out << "Dp";
+ mangleType(A.getAsTemplateOrTemplatePattern());
+ break;
+ case TemplateArgument::Expression:
+ Out << 'X';
+ mangleExpression(A.getAsExpr());
+ Out << 'E';
+ break;
+ case TemplateArgument::Integral:
+ mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral());
+ break;
+ case TemplateArgument::Declaration: {
+ assert(P && "Missing template parameter for declaration argument");
+ // <expr-primary> ::= L <mangled-name> E # external name
+
+ // Clang produces AST's where pointer-to-member-function expressions
+ // and pointer-to-function expressions are represented as a declaration not
+ // an expression. We compensate for it here to produce the correct mangling.
+ NamedDecl *D = cast<NamedDecl>(A.getAsDecl());
+ const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P);
+ bool compensateMangling = D->isCXXClassMember() &&
+ !Parameter->getType()->isReferenceType();
+ if (compensateMangling) {
+ Out << 'X';
+ mangleOperatorName(OO_Amp, 1);
+ }
+
+ Out << 'L';
+ // References to external entities use the mangled name; if the name would
+ // not normally be manged then mangle it as unqualified.
+ //
+ // FIXME: The ABI specifies that external names here should have _Z, but
+ // gcc leaves this off.
+ if (compensateMangling)
+ mangle(D, "_Z");
+ else
+ mangle(D, "Z");
+ Out << 'E';
+
+ if (compensateMangling)
+ Out << 'E';
+
+ break;
+ }
+
+ case TemplateArgument::Pack: {
+ // Note: proposal by Mike Herrick on 12/20/10
+ Out << 'J';
+ for (TemplateArgument::pack_iterator PA = A.pack_begin(),
+ PAEnd = A.pack_end();
+ PA != PAEnd; ++PA)
+ mangleTemplateArg(P, *PA);
+ Out << 'E';
+ }
+ }
+}
+
+void CXXNameMangler::mangleTemplateParameter(unsigned Index) {
+ // <template-param> ::= T_ # first template parameter
+ // ::= T <parameter-2 non-negative number> _
+ if (Index == 0)
+ Out << "T_";
+ else
+ Out << 'T' << (Index - 1) << '_';
+}
+
+// <substitution> ::= S <seq-id> _
+// ::= S_
+bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
+ // Try one of the standard substitutions first.
+ if (mangleStandardSubstitution(ND))
+ return true;
+
+ ND = cast<NamedDecl>(ND->getCanonicalDecl());
+ return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
+}
+
+bool CXXNameMangler::mangleSubstitution(QualType T) {
+ if (!T.getCVRQualifiers()) {
+ if (const RecordType *RT = T->getAs<RecordType>())
+ return mangleSubstitution(RT->getDecl());
+ }
+
+ uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+
+ return mangleSubstitution(TypePtr);
+}
+
+bool CXXNameMangler::mangleSubstitution(TemplateName Template) {
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return mangleSubstitution(TD);
+
+ Template = Context.getASTContext().getCanonicalTemplateName(Template);
+ return mangleSubstitution(
+ reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
+}
+
+bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
+ llvm::DenseMap<uintptr_t, unsigned>::iterator I = Substitutions.find(Ptr);
+ if (I == Substitutions.end())
+ return false;
+
+ unsigned SeqID = I->second;
+ if (SeqID == 0)
+ Out << "S_";
+ else {
+ SeqID--;
+
+ // <seq-id> is encoded in base-36, using digits and upper case letters.
+ char Buffer[10];
+ char *BufferPtr = llvm::array_endof(Buffer);
+
+ if (SeqID == 0) *--BufferPtr = '0';
+
+ while (SeqID) {
+ assert(BufferPtr > Buffer && "Buffer overflow!");
+
+ char c = static_cast<char>(SeqID % 36);
+
+ *--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10);
+ SeqID /= 36;
+ }
+
+ Out << 'S'
+ << llvm::StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr)
+ << '_';
+ }
+
+ return true;
+}
+
+static bool isCharType(QualType T) {
+ if (T.isNull())
+ return false;
+
+ return T->isSpecificBuiltinType(BuiltinType::Char_S) ||
+ T->isSpecificBuiltinType(BuiltinType::Char_U);
+}
+
+/// isCharSpecialization - Returns whether a given type is a template
+/// specialization of a given name with a single argument of type char.
+static bool isCharSpecialization(QualType T, const char *Name) {
+ if (T.isNull())
+ return false;
+
+ const RecordType *RT = T->getAs<RecordType>();
+ if (!RT)
+ return false;
+
+ const ClassTemplateSpecializationDecl *SD =
+ dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
+ if (!SD)
+ return false;
+
+ if (!isStdNamespace(SD->getDeclContext()))
+ return false;
+
+ const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
+ if (TemplateArgs.size() != 1)
+ return false;
+
+ if (!isCharType(TemplateArgs[0].getAsType()))
+ return false;
+
+ return SD->getIdentifier()->getName() == Name;
+}
+
+template <std::size_t StrLen>
+static bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl*SD,
+ const char (&Str)[StrLen]) {
+ if (!SD->getIdentifier()->isStr(Str))
+ return false;
+
+ const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
+ if (TemplateArgs.size() != 2)
+ return false;
+
+ if (!isCharType(TemplateArgs[0].getAsType()))
+ return false;
+
+ if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
+ return false;
+
+ return true;
+}
+
+bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
+ // <substitution> ::= St # ::std::
+ if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
+ if (isStd(NS)) {
+ Out << "St";
+ return true;
+ }
+ }
+
+ if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) {
+ if (!isStdNamespace(TD->getDeclContext()))
+ return false;
+
+ // <substitution> ::= Sa # ::std::allocator
+ if (TD->getIdentifier()->isStr("allocator")) {
+ Out << "Sa";
+ return true;
+ }
+
+ // <<substitution> ::= Sb # ::std::basic_string
+ if (TD->getIdentifier()->isStr("basic_string")) {
+ Out << "Sb";
+ return true;
+ }
+ }
+
+ if (const ClassTemplateSpecializationDecl *SD =
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ if (!isStdNamespace(SD->getDeclContext()))
+ return false;
+
+ // <substitution> ::= Ss # ::std::basic_string<char,
+ // ::std::char_traits<char>,
+ // ::std::allocator<char> >
+ if (SD->getIdentifier()->isStr("basic_string")) {
+ const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
+
+ if (TemplateArgs.size() != 3)
+ return false;
+
+ if (!isCharType(TemplateArgs[0].getAsType()))
+ return false;
+
+ if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
+ return false;
+
+ if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator"))
+ return false;
+
+ Out << "Ss";
+ return true;
+ }
+
+ // <substitution> ::= Si # ::std::basic_istream<char,
+ // ::std::char_traits<char> >
+ if (isStreamCharSpecialization(SD, "basic_istream")) {
+ Out << "Si";
+ return true;
+ }
+
+ // <substitution> ::= So # ::std::basic_ostream<char,
+ // ::std::char_traits<char> >
+ if (isStreamCharSpecialization(SD, "basic_ostream")) {
+ Out << "So";
+ return true;
+ }
+
+ // <substitution> ::= Sd # ::std::basic_iostream<char,
+ // ::std::char_traits<char> >
+ if (isStreamCharSpecialization(SD, "basic_iostream")) {
+ Out << "Sd";
+ return true;
+ }
+ }
+ return false;
+}
+
+void CXXNameMangler::addSubstitution(QualType T) {
+ if (!T.getCVRQualifiers()) {
+ if (const RecordType *RT = T->getAs<RecordType>()) {
+ addSubstitution(RT->getDecl());
+ return;
+ }
+ }
+
+ uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
+ addSubstitution(TypePtr);
+}
+
+void CXXNameMangler::addSubstitution(TemplateName Template) {
+ if (TemplateDecl *TD = Template.getAsTemplateDecl())
+ return addSubstitution(TD);
+
+ Template = Context.getASTContext().getCanonicalTemplateName(Template);
+ addSubstitution(reinterpret_cast<uintptr_t>(Template.getAsVoidPointer()));
+}
+
+void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
+ assert(!Substitutions.count(Ptr) && "Substitution already exists!");
+ Substitutions[Ptr] = SeqID++;
+}
+
+//
+
+/// \brief Mangles the name of the declaration D and emits that name to the
+/// given output stream.
+///
+/// If the declaration D requires a mangled name, this routine will emit that
+/// mangled name to \p os and return true. Otherwise, \p os will be unchanged
+/// 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,
+ llvm::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) &&
+ "Invalid mangleName() call on 'structor decl!");
+
+ PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
+ getASTContext().getSourceManager(),
+ "Mangling declaration");
+
+ CXXNameMangler Mangler(*this, Out);
+ return Mangler.mangle(D);
+}
+
+void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ llvm::raw_ostream &Out) {
+ CXXNameMangler Mangler(*this, Out, D, Type);
+ Mangler.mangle(D);
+}
+
+void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
+ CXXDtorType Type,
+ llvm::raw_ostream &Out) {
+ CXXNameMangler Mangler(*this, Out, D, Type);
+ Mangler.mangle(D);
+}
+
+void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
+ llvm::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>
+ // # base is the nominal target function of thunk
+ // # first call-offset is 'this' adjustment
+ // # second call-offset is result adjustment
+
+ assert(!isa<CXXDestructorDecl>(MD) &&
+ "Use mangleCXXDtor for destructor decls!");
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZT";
+ if (!Thunk.Return.isEmpty())
+ Mangler.getStream() << 'c';
+
+ // Mangle the 'this' pointer adjustment.
+ Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset);
+
+ // Mangle the return pointer adjustment if there is one.
+ if (!Thunk.Return.isEmpty())
+ Mangler.mangleCallOffset(Thunk.Return.NonVirtual,
+ Thunk.Return.VBaseOffsetOffset);
+
+ Mangler.mangleFunctionEncoding(MD);
+}
+
+void
+ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
+ CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment,
+ llvm::raw_ostream &Out) {
+ // <special-name> ::= T <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ CXXNameMangler Mangler(*this, Out, DD, Type);
+ Mangler.getStream() << "_ZT";
+
+ // Mangle the 'this' pointer adjustment.
+ Mangler.mangleCallOffset(ThisAdjustment.NonVirtual,
+ ThisAdjustment.VCallOffsetOffset);
+
+ Mangler.mangleFunctionEncoding(DD);
+}
+
+/// mangleGuardVariable - Returns the mangled name for a guard variable
+/// for the passed in VarDecl.
+void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D,
+ llvm::raw_ostream &Out) {
+ // <special-name> ::= GV <object name> # Guard variable for one-time
+ // # initialization
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZGV";
+ Mangler.mangleName(D);
+}
+
+void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D,
+ llvm::raw_ostream &Out) {
+ // We match the GCC mangling here.
+ // <special-name> ::= GR <object name>
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZGR";
+ Mangler.mangleName(D);
+}
+
+void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
+ llvm::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,
+ llvm::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,
+ llvm::raw_ostream &Out) {
+ // <special-name> ::= TC <type> <offset number> _ <base type>
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZTC";
+ Mangler.mangleNameOrStandardSubstitution(RD);
+ Mangler.getStream() << Offset;
+ Mangler.getStream() << '_';
+ Mangler.mangleNameOrStandardSubstitution(Type);
+}
+
+void ItaniumMangleContext::mangleCXXRTTI(QualType Ty,
+ llvm::raw_ostream &Out) {
+ // <special-name> ::= TI <type> # typeinfo structure
+ assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers");
+ CXXNameMangler Mangler(*this, Out);
+ Mangler.getStream() << "_ZTI";
+ Mangler.mangleType(Ty);
+}
+
+void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty,
+ llvm::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,
+ Diagnostic &Diags) {
+ return new ItaniumMangleContext(Context, Diags);
+}
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
new file mode 100644
index 0000000..3a0b909
--- /dev/null
+++ b/lib/AST/Mangle.cpp
@@ -0,0 +1,135 @@
+//===--- Mangle.cpp - Mangle C++ Names --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements generic name mangling support for blocks and Objective-C.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/Mangle.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/ABI.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#define MANGLE_CHECKER 0
+
+#if MANGLE_CHECKER
+#include <cxxabi.h>
+#endif
+
+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,
+ llvm::StringRef Outer,
+ const BlockDecl *BD,
+ llvm::raw_ostream &Out) {
+ Out << "__" << Outer << "_block_invoke_" << Context.getBlockId(BD, true);
+}
+
+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();
+ assert(DC == ExpectedDC && "Given decl context did not match expected!");
+#endif
+}
+
+}
+
+void MangleContext::mangleGlobalBlock(const BlockDecl *BD,
+ llvm::raw_ostream &Out) {
+ Out << "__block_global_" << getBlockId(BD, false);
+}
+
+void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD,
+ CXXCtorType CT, const BlockDecl *BD,
+ llvm::raw_ostream &ResStream) {
+ checkMangleDC(CD, BD);
+ llvm::SmallString<64> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ mangleCXXCtor(CD, CT, Out);
+ Out.flush();
+ mangleFunctionBlock(*this, Buffer, BD, ResStream);
+}
+
+void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD,
+ CXXDtorType DT, const BlockDecl *BD,
+ llvm::raw_ostream &ResStream) {
+ checkMangleDC(DD, BD);
+ llvm::SmallString<64> Buffer;
+ llvm::raw_svector_ostream Out(Buffer);
+ mangleCXXDtor(DD, DT, Out);
+ Out.flush();
+ mangleFunctionBlock(*this, Buffer, BD, ResStream);
+}
+
+void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD,
+ llvm::raw_ostream &Out) {
+ assert(!isa<CXXConstructorDecl>(DC) && !isa<CXXDestructorDecl>(DC));
+ checkMangleDC(DC, BD);
+
+ llvm::SmallString<64> Buffer;
+ llvm::raw_svector_ostream Stream(Buffer);
+ if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) {
+ mangleObjCMethodName(Method, Stream);
+ } else {
+ const NamedDecl *ND = cast<NamedDecl>(DC);
+ if (IdentifierInfo *II = ND->getIdentifier())
+ Stream << II->getName();
+ else {
+ // FIXME: We were doing a mangleUnqualifiedName() before, but that's
+ // a private member of a class that will soon itself be private to the
+ // Itanium C++ ABI object. What should we do now? Right now, I'm just
+ // calling the mangleName() method on the MangleContext; is there a
+ // better way?
+ mangleName(ND, Stream);
+ }
+ }
+ Stream.flush();
+ mangleFunctionBlock(*this, Buffer, BD, Out);
+}
+
+void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD,
+ llvm::raw_ostream &Out) {
+ llvm::SmallString<64> Name;
+ llvm::raw_svector_ostream OS(Name);
+
+ const ObjCContainerDecl *CD =
+ dyn_cast<ObjCContainerDecl>(MD->getDeclContext());
+ assert (CD && "Missing container decl in GetNameForMethod");
+ OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName();
+ if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD))
+ OS << '(' << CID << ')';
+ OS << ' ' << MD->getSelector().getAsString() << ']';
+
+ Out << OS.str().size() << OS.str();
+}
+
+void MangleContext::mangleBlock(const BlockDecl *BD,
+ llvm::raw_ostream &Out) {
+ 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, Out);
+}
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 87b7767..4de93bb 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -14,8 +14,10 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Type.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/TargetInfo.h"
using namespace clang;
@@ -26,6 +28,27 @@ public:
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
unsigned getMemberPointerSize(const MemberPointerType *MPT) const;
+
+ CallingConv getDefaultMethodCallConv() const {
+ if (Context.Target.getTriple().getArch() == llvm::Triple::x86)
+ return CC_X86ThisCall;
+ else
+ return CC_C;
+ }
+
+ bool isNearlyEmpty(const CXXRecordDecl *RD) const {
+ // FIXME: Audit the corners
+ if (!RD->isDynamicClass())
+ return false;
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+ // In the Microsoft ABI, classes can have one or two vtable pointers.
+ CharUnits PointerSize =
+ Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0));
+ return Layout.getNonVirtualSize() == PointerSize ||
+ Layout.getNonVirtualSize() == PointerSize * 2;
+ }
};
}
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
new file mode 100644
index 0000000..4bf7f23
--- /dev/null
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -0,0 +1,1188 @@
+//===--- MicrosoftMangle.cpp - Microsoft Visual C++ Name Mangling ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This provides C++ name mangling targetting the Microsoft Visual C++ ABI.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Mangle.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Basic/ABI.h"
+
+using namespace clang;
+
+namespace {
+
+/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the
+/// Microsoft Visual C++ ABI.
+class MicrosoftCXXNameMangler {
+ MangleContext &Context;
+ llvm::raw_ostream &Out;
+
+ ASTContext &getASTContext() const { return Context.getASTContext(); }
+
+public:
+ MicrosoftCXXNameMangler(MangleContext &C, llvm::raw_ostream &Out_)
+ : Context(C), Out(Out_) { }
+
+ void mangle(const NamedDecl *D, llvm::StringRef Prefix = "?");
+ void mangleName(const NamedDecl *ND);
+ void mangleFunctionEncoding(const FunctionDecl *FD);
+ void mangleVariableEncoding(const VarDecl *VD);
+ void mangleNumber(int64_t Number);
+ void mangleType(QualType T);
+
+private:
+ void mangleUnqualifiedName(const NamedDecl *ND) {
+ 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 mangleOperatorName(OverloadedOperatorKind OO);
+ void mangleQualifiers(Qualifiers Quals, bool IsMember);
+
+ void mangleObjCMethodName(const ObjCMethodDecl *MD);
+
+ // Declare manglers for every type class.
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define NON_CANONICAL_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T);
+#include "clang/AST/TypeNodes.def"
+
+ void mangleType(const TagType*);
+ void mangleType(const FunctionType *T, const FunctionDecl *D,
+ bool IsStructor, bool IsInstMethod);
+ void mangleType(const ArrayType *T, bool IsGlobal);
+ void mangleExtraDimensions(QualType T);
+ void mangleFunctionClass(const FunctionDecl *FD);
+ void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
+ void mangleThrowSpecification(const FunctionProtoType *T);
+
+};
+
+/// MicrosoftMangleContext - Overrides the default MangleContext for the
+/// Microsoft Visual C++ ABI.
+class MicrosoftMangleContext : public MangleContext {
+public:
+ MicrosoftMangleContext(ASTContext &Context,
+ Diagnostic &Diags) : MangleContext(Context, Diags) { }
+ virtual bool shouldMangleDeclName(const NamedDecl *D);
+ virtual void mangleName(const NamedDecl *D, llvm::raw_ostream &Out);
+ virtual void mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
+ llvm::raw_ostream &);
+ virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
+ const ThisAdjustment &ThisAdjustment,
+ llvm::raw_ostream &);
+ virtual void mangleCXXVTable(const CXXRecordDecl *RD,
+ llvm::raw_ostream &);
+ virtual void mangleCXXVTT(const CXXRecordDecl *RD,
+ llvm::raw_ostream &);
+ virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type,
+ llvm::raw_ostream &);
+ virtual void mangleCXXRTTI(QualType T, llvm::raw_ostream &);
+ virtual void mangleCXXRTTIName(QualType T, llvm::raw_ostream &);
+ virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ llvm::raw_ostream &);
+ virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ llvm::raw_ostream &);
+ virtual void mangleReferenceTemporary(const clang::VarDecl *,
+ llvm::raw_ostream &);
+};
+
+}
+
+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;
+ }
+
+ return false;
+}
+
+bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) {
+ // In C, functions with no attributes never need to be mangled. Fastpath them.
+ if (!getASTContext().getLangOptions().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;
+
+ // 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;
+
+ // Otherwise, no mangling is done outside C++ mode.
+ if (!getASTContext().getLangOptions().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)
+ return false;
+ }
+
+ // C functions and "main" are not mangled.
+ if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
+ return false;
+
+ return true;
+}
+
+void MicrosoftCXXNameMangler::mangle(const NamedDecl *D,
+ llvm::StringRef Prefix) {
+ // MSVC doesn't mangle C++ names the same way it mangles extern "C" names.
+ // Therefore it's really important that we don't decorate the
+ // name with leading underscores or leading/trailing at signs. So, emit a
+ // asm marker at the start so we get the name right.
+ Out << '\01'; // LLVM IR Marker for __asm("foo")
+
+ // 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 << ALA->getLabel();
+ return;
+ }
+
+ // <mangled-name> ::= ? <name> <type-encoding>
+ Out << Prefix;
+ mangleName(D);
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ mangleFunctionEncoding(FD);
+ else if (const VarDecl *VD = dyn_cast<VarDecl>(D))
+ mangleVariableEncoding(VD);
+ // TODO: Fields? Can MSVC even mangle them?
+}
+
+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;
+
+ // We should never ever see a FunctionNoProtoType at this point.
+ // We don't even know how to mangle their types anyway :).
+ const FunctionProtoType *FT = cast<FunctionProtoType>(FD->getType());
+
+ 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);
+
+ mangleType(FT, FD, InStructor, InInstMethod);
+}
+
+void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) {
+ // <type-encoding> ::= <storage-class> <variable-type>
+ // <storage-class> ::= 0 # private static member
+ // ::= 1 # protected static member
+ // ::= 2 # public static member
+ // ::= 3 # global
+ // ::= 4 # static local
+
+ // The first character in the encoding (after the name) is the storage class.
+ if (VD->isStaticDataMember()) {
+ // If it's a static member, it also encodes the access level.
+ switch (VD->getAccess()) {
+ default:
+ case AS_private: Out << '0'; break;
+ case AS_protected: Out << '1'; break;
+ case AS_public: Out << '2'; break;
+ }
+ }
+ else if (!VD->isStaticLocal())
+ Out << '3';
+ else
+ Out << '4';
+ // Now mangle the type.
+ // <variable-type> ::= <type> <cvr-qualifiers>
+ // ::= <type> A # pointers, references, arrays
+ // Pointers and references are odd. The type of 'int * const foo;' gets
+ // mangled as 'QAHA' instead of 'PAHB', for example.
+ QualType Ty = VD->getType();
+ if (Ty->isPointerType() || Ty->isReferenceType()) {
+ mangleType(Ty);
+ Out << 'A';
+ } else if (Ty->isArrayType()) {
+ // Global arrays are funny, too.
+ mangleType(cast<ArrayType>(Ty.getTypePtr()), true);
+ Out << 'A';
+ } else {
+ mangleType(Ty.getLocalUnqualifiedType());
+ mangleQualifiers(Ty.getLocalQualifiers(), false);
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) {
+ // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @
+ const DeclContext *DC = ND->getDeclContext();
+
+ // Always start with the unqualified name.
+ mangleUnqualifiedName(ND);
+
+ // If this is an extern variable declared locally, the relevant DeclContext
+ // is that of the containing namespace, or the translation unit.
+ if (isa<FunctionDecl>(DC) && ND->hasLinkage())
+ while (!DC->isNamespace() && !DC->isTranslationUnit())
+ DC = DC->getParent();
+
+ manglePostfix(DC);
+
+ // Terminate the whole name with an '@'.
+ Out << '@';
+}
+
+void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) {
+ // <number> ::= [?] <decimal digit> # <= 9
+ // ::= [?] <hex digit>+ @ # > 9; A = 0, B = 1, etc...
+ if (Number < 0) {
+ Out << '?';
+ Number = -Number;
+ }
+ if (Number >= 1 && Number <= 10) {
+ Out << Number-1;
+ } else {
+ // We have to build up the encoding in reverse order, so it will come
+ // out right when we write it out.
+ char Encoding[16];
+ char *EndPtr = Encoding+sizeof(Encoding);
+ char *CurPtr = EndPtr;
+ while (Number) {
+ *--CurPtr = 'A' + (Number % 16);
+ Number /= 16;
+ }
+ Out.write(CurPtr, EndPtr-CurPtr);
+ Out << '@';
+ }
+}
+
+void
+MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
+ DeclarationName Name) {
+ // <unqualified-name> ::= <operator-name>
+ // ::= <ctor-dtor-name>
+ // ::= <source-name>
+ switch (Name.getNameKind()) {
+ case DeclarationName::Identifier: {
+ if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
+ mangleSourceName(II);
+ break;
+ }
+
+ // Otherwise, an anonymous entity. We must have a declaration.
+ assert(ND && "mangling empty name without declaration");
+
+ if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
+ if (NS->isAnonymousNamespace()) {
+ Out << "?A";
+ break;
+ }
+ }
+
+ // We must have an anonymous struct.
+ const TagDecl *TD = cast<TagDecl>(ND);
+ if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
+ assert(TD->getDeclContext() == D->getDeclContext() &&
+ "Typedef should not be in another decl context!");
+ assert(D->getDeclName().getAsIdentifierInfo() &&
+ "Typedef was not named!");
+ mangleSourceName(D->getDeclName().getAsIdentifierInfo());
+ break;
+ }
+
+ // When VC encounters an anonymous type with no tag and no typedef,
+ // it literally emits '<unnamed-tag>'.
+ Out << "<unnamed-tag>";
+ break;
+ }
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ assert(false && "Can't mangle Objective-C selector names here!");
+ break;
+
+ case DeclarationName::CXXConstructorName:
+ assert(false && "Can't mangle constructors yet!");
+ break;
+
+ case DeclarationName::CXXDestructorName:
+ assert(false && "Can't mangle destructors yet!");
+ break;
+
+ case DeclarationName::CXXConversionFunctionName:
+ // <operator-name> ::= ?B # (cast)
+ // The target type is encoded as the return type.
+ Out << "?B";
+ break;
+
+ case DeclarationName::CXXOperatorName:
+ mangleOperatorName(Name.getCXXOverloadedOperator());
+ break;
+
+ case DeclarationName::CXXLiteralOperatorName:
+ // FIXME: Was this added in VS2010? Does MS even know how to mangle this?
+ assert(false && "Don't know how to mangle literal operators yet!");
+ break;
+
+ case DeclarationName::CXXUsingDirective:
+ assert(false && "Can't mangle a using directive name!");
+ break;
+ }
+}
+
+void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC,
+ bool NoFunction) {
+ // <postfix> ::= <unqualified-name> [<postfix>]
+ // ::= <template-postfix> <template-args> [<postfix>]
+ // ::= <template-param>
+ // ::= <substitution> [<postfix>]
+
+ if (!DC) return;
+
+ while (isa<LinkageSpecDecl>(DC))
+ DC = DC->getParent();
+
+ if (DC->isTranslationUnit())
+ return;
+
+ if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) {
+ Context.mangleBlock(BD, Out);
+ Out << '@';
+ return manglePostfix(DC->getParent(), NoFunction);
+ }
+
+ if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)))
+ return;
+ else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC))
+ mangleObjCMethodName(Method);
+ else {
+ mangleUnqualifiedName(cast<NamedDecl>(DC));
+ manglePostfix(DC->getParent(), NoFunction);
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO) {
+ switch (OO) {
+ // ?0 # constructor
+ // ?1 # destructor
+ // <operator-name> ::= ?2 # new
+ case OO_New: Out << "?2"; break;
+ // <operator-name> ::= ?3 # delete
+ case OO_Delete: Out << "?3"; break;
+ // <operator-name> ::= ?4 # =
+ case OO_Equal: Out << "?4"; break;
+ // <operator-name> ::= ?5 # >>
+ case OO_GreaterGreater: Out << "?5"; break;
+ // <operator-name> ::= ?6 # <<
+ case OO_LessLess: Out << "?6"; break;
+ // <operator-name> ::= ?7 # !
+ case OO_Exclaim: Out << "?7"; break;
+ // <operator-name> ::= ?8 # ==
+ case OO_EqualEqual: Out << "?8"; break;
+ // <operator-name> ::= ?9 # !=
+ case OO_ExclaimEqual: Out << "?9"; break;
+ // <operator-name> ::= ?A # []
+ case OO_Subscript: Out << "?A"; break;
+ // ?B # conversion
+ // <operator-name> ::= ?C # ->
+ case OO_Arrow: Out << "?C"; break;
+ // <operator-name> ::= ?D # *
+ case OO_Star: Out << "?D"; break;
+ // <operator-name> ::= ?E # ++
+ case OO_PlusPlus: Out << "?E"; break;
+ // <operator-name> ::= ?F # --
+ case OO_MinusMinus: Out << "?F"; break;
+ // <operator-name> ::= ?G # -
+ case OO_Minus: Out << "?G"; break;
+ // <operator-name> ::= ?H # +
+ case OO_Plus: Out << "?H"; break;
+ // <operator-name> ::= ?I # &
+ case OO_Amp: Out << "?I"; break;
+ // <operator-name> ::= ?J # ->*
+ case OO_ArrowStar: Out << "?J"; break;
+ // <operator-name> ::= ?K # /
+ case OO_Slash: Out << "?K"; break;
+ // <operator-name> ::= ?L # %
+ case OO_Percent: Out << "?L"; break;
+ // <operator-name> ::= ?M # <
+ case OO_Less: Out << "?M"; break;
+ // <operator-name> ::= ?N # <=
+ case OO_LessEqual: Out << "?N"; break;
+ // <operator-name> ::= ?O # >
+ case OO_Greater: Out << "?O"; break;
+ // <operator-name> ::= ?P # >=
+ case OO_GreaterEqual: Out << "?P"; break;
+ // <operator-name> ::= ?Q # ,
+ case OO_Comma: Out << "?Q"; break;
+ // <operator-name> ::= ?R # ()
+ case OO_Call: Out << "?R"; break;
+ // <operator-name> ::= ?S # ~
+ case OO_Tilde: Out << "?S"; break;
+ // <operator-name> ::= ?T # ^
+ case OO_Caret: Out << "?T"; break;
+ // <operator-name> ::= ?U # |
+ case OO_Pipe: Out << "?U"; break;
+ // <operator-name> ::= ?V # &&
+ case OO_AmpAmp: Out << "?V"; break;
+ // <operator-name> ::= ?W # ||
+ case OO_PipePipe: Out << "?W"; break;
+ // <operator-name> ::= ?X # *=
+ case OO_StarEqual: Out << "?X"; break;
+ // <operator-name> ::= ?Y # +=
+ case OO_PlusEqual: Out << "?Y"; break;
+ // <operator-name> ::= ?Z # -=
+ case OO_MinusEqual: Out << "?Z"; break;
+ // <operator-name> ::= ?_0 # /=
+ case OO_SlashEqual: Out << "?_0"; break;
+ // <operator-name> ::= ?_1 # %=
+ case OO_PercentEqual: Out << "?_1"; break;
+ // <operator-name> ::= ?_2 # >>=
+ case OO_GreaterGreaterEqual: Out << "?_2"; break;
+ // <operator-name> ::= ?_3 # <<=
+ case OO_LessLessEqual: Out << "?_3"; break;
+ // <operator-name> ::= ?_4 # &=
+ case OO_AmpEqual: Out << "?_4"; break;
+ // <operator-name> ::= ?_5 # |=
+ case OO_PipeEqual: Out << "?_5"; break;
+ // <operator-name> ::= ?_6 # ^=
+ case OO_CaretEqual: Out << "?_6"; break;
+ // ?_7 # vftable
+ // ?_8 # vbtable
+ // ?_9 # vcall
+ // ?_A # typeof
+ // ?_B # local static guard
+ // ?_C # string
+ // ?_D # vbase destructor
+ // ?_E # vector deleting destructor
+ // ?_F # default constructor closure
+ // ?_G # scalar deleting destructor
+ // ?_H # vector constructor iterator
+ // ?_I # vector destructor iterator
+ // ?_J # vector vbase constructor iterator
+ // ?_K # virtual displacement map
+ // ?_L # eh vector constructor iterator
+ // ?_M # eh vector destructor iterator
+ // ?_N # eh vector vbase constructor iterator
+ // ?_O # copy constructor closure
+ // ?_P<name> # udt returning <name>
+ // ?_Q # <unknown>
+ // ?_R0 # RTTI Type Descriptor
+ // ?_R1 # RTTI Base Class Descriptor at (a,b,c,d)
+ // ?_R2 # RTTI Base Class Array
+ // ?_R3 # RTTI Class Hierarchy Descriptor
+ // ?_R4 # RTTI Complete Object Locator
+ // ?_S # local vftable
+ // ?_T # local vftable constructor closure
+ // <operator-name> ::= ?_U # new[]
+ case OO_Array_New: Out << "?_U"; break;
+ // <operator-name> ::= ?_V # delete[]
+ case OO_Array_Delete: Out << "?_V"; break;
+
+ case OO_Conditional:
+ assert(false && "Don't know how to mangle ?:");
+ break;
+
+ case OO_None:
+ case NUM_OVERLOADED_OPERATORS:
+ assert(false && "Not an overloaded operator");
+ break;
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
+ // <source name> ::= <identifier> @
+ Out << II->getName() << '@';
+}
+
+void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) {
+ Context.mangleObjCMethodName(MD, Out);
+}
+
+void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals,
+ bool IsMember) {
+ // <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers>
+ // 'E' means __ptr64 (32-bit only); 'F' means __unaligned (32/64-bit only);
+ // 'I' means __restrict (32/64-bit).
+ // Note that the MSVC __restrict keyword isn't the same as the C99 restrict
+ // keyword!
+ // <base-cvr-qualifiers> ::= A # near
+ // ::= B # near const
+ // ::= C # near volatile
+ // ::= D # near const volatile
+ // ::= E # far (16-bit)
+ // ::= F # far const (16-bit)
+ // ::= G # far volatile (16-bit)
+ // ::= H # far const volatile (16-bit)
+ // ::= I # huge (16-bit)
+ // ::= J # huge const (16-bit)
+ // ::= K # huge volatile (16-bit)
+ // ::= L # huge const volatile (16-bit)
+ // ::= M <basis> # based
+ // ::= N <basis> # based const
+ // ::= O <basis> # based volatile
+ // ::= P <basis> # based const volatile
+ // ::= Q # near member
+ // ::= R # near const member
+ // ::= S # near volatile member
+ // ::= T # near const volatile member
+ // ::= U # far member (16-bit)
+ // ::= V # far const member (16-bit)
+ // ::= W # far volatile member (16-bit)
+ // ::= X # far const volatile member (16-bit)
+ // ::= Y # huge member (16-bit)
+ // ::= Z # huge const member (16-bit)
+ // ::= 0 # huge volatile member (16-bit)
+ // ::= 1 # huge const volatile member (16-bit)
+ // ::= 2 <basis> # based member
+ // ::= 3 <basis> # based const member
+ // ::= 4 <basis> # based volatile member
+ // ::= 5 <basis> # based const volatile member
+ // ::= 6 # near function (pointers only)
+ // ::= 7 # far function (pointers only)
+ // ::= 8 # near method (pointers only)
+ // ::= 9 # far method (pointers only)
+ // ::= _A <basis> # based function (pointers only)
+ // ::= _B <basis> # based function (far?) (pointers only)
+ // ::= _C <basis> # based method (pointers only)
+ // ::= _D <basis> # based method (far?) (pointers only)
+ // ::= _E # block (Clang)
+ // <basis> ::= 0 # __based(void)
+ // ::= 1 # __based(segment)?
+ // ::= 2 <name> # __based(name)
+ // ::= 3 # ?
+ // ::= 4 # ?
+ // ::= 5 # not really based
+ if (!IsMember) {
+ if (!Quals.hasVolatile()) {
+ if (!Quals.hasConst())
+ Out << 'A';
+ else
+ Out << 'B';
+ } else {
+ if (!Quals.hasConst())
+ Out << 'C';
+ else
+ Out << 'D';
+ }
+ } else {
+ if (!Quals.hasVolatile()) {
+ if (!Quals.hasConst())
+ Out << 'Q';
+ else
+ Out << 'R';
+ } else {
+ if (!Quals.hasConst())
+ Out << 'S';
+ else
+ Out << 'T';
+ }
+ }
+
+ // FIXME: For now, just drop all extension qualifiers on the floor.
+}
+
+void MicrosoftCXXNameMangler::mangleType(QualType T) {
+ // Only operate on the canonical type!
+ T = getASTContext().getCanonicalType(T);
+
+ Qualifiers Quals = T.getLocalQualifiers();
+ if (Quals) {
+ // We have to mangle these now, while we still have enough information.
+ // <pointer-cvr-qualifiers> ::= P # pointer
+ // ::= Q # const pointer
+ // ::= R # volatile pointer
+ // ::= S # const volatile pointer
+ if (T->isAnyPointerType() || T->isMemberPointerType() ||
+ T->isBlockPointerType()) {
+ if (!Quals.hasVolatile())
+ Out << 'Q';
+ else {
+ if (!Quals.hasConst())
+ Out << 'R';
+ else
+ Out << 'S';
+ }
+ } else
+ // Just emit qualifiers like normal.
+ // NB: When we mangle a pointer/reference type, and the pointee
+ // type has no qualifiers, the lack of qualifier gets mangled
+ // in there.
+ mangleQualifiers(Quals, false);
+ } else if (T->isAnyPointerType() || T->isMemberPointerType() ||
+ T->isBlockPointerType()) {
+ Out << 'P';
+ }
+ switch (T->getTypeClass()) {
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define NON_CANONICAL_TYPE(CLASS, PARENT) \
+case Type::CLASS: \
+llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \
+return;
+#define TYPE(CLASS, PARENT) \
+case Type::CLASS: \
+mangleType(static_cast<const CLASS##Type*>(T.getTypePtr())); \
+break;
+#include "clang/AST/TypeNodes.def"
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) {
+ // <type> ::= <builtin-type>
+ // <builtin-type> ::= X # void
+ // ::= C # signed char
+ // ::= D # char
+ // ::= E # unsigned char
+ // ::= F # short
+ // ::= G # unsigned short (or wchar_t if it's not a builtin)
+ // ::= H # int
+ // ::= I # unsigned int
+ // ::= J # long
+ // ::= K # unsigned long
+ // L # <none>
+ // ::= M # float
+ // ::= N # double
+ // ::= O # long double (__float80 is mangled differently)
+ // ::= _D # __int8 (yup, it's a distinct type in MSVC)
+ // ::= _E # unsigned __int8
+ // ::= _F # __int16
+ // ::= _G # unsigned __int16
+ // ::= _H # __int32
+ // ::= _I # unsigned __int32
+ // ::= _J # long long, __int64
+ // ::= _K # unsigned long long, __int64
+ // ::= _L # __int128
+ // ::= _M # unsigned __int128
+ // ::= _N # bool
+ // _O # <array in parameter>
+ // ::= _T # __float80 (Intel)
+ // ::= _W # wchar_t
+ // ::= _Z # __float80 (Digital Mars)
+ switch (T->getKind()) {
+ case BuiltinType::Void: Out << 'X'; break;
+ case BuiltinType::SChar: Out << 'C'; break;
+ case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'D'; break;
+ case BuiltinType::UChar: Out << 'E'; break;
+ case BuiltinType::Short: Out << 'F'; break;
+ case BuiltinType::UShort: Out << 'G'; break;
+ case BuiltinType::Int: Out << 'H'; break;
+ case BuiltinType::UInt: Out << 'I'; break;
+ case BuiltinType::Long: Out << 'J'; break;
+ case BuiltinType::ULong: Out << 'K'; break;
+ case BuiltinType::Float: Out << 'M'; break;
+ case BuiltinType::Double: Out << 'N'; break;
+ // TODO: Determine size and mangle accordingly
+ case BuiltinType::LongDouble: Out << 'O'; break;
+ // TODO: __int8 and friends
+ case BuiltinType::LongLong: Out << "_J"; break;
+ case BuiltinType::ULongLong: Out << "_K"; break;
+ case BuiltinType::Int128: Out << "_L"; break;
+ case BuiltinType::UInt128: Out << "_M"; break;
+ case BuiltinType::Bool: Out << "_N"; break;
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U: Out << "_W"; break;
+
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ assert(false &&
+ "Overloaded and dependent types shouldn't get to name mangling");
+ break;
+ case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break;
+ case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break;
+ case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break;
+
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::NullPtr:
+ assert(false && "Don't know how to mangle this type");
+ break;
+ }
+}
+
+// <type> ::= <function-type>
+void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T) {
+ // Structors only appear in decls, so at this point we know it's not a
+ // structor type.
+ // I'll probably have mangleType(MemberPointerType) call the mangleType()
+ // method directly.
+ mangleType(T, NULL, false, false);
+}
+void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T) {
+ llvm_unreachable("Can't mangle K&R function prototypes");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const FunctionType *T,
+ const FunctionDecl *D,
+ bool IsStructor,
+ bool IsInstMethod) {
+ // <function-type> ::= <this-cvr-qualifiers> <calling-convention>
+ // <return-type> <argument-list> <throw-spec>
+ const FunctionProtoType *Proto = cast<FunctionProtoType>(T);
+
+ // If this is a C++ instance method, mangle the CVR qualifiers for the
+ // this pointer.
+ if (IsInstMethod)
+ mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false);
+
+ mangleCallingConvention(T, IsInstMethod);
+
+ // <return-type> ::= <type>
+ // ::= @ # structors (they have no declared return type)
+ if (IsStructor)
+ Out << '@';
+ else
+ mangleType(Proto->getResultType());
+
+ // <argument-list> ::= X # void
+ // ::= <type>+ @
+ // ::= <type>* Z # varargs
+ if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) {
+ Out << 'X';
+ } else {
+ if (D) {
+ // If we got a decl, use the "types-as-written" to make sure arrays
+ // get mangled right.
+ for (FunctionDecl::param_const_iterator Parm = D->param_begin(),
+ ParmEnd = D->param_end();
+ Parm != ParmEnd; ++Parm)
+ mangleType((*Parm)->getTypeSourceInfo()->getType());
+ } else {
+ for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(),
+ ArgEnd = Proto->arg_type_end();
+ Arg != ArgEnd; ++Arg)
+ mangleType(*Arg);
+ }
+ // <builtin-type> ::= Z # ellipsis
+ if (Proto->isVariadic())
+ Out << 'Z';
+ else
+ Out << '@';
+ }
+
+ mangleThrowSpecification(Proto);
+}
+
+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
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ switch (MD->getAccess()) {
+ default:
+ case AS_private:
+ if (MD->isStatic())
+ Out << 'C';
+ else if (MD->isVirtual())
+ Out << 'E';
+ else
+ Out << 'A';
+ break;
+ case AS_protected:
+ if (MD->isStatic())
+ Out << 'K';
+ else if (MD->isVirtual())
+ Out << 'M';
+ else
+ Out << 'I';
+ break;
+ case AS_public:
+ if (MD->isStatic())
+ Out << 'S';
+ else if (MD->isVirtual())
+ Out << 'U';
+ else
+ Out << 'Q';
+ }
+ } else
+ Out << 'Y';
+}
+void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T,
+ bool IsInstMethod) {
+ // <calling-convention> ::= A # __cdecl
+ // ::= B # __export __cdecl
+ // ::= C # __pascal
+ // ::= D # __export __pascal
+ // ::= E # __thiscall
+ // ::= F # __export __thiscall
+ // ::= G # __stdcall
+ // ::= H # __export __stdcall
+ // ::= I # __fastcall
+ // ::= J # __export __fastcall
+ // The 'export' calling conventions are from a bygone era
+ // (*cough*Win16*cough*) when functions were declared for export with
+ // that keyword. (It didn't actually export them, it just made them so
+ // that they could be in a DLL and somebody from another module could call
+ // them.)
+ CallingConv CC = T->getCallConv();
+ if (CC == CC_Default)
+ CC = IsInstMethod ? getASTContext().getDefaultMethodCallConv() : CC_C;
+ switch (CC) {
+ case CC_Default:
+ case CC_C: Out << 'A'; break;
+ case CC_X86Pascal: Out << 'C'; break;
+ case CC_X86ThisCall: Out << 'E'; break;
+ case CC_X86StdCall: Out << 'G'; break;
+ case CC_X86FastCall: Out << 'I'; break;
+ }
+}
+void MicrosoftCXXNameMangler::mangleThrowSpecification(
+ const FunctionProtoType *FT) {
+ // <throw-spec> ::= Z # throw(...) (default)
+ // ::= @ # throw() or __declspec/__attribute__((nothrow))
+ // ::= <type>+
+ // NOTE: Since the Microsoft compiler ignores throw specifications, they are
+ // all actually mangled as 'Z'. (They're ignored because their associated
+ // functionality isn't implemented, and probably never will be.)
+ Out << 'Z';
+}
+
+void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T) {
+ assert(false && "Don't know how to mangle UnresolvedUsingTypes yet!");
+}
+
+// <type> ::= <union-type> | <struct-type> | <class-type> | <enum-type>
+// <union-type> ::= T <name>
+// <struct-type> ::= U <name>
+// <class-type> ::= V <name>
+// <enum-type> ::= W <size> <name>
+void MicrosoftCXXNameMangler::mangleType(const EnumType *T) {
+ mangleType(static_cast<const TagType*>(T));
+}
+void MicrosoftCXXNameMangler::mangleType(const RecordType *T) {
+ mangleType(static_cast<const TagType*>(T));
+}
+void MicrosoftCXXNameMangler::mangleType(const TagType *T) {
+ switch (T->getDecl()->getTagKind()) {
+ case TTK_Union:
+ Out << 'T';
+ break;
+ case TTK_Struct:
+ Out << 'U';
+ break;
+ case TTK_Class:
+ Out << 'V';
+ break;
+ case TTK_Enum:
+ Out << 'W';
+ Out << getASTContext().getTypeSizeInChars(
+ cast<EnumDecl>(T->getDecl())->getIntegerType()).getQuantity();
+ break;
+ }
+ mangleName(T->getDecl());
+}
+
+// <type> ::= <array-type>
+// <array-type> ::= P <cvr-qualifiers> [Y <dimension-count> <dimension>+]
+// <element-type> # as global
+// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+]
+// <element-type> # as param
+// 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::mangleType(const ArrayType *T, bool IsGlobal) {
+ // This isn't a recursive mangling, so now we have to do it all in this
+ // one call.
+ if (IsGlobal)
+ Out << 'P';
+ else
+ Out << 'Q';
+ mangleExtraDimensions(T->getElementType());
+}
+void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T) {
+ mangleType(static_cast<const ArrayType *>(T), false);
+}
+void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T) {
+ mangleType(static_cast<const ArrayType *>(T), false);
+}
+void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T) {
+ mangleType(static_cast<const ArrayType *>(T), false);
+}
+void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T) {
+ mangleType(static_cast<const ArrayType *>(T), false);
+}
+void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) {
+ llvm::SmallVector<llvm::APInt, 3> Dimensions;
+ for (;;) {
+ if (ElementTy->isConstantArrayType()) {
+ const ConstantArrayType *CAT =
+ static_cast<const ConstantArrayType *>(ElementTy.getTypePtr());
+ Dimensions.push_back(CAT->getSize());
+ ElementTy = CAT->getElementType();
+ } else if (ElementTy->isVariableArrayType()) {
+ assert(false && "Don't know how to mangle VLAs!");
+ } else if (ElementTy->isDependentSizedArrayType()) {
+ // The dependent expression has to be folded into a constant (TODO).
+ assert(false && "Don't know how to mangle dependent-sized arrays!");
+ } else if (ElementTy->isIncompleteArrayType()) continue;
+ else break;
+ }
+ mangleQualifiers(ElementTy.getQualifiers(), false);
+ // If there are any additional dimensions, mangle them now.
+ if (Dimensions.size() > 0) {
+ Out << 'Y';
+ // <dimension-count> ::= <number> # number of extra dimensions
+ mangleNumber(Dimensions.size());
+ for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) {
+ mangleNumber(Dimensions[Dim].getLimitedValue());
+ }
+ }
+ mangleType(ElementTy.getLocalUnqualifiedType());
+}
+
+// <type> ::= <pointer-to-member-type>
+// <pointer-to-member-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers>
+// <class name> <type>
+void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T) {
+ QualType PointeeType = T->getPointeeType();
+ if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) {
+ Out << '8';
+ mangleName(cast<RecordType>(T->getClass())->getDecl());
+ mangleType(FPT, NULL, false, true);
+ } else {
+ mangleQualifiers(PointeeType.getQualifiers(), true);
+ mangleName(cast<RecordType>(T->getClass())->getDecl());
+ mangleType(PointeeType.getLocalUnqualifiedType());
+ }
+}
+
+void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T) {
+ assert(false && "Don't know how to mangle TemplateTypeParmTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(
+ const SubstTemplateTypeParmPackType *T) {
+ assert(false &&
+ "Don't know how to mangle SubstTemplateTypeParmPackTypes yet!");
+}
+
+// <type> ::= <pointer-type>
+// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type>
+void MicrosoftCXXNameMangler::mangleType(const PointerType *T) {
+ QualType PointeeTy = T->getPointeeType();
+ if (PointeeTy->isArrayType()) {
+ // Pointers to arrays are mangled like arrays.
+ mangleExtraDimensions(T->getPointeeType());
+ } else if (PointeeTy->isFunctionType()) {
+ // Function pointers are special.
+ Out << '6';
+ mangleType(static_cast<const FunctionType *>(PointeeTy.getTypePtr()),
+ NULL, false, false);
+ } else {
+ if (!PointeeTy.hasQualifiers())
+ // Lack of qualifiers is mangled as 'A'.
+ Out << 'A';
+ mangleType(PointeeTy);
+ }
+}
+void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T) {
+ // Object pointers never have qualifiers.
+ Out << 'A';
+ mangleType(T->getPointeeType());
+}
+
+// <type> ::= <reference-type>
+// <reference-type> ::= A <cvr-qualifiers> <type>
+void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T) {
+ Out << 'A';
+ QualType PointeeTy = T->getPointeeType();
+ if (!PointeeTy.hasQualifiers())
+ // Lack of qualifiers is mangled as 'A'.
+ Out << 'A';
+ mangleType(PointeeTy);
+}
+
+void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T) {
+ assert(false && "Don't know how to mangle RValueReferenceTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const ComplexType *T) {
+ assert(false && "Don't know how to mangle ComplexTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const VectorType *T) {
+ assert(false && "Don't know how to mangle VectorTypes yet!");
+}
+void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T) {
+ assert(false && "Don't know how to mangle ExtVectorTypes yet!");
+}
+void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T) {
+ assert(false && "Don't know how to mangle DependentSizedExtVectorTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T) {
+ // ObjC interfaces have structs underlying them.
+ Out << 'U';
+ mangleName(T->getDecl());
+}
+
+void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T) {
+ // We don't allow overloading by different protocol qualification,
+ // so mangling them isn't necessary.
+ mangleType(T->getBaseType());
+}
+
+void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T) {
+ Out << "_E";
+ mangleType(T->getPointeeType());
+}
+
+void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T) {
+ assert(false && "Don't know how to mangle InjectedClassNameTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T) {
+ assert(false && "Don't know how to mangle TemplateSpecializationTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T) {
+ assert(false && "Don't know how to mangle DependentNameTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(
+ const DependentTemplateSpecializationType *T) {
+ assert(false &&
+ "Don't know how to mangle DependentTemplateSpecializationTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T) {
+ assert(false && "Don't know how to mangle PackExpansionTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T) {
+ assert(false && "Don't know how to mangle TypeOfTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T) {
+ assert(false && "Don't know how to mangle TypeOfExprTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T) {
+ assert(false && "Don't know how to mangle DecltypeTypes yet!");
+}
+
+void MicrosoftCXXNameMangler::mangleType(const AutoType *T) {
+ assert(false && "Don't know how to mangle AutoTypes yet!");
+}
+
+void MicrosoftMangleContext::mangleName(const NamedDecl *D,
+ llvm::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) &&
+ "Invalid mangleName() call on 'structor decl!");
+
+ PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
+ getASTContext().getSourceManager(),
+ "Mangling declaration");
+
+ MicrosoftCXXNameMangler Mangler(*this, Out);
+ return Mangler.mangle(D);
+}
+void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD,
+ const ThunkInfo &Thunk,
+ llvm::raw_ostream &) {
+ assert(false && "Can't yet mangle thunks!");
+}
+void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD,
+ CXXDtorType Type,
+ const ThisAdjustment &,
+ llvm::raw_ostream &) {
+ assert(false && "Can't yet mangle destructor thunks!");
+}
+void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD,
+ llvm::raw_ostream &) {
+ assert(false && "Can't yet mangle virtual tables!");
+}
+void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
+ llvm::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,
+ llvm::raw_ostream &) {
+ llvm_unreachable("The MS C++ ABI does not have constructor vtables!");
+}
+void MicrosoftMangleContext::mangleCXXRTTI(QualType T,
+ llvm::raw_ostream &) {
+ assert(false && "Can't yet mangle RTTI!");
+}
+void MicrosoftMangleContext::mangleCXXRTTIName(QualType T,
+ llvm::raw_ostream &) {
+ assert(false && "Can't yet mangle RTTI names!");
+}
+void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
+ CXXCtorType Type,
+ llvm::raw_ostream &) {
+ assert(false && "Can't yet mangle constructors!");
+}
+void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
+ CXXDtorType Type,
+ llvm::raw_ostream &) {
+ assert(false && "Can't yet mangle destructors!");
+}
+void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *,
+ llvm::raw_ostream &) {
+ assert(false && "Can't yet mangle reference temporaries!");
+}
+
+MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context,
+ Diagnostic &Diags) {
+ return new MicrosoftMangleContext(Context, Diags);
+}
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 212def8..650321d 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -22,7 +22,7 @@
using namespace clang;
NestedNameSpecifier *
-NestedNameSpecifier::FindOrInsert(ASTContext &Context,
+NestedNameSpecifier::FindOrInsert(const ASTContext &Context,
const NestedNameSpecifier &Mockup) {
llvm::FoldingSetNodeID ID;
Mockup.Profile(ID);
@@ -39,8 +39,8 @@ NestedNameSpecifier::FindOrInsert(ASTContext &Context,
}
NestedNameSpecifier *
-NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
- IdentifierInfo *II) {
+NestedNameSpecifier::Create(const ASTContext &Context,
+ NestedNameSpecifier *Prefix, IdentifierInfo *II) {
assert(II && "Identifier cannot be NULL");
assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent");
@@ -52,8 +52,8 @@ NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
}
NestedNameSpecifier *
-NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
- NamespaceDecl *NS) {
+NestedNameSpecifier::Create(const ASTContext &Context,
+ NestedNameSpecifier *Prefix, NamespaceDecl *NS) {
assert(NS && "Namespace cannot be NULL");
assert((!Prefix ||
(Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
@@ -66,18 +66,19 @@ NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
}
NestedNameSpecifier *
-NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix,
- bool Template, Type *T) {
+NestedNameSpecifier::Create(const ASTContext &Context,
+ NestedNameSpecifier *Prefix,
+ bool Template, const Type *T) {
assert(T && "Type cannot be NULL");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
Mockup.Prefix.setInt(Template? TypeSpecWithTemplate : TypeSpec);
- Mockup.Specifier = T;
+ Mockup.Specifier = const_cast<Type*>(T);
return FindOrInsert(Context, Mockup);
}
NestedNameSpecifier *
-NestedNameSpecifier::Create(ASTContext &Context, IdentifierInfo *II) {
+NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) {
assert(II && "Identifier cannot be NULL");
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(0);
@@ -86,7 +87,8 @@ NestedNameSpecifier::Create(ASTContext &Context, IdentifierInfo *II) {
return FindOrInsert(Context, Mockup);
}
-NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) {
+NestedNameSpecifier *
+NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) {
if (!Context.GlobalNestedNameSpecifier)
Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier();
return Context.GlobalNestedNameSpecifier;
@@ -113,6 +115,24 @@ bool NestedNameSpecifier::isDependent() const {
return false;
}
+bool NestedNameSpecifier::containsUnexpandedParameterPack() const {
+ switch (getKind()) {
+ case Identifier:
+ return getPrefix() && getPrefix()->containsUnexpandedParameterPack();
+
+ case Namespace:
+ case Global:
+ return false;
+
+ case TypeSpec:
+ case TypeSpecWithTemplate:
+ return getAsType()->containsUnexpandedParameterPack();
+ }
+
+ // Necessary to suppress a GCC warning.
+ return false;
+}
+
/// \brief Print this nested name specifier to the given output
/// stream.
void
@@ -139,7 +159,7 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS,
case TypeSpec: {
std::string TypeStr;
- Type *T = getAsType();
+ const Type *T = getAsType();
PrintingPolicy InnerPolicy(Policy);
InnerPolicy.SuppressScope = true;
diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp
index 5fe873a..eca351a 100644
--- a/lib/AST/ParentMap.cpp
+++ b/lib/AST/ParentMap.cpp
@@ -21,7 +21,7 @@ using namespace clang;
typedef llvm::DenseMap<Stmt*, Stmt*> MapTy;
static void BuildParentMap(MapTy& M, Stmt* S) {
- for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I)
+ for (Stmt::child_range I = S->children(); I; ++I)
if (*I) {
M[*I] = S;
BuildParentMap(M, *I);
@@ -40,6 +40,12 @@ ParentMap::~ParentMap() {
delete (MapTy*) Impl;
}
+void ParentMap::addStmt(Stmt* S) {
+ if (S) {
+ BuildParentMap(*(MapTy*) Impl, S);
+ }
+}
+
Stmt* ParentMap::getParent(Stmt* S) const {
MapTy* M = (MapTy*) Impl;
MapTy::iterator I = M->find(S);
@@ -51,6 +57,15 @@ Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const {
return S;
}
+Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const {
+ do {
+ S = getParent(S);
+ }
+ while (S && (isa<ParenExpr>(S) || isa<CastExpr>(S)));
+
+ return S;
+}
+
bool ParentMap::isConsumedExpr(Expr* E) const {
Stmt *P = getParent(E);
Stmt *DirectChild = E;
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index 4d9c516..035c48f 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -27,9 +27,10 @@ void ASTRecordLayout::Destroy(ASTContext &Ctx) {
Ctx.Deallocate(this);
}
-ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignment,
- unsigned datasize, const uint64_t *fieldoffsets,
- unsigned fieldcount)
+ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size,
+ CharUnits alignment, CharUnits datasize,
+ const uint64_t *fieldoffsets,
+ unsigned fieldcount)
: Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
FieldCount(fieldcount), CXXInfo(0) {
if (FieldCount > 0) {
@@ -39,16 +40,16 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx, uint64_t size, unsigned alignm
}
// Constructor for C++ records.
-ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx,
- uint64_t size, unsigned alignment,
- uint64_t datasize,
+ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
+ CharUnits size, CharUnits alignment,
+ CharUnits datasize,
const uint64_t *fieldoffsets,
unsigned fieldcount,
- uint64_t nonvirtualsize,
- unsigned nonvirtualalign,
- uint64_t SizeOfLargestEmptySubobject,
+ CharUnits nonvirtualsize,
+ CharUnits nonvirtualalign,
+ CharUnits SizeOfLargestEmptySubobject,
const CXXRecordDecl *PrimaryBase,
- bool PrimaryBaseIsVirtual,
+ bool IsPrimaryBaseVirtual,
const BaseOffsetsMapTy& BaseOffsets,
const BaseOffsetsMapTy& VBaseOffsets)
: Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment),
@@ -59,7 +60,8 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx,
memcpy(FieldOffsets, fieldoffsets, FieldCount * sizeof(*FieldOffsets));
}
- CXXInfo->PrimaryBase = PrimaryBaseInfo(PrimaryBase, PrimaryBaseIsVirtual);
+ CXXInfo->PrimaryBase.setPointer(PrimaryBase);
+ CXXInfo->PrimaryBase.setInt(IsPrimaryBaseVirtual);
CXXInfo->NonVirtualSize = nonvirtualsize;
CXXInfo->NonVirtualAlign = nonvirtualalign;
CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject;
@@ -68,11 +70,11 @@ ASTRecordLayout::ASTRecordLayout(ASTContext &Ctx,
#ifndef NDEBUG
if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
- if (getPrimaryBaseWasVirtual())
- assert(getVBaseClassOffset(PrimaryBase) == 0 &&
+ if (isPrimaryBaseVirtual())
+ assert(getVBaseClassOffset(PrimaryBase).isZero() &&
"Primary virtual base must be at offset 0!");
else
- assert(getBaseClassOffset(PrimaryBase) == 0 &&
+ assert(getBaseClassOffsetInBits(PrimaryBase) == 0 &&
"Primary base must be at offset 0!");
}
#endif
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 13fae29..cf14eba 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -8,12 +8,14 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Attr.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/Support/MathExtras.h"
@@ -55,62 +57,71 @@ struct BaseSubobjectInfo {
/// EmptySubobjectMap - Keeps track of which empty subobjects exist at different
/// offsets while laying out a C++ class.
class EmptySubobjectMap {
- ASTContext &Context;
-
+ const ASTContext &Context;
+ uint64_t CharWidth;
+
/// Class - The class whose empty entries we're keeping track of.
const CXXRecordDecl *Class;
/// EmptyClassOffsets - A map from offsets to empty record decls.
typedef llvm::SmallVector<const CXXRecordDecl *, 1> ClassVectorTy;
- typedef llvm::DenseMap<uint64_t, ClassVectorTy> EmptyClassOffsetsMapTy;
+ typedef llvm::DenseMap<CharUnits, ClassVectorTy> EmptyClassOffsetsMapTy;
EmptyClassOffsetsMapTy EmptyClassOffsets;
/// MaxEmptyClassOffset - The highest offset known to contain an empty
/// base subobject.
- uint64_t MaxEmptyClassOffset;
+ CharUnits MaxEmptyClassOffset;
/// ComputeEmptySubobjectSizes - Compute the size of the largest base or
/// member subobject that is empty.
void ComputeEmptySubobjectSizes();
- void AddSubobjectAtOffset(const CXXRecordDecl *RD, uint64_t Offset);
+ void AddSubobjectAtOffset(const CXXRecordDecl *RD, CharUnits Offset);
void UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
- uint64_t Offset, bool PlacingEmptyBase);
+ CharUnits Offset, bool PlacingEmptyBase);
void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
- uint64_t Offset);
- void UpdateEmptyFieldSubobjects(const FieldDecl *FD, uint64_t Offset);
+ CharUnits Offset);
+ void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset);
/// AnyEmptySubobjectsBeyondOffset - Returns whether there are any empty
/// subobjects beyond the given offset.
- bool AnyEmptySubobjectsBeyondOffset(uint64_t Offset) const {
+ bool AnyEmptySubobjectsBeyondOffset(CharUnits Offset) const {
return Offset <= MaxEmptyClassOffset;
}
+ CharUnits
+ getFieldOffset(const ASTRecordLayout &Layout, unsigned FieldNo) const {
+ uint64_t FieldOffset = Layout.getFieldOffset(FieldNo);
+ assert(FieldOffset % CharWidth == 0 &&
+ "Field offset not at char boundary!");
+
+ return Context.toCharUnitsFromBits(FieldOffset);
+ }
+
protected:
- bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
- uint64_t Offset) const;
+ bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
+ CharUnits Offset) const;
bool CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
- uint64_t Offset);
+ CharUnits Offset);
bool CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
- uint64_t Offset) const;
+ CharUnits Offset) const;
bool CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
- uint64_t Offset) const;
+ CharUnits Offset) const;
public:
/// This holds the size of the largest empty subobject (either a base
/// or a member). Will be zero if the record being built doesn't contain
/// any empty classes.
- uint64_t SizeOfLargestEmptySubobject;
+ CharUnits SizeOfLargestEmptySubobject;
- EmptySubobjectMap(ASTContext &Context, const CXXRecordDecl *Class)
- : Context(Context), Class(Class), MaxEmptyClassOffset(0),
- SizeOfLargestEmptySubobject(0) {
+ EmptySubobjectMap(const ASTContext &Context, const CXXRecordDecl *Class)
+ : Context(Context), CharWidth(Context.getCharWidth()), Class(Class) {
ComputeEmptySubobjectSizes();
}
@@ -119,11 +130,11 @@ public:
/// Returns false if placing the record will result in two components
/// (direct or indirect) of the same type having the same offset.
bool CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info,
- uint64_t Offset);
+ CharUnits Offset);
/// CanPlaceFieldAtOffset - Return whether a field can be placed at the given
/// offset.
- bool CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset);
+ bool CanPlaceFieldAtOffset(const FieldDecl *FD, CharUnits Offset);
};
void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
@@ -133,7 +144,7 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t EmptySize = 0;
+ CharUnits EmptySize;
const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl);
if (BaseDecl->isEmpty()) {
// If the class decl is empty, get its size.
@@ -143,8 +154,8 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
EmptySize = Layout.getSizeOfLargestEmptySubobject();
}
- SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject,
- EmptySize);
+ if (EmptySize > SizeOfLargestEmptySubobject)
+ SizeOfLargestEmptySubobject = EmptySize;
}
// Check the fields.
@@ -159,7 +170,7 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
if (!RT)
continue;
- uint64_t EmptySize = 0;
+ CharUnits EmptySize;
const CXXRecordDecl *MemberDecl = cast<CXXRecordDecl>(RT->getDecl());
const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl);
if (MemberDecl->isEmpty()) {
@@ -170,14 +181,14 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() {
EmptySize = Layout.getSizeOfLargestEmptySubobject();
}
- SizeOfLargestEmptySubobject = std::max(SizeOfLargestEmptySubobject,
- EmptySize);
+ if (EmptySize > SizeOfLargestEmptySubobject)
+ SizeOfLargestEmptySubobject = EmptySize;
}
}
bool
EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
- uint64_t Offset) const {
+ CharUnits Offset) const {
// We only need to check empty bases.
if (!RD->isEmpty())
return true;
@@ -195,24 +206,27 @@ EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD,
}
void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD,
- uint64_t Offset) {
+ CharUnits Offset) {
// We only care about empty bases.
if (!RD->isEmpty())
return;
+ // If we have empty structures inside an union, we can assign both
+ // the same offset. Just avoid pushing them twice in the list.
ClassVectorTy& Classes = EmptyClassOffsets[Offset];
- assert(std::find(Classes.begin(), Classes.end(), RD) == Classes.end() &&
- "Duplicate empty class detected!");
-
+ if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end())
+ return;
+
Classes.push_back(RD);
// Update the empty class offset.
- MaxEmptyClassOffset = std::max(MaxEmptyClassOffset, Offset);
+ if (Offset > MaxEmptyClassOffset)
+ MaxEmptyClassOffset = Offset;
}
bool
-EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
- uint64_t Offset) {
+EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
+ CharUnits Offset) {
// We don't have to keep looking past the maximum offset that's known to
// contain an empty class.
if (!AnyEmptySubobjectsBeyondOffset(Offset))
@@ -228,7 +242,7 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
if (Base->IsVirtual)
continue;
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
if (!CanPlaceBaseSubobjectAtOffset(Base, BaseOffset))
return false;
@@ -248,8 +262,10 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(),
E = Info->Class->field_end(); I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
-
- uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo);
+ if (FD->isBitField())
+ continue;
+
+ CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
if (!CanPlaceFieldSubobjectAtOffset(FD, FieldOffset))
return false;
}
@@ -258,7 +274,7 @@ EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info,
}
void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
- uint64_t Offset,
+ CharUnits Offset,
bool PlacingEmptyBase) {
if (!PlacingEmptyBase && Offset >= SizeOfLargestEmptySubobject) {
// We know that the only empty subobjects that can conflict with empty
@@ -278,7 +294,7 @@ void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
if (Base->IsVirtual)
continue;
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
UpdateEmptyBaseSubobjects(Base, BaseOffset, PlacingEmptyBase);
}
@@ -295,17 +311,19 @@ void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info,
for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(),
E = Info->Class->field_end(); I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
+ if (FD->isBitField())
+ continue;
- uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo);
+ CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
UpdateEmptyFieldSubobjects(FD, FieldOffset);
}
}
bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info,
- uint64_t Offset) {
+ CharUnits Offset) {
// If we know this class doesn't have any empty subobjects we don't need to
// bother checking.
- if (!SizeOfLargestEmptySubobject)
+ if (SizeOfLargestEmptySubobject.isZero())
return true;
if (!CanPlaceBaseSubobjectAtOffset(Info, Offset))
@@ -320,7 +338,7 @@ bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info,
bool
EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
- uint64_t Offset) const {
+ CharUnits Offset) const {
// We don't have to keep looking past the maximum offset that's known to
// contain an empty class.
if (!AnyEmptySubobjectsBeyondOffset(Offset))
@@ -340,7 +358,7 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
if (!CanPlaceFieldSubobjectAtOffset(BaseDecl, Class, BaseOffset))
return false;
}
@@ -352,7 +370,7 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *VBaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
+ CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
if (!CanPlaceFieldSubobjectAtOffset(VBaseDecl, Class, VBaseOffset))
return false;
}
@@ -363,8 +381,10 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
-
- uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo);
+ if (FD->isBitField())
+ continue;
+
+ CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
if (!CanPlaceFieldSubobjectAtOffset(FD, FieldOffset))
return false;
@@ -373,8 +393,9 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD,
return true;
}
-bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
- uint64_t Offset) const {
+bool
+EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
+ CharUnits Offset) const {
// We don't have to keep looking past the maximum offset that's known to
// contain an empty class.
if (!AnyEmptySubobjectsBeyondOffset(Offset))
@@ -397,7 +418,7 @@ bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
- uint64_t ElementOffset = Offset;
+ CharUnits ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
// We don't have to keep looking past the maximum offset that's known to
// contain an empty class.
@@ -415,7 +436,8 @@ bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD,
}
bool
-EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) {
+EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD,
+ CharUnits Offset) {
if (!CanPlaceFieldSubobjectAtOffset(FD, Offset))
return false;
@@ -427,7 +449,7 @@ EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, uint64_t Offset) {
void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *Class,
- uint64_t Offset) {
+ CharUnits Offset) {
// We know that the only empty subobjects that can conflict with empty
// field subobjects are subobjects of empty bases that can be placed at offset
// zero. Because of this, we only need to keep track of empty field
@@ -449,7 +471,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl);
UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset);
}
@@ -460,7 +482,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
const CXXRecordDecl *VBaseDecl =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
+ CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl);
UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset);
}
}
@@ -470,15 +492,17 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD,
for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
I != E; ++I, ++FieldNo) {
const FieldDecl *FD = *I;
-
- uint64_t FieldOffset = Offset + Layout.getFieldOffset(FieldNo);
+ if (FD->isBitField())
+ continue;
+
+ CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo);
UpdateEmptyFieldSubobjects(FD, FieldOffset);
}
}
void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
- uint64_t Offset) {
+ CharUnits Offset) {
QualType T = FD->getType();
if (const RecordType *RT = T->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
@@ -497,7 +521,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
uint64_t NumElements = Context.getConstantArrayElementCount(AT);
- uint64_t ElementOffset = Offset;
+ CharUnits ElementOffset = Offset;
for (uint64_t I = 0; I != NumElements; ++I) {
// We know that the only empty subobjects that can conflict with empty
@@ -519,7 +543,7 @@ protected:
// FIXME: Remove this and make the appropriate fields public.
friend class clang::ASTContext;
- ASTContext &Context;
+ const ASTContext &Context;
EmptySubobjectMap *EmptySubobjects;
@@ -527,7 +551,10 @@ protected:
uint64_t Size;
/// Alignment - The current alignment of the record layout.
- unsigned Alignment;
+ CharUnits Alignment;
+
+ /// \brief The alignment if attribute packed is not used.
+ CharUnits UnpackedAlignment;
llvm::SmallVector<uint64_t, 16> FieldOffsets;
@@ -545,13 +572,13 @@ protected:
/// MaxFieldAlignment - The maximum allowed field alignment. This is set by
/// #pragma pack.
- unsigned MaxFieldAlignment;
+ CharUnits MaxFieldAlignment;
/// DataSize - The data size of the record being laid out.
uint64_t DataSize;
- uint64_t NonVirtualSize;
- unsigned NonVirtualAlignment;
+ CharUnits NonVirtualSize;
+ CharUnits NonVirtualAlignment;
/// PrimaryBase - the primary base class (if one exists) of the class
/// we're laying out.
@@ -561,7 +588,7 @@ protected:
/// out is virtual.
bool PrimaryBaseIsVirtual;
- typedef llvm::DenseMap<const CXXRecordDecl *, uint64_t> BaseOffsetsMapTy;
+ typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy;
/// Bases - base classes and their offsets in the record.
BaseOffsetsMapTy Bases;
@@ -571,7 +598,7 @@ protected:
/// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are
/// primary base classes for some other direct or indirect base class.
- llvm::SmallSet<const CXXRecordDecl*, 32> IndirectPrimaryBases;
+ CXXIndirectPrimaryBaseSet IndirectPrimaryBases;
/// FirstNearlyEmptyVBase - The first nearly empty virtual base class in
/// inheritance graph order. Used for determining the primary base class.
@@ -581,11 +608,14 @@ protected:
/// avoid visiting virtual bases more than once.
llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases;
- RecordLayoutBuilder(ASTContext &Context, EmptySubobjectMap *EmptySubobjects)
- : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), Alignment(8),
- Packed(false), IsUnion(false), IsMac68kAlign(false),
- UnfilledBitsInLastByte(0), MaxFieldAlignment(0), DataSize(0),
- NonVirtualSize(0), NonVirtualAlignment(8), PrimaryBase(0),
+ RecordLayoutBuilder(const ASTContext &Context, EmptySubobjectMap
+ *EmptySubobjects)
+ : Context(Context), EmptySubobjects(EmptySubobjects), Size(0),
+ Alignment(CharUnits::One()), UnpackedAlignment(Alignment),
+ Packed(false), IsUnion(false), IsMac68kAlign(false),
+ UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()),
+ DataSize(0), NonVirtualSize(CharUnits::Zero()),
+ NonVirtualAlignment(CharUnits::One()), PrimaryBase(0),
PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { }
void Layout(const RecordDecl *D);
@@ -594,7 +624,8 @@ protected:
void LayoutFields(const RecordDecl *D);
void LayoutField(const FieldDecl *D);
- void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize);
+ void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize,
+ bool FieldPacked, const FieldDecl *D);
void LayoutBitField(const FieldDecl *D);
/// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects.
@@ -628,13 +659,6 @@ protected:
virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
- /// IdentifyPrimaryBases - Identify all virtual base classes, direct or
- /// indirect, that are primary base classes for some other direct or indirect
- /// base class.
- void IdentifyPrimaryBases(const CXXRecordDecl *RD);
-
- virtual bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
-
/// LayoutNonVirtualBases - Determines the primary base class (if any) and
/// lays it out. Will then proceed to lay out all non-virtual base clasess.
void LayoutNonVirtualBases(const CXXRecordDecl *RD);
@@ -642,8 +666,8 @@ protected:
/// LayoutNonVirtualBase - Lays out a single non-virtual base.
void LayoutNonVirtualBase(const BaseSubobjectInfo *Base);
- void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
- uint64_t Offset);
+ void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
+ CharUnits Offset);
/// LayoutVirtualBases - Lays out all the virtual bases.
void LayoutVirtualBases(const CXXRecordDecl *RD,
@@ -653,17 +677,26 @@ protected:
void LayoutVirtualBase(const BaseSubobjectInfo *Base);
/// LayoutBase - Will lay out a base and return the offset where it was
- /// placed, in bits.
- uint64_t LayoutBase(const BaseSubobjectInfo *Base);
+ /// placed, in chars.
+ CharUnits LayoutBase(const BaseSubobjectInfo *Base);
/// InitializeLayout - Initialize record layout for the given record decl.
void InitializeLayout(const Decl *D);
/// FinishLayout - Finalize record layout. Adjust record size based on the
/// alignment.
- void FinishLayout();
+ void FinishLayout(const NamedDecl *D);
+
+ void UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment);
+ void UpdateAlignment(CharUnits NewAlignment) {
+ UpdateAlignment(NewAlignment, NewAlignment);
+ }
+
+ void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset,
+ uint64_t UnpackedOffset, unsigned UnpackedAlign,
+ bool isPacked, const FieldDecl *D);
- void UpdateAlignment(unsigned NewAlignment);
+ DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT
@@ -674,42 +707,6 @@ public:
};
} // end anonymous namespace
-/// IsNearlyEmpty - Indicates when a class has a vtable pointer, but
-/// no other data.
-bool RecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
- // FIXME: Audit the corners
- if (!RD->isDynamicClass())
- return false;
- const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD);
- if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0))
- return true;
- return false;
-}
-
-void RecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
- const ASTRecordLayout::PrimaryBaseInfo &BaseInfo =
- Context.getASTRecordLayout(RD).getPrimaryBaseInfo();
-
- // If the record has a primary base class that is virtual, add it to the set
- // of primary bases.
- if (BaseInfo.isVirtual())
- IndirectPrimaryBases.insert(BaseInfo.getBase());
-
- // Now traverse all bases and find primary bases for them.
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- assert(!i->getType()->isDependentType() &&
- "Cannot layout class with dependent bases.");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
-
- // Only bases with virtual bases participate in computing the
- // indirect primary virtual base classes.
- if (Base->getNumVBases())
- IdentifyPrimaryBases(Base);
- }
-}
-
void
RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
@@ -721,7 +718,7 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) {
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
// Check if this is a nearly empty virtual base.
- if (I->isVirtual() && IsNearlyEmpty(Base)) {
+ if (I->isVirtual() && Context.isNearlyEmpty(Base)) {
// If it's not an indirect primary base, then we've found our primary
// base.
if (!IndirectPrimaryBases.count(Base)) {
@@ -754,14 +751,7 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
// Compute all the primary virtual bases for all of our direct and
// indirect bases, and record all their primary virtual base classes.
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- assert(!i->getType()->isDependentType() &&
- "Cannot lay out class with dependent bases.");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- IdentifyPrimaryBases(Base);
- }
+ RD->getIndirectPrimaryBases(IndirectPrimaryBases);
// 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
@@ -809,8 +799,18 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) {
Size += GetVirtualPointersSize(RD);
DataSize = Size;
+ CharUnits UnpackedBaseAlign =
+ Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0));
+ CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign;
+
+ // The maximum field alignment overrides base align.
+ if (!MaxFieldAlignment.isZero()) {
+ BaseAlign = std::min(BaseAlign, MaxFieldAlignment);
+ UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
+ }
+
// Update the alignment.
- UpdateAlignment(Context.Target.getPointerAlign(0));
+ UpdateAlignment(BaseAlign, UnpackedBaseAlign);
}
BaseSubobjectInfo *
@@ -845,7 +845,7 @@ RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD,
// Check if this base has a primary virtual base.
if (RD->getNumVBases()) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
- if (Layout.getPrimaryBaseWasVirtual()) {
+ if (Layout.isPrimaryBaseVirtual()) {
// This base does have a primary virtual base.
PrimaryVirtualBase = Layout.getPrimaryBase();
assert(PrimaryVirtualBase && "Didn't have a primary virtual base!");
@@ -977,7 +977,7 @@ RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) {
// Layout the base.
- uint64_t Offset = LayoutBase(Base);
+ CharUnits Offset = LayoutBase(Base);
// Add its base class offset.
assert(!Bases.count(Base->Class) && "base offset already exists!");
@@ -988,7 +988,7 @@ void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) {
void
RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
- uint64_t Offset) {
+ CharUnits Offset) {
// This base isn't interesting, it has no virtual bases.
if (!Info->Class->getNumVBases())
return;
@@ -1016,7 +1016,7 @@ RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info,
if (Base->IsVirtual)
continue;
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class);
AddPrimaryVirtualBaseOffsets(Base, BaseOffset);
}
}
@@ -1033,7 +1033,7 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD,
} else {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
PrimaryBase = Layout.getPrimaryBase();
- PrimaryBaseIsVirtual = Layout.getPrimaryBaseWasVirtual();
+ PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual();
}
for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
@@ -1074,7 +1074,7 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) {
assert(!Base->Derived && "Trying to lay out a primary virtual base!");
// Layout the base.
- uint64_t Offset = LayoutBase(Base);
+ CharUnits Offset = LayoutBase(Base);
// Add its base class offset.
assert(!VBases.count(Base->Class) && "vbase offset already exists!");
@@ -1083,38 +1083,48 @@ void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) {
AddPrimaryVirtualBaseOffsets(Base, Offset);
}
-uint64_t RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
+CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) {
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base->Class);
// If we have an empty base class, try to place it at offset 0.
if (Base->Class->isEmpty() &&
- EmptySubobjects->CanPlaceBaseAtOffset(Base, 0)) {
- Size = std::max(Size, Layout.getSize());
+ EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) {
+ uint64_t RecordSizeInBits = Context.toBits(Layout.getSize());
+ Size = std::max(Size, RecordSizeInBits);
- return 0;
+ return CharUnits::Zero();
}
- unsigned BaseAlign = Layout.getNonVirtualAlign();
+ 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);
+ UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment);
+ }
// Round up the current record size to the base's alignment boundary.
- uint64_t Offset = llvm::RoundUpToAlignment(DataSize, BaseAlign);
+ uint64_t Offset =
+ llvm::RoundUpToAlignment(DataSize, Context.toBits(BaseAlign));
// Try to place the base.
- while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset))
- Offset += BaseAlign;
+ while (!EmptySubobjects->CanPlaceBaseAtOffset(Base,
+ Context.toCharUnitsFromBits(Offset)))
+ Offset += Context.toBits(BaseAlign);
if (!Base->Class->isEmpty()) {
// Update the data size.
- DataSize = Offset + Layout.getNonVirtualSize();
+ DataSize = Offset + Context.toBits(Layout.getNonVirtualSize());
Size = std::max(Size, DataSize);
} else
- Size = std::max(Size, Offset + Layout.getSize());
+ Size = std::max(Size, Offset + Context.toBits(Layout.getSize()));
// Remember max struct/class alignment.
- UpdateAlignment(BaseAlign);
+ UpdateAlignment(BaseAlign, UnpackedBaseAlign);
- return Offset;
+ return Context.toCharUnitsFromBits(Offset);
}
void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
@@ -1129,14 +1139,14 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) {
// to bit-fields, but gcc appears not to follow that.
if (D->hasAttr<AlignMac68kAttr>()) {
IsMac68kAlign = true;
- MaxFieldAlignment = 2 * 8;
- Alignment = 2 * 8;
+ MaxFieldAlignment = CharUnits::fromQuantity(2);
+ Alignment = CharUnits::fromQuantity(2);
} else {
if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>())
- MaxFieldAlignment = MFAA->getAlignment();
+ MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment());
if (unsigned MaxAlign = D->getMaxAlignment())
- UpdateAlignment(MaxAlign);
+ UpdateAlignment(Context.toCharUnitsFromBits(MaxAlign));
}
}
@@ -1146,7 +1156,7 @@ void RecordLayoutBuilder::Layout(const RecordDecl *D) {
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
- FinishLayout();
+ FinishLayout(D);
}
void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
@@ -1157,7 +1167,7 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
LayoutFields(RD);
- NonVirtualSize = Size;
+ NonVirtualSize = Context.toCharUnitsFromBits(Size);
NonVirtualAlignment = Alignment;
// Lay out the virtual bases and add the primary virtual base offsets.
@@ -1167,7 +1177,7 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) {
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
- FinishLayout();
+ FinishLayout(RD);
#ifndef NDEBUG
// Check that we have base offsets for all bases.
@@ -1201,7 +1211,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
// We start laying out ivars not at the end of the superclass
// structure, but at the next byte following the last field.
- Size = llvm::RoundUpToAlignment(SL.getDataSize(), 8);
+ Size = Context.toBits(SL.getDataSize());
DataSize = Size;
}
@@ -1215,7 +1225,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) {
// Finally, round the size of the total struct up to the alignment of the
// struct itself.
- FinishLayout();
+ FinishLayout(D);
}
void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
@@ -1227,7 +1237,9 @@ void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
}
void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
- uint64_t TypeSize) {
+ uint64_t TypeSize,
+ bool FieldPacked,
+ const FieldDecl *D) {
assert(Context.getLangOptions().CPlusPlus &&
"Can only have wide bit-fields in C++!");
@@ -1258,6 +1270,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
UnfilledBitsInLastByte = 0;
uint64_t FieldOffset;
+ uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte;
if (IsUnion) {
DataSize = std::max(DataSize, FieldSize);
@@ -1276,16 +1289,20 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize,
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
+ CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, FieldOffset,
+ TypeAlign, FieldPacked, D);
+
// Update the size.
Size = std::max(Size, DataSize);
// Remember max struct/class alignment.
- UpdateAlignment(TypeAlign);
+ UpdateAlignment(Context.toCharUnitsFromBits(TypeAlign));
}
void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
- uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte);
+ uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte;
+ uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset;
uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
@@ -1293,29 +1310,48 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
unsigned FieldAlign = FieldInfo.second;
if (FieldSize > TypeSize) {
- LayoutWideBitField(FieldSize, TypeSize);
+ LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D);
return;
}
+ // The align if the field is not packed. This is to check if the attribute
+ // was unnecessary (-Wpacked).
+ unsigned UnpackedFieldAlign = FieldAlign;
+ uint64_t UnpackedFieldOffset = FieldOffset;
+ if (!Context.Target.useBitFieldTypeAlignment())
+ UnpackedFieldAlign = 1;
+
if (FieldPacked || !Context.Target.useBitFieldTypeAlignment())
FieldAlign = 1;
FieldAlign = std::max(FieldAlign, D->getMaxAlignment());
+ UnpackedFieldAlign = std::max(UnpackedFieldAlign, D->getMaxAlignment());
// The maximum field alignment overrides the aligned attribute.
- if (MaxFieldAlignment)
- FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+ if (!MaxFieldAlignment.isZero()) {
+ unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment);
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits);
+ UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits);
+ }
// Check if we need to add padding to give the field the correct alignment.
if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ if (FieldSize == 0 ||
+ (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize)
+ UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset,
+ UnpackedFieldAlign);
+
// Padding members don't affect overall alignment.
if (!D->getIdentifier())
- FieldAlign = 1;
+ FieldAlign = UnpackedFieldAlign = 1;
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
+ CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset,
+ UnpackedFieldAlign, FieldPacked, D);
+
// Update DataSize to include the last byte containing (part of) the bitfield.
if (IsUnion) {
// FIXME: I think FieldSize should be TypeSize here.
@@ -1331,7 +1367,8 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
Size = std::max(Size, DataSize);
// Remember max struct/class alignment.
- UpdateAlignment(FieldAlign);
+ UpdateAlignment(Context.toCharUnitsFromBits(FieldAlign),
+ Context.toCharUnitsFromBits(UnpackedFieldAlign));
}
void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
@@ -1340,42 +1377,74 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
return;
}
+ uint64_t UnpaddedFieldOffset = DataSize - UnfilledBitsInLastByte;
+
// Reset the unfilled bits.
UnfilledBitsInLastByte = 0;
bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
- uint64_t FieldOffset = IsUnion ? 0 : DataSize;
- uint64_t FieldSize;
- unsigned FieldAlign;
+ CharUnits FieldOffset =
+ IsUnion ? CharUnits::Zero() : Context.toCharUnitsFromBits(DataSize);
+ CharUnits FieldSize;
+ CharUnits FieldAlign;
if (D->getType()->isIncompleteArrayType()) {
// This is a flexible array member; we can't directly
// query getTypeInfo about these, so we figure it out here.
// Flexible array members don't have any size, but they
// have to be aligned appropriately for their element type.
- FieldSize = 0;
+ FieldSize = CharUnits::Zero();
const ArrayType* ATy = Context.getAsArrayType(D->getType());
- FieldAlign = Context.getTypeAlign(ATy->getElementType());
+ FieldAlign = Context.getTypeAlignInChars(ATy->getElementType());
} else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
unsigned AS = RT->getPointeeType().getAddressSpace();
- FieldSize = Context.Target.getPointerWidth(AS);
- FieldAlign = Context.Target.getPointerAlign(AS);
+ FieldSize =
+ Context.toCharUnitsFromBits(Context.Target.getPointerWidth(AS));
+ FieldAlign =
+ Context.toCharUnitsFromBits(Context.Target.getPointerAlign(AS));
} else {
- std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType());
+ std::pair<CharUnits, CharUnits> FieldInfo =
+ Context.getTypeInfoInChars(D->getType());
FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
+
+ if (Context.getLangOptions().MSBitfields) {
+ // If MS bitfield layout is required, figure out what type is being
+ // laid out and align the field to the width of that type.
+
+ // Resolve all typedefs down to their base type and round up the field
+ // alignment if necessary.
+ QualType T = Context.getBaseElementType(D->getType());
+ if (const BuiltinType *BTy = T->getAs<BuiltinType>()) {
+ CharUnits TypeSize = Context.getTypeSizeInChars(BTy);
+ if (TypeSize > FieldAlign)
+ FieldAlign = TypeSize;
+ }
+ }
}
+ // The align if the field is not packed. This is to check if the attribute
+ // was unnecessary (-Wpacked).
+ CharUnits UnpackedFieldAlign = FieldAlign;
+ CharUnits UnpackedFieldOffset = FieldOffset;
+
if (FieldPacked)
- FieldAlign = 8;
- FieldAlign = std::max(FieldAlign, D->getMaxAlignment());
+ FieldAlign = CharUnits::One();
+ CharUnits MaxAlignmentInChars =
+ Context.toCharUnitsFromBits(D->getMaxAlignment());
+ FieldAlign = std::max(FieldAlign, MaxAlignmentInChars);
+ UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars);
// The maximum field alignment overrides the aligned attribute.
- if (MaxFieldAlignment)
+ if (!MaxFieldAlignment.isZero()) {
FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+ UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment);
+ }
// Round up the current record size to the field's alignment boundary.
- FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+ FieldOffset = FieldOffset.RoundUpToAlignment(FieldAlign);
+ UnpackedFieldOffset =
+ UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign);
if (!IsUnion && EmptySubobjects) {
// Check if we can place the field at this offset.
@@ -1386,41 +1455,130 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) {
}
// Place this field at the current location.
- FieldOffsets.push_back(FieldOffset);
+ FieldOffsets.push_back(Context.toBits(FieldOffset));
+
+ CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffset,
+ Context.toBits(UnpackedFieldOffset),
+ Context.toBits(UnpackedFieldAlign), FieldPacked, D);
// Reserve space for this field.
+ uint64_t FieldSizeInBits = Context.toBits(FieldSize);
if (IsUnion)
- Size = std::max(Size, FieldSize);
+ Size = std::max(Size, FieldSizeInBits);
else
- Size = FieldOffset + FieldSize;
+ Size = Context.toBits(FieldOffset) + FieldSizeInBits;
// Update the data size.
DataSize = Size;
// Remember max struct/class alignment.
- UpdateAlignment(FieldAlign);
+ UpdateAlignment(FieldAlign, UnpackedFieldAlign);
}
-void RecordLayoutBuilder::FinishLayout() {
+void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) {
// In C++, records cannot be of size 0.
- if (Context.getLangOptions().CPlusPlus && Size == 0)
- Size = 8;
+ if (Context.getLangOptions().CPlusPlus && Size == 0) {
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
+ // Compatibility with gcc requires a class (pod or non-pod)
+ // which is not empty but of size 0; such as having fields of
+ // array of zero-length, remains of Size 0
+ if (RD->isEmpty())
+ Size = 8;
+ }
+ else
+ Size = 8;
+ }
// Finally, round the size of the record up to the alignment of the
// record itself.
- Size = llvm::RoundUpToAlignment(Size, Alignment);
+ uint64_t UnpaddedSize = Size - UnfilledBitsInLastByte;
+ uint64_t UnpackedSize =
+ llvm::RoundUpToAlignment(Size, Context.toBits(UnpackedAlignment));
+ Size = llvm::RoundUpToAlignment(Size, Context.toBits(Alignment));
+
+ unsigned CharBitNum = Context.Target.getCharWidth();
+ if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) {
+ // Warn if padding was introduced to the struct/class/union.
+ if (Size > UnpaddedSize) {
+ unsigned PadSize = Size - UnpaddedSize;
+ bool InBits = true;
+ if (PadSize % CharBitNum == 0) {
+ PadSize = PadSize / CharBitNum;
+ InBits = false;
+ }
+ Diag(RD->getLocation(), diag::warn_padded_struct_size)
+ << Context.getTypeDeclType(RD)
+ << PadSize
+ << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not
+ }
+
+ // Warn if we packed it unnecessarily. If the alignment is 1 byte don't
+ // bother since there won't be alignment issues.
+ if (Packed && UnpackedAlignment > CharUnits::One() && Size == UnpackedSize)
+ Diag(D->getLocation(), diag::warn_unnecessary_packed)
+ << Context.getTypeDeclType(RD);
+ }
}
-void RecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
+void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment,
+ CharUnits UnpackedNewAlignment) {
// The alignment is not modified when using 'mac68k' alignment.
if (IsMac68kAlign)
return;
- if (NewAlignment <= Alignment)
+ if (NewAlignment > Alignment) {
+ assert(llvm::isPowerOf2_32(NewAlignment.getQuantity() &&
+ "Alignment not a power of 2"));
+ Alignment = NewAlignment;
+ }
+
+ if (UnpackedNewAlignment > UnpackedAlignment) {
+ assert(llvm::isPowerOf2_32(UnpackedNewAlignment.getQuantity() &&
+ "Alignment not a power of 2"));
+ UnpackedAlignment = UnpackedNewAlignment;
+ }
+}
+
+void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
+ uint64_t UnpaddedOffset,
+ uint64_t UnpackedOffset,
+ unsigned UnpackedAlign,
+ bool isPacked,
+ const FieldDecl *D) {
+ // We let objc ivars without warning, objc interfaces generally are not used
+ // for padding tricks.
+ if (isa<ObjCIvarDecl>(D))
return;
- assert(llvm::isPowerOf2_32(NewAlignment && "Alignment not a power of 2"));
+ unsigned CharBitNum = Context.Target.getCharWidth();
- Alignment = NewAlignment;
+ // Warn if padding was introduced to the struct/class.
+ if (!IsUnion && Offset > UnpaddedOffset) {
+ unsigned PadSize = Offset - UnpaddedOffset;
+ bool InBits = true;
+ if (PadSize % CharBitNum == 0) {
+ PadSize = PadSize / CharBitNum;
+ InBits = false;
+ }
+ if (D->getIdentifier())
+ Diag(D->getLocation(), diag::warn_padded_struct_field)
+ << (D->getParent()->isStruct() ? 0 : 1) // struct|class
+ << Context.getTypeDeclType(D->getParent())
+ << PadSize
+ << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1) // plural or not
+ << D->getIdentifier();
+ else
+ Diag(D->getLocation(), diag::warn_padded_struct_anon_field)
+ << (D->getParent()->isStruct() ? 0 : 1) // struct|class
+ << Context.getTypeDeclType(D->getParent())
+ << PadSize
+ << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not
+ }
+
+ // Warn if we packed it unnecessarily. If the alignment is 1 byte don't
+ // bother since there won't be alignment issues.
+ if (isPacked && UnpackedAlign > CharBitNum && Offset == UnpackedOffset)
+ Diag(D->getLocation(), diag::warn_unnecessary_packed)
+ << D->getIdentifier();
}
const CXXMethodDecl *
@@ -1435,6 +1593,13 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (RD->isInAnonymousNamespace())
return 0;
+ // Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6.
+ // Same behavior as GCC.
+ TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind();
+ if (TSK == TSK_ImplicitInstantiation ||
+ TSK == TSK_ExplicitInstantiationDefinition)
+ return 0;
+
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
const CXXMethodDecl *MD = *I;
@@ -1463,26 +1628,21 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
return 0;
}
-// This class implements layout specific to the Microsoft ABI.
-class MSRecordLayoutBuilder: public RecordLayoutBuilder {
-public:
- MSRecordLayoutBuilder(ASTContext& Ctx, EmptySubobjectMap *EmptySubobjects):
- RecordLayoutBuilder(Ctx, EmptySubobjects) {}
-
- virtual bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
- virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
-};
+DiagnosticBuilder
+RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) {
+ return Context.getDiagnostics().Report(Loc, DiagID);
+}
-bool MSRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
- // FIXME: Audit the corners
- if (!RD->isDynamicClass())
- return false;
- const ASTRecordLayout &BaseInfo = Context.getASTRecordLayout(RD);
- // In the Microsoft ABI, classes can have one or two vtable pointers.
- if (BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0) ||
- BaseInfo.getNonVirtualSize() == Context.Target.getPointerWidth(0) * 2)
- return true;
- return false;
+namespace {
+ // This class implements layout specific to the Microsoft ABI.
+ class MSRecordLayoutBuilder : public RecordLayoutBuilder {
+ public:
+ MSRecordLayoutBuilder(const ASTContext& Ctx,
+ EmptySubobjectMap *EmptySubobjects) :
+ RecordLayoutBuilder(Ctx, EmptySubobjects) {}
+
+ virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const;
+ };
}
uint64_t
@@ -1497,7 +1657,8 @@ MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const {
/// getASTRecordLayout - 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::getASTRecordLayout(const RecordDecl *D) {
+const ASTRecordLayout &
+ASTContext::getASTRecordLayout(const RecordDecl *D) const {
D = D->getDefinition();
assert(D && "Cannot get layout of forward declarations!");
@@ -1531,12 +1692,16 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
// FIXME: This should be done in FinalizeLayout.
uint64_t DataSize =
IsPODForThePurposeOfLayout ? Builder->Size : Builder->DataSize;
- uint64_t NonVirtualSize =
- IsPODForThePurposeOfLayout ? DataSize : Builder->NonVirtualSize;
+ CharUnits NonVirtualSize =
+ IsPODForThePurposeOfLayout ?
+ toCharUnitsFromBits(DataSize) : Builder->NonVirtualSize;
+ CharUnits RecordSize = toCharUnitsFromBits(Builder->Size);
NewEntry =
- new (*this) ASTRecordLayout(*this, Builder->Size, Builder->Alignment,
- DataSize, Builder->FieldOffsets.data(),
+ new (*this) ASTRecordLayout(*this, RecordSize,
+ Builder->Alignment,
+ toCharUnitsFromBits(DataSize),
+ Builder->FieldOffsets.data(),
Builder->FieldOffsets.size(),
NonVirtualSize,
Builder->NonVirtualAlignment,
@@ -1548,9 +1713,12 @@ const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) {
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
+ CharUnits RecordSize = toCharUnitsFromBits(Builder.Size);
+
NewEntry =
- new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment,
- Builder.Size,
+ new (*this) ASTRecordLayout(*this, RecordSize,
+ Builder.Alignment,
+ toCharUnitsFromBits(Builder.Size),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
}
@@ -1572,9 +1740,6 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
const CXXMethodDecl *&Entry = KeyFunctions[RD];
if (!Entry)
Entry = RecordLayoutBuilder::ComputeKeyFunction(RD);
- else
- assert(Entry == RecordLayoutBuilder::ComputeKeyFunction(RD) &&
- "Key function changed!");
return Entry;
}
@@ -1586,7 +1751,7 @@ const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
/// implementation. This may differ by including synthesized ivars.
const ASTRecordLayout &
ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
- const ObjCImplementationDecl *Impl) {
+ const ObjCImplementationDecl *Impl) const {
assert(!D->isForwardDecl() && "Invalid interface decl!");
// Look up this layout, if already laid out, return what we have.
@@ -1609,9 +1774,12 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0);
Builder.Layout(D);
+ CharUnits RecordSize = toCharUnitsFromBits(Builder.Size);
+
const ASTRecordLayout *NewEntry =
- new (*this) ASTRecordLayout(*this, Builder.Size, Builder.Alignment,
- Builder.DataSize,
+ new (*this) ASTRecordLayout(*this, RecordSize,
+ Builder.Alignment,
+ toCharUnitsFromBits(Builder.DataSize),
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size());
@@ -1621,18 +1789,18 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D,
}
static void PrintOffset(llvm::raw_ostream &OS,
- uint64_t Offset, unsigned IndentLevel) {
- OS << llvm::format("%4d | ", Offset);
+ CharUnits Offset, unsigned IndentLevel) {
+ OS << llvm::format("%4d | ", Offset.getQuantity());
OS.indent(IndentLevel * 2);
}
static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
- const CXXRecordDecl *RD, ASTContext &C,
- uint64_t Offset,
+ const CXXRecordDecl *RD, const ASTContext &C,
+ CharUnits Offset,
unsigned IndentLevel,
const char* Description,
bool IncludeVirtualBases) {
- const ASTRecordLayout &Info = C.getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = C.getASTRecordLayout(RD);
PrintOffset(OS, Offset, IndentLevel);
OS << C.getTypeDeclType(const_cast<CXXRecordDecl *>(RD)).getAsString();
@@ -1644,7 +1812,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
IndentLevel++;
- const CXXRecordDecl *PrimaryBase = Info.getPrimaryBase();
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
// Vtable pointer.
if (RD->isDynamicClass() && !PrimaryBase) {
@@ -1662,7 +1830,7 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t BaseOffset = Offset + Info.getBaseClassOffset(Base) / 8;
+ CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base);
DumpCXXRecordLayout(OS, Base, C, BaseOffset, IndentLevel,
Base == PrimaryBase ? "(primary base)" : "(base)",
@@ -1674,7 +1842,8 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
for (CXXRecordDecl::field_iterator I = RD->field_begin(),
E = RD->field_end(); I != E; ++I, ++FieldNo) {
const FieldDecl *Field = *I;
- uint64_t FieldOffset = Offset + Info.getFieldOffset(FieldNo) / 8;
+ CharUnits FieldOffset = Offset +
+ C.toCharUnitsFromBits(Layout.getFieldOffset(FieldNo));
if (const RecordType *RT = Field->getType()->getAs<RecordType>()) {
if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
@@ -1699,27 +1868,27 @@ static void DumpCXXRecordLayout(llvm::raw_ostream &OS,
const CXXRecordDecl *VBase =
cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
- uint64_t VBaseOffset = Offset + Info.getVBaseClassOffset(VBase) / 8;
+ CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBase);
DumpCXXRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel,
VBase == PrimaryBase ?
"(primary virtual base)" : "(virtual base)",
/*IncludeVirtualBases=*/false);
}
- OS << " sizeof=" << Info.getSize() / 8;
- OS << ", dsize=" << Info.getDataSize() / 8;
- OS << ", align=" << Info.getAlignment() / 8 << '\n';
- OS << " nvsize=" << Info.getNonVirtualSize() / 8;
- OS << ", nvalign=" << Info.getNonVirtualAlign() / 8 << '\n';
+ OS << " sizeof=" << Layout.getSize().getQuantity();
+ OS << ", dsize=" << Layout.getDataSize().getQuantity();
+ OS << ", align=" << Layout.getAlignment().getQuantity() << '\n';
+ OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
+ OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << '\n';
OS << '\n';
}
void ASTContext::DumpRecordLayout(const RecordDecl *RD,
- llvm::raw_ostream &OS) {
+ llvm::raw_ostream &OS) const {
const ASTRecordLayout &Info = getASTRecordLayout(RD);
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
- return DumpCXXRecordLayout(OS, CXXRD, *this, 0, 0, 0,
+ return DumpCXXRecordLayout(OS, CXXRD, *this, CharUnits(), 0, 0,
/*IncludeVirtualBases=*/true);
OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n";
@@ -1727,9 +1896,9 @@ void ASTContext::DumpRecordLayout(const RecordDecl *RD,
RD->dump();
OS << "\nLayout: ";
OS << "<ASTRecordLayout\n";
- OS << " Size:" << Info.getSize() << "\n";
- OS << " DataSize:" << Info.getDataSize() << "\n";
- OS << " Alignment:" << Info.getAlignment() << "\n";
+ OS << " Size:" << toBits(Info.getSize()) << "\n";
+ OS << " DataSize:" << toBits(Info.getDataSize()) << "\n";
+ OS << " Alignment:" << toBits(Info.getAlignment()) << "\n";
OS << " FieldOffsets: [";
for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) {
if (i) OS << ", ";
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index fc88981..7e73f02 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -46,7 +46,7 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
}
const char *Stmt::getStmtClassName() const {
- return getStmtInfoTableEntry((StmtClass)sClass).Name;
+ return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
}
void Stmt::PrintStats() {
@@ -84,17 +84,84 @@ bool Stmt::CollectingStats(bool Enable) {
return StatSwitch;
}
+namespace {
+ struct good {};
+ struct bad {};
+
+ // These silly little functions have to be static inline to suppress
+ // unused warnings, and they have to be defined to suppress other
+ // warnings.
+ static inline good is_good(good) { return good(); }
+
+ typedef Stmt::child_range children_t();
+ template <class T> good implements_children(children_t T::*) {
+ return good();
+ }
+ static inline bad implements_children(children_t Stmt::*) {
+ return bad();
+ }
+
+ typedef SourceRange getSourceRange_t() const;
+ template <class T> good implements_getSourceRange(getSourceRange_t T::*) {
+ return good();
+ }
+ static inline bad implements_getSourceRange(getSourceRange_t Stmt::*) {
+ return bad();
+ }
+
+#define ASSERT_IMPLEMENTS_children(type) \
+ (void) sizeof(is_good(implements_children(&type::children)))
+#define ASSERT_IMPLEMENTS_getSourceRange(type) \
+ (void) sizeof(is_good(implements_getSourceRange(&type::getSourceRange)))
+}
+
+/// Check whether the various Stmt classes implement their member
+/// functions.
+static inline void check_implementations() {
+#define ABSTRACT_STMT(type)
+#define STMT(type, base) \
+ ASSERT_IMPLEMENTS_children(type); \
+ ASSERT_IMPLEMENTS_getSourceRange(type);
+#include "clang/AST/StmtNodes.inc"
+}
+
+Stmt::child_range Stmt::children() {
+ switch (getStmtClass()) {
+ case Stmt::NoStmtClass: llvm_unreachable("statement without class");
+#define ABSTRACT_STMT(type)
+#define STMT(type, base) \
+ case Stmt::type##Class: \
+ return static_cast<type*>(this)->children();
+#include "clang/AST/StmtNodes.inc"
+ }
+ llvm_unreachable("unknown statement kind!");
+ return child_range();
+}
+
+SourceRange Stmt::getSourceRange() const {
+ switch (getStmtClass()) {
+ case Stmt::NoStmtClass: llvm_unreachable("statement without class");
+#define ABSTRACT_STMT(type)
+#define STMT(type, base) \
+ case Stmt::type##Class: \
+ return static_cast<const type*>(this)->getSourceRange();
+#include "clang/AST/StmtNodes.inc"
+ }
+ llvm_unreachable("unknown statement kind!");
+ return SourceRange();
+}
+
void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
if (this->Body)
C.Deallocate(Body);
- this->NumStmts = NumStmts;
+ this->CompoundStmtBits.NumStmts = NumStmts;
Body = new (C) Stmt*[NumStmts];
memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts);
}
const char *LabelStmt::getName() const {
- return getID()->getNameStart();
+ return getDecl()->getIdentifier()->getNameStart();
}
// This is defined here to avoid polluting Stmt.h with importing Expr.h
@@ -106,7 +173,7 @@ SourceRange ReturnStmt::getSourceRange() const {
}
bool Stmt::hasImplicitControlFlow() const {
- switch (sClass) {
+ switch (StmtBits.sClass) {
default:
return false;
@@ -416,7 +483,7 @@ ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context,
Stmt *atFinallyStmt) {
unsigned Size = sizeof(ObjCAtTryStmt) +
(1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *);
- void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
+ void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>());
return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts,
atFinallyStmt);
}
@@ -426,7 +493,7 @@ ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context,
bool HasFinally) {
unsigned Size = sizeof(ObjCAtTryStmt) +
(1 + NumCatchStmts + HasFinally) * sizeof(Stmt *);
- void *Mem = Context.Allocate(Size, llvm::alignof<ObjCAtTryStmt>());
+ void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>());
return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally);
}
@@ -448,7 +515,7 @@ CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
std::size_t Size = sizeof(CXXTryStmt);
Size += ((numHandlers + 1) * sizeof(Stmt));
- void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>());
+ void *Mem = C.Allocate(Size, llvm::alignOf<CXXTryStmt>());
return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers);
}
@@ -457,7 +524,7 @@ CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty,
std::size_t Size = sizeof(CXXTryStmt);
Size += ((numHandlers + 1) * sizeof(Stmt));
- void *Mem = C.Allocate(Size, llvm::alignof<CXXTryStmt>());
+ void *Mem = C.Allocate(Size, llvm::alignOf<CXXTryStmt>());
return new (Mem) CXXTryStmt(Empty, numHandlers);
}
@@ -530,7 +597,7 @@ void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
}
SwitchStmt::SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond)
- : Stmt(SwitchStmtClass), FirstCase(0)
+ : Stmt(SwitchStmtClass), FirstCase(0), AllEnumCasesCovered(0)
{
setConditionVariable(C, Var);
SubExprs[COND] = reinterpret_cast<Stmt*>(cond);
@@ -556,6 +623,11 @@ void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
V->getSourceRange().getEnd());
}
+Stmt *SwitchCase::getSubStmt() {
+ if (isa<CaseStmt>(this)) return cast<CaseStmt>(this)->getSubStmt();
+ return cast<DefaultStmt>(this)->getSubStmt();
+}
+
WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body,
SourceLocation WL)
: Stmt(WhileStmtClass)
@@ -585,101 +657,13 @@ void WhileStmt::setConditionVariable(ASTContext &C, VarDecl *V) {
V->getSourceRange().getEnd());
}
-//===----------------------------------------------------------------------===//
-// Child Iterators for iterating over subexpressions/substatements
-//===----------------------------------------------------------------------===//
-
-// DeclStmt
-Stmt::child_iterator DeclStmt::child_begin() {
- return StmtIterator(DG.begin(), DG.end());
-}
-
-Stmt::child_iterator DeclStmt::child_end() {
- return StmtIterator(DG.end(), DG.end());
-}
-
-// NullStmt
-Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); }
-Stmt::child_iterator NullStmt::child_end() { return child_iterator(); }
-
-// CompoundStmt
-Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; }
-Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+NumStmts; }
-
-// CaseStmt
-Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; }
-
-// DefaultStmt
-Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; }
-Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; }
-
-// LabelStmt
-Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; }
-Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; }
-
-// IfStmt
-Stmt::child_iterator IfStmt::child_begin() {
- return &SubExprs[0];
-}
-Stmt::child_iterator IfStmt::child_end() {
- return &SubExprs[0]+END_EXPR;
-}
-
-// SwitchStmt
-Stmt::child_iterator SwitchStmt::child_begin() {
- return &SubExprs[0];
-}
-Stmt::child_iterator SwitchStmt::child_end() {
- return &SubExprs[0]+END_EXPR;
-}
-
-// WhileStmt
-Stmt::child_iterator WhileStmt::child_begin() {
- return &SubExprs[0];
-}
-Stmt::child_iterator WhileStmt::child_end() {
- return &SubExprs[0]+END_EXPR;
-}
-
-// DoStmt
-Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; }
-Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; }
-
-// ForStmt
-Stmt::child_iterator ForStmt::child_begin() {
- return &SubExprs[0];
-}
-Stmt::child_iterator ForStmt::child_end() {
- return &SubExprs[0]+END_EXPR;
-}
-
-// ObjCForCollectionStmt
-Stmt::child_iterator ObjCForCollectionStmt::child_begin() {
- return &SubExprs[0];
-}
-Stmt::child_iterator ObjCForCollectionStmt::child_end() {
- return &SubExprs[0]+END_EXPR;
-}
-
-// GotoStmt
-Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); }
-Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); }
-
// IndirectGotoStmt
-Expr* IndirectGotoStmt::getTarget() { return cast<Expr>(Target); }
-const Expr* IndirectGotoStmt::getTarget() const { return cast<Expr>(Target); }
-
-Stmt::child_iterator IndirectGotoStmt::child_begin() { return &Target; }
-Stmt::child_iterator IndirectGotoStmt::child_end() { return &Target+1; }
-
-// ContinueStmt
-Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); }
-Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); }
-
-// BreakStmt
-Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); }
-Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); }
+LabelDecl *IndirectGotoStmt::getConstantTarget() {
+ if (AddrLabelExpr *E =
+ dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts()))
+ return E->getLabel();
+ return 0;
+}
// ReturnStmt
const Expr* ReturnStmt::getRetValue() const {
@@ -688,69 +672,3 @@ const Expr* ReturnStmt::getRetValue() const {
Expr* ReturnStmt::getRetValue() {
return cast_or_null<Expr>(RetExpr);
}
-
-Stmt::child_iterator ReturnStmt::child_begin() {
- return &RetExpr;
-}
-Stmt::child_iterator ReturnStmt::child_end() {
- return RetExpr ? &RetExpr+1 : &RetExpr;
-}
-
-// AsmStmt
-Stmt::child_iterator AsmStmt::child_begin() {
- return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0];
-}
-Stmt::child_iterator AsmStmt::child_end() {
- return NumOutputs + NumInputs == 0 ? 0 : &Exprs[0] + NumOutputs + NumInputs;
-}
-
-// ObjCAtCatchStmt
-Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &Body; }
-Stmt::child_iterator ObjCAtCatchStmt::child_end() { return &Body + 1; }
-
-// ObjCAtFinallyStmt
-Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; }
-Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; }
-
-// ObjCAtTryStmt
-Stmt::child_iterator ObjCAtTryStmt::child_begin() { return getStmts(); }
-
-Stmt::child_iterator ObjCAtTryStmt::child_end() {
- return getStmts() + 1 + NumCatchStmts + HasFinally;
-}
-
-// ObjCAtThrowStmt
-Stmt::child_iterator ObjCAtThrowStmt::child_begin() {
- return &Throw;
-}
-
-Stmt::child_iterator ObjCAtThrowStmt::child_end() {
- return &Throw+1;
-}
-
-// ObjCAtSynchronizedStmt
-Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() {
- return &SubStmts[0];
-}
-
-Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() {
- return &SubStmts[0]+END_EXPR;
-}
-
-// CXXCatchStmt
-Stmt::child_iterator CXXCatchStmt::child_begin() {
- return &HandlerBlock;
-}
-
-Stmt::child_iterator CXXCatchStmt::child_end() {
- return &HandlerBlock + 1;
-}
-
-// CXXTryStmt
-Stmt::child_iterator CXXTryStmt::child_begin() {
- return reinterpret_cast<Stmt **>(this + 1);
-}
-
-Stmt::child_iterator CXXTryStmt::child_end() {
- return reinterpret_cast<Stmt **>(this + 1) + NumHandlers + 1;
-}
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 5c236a4..846bd4c 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -59,19 +59,12 @@ namespace {
Visit(S);
// Print out children.
- Stmt::child_iterator CI = S->child_begin(), CE = S->child_end();
- if (CI != CE) {
- while (CI != CE) {
+ Stmt::child_range CI = S->children();
+ if (CI) {
+ while (CI) {
OS << '\n';
DumpSubTree(*CI++);
}
- if (const ConditionalOperator *CO =
- dyn_cast<ConditionalOperator>(S)) {
- if (CO->getSAVE()) {
- OS << '\n';
- DumpSubTree(CO->getSAVE());
- }
- }
}
}
OS << ')';
@@ -90,25 +83,44 @@ namespace {
}
void DumpType(QualType T) {
- OS << "'" << T.getAsString() << "'";
+ SplitQualType T_split = T.split();
+ OS << "'" << QualType::getAsString(T_split) << "'";
if (!T.isNull()) {
// If the type is sugared, also dump a (shallow) desugared type.
- QualType Simplified = T.getDesugaredType();
- if (Simplified != T)
- OS << ":'" << Simplified.getAsString() << "'";
+ SplitQualType D_split = T.getSplitDesugaredType();
+ if (T_split != D_split)
+ OS << ":'" << QualType::getAsString(D_split) << "'";
}
}
+ void DumpDeclRef(Decl *node);
void DumpStmt(const Stmt *Node) {
Indent();
OS << "(" << Node->getStmtClassName()
<< " " << (void*)Node;
DumpSourceRange(Node);
}
+ void DumpValueKind(ExprValueKind K) {
+ switch (K) {
+ case VK_RValue: break;
+ case VK_LValue: OS << " lvalue"; break;
+ case VK_XValue: OS << " xvalue"; break;
+ }
+ }
+ void DumpObjectKind(ExprObjectKind K) {
+ switch (K) {
+ case OK_Ordinary: break;
+ case OK_BitField: OS << " bitfield"; break;
+ case OK_ObjCProperty: OS << " objcproperty"; break;
+ case OK_VectorComponent: OS << " vectorcomponent"; break;
+ }
+ }
void DumpExpr(const Expr *Node) {
DumpStmt(Node);
OS << ' ';
DumpType(Node->getType());
+ DumpValueKind(Node->getValueKind());
+ DumpObjectKind(Node->getObjectKind());
}
void DumpSourceRange(const Stmt *Node);
void DumpLocation(SourceLocation Loc);
@@ -122,7 +134,6 @@ namespace {
// Exprs
void VisitExpr(Expr *Node);
void VisitCastExpr(CastExpr *Node);
- void VisitImplicitCastExpr(ImplicitCastExpr *Node);
void VisitDeclRefExpr(DeclRefExpr *Node);
void VisitPredefinedExpr(PredefinedExpr *Node);
void VisitCharacterLiteral(CharacterLiteral *Node);
@@ -136,7 +147,7 @@ namespace {
void VisitBinaryOperator(BinaryOperator *Node);
void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
void VisitAddrLabelExpr(AddrLabelExpr *Node);
- void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node);
+ void VisitBlockExpr(BlockExpr *Node);
// C++
void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
@@ -145,7 +156,7 @@ namespace {
void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node);
void VisitCXXConstructExpr(CXXConstructExpr *Node);
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node);
- void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node);
+ void VisitExprWithCleanups(ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node);
void DumpCXXTemporary(CXXTemporary *Temporary);
@@ -156,10 +167,7 @@ namespace {
void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
- void VisitObjCImplicitSetterGetterRefExpr(
- ObjCImplicitSetterGetterRefExpr *Node);
void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
- void VisitObjCSuperExpr(ObjCSuperExpr *Node);
};
}
@@ -170,15 +178,15 @@ namespace {
void StmtDumper::DumpLocation(SourceLocation Loc) {
SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
- if (SpellingLoc.isInvalid()) {
- OS << "<invalid sloc>";
- return;
- }
-
// The general format we print out is filename:line:col, but we drop pieces
// that haven't changed since the last loc printed.
PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
+ if (PLoc.isInvalid()) {
+ OS << "<invalid sloc>";
+ return;
+ }
+
if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
OS << PLoc.getFilename() << ':' << PLoc.getLine()
<< ':' << PLoc.getColumn();
@@ -274,6 +282,8 @@ void StmtDumper::DumpDeclarator(Decl *D) {
UD->getTargetNestedNameDecl()->print(OS,
PrintingPolicy(UD->getASTContext().getLangOptions()));
OS << ";\"";
+ } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
+ OS << "label " << LD->getNameAsString();
} else {
assert(0 && "Unexpected decl");
}
@@ -345,39 +355,25 @@ void StmtDumper::VisitCastExpr(CastExpr *Node) {
OS << ">";
}
-void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
- VisitCastExpr(Node);
- switch (Node->getValueKind()) {
- case VK_LValue:
- OS << " lvalue";
- break;
- case VK_XValue:
- OS << " xvalue";
- break;
- case VK_RValue:
- break;
- }
-}
-
void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
DumpExpr(Node);
OS << " ";
- switch (Node->getDecl()->getKind()) {
- default: OS << "Decl"; break;
- case Decl::Function: OS << "FunctionDecl"; break;
- case Decl::Var: OS << "Var"; break;
- case Decl::ParmVar: OS << "ParmVar"; break;
- case Decl::EnumConstant: OS << "EnumConstant"; break;
- case Decl::Typedef: OS << "Typedef"; break;
- case Decl::Record: OS << "Record"; break;
- case Decl::Enum: OS << "Enum"; break;
- case Decl::CXXRecord: OS << "CXXRecord"; break;
- case Decl::ObjCInterface: OS << "ObjCInterface"; break;
- case Decl::ObjCClass: OS << "ObjCClass"; break;
+ DumpDeclRef(Node->getDecl());
+}
+
+void StmtDumper::DumpDeclRef(Decl *d) {
+ OS << d->getDeclKindName() << ' ' << (void*) d;
+
+ if (NamedDecl *nd = dyn_cast<NamedDecl>(d)) {
+ OS << " '";
+ nd->getDeclName().printName(OS);
+ OS << "'";
}
- OS << "='" << Node->getDecl() << "' " << (void*)Node->getDecl();
+ if (ValueDecl *vd = dyn_cast<ValueDecl>(d)) {
+ OS << ' '; DumpType(vd->getType());
+ }
}
void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
@@ -475,6 +471,30 @@ void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
DumpType(Node->getComputationResultType());
}
+void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
+ DumpExpr(Node);
+
+ IndentLevel++;
+ BlockDecl *block = Node->getBlockDecl();
+ if (block->capturesCXXThis()) {
+ OS << '\n'; Indent(); OS << "(capture this)";
+ }
+ for (BlockDecl::capture_iterator
+ i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
+ OS << '\n';
+ Indent();
+ OS << "(capture ";
+ if (i->isByRef()) OS << "byref ";
+ if (i->isNested()) OS << "nested ";
+ DumpDeclRef(i->getVariable());
+ if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
+ OS << ")";
+ }
+ IndentLevel--;
+
+ DumpSubTree(block->getBody());
+}
+
// GNU extensions.
void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
@@ -483,14 +503,6 @@ void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
<< " " << (void*)Node->getLabel();
}
-void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
- DumpExpr(Node);
- OS << " ";
- DumpType(Node->getArgType1());
- OS << " ";
- DumpType(Node->getArgType2());
-}
-
//===----------------------------------------------------------------------===//
// C++ Expressions
//===----------------------------------------------------------------------===//
@@ -535,7 +547,7 @@ void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
DumpCXXTemporary(Node->getTemporary());
}
-void StmtDumper::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *Node) {
+void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
DumpExpr(Node);
++IndentLevel;
for (unsigned i = 0, e = Node->getNumTemporaries(); i != e; ++i) {
@@ -606,29 +618,25 @@ void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
DumpExpr(Node);
+ if (Node->isImplicitProperty()) {
+ OS << " Kind=MethodRef Getter=\"";
+ if (Node->getImplicitPropertyGetter())
+ OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
+ else
+ OS << "(null)";
- OS << " Kind=PropertyRef Property=\"" << Node->getProperty() << '"';
-}
-
-void StmtDumper::VisitObjCImplicitSetterGetterRefExpr(
- ObjCImplicitSetterGetterRefExpr *Node) {
- DumpExpr(Node);
-
- ObjCMethodDecl *Getter = Node->getGetterMethod();
- ObjCMethodDecl *Setter = Node->getSetterMethod();
- OS << " Kind=MethodRef Getter=\""
- << Getter->getSelector().getAsString()
- << "\" Setter=\"";
- if (Setter)
- OS << Setter->getSelector().getAsString();
- else
- OS << "(null)";
- OS << "\"";
-}
+ OS << "\" Setter=\"";
+ if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter())
+ OS << Setter->getSelector().getAsString();
+ else
+ OS << "(null)";
+ OS << "\"";
+ } else {
+ OS << " Kind=PropertyRef Property=\"" << Node->getExplicitProperty() << '"';
+ }
-void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) {
- DumpExpr(Node);
- OS << " super";
+ if (Node->isSuperReceiver())
+ OS << " super";
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp
index 7fc7c96..9a7265a 100644
--- a/lib/AST/StmtIterator.cpp
+++ b/lib/AST/StmtIterator.cpp
@@ -18,9 +18,9 @@ using namespace clang;
// FIXME: Add support for dependent-sized array types in C++?
// Does it even make sense to build a CFG for an uninstantiated template?
-static inline VariableArrayType* FindVA(Type* t) {
- while (ArrayType* vt = dyn_cast<ArrayType>(t)) {
- if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt))
+static inline const VariableArrayType *FindVA(const Type* t) {
+ while (const ArrayType *vt = dyn_cast<ArrayType>(t)) {
+ if (const VariableArrayType *vat = dyn_cast<VariableArrayType>(vt))
if (vat->getSizeExpr())
return vat;
@@ -33,7 +33,7 @@ static inline VariableArrayType* FindVA(Type* t) {
void StmtIteratorBase::NextVA() {
assert (getVAPtr());
- VariableArrayType* p = getVAPtr();
+ const VariableArrayType *p = getVAPtr();
p = FindVA(p->getElementType().getTypePtr());
setVAPtr(p);
@@ -90,7 +90,7 @@ void StmtIteratorBase::NextDecl(bool ImmediateAdvance) {
bool StmtIteratorBase::HandleDecl(Decl* D) {
if (VarDecl* VD = dyn_cast<VarDecl>(D)) {
- if (VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) {
+ if (const VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) {
setVAPtr(VAPtr);
return true;
}
@@ -99,7 +99,7 @@ bool StmtIteratorBase::HandleDecl(Decl* D) {
return true;
}
else if (TypedefDecl* TD = dyn_cast<TypedefDecl>(D)) {
- if (VariableArrayType* VAPtr =
+ if (const VariableArrayType* VAPtr =
FindVA(TD->getUnderlyingType().getTypePtr())) {
setVAPtr(VAPtr);
return true;
@@ -124,16 +124,16 @@ StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge)
NextDecl(false);
}
-StmtIteratorBase::StmtIteratorBase(VariableArrayType* t)
+StmtIteratorBase::StmtIteratorBase(const VariableArrayType* t)
: stmt(0), decl(0), RawVAPtr(SizeOfTypeVAMode) {
RawVAPtr |= reinterpret_cast<uintptr_t>(t);
}
Stmt*& StmtIteratorBase::GetDeclExpr() const {
- if (VariableArrayType* VAPtr = getVAPtr()) {
+ if (const VariableArrayType* VAPtr = getVAPtr()) {
assert (VAPtr->SizeExpr);
- return VAPtr->SizeExpr;
+ return const_cast<Stmt*&>(VAPtr->SizeExpr);
}
assert (inDecl() || inDeclGroup());
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 5236a66..1cdd220 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -15,9 +15,11 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/PrettyPrinter.h"
#include "llvm/Support/Format.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -63,6 +65,7 @@ namespace {
void PrintRawDeclStmt(DeclStmt *S);
void PrintRawIfStmt(IfStmt *If);
void PrintRawCXXCatchStmt(CXXCatchStmt *Catch);
+ void PrintCallArgs(CallExpr *E);
void PrintExpr(Expr *E) {
if (E)
@@ -83,10 +86,10 @@ namespace {
else StmtVisitor<StmtPrinter>::Visit(S);
}
- void VisitStmt(Stmt *Node) ATTRIBUTE_UNUSED {
+ void VisitStmt(Stmt *Node) LLVM_ATTRIBUTE_UNUSED {
Indent() << "<<unknown stmt type>>\n";
}
- void VisitExpr(Expr *Node) ATTRIBUTE_UNUSED {
+ void VisitExpr(Expr *Node) LLVM_ATTRIBUTE_UNUSED {
OS << "<<unknown expr type>>";
}
void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
@@ -217,10 +220,6 @@ void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) {
}
}
-void StmtPrinter::VisitSwitchCase(SwitchCase*) {
- assert(0 && "SwitchCase is an abstract class");
-}
-
void StmtPrinter::VisitWhileStmt(WhileStmt *Node) {
Indent() << "while (";
PrintExpr(Node->getCond());
@@ -479,7 +478,8 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
void StmtPrinter::VisitDependentScopeDeclRefExpr(
DependentScopeDeclRefExpr *Node) {
- Node->getQualifier()->print(OS, Policy);
+ if (NestedNameSpecifier *Qualifier = Node->getQualifier())
+ Qualifier->print(OS, Policy);
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
OS << TemplateSpecializationType::PrintTemplateArgumentList(
@@ -508,22 +508,17 @@ void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
}
void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) {
- if (Node->getBase()) {
+ if (Node->isSuperReceiver())
+ OS << "super.";
+ else if (Node->getBase()) {
PrintExpr(Node->getBase());
OS << ".";
}
- OS << Node->getProperty()->getName();
-}
-
-void StmtPrinter::VisitObjCImplicitSetterGetterRefExpr(
- ObjCImplicitSetterGetterRefExpr *Node) {
- if (Node->getBase()) {
- PrintExpr(Node->getBase());
- OS << ".";
- }
- if (Node->getGetterMethod())
- OS << Node->getGetterMethod();
+ if (Node->isImplicitProperty())
+ OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
+ else
+ OS << Node->getExplicitProperty()->getName();
}
void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) {
@@ -727,9 +722,7 @@ void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
OS << "]";
}
-void StmtPrinter::VisitCallExpr(CallExpr *Call) {
- PrintExpr(Call->getCallee());
- OS << "(";
+void StmtPrinter::PrintCallArgs(CallExpr *Call) {
for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) {
if (isa<CXXDefaultArgExpr>(Call->getArg(i))) {
// Don't print any defaulted arguments
@@ -739,6 +732,12 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
if (i) OS << ", ";
PrintExpr(Call->getArg(i));
}
+}
+
+void StmtPrinter::VisitCallExpr(CallExpr *Call) {
+ PrintExpr(Call->getCallee());
+ OS << "(";
+ PrintCallArgs(Call);
OS << ")";
}
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
@@ -793,21 +792,20 @@ void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
}
void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) {
PrintExpr(Node->getCond());
-
- if (Node->getLHS()) {
- OS << " ? ";
- PrintExpr(Node->getLHS());
- OS << " : ";
- }
- else { // Handle GCC extension where LHS can be NULL.
- OS << " ?: ";
- }
-
+ OS << " ? ";
+ PrintExpr(Node->getLHS());
+ OS << " : ";
PrintExpr(Node->getRHS());
}
// GNU extensions.
+void
+StmtPrinter::VisitBinaryConditionalOperator(BinaryConditionalOperator *Node) {
+ PrintExpr(Node->getCommon());
+ OS << " ?: ";
+ PrintExpr(Node->getFalseExpr());
+}
void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) {
OS << "&&" << Node->getLabel()->getName();
}
@@ -818,12 +816,6 @@ void StmtPrinter::VisitStmtExpr(StmtExpr *E) {
OS << ")";
}
-void StmtPrinter::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) {
- OS << "__builtin_types_compatible_p(";
- OS << Node->getArgType1().getAsString(Policy) << ",";
- OS << Node->getArgType2().getAsString(Policy) << ")";
-}
-
void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) {
OS << "__builtin_choose_expr(";
PrintExpr(Node->getCond());
@@ -968,6 +960,15 @@ void StmtPrinter::VisitCXXMemberCallExpr(CXXMemberCallExpr *Node) {
VisitCallExpr(cast<CallExpr>(Node));
}
+void StmtPrinter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *Node) {
+ PrintExpr(Node->getCallee());
+ OS << "<<<";
+ PrintCallArgs(Node->getConfig());
+ OS << ">>>(";
+ PrintCallArgs(Node);
+ OS << ")";
+}
+
void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
OS << Node->getCastName() << '<';
OS << Node->getTypeAsWritten().getAsString(Policy) << ">(";
@@ -1001,6 +1002,16 @@ void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
OS << ")";
}
+void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) {
+ OS << "__uuidof(";
+ if (Node->isTypeOperand()) {
+ OS << Node->getTypeOperand().getAsString(Policy);
+ } else {
+ PrintExpr(Node->getExprOperand());
+ }
+ OS << ")";
+}
+
void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
OS << (Node->getValue() ? "true" : "false");
}
@@ -1051,7 +1062,10 @@ void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
}
void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
- OS << Node->getType().getAsString(Policy) << "()";
+ if (TypeSourceInfo *TSInfo = Node->getTypeSourceInfo())
+ OS << TSInfo->getType().getAsString(Policy) << "()";
+ else
+ OS << Node->getType().getAsString(Policy) << "()";
}
void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
@@ -1123,17 +1137,18 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
}
void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
- // FIXME. For now we just print a trivial constructor call expression,
- // constructing its first argument object.
- if (E->getNumArgs() == 1) {
- CXXConstructorDecl *CD = E->getConstructor();
- if (CD->isTrivial())
- PrintExpr(E->getArg(0));
+ for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
+ if (isa<CXXDefaultArgExpr>(E->getArg(i))) {
+ // Don't print any defaulted arguments
+ break;
+ }
+
+ if (i) OS << ", ";
+ PrintExpr(E->getArg(i));
}
- // Nothing to print.
}
-void StmtPrinter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) {
+void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
// Just forward to the sub expression.
PrintExpr(E->getSubExpr());
}
@@ -1197,7 +1212,7 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
static const char *getTypeTraitName(UnaryTypeTrait UTT) {
switch (UTT) {
- default: assert(false && "Unknown type trait");
+ default: llvm_unreachable("Unknown unary type trait");
case UTT_HasNothrowAssign: return "__has_nothrow_assign";
case UTT_HasNothrowCopy: return "__has_nothrow_copy";
case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
@@ -1214,6 +1229,16 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) {
case UTT_IsPolymorphic: return "__is_polymorphic";
case UTT_IsUnion: return "__is_union";
}
+ return "";
+}
+
+static const char *getTypeTraitName(BinaryTypeTrait BTT) {
+ switch (BTT) {
+ case BTT_IsBaseOf: return "__is_base_of";
+ case BTT_TypeCompatible: return "__builtin_types_compatible_p";
+ case BTT_IsConvertibleTo: return "__is_convertible_to";
+ }
+ return "";
}
void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
@@ -1221,6 +1246,32 @@ void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
<< E->getQueriedType().getAsString(Policy) << ")";
}
+void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
+ OS << getTypeTraitName(E->getTrait()) << "("
+ << E->getLhsType().getAsString(Policy) << ","
+ << E->getRhsType().getAsString(Policy) << ")";
+}
+
+void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
+ OS << "noexcept(";
+ PrintExpr(E->getOperand());
+ OS << ")";
+}
+
+void StmtPrinter::VisitPackExpansionExpr(PackExpansionExpr *E) {
+ PrintExpr(E->getPattern());
+ OS << "...";
+}
+
+void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
+ OS << "sizeof...(" << E->getPack()->getNameAsString() << ")";
+}
+
+void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
+ SubstNonTypeTemplateParmPackExpr *Node) {
+ OS << Node->getParameterPack()->getNameAsString();
+}
+
// Obj-C
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
@@ -1260,7 +1311,7 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
OS << ' ';
Selector selector = Mess->getSelector();
if (selector.isUnarySelector()) {
- OS << selector.getIdentifierInfoForSlot(0)->getName();
+ OS << selector.getNameForSlot(0);
} else {
for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) {
if (i < selector.getNumArgs()) {
@@ -1278,9 +1329,6 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
OS << "]";
}
-void StmtPrinter::VisitObjCSuperExpr(ObjCSuperExpr *) {
- OS << "super";
-}
void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
BlockDecl *BD = Node->getBlockDecl();
@@ -1313,6 +1361,9 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) {
OS << Node->getDecl();
}
+
+void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {}
+
//===----------------------------------------------------------------------===//
// Stmt method implementations
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 78a336d..b540011 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -25,11 +25,11 @@ using namespace clang;
namespace {
class StmtProfiler : public StmtVisitor<StmtProfiler> {
llvm::FoldingSetNodeID &ID;
- ASTContext &Context;
+ const ASTContext &Context;
bool Canonical;
public:
- StmtProfiler(llvm::FoldingSetNodeID &ID, ASTContext &Context,
+ StmtProfiler(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
bool Canonical)
: ID(ID), Context(Context), Canonical(Canonical) { }
@@ -68,8 +68,7 @@ namespace {
void StmtProfiler::VisitStmt(Stmt *S) {
ID.AddInteger(S->getStmtClass());
- for (Stmt::child_iterator C = S->child_begin(), CEnd = S->child_end();
- C != CEnd; ++C)
+ for (Stmt::child_range C = S->children(); C; ++C)
Visit(*C);
}
@@ -102,7 +101,7 @@ void StmtProfiler::VisitDefaultStmt(DefaultStmt *S) {
void StmtProfiler::VisitLabelStmt(LabelStmt *S) {
VisitStmt(S);
- VisitName(S->getID());
+ VisitDecl(S->getDecl());
}
void StmtProfiler::VisitIfStmt(IfStmt *S) {
@@ -130,7 +129,7 @@ void StmtProfiler::VisitForStmt(ForStmt *S) {
void StmtProfiler::VisitGotoStmt(GotoStmt *S) {
VisitStmt(S);
- VisitName(S->getLabel()->getID());
+ VisitDecl(S->getLabel());
}
void StmtProfiler::VisitIndirectGotoStmt(IndirectGotoStmt *S) {
@@ -350,19 +349,17 @@ void StmtProfiler::VisitConditionalOperator(ConditionalOperator *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) {
+void StmtProfiler::VisitBinaryConditionalOperator(BinaryConditionalOperator *S){
VisitExpr(S);
- VisitName(S->getLabel()->getID());
}
-void StmtProfiler::VisitStmtExpr(StmtExpr *S) {
+void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) {
VisitExpr(S);
+ VisitDecl(S->getLabel());
}
-void StmtProfiler::VisitTypesCompatibleExpr(TypesCompatibleExpr *S) {
+void StmtProfiler::VisitStmtExpr(StmtExpr *S) {
VisitExpr(S);
- VisitType(S->getArgType1());
- VisitType(S->getArgType2());
}
void StmtProfiler::VisitShuffleVectorExpr(ShuffleVectorExpr *S) {
@@ -431,8 +428,6 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) {
VisitDecl(S->getDecl());
ID.AddBoolean(S->isByRef());
ID.AddBoolean(S->isConstQualAdded());
- if (S->getCopyConstructorExpr())
- Visit(S->getCopyConstructorExpr());
}
static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S,
@@ -652,6 +647,10 @@ void StmtProfiler::VisitCXXMemberCallExpr(CXXMemberCallExpr *S) {
VisitCallExpr(S);
}
+void StmtProfiler::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *S) {
+ VisitCallExpr(S);
+}
+
void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) {
VisitExplicitCastExpr(S);
}
@@ -687,6 +686,12 @@ void StmtProfiler::VisitCXXTypeidExpr(CXXTypeidExpr *S) {
VisitType(S->getTypeOperand());
}
+void StmtProfiler::VisitCXXUuidofExpr(CXXUuidofExpr *S) {
+ VisitExpr(S);
+ if (S->isTypeOperand())
+ VisitType(S->getTypeOperand());
+}
+
void StmtProfiler::VisitCXXThisExpr(CXXThisExpr *S) {
VisitExpr(S);
}
@@ -774,6 +779,13 @@ void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) {
VisitType(S->getQueriedType());
}
+void StmtProfiler::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *S) {
+ VisitExpr(S);
+ ID.AddInteger(S->getTrait());
+ VisitType(S->getLhsType());
+ VisitType(S->getRhsType());
+}
+
void
StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
VisitExpr(S);
@@ -784,11 +796,8 @@ StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
-void StmtProfiler::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *S) {
+void StmtProfiler::VisitExprWithCleanups(ExprWithCleanups *S) {
VisitExpr(S);
- for (unsigned I = 0, N = S->getNumTemporaries(); I != N; ++I)
- VisitDecl(
- const_cast<CXXDestructorDecl *>(S->getTemporary(I)->getDestructor()));
}
void
@@ -824,6 +833,30 @@ void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) {
VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
+void StmtProfiler::VisitCXXNoexceptExpr(CXXNoexceptExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitPackExpansionExpr(PackExpansionExpr *S) {
+ VisitExpr(S);
+}
+
+void StmtProfiler::VisitSizeOfPackExpr(SizeOfPackExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getPack());
+}
+
+void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr(
+ SubstNonTypeTemplateParmPackExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getParameterPack());
+ VisitTemplateArgument(S->getArgumentPack());
+}
+
+void StmtProfiler::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
+ VisitExpr(E);
+}
+
void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) {
VisitExpr(S);
}
@@ -852,15 +885,16 @@ void StmtProfiler::VisitObjCIvarRefExpr(ObjCIvarRefExpr *S) {
void StmtProfiler::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *S) {
VisitExpr(S);
- VisitDecl(S->getProperty());
-}
-
-void StmtProfiler::VisitObjCImplicitSetterGetterRefExpr(
- ObjCImplicitSetterGetterRefExpr *S) {
- VisitExpr(S);
- VisitDecl(S->getGetterMethod());
- VisitDecl(S->getSetterMethod());
- VisitDecl(S->getInterfaceDecl());
+ if (S->isImplicitProperty()) {
+ VisitDecl(S->getImplicitPropertyGetter());
+ VisitDecl(S->getImplicitPropertySetter());
+ } else {
+ VisitDecl(S->getExplicitProperty());
+ }
+ if (S->isSuperReceiver()) {
+ ID.AddBoolean(S->isSuperReceiver());
+ VisitType(S->getSuperReceiverType());
+ }
}
void StmtProfiler::VisitObjCMessageExpr(ObjCMessageExpr *S) {
@@ -869,10 +903,6 @@ void StmtProfiler::VisitObjCMessageExpr(ObjCMessageExpr *S) {
VisitDecl(S->getMethodDecl());
}
-void StmtProfiler::VisitObjCSuperExpr(ObjCSuperExpr *S) {
- VisitExpr(S);
-}
-
void StmtProfiler::VisitObjCIsaExpr(ObjCIsaExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isArrow());
@@ -885,6 +915,7 @@ void StmtProfiler::VisitDecl(Decl *D) {
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
ID.AddInteger(NTTP->getDepth());
ID.AddInteger(NTTP->getIndex());
+ ID.AddBoolean(NTTP->isParameterPack());
VisitType(NTTP->getType());
return;
}
@@ -902,6 +933,7 @@ void StmtProfiler::VisitDecl(Decl *D) {
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
ID.AddInteger(TTP->getDepth());
ID.AddInteger(TTP->getIndex());
+ ID.AddBoolean(TTP->isParameterPack());
return;
}
}
@@ -952,7 +984,8 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
break;
case TemplateArgument::Template:
- VisitTemplateName(Arg.getAsTemplate());
+ case TemplateArgument::TemplateExpansion:
+ VisitTemplateName(Arg.getAsTemplateOrTemplatePattern());
break;
case TemplateArgument::Declaration:
@@ -976,7 +1009,7 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
}
}
-void Stmt::Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
+void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
bool Canonical) {
StmtProfiler Profiler(ID, Context, Canonical);
Profiler.Visit(this);
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index a3bf145..5ab5f46 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -12,41 +12,172 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/FoldingSet.h"
#include "clang/AST/TemplateBase.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Diagnostic.h"
+#include "llvm/ADT/FoldingSet.h"
+#include <algorithm>
+#include <cctype>
+#include <iomanip>
+#include <sstream>
using namespace clang;
+/// \brief Print a template integral argument value.
+///
+/// \param TemplArg the TemplateArgument instance to print.
+///
+/// \param Out the raw_ostream instance to use for printing.
+static void printIntegral(const TemplateArgument &TemplArg,
+ llvm::raw_ostream &Out) {
+ const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr();
+ const llvm::APSInt *Val = TemplArg.getAsIntegral();
+
+ if (T->isBooleanType()) {
+ Out << (Val->getBoolValue() ? "true" : "false");
+ } else if (T->isCharType()) {
+ char Ch = Val->getSExtValue();
+ if (std::isprint(Ch)) {
+ Out << "'";
+ if (Ch == '\'' || Ch == '\\')
+ Out << '\\';
+ Out << Ch << "'";
+ } else {
+ std::ostringstream Str;
+ Str << std::setw(2) << std::setfill('0') << std::hex << (int)Ch;
+ Out << "'\\x" << Str.str() << "'";
+ }
+ } else {
+ Out << Val->toString(10);
+ }
+}
+
//===----------------------------------------------------------------------===//
// TemplateArgument Implementation
//===----------------------------------------------------------------------===//
-/// \brief Construct a template argument pack.
-void TemplateArgument::setArgumentPack(TemplateArgument *args, unsigned NumArgs,
- bool CopyArgs) {
- assert(isNull() && "Must call setArgumentPack on a null argument");
+TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context,
+ const TemplateArgument *Args,
+ unsigned NumArgs) {
+ if (NumArgs == 0)
+ return TemplateArgument(0, 0);
+
+ TemplateArgument *Storage = new (Context) TemplateArgument [NumArgs];
+ std::copy(Args, Args + NumArgs, Storage);
+ return TemplateArgument(Storage, NumArgs);
+}
+
+bool TemplateArgument::isDependent() const {
+ switch (getKind()) {
+ case Null:
+ assert(false && "Should not have a NULL template argument");
+ return false;
+
+ case Type:
+ return getAsType()->isDependentType();
+
+ case Template:
+ return getAsTemplate().isDependent();
+
+ case TemplateExpansion:
+ return true;
+
+ case Declaration:
+ if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl()))
+ return DC->isDependentContext();
+ return getAsDecl()->getDeclContext()->isDependentContext();
+
+ case Integral:
+ // Never dependent
+ return false;
+
+ case Expression:
+ return (getAsExpr()->isTypeDependent() || getAsExpr()->isValueDependent());
+
+ case Pack:
+ for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P) {
+ if (P->isDependent())
+ return true;
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
+bool TemplateArgument::isPackExpansion() const {
+ switch (getKind()) {
+ case Null:
+ case Declaration:
+ case Integral:
+ case Pack:
+ case Template:
+ return false;
+
+ case TemplateExpansion:
+ return true;
+
+ case Type:
+ return isa<PackExpansionType>(getAsType());
+
+ case Expression:
+ return isa<PackExpansionExpr>(getAsExpr());
+ }
+
+ return false;
+}
+
+bool TemplateArgument::containsUnexpandedParameterPack() const {
+ switch (getKind()) {
+ case Null:
+ case Declaration:
+ case Integral:
+ case TemplateExpansion:
+ break;
+
+ case Type:
+ if (getAsType()->containsUnexpandedParameterPack())
+ return true;
+ break;
+
+ case Template:
+ if (getAsTemplate().containsUnexpandedParameterPack())
+ return true;
+ break;
+
+ case Expression:
+ if (getAsExpr()->containsUnexpandedParameterPack())
+ return true;
+ break;
- Kind = Pack;
- Args.NumArgs = NumArgs;
- Args.CopyArgs = CopyArgs;
- if (!Args.CopyArgs) {
- Args.Args = args;
- return;
+ case Pack:
+ for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P)
+ if (P->containsUnexpandedParameterPack())
+ return true;
+
+ break;
}
- // FIXME: Allocate in ASTContext
- Args.Args = new TemplateArgument[NumArgs];
- for (unsigned I = 0; I != Args.NumArgs; ++I)
- Args.Args[I] = args[I];
+ return false;
+}
+
+llvm::Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
+ assert(Kind == TemplateExpansion);
+ if (TemplateArg.NumExpansions)
+ return TemplateArg.NumExpansions - 1;
+
+ return llvm::Optional<unsigned>();
}
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
- ASTContext &Context) const {
+ const ASTContext &Context) const {
ID.AddInteger(Kind);
switch (Kind) {
case Null:
@@ -61,18 +192,22 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
break;
case Template:
+ case TemplateExpansion: {
+ TemplateName Template = getAsTemplateOrTemplatePattern();
if (TemplateTemplateParmDecl *TTP
= dyn_cast_or_null<TemplateTemplateParmDecl>(
- getAsTemplate().getAsTemplateDecl())) {
+ Template.getAsTemplateDecl())) {
ID.AddBoolean(true);
ID.AddInteger(TTP->getDepth());
ID.AddInteger(TTP->getPosition());
+ ID.AddBoolean(TTP->isParameterPack());
} else {
ID.AddBoolean(false);
- ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
- .getAsVoidPointer());
+ ID.AddPointer(Context.getCanonicalTemplateName(Template)
+ .getAsVoidPointer());
}
break;
+ }
case Integral:
getAsIntegral()->Profile(ID);
@@ -97,8 +232,9 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
case Null:
case Type:
case Declaration:
+ case Expression:
case Template:
- case Expression:
+ case TemplateExpansion:
return TypeOrValue == Other.TypeOrValue;
case Integral:
@@ -117,10 +253,102 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const {
return false;
}
+TemplateArgument TemplateArgument::getPackExpansionPattern() const {
+ assert(isPackExpansion());
+
+ switch (getKind()) {
+ case Type:
+ return getAsType()->getAs<PackExpansionType>()->getPattern();
+
+ case Expression:
+ return cast<PackExpansionExpr>(getAsExpr())->getPattern();
+
+ case TemplateExpansion:
+ return TemplateArgument(getAsTemplateOrTemplatePattern());
+
+ case Declaration:
+ case Integral:
+ case Pack:
+ case Null:
+ case Template:
+ return TemplateArgument();
+ }
+
+ return TemplateArgument();
+}
+
+void TemplateArgument::print(const PrintingPolicy &Policy,
+ llvm::raw_ostream &Out) const {
+ switch (getKind()) {
+ case Null:
+ Out << "<no value>";
+ break;
+
+ case Type: {
+ std::string TypeStr;
+ getAsType().getAsStringInternal(TypeStr, Policy);
+ Out << TypeStr;
+ break;
+ }
+
+ case Declaration: {
+ bool Unnamed = true;
+ if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getAsDecl())) {
+ if (ND->getDeclName()) {
+ Unnamed = false;
+ Out << ND->getNameAsString();
+ }
+ }
+
+ if (Unnamed) {
+ Out << "<anonymous>";
+ }
+ break;
+ }
+
+ case Template:
+ getAsTemplate().print(Out, Policy);
+ break;
+
+ case TemplateExpansion:
+ getAsTemplateOrTemplatePattern().print(Out, Policy);
+ Out << "...";
+ break;
+
+ case Integral: {
+ printIntegral(*this, Out);
+ break;
+ }
+
+ case Expression:
+ getAsExpr()->printPretty(Out, 0, Policy);
+ break;
+
+ case Pack:
+ Out << "<";
+ bool First = true;
+ for (TemplateArgument::pack_iterator P = pack_begin(), PEnd = pack_end();
+ P != PEnd; ++P) {
+ if (First)
+ First = false;
+ else
+ Out << ", ";
+
+ P->print(Policy, Out);
+ }
+ Out << ">";
+ break;
+ }
+}
+
//===----------------------------------------------------------------------===//
// TemplateArgumentLoc Implementation
//===----------------------------------------------------------------------===//
+TemplateArgumentLocInfo::TemplateArgumentLocInfo() {
+ memset(this, 0, sizeof(TemplateArgumentLocInfo));
+}
+
SourceRange TemplateArgumentLoc::getSourceRange() const {
switch (Argument.getKind()) {
case TemplateArgument::Expression:
@@ -137,10 +365,16 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
case TemplateArgument::Template:
if (getTemplateQualifierRange().isValid())
- return SourceRange(getTemplateQualifierRange().getBegin(),
+ return SourceRange(getTemplateQualifierRange().getBegin(),
getTemplateNameLoc());
return SourceRange(getTemplateNameLoc());
+ case TemplateArgument::TemplateExpansion:
+ if (getTemplateQualifierRange().isValid())
+ return SourceRange(getTemplateQualifierRange().getBegin(),
+ getTemplateEllipsisLoc());
+ return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc());
+
case TemplateArgument::Integral:
case TemplateArgument::Pack:
case TemplateArgument::Null:
@@ -151,6 +385,68 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
return SourceRange();
}
+TemplateArgumentLoc
+TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
+ llvm::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
+ = cast<PackExpansionTypeLoc>(ExpansionTSInfo->getTypeLoc());
+ 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(),
+ getTemplateQualifierRange(),
+ getTemplateNameLoc());
+
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Template:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Pack:
+ case TemplateArgument::Null:
+ return TemplateArgumentLoc();
+ }
+
+ return TemplateArgumentLoc();
+}
+
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
const TemplateArgument &Arg) {
switch (Arg.getKind()) {
@@ -170,7 +466,10 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
case TemplateArgument::Template:
return DB << Arg.getAsTemplate();
-
+
+ case TemplateArgument::TemplateExpansion:
+ return DB << Arg.getAsTemplateOrTemplatePattern() << "...";
+
case TemplateArgument::Expression: {
// This shouldn't actually ever happen, so it's okay that we're
// regurgitating an expression here.
@@ -184,9 +483,16 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
return DB << OS.str();
}
- case TemplateArgument::Pack:
- // FIXME: Format arguments in a list!
- return DB << "<parameter pack>";
+ case TemplateArgument::Pack: {
+ // FIXME: We're guessing at LangOptions!
+ llvm::SmallString<32> Str;
+ llvm::raw_svector_ostream OS(Str);
+ LangOptions LangOpts;
+ LangOpts.CPlusPlus = true;
+ PrintingPolicy Policy(LangOpts);
+ Arg.print(Policy, OS);
+ return DB << OS.str();
+ }
}
return DB;
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index ef7b315..6b378a0 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/TemplateName.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/PrettyPrinter.h"
@@ -21,15 +22,33 @@
using namespace clang;
using namespace llvm;
+TemplateArgument
+SubstTemplateTemplateParmPackStorage::getArgumentPack() const {
+ return TemplateArgument(Arguments, size());
+}
+
+void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Context, Parameter, TemplateArgument(Arguments, size()));
+}
+
+void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID,
+ ASTContext &Context,
+ TemplateTemplateParmDecl *Parameter,
+ const TemplateArgument &ArgPack) {
+ ID.AddPointer(Parameter);
+ ArgPack.Profile(ID, Context);
+}
+
TemplateName::NameKind TemplateName::getKind() const {
if (Storage.is<TemplateDecl *>())
return Template;
- if (Storage.is<OverloadedTemplateStorage *>())
- return OverloadedTemplate;
+ if (Storage.is<DependentTemplateName *>())
+ return DependentTemplate;
if (Storage.is<QualifiedTemplateName *>())
return QualifiedTemplate;
- assert(Storage.is<DependentTemplateName *>() && "There's a case unhandled!");
- return DependentTemplate;
+
+ return getAsOverloadedTemplate()? OverloadedTemplate
+ : SubstTemplateTemplateParmPack;
}
TemplateDecl *TemplateName::getAsTemplateDecl() const {
@@ -44,8 +63,14 @@ TemplateDecl *TemplateName::getAsTemplateDecl() const {
bool TemplateName::isDependent() const {
if (TemplateDecl *Template = getAsTemplateDecl()) {
- return isa<TemplateTemplateParmDecl>(Template) ||
- Template->getDeclContext()->isDependentContext();
+ if (isa<TemplateTemplateParmDecl>(Template))
+ return true;
+ // FIXME: Hack, getDeclContext() can be null if Template is still
+ // initializing due to PCH reading, so we check it before using it.
+ // Should probably modify TemplateSpecializationType to allow constructing
+ // it without the isDependent() checking.
+ return Template->getDeclContext() &&
+ Template->getDeclContext()->isDependentContext();
}
assert(!getAsOverloadedTemplate() &&
@@ -54,6 +79,22 @@ bool TemplateName::isDependent() const {
return true;
}
+bool TemplateName::containsUnexpandedParameterPack() const {
+ if (TemplateDecl *Template = getAsTemplateDecl()) {
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(Template))
+ return TTP->isParameterPack();
+
+ return false;
+ }
+
+ if (DependentTemplateName *DTN = getAsDependentTemplateName())
+ return DTN->getQualifier() &&
+ DTN->getQualifier()->containsUnexpandedParameterPack();
+
+ return getAsSubstTemplateTemplateParmPack() != 0;
+}
+
void
TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
bool SuppressNNS) const {
@@ -74,7 +115,9 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
OS << DTN->getIdentifier()->getName();
else
OS << "operator " << getOperatorSpelling(DTN->getOperator());
- }
+ } else if (SubstTemplateTemplateParmPackStorage *SubstPack
+ = getAsSubstTemplateTemplateParmPack())
+ OS << SubstPack->getParameterPack()->getNameAsString();
}
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index ca10532..b03314e 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -19,6 +19,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
@@ -35,14 +36,13 @@ bool QualType::isConstant(QualType T, ASTContext &Ctx) {
return false;
}
-Type::~Type() { }
-
unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context,
QualType ElementType,
const llvm::APInt &NumElements) {
llvm::APSInt SizeExtended(NumElements, true);
unsigned SizeTypeBits = Context.getTypeSize(Context.getSizeType());
- SizeExtended.extend(std::max(SizeTypeBits, SizeExtended.getBitWidth()) * 2);
+ SizeExtended = SizeExtended.extend(std::max(SizeTypeBits,
+ SizeExtended.getBitWidth()) * 2);
uint64_t ElementSize
= Context.getTypeSizeInChars(ElementType).getQuantity();
@@ -63,8 +63,20 @@ unsigned ConstantArrayType::getMaxSizeBits(ASTContext &Context) {
return Bits;
}
+DependentSizedArrayType::DependentSizedArrayType(const ASTContext &Context,
+ QualType et, QualType can,
+ Expr *e, ArraySizeModifier sm,
+ unsigned tq,
+ SourceRange brackets)
+ : ArrayType(DependentSizedArray, et, can, sm, tq,
+ (et->containsUnexpandedParameterPack() ||
+ (e && e->containsUnexpandedParameterPack()))),
+ Context(Context), SizeExpr((Stmt*) e), Brackets(brackets)
+{
+}
+
void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID,
- ASTContext &Context,
+ const ASTContext &Context,
QualType ET,
ArraySizeModifier SizeMod,
unsigned TypeQuals,
@@ -75,14 +87,51 @@ void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID,
E->Profile(ID, Context, true);
}
+DependentSizedExtVectorType::DependentSizedExtVectorType(const
+ ASTContext &Context,
+ QualType ElementType,
+ QualType can,
+ Expr *SizeExpr,
+ SourceLocation loc)
+ : Type(DependentSizedExtVector, can, /*Dependent=*/true,
+ ElementType->isVariablyModifiedType(),
+ (ElementType->containsUnexpandedParameterPack() ||
+ (SizeExpr && SizeExpr->containsUnexpandedParameterPack()))),
+ Context(Context), SizeExpr(SizeExpr), ElementType(ElementType),
+ loc(loc)
+{
+}
+
void
DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID,
- ASTContext &Context,
+ const ASTContext &Context,
QualType ElementType, Expr *SizeExpr) {
ID.AddPointer(ElementType.getAsOpaquePtr());
SizeExpr->Profile(ID, Context, true);
}
+VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType,
+ VectorKind vecKind)
+ : Type(Vector, canonType, vecType->isDependentType(),
+ vecType->isVariablyModifiedType(),
+ vecType->containsUnexpandedParameterPack()),
+ ElementType(vecType)
+{
+ VectorTypeBits.VecKind = vecKind;
+ VectorTypeBits.NumElements = nElements;
+}
+
+VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements,
+ QualType canonType, VectorKind vecKind)
+ : Type(tc, canonType, vecType->isDependentType(),
+ vecType->isVariablyModifiedType(),
+ vecType->containsUnexpandedParameterPack()),
+ ElementType(vecType)
+{
+ VectorTypeBits.VecKind = vecKind;
+ VectorTypeBits.NumElements = nElements;
+}
+
/// getArrayElementTypeNoTypeQual - If this is an array type, return the
/// element type of the array, potentially with type qualifiers missing.
/// This method should never be used when type qualifiers are meaningful.
@@ -101,51 +150,18 @@ const Type *Type::getArrayElementTypeNoTypeQual() const {
->getElementType().getTypePtr();
}
-/// \brief Retrieve the unqualified variant of the given type, removing as
-/// little sugar as possible.
-///
-/// This routine looks through various kinds of sugar to find the
-/// least-desuraged type that is unqualified. For example, given:
-///
-/// \code
-/// typedef int Integer;
-/// typedef const Integer CInteger;
-/// typedef CInteger DifferenceType;
-/// \endcode
-///
-/// Executing \c getUnqualifiedTypeSlow() on the type \c DifferenceType will
-/// desugar until we hit the type \c Integer, which has no qualifiers on it.
-QualType QualType::getUnqualifiedTypeSlow() const {
- QualType Cur = *this;
- while (true) {
- if (!Cur.hasQualifiers())
- return Cur;
-
- const Type *CurTy = Cur.getTypePtr();
- switch (CurTy->getTypeClass()) {
-#define ABSTRACT_TYPE(Class, Parent)
-#define TYPE(Class, Parent) \
- case Type::Class: { \
- const Class##Type *Ty = cast<Class##Type>(CurTy); \
- if (!Ty->isSugared()) \
- return Cur.getLocalUnqualifiedType(); \
- Cur = Ty->desugar(); \
- break; \
- }
-#include "clang/AST/TypeNodes.def"
- }
- }
-
- return Cur.getUnqualifiedType();
-}
-
/// getDesugaredType - Return the specified type with any "sugar" removed from
/// the type. This takes off typedefs, typeof's etc. If the outer level of
/// the type is already concrete, it returns it unmodified. This is similar
/// to getting the canonical type, but it doesn't remove *all* typedefs. For
/// example, it returns "T*" as "T*", (not as "int*"), because the pointer is
/// concrete.
-QualType QualType::getDesugaredType(QualType T) {
+QualType QualType::getDesugaredType(QualType T, const ASTContext &Context) {
+ SplitQualType split = getSplitDesugaredType(T);
+ return Context.getQualifiedType(split.first, split.second);
+}
+
+SplitQualType QualType::getSplitDesugaredType(QualType T) {
QualifierCollector Qs;
QualType Cur = T;
@@ -157,7 +173,7 @@ QualType QualType::getDesugaredType(QualType T) {
case Type::Class: { \
const Class##Type *Ty = cast<Class##Type>(CurTy); \
if (!Ty->isSugared()) \
- return Qs.apply(Cur); \
+ return SplitQualType(Ty, Qs); \
Cur = Ty->desugar(); \
break; \
}
@@ -166,6 +182,52 @@ QualType QualType::getDesugaredType(QualType T) {
}
}
+SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) {
+ SplitQualType split = type.split();
+
+ // All the qualifiers we've seen so far.
+ Qualifiers quals = split.second;
+
+ // The last type node we saw with any nodes inside it.
+ const Type *lastTypeWithQuals = split.first;
+
+ while (true) {
+ QualType next;
+
+ // Do a single-step desugar, aborting the loop if the type isn't
+ // sugared.
+ switch (split.first->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Parent)
+#define TYPE(Class, Parent) \
+ case Type::Class: { \
+ const Class##Type *ty = cast<Class##Type>(split.first); \
+ if (!ty->isSugared()) goto done; \
+ next = ty->desugar(); \
+ break; \
+ }
+#include "clang/AST/TypeNodes.def"
+ }
+
+ // Otherwise, split the underlying type. If that yields qualifiers,
+ // update the information.
+ split = next.split();
+ if (!split.second.empty()) {
+ lastTypeWithQuals = split.first;
+ quals.addConsistentQualifiers(split.second);
+ }
+ }
+
+ done:
+ return SplitQualType(lastTypeWithQuals, quals);
+}
+
+QualType QualType::IgnoreParens(QualType T) {
+ // FIXME: this seems inherently un-qualifiers-safe.
+ while (const ParenType *PT = T->getAs<ParenType>())
+ T = PT->getInnerType();
+ return T;
+}
+
/// 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.
@@ -268,42 +330,6 @@ QualType Type::getPointeeType() const {
return QualType();
}
-/// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length
-/// array types and types that contain variable array types in their
-/// declarator
-bool Type::isVariablyModifiedType() const {
- // FIXME: We should really keep a "variably modified" bit in Type, rather
- // than walking the type hierarchy to recompute it.
-
- // A VLA is a variably modified type.
- if (isVariableArrayType())
- return true;
-
- // An array can contain a variably modified type
- if (const Type *T = getArrayElementTypeNoTypeQual())
- return T->isVariablyModifiedType();
-
- // A pointer can point to a variably modified type.
- // Also, C++ references and member pointers can point to a variably modified
- // type, where VLAs appear as an extension to C++, and should be treated
- // correctly.
- if (const PointerType *PT = getAs<PointerType>())
- return PT->getPointeeType()->isVariablyModifiedType();
- if (const ReferenceType *RT = getAs<ReferenceType>())
- return RT->getPointeeType()->isVariablyModifiedType();
- if (const MemberPointerType *PT = getAs<MemberPointerType>())
- return PT->getPointeeType()->isVariablyModifiedType();
-
- // A function can return a variably modified type
- // This one isn't completely obvious, but it follows from the
- // definition in C99 6.7.5p3. Because of this rule, it's
- // illegal to declare a function returning a variably modified type.
- if (const FunctionType *FT = getAs<FunctionType>())
- return FT->getResultType()->isVariablyModifiedType();
-
- return false;
-}
-
const RecordType *Type::getAsStructureType() const {
// If this is directly a structure type, return it.
if (const RecordType *RT = dyn_cast<RecordType>(this)) {
@@ -346,10 +372,11 @@ const RecordType *Type::getAsUnionType() const {
ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base,
ObjCProtocolDecl * const *Protocols,
unsigned NumProtocols)
- : Type(ObjCObject, Canonical, false),
- NumProtocols(NumProtocols),
- BaseType(Base) {
- assert(this->NumProtocols == NumProtocols &&
+ : Type(ObjCObject, Canonical, false, false, false),
+ BaseType(Base)
+{
+ ObjCObjectTypeBits.NumProtocols = NumProtocols;
+ assert(getNumProtocols() == NumProtocols &&
"bitfield overflow in protocol count");
if (NumProtocols)
memcpy(getProtocolStorage(), Protocols,
@@ -405,15 +432,69 @@ CXXRecordDecl *Type::getAsCXXRecordDecl() const {
return 0;
}
+namespace {
+ class GetContainedAutoVisitor :
+ public TypeVisitor<GetContainedAutoVisitor, AutoType*> {
+ public:
+ using TypeVisitor<GetContainedAutoVisitor, AutoType*>::Visit;
+ AutoType *Visit(QualType T) {
+ if (T.isNull())
+ return 0;
+ return Visit(T.getTypePtr());
+ }
+
+ // The 'auto' type itself.
+ AutoType *VisitAutoType(const AutoType *AT) {
+ return const_cast<AutoType*>(AT);
+ }
+
+ // Only these types can contain the desired 'auto' type.
+ AutoType *VisitPointerType(const PointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+ AutoType *VisitBlockPointerType(const BlockPointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+ AutoType *VisitReferenceType(const ReferenceType *T) {
+ return Visit(T->getPointeeTypeAsWritten());
+ }
+ AutoType *VisitMemberPointerType(const MemberPointerType *T) {
+ return Visit(T->getPointeeType());
+ }
+ AutoType *VisitArrayType(const ArrayType *T) {
+ return Visit(T->getElementType());
+ }
+ AutoType *VisitDependentSizedExtVectorType(
+ const DependentSizedExtVectorType *T) {
+ return Visit(T->getElementType());
+ }
+ AutoType *VisitVectorType(const VectorType *T) {
+ return Visit(T->getElementType());
+ }
+ AutoType *VisitFunctionType(const FunctionType *T) {
+ return Visit(T->getResultType());
+ }
+ AutoType *VisitParenType(const ParenType *T) {
+ return Visit(T->getInnerType());
+ }
+ AutoType *VisitAttributedType(const AttributedType *T) {
+ return Visit(T->getModifiedType());
+ }
+ };
+}
+
+AutoType *Type::getContainedAutoType() const {
+ return GetContainedAutoVisitor().Visit(this);
+}
+
bool Type::isIntegerType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::Int128;
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
// Incomplete enum types are not treated as integer types.
// FIXME: In C++, enum types are never integer types.
- if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
- return true;
+ return ET->getDecl()->isComplete();
return false;
}
@@ -449,9 +530,8 @@ bool Type::isIntegralType(ASTContext &Ctx) const {
BT->getKind() <= BuiltinType::Int128;
if (!Ctx.getLangOptions().CPlusPlus)
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
- if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
- return true; // Complete enum types are integral in C.
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->isComplete(); // Complete enum types are integral in C.
return false;
}
@@ -463,19 +543,28 @@ bool Type::isIntegralOrEnumerationType() const {
// Check for a complete enum type; incomplete enum types are not properly an
// enumeration type in the sense required here.
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
- if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
- return true;
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->isComplete();
return false;
}
-bool Type::isEnumeralType() const {
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
- return TT->getDecl()->isEnum();
+bool Type::isIntegralOrUnscopedEnumerationType() const {
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+ return BT->getKind() >= BuiltinType::Bool &&
+ BT->getKind() <= BuiltinType::Int128;
+
+ // Check for a complete enum type; incomplete enum types are not properly an
+ // enumeration type in the sense required here.
+ // C++0x: However, if the underlying type of the enum is fixed, it is
+ // considered complete.
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
+
return false;
}
+
bool Type::isBooleanType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() == BuiltinType::Bool;
@@ -493,20 +582,28 @@ bool Type::isCharType() const {
bool Type::isWideCharType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() == BuiltinType::WChar;
+ return BT->getKind() == BuiltinType::WChar_S ||
+ BT->getKind() == BuiltinType::WChar_U;
return false;
}
/// \brief Determine whether this type is any of the built-in character
/// types.
bool Type::isAnyCharacterType() const {
- if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return (BT->getKind() >= BuiltinType::Char_U &&
- BT->getKind() <= BuiltinType::Char32) ||
- (BT->getKind() >= BuiltinType::Char_S &&
- BT->getKind() <= BuiltinType::WChar);
-
- return false;
+ const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType);
+ if (BT == 0) return false;
+ switch (BT->getKind()) {
+ default: return false;
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ case BuiltinType::WChar_S:
+ return true;
+ }
}
/// isSignedIntegerType - Return true if this is an integer type that is
@@ -518,8 +615,12 @@ bool Type::isSignedIntegerType() const {
BT->getKind() <= BuiltinType::Int128;
}
- if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
- return ET->getDecl()->getIntegerType()->isSignedIntegerType();
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
+ // Incomplete enum types are not treated as integer types.
+ // FIXME: In C++, enum types are never integer types.
+ if (ET->getDecl()->isComplete())
+ return ET->getDecl()->getIntegerType()->isSignedIntegerType();
+ }
return false;
}
@@ -540,8 +641,12 @@ bool Type::isUnsignedIntegerType() const {
BT->getKind() <= BuiltinType::UInt128;
}
- if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
- return ET->getDecl()->getIntegerType()->isUnsignedIntegerType();
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) {
+ // Incomplete enum types are not treated as integer types.
+ // FIXME: In C++, enum types are never integer types.
+ if (ET->getDecl()->isComplete())
+ return ET->getDecl()->getIntegerType()->isUnsignedIntegerType();
+ }
return false;
}
@@ -579,8 +684,8 @@ bool Type::isRealType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
BT->getKind() <= BuiltinType::LongDouble;
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
- return TT->getDecl()->isEnum() && TT->getDecl()->isDefinition();
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
+ return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped();
return false;
}
@@ -591,20 +696,22 @@ bool Type::isArithmeticType() const {
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
// GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2).
// If a body isn't seen by the time we get here, return false.
- return ET->getDecl()->isDefinition();
+ //
+ // C++0x: Enumerations are not arithmetic types. For now, just return
+ // false for scoped enumerations since that will disable any
+ // unwanted implicit conversions.
+ return !ET->getDecl()->isScoped() && ET->getDecl()->isComplete();
return isa<ComplexType>(CanonicalType);
}
bool Type::isScalarType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() != BuiltinType::Void;
- if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) {
+ return BT->getKind() > BuiltinType::Void &&
+ BT->getKind() <= BuiltinType::NullPtr;
+ if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
// Enums are scalar types, but only if they are defined. Incomplete enums
// are not treated as scalar types.
- if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition())
- return true;
- return false;
- }
+ return ET->getDecl()->isComplete();
return isa<PointerType>(CanonicalType) ||
isa<BlockPointerType>(CanonicalType) ||
isa<MemberPointerType>(CanonicalType) ||
@@ -612,6 +719,35 @@ bool Type::isScalarType() const {
isa<ObjCObjectPointerType>(CanonicalType);
}
+Type::ScalarTypeKind Type::getScalarTypeKind() const {
+ assert(isScalarType());
+
+ const Type *T = CanonicalType.getTypePtr();
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) {
+ if (BT->getKind() == BuiltinType::Bool) return STK_Bool;
+ if (BT->getKind() == BuiltinType::NullPtr) return STK_Pointer;
+ if (BT->isInteger()) return STK_Integral;
+ if (BT->isFloatingPoint()) return STK_Floating;
+ llvm_unreachable("unknown scalar builtin type");
+ } else if (isa<PointerType>(T) ||
+ isa<BlockPointerType>(T) ||
+ isa<ObjCObjectPointerType>(T)) {
+ return STK_Pointer;
+ } else if (isa<MemberPointerType>(T)) {
+ return STK_MemberPointer;
+ } else if (isa<EnumType>(T)) {
+ assert(cast<EnumType>(T)->getDecl()->isComplete());
+ return STK_Integral;
+ } else if (const ComplexType *CT = dyn_cast<ComplexType>(T)) {
+ if (CT->getElementType()->isRealFloatingType())
+ return STK_FloatingComplex;
+ return STK_IntegralComplex;
+ }
+
+ llvm_unreachable("unknown scalar type");
+ return STK_Pointer;
+}
+
/// \brief Determines whether the type is a C++ aggregate type or C
/// aggregate or union type.
///
@@ -652,8 +788,12 @@ bool Type::isIncompleteType() const {
// Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never
// be completed.
return isVoidType();
- case Record:
case Enum:
+ // An enumeration with fixed underlying type is complete (C++0x 7.2p3).
+ if (cast<EnumType>(CanonicalType)->getDecl()->isFixed())
+ return false;
+ // Fall through.
+ case Record:
// A tagged type (struct/union/enum/class) is incomplete if the decl is a
// forward declaration, but not a full definition (C99 6.2.5p22).
return !cast<TagType>(CanonicalType)->getDecl()->isDefinition();
@@ -678,7 +818,11 @@ bool Type::isIncompleteType() const {
/// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10)
bool Type::isPODType() const {
// The compiler shouldn't query this for incomplete types, but the user might.
- // We return false for that case.
+ // We return false for that case. Except for incomplete arrays of PODs, which
+ // are PODs according to the standard.
+ if (isIncompleteArrayType() &&
+ cast<ArrayType>(CanonicalType)->getElementType()->isPODType())
+ return true;
if (isIncompleteType())
return false;
@@ -687,7 +831,7 @@ bool Type::isPODType() const {
default: return false;
case VariableArray:
case ConstantArray:
- // IncompleteArray is caught by isIncompleteType() above.
+ // IncompleteArray is handled above.
return cast<ArrayType>(CanonicalType)->getElementType()->isPODType();
case Builtin:
@@ -765,7 +909,8 @@ bool Type::isPromotableIntegerType() const {
// Enumerated types are promotable to their compatible integer types
// (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2).
if (const EnumType *ET = getAs<EnumType>()){
- if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull())
+ if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull()
+ || ET->getDecl()->isScoped())
return false;
const BuiltinType *BT
@@ -808,9 +953,6 @@ bool Type::isSpecifierType() const {
}
}
-TypeWithKeyword::~TypeWithKeyword() {
-}
-
ElaboratedTypeKeyword
TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) {
switch (TypeSpec) {
@@ -830,8 +972,10 @@ TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) {
case TST_struct: return TTK_Struct;
case TST_union: return TTK_Union;
case TST_enum: return TTK_Enum;
- default: llvm_unreachable("Type specifier is not a tag type kind.");
}
+
+ llvm_unreachable("Type specifier is not a tag type kind.");
+ return TTK_Union;
}
ElaboratedTypeKeyword
@@ -877,7 +1021,6 @@ TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) {
const char*
TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) {
switch (Keyword) {
- default: llvm_unreachable("Unknown elaborated type keyword.");
case ETK_None: return "";
case ETK_Typename: return "typename";
case ETK_Class: return "class";
@@ -885,28 +1028,33 @@ TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) {
case ETK_Union: return "union";
case ETK_Enum: return "enum";
}
-}
-ElaboratedType::~ElaboratedType() {}
-DependentNameType::~DependentNameType() {}
-DependentTemplateSpecializationType::~DependentTemplateSpecializationType() {}
+ llvm_unreachable("Unknown elaborated type keyword.");
+ return "";
+}
DependentTemplateSpecializationType::DependentTemplateSpecializationType(
ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *NNS, const IdentifierInfo *Name,
unsigned NumArgs, const TemplateArgument *Args,
QualType Canon)
- : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true),
+ : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true,
+ /*VariablyModified=*/false,
+ NNS->containsUnexpandedParameterPack()),
NNS(NNS), Name(Name), NumArgs(NumArgs) {
assert(NNS && NNS->isDependent() &&
"DependentTemplateSpecializatonType requires dependent qualifier");
- for (unsigned I = 0; I != NumArgs; ++I)
+ for (unsigned I = 0; I != NumArgs; ++I) {
+ if (Args[I].containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
+
new (&getArgBuffer()[I]) TemplateArgument(Args[I]);
+ }
}
void
DependentTemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
- ASTContext &Context,
+ const ASTContext &Context,
ElaboratedTypeKeyword Keyword,
NestedNameSpecifier *Qualifier,
const IdentifierInfo *Name,
@@ -935,17 +1083,18 @@ bool Type::isElaboratedTypeSpecifier() const {
}
const char *Type::getTypeClassName() const {
- switch (TC) {
- default: assert(0 && "Type class not in TypeNodes.def!");
+ switch (TypeBits.TC) {
#define ABSTRACT_TYPE(Derived, Base)
#define TYPE(Derived, Base) case Derived: return #Derived;
#include "clang/AST/TypeNodes.def"
}
+
+ llvm_unreachable("Invalid type class.");
+ return 0;
}
const char *BuiltinType::getName(const LangOptions &LO) const {
switch (getKind()) {
- default: assert(0 && "Unknown builtin type!");
case Void: return "void";
case Bool: return LO.Bool ? "bool" : "_Bool";
case Char_S: return "char";
@@ -965,21 +1114,22 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
case Float: return "float";
case Double: return "double";
case LongDouble: return "long double";
- case WChar: return "wchar_t";
+ case WChar_S:
+ case WChar_U: return "wchar_t";
case Char16: return "char16_t";
case Char32: return "char32_t";
case NullPtr: return "nullptr_t";
case Overload: return "<overloaded function type>";
case Dependent: return "<dependent type>";
- case UndeducedAuto: return "auto";
case ObjCId: return "id";
case ObjCClass: return "Class";
case ObjCSel: return "SEL";
}
+
+ llvm_unreachable("Invalid builtin type.");
+ return 0;
}
-void FunctionType::ANCHOR() {} // Key function for FunctionType.
-
QualType QualType::getNonLValueExprType(ASTContext &Context) const {
if (const ReferenceType *RefType = getTypePtr()->getAs<ReferenceType>())
return RefType->getPointeeType();
@@ -998,8 +1148,9 @@ QualType QualType::getNonLValueExprType(ASTContext &Context) const {
llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
switch (CC) {
- case CC_Default: llvm_unreachable("no name for default cc");
- default: return "";
+ case CC_Default:
+ llvm_unreachable("no name for default cc");
+ return "";
case CC_C: return "cdecl";
case CC_X86StdCall: return "stdcall";
@@ -1007,62 +1158,76 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_X86ThisCall: return "thiscall";
case CC_X86Pascal: return "pascal";
}
+
+ llvm_unreachable("Invalid calling convention.");
+ return "";
+}
+
+FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
+ unsigned numArgs, QualType canonical,
+ const ExtProtoInfo &epi)
+ : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals,
+ epi.RefQualifier, canonical,
+ result->isDependentType(),
+ result->isVariablyModifiedType(),
+ result->containsUnexpandedParameterPack(),
+ epi.ExtInfo),
+ NumArgs(numArgs), NumExceptions(epi.NumExceptions),
+ HasExceptionSpec(epi.HasExceptionSpec),
+ HasAnyExceptionSpec(epi.HasAnyExceptionSpec)
+{
+ // Fill in the trailing argument array.
+ QualType *argSlot = reinterpret_cast<QualType*>(this+1);
+ for (unsigned i = 0; i != numArgs; ++i) {
+ if (args[i]->isDependentType())
+ setDependent();
+
+ if (args[i]->containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
+
+ argSlot[i] = args[i];
+ }
+
+ // Fill in the exception array.
+ QualType *exnSlot = argSlot + numArgs;
+ for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
+ if (epi.Exceptions[i]->isDependentType())
+ setDependent();
+
+ if (epi.Exceptions[i]->containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
+
+ exnSlot[i] = epi.Exceptions[i];
+ }
+}
+
+bool FunctionProtoType::isTemplateVariadic() const {
+ for (unsigned ArgIdx = getNumArgs(); ArgIdx; --ArgIdx)
+ if (isa<PackExpansionType>(getArgType(ArgIdx - 1)))
+ return true;
+
+ return false;
}
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
- arg_type_iterator ArgTys,
- unsigned NumArgs, bool isVariadic,
- unsigned TypeQuals, bool hasExceptionSpec,
- bool anyExceptionSpec, unsigned NumExceptions,
- exception_iterator Exs,
- const FunctionType::ExtInfo &Info) {
+ const QualType *ArgTys, unsigned NumArgs,
+ const ExtProtoInfo &epi) {
ID.AddPointer(Result.getAsOpaquePtr());
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i].getAsOpaquePtr());
- ID.AddInteger(isVariadic);
- ID.AddInteger(TypeQuals);
- ID.AddInteger(hasExceptionSpec);
- if (hasExceptionSpec) {
- ID.AddInteger(anyExceptionSpec);
- for (unsigned i = 0; i != NumExceptions; ++i)
- ID.AddPointer(Exs[i].getAsOpaquePtr());
+ ID.AddBoolean(epi.Variadic);
+ ID.AddInteger(epi.TypeQuals);
+ ID.AddInteger(epi.RefQualifier);
+ if (epi.HasExceptionSpec) {
+ ID.AddBoolean(epi.HasAnyExceptionSpec);
+ for (unsigned i = 0; i != epi.NumExceptions; ++i)
+ ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());
}
- ID.AddInteger(Info.getNoReturn());
- ID.AddInteger(Info.getRegParm());
- ID.AddInteger(Info.getCC());
+ epi.ExtInfo.Profile(ID);
}
void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) {
- Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(),
- getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(),
- getNumExceptions(), exception_begin(),
- getExtInfo());
-}
-
-/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
-/// potentially looking through *all* consequtive typedefs. This returns the
-/// sum of the type qualifiers, so if you have:
-/// typedef const int A;
-/// typedef volatile A B;
-/// looking through the typedefs for B will give you "const volatile A".
-///
-QualType TypedefType::LookThroughTypedefs() const {
- // Usually, there is only a single level of typedefs, be fast in that case.
- QualType FirstType = getDecl()->getUnderlyingType();
- if (!isa<TypedefType>(FirstType))
- return FirstType;
-
- // Otherwise, do the fully general loop.
- QualifierCollector Qs;
-
- QualType CurType;
- const TypedefType *TDT = this;
- do {
- CurType = TDT->getDecl()->getUnderlyingType();
- TDT = dyn_cast<TypedefType>(Qs.strip(CurType));
- } while (TDT);
-
- return Qs.apply(CurType);
+ Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo());
}
QualType TypedefType::desugar() const {
@@ -1070,7 +1235,10 @@ QualType TypedefType::desugar() const {
}
TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
- : Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) {
+ : Type(TypeOfExpr, can, E->isTypeDependent(),
+ E->getType()->isVariablyModifiedType(),
+ E->containsUnexpandedParameterPack()),
+ TOExpr(E) {
}
QualType TypeOfExprType::desugar() const {
@@ -1078,25 +1246,29 @@ QualType TypeOfExprType::desugar() const {
}
void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
- ASTContext &Context, Expr *E) {
+ const ASTContext &Context, Expr *E) {
E->Profile(ID, Context, true);
}
DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
- : Type(Decltype, can, E->isTypeDependent()), E(E),
+ : Type(Decltype, can, E->isTypeDependent(),
+ E->getType()->isVariablyModifiedType(),
+ E->containsUnexpandedParameterPack()),
+ E(E),
UnderlyingType(underlyingType) {
}
-DependentDecltypeType::DependentDecltypeType(ASTContext &Context, Expr *E)
+DependentDecltypeType::DependentDecltypeType(const ASTContext &Context, Expr *E)
: DecltypeType(E, Context.DependentTy), Context(Context) { }
void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID,
- ASTContext &Context, Expr *E) {
+ const ASTContext &Context, Expr *E) {
E->Profile(ID, Context, true);
}
TagType::TagType(TypeClass TC, const TagDecl *D, QualType can)
- : Type(TC, can, D->isDependentType()),
+ : Type(TC, can, D->isDependentType(), /*VariablyModified=*/false,
+ /*ContainsUnexpandedParameterPack=*/false),
decl(const_cast<TagDecl*>(D)) {}
static TagDecl *getInterestingTagDecl(TagDecl *decl) {
@@ -1130,43 +1302,32 @@ bool EnumType::classof(const TagType *TT) {
return isa<EnumDecl>(TT->getDecl());
}
-static bool isDependent(const TemplateArgument &Arg) {
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- assert(false && "Should not have a NULL template argument");
- return false;
-
- case TemplateArgument::Type:
- return Arg.getAsType()->isDependentType();
-
- case TemplateArgument::Template:
- return Arg.getAsTemplate().isDependent();
-
- case TemplateArgument::Declaration:
- if (DeclContext *DC = dyn_cast<DeclContext>(Arg.getAsDecl()))
- return DC->isDependentContext();
- return Arg.getAsDecl()->getDeclContext()->isDependentContext();
-
- case TemplateArgument::Integral:
- // Never dependent
- return false;
-
- case TemplateArgument::Expression:
- return (Arg.getAsExpr()->isTypeDependent() ||
- Arg.getAsExpr()->isValueDependent());
+SubstTemplateTypeParmPackType::
+SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param,
+ QualType Canon,
+ const TemplateArgument &ArgPack)
+ : Type(SubstTemplateTypeParmPack, Canon, true, false, true), Replaced(Param),
+ Arguments(ArgPack.pack_begin()), NumArguments(ArgPack.pack_size())
+{
+}
- case TemplateArgument::Pack:
- for (TemplateArgument::pack_iterator P = Arg.pack_begin(),
- PEnd = Arg.pack_end();
- P != PEnd; ++P) {
- if (isDependent(*P))
- return true;
- }
+TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const {
+ return TemplateArgument(Arguments, NumArguments);
+}
- return false;
- }
+void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getReplacedParameter(), getArgumentPack());
+}
- return false;
+void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID,
+ const TemplateTypeParmType *Replaced,
+ const TemplateArgument &ArgPack) {
+ ID.AddPointer(Replaced);
+ ID.AddInteger(ArgPack.pack_size());
+ for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(),
+ PEnd = ArgPack.pack_end();
+ P != PEnd; ++P)
+ ID.AddPointer(P->getAsType().getAsOpaquePtr());
}
bool TemplateSpecializationType::
@@ -1177,7 +1338,7 @@ anyDependentTemplateArguments(const TemplateArgumentListInfo &Args) {
bool TemplateSpecializationType::
anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) {
for (unsigned i = 0; i != N; ++i)
- if (isDependent(Args[i].getArgument()))
+ if (Args[i].getArgument().isDependent())
return true;
return false;
}
@@ -1185,7 +1346,7 @@ anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) {
bool TemplateSpecializationType::
anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) {
for (unsigned i = 0; i != N; ++i)
- if (isDependent(Args[i]))
+ if (Args[i].isDependent())
return true;
return false;
}
@@ -1196,16 +1357,28 @@ TemplateSpecializationType(TemplateName T,
unsigned NumArgs, QualType Canon)
: Type(TemplateSpecialization,
Canon.isNull()? QualType(this, 0) : Canon,
- T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)),
- Template(T), NumArgs(NumArgs) {
+ T.isDependent(), false,
+ T.containsUnexpandedParameterPack()),
+ Template(T), NumArgs(NumArgs)
+{
assert((!Canon.isNull() ||
T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) &&
"No canonical type for non-dependent class template specialization");
TemplateArgument *TemplateArgs
= reinterpret_cast<TemplateArgument *>(this + 1);
- for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ // Update dependent and variably-modified bits.
+ if (Args[Arg].isDependent())
+ setDependent();
+ if (Args[Arg].getKind() == TemplateArgument::Type &&
+ Args[Arg].getAsType()->isVariablyModifiedType())
+ setVariablyModified();
+ if (Args[Arg].containsUnexpandedParameterPack())
+ setContainsUnexpandedParameterPack();
+
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
+ }
}
void
@@ -1213,26 +1386,26 @@ TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
TemplateName T,
const TemplateArgument *Args,
unsigned NumArgs,
- ASTContext &Context) {
+ const ASTContext &Context) {
T.Profile(ID);
for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
Args[Idx].Profile(ID, Context);
}
-QualType QualifierCollector::apply(QualType QT) const {
+QualType
+QualifierCollector::apply(const ASTContext &Context, QualType QT) const {
if (!hasNonFastQualifiers())
return QT.withFastQualifiers(getFastQualifiers());
- assert(Context && "extended qualifiers but no context!");
- return Context->getQualifiedType(QT, *this);
+ return Context.getQualifiedType(QT, *this);
}
-QualType QualifierCollector::apply(const Type *T) const {
+QualType
+QualifierCollector::apply(const ASTContext &Context, const Type *T) const {
if (!hasNonFastQualifiers())
return QualType(T, getFastQualifiers());
- assert(Context && "extended qualifiers but no context!");
- return Context->getQualifiedType(T, *this);
+ return Context.getQualifiedType(T, *this);
}
void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID,
@@ -1248,95 +1421,223 @@ void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getBaseType(), qual_begin(), getNumProtocols());
}
-/// \brief Determine the linkage of this type.
-Linkage Type::getLinkage() const {
- if (this != CanonicalType.getTypePtr())
- return CanonicalType->getLinkage();
+namespace {
+
+/// \brief The cached properties of a type.
+class CachedProperties {
+ char linkage;
+ char visibility;
+ bool local;
- if (!LinkageKnown) {
- CachedLinkage = getLinkageImpl();
- LinkageKnown = true;
- }
+public:
+ CachedProperties(Linkage linkage, Visibility visibility, bool local)
+ : linkage(linkage), visibility(visibility), local(local) {}
- return static_cast<clang::Linkage>(CachedLinkage);
+ Linkage getLinkage() const { return (Linkage) linkage; }
+ Visibility getVisibility() const { return (Visibility) visibility; }
+ bool hasLocalOrUnnamedType() const { return local; }
+
+ friend CachedProperties merge(CachedProperties L, CachedProperties R) {
+ return CachedProperties(minLinkage(L.getLinkage(), R.getLinkage()),
+ minVisibility(L.getVisibility(), R.getVisibility()),
+ L.hasLocalOrUnnamedType() | R.hasLocalOrUnnamedType());
+ }
+};
}
-Linkage Type::getLinkageImpl() const {
- // C++ [basic.link]p8:
- // Names not covered by these rules have no linkage.
- return NoLinkage;
-}
+static CachedProperties computeCachedProperties(const Type *T);
-void Type::ClearLinkageCache() {
- if (this != CanonicalType.getTypePtr())
- CanonicalType->ClearLinkageCache();
- else
- LinkageKnown = false;
-}
+namespace clang {
+/// The type-property cache. This is templated so as to be
+/// instantiated at an internal type to prevent unnecessary symbol
+/// leakage.
+template <class Private> class TypePropertyCache {
+public:
+ static CachedProperties get(QualType T) {
+ return get(T.getTypePtr());
+ }
-Linkage BuiltinType::getLinkageImpl() const {
- // C++ [basic.link]p8:
- // A type is said to have linkage if and only if:
- // - it is a fundamental type (3.9.1); or
- return ExternalLinkage;
-}
+ static CachedProperties get(const Type *T) {
+ ensure(T);
+ return CachedProperties(T->TypeBits.getLinkage(),
+ T->TypeBits.getVisibility(),
+ T->TypeBits.hasLocalOrUnnamedType());
+ }
-Linkage TagType::getLinkageImpl() const {
- // C++ [basic.link]p8:
- // - 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
- return getDecl()->getLinkage();
-}
+ static void ensure(const Type *T) {
+ // If the cache is valid, we're okay.
+ if (T->TypeBits.isCacheValid()) return;
+
+ // If this type is non-canonical, ask its canonical type for the
+ // relevant information.
+ if (!T->isCanonicalUnqualified()) {
+ const Type *CT = T->getCanonicalTypeInternal().getTypePtr();
+ ensure(CT);
+ T->TypeBits.CacheValidAndVisibility =
+ CT->TypeBits.CacheValidAndVisibility;
+ T->TypeBits.CachedLinkage = CT->TypeBits.CachedLinkage;
+ T->TypeBits.CachedLocalOrUnnamed = CT->TypeBits.CachedLocalOrUnnamed;
+ return;
+ }
-// C++ [basic.link]p8:
-// - it is a compound type (3.9.2) other than a class or enumeration,
-// compounded exclusively from types that have linkage; or
-Linkage ComplexType::getLinkageImpl() const {
- return ElementType->getLinkage();
+ // Compute the cached properties and then set the cache.
+ CachedProperties Result = computeCachedProperties(T);
+ T->TypeBits.CacheValidAndVisibility = Result.getVisibility() + 1U;
+ assert(T->TypeBits.isCacheValid() &&
+ T->TypeBits.getVisibility() == Result.getVisibility());
+ T->TypeBits.CachedLinkage = Result.getLinkage();
+ T->TypeBits.CachedLocalOrUnnamed = Result.hasLocalOrUnnamedType();
+ }
+};
}
-Linkage PointerType::getLinkageImpl() const {
- return PointeeType->getLinkage();
-}
+// Instantiate the friend template at a private class. In a
+// reasonable implementation, these symbols will be internal.
+// It is terrible that this is the best way to accomplish this.
+namespace { class Private {}; }
+typedef TypePropertyCache<Private> Cache;
+
+static CachedProperties computeCachedProperties(const Type *T) {
+ switch (T->getTypeClass()) {
+#define TYPE(Class,Base)
+#define NON_CANONICAL_TYPE(Class,Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("didn't expect a non-canonical type here");
+
+#define TYPE(Class,Base)
+#define DEPENDENT_TYPE(Class,Base) case Type::Class:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class:
+#include "clang/AST/TypeNodes.def"
+ // Treat dependent types as external.
+ assert(T->isDependentType());
+ return CachedProperties(ExternalLinkage, DefaultVisibility, false);
+
+ case Type::Builtin:
+ // C++ [basic.link]p8:
+ // A type is said to have linkage if and only if:
+ // - it is a fundamental type (3.9.1); or
+ return CachedProperties(ExternalLinkage, DefaultVisibility, false);
+
+ case Type::Record:
+ case Type::Enum: {
+ const TagDecl *Tag = cast<TagType>(T)->getDecl();
+
+ // C++ [basic.link]p8:
+ // - 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
+ NamedDecl::LinkageInfo LV = Tag->getLinkageAndVisibility();
+ bool IsLocalOrUnnamed =
+ Tag->getDeclContext()->isFunctionOrMethod() ||
+ (!Tag->getIdentifier() && !Tag->getTypedefForAnonDecl());
+ return CachedProperties(LV.linkage(), LV.visibility(), IsLocalOrUnnamed);
+ }
+
+ // C++ [basic.link]p8:
+ // - it is a compound type (3.9.2) other than a class or enumeration,
+ // compounded exclusively from types that have linkage; or
+ case Type::Complex:
+ return Cache::get(cast<ComplexType>(T)->getElementType());
+ case Type::Pointer:
+ return Cache::get(cast<PointerType>(T)->getPointeeType());
+ case Type::BlockPointer:
+ return Cache::get(cast<BlockPointerType>(T)->getPointeeType());
+ case Type::LValueReference:
+ case Type::RValueReference:
+ return Cache::get(cast<ReferenceType>(T)->getPointeeType());
+ case Type::MemberPointer: {
+ const MemberPointerType *MPT = cast<MemberPointerType>(T);
+ return merge(Cache::get(MPT->getClass()),
+ Cache::get(MPT->getPointeeType()));
+ }
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ return Cache::get(cast<ArrayType>(T)->getElementType());
+ case Type::Vector:
+ case Type::ExtVector:
+ return Cache::get(cast<VectorType>(T)->getElementType());
+ case Type::FunctionNoProto:
+ return Cache::get(cast<FunctionType>(T)->getResultType());
+ case Type::FunctionProto: {
+ const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
+ CachedProperties result = Cache::get(FPT->getResultType());
+ for (FunctionProtoType::arg_type_iterator ai = FPT->arg_type_begin(),
+ ae = FPT->arg_type_end(); ai != ae; ++ai)
+ result = merge(result, Cache::get(*ai));
+ return result;
+ }
+ case Type::ObjCInterface: {
+ NamedDecl::LinkageInfo LV =
+ cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility();
+ return CachedProperties(LV.linkage(), LV.visibility(), false);
+ }
+ case Type::ObjCObject:
+ return Cache::get(cast<ObjCObjectType>(T)->getBaseType());
+ case Type::ObjCObjectPointer:
+ return Cache::get(cast<ObjCObjectPointerType>(T)->getPointeeType());
+ }
+
+ llvm_unreachable("unhandled type class");
-Linkage BlockPointerType::getLinkageImpl() const {
- return PointeeType->getLinkage();
+ // C++ [basic.link]p8:
+ // Names not covered by these rules have no linkage.
+ return CachedProperties(NoLinkage, DefaultVisibility, false);
}
-Linkage ReferenceType::getLinkageImpl() const {
- return PointeeType->getLinkage();
+/// \brief Determine the linkage of this type.
+Linkage Type::getLinkage() const {
+ Cache::ensure(this);
+ return TypeBits.getLinkage();
}
-Linkage MemberPointerType::getLinkageImpl() const {
- return minLinkage(Class->getLinkage(), PointeeType->getLinkage());
+/// \brief Determine the linkage of this type.
+Visibility Type::getVisibility() const {
+ Cache::ensure(this);
+ return TypeBits.getVisibility();
}
-Linkage ArrayType::getLinkageImpl() const {
- return ElementType->getLinkage();
+bool Type::hasUnnamedOrLocalType() const {
+ Cache::ensure(this);
+ return TypeBits.hasLocalOrUnnamedType();
}
-Linkage VectorType::getLinkageImpl() const {
- return ElementType->getLinkage();
+std::pair<Linkage,Visibility> Type::getLinkageAndVisibility() const {
+ Cache::ensure(this);
+ return std::make_pair(TypeBits.getLinkage(), TypeBits.getVisibility());
}
-Linkage FunctionNoProtoType::getLinkageImpl() const {
- return getResultType()->getLinkage();
+void Type::ClearLinkageCache() {
+ TypeBits.CacheValidAndVisibility = 0;
+ if (QualType(this, 0) != CanonicalType)
+ CanonicalType->TypeBits.CacheValidAndVisibility = 0;
}
-Linkage FunctionProtoType::getLinkageImpl() const {
- Linkage L = getResultType()->getLinkage();
- for (arg_type_iterator A = arg_type_begin(), AEnd = arg_type_end();
- A != AEnd; ++A)
- L = minLinkage(L, (*A)->getLinkage());
+bool Type::hasSizedVLAType() const {
+ if (!isVariablyModifiedType()) return false;
- return L;
-}
+ if (const PointerType *ptr = getAs<PointerType>())
+ return ptr->getPointeeType()->hasSizedVLAType();
+ if (const ReferenceType *ref = getAs<ReferenceType>())
+ return ref->getPointeeType()->hasSizedVLAType();
+ if (const ArrayType *arr = getAsArrayTypeUnsafe()) {
+ if (isa<VariableArrayType>(arr) &&
+ cast<VariableArrayType>(arr)->getSizeExpr())
+ return true;
+
+ return arr->getElementType()->hasSizedVLAType();
+ }
-Linkage ObjCObjectType::getLinkageImpl() const {
- return ExternalLinkage;
+ return false;
}
-Linkage ObjCObjectPointerType::getLinkageImpl() const {
- return ExternalLinkage;
+QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
+ /// Currently, the only destruction kind we recognize is C++ objects
+ /// with non-trivial destructors.
+ const CXXRecordDecl *record =
+ type->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+ if (record && !record->hasTrivialDestructor())
+ return DK_cxx_destructor;
+
+ return DK_none;
}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 66578fb..14db7f8 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -77,14 +77,15 @@ TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) {
/// \brief Initializes a type location, and all of its children
/// recursively, as if the entire tree had been written in the
/// given location.
-void TypeLoc::initializeImpl(TypeLoc TL, SourceLocation Loc) {
+void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL,
+ SourceLocation Loc) {
while (true) {
switch (TL.getTypeLocClass()) {
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
case CLASS: { \
CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \
- TLCasted.initializeLocal(Loc); \
+ TLCasted.initializeLocal(Context, Loc); \
TL = TLCasted.getNextTypeLoc(); \
if (!TL) return; \
continue; \
@@ -187,11 +188,10 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
return TST_char16;
case BuiltinType::Char32:
return TST_char32;
- case BuiltinType::WChar:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
return TST_wchar;
- case BuiltinType::UndeducedAuto:
- return TST_auto;
-
+
case BuiltinType::UChar:
case BuiltinType::UShort:
case BuiltinType::UInt:
@@ -222,3 +222,44 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
return TST_unspecified;
}
+
+TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
+ while (ParenTypeLoc* PTL = dyn_cast<ParenTypeLoc>(&TL))
+ TL = PTL->getInnerLoc();
+ return TL;
+}
+
+void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context,
+ unsigned NumArgs,
+ const TemplateArgument *Args,
+ TemplateArgumentLocInfo *ArgInfos,
+ SourceLocation Loc) {
+ for (unsigned i = 0, e = NumArgs; i != e; ++i) {
+ switch (Args[i].getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Pack:
+ case TemplateArgument::Expression:
+ // FIXME: Can we do better for declarations and integral values?
+ ArgInfos[i] = TemplateArgumentLocInfo();
+ break;
+
+ case TemplateArgument::Type:
+ ArgInfos[i] = TemplateArgumentLocInfo(
+ Context.getTrivialTypeSourceInfo(Args[i].getAsType(),
+ Loc));
+ break;
+
+ case TemplateArgument::Template:
+ ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc,
+ SourceLocation());
+ break;
+
+ case TemplateArgument::TemplateExpansion:
+ ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc, Loc);
+ break;
+ }
+ }
+}
+
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index d3a6b64..1390739 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -30,12 +30,13 @@ namespace {
public:
explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { }
- void Print(QualType T, std::string &S);
+ void print(const Type *ty, Qualifiers qs, std::string &buffer);
+ void print(QualType T, std::string &S);
void AppendScope(DeclContext *DC, std::string &S);
- void PrintTag(TagDecl *T, std::string &S);
+ void printTag(TagDecl *T, std::string &S);
#define ABSTRACT_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) \
- void Print##CLASS(const CLASS##Type *T, std::string &S);
+ void print##CLASS(const CLASS##Type *T, std::string &S);
#include "clang/AST/TypeNodes.def"
};
}
@@ -55,9 +56,14 @@ static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
}
}
-void TypePrinter::Print(QualType T, std::string &S) {
- if (T.isNull()) {
- S += "NULL TYPE";
+void TypePrinter::print(QualType t, std::string &buffer) {
+ SplitQualType split = t.split();
+ print(split.first, split.second, buffer);
+}
+
+void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) {
+ if (!T) {
+ buffer += "NULL TYPE";
return;
}
@@ -65,28 +71,104 @@ void TypePrinter::Print(QualType T, std::string &S) {
return;
// Print qualifiers as appropriate.
- Qualifiers Quals = T.getLocalQualifiers();
- if (!Quals.empty()) {
- std::string TQS;
- Quals.getAsStringInternal(TQS, Policy);
+
+ // CanPrefixQualifiers - We prefer to print type qualifiers before the type,
+ // so that we get "const int" instead of "int const", but we can't do this if
+ // the type is complex. For example if the type is "int*", we *must* print
+ // "int * const", printing "const int *" is different. Only do this when the
+ // type expands to a simple string.
+ bool CanPrefixQualifiers = false;
+
+ Type::TypeClass TC = T->getTypeClass();
+ if (const AutoType *AT = dyn_cast<AutoType>(T))
+ TC = AT->desugar()->getTypeClass();
+ if (const SubstTemplateTypeParmType *Subst
+ = dyn_cast<SubstTemplateTypeParmType>(T))
+ TC = Subst->getReplacementType()->getTypeClass();
+
+ switch (TC) {
+ case Type::Builtin:
+ case Type::Complex:
+ case Type::UnresolvedUsing:
+ case Type::Typedef:
+ case Type::TypeOfExpr:
+ case Type::TypeOf:
+ case Type::Decltype:
+ case Type::Record:
+ case Type::Enum:
+ case Type::Elaborated:
+ case Type::TemplateTypeParm:
+ case Type::SubstTemplateTypeParmPack:
+ case Type::TemplateSpecialization:
+ case Type::InjectedClassName:
+ case Type::DependentName:
+ case Type::DependentTemplateSpecialization:
+ case Type::ObjCObject:
+ case Type::ObjCInterface:
+ CanPrefixQualifiers = true;
+ break;
+
+ case Type::ObjCObjectPointer:
+ CanPrefixQualifiers = T->isObjCIdType() || T->isObjCClassType() ||
+ T->isObjCQualifiedIdType() || T->isObjCQualifiedClassType();
+ break;
+
+ case Type::Pointer:
+ case Type::BlockPointer:
+ case Type::LValueReference:
+ case Type::RValueReference:
+ case Type::MemberPointer:
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::DependentSizedArray:
+ case Type::DependentSizedExtVector:
+ case Type::Vector:
+ case Type::ExtVector:
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ case Type::Paren:
+ case Type::Attributed:
+ case Type::PackExpansion:
+ case Type::SubstTemplateTypeParm:
+ case Type::Auto:
+ CanPrefixQualifiers = false;
+ break;
+ }
+
+ if (!CanPrefixQualifiers && !Quals.empty()) {
+ std::string qualsBuffer;
+ Quals.getAsStringInternal(qualsBuffer, Policy);
- if (!S.empty()) {
- TQS += ' ';
- TQS += S;
+ if (!buffer.empty()) {
+ qualsBuffer += ' ';
+ qualsBuffer += buffer;
}
- std::swap(S, TQS);
+ std::swap(buffer, qualsBuffer);
}
switch (T->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, PARENT)
-#define TYPE(CLASS, PARENT) case Type::CLASS: \
- Print##CLASS(cast<CLASS##Type>(T.getTypePtr()), S); \
+#define TYPE(CLASS, PARENT) case Type::CLASS: \
+ print##CLASS(cast<CLASS##Type>(T), buffer); \
break;
#include "clang/AST/TypeNodes.def"
}
+
+ // If we're adding the qualifiers as a prefix, do it now.
+ if (CanPrefixQualifiers && !Quals.empty()) {
+ std::string qualsBuffer;
+ Quals.getAsStringInternal(qualsBuffer, Policy);
+
+ if (!buffer.empty()) {
+ qualsBuffer += ' ';
+ qualsBuffer += buffer;
+ }
+ std::swap(buffer, qualsBuffer);
+ }
}
-void TypePrinter::PrintBuiltin(const BuiltinType *T, std::string &S) {
+void TypePrinter::printBuiltin(const BuiltinType *T, std::string &S) {
if (S.empty()) {
S = T->getName(Policy.LangOpts);
} else {
@@ -96,12 +178,12 @@ void TypePrinter::PrintBuiltin(const BuiltinType *T, std::string &S) {
}
}
-void TypePrinter::PrintComplex(const ComplexType *T, std::string &S) {
- Print(T->getElementType(), S);
+void TypePrinter::printComplex(const ComplexType *T, std::string &S) {
+ print(T->getElementType(), S);
S = "_Complex " + S;
}
-void TypePrinter::PrintPointer(const PointerType *T, std::string &S) {
+void TypePrinter::printPointer(const PointerType *T, std::string &S) {
S = '*' + S;
// Handle things like 'int (*A)[4];' correctly.
@@ -109,15 +191,15 @@ void TypePrinter::PrintPointer(const PointerType *T, std::string &S) {
if (isa<ArrayType>(T->getPointeeType()))
S = '(' + S + ')';
- Print(T->getPointeeType(), S);
+ print(T->getPointeeType(), S);
}
-void TypePrinter::PrintBlockPointer(const BlockPointerType *T, std::string &S) {
+void TypePrinter::printBlockPointer(const BlockPointerType *T, std::string &S) {
S = '^' + S;
- Print(T->getPointeeType(), S);
+ print(T->getPointeeType(), S);
}
-void TypePrinter::PrintLValueReference(const LValueReferenceType *T,
+void TypePrinter::printLValueReference(const LValueReferenceType *T,
std::string &S) {
S = '&' + S;
@@ -126,10 +208,10 @@ void TypePrinter::PrintLValueReference(const LValueReferenceType *T,
if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
S = '(' + S + ')';
- Print(T->getPointeeTypeAsWritten(), S);
+ print(T->getPointeeTypeAsWritten(), S);
}
-void TypePrinter::PrintRValueReference(const RValueReferenceType *T,
+void TypePrinter::printRValueReference(const RValueReferenceType *T,
std::string &S) {
S = "&&" + S;
@@ -138,13 +220,13 @@ void TypePrinter::PrintRValueReference(const RValueReferenceType *T,
if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
S = '(' + S + ')';
- Print(T->getPointeeTypeAsWritten(), S);
+ print(T->getPointeeTypeAsWritten(), S);
}
-void TypePrinter::PrintMemberPointer(const MemberPointerType *T,
+void TypePrinter::printMemberPointer(const MemberPointerType *T,
std::string &S) {
std::string C;
- Print(QualType(T->getClass(), 0), C);
+ print(QualType(T->getClass(), 0), C);
C += "::*";
S = C + S;
@@ -153,25 +235,25 @@ void TypePrinter::PrintMemberPointer(const MemberPointerType *T,
if (isa<ArrayType>(T->getPointeeType()))
S = '(' + S + ')';
- Print(T->getPointeeType(), S);
+ print(T->getPointeeType(), S);
}
-void TypePrinter::PrintConstantArray(const ConstantArrayType *T,
+void TypePrinter::printConstantArray(const ConstantArrayType *T,
std::string &S) {
S += '[';
S += llvm::utostr(T->getSize().getZExtValue());
S += ']';
- Print(T->getElementType(), S);
+ print(T->getElementType(), S);
}
-void TypePrinter::PrintIncompleteArray(const IncompleteArrayType *T,
+void TypePrinter::printIncompleteArray(const IncompleteArrayType *T,
std::string &S) {
S += "[]";
- Print(T->getElementType(), S);
+ print(T->getElementType(), S);
}
-void TypePrinter::PrintVariableArray(const VariableArrayType *T,
+void TypePrinter::printVariableArray(const VariableArrayType *T,
std::string &S) {
S += '[';
@@ -193,10 +275,10 @@ void TypePrinter::PrintVariableArray(const VariableArrayType *T,
}
S += ']';
- Print(T->getElementType(), S);
+ print(T->getElementType(), S);
}
-void TypePrinter::PrintDependentSizedArray(const DependentSizedArrayType *T,
+void TypePrinter::printDependentSizedArray(const DependentSizedArrayType *T,
std::string &S) {
S += '[';
@@ -208,13 +290,13 @@ void TypePrinter::PrintDependentSizedArray(const DependentSizedArrayType *T,
}
S += ']';
- Print(T->getElementType(), S);
+ print(T->getElementType(), S);
}
-void TypePrinter::PrintDependentSizedExtVector(
+void TypePrinter::printDependentSizedExtVector(
const DependentSizedExtVectorType *T,
std::string &S) {
- Print(T->getElementType(), S);
+ print(T->getElementType(), S);
S += " __attribute__((ext_vector_type(";
if (T->getSizeExpr()) {
@@ -226,36 +308,52 @@ void TypePrinter::PrintDependentSizedExtVector(
S += ")))";
}
-void TypePrinter::PrintVector(const VectorType *T, std::string &S) {
- if (T->getAltiVecSpecific() != VectorType::NotAltiVec) {
- if (T->getAltiVecSpecific() == VectorType::Pixel)
- S = "__vector __pixel " + S;
- else {
- Print(T->getElementType(), S);
- S = ((T->getAltiVecSpecific() == VectorType::Bool)
- ? "__vector __bool " : "__vector ") + S;
- }
- } else {
+void TypePrinter::printVector(const VectorType *T, std::string &S) {
+ switch (T->getVectorKind()) {
+ case VectorType::AltiVecPixel:
+ S = "__vector __pixel " + S;
+ break;
+ case VectorType::AltiVecBool:
+ print(T->getElementType(), S);
+ S = "__vector __bool " + S;
+ break;
+ case VectorType::AltiVecVector:
+ print(T->getElementType(), S);
+ S = "__vector " + S;
+ break;
+ case VectorType::NeonVector:
+ print(T->getElementType(), S);
+ S = ("__attribute__((neon_vector_type(" +
+ llvm::utostr_32(T->getNumElements()) + "))) " + S);
+ break;
+ case VectorType::NeonPolyVector:
+ print(T->getElementType(), S);
+ S = ("__attribute__((neon_polyvector_type(" +
+ llvm::utostr_32(T->getNumElements()) + "))) " + S);
+ break;
+ case VectorType::GenericVector: {
// FIXME: We prefer to print the size directly here, but have no way
// to get the size of the type.
- Print(T->getElementType(), S);
+ print(T->getElementType(), S);
std::string V = "__attribute__((__vector_size__(";
V += llvm::utostr_32(T->getNumElements()); // convert back to bytes.
std::string ET;
- Print(T->getElementType(), ET);
+ print(T->getElementType(), ET);
V += " * sizeof(" + ET + ")))) ";
S = V + S;
+ break;
+ }
}
}
-void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) {
+void TypePrinter::printExtVector(const ExtVectorType *T, std::string &S) {
S += " __attribute__((ext_vector_type(";
S += llvm::utostr_32(T->getNumElements());
S += ")))";
- Print(T->getElementType(), S);
+ print(T->getElementType(), S);
}
-void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
+void TypePrinter::printFunctionProto(const FunctionProtoType *T,
std::string &S) {
// If needed for precedence reasons, wrap the inner part in grouping parens.
if (!S.empty())
@@ -267,7 +365,7 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
ParamPolicy.SuppressSpecifiers = false;
for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
if (i) S += ", ";
- Print(T->getArgType(i), Tmp);
+ print(T->getArgType(i), Tmp);
S += Tmp;
Tmp.clear();
}
@@ -309,6 +407,21 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += " __attribute__((regparm (" +
llvm::utostr_32(Info.getRegParm()) + ")))";
+ AppendTypeQualList(S, T->getTypeQuals());
+
+ switch (T->getRefQualifier()) {
+ case RQ_None:
+ break;
+
+ case RQ_LValue:
+ S += " &";
+ break;
+
+ case RQ_RValue:
+ S += " &&";
+ break;
+ }
+
if (T->hasExceptionSpec()) {
S += " throw(";
if (T->hasAnyExceptionSpec())
@@ -319,18 +432,16 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
S += ", ";
std::string ExceptionType;
- Print(T->getExceptionType(I), ExceptionType);
+ print(T->getExceptionType(I), ExceptionType);
S += ExceptionType;
}
S += ")";
}
- AppendTypeQualList(S, T->getTypeQuals());
-
- Print(T->getResultType(), S);
+ print(T->getResultType(), S);
}
-void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T,
+void TypePrinter::printFunctionNoProto(const FunctionNoProtoType *T,
std::string &S) {
// If needed for precedence reasons, wrap the inner part in grouping parens.
if (!S.empty())
@@ -339,10 +450,10 @@ void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T,
S += "()";
if (T->getNoReturnAttr())
S += " __attribute__((noreturn))";
- Print(T->getResultType(), S);
+ print(T->getResultType(), S);
}
-static void PrintTypeSpec(const NamedDecl *D, std::string &S) {
+static void printTypeSpec(const NamedDecl *D, std::string &S) {
IdentifierInfo *II = D->getIdentifier();
if (S.empty())
S = II->getName().str();
@@ -350,16 +461,16 @@ static void PrintTypeSpec(const NamedDecl *D, std::string &S) {
S = II->getName().str() + ' ' + S;
}
-void TypePrinter::PrintUnresolvedUsing(const UnresolvedUsingType *T,
+void TypePrinter::printUnresolvedUsing(const UnresolvedUsingType *T,
std::string &S) {
- PrintTypeSpec(T->getDecl(), S);
+ printTypeSpec(T->getDecl(), S);
}
-void TypePrinter::PrintTypedef(const TypedefType *T, std::string &S) {
- PrintTypeSpec(T->getDecl(), S);
+void TypePrinter::printTypedef(const TypedefType *T, std::string &S) {
+ printTypeSpec(T->getDecl(), S);
}
-void TypePrinter::PrintTypeOfExpr(const TypeOfExprType *T, std::string &S) {
+void TypePrinter::printTypeOfExpr(const TypeOfExprType *T, std::string &S) {
if (!S.empty()) // Prefix the basic type, e.g. 'typeof(e) X'.
S = ' ' + S;
std::string Str;
@@ -368,15 +479,15 @@ void TypePrinter::PrintTypeOfExpr(const TypeOfExprType *T, std::string &S) {
S = "typeof " + s.str() + S;
}
-void TypePrinter::PrintTypeOf(const TypeOfType *T, std::string &S) {
+void TypePrinter::printTypeOf(const TypeOfType *T, std::string &S) {
if (!S.empty()) // Prefix the basic type, e.g. 'typeof(t) X'.
S = ' ' + S;
std::string Tmp;
- Print(T->getUnderlyingType(), Tmp);
+ print(T->getUnderlyingType(), Tmp);
S = "typeof(" + Tmp + ")" + S;
}
-void TypePrinter::PrintDecltype(const DecltypeType *T, std::string &S) {
+void TypePrinter::printDecltype(const DecltypeType *T, std::string &S) {
if (!S.empty()) // Prefix the basic type, e.g. 'decltype(t) X'.
S = ' ' + S;
std::string Str;
@@ -385,6 +496,17 @@ void TypePrinter::PrintDecltype(const DecltypeType *T, std::string &S) {
S = "decltype(" + s.str() + ")" + S;
}
+void TypePrinter::printAuto(const AutoType *T, std::string &S) {
+ // If the type has been deduced, do not print 'auto'.
+ if (T->isDeduced()) {
+ print(T->getDeducedType(), S);
+ } else {
+ if (!S.empty()) // Prefix the basic type, e.g. 'auto X'.
+ S = ' ' + S;
+ S = "auto" + S;
+ }
+}
+
/// Appends the given scope to the end of a string.
void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
if (DC->isTranslationUnit()) return;
@@ -402,8 +524,8 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.getFlatArgumentList(),
- TemplateArgs.flat_size(),
+ TemplateArgs.data(),
+ TemplateArgs.size(),
Policy);
Buffer += Spec->getIdentifier()->getName();
Buffer += TemplateArgsStr;
@@ -418,7 +540,7 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) {
Buffer += "::";
}
-void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) {
+void TypePrinter::printTag(TagDecl *D, std::string &InnerString) {
if (Policy.SuppressTag)
return;
@@ -457,9 +579,9 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) {
if (!HasKindDecoration)
OS << " " << D->getKindName();
- if (D->getLocation().isValid()) {
- PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc(
+ PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc(
D->getLocation());
+ if (PLoc.isValid()) {
OS << " at " << PLoc.getFilename()
<< ':' << PLoc.getLine()
<< ':' << PLoc.getColumn();
@@ -482,8 +604,8 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) {
NumArgs = TST->getNumArgs();
} else {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- Args = TemplateArgs.getFlatArgumentList();
- NumArgs = TemplateArgs.flat_size();
+ Args = TemplateArgs.data();
+ NumArgs = TemplateArgs.size();
}
Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args,
NumArgs,
@@ -498,15 +620,15 @@ void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) {
std::swap(Buffer, InnerString);
}
-void TypePrinter::PrintRecord(const RecordType *T, std::string &S) {
- PrintTag(T->getDecl(), S);
+void TypePrinter::printRecord(const RecordType *T, std::string &S) {
+ printTag(T->getDecl(), S);
}
-void TypePrinter::PrintEnum(const EnumType *T, std::string &S) {
- PrintTag(T->getDecl(), S);
+void TypePrinter::printEnum(const EnumType *T, std::string &S) {
+ printTag(T->getDecl(), S);
}
-void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T,
+void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T,
std::string &S) {
if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'.
S = ' ' + S;
@@ -518,12 +640,18 @@ void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T,
S = T->getName()->getName().str() + S;
}
-void TypePrinter::PrintSubstTemplateTypeParm(const SubstTemplateTypeParmType *T,
+void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T,
std::string &S) {
- Print(T->getReplacementType(), S);
+ print(T->getReplacementType(), S);
}
-void TypePrinter::PrintTemplateSpecialization(
+void TypePrinter::printSubstTemplateTypeParmPack(
+ const SubstTemplateTypeParmPackType *T,
+ std::string &S) {
+ printTemplateTypeParm(T->getReplacedParameter(), S);
+}
+
+void TypePrinter::printTemplateSpecialization(
const TemplateSpecializationType *T,
std::string &S) {
std::string SpecString;
@@ -543,12 +671,12 @@ void TypePrinter::PrintTemplateSpecialization(
S = SpecString + ' ' + S;
}
-void TypePrinter::PrintInjectedClassName(const InjectedClassNameType *T,
+void TypePrinter::printInjectedClassName(const InjectedClassNameType *T,
std::string &S) {
- PrintTemplateSpecialization(T->getInjectedTST(), S);
+ printTemplateSpecialization(T->getInjectedTST(), S);
}
-void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) {
+void TypePrinter::printElaborated(const ElaboratedType *T, std::string &S) {
std::string MyString;
{
@@ -564,7 +692,7 @@ void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) {
std::string TypeStr;
PrintingPolicy InnerPolicy(Policy);
InnerPolicy.SuppressScope = true;
- TypePrinter(InnerPolicy).Print(T->getNamedType(), TypeStr);
+ TypePrinter(InnerPolicy).print(T->getNamedType(), TypeStr);
MyString += TypeStr;
if (S.empty())
@@ -573,7 +701,13 @@ void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) {
S = MyString + ' ' + S;
}
-void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S) {
+void TypePrinter::printParen(const ParenType *T, std::string &S) {
+ if (!S.empty() && !isa<FunctionType>(T->getInnerType()))
+ S = '(' + S + ')';
+ print(T->getInnerType(), S);
+}
+
+void TypePrinter::printDependentName(const DependentNameType *T, std::string &S) {
std::string MyString;
{
@@ -593,7 +727,7 @@ void TypePrinter::PrintDependentName(const DependentNameType *T, std::string &S)
S = MyString + ' ' + S;
}
-void TypePrinter::PrintDependentTemplateSpecialization(
+void TypePrinter::printDependentTemplateSpecialization(
const DependentTemplateSpecializationType *T, std::string &S) {
std::string MyString;
{
@@ -617,7 +751,91 @@ void TypePrinter::PrintDependentTemplateSpecialization(
S = MyString + ' ' + S;
}
-void TypePrinter::PrintObjCInterface(const ObjCInterfaceType *T,
+void TypePrinter::printPackExpansion(const PackExpansionType *T,
+ std::string &S) {
+ print(T->getPattern(), S);
+ S += "...";
+}
+
+void TypePrinter::printAttributed(const AttributedType *T,
+ std::string &S) {
+ print(T->getModifiedType(), S);
+
+ // TODO: not all attributes are GCC-style attributes.
+ S += "__attribute__((";
+ switch (T->getAttrKind()) {
+ case AttributedType::attr_address_space:
+ S += "address_space(";
+ S += T->getEquivalentType().getAddressSpace();
+ S += ")";
+ break;
+
+ case AttributedType::attr_vector_size: {
+ S += "__vector_size__(";
+ if (const VectorType *vector =T->getEquivalentType()->getAs<VectorType>()) {
+ S += vector->getNumElements();
+ S += " * sizeof(";
+
+ std::string tmp;
+ print(vector->getElementType(), tmp);
+ S += tmp;
+ S += ")";
+ }
+ S += ")";
+ break;
+ }
+
+ case AttributedType::attr_neon_vector_type:
+ case AttributedType::attr_neon_polyvector_type: {
+ if (T->getAttrKind() == AttributedType::attr_neon_vector_type)
+ S += "neon_vector_type(";
+ else
+ S += "neon_polyvector_type(";
+ const VectorType *vector = T->getEquivalentType()->getAs<VectorType>();
+ S += llvm::utostr_32(vector->getNumElements());
+ S += ")";
+ break;
+ }
+
+ case AttributedType::attr_regparm: {
+ S += "regparm(";
+ QualType t = T->getEquivalentType();
+ while (!t->isFunctionType())
+ t = t->getPointeeType();
+ S += t->getAs<FunctionType>()->getRegParmType();
+ S += ")";
+ break;
+ }
+
+ case AttributedType::attr_objc_gc: {
+ S += "objc_gc(";
+
+ QualType tmp = T->getEquivalentType();
+ while (tmp.getObjCGCAttr() == Qualifiers::GCNone) {
+ QualType next = tmp->getPointeeType();
+ if (next == tmp) break;
+ tmp = next;
+ }
+
+ if (tmp.isObjCGCWeak())
+ S += "weak";
+ else
+ S += "strong";
+ S += ")";
+ break;
+ }
+
+ case AttributedType::attr_noreturn: S += "noreturn"; break;
+ case AttributedType::attr_cdecl: S += "cdecl"; break;
+ case AttributedType::attr_fastcall: S += "fastcall"; break;
+ case AttributedType::attr_stdcall: S += "stdcall"; break;
+ case AttributedType::attr_thiscall: S += "thiscall"; break;
+ case AttributedType::attr_pascal: S += "pascal"; break;
+ }
+ S += "))";
+}
+
+void TypePrinter::printObjCInterface(const ObjCInterfaceType *T,
std::string &S) {
if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
S = ' ' + S;
@@ -626,13 +844,13 @@ void TypePrinter::PrintObjCInterface(const ObjCInterfaceType *T,
S = ObjCQIString + S;
}
-void TypePrinter::PrintObjCObject(const ObjCObjectType *T,
+void TypePrinter::printObjCObject(const ObjCObjectType *T,
std::string &S) {
if (T->qual_empty())
- return Print(T->getBaseType(), S);
+ return print(T->getBaseType(), S);
std::string tmp;
- Print(T->getBaseType(), tmp);
+ print(T->getBaseType(), tmp);
tmp += '<';
bool isFirst = true;
for (ObjCObjectType::qual_iterator
@@ -652,18 +870,23 @@ void TypePrinter::PrintObjCObject(const ObjCObjectType *T,
std::swap(tmp, S);
}
-void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T,
+void TypePrinter::printObjCObjectPointer(const ObjCObjectPointerType *T,
std::string &S) {
std::string ObjCQIString;
+ T->getPointeeType().getLocalQualifiers().getAsStringInternal(ObjCQIString,
+ Policy);
+ if (!ObjCQIString.empty())
+ ObjCQIString += ' ';
+
if (T->isObjCIdType() || T->isObjCQualifiedIdType())
- ObjCQIString = "id";
+ ObjCQIString += "id";
else if (T->isObjCClassType() || T->isObjCQualifiedClassType())
- ObjCQIString = "Class";
+ ObjCQIString += "Class";
else if (T->isObjCSelType())
- ObjCQIString = "SEL";
+ ObjCQIString += "SEL";
else
- ObjCQIString = T->getInterfaceDecl()->getNameAsString();
+ ObjCQIString += T->getInterfaceDecl()->getNameAsString();
if (!T->qual_empty()) {
ObjCQIString += '<';
@@ -677,9 +900,6 @@ void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T,
ObjCQIString += '>';
}
- T->getPointeeType().getLocalQualifiers().getAsStringInternal(ObjCQIString,
- Policy);
-
if (!T->isObjCIdType() && !T->isObjCQualifiedIdType())
ObjCQIString += " *"; // Don't forget the implicit pointer.
else if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
@@ -688,44 +908,6 @@ void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T,
S = ObjCQIString + S;
}
-static void PrintTemplateArgument(std::string &Buffer,
- const TemplateArgument &Arg,
- const PrintingPolicy &Policy) {
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- assert(false && "Null template argument");
- break;
-
- case TemplateArgument::Type:
- Arg.getAsType().getAsStringInternal(Buffer, Policy);
- break;
-
- case TemplateArgument::Declaration:
- Buffer = cast<NamedDecl>(Arg.getAsDecl())->getNameAsString();
- break;
-
- case TemplateArgument::Template: {
- llvm::raw_string_ostream s(Buffer);
- Arg.getAsTemplate().print(s, Policy);
- break;
- }
-
- case TemplateArgument::Integral:
- Buffer = Arg.getAsIntegral()->toString(10, true);
- break;
-
- case TemplateArgument::Expression: {
- llvm::raw_string_ostream s(Buffer);
- Arg.getAsExpr()->printPretty(s, 0, Policy);
- break;
- }
-
- case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
- break;
- }
-}
-
std::string TemplateSpecializationType::
PrintTemplateArgumentList(const TemplateArgumentListInfo &Args,
const PrintingPolicy &Policy) {
@@ -738,17 +920,27 @@ std::string
TemplateSpecializationType::PrintTemplateArgumentList(
const TemplateArgument *Args,
unsigned NumArgs,
- const PrintingPolicy &Policy) {
+ const PrintingPolicy &Policy,
+ bool SkipBrackets) {
std::string SpecString;
- SpecString += '<';
+ if (!SkipBrackets)
+ SpecString += '<';
+
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (Arg)
+ if (SpecString.size() > !SkipBrackets)
SpecString += ", ";
// Print the argument into a string.
std::string ArgString;
- PrintTemplateArgument(ArgString, Args[Arg], Policy);
-
+ if (Args[Arg].getKind() == TemplateArgument::Pack) {
+ ArgString = PrintTemplateArgumentList(Args[Arg].pack_begin(),
+ Args[Arg].pack_size(),
+ Policy, true);
+ } else {
+ llvm::raw_string_ostream ArgOut(ArgString);
+ Args[Arg].print(Policy, ArgOut);
+ }
+
// If this is the first argument and its string representation
// begins with the global scope specifier ('::foo'), add a space
// to avoid printing the diagraph '<:'.
@@ -761,10 +953,11 @@ TemplateSpecializationType::PrintTemplateArgumentList(
// If the last character of our string is '>', add another space to
// keep the two '>''s separate tokens. We don't *have* to do this in
// C++0x, but it's still good hygiene.
- if (SpecString[SpecString.size() - 1] == '>')
+ if (!SpecString.empty() && SpecString[SpecString.size() - 1] == '>')
SpecString += ' ';
- SpecString += '>';
+ if (!SkipBrackets)
+ SpecString += '>';
return SpecString;
}
@@ -776,12 +969,20 @@ PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs,
std::string SpecString;
SpecString += '<';
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (Arg)
+ if (SpecString.size() > 1)
SpecString += ", ";
// Print the argument into a string.
std::string ArgString;
- PrintTemplateArgument(ArgString, Args[Arg].getArgument(), Policy);
+ if (Args[Arg].getArgument().getKind() == TemplateArgument::Pack) {
+ ArgString = PrintTemplateArgumentList(
+ Args[Arg].getArgument().pack_begin(),
+ Args[Arg].getArgument().pack_size(),
+ Policy, true);
+ } else {
+ llvm::raw_string_ostream ArgOut(ArgString);
+ Args[Arg].getArgument().print(Policy, ArgOut);
+ }
// If this is the first argument and its string representation
// begins with the global scope specifier ('::foo'), add a space
@@ -847,15 +1048,15 @@ void Qualifiers::getAsStringInternal(std::string &S,
}
}
-std::string QualType::getAsString() const {
- std::string S;
- LangOptions LO;
- getAsStringInternal(S, PrintingPolicy(LO));
- return S;
+std::string QualType::getAsString(const Type *ty, Qualifiers qs) {
+ std::string buffer;
+ LangOptions options;
+ getAsStringInternal(ty, qs, buffer, PrintingPolicy(options));
+ return buffer;
}
-void QualType::getAsStringInternal(std::string &S,
- const PrintingPolicy &Policy) const {
- TypePrinter Printer(Policy);
- Printer.Print(*this, S);
+void QualType::getAsStringInternal(const Type *ty, Qualifiers qs,
+ std::string &buffer,
+ const PrintingPolicy &policy) {
+ TypePrinter(policy).print(ty, qs, buffer);
}
OpenPOWER on IntegriCloud