aboutsummaryrefslogtreecommitdiff
path: root/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST')
-rw-r--r--lib/AST/APValue.cpp4
-rw-r--r--lib/AST/ASTConsumer.cpp2
-rw-r--r--lib/AST/ASTContext.cpp767
-rw-r--r--lib/AST/ASTDiagnostic.cpp567
-rw-r--r--lib/AST/ASTDumper.cpp1996
-rw-r--r--lib/AST/ASTImporter.cpp163
-rw-r--r--lib/AST/AttrImpl.cpp4
-rw-r--r--lib/AST/CMakeLists.txt7
-rw-r--r--lib/AST/CXXABI.h6
-rw-r--r--lib/AST/CXXInheritance.cpp43
-rw-r--r--lib/AST/Comment.cpp40
-rw-r--r--lib/AST/CommentBriefParser.cpp2
-rw-r--r--lib/AST/CommentCommandTraits.cpp34
-rw-r--r--lib/AST/CommentDumper.cpp257
-rw-r--r--lib/AST/CommentLexer.cpp127
-rw-r--r--lib/AST/CommentParser.cpp66
-rw-r--r--lib/AST/CommentSema.cpp269
-rw-r--r--lib/AST/Decl.cpp1305
-rw-r--r--lib/AST/DeclBase.cpp141
-rw-r--r--lib/AST/DeclCXX.cpp828
-rw-r--r--lib/AST/DeclFriend.cpp21
-rw-r--r--lib/AST/DeclGroup.cpp2
-rw-r--r--lib/AST/DeclObjC.cpp428
-rw-r--r--lib/AST/DeclOpenMP.cpp60
-rw-r--r--lib/AST/DeclPrinter.cpp193
-rw-r--r--lib/AST/DeclTemplate.cpp61
-rw-r--r--lib/AST/DeclarationName.cpp15
-rw-r--r--lib/AST/DumpXML.cpp28
-rw-r--r--lib/AST/Expr.cpp168
-rw-r--r--lib/AST/ExprCXX.cpp76
-rw-r--r--lib/AST/ExprClassification.cpp37
-rw-r--r--lib/AST/ExprConstant.cpp306
-rw-r--r--lib/AST/ExternalASTSource.cpp4
-rw-r--r--lib/AST/InheritViz.cpp2
-rw-r--r--lib/AST/ItaniumCXXABI.cpp15
-rw-r--r--lib/AST/ItaniumMangle.cpp80
-rw-r--r--lib/AST/LambdaMangleContext.cpp9
-rw-r--r--lib/AST/Mangle.cpp2
-rw-r--r--lib/AST/MicrosoftCXXABI.cpp136
-rw-r--r--lib/AST/MicrosoftMangle.cpp218
-rw-r--r--lib/AST/NSAPI.cpp39
-rw-r--r--lib/AST/NestedNameSpecifier.cpp15
-rw-r--r--lib/AST/RawCommentList.cpp6
-rw-r--r--lib/AST/RecordLayout.cpp7
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp135
-rw-r--r--lib/AST/Stmt.cpp156
-rw-r--r--lib/AST/StmtDumper.cpp760
-rw-r--r--lib/AST/StmtPrinter.cpp214
-rw-r--r--lib/AST/TemplateBase.cpp21
-rw-r--r--lib/AST/TemplateName.cpp14
-rw-r--r--lib/AST/Type.cpp249
-rw-r--r--lib/AST/TypeLoc.cpp30
-rw-r--r--lib/AST/TypePrinter.cpp140
-rw-r--r--lib/AST/VTableBuilder.cpp126
54 files changed, 6661 insertions, 3740 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index 2d7c9bd7864a..98e825b3bafb 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -19,8 +19,8 @@
#include "clang/AST/Type.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
@@ -348,6 +348,8 @@ void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{
bool IsReference = Ty->isReferenceType();
QualType InnerTy
= IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType();
+ if (InnerTy.isNull())
+ InnerTy = Ty;
if (!hasLValuePath()) {
// No lvalue path: just print the offset.
diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp
index a4e17c03e4e3..55033b238c66 100644
--- a/lib/AST/ASTConsumer.cpp
+++ b/lib/AST/ASTConsumer.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/DeclGroup.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclGroup.h"
using namespace clang;
bool ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 74c68ae627ce..7245c0316082 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -12,28 +12,29 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "CXXABI.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/Comment.h"
#include "clang/AST/CommentCommandTraits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/TypeLoc.h"
#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/AST/Comment.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Capacity.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Capacity.h"
-#include "CXXABI.h"
#include <map>
using namespace clang;
@@ -84,6 +85,14 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const {
return NULL;
}
+ if (const ClassTemplateSpecializationDecl *CTSD =
+ dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+ TemplateSpecializationKind TSK = CTSD->getSpecializationKind();
+ if (TSK == TSK_ImplicitInstantiation ||
+ TSK == TSK_Undeclared)
+ return NULL;
+ }
+
if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return NULL;
@@ -364,10 +373,12 @@ static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod,
if (!ID)
return;
// Add redeclared method here.
- for (const ObjCCategoryDecl *ClsExtDecl = ID->getFirstClassExtension();
- ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) {
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = ID->known_extensions_begin(),
+ ExtEnd = ID->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
if (ObjCMethodDecl *RedeclaredMethod =
- ClsExtDecl->getMethod(ObjCMethod->getSelector(),
+ Ext->getMethod(ObjCMethod->getSelector(),
ObjCMethod->isInstanceMethod()))
Redeclared.push_back(RedeclaredMethod);
}
@@ -412,15 +423,26 @@ comments::FullComment *ASTContext::getCommentForDecl(
if (!RC) {
if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) {
SmallVector<const NamedDecl*, 8> Overridden;
- if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D))
+ const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D);
+ if (OMD && OMD->isPropertyAccessor())
+ if (const ObjCPropertyDecl *PDecl = OMD->findPropertyDecl())
+ if (comments::FullComment *FC = getCommentForDecl(PDecl, PP))
+ return cloneFullComment(FC, D);
+ if (OMD)
addRedeclaredMethods(OMD, Overridden);
getOverriddenMethods(dyn_cast<NamedDecl>(D), Overridden);
- for (unsigned i = 0, e = Overridden.size(); i < e; i++) {
- if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP)) {
- comments::FullComment *CFC = cloneFullComment(FC, D);
- return CFC;
- }
- }
+ for (unsigned i = 0, e = Overridden.size(); i < e; i++)
+ if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP))
+ return cloneFullComment(FC, D);
+ }
+ else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) {
+ // Attach any tag type's documentation to its typedef if latter
+ // does not have one of its own.
+ QualType QT = TD->getUnderlyingType();
+ if (const TagType *TT = QT->getAs<TagType>())
+ if (const Decl *TD = TT->getDecl())
+ if (comments::FullComment *FC = getCommentForDecl(TD, PP))
+ return cloneFullComment(FC, D);
}
return NULL;
}
@@ -571,12 +593,14 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
CXXABI *ASTContext::createCXXABI(const TargetInfo &T) {
if (!LangOpts.CPlusPlus) return 0;
- switch (T.getCXXABI()) {
- case CXXABI_ARM:
+ switch (T.getCXXABI().getKind()) {
+ case TargetCXXABI::GenericARM:
+ case TargetCXXABI::iOS:
return CreateARMCXXABI(*this);
- case CXXABI_Itanium:
+ case TargetCXXABI::GenericAArch64: // Same as Itanium at this level
+ case TargetCXXABI::GenericItanium:
return CreateItaniumCXXABI(*this);
- case CXXABI_Microsoft:
+ case TargetCXXABI::Microsoft:
return CreateMicrosoftCXXABI(*this);
}
llvm_unreachable("Invalid CXXABI type!");
@@ -630,9 +654,9 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
DeclarationNames(*this),
ExternalSource(0), Listener(0),
Comments(SM), CommentsLoaded(false),
- CommentCommandTraits(BumpAlloc),
+ CommentCommandTraits(BumpAlloc, LOpts.CommentOpts),
LastSDM(0, 0),
- UniqueBlockByRefTypeID(0)
+ UniqueBlockByRefTypeID(0)
{
if (size_reserve > 0) Types.reserve(size_reserve);
TUDecl = TranslationUnitDecl::Create(*this);
@@ -873,12 +897,26 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId);
InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass);
InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel);
+
+ if (LangOpts.OpenCL) {
+ InitBuiltinType(OCLImage1dTy, BuiltinType::OCLImage1d);
+ InitBuiltinType(OCLImage1dArrayTy, BuiltinType::OCLImage1dArray);
+ InitBuiltinType(OCLImage1dBufferTy, BuiltinType::OCLImage1dBuffer);
+ InitBuiltinType(OCLImage2dTy, BuiltinType::OCLImage2d);
+ InitBuiltinType(OCLImage2dArrayTy, BuiltinType::OCLImage2dArray);
+ InitBuiltinType(OCLImage3dTy, BuiltinType::OCLImage3d);
+
+ InitBuiltinType(OCLSamplerTy, BuiltinType::OCLSampler);
+ InitBuiltinType(OCLEventTy, BuiltinType::OCLEvent);
+ }
// Builtin type for __objc_yes and __objc_no
ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ?
SignedCharTy : BoolTy);
ObjCConstantStringType = QualType();
+
+ ObjCSuperType = QualType();
// void * type
VoidPtrTy = getPointerType(VoidTy);
@@ -1411,6 +1449,22 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
Width = Target->getPointerWidth(0);
Align = Target->getPointerAlign(0);
break;
+ case BuiltinType::OCLSampler:
+ // Samplers are modeled as integers.
+ Width = Target->getIntWidth();
+ Align = Target->getIntAlign();
+ break;
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ // Currently these types are pointers to opaque types.
+ Width = Target->getPointerWidth(0);
+ Align = Target->getPointerAlign(0);
+ break;
}
break;
case Type::ObjCObjectPointer:
@@ -1442,10 +1496,7 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::MemberPointer: {
const MemberPointerType *MPT = cast<MemberPointerType>(T);
- std::pair<uint64_t, unsigned> PtrDiffInfo =
- getTypeInfo(getPointerDiffType());
- Width = PtrDiffInfo.first * ABI->getMemberPointerSize(MPT);
- Align = PtrDiffInfo.second;
+ llvm::tie(Width, Align) = ABI->getMemberPointerWidthAndAlign(MPT);
break;
}
case Type::Complex: {
@@ -1548,18 +1599,21 @@ ASTContext::getTypeInfoImpl(const Type *T) const {
}
case Type::Atomic: {
+ // Start with the base type information.
std::pair<uint64_t, unsigned> Info
= getTypeInfo(cast<AtomicType>(T)->getValueType());
Width = Info.first;
Align = Info.second;
- if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth() &&
- llvm::isPowerOf2_64(Width)) {
- // We can potentially perform lock-free atomic operations for this
- // type; promote the alignment appropriately.
- // FIXME: We could potentially promote the width here as well...
- // is that worthwhile? (Non-struct atomic types generally have
- // power-of-two size anyway, but structs might not. Requires a bit
- // of implementation work to make sure we zero out the extra bits.)
+
+ // If the size of the type doesn't exceed the platform's max
+ // atomic promotion width, make the size and alignment more
+ // favorable to atomic operations:
+ if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth()) {
+ // Round the size up to a power of 2.
+ if (!llvm::isPowerOf2_64(Width))
+ Width = llvm::NextPowerOf2(Width);
+
+ // Set the alignment equal to the size.
Align = static_cast<unsigned>(Width);
}
}
@@ -1658,9 +1712,13 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
}
// Categories of this Interface.
- for (const ObjCCategoryDecl *CDeclChain = OI->getCategoryList();
- CDeclChain; CDeclChain = CDeclChain->getNextClassCategory())
- CollectInheritedProtocols(CDeclChain, Protocols);
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = OI->visible_categories_begin(),
+ CatEnd = OI->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ CollectInheritedProtocols(*Cat, Protocols);
+ }
+
if (ObjCInterfaceDecl *SD = OI->getSuperClass())
while (SD) {
CollectInheritedProtocols(SD, Protocols);
@@ -1690,10 +1748,13 @@ void ASTContext::CollectInheritedProtocols(const Decl *CDecl,
unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const {
unsigned count = 0;
// Count ivars declared in class extension.
- for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl;
- CDecl = CDecl->getNextClassExtension())
- count += CDecl->ivar_size();
-
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = OI->known_extensions_begin(),
+ ExtEnd = OI->known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ count += Ext->ivar_size();
+ }
+
// Count ivar defined in this class's implementation. This
// includes synthesized ivars.
if (ObjCImplementationDecl *ImplDecl = OI->getImplementation())
@@ -1750,12 +1811,16 @@ void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD,
ObjCImpls[CatD] = ImplD;
}
-ObjCInterfaceDecl *ASTContext::getObjContainingInterface(NamedDecl *ND) const {
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ND->getDeclContext()))
+const ObjCInterfaceDecl *ASTContext::getObjContainingInterface(
+ const NamedDecl *ND) const {
+ if (const ObjCInterfaceDecl *ID =
+ dyn_cast<ObjCInterfaceDecl>(ND->getDeclContext()))
return ID;
- if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ND->getDeclContext()))
+ if (const ObjCCategoryDecl *CD =
+ dyn_cast<ObjCCategoryDecl>(ND->getDeclContext()))
return CD->getClassInterface();
- if (ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(ND->getDeclContext()))
+ if (const ObjCImplDecl *IMD =
+ dyn_cast<ObjCImplDecl>(ND->getDeclContext()))
return IMD->getClassInterface();
return 0;
@@ -1906,8 +1971,10 @@ const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T,
const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = Info;
- Result = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ Result = getFunctionType(FPT->getResultType(),
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
}
return cast<FunctionType>(Result.getTypePtr());
@@ -2562,16 +2629,25 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy,
return QualType(New, 0);
}
+/// \brief Determine whether \p T is canonical as the result type of a function.
+static bool isCanonicalResultType(QualType T) {
+ return T.isCanonical() &&
+ (T.getObjCLifetime() == Qualifiers::OCL_None ||
+ T.getObjCLifetime() == Qualifiers::OCL_ExplicitNone);
+}
+
/// 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,
+ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray,
const FunctionProtoType::ExtProtoInfo &EPI) const {
+ size_t NumArgs = ArgArray.size();
+
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
- FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI, *this);
+ FunctionProtoType::Profile(ID, ResultTy, ArgArray.begin(), NumArgs, EPI,
+ *this);
void *InsertPos = 0;
if (FunctionProtoType *FTP =
@@ -2580,7 +2656,7 @@ ASTContext::getFunctionType(QualType ResultTy,
// Determine whether the type being created is already canonical or not.
bool isCanonical =
- EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical() &&
+ EPI.ExceptionSpecType == EST_None && isCanonicalResultType(ResultTy) &&
!EPI.HasTrailingReturn;
for (unsigned i = 0; i != NumArgs && isCanonical; ++i)
if (!ArgArray[i].isCanonicalAsParam())
@@ -2606,9 +2682,15 @@ ASTContext::getFunctionType(QualType ResultTy,
CanonicalEPI.ExtInfo
= CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv));
- Canonical = getFunctionType(getCanonicalType(ResultTy),
- CanonicalArgs.data(), NumArgs,
- CanonicalEPI);
+ // Result types do not have ARC lifetime qualifiers.
+ QualType CanResultTy = getCanonicalType(ResultTy);
+ if (ResultTy.getQualifiers().hasObjCLifetime()) {
+ Qualifiers Qs = CanResultTy.getQualifiers();
+ Qs.removeObjCLifetime();
+ CanResultTy = getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
+ }
+
+ Canonical = getFunctionType(CanResultTy, CanonicalArgs, CanonicalEPI);
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
@@ -2641,7 +2723,7 @@ ASTContext::getFunctionType(QualType ResultTy,
FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment);
FunctionProtoType::ExtProtoInfo newEPI = EPI;
newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv);
- new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI);
+ new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
@@ -2877,8 +2959,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name,
QualType TST = getTemplateSpecializationType(Name, Args, Underlying);
TypeSourceInfo *DI = CreateTypeSourceInfo(TST);
- TemplateSpecializationTypeLoc TL
- = cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc());
+ TemplateSpecializationTypeLoc TL =
+ DI->getTypeLoc().castAs<TemplateSpecializationTypeLoc>();
TL.setTemplateKeywordLoc(SourceLocation());
TL.setTemplateNameLoc(NameLoc);
TL.setLAngleLoc(Args.getLAngleLoc());
@@ -3154,7 +3236,7 @@ ASTContext::getDependentTemplateSpecializationType(
}
QualType ASTContext::getPackExpansionType(QualType Pattern,
- llvm::Optional<unsigned> NumExpansions) {
+ Optional<unsigned> NumExpansions) {
llvm::FoldingSetNodeID ID;
PackExpansionType::Profile(ID, Pattern, NumExpansions);
@@ -3528,6 +3610,14 @@ QualType ASTContext::getUnsignedWCharType() const {
return UnsignedIntTy;
}
+QualType ASTContext::getIntPtrType() const {
+ return getFromTargetType(Target->getIntPtrType());
+}
+
+QualType ASTContext::getUIntPtrType() const {
+ return getCorrespondingUnsignedType(getIntPtrType());
+}
+
/// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17)
/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9).
QualType ASTContext::getPointerDiffType() const {
@@ -3993,7 +4083,8 @@ ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const {
uint64_t ElementCount = 1;
do {
ElementCount *= CA->getSize().getZExtValue();
- CA = dyn_cast<ConstantArrayType>(CA->getElementType());
+ CA = dyn_cast_or_null<ConstantArrayType>(
+ CA->getElementType()->getAsArrayTypeUnsafe());
} while (CA);
return ElementCount;
}
@@ -4032,7 +4123,7 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size,
assert(Domain->isRealFloatingType() && "Unknown domain!");
switch (EltRank) {
- case HalfRank: llvm_unreachable("Half ranks are not valid here");
+ case HalfRank: return HalfTy;
case FloatRank: return FloatTy;
case DoubleRank: return DoubleTy;
case LongDoubleRank: return LongDoubleTy;
@@ -4159,8 +4250,8 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
// At this point, we should have a signed or unsigned integer type.
if (Promotable->isSignedIntegerType())
return IntTy;
- uint64_t PromotableSize = getTypeSize(Promotable);
- uint64_t IntSize = getTypeSize(IntTy);
+ uint64_t PromotableSize = getIntWidth(Promotable);
+ uint64_t IntSize = getIntWidth(IntTy);
assert(Promotable->isUnsignedIntegerType() && PromotableSize <= IntSize);
return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy;
}
@@ -4273,6 +4364,16 @@ QualType ASTContext::getCFConstantStringType() const {
return getTagDeclType(CFConstantStringTypeDecl);
}
+QualType ASTContext::getObjCSuperType() const {
+ if (ObjCSuperType.isNull()) {
+ RecordDecl *ObjCSuperTypeDecl =
+ CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get("objc_super"));
+ TUDecl->addDecl(ObjCSuperTypeDecl);
+ ObjCSuperType = getTagDeclType(ObjCSuperTypeDecl);
+ }
+ return ObjCSuperType;
+}
+
void ASTContext::setCFConstantStringType(QualType T) {
const RecordType *Rec = T->getAs<RecordType>();
assert(Rec && "Invalid CFConstantStringType");
@@ -4361,78 +4462,68 @@ QualType ASTContext::getBlockDescriptorExtendedType() const {
return getTagDeclType(BlockDescriptorExtendedType);
}
-bool ASTContext::BlockRequiresCopying(QualType Ty) const {
- if (Ty->isObjCRetainableType())
+/// BlockRequiresCopying - Returns true if byref variable "D" of type "Ty"
+/// requires copy/dispose. Note that this must match the logic
+/// in buildByrefHelpers.
+bool ASTContext::BlockRequiresCopying(QualType Ty,
+ const VarDecl *D) {
+ if (const CXXRecordDecl *record = Ty->getAsCXXRecordDecl()) {
+ const Expr *copyExpr = getBlockVarCopyInits(D);
+ if (!copyExpr && record->hasTrivialDestructor()) return false;
+
return true;
- if (getLangOpts().CPlusPlus) {
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- return RD->hasConstCopyConstructor();
-
+ }
+
+ if (!Ty->isObjCRetainableType()) return false;
+
+ Qualifiers qs = Ty.getQualifiers();
+
+ // If we have lifetime, that dominates.
+ if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) {
+ assert(getLangOpts().ObjCAutoRefCount);
+
+ switch (lifetime) {
+ case Qualifiers::OCL_None: llvm_unreachable("impossible");
+
+ // These are just bits as far as the runtime is concerned.
+ case Qualifiers::OCL_ExplicitNone:
+ case Qualifiers::OCL_Autoreleasing:
+ return false;
+
+ // Tell the runtime that this is ARC __weak, called by the
+ // byref routines.
+ case Qualifiers::OCL_Weak:
+ // ARC __strong __block variables need to be retained.
+ case Qualifiers::OCL_Strong:
+ return true;
}
+ llvm_unreachable("fell out of lifetime switch!");
}
- return false;
+ return (Ty->isBlockPointerType() || isObjCNSObjectType(Ty) ||
+ Ty->isObjCObjectPointerType());
}
-QualType
-ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const {
- // type = struct __Block_byref_1_X {
- // void *__isa;
- // struct __Block_byref_1_X *__forwarding;
- // unsigned int __flags;
- // unsigned int __size;
- // void *__copy_helper; // as needed
- // void *__destroy_help // as needed
- // int X;
- // } *
-
- bool HasCopyAndDispose = BlockRequiresCopying(Ty);
-
- // FIXME: Move up
- SmallString<36> Name;
- llvm::raw_svector_ostream(Name) << "__Block_byref_" <<
- ++UniqueBlockByRefTypeID << '_' << DeclName;
- RecordDecl *T;
- T = CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get(Name.str()));
- T->startDefinition();
- QualType Int32Ty = IntTy;
- assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported");
- QualType FieldTypes[] = {
- getPointerType(VoidPtrTy),
- getPointerType(getTagDeclType(T)),
- Int32Ty,
- Int32Ty,
- getPointerType(VoidPtrTy),
- getPointerType(VoidPtrTy),
- Ty
- };
-
- StringRef FieldNames[] = {
- "__isa",
- "__forwarding",
- "__flags",
- "__size",
- "__copy_helper",
- "__destroy_helper",
- DeclName,
- };
-
- for (size_t i = 0; i < 7; ++i) {
- if (!HasCopyAndDispose && i >=4 && i <= 5)
- continue;
- FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(),
- SourceLocation(),
- &Idents.get(FieldNames[i]),
- FieldTypes[i], /*TInfo=*/0,
- /*BitWidth=*/0, /*Mutable=*/false,
- ICIS_NoInit);
- Field->setAccess(AS_public);
- T->addDecl(Field);
- }
-
- T->completeDefinition();
-
- return getPointerType(getTagDeclType(T));
+bool ASTContext::getByrefLifetime(QualType Ty,
+ Qualifiers::ObjCLifetime &LifeTime,
+ bool &HasByrefExtendedLayout) const {
+
+ if (!getLangOpts().ObjC1 ||
+ getLangOpts().getGC() != LangOptions::NonGC)
+ return false;
+
+ HasByrefExtendedLayout = false;
+ if (Ty->isRecordType()) {
+ HasByrefExtendedLayout = true;
+ LifeTime = Qualifiers::OCL_None;
+ }
+ else if (getLangOpts().ObjCAutoRefCount)
+ LifeTime = Ty.getObjCLifetime();
+ // MRR.
+ else if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType())
+ LifeTime = Qualifiers::OCL_ExplicitNone;
+ else
+ LifeTime = Qualifiers::OCL_None;
+ return true;
}
TypedefDecl *ASTContext::getObjCInstanceTypeDecl() {
@@ -4793,17 +4884,19 @@ void ASTContext::getObjCEncodingForType(QualType T, std::string& S,
true /* outermost type */);
}
-static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) {
- switch (T->getAs<BuiltinType>()->getKind()) {
- default: llvm_unreachable("Unhandled builtin type kind");
+static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
+ BuiltinType::Kind kind) {
+ switch (kind) {
case BuiltinType::Void: return 'v';
case BuiltinType::Bool: return 'B';
case BuiltinType::Char_U:
case BuiltinType::UChar: return 'C';
+ case BuiltinType::Char16:
case BuiltinType::UShort: return 'S';
+ case BuiltinType::Char32:
case BuiltinType::UInt: return 'I';
case BuiltinType::ULong:
- return C->getIntWidth(T) == 32 ? 'L' : 'Q';
+ return C->getTargetInfo().getLongWidth() == 32 ? 'L' : 'Q';
case BuiltinType::UInt128: return 'T';
case BuiltinType::ULongLong: return 'Q';
case BuiltinType::Char_S:
@@ -4813,13 +4906,40 @@ static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) {
case BuiltinType::WChar_U:
case BuiltinType::Int: return 'i';
case BuiltinType::Long:
- return C->getIntWidth(T) == 32 ? 'l' : 'q';
+ return C->getTargetInfo().getLongWidth() == 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::NullPtr: return '*'; // like char*
+
+ case BuiltinType::Half:
+ // FIXME: potentially need @encodes for these!
+ return ' ';
+
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ llvm_unreachable("@encoding ObjC primitive type");
+
+ // OpenCL and placeholder types don't need @encodings.
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::Dependent:
+#define BUILTIN_TYPE(KIND, ID)
+#define PLACEHOLDER_TYPE(KIND, ID) \
+ case BuiltinType::KIND:
+#include "clang/AST/BuiltinTypes.def"
+ llvm_unreachable("invalid builtin type for @encode");
}
+ llvm_unreachable("invalid BuiltinType::Kind value");
}
static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) {
@@ -4830,7 +4950,8 @@ static char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) {
return 'i';
// The encoding of a fixed enum type matches its fixed underlying type.
- return ObjCEncodingForPrimitiveKind(C, Enum->getIntegerType());
+ const BuiltinType *BT = Enum->getIntegerType()->castAs<BuiltinType>();
+ return getObjCEncodingForPrimitiveKind(C, BT->getKind());
}
static void EncodeBitField(const ASTContext *Ctx, std::string& S,
@@ -4858,8 +4979,10 @@ static void EncodeBitField(const ASTContext *Ctx, std::string& S,
S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex()));
if (const EnumType *ET = T->getAs<EnumType>())
S += ObjCEncodingForEnumType(Ctx, ET);
- else
- S += ObjCEncodingForPrimitiveKind(Ctx, T);
+ else {
+ const BuiltinType *BT = T->castAs<BuiltinType>();
+ S += getObjCEncodingForPrimitiveKind(Ctx, BT->getKind());
+ }
}
S += llvm::utostr(FD->getBitWidthValue(*Ctx));
}
@@ -4873,33 +4996,52 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
bool EncodingProperty,
bool StructField,
bool EncodeBlockParameters,
- bool EncodeClassNames) const {
- if (T->getAs<BuiltinType>()) {
+ bool EncodeClassNames,
+ bool EncodePointerToObjCTypedef) const {
+ CanQualType CT = getCanonicalType(T);
+ switch (CT->getTypeClass()) {
+ case Type::Builtin:
+ case Type::Enum:
if (FD && FD->isBitField())
return EncodeBitField(this, S, T, FD);
- S += ObjCEncodingForPrimitiveKind(this, T);
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CT))
+ S += getObjCEncodingForPrimitiveKind(this, BT->getKind());
+ else
+ S += ObjCEncodingForEnumType(this, cast<EnumType>(CT));
return;
- }
- if (const ComplexType *CT = T->getAs<ComplexType>()) {
+ case Type::Complex: {
+ const ComplexType *CT = T->castAs<ComplexType>();
S += 'j';
getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false,
false);
return;
}
-
- // encoding for pointer or r3eference types.
- QualType PointeeTy;
- if (const PointerType *PT = T->getAs<PointerType>()) {
- if (PT->isObjCSelType()) {
- S += ':';
- return;
- }
- PointeeTy = PT->getPointeeType();
+
+ case Type::Atomic: {
+ const AtomicType *AT = T->castAs<AtomicType>();
+ S += 'A';
+ getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, 0,
+ false, false);
+ return;
}
- else if (const ReferenceType *RT = T->getAs<ReferenceType>())
- PointeeTy = RT->getPointeeType();
- if (!PointeeTy.isNull()) {
+
+ // encoding for pointer or reference types.
+ case Type::Pointer:
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ QualType PointeeTy;
+ if (isa<PointerType>(CT)) {
+ const PointerType *PT = T->castAs<PointerType>();
+ if (PT->isObjCSelType()) {
+ S += ':';
+ return;
+ }
+ PointeeTy = PT->getPointeeType();
+ } else {
+ PointeeTy = T->castAs<ReferenceType>()->getPointeeType();
+ }
+
bool isReadOnly = false;
// For historical/compatibility reasons, the read-only qualifier of the
// pointee gets emitted _before_ the '^'. The read-only qualifier of
@@ -4954,10 +5096,12 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
NULL);
return;
}
-
- if (const ArrayType *AT =
- // Ignore type qualifiers etc.
- dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray: {
+ const ArrayType *AT = cast<ArrayType>(CT);
+
if (isa<IncompleteArrayType>(AT) && !StructField) {
// Incomplete arrays are encoded as a pointer to the array element.
S += '^';
@@ -4986,13 +5130,13 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
- if (T->getAs<FunctionType>()) {
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
S += '?';
return;
- }
- if (const RecordType *RTy = T->getAs<RecordType>()) {
- RecordDecl *RDecl = RTy->getDecl();
+ case Type::Record: {
+ RecordDecl *RDecl = cast<RecordType>(CT)->getDecl();
S += RDecl->isUnion() ? '(' : '{';
// Anonymous structures print as '?'
if (const IdentifierInfo *II = RDecl->getIdentifier()) {
@@ -5000,13 +5144,11 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(RDecl)) {
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
+ llvm::raw_string_ostream OS(S);
+ TemplateSpecializationType::PrintTemplateArgumentList(OS,
TemplateArgs.data(),
TemplateArgs.size(),
(*this).getPrintingPolicy());
-
- S += TemplateArgsStr;
}
} else {
S += '?';
@@ -5043,19 +5185,12 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S += RDecl->isUnion() ? ')' : '}';
return;
}
-
- if (const EnumType *ET = T->getAs<EnumType>()) {
- if (FD && FD->isBitField())
- EncodeBitField(this, S, T, FD);
- else
- S += ObjCEncodingForEnumType(this, ET);
- return;
- }
- if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
+ case Type::BlockPointer: {
+ const BlockPointerType *BT = T->castAs<BlockPointerType>();
S += "@?"; // Unlike a pointer-to-function, which is "^?".
if (EncodeBlockParameters) {
- const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
+ const FunctionType *FT = BT->getPointeeType()->castAs<FunctionType>();
S += '<';
// Block return type
@@ -5089,11 +5224,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
return;
}
- // Ignore protocol qualifiers when mangling at this level.
- if (const ObjCObjectType *OT = T->getAs<ObjCObjectType>())
- T = OT->getBaseType();
+ case Type::ObjCObject:
+ case Type::ObjCInterface: {
+ // Ignore protocol qualifiers when mangling at this level.
+ T = T->castAs<ObjCObjectType>()->getBaseType();
- if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) {
+ // The assumption seems to be that this assert will succeed
+ // because nested levels will have filtered out 'id' and 'Class'.
+ const ObjCInterfaceType *OIT = T->castAs<ObjCInterfaceType>();
// @encode(class_name)
ObjCInterfaceDecl *OI = OIT->getDecl();
S += '{';
@@ -5107,13 +5245,16 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
if (Field->isBitField())
getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field);
else
- getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD);
+ getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD,
+ false, false, false, false, false,
+ EncodePointerToObjCTypedef);
}
S += '}';
return;
}
- if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) {
+ case Type::ObjCObjectPointer: {
+ const ObjCObjectPointerType *OPT = T->castAs<ObjCObjectPointerType>();
if (OPT->isObjCIdType()) {
S += '@';
return;
@@ -5148,14 +5289,17 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
QualType PointeeTy = OPT->getPointeeType();
if (!EncodingProperty &&
- isa<TypedefType>(PointeeTy.getTypePtr())) {
+ isa<TypedefType>(PointeeTy.getTypePtr()) &&
+ !EncodePointerToObjCTypedef) {
// Another historical/compatibility reason.
// We encode the underlying type which comes out as
// {...};
S += '^';
getObjCEncodingForTypeImpl(PointeeTy, S,
false, ExpandPointedToStructures,
- NULL);
+ NULL,
+ false, false, false, false, false,
+ /*EncodePointerToObjCTypedef*/true);
return;
}
@@ -5176,18 +5320,29 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
}
// gcc just blithely ignores member pointers.
- // TODO: maybe there should be a mangling for these
- if (T->getAs<MemberPointerType>())
+ // FIXME: we shoul do better than that. 'M' is available.
+ case Type::MemberPointer:
return;
- if (T->isVectorType()) {
+ case Type::Vector:
+ case Type::ExtVector:
// This matches gcc's encoding, even though technically it is
// insufficient.
// FIXME. We should do a better job than gcc.
return;
+
+#define ABSTRACT_TYPE(KIND, BASE)
+#define TYPE(KIND, BASE)
+#define DEPENDENT_TYPE(KIND, BASE) \
+ case Type::KIND:
+#define NON_CANONICAL_TYPE(KIND, BASE) \
+ case Type::KIND:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(KIND, BASE) \
+ case Type::KIND:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("@encode for dependent type!");
}
-
- llvm_unreachable("@encode for type not implemented!");
+ llvm_unreachable("bad type kind!");
}
void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
@@ -5426,6 +5581,85 @@ static TypedefDecl *CreateVoidPtrBuiltinVaListDecl(const ASTContext *Context) {
return VaListTypeDecl;
}
+static TypedefDecl *
+CreateAArch64ABIBuiltinVaListDecl(const ASTContext *Context) {
+ RecordDecl *VaListTagDecl;
+ if (Context->getLangOpts().CPlusPlus) {
+ // namespace std { struct __va_list {
+ NamespaceDecl *NS;
+ NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context),
+ Context->getTranslationUnitDecl(),
+ /*Inline*/false, SourceLocation(),
+ SourceLocation(), &Context->Idents.get("std"),
+ /*PrevDecl*/0);
+
+ VaListTagDecl = CXXRecordDecl::Create(*Context, TTK_Struct,
+ Context->getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("__va_list"));
+ VaListTagDecl->setDeclContext(NS);
+ } else {
+ // struct __va_list
+ VaListTagDecl = CreateRecordDecl(*Context, TTK_Struct,
+ Context->getTranslationUnitDecl(),
+ &Context->Idents.get("__va_list"));
+ }
+
+ VaListTagDecl->startDefinition();
+
+ const size_t NumFields = 5;
+ QualType FieldTypes[NumFields];
+ const char *FieldNames[NumFields];
+
+ // void *__stack;
+ FieldTypes[0] = Context->getPointerType(Context->VoidTy);
+ FieldNames[0] = "__stack";
+
+ // void *__gr_top;
+ FieldTypes[1] = Context->getPointerType(Context->VoidTy);
+ FieldNames[1] = "__gr_top";
+
+ // void *__vr_top;
+ FieldTypes[2] = Context->getPointerType(Context->VoidTy);
+ FieldNames[2] = "__vr_top";
+
+ // int __gr_offs;
+ FieldTypes[3] = Context->IntTy;
+ FieldNames[3] = "__gr_offs";
+
+ // int __vr_offs;
+ FieldTypes[4] = Context->IntTy;
+ FieldNames[4] = "__vr_offs";
+
+ // Create fields
+ for (unsigned i = 0; i < NumFields; ++i) {
+ FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context),
+ VaListTagDecl,
+ SourceLocation(),
+ SourceLocation(),
+ &Context->Idents.get(FieldNames[i]),
+ FieldTypes[i], /*TInfo=*/0,
+ /*BitWidth=*/0,
+ /*Mutable=*/false,
+ ICIS_NoInit);
+ Field->setAccess(AS_public);
+ VaListTagDecl->addDecl(Field);
+ }
+ VaListTagDecl->completeDefinition();
+ QualType VaListTagType = Context->getRecordType(VaListTagDecl);
+ Context->VaListTagTy = VaListTagType;
+
+ // } __builtin_va_list;
+ TypedefDecl *VaListTypedefDecl
+ = TypedefDecl::Create(const_cast<ASTContext &>(*Context),
+ Context->getTranslationUnitDecl(),
+ SourceLocation(), SourceLocation(),
+ &Context->Idents.get("__builtin_va_list"),
+ Context->getTrivialTypeSourceInfo(VaListTagType));
+
+ return VaListTypedefDecl;
+}
+
static TypedefDecl *CreatePowerABIBuiltinVaListDecl(const ASTContext *Context) {
// typedef struct __va_list_tag {
RecordDecl *VaListTagDecl;
@@ -5659,6 +5893,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context,
return CreateCharPtrBuiltinVaListDecl(Context);
case TargetInfo::VoidPtrBuiltinVaList:
return CreateVoidPtrBuiltinVaListDecl(Context);
+ case TargetInfo::AArch64ABIBuiltinVaList:
+ return CreateAArch64ABIBuiltinVaListDecl(Context);
case TargetInfo::PowerABIBuiltinVaList:
return CreatePowerABIBuiltinVaListDecl(Context);
case TargetInfo::X86_64ABIBuiltinVaList:
@@ -6496,14 +6732,14 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
if (lbaseInfo.getProducesResult() != rbaseInfo.getProducesResult())
return QualType();
- // functypes which return are preferred over those that do not.
- if (lbaseInfo.getNoReturn() && !rbaseInfo.getNoReturn())
- allLTypes = false;
- else if (!lbaseInfo.getNoReturn() && rbaseInfo.getNoReturn())
- allRTypes = false;
// FIXME: some uses, e.g. conditional exprs, really want this to be 'both'.
bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn();
+ if (lbaseInfo.getNoReturn() != NoReturn)
+ allLTypes = false;
+ if (rbaseInfo.getNoReturn() != NoReturn)
+ allRTypes = false;
+
FunctionType::ExtInfo einfo = lbaseInfo.withNoReturn(NoReturn);
if (lproto && rproto) { // two C99 style function prototypes
@@ -6557,7 +6793,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = lproto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType, types.begin(), types.size(), EPI);
+ return getFunctionType(retType, types, EPI);
}
if (lproto) allRTypes = false;
@@ -6594,8 +6830,10 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo();
EPI.ExtInfo = einfo;
- return getFunctionType(retType, proto->arg_type_begin(),
- proto->getNumArgs(), EPI);
+ return getFunctionType(retType,
+ ArrayRef<QualType>(proto->arg_type_begin(),
+ proto->getNumArgs()),
+ EPI);
}
if (allLTypes) return lhs;
@@ -6603,6 +6841,27 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs,
return getFunctionNoProtoType(retType, einfo);
}
+/// Given that we have an enum type and a non-enum type, try to merge them.
+static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET,
+ QualType other, bool isBlockReturnType) {
+ // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
+ // a signed integer type, or an unsigned integer type.
+ // Compatibility is based on the underlying type, not the promotion
+ // type.
+ QualType underlyingType = ET->getDecl()->getIntegerType();
+ if (underlyingType.isNull()) return QualType();
+ if (Context.hasSameType(underlyingType, other))
+ return other;
+
+ // In block return types, we're more permissive and accept any
+ // integral type of the same size.
+ if (isBlockReturnType && other->isIntegerType() &&
+ Context.getTypeSize(underlyingType) == Context.getTypeSize(other))
+ return other;
+
+ return QualType();
+}
+
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
bool OfBlockPointer,
bool Unqualified, bool BlockReturnType) {
@@ -6684,19 +6943,13 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS,
// If the canonical type classes don't match.
if (LHSClass != RHSClass) {
- // C99 6.7.2.2p4: Each enumerated type shall be compatible with char,
- // a signed integer type, or an unsigned integer type.
- // Compatibility is based on the underlying type, not the promotion
- // type.
+ // Note that we only have special rules for turning block enum
+ // returns into block int returns, not vice-versa.
if (const EnumType* ETy = LHS->getAs<EnumType>()) {
- QualType TINT = ETy->getDecl()->getIntegerType();
- if (!TINT.isNull() && hasSameType(TINT, RHSCan.getUnqualifiedType()))
- return RHS;
+ return mergeEnumWithInteger(*this, ETy, RHS, false);
}
if (const EnumType* ETy = RHS->getAs<EnumType>()) {
- QualType TINT = ETy->getDecl()->getIntegerType();
- if (!TINT.isNull() && hasSameType(TINT, LHSCan.getUnqualifiedType()))
- return LHS;
+ return mergeEnumWithInteger(*this, ETy, LHS, BlockReturnType);
}
// allow block pointer type to match an 'id' type.
if (OfBlockPointer && !BlockReturnType) {
@@ -6928,8 +7181,10 @@ QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.ExtInfo = getFunctionExtInfo(LHS);
QualType ResultType
- = getFunctionType(OldReturnType, FPT->arg_type_begin(),
- FPT->getNumArgs(), EPI);
+ = getFunctionType(OldReturnType,
+ ArrayRef<QualType>(FPT->arg_type_begin(),
+ FPT->getNumArgs()),
+ EPI);
return ResultType;
}
}
@@ -7137,6 +7392,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context,
case 'H':
Type = Context.getObjCSelType();
break;
+ case 'M':
+ Type = Context.getObjCSuperType();
+ break;
case 'a':
Type = Context.getBuiltinVaListType();
assert(!Type.isNull() && "builtin va list type not initialized!");
@@ -7318,7 +7576,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
EPI.ExtInfo = EI;
EPI.Variadic = Variadic;
- return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), EPI);
+ return getFunctionType(ResType, ArgTypes, EPI);
}
GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
@@ -7383,9 +7641,6 @@ GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
TSK = VD->getTemplateSpecializationKind();
Linkage L = VD->getLinkage();
- if (L == ExternalLinkage && getLangOpts().CPlusPlus &&
- VD->getType()->getLinkage() == UniqueExternalLinkage)
- L = UniqueExternalLinkage;
switch (L) {
case NoLinkage:
@@ -7418,7 +7673,15 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
return false;
- } else if (!isa<FunctionDecl>(D))
+ } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // We never need to emit an uninstantiated function template.
+ if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate)
+ return false;
+ } else
+ return false;
+
+ // If this is a member of a class template, we do not need to emit it.
+ if (D->getDeclContext()->isDependentContext())
return false;
// Weak references don't produce any output by themselves.
@@ -7438,13 +7701,16 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
return true;
- // The key function for a class is required.
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
- const CXXRecordDecl *RD = MD->getParent();
- if (MD->isOutOfLine() && RD->isDynamicClass()) {
- const CXXMethodDecl *KeyFunc = getKeyFunction(RD);
- if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
- return true;
+ // The key function for a class is required. This rule only comes
+ // into play when inline functions can be key functions, though.
+ if (getTargetInfo().getCXXABI().canKeyFunctionBeInline()) {
+ if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ const CXXRecordDecl *RD = MD->getParent();
+ if (MD->isOutOfLine() && RD->isDynamicClass()) {
+ const CXXMethodDecl *KeyFunc = getCurrentKeyFunction(RD);
+ if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl())
+ return true;
+ }
}
}
@@ -7465,27 +7731,20 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly)
return false;
- // Structs that have non-trivial constructors or destructors are required.
+ // Variables that can be needed in other TUs are required.
+ GVALinkage L = GetGVALinkageForVariable(VD);
+ if (L != GVA_Internal && L != GVA_TemplateInstantiation)
+ return true;
- // FIXME: Handle references.
- // FIXME: Be more selective about which constructors we care about.
- if (const RecordType *RT = VD->getType()->getAs<RecordType>()) {
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- if (RD->hasDefinition() && !(RD->hasTrivialDefaultConstructor() &&
- RD->hasTrivialCopyConstructor() &&
- RD->hasTrivialMoveConstructor() &&
- RD->hasTrivialDestructor()))
- return true;
- }
- }
+ // Variables that have destruction with side-effects are required.
+ if (VD->getType().isDestructedType())
+ return true;
- GVALinkage L = GetGVALinkageForVariable(VD);
- if (L == GVA_Internal || L == GVA_TemplateInstantiation) {
- if (!(VD->getInit() && VD->getInit()->HasSideEffects(*this)))
- return false;
- }
+ // Variables that have initialization with side-effects are required.
+ if (VD->getInit() && VD->getInit()->HasSideEffects(*this))
+ return true;
- return true;
+ return false;
}
CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
@@ -7494,7 +7753,8 @@ CallingConv ASTContext::getDefaultCXXMethodCallConv(bool isVariadic) {
}
CallingConv ASTContext::getCanonicalCallConv(CallingConv CC) const {
- if (CC == CC_C && !LangOpts.MRTD && getTargetInfo().getCXXABI() != CXXABI_Microsoft)
+ if (CC == CC_C && !LangOpts.MRTD &&
+ getTargetInfo().getCXXABI().isMemberFunctionCCDefault())
return CC_Default;
return CC;
}
@@ -7505,11 +7765,13 @@ bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const {
}
MangleContext *ASTContext::createMangleContext() {
- switch (Target->getCXXABI()) {
- case CXXABI_ARM:
- case CXXABI_Itanium:
+ switch (Target->getCXXABI().getKind()) {
+ case TargetCXXABI::GenericAArch64:
+ case TargetCXXABI::GenericItanium:
+ case TargetCXXABI::GenericARM:
+ case TargetCXXABI::iOS:
return createItaniumMangleContext(*this, getDiagnostics());
- case CXXABI_Microsoft:
+ case TargetCXXABI::Microsoft:
return createMicrosoftMangleContext(*this, getDiagnostics());
}
llvm_unreachable("Unsupported ABI");
@@ -7534,6 +7796,23 @@ size_t ASTContext::getSideTableAllocatedMemory() const {
+ llvm::capacity_in_bytes(ClassScopeSpecializationPattern);
}
+void ASTContext::addUnnamedTag(const TagDecl *Tag) {
+ // FIXME: This mangling should be applied to function local classes too
+ if (!Tag->getName().empty() || Tag->getTypedefNameForAnonDecl() ||
+ !isa<CXXRecordDecl>(Tag->getParent()) || Tag->getLinkage() != ExternalLinkage)
+ return;
+
+ std::pair<llvm::DenseMap<const DeclContext *, unsigned>::iterator, bool> P =
+ UnnamedMangleContexts.insert(std::make_pair(Tag->getParent(), 0));
+ UnnamedMangleNumbers.insert(std::make_pair(Tag, P.first->second++));
+}
+
+int ASTContext::getUnnamedTagManglingNumber(const TagDecl *Tag) const {
+ llvm::DenseMap<const TagDecl *, unsigned>::const_iterator I =
+ UnnamedMangleNumbers.find(Tag);
+ return I != UnnamedMangleNumbers.end() ? I->second : -1;
+}
+
unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) {
CXXRecordDecl *Lambda = CallOperator->getParent();
return LambdaMangleContexts[Lambda->getDeclContext()]
diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp
index 0b9c5249448f..1ed65e476ce3 100644
--- a/lib/AST/ASTDiagnostic.cpp
+++ b/lib/AST/ASTDiagnostic.cpp
@@ -11,12 +11,11 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTDiagnostic.h"
-
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/AST/TemplateBase.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/TemplateBase.h"
#include "clang/AST/Type.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
@@ -232,7 +231,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType,
QualType ToType, bool PrintTree,
bool PrintFromType, bool ElideType,
- bool ShowColors, std::string &S);
+ bool ShowColors, raw_ostream &OS);
void clang::FormatASTNodeDiagnosticArgument(
DiagnosticsEngine::ArgumentKind Kind,
@@ -248,7 +247,8 @@ void clang::FormatASTNodeDiagnosticArgument(
ArrayRef<intptr_t> QualTypeVals) {
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
- std::string S;
+ size_t OldEnd = Output.size();
+ llvm::raw_svector_ostream OS(Output);
bool NeedQuotes = true;
switch (Kind) {
@@ -262,7 +262,7 @@ void clang::FormatASTNodeDiagnosticArgument(
if (FormatTemplateTypeDiff(Context, FromType, ToType, TDT.PrintTree,
TDT.PrintFromType, TDT.ElideType,
- TDT.ShowColors, S)) {
+ TDT.ShowColors, OS)) {
NeedQuotes = !TDT.PrintTree;
TDT.TemplateDiffUsed = true;
break;
@@ -273,7 +273,7 @@ void clang::FormatASTNodeDiagnosticArgument(
if (TDT.PrintTree)
return;
- // Attempting to do a templete diff on non-templates. Set the variables
+ // Attempting to do a template diff on non-templates. Set the variables
// and continue with regular type printing of the appropriate type.
Val = TDT.PrintFromType ? TDT.FromType : TDT.ToType;
ModLen = 0;
@@ -285,23 +285,23 @@ void clang::FormatASTNodeDiagnosticArgument(
"Invalid modifier for QualType argument");
QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
- S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs,
- QualTypeVals);
+ OS << ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs,
+ QualTypeVals);
NeedQuotes = false;
break;
}
case DiagnosticsEngine::ak_declarationname: {
- DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
- S = N.getAsString();
-
if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
- S = '+' + S;
+ OS << '+';
else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12)
&& ArgLen==0)
- S = '-' + S;
+ OS << '-';
else
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for DeclarationName argument");
+
+ DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
+ N.printName(OS);
break;
}
case DiagnosticsEngine::ak_nameddecl: {
@@ -314,13 +314,12 @@ void clang::FormatASTNodeDiagnosticArgument(
Qualified = false;
}
const NamedDecl *ND = reinterpret_cast<const NamedDecl*>(Val);
- ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), Qualified);
+ ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), Qualified);
break;
}
case DiagnosticsEngine::ak_nestednamespec: {
- llvm::raw_string_ostream OS(S);
- reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
- Context.getPrintingPolicy());
+ NestedNameSpecifier *NNS = reinterpret_cast<NestedNameSpecifier*>(Val);
+ NNS->print(OS, Context.getPrintingPolicy());
NeedQuotes = false;
break;
}
@@ -331,39 +330,39 @@ void clang::FormatASTNodeDiagnosticArgument(
if (DC->isTranslationUnit()) {
// FIXME: Get these strings from some localized place
if (Context.getLangOpts().CPlusPlus)
- S = "the global namespace";
+ OS << "the global namespace";
else
- S = "the global scope";
+ OS << "the global scope";
} else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
- S = ConvertTypeToDiagnosticString(Context,
- Context.getTypeDeclType(Type),
- PrevArgs, NumPrevArgs, QualTypeVals);
+ OS << ConvertTypeToDiagnosticString(Context,
+ Context.getTypeDeclType(Type),
+ PrevArgs, NumPrevArgs,
+ QualTypeVals);
} else {
// FIXME: Get these strings from some localized place
NamedDecl *ND = cast<NamedDecl>(DC);
if (isa<NamespaceDecl>(ND))
- S += "namespace ";
+ OS << "namespace ";
else if (isa<ObjCMethodDecl>(ND))
- S += "method ";
+ OS << "method ";
else if (isa<FunctionDecl>(ND))
- S += "function ";
-
- S += "'";
- ND->getNameForDiagnostic(S, Context.getPrintingPolicy(), true);
- S += "'";
+ OS << "function ";
+
+ OS << '\'';
+ ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), true);
+ OS << '\'';
}
NeedQuotes = false;
break;
}
}
-
- if (NeedQuotes)
- Output.push_back('\'');
-
- Output.append(S.begin(), S.end());
-
- if (NeedQuotes)
+
+ OS.flush();
+
+ if (NeedQuotes) {
+ Output.insert(Output.begin()+OldEnd, '\'');
Output.push_back('\'');
+ }
}
/// TemplateDiff - A class that constructs a pretty string for a pair of
@@ -396,21 +395,39 @@ class TemplateDiff {
/// will this type be outputed.
QualType ToType;
- /// Str - Storage for the output stream.
- llvm::SmallString<128> Str;
-
/// OS - The stream used to construct the output strings.
- llvm::raw_svector_ostream OS;
+ raw_ostream &OS;
/// IsBold - Keeps track of the bold formatting for the output string.
bool IsBold;
/// DiffTree - A tree representation the differences between two types.
class DiffTree {
+ public:
+ /// DiffKind - The difference in a DiffNode and which fields are used.
+ enum DiffKind {
+ /// Incomplete or invalid node.
+ Invalid,
+ /// Another level of templates, uses TemplateDecl and Qualifiers
+ Template,
+ /// Type difference, uses QualType
+ Type,
+ /// Expression difference, uses Expr
+ Expression,
+ /// Template argument difference, uses TemplateDecl
+ TemplateTemplate,
+ /// Integer difference, uses APSInt and Expr
+ Integer,
+ /// Declaration difference, uses ValueDecl
+ Declaration
+ };
+ private:
/// DiffNode - The root node stores the original type. Each child node
/// stores template arguments of their parents. For templated types, the
/// template decl is also stored.
struct DiffNode {
+ DiffKind Kind;
+
/// NextNode - The index of the next sibling node or 0.
unsigned NextNode;
@@ -439,6 +456,9 @@ class TemplateDiff {
/// IsValidFromInt, IsValidToInt - Whether the APSInt's are valid.
bool IsValidFromInt, IsValidToInt;
+ /// FromValueDecl, ToValueDecl - Whether the argument is a decl.
+ ValueDecl *FromValueDecl, *ToValueDecl;
+
/// FromDefault, ToDefault - Whether the argument is a default argument.
bool FromDefault, ToDefault;
@@ -446,13 +466,14 @@ class TemplateDiff {
bool Same;
DiffNode(unsigned ParentNode = 0)
- : NextNode(0), ChildNode(0), ParentNode(ParentNode),
+ : Kind(Invalid), NextNode(0), ChildNode(0), ParentNode(ParentNode),
FromType(), ToType(), FromExpr(0), ToExpr(0), FromTD(0), ToTD(0),
- FromDefault(false), ToDefault(false), Same(false) { }
+ IsValidFromInt(false), IsValidToInt(false), FromValueDecl(0),
+ ToValueDecl(0), FromDefault(false), ToDefault(false), Same(false) { }
};
/// FlatTree - A flattened tree used to store the DiffNodes.
- llvm::SmallVector<DiffNode, 16> FlatTree;
+ SmallVector<DiffNode, 16> FlatTree;
/// CurrentNode - The index of the current node being used.
unsigned CurrentNode;
@@ -504,6 +525,12 @@ class TemplateDiff {
FlatTree[CurrentNode].ToQual = ToQual;
}
+ /// SetNode - Set FromValueDecl and ToValueDecl of the current node.
+ void SetNode(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl) {
+ FlatTree[CurrentNode].FromValueDecl = FromValueDecl;
+ FlatTree[CurrentNode].ToValueDecl = ToValueDecl;
+ }
+
/// SetSame - Sets the same flag of the current node.
void SetSame(bool Same) {
FlatTree[CurrentNode].Same = Same;
@@ -515,6 +542,11 @@ class TemplateDiff {
FlatTree[CurrentNode].ToDefault = ToDefault;
}
+ /// SetKind - Sets the current node's type.
+ void SetKind(DiffKind Kind) {
+ FlatTree[CurrentNode].Kind = Kind;
+ }
+
/// Up - Changes the node to the parent of the current node.
void Up() {
CurrentNode = FlatTree[CurrentNode].ParentNode;
@@ -554,39 +586,6 @@ class TemplateDiff {
ReadNode = FlatTree[ReadNode].ParentNode;
}
- /// NodeIsTemplate - Returns true if a template decl is set, and types are
- /// set.
- bool NodeIsTemplate() {
- return (FlatTree[ReadNode].FromTD &&
- !FlatTree[ReadNode].ToType.isNull()) ||
- (FlatTree[ReadNode].ToTD && !FlatTree[ReadNode].ToType.isNull());
- }
-
- /// NodeIsQualType - Returns true if a Qualtype is set.
- bool NodeIsQualType() {
- return !FlatTree[ReadNode].FromType.isNull() ||
- !FlatTree[ReadNode].ToType.isNull();
- }
-
- /// NodeIsExpr - Returns true if an expr is set.
- bool NodeIsExpr() {
- return FlatTree[ReadNode].FromExpr || FlatTree[ReadNode].ToExpr;
- }
-
- /// NodeIsTemplateTemplate - Returns true if the argument is a template
- /// template type.
- bool NodeIsTemplateTemplate() {
- return FlatTree[ReadNode].FromType.isNull() &&
- FlatTree[ReadNode].ToType.isNull() &&
- (FlatTree[ReadNode].FromTD || FlatTree[ReadNode].ToTD);
- }
-
- /// NodeIsAPSInt - Returns true if the arugments are stored in APSInt's.
- bool NodeIsAPSInt() {
- return FlatTree[ReadNode].IsValidFromInt ||
- FlatTree[ReadNode].IsValidToInt;
- }
-
/// GetNode - Gets the FromType and ToType.
void GetNode(QualType &FromType, QualType &ToType) {
FromType = FlatTree[ReadNode].FromType;
@@ -620,6 +619,12 @@ class TemplateDiff {
ToQual = FlatTree[ReadNode].ToQual;
}
+ /// GetNode - Gets the FromValueDecl and ToValueDecl.
+ void GetNode(ValueDecl *&FromValueDecl, ValueDecl *&ToValueDecl) {
+ FromValueDecl = FlatTree[ReadNode].FromValueDecl;
+ ToValueDecl = FlatTree[ReadNode].ToValueDecl;
+ }
+
/// NodeIsSame - Returns true the arguments are the same.
bool NodeIsSame() {
return FlatTree[ReadNode].Same;
@@ -662,9 +667,12 @@ class TemplateDiff {
/// Empty - Returns true if the tree has no information.
bool Empty() {
- return !FlatTree[0].FromTD && !FlatTree[0].ToTD &&
- !FlatTree[0].FromExpr && !FlatTree[0].ToExpr &&
- FlatTree[0].FromType.isNull() && FlatTree[0].ToType.isNull();
+ return GetKind() == Invalid;
+ }
+
+ /// GetKind - Returns the current node's type.
+ DiffKind GetKind() {
+ return FlatTree[ReadNode].Kind;
}
};
@@ -681,6 +689,10 @@ class TemplateDiff {
/// traverse over.
const TemplateSpecializationType *TST;
+ /// DesugarTST - desugared template specialization used to extract
+ /// default argument information
+ const TemplateSpecializationType *DesugarTST;
+
/// Index - the index of the template argument in TST.
unsigned Index;
@@ -693,8 +705,10 @@ class TemplateDiff {
/// TSTiterator - Constructs an iterator and sets it to the first template
/// argument.
- TSTiterator(const TemplateSpecializationType *TST)
- : TST(TST), Index(0), CurrentTA(0), EndTA(0) {
+ TSTiterator(ASTContext &Context, const TemplateSpecializationType *TST)
+ : TST(TST),
+ DesugarTST(GetTemplateSpecializationType(Context, TST->desugar())),
+ Index(0), CurrentTA(0), EndTA(0) {
if (isEnd()) return;
// Set to first template argument. If not a parameter pack, done.
@@ -715,12 +729,17 @@ class TemplateDiff {
/// isEnd - Returns true if the iterator is one past the end.
bool isEnd() const {
- return Index == TST->getNumArgs();
+ return Index >= TST->getNumArgs();
}
/// &operator++ - Increment the iterator to the next template argument.
TSTiterator &operator++() {
- assert(!isEnd() && "Iterator incremented past end of arguments.");
+ // After the end, Index should be the default argument position in
+ // DesugarTST, if it exists.
+ if (isEnd()) {
+ ++Index;
+ return *this;
+ }
// If in a parameter pack, advance in the parameter pack.
if (CurrentTA != EndTA) {
@@ -761,6 +780,11 @@ class TemplateDiff {
pointer operator->() const {
return &operator*();
}
+
+ /// getDesugar - Returns the deduced template argument from DesguarTST
+ reference getDesugar() const {
+ return DesugarTST->getArg(Index);
+ }
};
// These functions build up the template diff tree, including functions to
@@ -787,7 +811,7 @@ class TemplateDiff {
TemplateName(CTSD->getSpecializedTemplate()),
CTSD->getTemplateArgs().data(),
CTSD->getTemplateArgs().size(),
- Ty.getCanonicalType());
+ Ty.getLocalUnqualifiedType().getCanonicalType());
return Ty->getAs<TemplateSpecializationType>();
}
@@ -800,7 +824,7 @@ class TemplateDiff {
TemplateParameterList *Params =
FromTST->getTemplateName().getAsTemplateDecl()->getTemplateParameters();
unsigned TotalArgs = 0;
- for (TSTiterator FromIter(FromTST), ToIter(ToTST);
+ for (TSTiterator FromIter(Context, FromTST), ToIter(Context, ToTST);
!FromIter.isEnd() || !ToIter.isEnd(); ++TotalArgs) {
Tree.AddNode();
@@ -814,11 +838,12 @@ class TemplateDiff {
if (TemplateTypeParmDecl *DefaultTTPD =
dyn_cast<TemplateTypeParmDecl>(ParamND)) {
QualType FromType, ToType;
- GetType(FromIter, DefaultTTPD, FromType);
- GetType(ToIter, DefaultTTPD, ToType);
+ FromType = GetType(FromIter, DefaultTTPD);
+ ToType = GetType(ToIter, DefaultTTPD);
Tree.SetNode(FromType, ToType);
Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(),
ToIter.isEnd() && !ToType.isNull());
+ Tree.SetKind(DiffTree::Type);
if (!FromType.isNull() && !ToType.isNull()) {
if (Context.hasSameType(FromType, ToType)) {
Tree.SetSame(true);
@@ -837,6 +862,7 @@ class TemplateDiff {
Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(),
ToArgTST->getTemplateName().getAsTemplateDecl());
Tree.SetNode(FromQual, ToQual);
+ Tree.SetKind(DiffTree::Template);
DiffTemplate(FromArgTST, ToArgTST);
}
}
@@ -846,41 +872,83 @@ class TemplateDiff {
// Handle Expressions
if (NonTypeTemplateParmDecl *DefaultNTTPD =
dyn_cast<NonTypeTemplateParmDecl>(ParamND)) {
- Expr *FromExpr, *ToExpr;
+ Expr *FromExpr = 0, *ToExpr = 0;
llvm::APSInt FromInt, ToInt;
+ ValueDecl *FromValueDecl = 0, *ToValueDecl = 0;
+ unsigned ParamWidth = 128; // Safe default
+ if (DefaultNTTPD->getType()->isIntegralOrEnumerationType())
+ ParamWidth = Context.getIntWidth(DefaultNTTPD->getType());
bool HasFromInt = !FromIter.isEnd() &&
FromIter->getKind() == TemplateArgument::Integral;
bool HasToInt = !ToIter.isEnd() &&
ToIter->getKind() == TemplateArgument::Integral;
- //bool IsValidFromInt = false, IsValidToInt = false;
+ bool HasFromValueDecl =
+ !FromIter.isEnd() &&
+ FromIter->getKind() == TemplateArgument::Declaration;
+ bool HasToValueDecl =
+ !ToIter.isEnd() &&
+ ToIter->getKind() == TemplateArgument::Declaration;
+
+ assert(((!HasFromInt && !HasToInt) ||
+ (!HasFromValueDecl && !HasToValueDecl)) &&
+ "Template argument cannot be both integer and declaration");
+
if (HasFromInt)
FromInt = FromIter->getAsIntegral();
+ else if (HasFromValueDecl)
+ FromValueDecl = FromIter->getAsDecl();
else
- GetExpr(FromIter, DefaultNTTPD, FromExpr);
+ FromExpr = GetExpr(FromIter, DefaultNTTPD);
if (HasToInt)
ToInt = ToIter->getAsIntegral();
+ else if (HasToValueDecl)
+ ToValueDecl = ToIter->getAsDecl();
else
- GetExpr(ToIter, DefaultNTTPD, ToExpr);
+ ToExpr = GetExpr(ToIter, DefaultNTTPD);
- if (!HasFromInt && !HasToInt) {
+ if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) {
Tree.SetNode(FromExpr, ToExpr);
- Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr));
Tree.SetDefault(FromIter.isEnd() && FromExpr,
ToIter.isEnd() && ToExpr);
- } else {
+ if (DefaultNTTPD->getType()->isIntegralOrEnumerationType()) {
+ if (FromExpr)
+ FromInt = GetInt(FromIter, FromExpr);
+ if (ToExpr)
+ ToInt = GetInt(ToIter, ToExpr);
+ Tree.SetNode(FromInt, ToInt, FromExpr, ToExpr);
+ Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
+ Tree.SetKind(DiffTree::Integer);
+ } else {
+ Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr));
+ Tree.SetKind(DiffTree::Expression);
+ }
+ } else if (HasFromInt || HasToInt) {
if (!HasFromInt && FromExpr) {
- FromInt = FromExpr->EvaluateKnownConstInt(Context);
+ FromInt = GetInt(FromIter, FromExpr);
HasFromInt = true;
}
if (!HasToInt && ToExpr) {
- ToInt = ToExpr->EvaluateKnownConstInt(Context);
+ ToInt = GetInt(ToIter, ToExpr);
HasToInt = true;
}
Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt);
- Tree.SetSame(llvm::APSInt::isSameValue(FromInt, ToInt));
+ Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt));
Tree.SetDefault(FromIter.isEnd() && HasFromInt,
ToIter.isEnd() && HasToInt);
+ Tree.SetKind(DiffTree::Integer);
+ } else {
+ if (!HasFromValueDecl && FromExpr)
+ FromValueDecl = GetValueDecl(FromIter, FromExpr);
+ if (!HasToValueDecl && ToExpr)
+ ToValueDecl = GetValueDecl(ToIter, ToExpr);
+ Tree.SetNode(FromValueDecl, ToValueDecl);
+ Tree.SetSame(FromValueDecl && ToValueDecl &&
+ FromValueDecl->getCanonicalDecl() ==
+ ToValueDecl->getCanonicalDecl());
+ Tree.SetDefault(FromIter.isEnd() && FromValueDecl,
+ ToIter.isEnd() && ToValueDecl);
+ Tree.SetKind(DiffTree::Declaration);
}
}
@@ -888,15 +956,17 @@ class TemplateDiff {
if (TemplateTemplateParmDecl *DefaultTTPD =
dyn_cast<TemplateTemplateParmDecl>(ParamND)) {
TemplateDecl *FromDecl, *ToDecl;
- GetTemplateDecl(FromIter, DefaultTTPD, FromDecl);
- GetTemplateDecl(ToIter, DefaultTTPD, ToDecl);
+ FromDecl = GetTemplateDecl(FromIter, DefaultTTPD);
+ ToDecl = GetTemplateDecl(ToIter, DefaultTTPD);
Tree.SetNode(FromDecl, ToDecl);
- Tree.SetSame(FromDecl && ToDecl &&
- FromDecl->getIdentifier() == ToDecl->getIdentifier());
+ Tree.SetSame(
+ FromDecl && ToDecl &&
+ FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl());
+ Tree.SetKind(DiffTree::TemplateTemplate);
}
- if (!FromIter.isEnd()) ++FromIter;
- if (!ToIter.isEnd()) ++ToIter;
+ ++FromIter;
+ ++ToIter;
Tree.Up();
}
}
@@ -917,8 +987,8 @@ class TemplateDiff {
/// even if the template arguments are not.
static bool hasSameBaseTemplate(const TemplateSpecializationType *FromTST,
const TemplateSpecializationType *ToTST) {
- return FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() ==
- ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier();
+ return FromTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl() ==
+ ToTST->getTemplateName().getAsTemplateDecl()->getCanonicalDecl();
}
/// hasSameTemplate - Returns true if both types are specialized from the
@@ -962,22 +1032,21 @@ class TemplateDiff {
/// GetType - Retrieves the template type arguments, including default
/// arguments.
- void GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD,
- QualType &ArgType) {
- ArgType = QualType();
+ QualType GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD) {
bool isVariadic = DefaultTTPD->isParameterPack();
if (!Iter.isEnd())
- ArgType = Iter->getAsType();
- else if (!isVariadic)
- ArgType = DefaultTTPD->getDefaultArgument();
+ return Iter->getAsType();
+ if (!isVariadic)
+ return DefaultTTPD->getDefaultArgument();
+
+ return QualType();
}
/// GetExpr - Retrieves the template expression argument, including default
/// arguments.
- void GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD,
- Expr *&ArgExpr) {
- ArgExpr = 0;
+ Expr *GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD) {
+ Expr *ArgExpr = 0;
bool isVariadic = DefaultNTTPD->isParameterPack();
if (!Iter.isEnd())
@@ -989,14 +1058,50 @@ class TemplateDiff {
while (SubstNonTypeTemplateParmExpr *SNTTPE =
dyn_cast<SubstNonTypeTemplateParmExpr>(ArgExpr))
ArgExpr = SNTTPE->getReplacement();
+
+ return ArgExpr;
+ }
+
+ /// GetInt - Retrieves the template integer argument, including evaluating
+ /// default arguments.
+ llvm::APInt GetInt(const TSTiterator &Iter, Expr *ArgExpr) {
+ // Default, value-depenedent expressions require fetching
+ // from the desugared TemplateArgument
+ if (Iter.isEnd() && ArgExpr->isValueDependent())
+ switch (Iter.getDesugar().getKind()) {
+ case TemplateArgument::Integral:
+ return Iter.getDesugar().getAsIntegral();
+ case TemplateArgument::Expression:
+ ArgExpr = Iter.getDesugar().getAsExpr();
+ return ArgExpr->EvaluateKnownConstInt(Context);
+ default:
+ assert(0 && "Unexpected template argument kind");
+ }
+ return ArgExpr->EvaluateKnownConstInt(Context);
+ }
+
+ /// GetValueDecl - Retrieves the template integer argument, including
+ /// default expression argument.
+ ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) {
+ // Default, value-depenedent expressions require fetching
+ // from the desugared TemplateArgument
+ if (Iter.isEnd() && ArgExpr->isValueDependent())
+ switch (Iter.getDesugar().getKind()) {
+ case TemplateArgument::Declaration:
+ return Iter.getDesugar().getAsDecl();
+ case TemplateArgument::Expression:
+ ArgExpr = Iter.getDesugar().getAsExpr();
+ return cast<DeclRefExpr>(ArgExpr)->getDecl();
+ default:
+ assert(0 && "Unexpected template argument kind");
+ }
+ return cast<DeclRefExpr>(ArgExpr)->getDecl();
}
/// GetTemplateDecl - Retrieves the template template arguments, including
/// default arguments.
- void GetTemplateDecl(const TSTiterator &Iter,
- TemplateTemplateParmDecl *DefaultTTPD,
- TemplateDecl *&ArgDecl) {
- ArgDecl = 0;
+ TemplateDecl *GetTemplateDecl(const TSTiterator &Iter,
+ TemplateTemplateParmDecl *DefaultTTPD) {
bool isVariadic = DefaultTTPD->isParameterPack();
TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument();
@@ -1005,13 +1110,25 @@ class TemplateDiff {
DefaultTD = TA.getAsTemplate().getAsTemplateDecl();
if (!Iter.isEnd())
- ArgDecl = Iter->getAsTemplate().getAsTemplateDecl();
- else if (!isVariadic)
- ArgDecl = DefaultTD;
+ return Iter->getAsTemplate().getAsTemplateDecl();
+ if (!isVariadic)
+ return DefaultTD;
+
+ return 0;
+ }
+
+ /// IsSameConvertedInt - Returns true if both integers are equal when
+ /// converted to an integer type with the given width.
+ static bool IsSameConvertedInt(unsigned Width, const llvm::APSInt &X,
+ const llvm::APSInt &Y) {
+ llvm::APInt ConvertedX = X.extOrTrunc(Width);
+ llvm::APInt ConvertedY = Y.extOrTrunc(Width);
+ return ConvertedX == ConvertedY;
}
/// IsEqualExpr - Returns true if the expressions evaluate to the same value.
- static bool IsEqualExpr(ASTContext &Context, Expr *FromExpr, Expr *ToExpr) {
+ static bool IsEqualExpr(ASTContext &Context, unsigned ParamWidth,
+ Expr *FromExpr, Expr *ToExpr) {
if (FromExpr == ToExpr)
return true;
@@ -1033,7 +1150,7 @@ class TemplateDiff {
Expr::EvalResult FromResult, ToResult;
if (!FromExpr->EvaluateAsRValue(FromResult, Context) ||
!ToExpr->EvaluateAsRValue(ToResult, Context))
- assert(0 && "Template arguments must be known at compile time.");
+ return false;
APValue &FromVal = FromResult.Val;
APValue &ToVal = ToResult.Val;
@@ -1042,7 +1159,7 @@ class TemplateDiff {
switch (FromVal.getKind()) {
case APValue::Int:
- return FromVal.getInt() == ToVal.getInt();
+ return IsSameConvertedInt(ParamWidth, FromVal.getInt(), ToVal.getInt());
case APValue::LValue: {
APValue::LValueBase FromBase = FromVal.getLValueBase();
APValue::LValueBase ToBase = ToVal.getLValueBase();
@@ -1068,81 +1185,97 @@ class TemplateDiff {
void TreeToString(int Indent = 1) {
if (PrintTree) {
OS << '\n';
- for (int i = 0; i < Indent; ++i)
- OS << " ";
+ OS.indent(2 * Indent);
++Indent;
}
// Handle cases where the difference is not templates with different
// arguments.
- if (!Tree.NodeIsTemplate()) {
- if (Tree.NodeIsQualType()) {
+ switch (Tree.GetKind()) {
+ case DiffTree::Invalid:
+ llvm_unreachable("Template diffing failed with bad DiffNode");
+ case DiffTree::Type: {
QualType FromType, ToType;
Tree.GetNode(FromType, ToType);
PrintTypeNames(FromType, ToType, Tree.FromDefault(), Tree.ToDefault(),
Tree.NodeIsSame());
return;
}
- if (Tree.NodeIsExpr()) {
+ case DiffTree::Expression: {
Expr *FromExpr, *ToExpr;
Tree.GetNode(FromExpr, ToExpr);
PrintExpr(FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
Tree.NodeIsSame());
return;
}
- if (Tree.NodeIsTemplateTemplate()) {
+ case DiffTree::TemplateTemplate: {
TemplateDecl *FromTD, *ToTD;
Tree.GetNode(FromTD, ToTD);
PrintTemplateTemplate(FromTD, ToTD, Tree.FromDefault(),
Tree.ToDefault(), Tree.NodeIsSame());
return;
}
-
- if (Tree.NodeIsAPSInt()) {
+ case DiffTree::Integer: {
llvm::APSInt FromInt, ToInt;
+ Expr *FromExpr, *ToExpr;
bool IsValidFromInt, IsValidToInt;
+ Tree.GetNode(FromExpr, ToExpr);
Tree.GetNode(FromInt, ToInt, IsValidFromInt, IsValidToInt);
PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt,
- Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame());
+ FromExpr, ToExpr, Tree.FromDefault(), Tree.ToDefault(),
+ Tree.NodeIsSame());
return;
}
- llvm_unreachable("Unable to deduce template difference.");
- }
-
- // Node is root of template. Recurse on children.
- TemplateDecl *FromTD, *ToTD;
- Tree.GetNode(FromTD, ToTD);
-
- assert(Tree.HasChildren() && "Template difference not found in diff tree.");
-
- Qualifiers FromQual, ToQual;
- Tree.GetNode(FromQual, ToQual);
- PrintQualifiers(FromQual, ToQual);
+ case DiffTree::Declaration: {
+ ValueDecl *FromValueDecl, *ToValueDecl;
+ Tree.GetNode(FromValueDecl, ToValueDecl);
+ PrintValueDecl(FromValueDecl, ToValueDecl, Tree.FromDefault(),
+ Tree.ToDefault(), Tree.NodeIsSame());
+ return;
+ }
+ case DiffTree::Template: {
+ // Node is root of template. Recurse on children.
+ TemplateDecl *FromTD, *ToTD;
+ Tree.GetNode(FromTD, ToTD);
- OS << FromTD->getNameAsString() << '<';
- Tree.MoveToChild();
- unsigned NumElideArgs = 0;
- do {
- if (ElideType) {
- if (Tree.NodeIsSame()) {
- ++NumElideArgs;
- continue;
+ if (!Tree.HasChildren()) {
+ // If we're dealing with a template specialization with zero
+ // arguments, there are no children; special-case this.
+ OS << FromTD->getNameAsString() << "<>";
+ return;
}
- if (NumElideArgs > 0) {
+
+ Qualifiers FromQual, ToQual;
+ Tree.GetNode(FromQual, ToQual);
+ PrintQualifiers(FromQual, ToQual);
+
+ OS << FromTD->getNameAsString() << '<';
+ Tree.MoveToChild();
+ unsigned NumElideArgs = 0;
+ do {
+ if (ElideType) {
+ if (Tree.NodeIsSame()) {
+ ++NumElideArgs;
+ continue;
+ }
+ if (NumElideArgs > 0) {
+ PrintElideArgs(NumElideArgs, Indent);
+ NumElideArgs = 0;
+ OS << ", ";
+ }
+ }
+ TreeToString(Indent);
+ if (Tree.HasNextSibling())
+ OS << ", ";
+ } while (Tree.AdvanceSibling());
+ if (NumElideArgs > 0)
PrintElideArgs(NumElideArgs, Indent);
- NumElideArgs = 0;
- OS << ", ";
- }
+
+ Tree.Parent();
+ OS << ">";
+ return;
}
- TreeToString(Indent);
- if (Tree.HasNextSibling())
- OS << ", ";
- } while (Tree.AdvanceSibling());
- if (NumElideArgs > 0)
- PrintElideArgs(NumElideArgs, Indent);
-
- Tree.Parent();
- OS << ">";
+ }
}
// To signal to the text printer that a certain text needs to be bolded,
@@ -1260,21 +1393,29 @@ class TemplateDiff {
void PrintTemplateTemplate(TemplateDecl *FromTD, TemplateDecl *ToTD,
bool FromDefault, bool ToDefault, bool Same) {
assert((FromTD || ToTD) && "Only one template argument may be missing.");
+
+ std::string FromName = FromTD ? FromTD->getName() : "(no argument)";
+ std::string ToName = ToTD ? ToTD->getName() : "(no argument)";
+ if (FromTD && ToTD && FromName == ToName) {
+ FromName = FromTD->getQualifiedNameAsString();
+ ToName = ToTD->getQualifiedNameAsString();
+ }
+
if (Same) {
OS << "template " << FromTD->getNameAsString();
} else if (!PrintTree) {
OS << (FromDefault ? "(default) template " : "template ");
Bold();
- OS << (FromTD ? FromTD->getNameAsString() : "(no argument)");
+ OS << FromName;
Unbold();
} else {
OS << (FromDefault ? "[(default) template " : "[template ");
Bold();
- OS << (FromTD ? FromTD->getNameAsString() : "(no argument)");
+ OS << FromName;
Unbold();
OS << " != " << (ToDefault ? "(default) template " : "template ");
Bold();
- OS << (ToTD ? ToTD->getNameAsString() : "(no argument)");
+ OS << ToName;
Unbold();
OS << ']';
}
@@ -1283,8 +1424,8 @@ class TemplateDiff {
/// PrintAPSInt - Handles printing of integral arguments, highlighting
/// argument differences.
void PrintAPSInt(llvm::APSInt FromInt, llvm::APSInt ToInt,
- bool IsValidFromInt, bool IsValidToInt, bool FromDefault,
- bool ToDefault, bool Same) {
+ bool IsValidFromInt, bool IsValidToInt, Expr *FromExpr,
+ Expr *ToExpr, bool FromDefault, bool ToDefault, bool Same) {
assert((IsValidFromInt || IsValidToInt) &&
"Only one integral argument may be missing.");
@@ -1292,20 +1433,74 @@ class TemplateDiff {
OS << FromInt.toString(10);
} else if (!PrintTree) {
OS << (FromDefault ? "(default) " : "");
+ PrintAPSInt(FromInt, FromExpr, IsValidFromInt);
+ } else {
+ OS << (FromDefault ? "[(default) " : "[");
+ PrintAPSInt(FromInt, FromExpr, IsValidFromInt);
+ OS << " != " << (ToDefault ? "(default) " : "");
+ PrintAPSInt(ToInt, ToExpr, IsValidToInt);
+ OS << ']';
+ }
+ }
+
+ /// PrintAPSInt - If valid, print the APSInt. If the expression is
+ /// gives more information, print it too.
+ void PrintAPSInt(llvm::APSInt Val, Expr *E, bool Valid) {
+ Bold();
+ if (Valid) {
+ if (HasExtraInfo(E)) {
+ PrintExpr(E);
+ Unbold();
+ OS << " aka ";
+ Bold();
+ }
+ OS << Val.toString(10);
+ } else {
+ OS << "(no argument)";
+ }
+ Unbold();
+ }
+
+ /// HasExtraInfo - Returns true if E is not an integer literal or the
+ /// negation of an integer literal
+ bool HasExtraInfo(Expr *E) {
+ if (!E) return false;
+ if (isa<IntegerLiteral>(E)) return false;
+
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
+ if (UO->getOpcode() == UO_Minus)
+ if (isa<IntegerLiteral>(UO->getSubExpr()))
+ return false;
+
+ return true;
+ }
+
+ /// PrintDecl - Handles printing of Decl arguments, highlighting
+ /// argument differences.
+ void PrintValueDecl(ValueDecl *FromValueDecl, ValueDecl *ToValueDecl,
+ bool FromDefault, bool ToDefault, bool Same) {
+ assert((FromValueDecl || ToValueDecl) &&
+ "Only one Decl argument may be NULL");
+
+ if (Same) {
+ OS << FromValueDecl->getName();
+ } else if (!PrintTree) {
+ OS << (FromDefault ? "(default) " : "");
Bold();
- OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)");
+ OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
} else {
OS << (FromDefault ? "[(default) " : "[");
Bold();
- OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)");
+ OS << (FromValueDecl ? FromValueDecl->getName() : "(no argument)");
Unbold();
OS << " != " << (ToDefault ? "(default) " : "");
Bold();
- OS << (IsValidToInt ? ToInt.toString(10) : "(no argument)");
+ OS << (ToValueDecl ? ToValueDecl->getName() : "(no argument)");
Unbold();
OS << ']';
}
+
}
// Prints the appropriate placeholder for elided template arguments.
@@ -1386,9 +1581,9 @@ class TemplateDiff {
public:
- TemplateDiff(ASTContext &Context, QualType FromType, QualType ToType,
- bool PrintTree, bool PrintFromType, bool ElideType,
- bool ShowColor)
+ TemplateDiff(raw_ostream &OS, ASTContext &Context, QualType FromType,
+ QualType ToType, bool PrintTree, bool PrintFromType,
+ bool ElideType, bool ShowColor)
: Context(Context),
Policy(Context.getLangOpts()),
ElideType(ElideType),
@@ -1397,7 +1592,7 @@ public:
// When printing a single type, the FromType is the one printed.
FromType(PrintFromType ? FromType : ToType),
ToType(PrintFromType ? ToType : FromType),
- OS(Str),
+ OS(OS),
IsBold(false) {
}
@@ -1424,6 +1619,7 @@ public:
ToQual -= QualType(ToOrigTST, 0).getQualifiers();
Tree.SetNode(FromType, ToType);
Tree.SetNode(FromQual, ToQual);
+ Tree.SetKind(DiffTree::Template);
// Same base template, but different arguments.
Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(),
@@ -1432,17 +1628,16 @@ public:
DiffTemplate(FromOrigTST, ToOrigTST);
}
- /// MakeString - When the two types given are templated types with the same
+ /// Emit - When the two types given are templated types with the same
/// base template, a string representation of the type difference will be
- /// loaded into S and return true. Otherwise, return false.
- bool MakeString(std::string &S) {
+ /// emitted to the stream and return true. Otherwise, return false.
+ bool Emit() {
Tree.StartTraverse();
if (Tree.Empty())
return false;
TreeToString();
assert(!IsBold && "Bold is applied to end of string.");
- S = OS.str();
return true;
}
}; // end class TemplateDiff
@@ -1454,11 +1649,11 @@ public:
static bool FormatTemplateTypeDiff(ASTContext &Context, QualType FromType,
QualType ToType, bool PrintTree,
bool PrintFromType, bool ElideType,
- bool ShowColors, std::string &S) {
+ bool ShowColors, raw_ostream &OS) {
if (PrintTree)
PrintFromType = true;
- TemplateDiff TD(Context, FromType, ToType, PrintTree, PrintFromType,
+ TemplateDiff TD(OS, Context, FromType, ToType, PrintTree, PrintFromType,
ElideType, ShowColors);
TD.DiffTemplate();
- return TD.MakeString(S);
+ return TD.Emit();
}
diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp
new file mode 100644
index 000000000000..b1d174b855eb
--- /dev/null
+++ b/lib/AST/ASTDumper.cpp
@@ -0,0 +1,1996 @@
+//===--- ASTDumper.cpp - Dumping implementation for ASTs ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the AST dump methods, which dump out the
+// AST in a form that exposes type details and other fields.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CommentVisitor.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/Module.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+using namespace clang::comments;
+
+//===----------------------------------------------------------------------===//
+// ASTDumper Visitor
+//===----------------------------------------------------------------------===//
+
+namespace {
+ // Colors used for various parts of the AST dump
+
+ struct TerminalColor {
+ raw_ostream::Colors Color;
+ bool Bold;
+ };
+
+ // Decl kind names (VarDecl, FunctionDecl, etc)
+ static const TerminalColor DeclKindNameColor = { raw_ostream::GREEN, true };
+ // Attr names (CleanupAttr, GuardedByAttr, etc)
+ static const TerminalColor AttrColor = { raw_ostream::BLUE, true };
+ // Statement names (DeclStmt, ImplicitCastExpr, etc)
+ static const TerminalColor StmtColor = { raw_ostream::MAGENTA, true };
+ // Comment names (FullComment, ParagraphComment, TextComment, etc)
+ static const TerminalColor CommentColor = { raw_ostream::YELLOW, true };
+
+ // Type names (int, float, etc, plus user defined types)
+ static const TerminalColor TypeColor = { raw_ostream::GREEN, false };
+
+ // Pointer address
+ static const TerminalColor AddressColor = { raw_ostream::YELLOW, false };
+ // Source locations
+ static const TerminalColor LocationColor = { raw_ostream::YELLOW, false };
+
+ // lvalue/xvalue
+ static const TerminalColor ValueKindColor = { raw_ostream::CYAN, false };
+ // bitfield/objcproperty/objcsubscript/vectorcomponent
+ static const TerminalColor ObjectKindColor = { raw_ostream::CYAN, false };
+
+ // Null statements
+ static const TerminalColor NullColor = { raw_ostream::BLUE, false };
+
+ // CastKind from CastExpr's
+ static const TerminalColor CastColor = { raw_ostream::RED, false };
+
+ // Value of the statement
+ static const TerminalColor ValueColor = { raw_ostream::CYAN, true };
+ // Decl names
+ static const TerminalColor DeclNameColor = { raw_ostream::CYAN, true };
+
+ // Indents ( `, -. | )
+ static const TerminalColor IndentColor = { raw_ostream::BLUE, false };
+
+ class ASTDumper
+ : public ConstDeclVisitor<ASTDumper>, public ConstStmtVisitor<ASTDumper>,
+ public ConstCommentVisitor<ASTDumper> {
+ raw_ostream &OS;
+ const CommandTraits *Traits;
+ const SourceManager *SM;
+ bool IsFirstLine;
+
+ // Indicates whether more child are expected at the current tree depth
+ enum IndentType { IT_Child, IT_LastChild };
+
+ /// Indents[i] indicates if another child exists at level i.
+ /// Used by Indent() to print the tree structure.
+ llvm::SmallVector<IndentType, 32> Indents;
+
+ /// Indicates that more children will be needed at this indent level.
+ /// If true, prevents lastChild() from marking the node as the last child.
+ /// This is used when there are multiple collections of children to be
+ /// dumped as well as during conditional node dumping.
+ bool MoreChildren;
+
+ /// Keep track of the last location we print out so that we can
+ /// print out deltas from then on out.
+ const char *LastLocFilename;
+ unsigned LastLocLine;
+
+ /// The \c FullComment parent of the comment being dumped.
+ const FullComment *FC;
+
+ bool ShowColors;
+
+ class IndentScope {
+ ASTDumper &Dumper;
+ // Preserve the Dumper's MoreChildren value from the previous IndentScope
+ bool MoreChildren;
+ public:
+ IndentScope(ASTDumper &Dumper) : Dumper(Dumper) {
+ MoreChildren = Dumper.hasMoreChildren();
+ Dumper.setMoreChildren(false);
+ Dumper.indent();
+ }
+ ~IndentScope() {
+ Dumper.setMoreChildren(MoreChildren);
+ Dumper.unindent();
+ }
+ };
+
+ class ColorScope {
+ ASTDumper &Dumper;
+ public:
+ ColorScope(ASTDumper &Dumper, TerminalColor Color)
+ : Dumper(Dumper) {
+ if (Dumper.ShowColors)
+ Dumper.OS.changeColor(Color.Color, Color.Bold);
+ }
+ ~ColorScope() {
+ if (Dumper.ShowColors)
+ Dumper.OS.resetColor();
+ }
+ };
+
+ public:
+ ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
+ const SourceManager *SM)
+ : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false),
+ LastLocFilename(""), LastLocLine(~0U), FC(0),
+ ShowColors(SM && SM->getDiagnostics().getShowColors()) { }
+
+ ASTDumper(raw_ostream &OS, const CommandTraits *Traits,
+ const SourceManager *SM, bool ShowColors)
+ : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false),
+ LastLocFilename(""), LastLocLine(~0U),
+ ShowColors(ShowColors) { }
+
+ ~ASTDumper() {
+ OS << "\n";
+ }
+
+ void dumpDecl(const Decl *D);
+ void dumpStmt(const Stmt *S);
+ void dumpFullComment(const FullComment *C);
+
+ // Formatting
+ void indent();
+ void unindent();
+ void lastChild();
+ bool hasMoreChildren();
+ void setMoreChildren(bool Value);
+
+ // Utilities
+ void dumpPointer(const void *Ptr);
+ void dumpSourceRange(SourceRange R);
+ void dumpLocation(SourceLocation Loc);
+ void dumpBareType(QualType T);
+ void dumpType(QualType T);
+ void dumpBareDeclRef(const Decl *Node);
+ void dumpDeclRef(const Decl *Node, const char *Label = 0);
+ void dumpName(const NamedDecl *D);
+ bool hasNodes(const DeclContext *DC);
+ void dumpDeclContext(const DeclContext *DC);
+ void dumpAttr(const Attr *A);
+
+ // C++ Utilities
+ void dumpAccessSpecifier(AccessSpecifier AS);
+ void dumpCXXCtorInitializer(const CXXCtorInitializer *Init);
+ void dumpTemplateParameters(const TemplateParameterList *TPL);
+ void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI);
+ void dumpTemplateArgumentLoc(const TemplateArgumentLoc &A);
+ void dumpTemplateArgumentList(const TemplateArgumentList &TAL);
+ void dumpTemplateArgument(const TemplateArgument &A,
+ SourceRange R = SourceRange());
+
+ // Decls
+ void VisitLabelDecl(const LabelDecl *D);
+ void VisitTypedefDecl(const TypedefDecl *D);
+ void VisitEnumDecl(const EnumDecl *D);
+ void VisitRecordDecl(const RecordDecl *D);
+ void VisitEnumConstantDecl(const EnumConstantDecl *D);
+ void VisitIndirectFieldDecl(const IndirectFieldDecl *D);
+ void VisitFunctionDecl(const FunctionDecl *D);
+ void VisitFieldDecl(const FieldDecl *D);
+ void VisitVarDecl(const VarDecl *D);
+ void VisitFileScopeAsmDecl(const FileScopeAsmDecl *D);
+ void VisitImportDecl(const ImportDecl *D);
+
+ // C++ Decls
+ void VisitNamespaceDecl(const NamespaceDecl *D);
+ void VisitUsingDirectiveDecl(const UsingDirectiveDecl *D);
+ void VisitNamespaceAliasDecl(const NamespaceAliasDecl *D);
+ void VisitTypeAliasDecl(const TypeAliasDecl *D);
+ void VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D);
+ void VisitCXXRecordDecl(const CXXRecordDecl *D);
+ void VisitStaticAssertDecl(const StaticAssertDecl *D);
+ void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
+ void VisitClassTemplateDecl(const ClassTemplateDecl *D);
+ void VisitClassTemplateSpecializationDecl(
+ const ClassTemplateSpecializationDecl *D);
+ void VisitClassTemplatePartialSpecializationDecl(
+ const ClassTemplatePartialSpecializationDecl *D);
+ void VisitClassScopeFunctionSpecializationDecl(
+ const ClassScopeFunctionSpecializationDecl *D);
+ void VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D);
+ void VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D);
+ void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D);
+ void VisitUsingDecl(const UsingDecl *D);
+ void VisitUnresolvedUsingTypenameDecl(const UnresolvedUsingTypenameDecl *D);
+ void VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D);
+ void VisitUsingShadowDecl(const UsingShadowDecl *D);
+ void VisitLinkageSpecDecl(const LinkageSpecDecl *D);
+ void VisitAccessSpecDecl(const AccessSpecDecl *D);
+ void VisitFriendDecl(const FriendDecl *D);
+
+ // ObjC Decls
+ void VisitObjCIvarDecl(const ObjCIvarDecl *D);
+ void VisitObjCMethodDecl(const ObjCMethodDecl *D);
+ void VisitObjCCategoryDecl(const ObjCCategoryDecl *D);
+ void VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D);
+ void VisitObjCProtocolDecl(const ObjCProtocolDecl *D);
+ void VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D);
+ void VisitObjCImplementationDecl(const ObjCImplementationDecl *D);
+ void VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D);
+ void VisitObjCPropertyDecl(const ObjCPropertyDecl *D);
+ void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D);
+ void VisitBlockDecl(const BlockDecl *D);
+
+ // Stmts.
+ void VisitStmt(const Stmt *Node);
+ void VisitDeclStmt(const DeclStmt *Node);
+ void VisitAttributedStmt(const AttributedStmt *Node);
+ void VisitLabelStmt(const LabelStmt *Node);
+ void VisitGotoStmt(const GotoStmt *Node);
+
+ // Exprs
+ void VisitExpr(const Expr *Node);
+ void VisitCastExpr(const CastExpr *Node);
+ void VisitDeclRefExpr(const DeclRefExpr *Node);
+ void VisitPredefinedExpr(const PredefinedExpr *Node);
+ void VisitCharacterLiteral(const CharacterLiteral *Node);
+ void VisitIntegerLiteral(const IntegerLiteral *Node);
+ void VisitFloatingLiteral(const FloatingLiteral *Node);
+ void VisitStringLiteral(const StringLiteral *Str);
+ void VisitUnaryOperator(const UnaryOperator *Node);
+ void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Node);
+ void VisitMemberExpr(const MemberExpr *Node);
+ void VisitExtVectorElementExpr(const ExtVectorElementExpr *Node);
+ void VisitBinaryOperator(const BinaryOperator *Node);
+ void VisitCompoundAssignOperator(const CompoundAssignOperator *Node);
+ void VisitAddrLabelExpr(const AddrLabelExpr *Node);
+ void VisitBlockExpr(const BlockExpr *Node);
+ void VisitOpaqueValueExpr(const OpaqueValueExpr *Node);
+
+ // C++
+ void VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node);
+ void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node);
+ void VisitCXXThisExpr(const CXXThisExpr *Node);
+ void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node);
+ void VisitCXXConstructExpr(const CXXConstructExpr *Node);
+ void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node);
+ void VisitExprWithCleanups(const ExprWithCleanups *Node);
+ void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
+ void dumpCXXTemporary(const CXXTemporary *Temporary);
+
+ // ObjC
+ void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node);
+ void VisitObjCEncodeExpr(const ObjCEncodeExpr *Node);
+ void VisitObjCMessageExpr(const ObjCMessageExpr *Node);
+ void VisitObjCBoxedExpr(const ObjCBoxedExpr *Node);
+ void VisitObjCSelectorExpr(const ObjCSelectorExpr *Node);
+ void VisitObjCProtocolExpr(const ObjCProtocolExpr *Node);
+ void VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node);
+ void VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node);
+ void VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node);
+ void VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node);
+
+ // Comments.
+ const char *getCommandName(unsigned CommandID);
+ void dumpComment(const Comment *C);
+
+ // Inline comments.
+ void visitTextComment(const TextComment *C);
+ void visitInlineCommandComment(const InlineCommandComment *C);
+ void visitHTMLStartTagComment(const HTMLStartTagComment *C);
+ void visitHTMLEndTagComment(const HTMLEndTagComment *C);
+
+ // Block comments.
+ void visitBlockCommandComment(const BlockCommandComment *C);
+ void visitParamCommandComment(const ParamCommandComment *C);
+ void visitTParamCommandComment(const TParamCommandComment *C);
+ void visitVerbatimBlockComment(const VerbatimBlockComment *C);
+ void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
+ void visitVerbatimLineComment(const VerbatimLineComment *C);
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Utilities
+//===----------------------------------------------------------------------===//
+
+// Print out the appropriate tree structure using the Indents vector.
+// Example of tree and the Indents vector at each level.
+// A { }
+// |-B { IT_Child }
+// | `-C { IT_Child, IT_LastChild }
+// `-D { IT_LastChild }
+// |-E { IT_LastChild, IT_Child }
+// `-F { IT_LastChild, IT_LastChild }
+// Type non-last element, last element
+// IT_Child "| " "|-"
+// IT_LastChild " " "`-"
+void ASTDumper::indent() {
+ if (IsFirstLine)
+ IsFirstLine = false;
+ else
+ OS << "\n";
+
+ ColorScope Color(*this, IndentColor);
+ for (llvm::SmallVector<IndentType, 32>::const_iterator I = Indents.begin(),
+ E = Indents.end();
+ I != E; ++I) {
+ switch (*I) {
+ case IT_Child:
+ if (I == E - 1)
+ OS << "|-";
+ else
+ OS << "| ";
+ continue;
+ case IT_LastChild:
+ if (I == E - 1)
+ OS << "`-";
+ else
+ OS << " ";
+ continue;
+ }
+ llvm_unreachable("Invalid IndentType");
+ }
+ Indents.push_back(IT_Child);
+}
+
+void ASTDumper::unindent() {
+ Indents.pop_back();
+}
+
+// Call before each potential last child node is to be dumped. If MoreChildren
+// is false, then this is the last child, otherwise treat as a regular node.
+void ASTDumper::lastChild() {
+ if (!hasMoreChildren())
+ Indents.back() = IT_LastChild;
+}
+
+// MoreChildren should be set before calling another function that may print
+// additional nodes to prevent conflicting final child nodes.
+bool ASTDumper::hasMoreChildren() {
+ return MoreChildren;
+}
+
+void ASTDumper::setMoreChildren(bool Value) {
+ MoreChildren = Value;
+}
+
+void ASTDumper::dumpPointer(const void *Ptr) {
+ ColorScope Color(*this, AddressColor);
+ OS << ' ' << Ptr;
+}
+
+void ASTDumper::dumpLocation(SourceLocation Loc) {
+ ColorScope Color(*this, LocationColor);
+ SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
+
+ // 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();
+ LastLocFilename = PLoc.getFilename();
+ LastLocLine = PLoc.getLine();
+ } else if (PLoc.getLine() != LastLocLine) {
+ OS << "line" << ':' << PLoc.getLine()
+ << ':' << PLoc.getColumn();
+ LastLocLine = PLoc.getLine();
+ } else {
+ OS << "col" << ':' << PLoc.getColumn();
+ }
+}
+
+void ASTDumper::dumpSourceRange(SourceRange R) {
+ // Can't translate locations if a SourceManager isn't available.
+ if (!SM)
+ return;
+
+ OS << " <";
+ dumpLocation(R.getBegin());
+ if (R.getBegin() != R.getEnd()) {
+ OS << ", ";
+ dumpLocation(R.getEnd());
+ }
+ OS << ">";
+
+ // <t2.c:123:421[blah], t2.c:412:321>
+
+}
+
+void ASTDumper::dumpBareType(QualType T) {
+ ColorScope Color(*this, TypeColor);
+
+ SplitQualType T_split = T.split();
+ OS << "'" << QualType::getAsString(T_split) << "'";
+
+ if (!T.isNull()) {
+ // If the type is sugared, also dump a (shallow) desugared type.
+ SplitQualType D_split = T.getSplitDesugaredType();
+ if (T_split != D_split)
+ OS << ":'" << QualType::getAsString(D_split) << "'";
+ }
+}
+
+void ASTDumper::dumpType(QualType T) {
+ OS << ' ';
+ dumpBareType(T);
+}
+
+void ASTDumper::dumpBareDeclRef(const Decl *D) {
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << D->getDeclKindName();
+ }
+ dumpPointer(D);
+
+ if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
+ ColorScope Color(*this, DeclNameColor);
+ OS << " '";
+ ND->getDeclName().printName(OS);
+ OS << "'";
+ }
+
+ if (const ValueDecl *VD = dyn_cast<ValueDecl>(D))
+ dumpType(VD->getType());
+}
+
+void ASTDumper::dumpDeclRef(const Decl *D, const char *Label) {
+ if (!D)
+ return;
+
+ IndentScope Indent(*this);
+ if (Label)
+ OS << Label << ' ';
+ dumpBareDeclRef(D);
+}
+
+void ASTDumper::dumpName(const NamedDecl *ND) {
+ if (ND->getDeclName()) {
+ ColorScope Color(*this, DeclNameColor);
+ OS << ' ' << ND->getNameAsString();
+ }
+}
+
+bool ASTDumper::hasNodes(const DeclContext *DC) {
+ if (!DC)
+ return false;
+
+ return DC->decls_begin() != DC->decls_end();
+}
+
+void ASTDumper::dumpDeclContext(const DeclContext *DC) {
+ if (!DC)
+ return;
+ for (DeclContext::decl_iterator I = DC->decls_begin(), E = DC->decls_end();
+ I != E; ++I) {
+ DeclContext::decl_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+}
+
+void ASTDumper::dumpAttr(const Attr *A) {
+ IndentScope Indent(*this);
+ {
+ ColorScope Color(*this, AttrColor);
+ switch (A->getKind()) {
+#define ATTR(X) case attr::X: OS << #X; break;
+#include "clang/Basic/AttrList.inc"
+ default: llvm_unreachable("unexpected attribute kind");
+ }
+ OS << "Attr";
+ }
+ dumpPointer(A);
+ dumpSourceRange(A->getRange());
+#include "clang/AST/AttrDump.inc"
+}
+
+static Decl *getPreviousDeclImpl(...) {
+ return 0;
+}
+
+template<typename T>
+static const Decl *getPreviousDeclImpl(const Redeclarable<T> *D) {
+ return D->getPreviousDecl();
+}
+
+/// Get the previous declaration in the redeclaration chain for a declaration.
+static const Decl *getPreviousDecl(const Decl *D) {
+ switch (D->getKind()) {
+#define DECL(DERIVED, BASE) \
+ case Decl::DERIVED: \
+ return getPreviousDeclImpl(cast<DERIVED##Decl>(D));
+#define ABSTRACT_DECL(DECL)
+#include "clang/AST/DeclNodes.inc"
+ }
+ llvm_unreachable("Decl that isn't part of DeclNodes.inc!");
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Utilities
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::dumpAccessSpecifier(AccessSpecifier AS) {
+ switch (AS) {
+ case AS_none:
+ break;
+ case AS_public:
+ OS << "public";
+ break;
+ case AS_protected:
+ OS << "protected";
+ break;
+ case AS_private:
+ OS << "private";
+ break;
+ }
+}
+
+void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) {
+ IndentScope Indent(*this);
+ OS << "CXXCtorInitializer";
+ if (Init->isAnyMemberInitializer()) {
+ OS << ' ';
+ dumpBareDeclRef(Init->getAnyMember());
+ } else {
+ dumpType(QualType(Init->getBaseClass(), 0));
+ }
+ dumpStmt(Init->getInit());
+}
+
+void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) {
+ if (!TPL)
+ return;
+
+ for (TemplateParameterList::const_iterator I = TPL->begin(), E = TPL->end();
+ I != E; ++I)
+ dumpDecl(*I);
+}
+
+void ASTDumper::dumpTemplateArgumentListInfo(
+ const TemplateArgumentListInfo &TALI) {
+ for (unsigned i = 0, e = TALI.size(); i < e; ++i) {
+ if (i + 1 == e)
+ lastChild();
+ dumpTemplateArgumentLoc(TALI[i]);
+ }
+}
+
+void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A) {
+ dumpTemplateArgument(A.getArgument(), A.getSourceRange());
+}
+
+void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) {
+ for (unsigned i = 0, e = TAL.size(); i < e; ++i)
+ dumpTemplateArgument(TAL[i]);
+}
+
+void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) {
+ IndentScope Indent(*this);
+ OS << "TemplateArgument";
+ if (R.isValid())
+ dumpSourceRange(R);
+
+ switch (A.getKind()) {
+ case TemplateArgument::Null:
+ OS << " null";
+ break;
+ case TemplateArgument::Type:
+ OS << " type";
+ lastChild();
+ dumpType(A.getAsType());
+ break;
+ case TemplateArgument::Declaration:
+ OS << " decl";
+ lastChild();
+ dumpDeclRef(A.getAsDecl());
+ break;
+ case TemplateArgument::NullPtr:
+ OS << " nullptr";
+ break;
+ case TemplateArgument::Integral:
+ OS << " integral " << A.getAsIntegral();
+ break;
+ case TemplateArgument::Template:
+ OS << " template ";
+ A.getAsTemplate().dump(OS);
+ break;
+ case TemplateArgument::TemplateExpansion:
+ OS << " template expansion";
+ A.getAsTemplateOrTemplatePattern().dump(OS);
+ break;
+ case TemplateArgument::Expression:
+ OS << " expr";
+ lastChild();
+ dumpStmt(A.getAsExpr());
+ break;
+ case TemplateArgument::Pack:
+ OS << " pack";
+ for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpTemplateArgument(*I);
+ }
+ break;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Decl dumping methods.
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::dumpDecl(const Decl *D) {
+ IndentScope Indent(*this);
+
+ if (!D) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << D->getDeclKindName() << "Decl";
+ }
+ dumpPointer(D);
+ if (D->getLexicalDeclContext() != D->getDeclContext())
+ OS << " parent " << cast<Decl>(D->getDeclContext());
+ if (const Decl *Prev = getPreviousDecl(D))
+ OS << " prev " << Prev;
+ dumpSourceRange(D->getSourceRange());
+
+ bool HasAttrs = D->attr_begin() != D->attr_end();
+ bool HasComment = D->getASTContext().getCommentForDecl(D, 0);
+ // Decls within functions are visited by the body
+ bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) &&
+ hasNodes(dyn_cast<DeclContext>(D));
+
+ setMoreChildren(HasAttrs || HasComment || HasDeclContext);
+ ConstDeclVisitor<ASTDumper>::Visit(D);
+
+ setMoreChildren(HasComment || HasDeclContext);
+ for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpAttr(*I);
+ }
+
+ setMoreChildren(HasDeclContext);
+ lastChild();
+ dumpFullComment(D->getASTContext().getCommentForDecl(D, 0));
+
+ setMoreChildren(false);
+ if (HasDeclContext)
+ dumpDeclContext(cast<DeclContext>(D));
+}
+
+void ASTDumper::VisitLabelDecl(const LabelDecl *D) {
+ dumpName(D);
+}
+
+void ASTDumper::VisitTypedefDecl(const TypedefDecl *D) {
+ dumpName(D);
+ dumpType(D->getUnderlyingType());
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+}
+
+void ASTDumper::VisitEnumDecl(const EnumDecl *D) {
+ if (D->isScoped()) {
+ if (D->isScopedUsingClassTag())
+ OS << " class";
+ else
+ OS << " struct";
+ }
+ dumpName(D);
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+ if (D->isFixed())
+ dumpType(D->getIntegerType());
+}
+
+void ASTDumper::VisitRecordDecl(const RecordDecl *D) {
+ OS << ' ' << D->getKindName();
+ dumpName(D);
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+}
+
+void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (const Expr *Init = D->getInitExpr()) {
+ lastChild();
+ dumpStmt(Init);
+ }
+}
+
+void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ for (IndirectFieldDecl::chain_iterator I = D->chain_begin(),
+ E = D->chain_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDeclRef(*I);
+ }
+}
+
+void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+
+ StorageClass SC = D->getStorageClass();
+ if (SC != SC_None)
+ OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
+ if (D->isInlineSpecified())
+ OS << " inline";
+ if (D->isVirtualAsWritten())
+ OS << " virtual";
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+
+ if (D->isPure())
+ OS << " pure";
+ else if (D->isDeletedAsWritten())
+ OS << " delete";
+
+ bool OldMoreChildren = hasMoreChildren();
+ const FunctionTemplateSpecializationInfo *FTSI =
+ D->getTemplateSpecializationInfo();
+ bool HasTemplateSpecialization = FTSI;
+
+ bool HasNamedDecls = D->getDeclsInPrototypeScope().begin() !=
+ D->getDeclsInPrototypeScope().end();
+
+ bool HasFunctionDecls = D->param_begin() != D->param_end();
+
+ const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D);
+ bool HasCtorInitializers = C && C->init_begin() != C->init_end();
+
+ bool HasDeclarationBody = D->doesThisDeclarationHaveABody();
+
+ setMoreChildren(OldMoreChildren || HasNamedDecls || HasFunctionDecls ||
+ HasCtorInitializers || HasDeclarationBody);
+ if (HasTemplateSpecialization) {
+ lastChild();
+ dumpTemplateArgumentList(*FTSI->TemplateArguments);
+ }
+
+ setMoreChildren(OldMoreChildren || HasFunctionDecls ||
+ HasCtorInitializers || HasDeclarationBody);
+ for (ArrayRef<NamedDecl *>::iterator
+ I = D->getDeclsInPrototypeScope().begin(),
+ E = D->getDeclsInPrototypeScope().end(); I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+
+ setMoreChildren(OldMoreChildren || HasCtorInitializers || HasDeclarationBody);
+ for (FunctionDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+
+ setMoreChildren(OldMoreChildren || HasDeclarationBody);
+ if (HasCtorInitializers)
+ for (CXXConstructorDecl::init_const_iterator I = C->init_begin(),
+ E = C->init_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpCXXCtorInitializer(*I);
+ }
+
+ setMoreChildren(OldMoreChildren);
+ if (HasDeclarationBody) {
+ lastChild();
+ dumpStmt(D->getBody());
+ }
+}
+
+void ASTDumper::VisitFieldDecl(const FieldDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (D->isMutable())
+ OS << " mutable";
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+
+ bool OldMoreChildren = hasMoreChildren();
+ bool IsBitField = D->isBitField();
+ Expr *Init = D->getInClassInitializer();
+ bool HasInit = Init;
+
+ setMoreChildren(OldMoreChildren || HasInit);
+ if (IsBitField) {
+ lastChild();
+ dumpStmt(D->getBitWidth());
+ }
+ setMoreChildren(OldMoreChildren);
+ if (HasInit) {
+ lastChild();
+ dumpStmt(Init);
+ }
+}
+
+void ASTDumper::VisitVarDecl(const VarDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ StorageClass SC = D->getStorageClass();
+ if (SC != SC_None)
+ OS << ' ' << VarDecl::getStorageClassSpecifierString(SC);
+ if (D->isThreadSpecified())
+ OS << " __thread";
+ if (D->isModulePrivate())
+ OS << " __module_private__";
+ if (D->isNRVOVariable())
+ OS << " nrvo";
+ if (D->hasInit()) {
+ lastChild();
+ dumpStmt(D->getInit());
+ }
+}
+
+void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) {
+ lastChild();
+ dumpStmt(D->getAsmString());
+}
+
+void ASTDumper::VisitImportDecl(const ImportDecl *D) {
+ OS << ' ' << D->getImportedModule()->getFullModuleName();
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Declarations
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitNamespaceDecl(const NamespaceDecl *D) {
+ dumpName(D);
+ if (D->isInline())
+ OS << " inline";
+ if (!D->isOriginalNamespace())
+ dumpDeclRef(D->getOriginalNamespace(), "original");
+}
+
+void ASTDumper::VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) {
+ OS << ' ';
+ dumpBareDeclRef(D->getNominatedNamespace());
+}
+
+void ASTDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getAliasedNamespace());
+}
+
+void ASTDumper::VisitTypeAliasDecl(const TypeAliasDecl *D) {
+ dumpName(D);
+ dumpType(D->getUnderlyingType());
+}
+
+void ASTDumper::VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) {
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+ dumpDecl(D->getTemplatedDecl());
+}
+
+void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) {
+ VisitRecordDecl(D);
+ if (!D->isCompleteDefinition())
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator I = D->bases_begin(),
+ E = D->bases_end();
+ I != E; ++I) {
+ IndentScope Indent(*this);
+ if (I->isVirtual())
+ OS << "virtual ";
+ dumpAccessSpecifier(I->getAccessSpecifier());
+ dumpType(I->getType());
+ if (I->isPackExpansion())
+ OS << "...";
+ }
+}
+
+void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) {
+ dumpStmt(D->getAssertExpr());
+ lastChild();
+ dumpStmt(D->getMessage());
+}
+
+void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+ dumpDecl(D->getTemplatedDecl());
+ for (FunctionTemplateDecl::spec_iterator I = D->spec_begin(),
+ E = D->spec_end();
+ I != E; ++I) {
+ FunctionTemplateDecl::spec_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
+ switch (I->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ if (D == D->getCanonicalDecl())
+ dumpDecl(*I);
+ else
+ dumpDeclRef(*I);
+ break;
+ case TSK_ExplicitSpecialization:
+ dumpDeclRef(*I);
+ break;
+ }
+ }
+}
+
+void ASTDumper::VisitClassTemplateDecl(const ClassTemplateDecl *D) {
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+
+ ClassTemplateDecl::spec_iterator I = D->spec_begin();
+ ClassTemplateDecl::spec_iterator E = D->spec_end();
+ if (I == E)
+ lastChild();
+ dumpDecl(D->getTemplatedDecl());
+ for (; I != E; ++I) {
+ ClassTemplateDecl::spec_iterator Next = I;
+ ++Next;
+ if (Next == E)
+ lastChild();
+ switch (I->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ case TSK_ImplicitInstantiation:
+ if (D == D->getCanonicalDecl())
+ dumpDecl(*I);
+ else
+ dumpDeclRef(*I);
+ break;
+ case TSK_ExplicitSpecialization:
+ case TSK_ExplicitInstantiationDeclaration:
+ case TSK_ExplicitInstantiationDefinition:
+ dumpDeclRef(*I);
+ break;
+ }
+ }
+}
+
+void ASTDumper::VisitClassTemplateSpecializationDecl(
+ const ClassTemplateSpecializationDecl *D) {
+ VisitCXXRecordDecl(D);
+ dumpTemplateArgumentList(D->getTemplateArgs());
+}
+
+void ASTDumper::VisitClassTemplatePartialSpecializationDecl(
+ const ClassTemplatePartialSpecializationDecl *D) {
+ VisitClassTemplateSpecializationDecl(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+}
+
+void ASTDumper::VisitClassScopeFunctionSpecializationDecl(
+ const ClassScopeFunctionSpecializationDecl *D) {
+ dumpDeclRef(D->getSpecialization());
+ if (D->hasExplicitTemplateArgs())
+ dumpTemplateArgumentListInfo(D->templateArgs());
+}
+
+void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) {
+ if (D->wasDeclaredWithTypename())
+ OS << " typename";
+ else
+ OS << " class";
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+ if (D->hasDefaultArgument())
+ dumpType(D->getDefaultArgument());
+}
+
+void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) {
+ dumpType(D->getType());
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+ if (D->hasDefaultArgument())
+ dumpStmt(D->getDefaultArgument());
+}
+
+void ASTDumper::VisitTemplateTemplateParmDecl(
+ const TemplateTemplateParmDecl *D) {
+ if (D->isParameterPack())
+ OS << " ...";
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+ if (D->hasDefaultArgument())
+ dumpTemplateArgumentLoc(D->getDefaultArgument());
+}
+
+void ASTDumper::VisitUsingDecl(const UsingDecl *D) {
+ OS << ' ';
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+}
+
+void ASTDumper::VisitUnresolvedUsingTypenameDecl(
+ const UnresolvedUsingTypenameDecl *D) {
+ OS << ' ';
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+}
+
+void ASTDumper::VisitUnresolvedUsingValueDecl(const UnresolvedUsingValueDecl *D) {
+ OS << ' ';
+ D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy());
+ OS << D->getNameAsString();
+ dumpType(D->getType());
+}
+
+void ASTDumper::VisitUsingShadowDecl(const UsingShadowDecl *D) {
+ OS << ' ';
+ dumpBareDeclRef(D->getTargetDecl());
+}
+
+void ASTDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) {
+ switch (D->getLanguage()) {
+ case LinkageSpecDecl::lang_c: OS << " C"; break;
+ case LinkageSpecDecl::lang_cxx: OS << " C++"; break;
+ }
+}
+
+void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) {
+ OS << ' ';
+ dumpAccessSpecifier(D->getAccess());
+}
+
+void ASTDumper::VisitFriendDecl(const FriendDecl *D) {
+ lastChild();
+ if (TypeSourceInfo *T = D->getFriendType())
+ dumpType(T->getType());
+ else
+ dumpDecl(D->getFriendDecl());
+}
+
+//===----------------------------------------------------------------------===//
+// Obj-C Declarations
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitObjCIvarDecl(const ObjCIvarDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+ if (D->getSynthesize())
+ OS << " synthesize";
+
+ switch (D->getAccessControl()) {
+ case ObjCIvarDecl::None:
+ OS << " none";
+ break;
+ case ObjCIvarDecl::Private:
+ OS << " private";
+ break;
+ case ObjCIvarDecl::Protected:
+ OS << " protected";
+ break;
+ case ObjCIvarDecl::Public:
+ OS << " public";
+ break;
+ case ObjCIvarDecl::Package:
+ OS << " package";
+ break;
+ }
+}
+
+void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) {
+ if (D->isInstanceMethod())
+ OS << " -";
+ else
+ OS << " +";
+ dumpName(D);
+ dumpType(D->getResultType());
+
+ bool OldMoreChildren = hasMoreChildren();
+ bool IsVariadic = D->isVariadic();
+ bool HasBody = D->hasBody();
+
+ setMoreChildren(OldMoreChildren || IsVariadic || HasBody);
+ if (D->isThisDeclarationADefinition()) {
+ lastChild();
+ dumpDeclContext(D);
+ } else {
+ for (ObjCMethodDecl::param_const_iterator I = D->param_begin(),
+ E = D->param_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+ }
+
+ setMoreChildren(OldMoreChildren || HasBody);
+ if (IsVariadic) {
+ lastChild();
+ IndentScope Indent(*this);
+ OS << "...";
+ }
+
+ setMoreChildren(OldMoreChildren);
+ if (HasBody) {
+ lastChild();
+ dumpStmt(D->getBody());
+ }
+}
+
+void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getClassInterface());
+ if (D->protocol_begin() == D->protocol_end())
+ lastChild();
+ dumpDeclRef(D->getImplementation());
+ for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDeclRef(*I);
+ }
+}
+
+void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getClassInterface());
+ lastChild();
+ dumpDeclRef(D->getCategoryDecl());
+}
+
+void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) {
+ dumpName(D);
+ for (ObjCProtocolDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDeclRef(*I);
+ }
+}
+
+void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getSuperClass(), "super");
+ if (D->protocol_begin() == D->protocol_end())
+ lastChild();
+ dumpDeclRef(D->getImplementation());
+ for (ObjCInterfaceDecl::protocol_iterator I = D->protocol_begin(),
+ E = D->protocol_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDeclRef(*I);
+ }
+}
+
+void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) {
+ dumpName(D);
+ dumpDeclRef(D->getSuperClass(), "super");
+ if (D->init_begin() == D->init_end())
+ lastChild();
+ dumpDeclRef(D->getClassInterface());
+ for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(),
+ E = D->init_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpCXXCtorInitializer(*I);
+ }
+}
+
+void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) {
+ dumpName(D);
+ lastChild();
+ dumpDeclRef(D->getClassInterface());
+}
+
+void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) {
+ dumpName(D);
+ dumpType(D->getType());
+
+ if (D->getPropertyImplementation() == ObjCPropertyDecl::Required)
+ OS << " required";
+ else if (D->getPropertyImplementation() == ObjCPropertyDecl::Optional)
+ OS << " optional";
+
+ ObjCPropertyDecl::PropertyAttributeKind Attrs = D->getPropertyAttributes();
+ if (Attrs != ObjCPropertyDecl::OBJC_PR_noattr) {
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_readonly)
+ OS << " readonly";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
+ OS << " assign";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_readwrite)
+ OS << " readwrite";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_retain)
+ OS << " retain";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_copy)
+ OS << " copy";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic)
+ OS << " nonatomic";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_atomic)
+ OS << " atomic";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_weak)
+ OS << " weak";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_strong)
+ OS << " strong";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained)
+ OS << " unsafe_unretained";
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) {
+ if (!(Attrs & ObjCPropertyDecl::OBJC_PR_setter))
+ lastChild();
+ dumpDeclRef(D->getGetterMethodDecl(), "getter");
+ }
+ if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) {
+ lastChild();
+ dumpDeclRef(D->getSetterMethodDecl(), "setter");
+ }
+ }
+}
+
+void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) {
+ dumpName(D->getPropertyDecl());
+ if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize)
+ OS << " synthesize";
+ else
+ OS << " dynamic";
+ dumpDeclRef(D->getPropertyDecl());
+ lastChild();
+ dumpDeclRef(D->getPropertyIvarDecl());
+}
+
+void ASTDumper::VisitBlockDecl(const BlockDecl *D) {
+ for (BlockDecl::param_const_iterator I = D->param_begin(), E = D->param_end();
+ I != E; ++I)
+ dumpDecl(*I);
+
+ if (D->isVariadic()) {
+ IndentScope Indent(*this);
+ OS << "...";
+ }
+
+ if (D->capturesCXXThis()) {
+ IndentScope Indent(*this);
+ OS << "capture this";
+ }
+ for (BlockDecl::capture_iterator I = D->capture_begin(), E = D->capture_end();
+ I != E; ++I) {
+ IndentScope Indent(*this);
+ OS << "capture";
+ if (I->isByRef())
+ OS << " byref";
+ if (I->isNested())
+ OS << " nested";
+ if (I->getVariable()) {
+ OS << ' ';
+ dumpBareDeclRef(I->getVariable());
+ }
+ if (I->hasCopyExpr())
+ dumpStmt(I->getCopyExpr());
+ }
+ lastChild();
+ dumpStmt(D->getBody());
+}
+
+//===----------------------------------------------------------------------===//
+// Stmt dumping methods.
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::dumpStmt(const Stmt *S) {
+ IndentScope Indent(*this);
+
+ if (!S) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+
+ if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+ VisitDeclStmt(DS);
+ return;
+ }
+
+ setMoreChildren(S->children());
+ ConstStmtVisitor<ASTDumper>::Visit(S);
+ setMoreChildren(false);
+ for (Stmt::const_child_range CI = S->children(); CI; ++CI) {
+ Stmt::const_child_range Next = CI;
+ ++Next;
+ if (!Next)
+ lastChild();
+ dumpStmt(*CI);
+ }
+}
+
+void ASTDumper::VisitStmt(const Stmt *Node) {
+ {
+ ColorScope Color(*this, StmtColor);
+ OS << Node->getStmtClassName();
+ }
+ dumpPointer(Node);
+ dumpSourceRange(Node->getSourceRange());
+}
+
+void ASTDumper::VisitDeclStmt(const DeclStmt *Node) {
+ VisitStmt(Node);
+ for (DeclStmt::const_decl_iterator I = Node->decl_begin(),
+ E = Node->decl_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpDecl(*I);
+ }
+}
+
+void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) {
+ VisitStmt(Node);
+ for (ArrayRef<const Attr *>::iterator I = Node->getAttrs().begin(),
+ E = Node->getAttrs().end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpAttr(*I);
+ }
+}
+
+void ASTDumper::VisitLabelStmt(const LabelStmt *Node) {
+ VisitStmt(Node);
+ OS << " '" << Node->getName() << "'";
+}
+
+void ASTDumper::VisitGotoStmt(const GotoStmt *Node) {
+ VisitStmt(Node);
+ OS << " '" << Node->getLabel()->getName() << "'";
+ dumpPointer(Node->getLabel());
+}
+
+//===----------------------------------------------------------------------===//
+// Expr dumping methods.
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitExpr(const Expr *Node) {
+ VisitStmt(Node);
+ dumpType(Node->getType());
+
+ {
+ ColorScope Color(*this, ValueKindColor);
+ switch (Node->getValueKind()) {
+ case VK_RValue:
+ break;
+ case VK_LValue:
+ OS << " lvalue";
+ break;
+ case VK_XValue:
+ OS << " xvalue";
+ break;
+ }
+ }
+
+ {
+ ColorScope Color(*this, ObjectKindColor);
+ switch (Node->getObjectKind()) {
+ case OK_Ordinary:
+ break;
+ case OK_BitField:
+ OS << " bitfield";
+ break;
+ case OK_ObjCProperty:
+ OS << " objcproperty";
+ break;
+ case OK_ObjCSubscript:
+ OS << " objcsubscript";
+ break;
+ case OK_VectorComponent:
+ OS << " vectorcomponent";
+ break;
+ }
+ }
+}
+
+static void dumpBasePath(raw_ostream &OS, const CastExpr *Node) {
+ if (Node->path_empty())
+ return;
+
+ OS << " (";
+ bool First = true;
+ for (CastExpr::path_const_iterator I = Node->path_begin(),
+ E = Node->path_end();
+ I != E; ++I) {
+ const CXXBaseSpecifier *Base = *I;
+ if (!First)
+ OS << " -> ";
+
+ const CXXRecordDecl *RD =
+ cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+
+ if (Base->isVirtual())
+ OS << "virtual ";
+ OS << RD->getName();
+ First = false;
+ }
+
+ OS << ')';
+}
+
+void ASTDumper::VisitCastExpr(const CastExpr *Node) {
+ VisitExpr(Node);
+ OS << " <";
+ {
+ ColorScope Color(*this, CastColor);
+ OS << Node->getCastKindName();
+ }
+ dumpBasePath(OS, Node);
+ OS << ">";
+}
+
+void ASTDumper::VisitDeclRefExpr(const DeclRefExpr *Node) {
+ VisitExpr(Node);
+
+ OS << " ";
+ dumpBareDeclRef(Node->getDecl());
+ if (Node->getDecl() != Node->getFoundDecl()) {
+ OS << " (";
+ dumpBareDeclRef(Node->getFoundDecl());
+ OS << ")";
+ }
+}
+
+void ASTDumper::VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node) {
+ VisitExpr(Node);
+ OS << " (";
+ if (!Node->requiresADL())
+ OS << "no ";
+ OS << "ADL) = '" << Node->getName() << '\'';
+
+ UnresolvedLookupExpr::decls_iterator
+ I = Node->decls_begin(), E = Node->decls_end();
+ if (I == E)
+ OS << " empty";
+ for (; I != E; ++I)
+ dumpPointer(*I);
+}
+
+void ASTDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) {
+ VisitExpr(Node);
+
+ {
+ ColorScope Color(*this, DeclKindNameColor);
+ OS << " " << Node->getDecl()->getDeclKindName() << "Decl";
+ }
+ OS << "='" << *Node->getDecl() << "'";
+ dumpPointer(Node->getDecl());
+ if (Node->isFreeIvar())
+ OS << " isFreeIvar";
+}
+
+void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) {
+ VisitExpr(Node);
+ switch (Node->getIdentType()) {
+ default: llvm_unreachable("unknown case");
+ case PredefinedExpr::Func: OS << " __func__"; break;
+ case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
+ case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
+ case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
+ }
+}
+
+void ASTDumper::VisitCharacterLiteral(const CharacterLiteral *Node) {
+ VisitExpr(Node);
+ ColorScope Color(*this, ValueColor);
+ OS << " " << Node->getValue();
+}
+
+void ASTDumper::VisitIntegerLiteral(const IntegerLiteral *Node) {
+ VisitExpr(Node);
+
+ bool isSigned = Node->getType()->isSignedIntegerType();
+ ColorScope Color(*this, ValueColor);
+ OS << " " << Node->getValue().toString(10, isSigned);
+}
+
+void ASTDumper::VisitFloatingLiteral(const FloatingLiteral *Node) {
+ VisitExpr(Node);
+ ColorScope Color(*this, ValueColor);
+ OS << " " << Node->getValueAsApproximateDouble();
+}
+
+void ASTDumper::VisitStringLiteral(const StringLiteral *Str) {
+ VisitExpr(Str);
+ ColorScope Color(*this, ValueColor);
+ OS << " ";
+ Str->outputString(OS);
+}
+
+void ASTDumper::VisitUnaryOperator(const UnaryOperator *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
+ << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
+}
+
+void ASTDumper::VisitUnaryExprOrTypeTraitExpr(
+ const UnaryExprOrTypeTraitExpr *Node) {
+ VisitExpr(Node);
+ switch(Node->getKind()) {
+ case UETT_SizeOf:
+ OS << " sizeof";
+ break;
+ case UETT_AlignOf:
+ OS << " alignof";
+ break;
+ case UETT_VecStep:
+ OS << " vec_step";
+ break;
+ }
+ if (Node->isArgumentType())
+ dumpType(Node->getArgumentType());
+}
+
+void ASTDumper::VisitMemberExpr(const MemberExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl();
+ dumpPointer(Node->getMemberDecl());
+}
+
+void ASTDumper::VisitExtVectorElementExpr(const ExtVectorElementExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << Node->getAccessor().getNameStart();
+}
+
+void ASTDumper::VisitBinaryOperator(const BinaryOperator *Node) {
+ VisitExpr(Node);
+ OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
+}
+
+void ASTDumper::VisitCompoundAssignOperator(
+ const CompoundAssignOperator *Node) {
+ VisitExpr(Node);
+ OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
+ << "' ComputeLHSTy=";
+ dumpBareType(Node->getComputationLHSType());
+ OS << " ComputeResultTy=";
+ dumpBareType(Node->getComputationResultType());
+}
+
+void ASTDumper::VisitBlockExpr(const BlockExpr *Node) {
+ VisitExpr(Node);
+ dumpDecl(Node->getBlockDecl());
+}
+
+void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) {
+ VisitExpr(Node);
+
+ if (Expr *Source = Node->getSourceExpr()) {
+ lastChild();
+ dumpStmt(Source);
+ }
+}
+
+// GNU extensions.
+
+void ASTDumper::VisitAddrLabelExpr(const AddrLabelExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << Node->getLabel()->getName();
+ dumpPointer(Node->getLabel());
+}
+
+//===----------------------------------------------------------------------===//
+// C++ Expressions
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitCXXNamedCastExpr(const CXXNamedCastExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << Node->getCastName()
+ << "<" << Node->getTypeAsWritten().getAsString() << ">"
+ << " <" << Node->getCastKindName();
+ dumpBasePath(OS, Node);
+ OS << ">";
+}
+
+void ASTDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->getValue() ? "true" : "false");
+}
+
+void ASTDumper::VisitCXXThisExpr(const CXXThisExpr *Node) {
+ VisitExpr(Node);
+ OS << " this";
+}
+
+void ASTDumper::VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node) {
+ VisitExpr(Node);
+ OS << " functional cast to " << Node->getTypeAsWritten().getAsString()
+ << " <" << Node->getCastKindName() << ">";
+}
+
+void ASTDumper::VisitCXXConstructExpr(const CXXConstructExpr *Node) {
+ VisitExpr(Node);
+ CXXConstructorDecl *Ctor = Node->getConstructor();
+ dumpType(Ctor->getType());
+ if (Node->isElidable())
+ OS << " elidable";
+ if (Node->requiresZeroInitialization())
+ OS << " zeroing";
+}
+
+void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) {
+ VisitExpr(Node);
+ OS << " ";
+ dumpCXXTemporary(Node->getTemporary());
+}
+
+void ASTDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) {
+ VisitExpr(Node);
+ for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i)
+ dumpDeclRef(Node->getObject(i), "cleanup");
+}
+
+void ASTDumper::dumpCXXTemporary(const CXXTemporary *Temporary) {
+ OS << "(CXXTemporary";
+ dumpPointer(Temporary);
+ OS << ")";
+}
+
+//===----------------------------------------------------------------------===//
+// Obj-C Expressions
+//===----------------------------------------------------------------------===//
+
+void ASTDumper::VisitObjCMessageExpr(const ObjCMessageExpr *Node) {
+ VisitExpr(Node);
+ OS << " selector=" << Node->getSelector().getAsString();
+ switch (Node->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ break;
+
+ case ObjCMessageExpr::Class:
+ OS << " class=";
+ dumpBareType(Node->getClassReceiver());
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ OS << " super (instance)";
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ OS << " super (class)";
+ break;
+ }
+}
+
+void ASTDumper::VisitObjCBoxedExpr(const ObjCBoxedExpr *Node) {
+ VisitExpr(Node);
+ OS << " selector=" << Node->getBoxingMethod()->getSelector().getAsString();
+}
+
+void ASTDumper::VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node) {
+ VisitStmt(Node);
+ if (const VarDecl *CatchParam = Node->getCatchParamDecl())
+ dumpDecl(CatchParam);
+ else
+ OS << " catch all";
+}
+
+void ASTDumper::VisitObjCEncodeExpr(const ObjCEncodeExpr *Node) {
+ VisitExpr(Node);
+ dumpType(Node->getEncodedType());
+}
+
+void ASTDumper::VisitObjCSelectorExpr(const ObjCSelectorExpr *Node) {
+ VisitExpr(Node);
+
+ OS << " " << Node->getSelector().getAsString();
+}
+
+void ASTDumper::VisitObjCProtocolExpr(const ObjCProtocolExpr *Node) {
+ VisitExpr(Node);
+
+ OS << ' ' << *Node->getProtocol();
+}
+
+void ASTDumper::VisitObjCPropertyRefExpr(const ObjCPropertyRefExpr *Node) {
+ VisitExpr(Node);
+ if (Node->isImplicitProperty()) {
+ OS << " Kind=MethodRef Getter=\"";
+ if (Node->getImplicitPropertyGetter())
+ OS << Node->getImplicitPropertyGetter()->getSelector().getAsString();
+ else
+ OS << "(null)";
+
+ OS << "\" Setter=\"";
+ if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter())
+ OS << Setter->getSelector().getAsString();
+ else
+ OS << "(null)";
+ OS << "\"";
+ } else {
+ OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"';
+ }
+
+ if (Node->isSuperReceiver())
+ OS << " super";
+
+ OS << " Messaging=";
+ if (Node->isMessagingGetter() && Node->isMessagingSetter())
+ OS << "Getter&Setter";
+ else if (Node->isMessagingGetter())
+ OS << "Getter";
+ else if (Node->isMessagingSetter())
+ OS << "Setter";
+}
+
+void ASTDumper::VisitObjCSubscriptRefExpr(const ObjCSubscriptRefExpr *Node) {
+ VisitExpr(Node);
+ if (Node->isArraySubscriptRefExpr())
+ OS << " Kind=ArraySubscript GetterForArray=\"";
+ else
+ OS << " Kind=DictionarySubscript GetterForDictionary=\"";
+ if (Node->getAtIndexMethodDecl())
+ OS << Node->getAtIndexMethodDecl()->getSelector().getAsString();
+ else
+ OS << "(null)";
+
+ if (Node->isArraySubscriptRefExpr())
+ OS << "\" SetterForArray=\"";
+ else
+ OS << "\" SetterForDictionary=\"";
+ if (Node->setAtIndexMethodDecl())
+ OS << Node->setAtIndexMethodDecl()->getSelector().getAsString();
+ else
+ OS << "(null)";
+}
+
+void ASTDumper::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *Node) {
+ VisitExpr(Node);
+ OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no");
+}
+
+//===----------------------------------------------------------------------===//
+// Comments
+//===----------------------------------------------------------------------===//
+
+const char *ASTDumper::getCommandName(unsigned CommandID) {
+ if (Traits)
+ return Traits->getCommandInfo(CommandID)->Name;
+ const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
+ if (Info)
+ return Info->Name;
+ return "<not a builtin command>";
+}
+
+void ASTDumper::dumpFullComment(const FullComment *C) {
+ if (!C)
+ return;
+
+ FC = C;
+ dumpComment(C);
+ FC = 0;
+}
+
+void ASTDumper::dumpComment(const Comment *C) {
+ IndentScope Indent(*this);
+
+ if (!C) {
+ ColorScope Color(*this, NullColor);
+ OS << "<<<NULL>>>";
+ return;
+ }
+
+ {
+ ColorScope Color(*this, CommentColor);
+ OS << C->getCommentKindName();
+ }
+ dumpPointer(C);
+ dumpSourceRange(C->getSourceRange());
+ ConstCommentVisitor<ASTDumper>::visit(C);
+ for (Comment::child_iterator I = C->child_begin(), E = C->child_end();
+ I != E; ++I) {
+ if (I + 1 == E)
+ lastChild();
+ dumpComment(*I);
+ }
+}
+
+void ASTDumper::visitTextComment(const TextComment *C) {
+ OS << " Text=\"" << C->getText() << "\"";
+}
+
+void ASTDumper::visitInlineCommandComment(const InlineCommandComment *C) {
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
+ switch (C->getRenderKind()) {
+ case InlineCommandComment::RenderNormal:
+ OS << " RenderNormal";
+ break;
+ case InlineCommandComment::RenderBold:
+ OS << " RenderBold";
+ break;
+ case InlineCommandComment::RenderMonospaced:
+ OS << " RenderMonospaced";
+ break;
+ case InlineCommandComment::RenderEmphasized:
+ OS << " RenderEmphasized";
+ break;
+ }
+
+ for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
+ OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
+}
+
+void ASTDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
+ OS << " Name=\"" << C->getTagName() << "\"";
+ if (C->getNumAttrs() != 0) {
+ OS << " Attrs: ";
+ for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
+ const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
+ OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
+ }
+ }
+ if (C->isSelfClosing())
+ OS << " SelfClosing";
+}
+
+void ASTDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
+ OS << " Name=\"" << C->getTagName() << "\"";
+}
+
+void ASTDumper::visitBlockCommandComment(const BlockCommandComment *C) {
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
+ for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
+ OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
+}
+
+void ASTDumper::visitParamCommandComment(const ParamCommandComment *C) {
+ OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection());
+
+ if (C->isDirectionExplicit())
+ OS << " explicitly";
+ else
+ OS << " implicitly";
+
+ if (C->hasParamName()) {
+ if (C->isParamIndexValid())
+ OS << " Param=\"" << C->getParamName(FC) << "\"";
+ else
+ OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
+ }
+
+ if (C->isParamIndexValid())
+ OS << " ParamIndex=" << C->getParamIndex();
+}
+
+void ASTDumper::visitTParamCommandComment(const TParamCommandComment *C) {
+ if (C->hasParamName()) {
+ if (C->isPositionValid())
+ OS << " Param=\"" << C->getParamName(FC) << "\"";
+ else
+ OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
+ }
+
+ if (C->isPositionValid()) {
+ OS << " Position=<";
+ for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
+ OS << C->getIndex(i);
+ if (i != e - 1)
+ OS << ", ";
+ }
+ OS << ">";
+ }
+}
+
+void ASTDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
+ OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""
+ " CloseName=\"" << C->getCloseName() << "\"";
+}
+
+void ASTDumper::visitVerbatimBlockLineComment(
+ const VerbatimBlockLineComment *C) {
+ OS << " Text=\"" << C->getText() << "\"";
+}
+
+void ASTDumper::visitVerbatimLineComment(const VerbatimLineComment *C) {
+ OS << " Text=\"" << C->getText() << "\"";
+}
+
+//===----------------------------------------------------------------------===//
+// Decl method implementations
+//===----------------------------------------------------------------------===//
+
+void Decl::dump() const {
+ dump(llvm::errs());
+}
+
+void Decl::dump(raw_ostream &OS) const {
+ ASTDumper P(OS, &getASTContext().getCommentCommandTraits(),
+ &getASTContext().getSourceManager());
+ P.dumpDecl(this);
+}
+
+void Decl::dumpColor() const {
+ ASTDumper P(llvm::errs(), &getASTContext().getCommentCommandTraits(),
+ &getASTContext().getSourceManager(), /*ShowColors*/true);
+ P.dumpDecl(this);
+}
+//===----------------------------------------------------------------------===//
+// Stmt method implementations
+//===----------------------------------------------------------------------===//
+
+void Stmt::dump(SourceManager &SM) const {
+ dump(llvm::errs(), SM);
+}
+
+void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
+ ASTDumper P(OS, 0, &SM);
+ P.dumpStmt(this);
+}
+
+void Stmt::dump() const {
+ ASTDumper P(llvm::errs(), 0, 0);
+ P.dumpStmt(this);
+}
+
+void Stmt::dumpColor() const {
+ ASTDumper P(llvm::errs(), 0, 0, /*ShowColors*/true);
+ P.dumpStmt(this);
+}
+
+//===----------------------------------------------------------------------===//
+// Comment method implementations
+//===----------------------------------------------------------------------===//
+
+void Comment::dump() const {
+ dump(llvm::errs(), 0, 0);
+}
+
+void Comment::dump(const ASTContext &Context) const {
+ dump(llvm::errs(), &Context.getCommentCommandTraits(),
+ &Context.getSourceManager());
+}
+
+void Comment::dump(raw_ostream &OS, const CommandTraits *Traits,
+ const SourceManager *SM) const {
+ const FullComment *FC = dyn_cast<FullComment>(this);
+ ASTDumper D(OS, Traits, SM);
+ D.dumpFullComment(FC);
+}
+
+void Comment::dumpColor() const {
+ const FullComment *FC = dyn_cast<FullComment>(this);
+ ASTDumper D(llvm::errs(), 0, 0, /*ShowColors*/true);
+ D.dumpFullComment(FC);
+}
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 0d4f303af2b5..d2e6d2970531 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTImporter.h"
-
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/DeclCXX.h"
@@ -122,6 +121,7 @@ namespace clang {
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord,
bool Complain = true);
bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
+ bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC);
bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To);
Decl *VisitDecl(Decl *D);
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
@@ -206,12 +206,16 @@ namespace {
/// \brief Whether to complain about failures.
bool Complain;
+ /// \brief \c true if the last diagnostic came from C2.
+ bool LastDiagFromC2;
+
StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2,
llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls,
bool StrictTypeSpelling = false,
bool Complain = true)
: C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls),
- StrictTypeSpelling(StrictTypeSpelling), Complain(Complain) { }
+ StrictTypeSpelling(StrictTypeSpelling), Complain(Complain),
+ LastDiagFromC2(false) {}
/// \brief Determine whether the two declarations are structurally
/// equivalent.
@@ -229,11 +233,17 @@ namespace {
public:
DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) {
assert(Complain && "Not allowed to complain");
+ if (LastDiagFromC2)
+ C1.getDiagnostics().notePriorDiagnosticFrom(C2.getDiagnostics());
+ LastDiagFromC2 = false;
return C1.getDiagnostics().Report(Loc, DiagID);
}
DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) {
assert(Complain && "Not allowed to complain");
+ if (!LastDiagFromC2)
+ C2.getDiagnostics().notePriorDiagnosticFrom(C1.getDiagnostics());
+ LastDiagFromC2 = true;
return C2.getDiagnostics().Report(Loc, DiagID);
}
};
@@ -892,14 +902,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
/// including the next assigned index (if none of them match). Returns an
/// empty option if the context is not a record, i.e.. if the anonymous
/// struct/union is at namespace or block scope.
-static llvm::Optional<unsigned>
-findAnonymousStructOrUnionIndex(RecordDecl *Anon) {
+static Optional<unsigned> findAnonymousStructOrUnionIndex(RecordDecl *Anon) {
ASTContext &Context = Anon->getASTContext();
QualType AnonTy = Context.getRecordType(Anon);
RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
if (!Owner)
- return llvm::Optional<unsigned>();
+ return None;
unsigned Index = 0;
for (DeclContext::decl_iterator D = Owner->noload_decls_begin(),
@@ -934,10 +943,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
- if (llvm::Optional<unsigned> Index1
- = findAnonymousStructOrUnionIndex(D1)) {
- if (llvm::Optional<unsigned> Index2
- = findAnonymousStructOrUnionIndex(D2)) {
+ if (Optional<unsigned> Index1 = findAnonymousStructOrUnionIndex(D1)) {
+ if (Optional<unsigned> Index2 = findAnonymousStructOrUnionIndex(D2)) {
if (*Index1 != *Index2)
return false;
}
@@ -1612,8 +1619,7 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) {
ToEPI.ExceptionSpecTemplate = cast_or_null<FunctionDecl>(
Importer.Import(FromEPI.ExceptionSpecTemplate));
- return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(),
- ArgTypes.size(), ToEPI);
+ return Importer.getToContext().getFunctionType(ToResultType, ArgTypes, ToEPI);
}
QualType ASTNodeImporter::VisitParenType(const ParenType *T) {
@@ -1825,7 +1831,7 @@ void ASTNodeImporter::ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD) {
if (RecordDecl *FromRecord = dyn_cast<RecordDecl>(FromD)) {
if (RecordDecl *ToRecord = cast_or_null<RecordDecl>(ToD)) {
- if (FromRecord->getDefinition() && !ToRecord->getDefinition()) {
+ if (FromRecord->getDefinition() && FromRecord->isCompleteDefinition() && !ToRecord->getDefinition()) {
ImportDefinition(FromRecord, ToRecord);
}
}
@@ -1907,11 +1913,7 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data();
struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data();
ToData.UserDeclaredConstructor = FromData.UserDeclaredConstructor;
- ToData.UserDeclaredCopyConstructor = FromData.UserDeclaredCopyConstructor;
- ToData.UserDeclaredMoveConstructor = FromData.UserDeclaredMoveConstructor;
- ToData.UserDeclaredCopyAssignment = FromData.UserDeclaredCopyAssignment;
- ToData.UserDeclaredMoveAssignment = FromData.UserDeclaredMoveAssignment;
- ToData.UserDeclaredDestructor = FromData.UserDeclaredDestructor;
+ ToData.UserDeclaredSpecialMembers = FromData.UserDeclaredSpecialMembers;
ToData.Aggregate = FromData.Aggregate;
ToData.PlainOldData = FromData.PlainOldData;
ToData.Empty = FromData.Empty;
@@ -1925,30 +1927,41 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To,
ToData.HasMutableFields = FromData.HasMutableFields;
ToData.HasOnlyCMembers = FromData.HasOnlyCMembers;
ToData.HasInClassInitializer = FromData.HasInClassInitializer;
- ToData.HasTrivialDefaultConstructor = FromData.HasTrivialDefaultConstructor;
+ ToData.HasUninitializedReferenceMember
+ = FromData.HasUninitializedReferenceMember;
+ ToData.NeedOverloadResolutionForMoveConstructor
+ = FromData.NeedOverloadResolutionForMoveConstructor;
+ ToData.NeedOverloadResolutionForMoveAssignment
+ = FromData.NeedOverloadResolutionForMoveAssignment;
+ ToData.NeedOverloadResolutionForDestructor
+ = FromData.NeedOverloadResolutionForDestructor;
+ ToData.DefaultedMoveConstructorIsDeleted
+ = FromData.DefaultedMoveConstructorIsDeleted;
+ ToData.DefaultedMoveAssignmentIsDeleted
+ = FromData.DefaultedMoveAssignmentIsDeleted;
+ ToData.DefaultedDestructorIsDeleted = FromData.DefaultedDestructorIsDeleted;
+ ToData.HasTrivialSpecialMembers = FromData.HasTrivialSpecialMembers;
+ ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
ToData.HasConstexprNonCopyMoveConstructor
= FromData.HasConstexprNonCopyMoveConstructor;
ToData.DefaultedDefaultConstructorIsConstexpr
= FromData.DefaultedDefaultConstructorIsConstexpr;
ToData.HasConstexprDefaultConstructor
= FromData.HasConstexprDefaultConstructor;
- ToData.HasTrivialCopyConstructor = FromData.HasTrivialCopyConstructor;
- ToData.HasTrivialMoveConstructor = FromData.HasTrivialMoveConstructor;
- ToData.HasTrivialCopyAssignment = FromData.HasTrivialCopyAssignment;
- ToData.HasTrivialMoveAssignment = FromData.HasTrivialMoveAssignment;
- ToData.HasTrivialDestructor = FromData.HasTrivialDestructor;
- ToData.HasIrrelevantDestructor = FromData.HasIrrelevantDestructor;
ToData.HasNonLiteralTypeFieldsOrBases
= FromData.HasNonLiteralTypeFieldsOrBases;
// ComputedVisibleConversions not imported.
ToData.UserProvidedDefaultConstructor
= FromData.UserProvidedDefaultConstructor;
- ToData.DeclaredDefaultConstructor = FromData.DeclaredDefaultConstructor;
- ToData.DeclaredCopyConstructor = FromData.DeclaredCopyConstructor;
- ToData.DeclaredMoveConstructor = FromData.DeclaredMoveConstructor;
- ToData.DeclaredCopyAssignment = FromData.DeclaredCopyAssignment;
- ToData.DeclaredMoveAssignment = FromData.DeclaredMoveAssignment;
- ToData.DeclaredDestructor = FromData.DeclaredDestructor;
+ ToData.DeclaredSpecialMembers = FromData.DeclaredSpecialMembers;
+ ToData.ImplicitCopyConstructorHasConstParam
+ = FromData.ImplicitCopyConstructorHasConstParam;
+ ToData.ImplicitCopyAssignmentHasConstParam
+ = FromData.ImplicitCopyAssignmentHasConstParam;
+ ToData.HasDeclaredCopyConstructorWithConstParam
+ = FromData.HasDeclaredCopyConstructorWithConstParam;
+ ToData.HasDeclaredCopyAssignmentWithConstParam
+ = FromData.HasDeclaredCopyAssignmentWithConstParam;
ToData.FailedImplicitMoveConstructor
= FromData.FailedImplicitMoveConstructor;
ToData.FailedImplicitMoveAssignment = FromData.FailedImplicitMoveAssignment;
@@ -2143,7 +2156,18 @@ bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
return Ctx.IsStructurallyEquivalent(FromEnum, ToEnum);
}
-bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
+bool ASTNodeImporter::IsStructuralMatch(EnumConstantDecl *FromEC,
+ EnumConstantDecl *ToEC)
+{
+ const llvm::APSInt &FromVal = FromEC->getInitVal();
+ const llvm::APSInt &ToVal = ToEC->getInitVal();
+
+ return FromVal.isSigned() == ToVal.isSigned() &&
+ FromVal.getBitWidth() == ToVal.getBitWidth() &&
+ FromVal == ToVal;
+}
+
+bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From,
ClassTemplateDecl *To) {
StructuralEquivalenceContext Ctx(Importer.getFromContext(),
Importer.getToContext(),
@@ -2185,7 +2209,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) {
MergeWithNamespace = cast<NamespaceDecl>(DC)->getAnonymousNamespace();
} else {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Namespace))
@@ -2248,7 +2272,7 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) {
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2328,7 +2352,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
// We may already have an enum of the same name; try to find and match it.
if (!DC->isFunctionOrMethod() && SearchName) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(SearchName, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2414,7 +2438,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
RecordDecl *AdoptDecl = 0;
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(SearchName, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2431,10 +2455,10 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
FoundRecord->isAnonymousStructOrUnion()) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
- if (llvm::Optional<unsigned> Index1
+ if (Optional<unsigned> Index1
= findAnonymousStructOrUnionIndex(D)) {
- if (llvm::Optional<unsigned> Index2
- = findAnonymousStructOrUnionIndex(FoundRecord)) {
+ if (Optional<unsigned> Index2 =
+ findAnonymousStructOrUnionIndex(FoundRecord)) {
if (*Index1 != *Index2)
continue;
}
@@ -2521,12 +2545,18 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
if (!LexicalDC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
continue;
-
+
+ if (EnumConstantDecl *FoundEnumConstant
+ = dyn_cast<EnumConstantDecl>(FoundDecls[I])) {
+ if (IsStructuralMatch(D, FoundEnumConstant))
+ return Importer.Imported(D, FoundEnumConstant);
+ }
+
ConflictingDecls.push_back(FoundDecls[I]);
}
@@ -2567,7 +2597,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
if (!LexicalDC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -2629,8 +2659,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
FunctionProtoType::ExtProtoInfo DefaultEPI;
FromTy = Importer.getFromContext().getFunctionType(
FromFPT->getResultType(),
- FromFPT->arg_type_begin(),
- FromFPT->arg_type_end() - FromFPT->arg_type_begin(),
+ ArrayRef<QualType>(FromFPT->arg_type_begin(),
+ FromFPT->getNumArgs()),
DefaultEPI);
usedDifferentExceptionSpec = true;
}
@@ -2686,8 +2716,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
cast<CXXRecordDecl>(DC),
D->getInnerLocStart(),
NameInfo, T, TInfo,
- Method->isStatic(),
- Method->getStorageClassAsWritten(),
+ Method->getStorageClass(),
Method->isInlineSpecified(),
D->isConstexpr(),
Importer.Import(D->getLocEnd()));
@@ -2695,7 +2724,6 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToFunction = FunctionDecl::Create(Importer.getToContext(), DC,
D->getInnerLocStart(),
NameInfo, T, TInfo, D->getStorageClass(),
- D->getStorageClassAsWritten(),
D->isInlineSpecified(),
D->hasWrittenPrototype(),
D->isConstexpr());
@@ -2777,7 +2805,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
return 0;
// Determine whether we've already imported this field.
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (FieldDecl *FoundField = dyn_cast<FieldDecl>(FoundDecls[I])) {
@@ -2833,7 +2861,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
return 0;
// Determine whether we've already imported this field.
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (IndirectFieldDecl *FoundField
@@ -2898,7 +2926,7 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) {
return 0;
// Determine whether we've already imported this ivar
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(FoundDecls[I])) {
@@ -2953,7 +2981,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
VarDecl *MergeWithVar = 0;
SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(IDNS))
@@ -3046,8 +3074,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo,
- D->getStorageClass(),
- D->getStorageClassAsWritten());
+ D->getStorageClass());
ToVar->setQualifierInfo(Importer.Import(D->getQualifierLoc()));
ToVar->setAccess(D->getAccess());
ToVar->setLexicalDeclContext(LexicalDC);
@@ -3115,7 +3142,6 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
Importer.Import(D->getInnerLocStart()),
Loc, Name.getAsIdentifierInfo(),
T, TInfo, D->getStorageClass(),
- D->getStorageClassAsWritten(),
/*FIXME: Default argument*/ 0);
ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg());
return Importer.Imported(D, ToParm);
@@ -3129,7 +3155,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
return 0;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCMethodDecl *FoundMethod = dyn_cast<ObjCMethodDecl>(FoundDecls[I])) {
@@ -3376,7 +3402,7 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
return 0;
ObjCProtocolDecl *MergeWithProtocol = 0;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol))
@@ -3480,10 +3506,13 @@ bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From,
// Import categories. When the categories themselves are imported, they'll
// hook themselves into this interface.
- for (ObjCCategoryDecl *FromCat = From->getCategoryList(); FromCat;
- FromCat = FromCat->getNextClassCategory())
- Importer.Import(FromCat);
-
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = From->known_categories_begin(),
+ CatEnd = From->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ Importer.Import(*Cat);
+ }
+
// If we have an @implementation, import it as well.
if (From->getImplementation()) {
ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>(
@@ -3523,7 +3552,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
// Look for an existing interface with the same name.
ObjCInterfaceDecl *MergeWithIface = 0;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
@@ -3675,7 +3704,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
return 0;
// Check whether we have already imported this property.
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (ObjCPropertyDecl *FoundProp
@@ -3908,7 +3937,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// We may already have a template of the same name; try to find and match it.
if (!DC->isFunctionOrMethod()) {
SmallVector<NamedDecl *, 4> ConflictingDecls;
- llvm::SmallVector<NamedDecl *, 2> FoundDecls;
+ SmallVector<NamedDecl *, 2> FoundDecls;
DC->localUncachedLookup(Name, FoundDecls);
for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary))
@@ -4295,7 +4324,7 @@ ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
bool MinimalImport)
: ToContext(ToContext), FromContext(FromContext),
ToFileManager(ToFileManager), FromFileManager(FromFileManager),
- Minimal(MinimalImport)
+ Minimal(MinimalImport), LastDiagFromFrom(false)
{
ImportedDecls[FromContext.getTranslationUnitDecl()]
= ToContext.getTranslationUnitDecl();
@@ -4798,10 +4827,18 @@ DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name,
}
DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) {
+ if (LastDiagFromFrom)
+ ToContext.getDiagnostics().notePriorDiagnosticFrom(
+ FromContext.getDiagnostics());
+ LastDiagFromFrom = false;
return ToContext.getDiagnostics().Report(Loc, DiagID);
}
DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) {
+ if (!LastDiagFromFrom)
+ FromContext.getDiagnostics().notePriorDiagnosticFrom(
+ ToContext.getDiagnostics());
+ LastDiagFromFrom = true;
return FromContext.getDiagnostics().Report(Loc, DiagID);
}
diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp
index cffcc6501eff..daf65e56bdc6 100644
--- a/lib/AST/AttrImpl.cpp
+++ b/lib/AST/AttrImpl.cpp
@@ -13,8 +13,8 @@
#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Type.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
using namespace clang;
Attr::~Attr() { }
@@ -23,4 +23,6 @@ void InheritableAttr::anchor() { }
void InheritableParamAttr::anchor() { }
+void MSInheritanceAttr::anchor() { }
+
#include "clang/AST/AttrImpl.inc"
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index d20d77ef7ea5..e804fe720558 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -5,13 +5,13 @@ add_clang_library(clangAST
ASTConsumer.cpp
ASTContext.cpp
ASTDiagnostic.cpp
+ ASTDumper.cpp
ASTImporter.cpp
AttrImpl.cpp
CXXInheritance.cpp
Comment.cpp
CommentBriefParser.cpp
CommentCommandTraits.cpp
- CommentDumper.cpp
CommentLexer.cpp
CommentParser.cpp
CommentSema.cpp
@@ -22,6 +22,7 @@ add_clang_library(clangAST
DeclFriend.cpp
DeclGroup.cpp
DeclObjC.cpp
+ DeclOpenMP.cpp
DeclPrinter.cpp
DeclTemplate.cpp
DumpXML.cpp
@@ -45,7 +46,6 @@ add_clang_library(clangAST
RecordLayoutBuilder.cpp
SelectorLocationsKind.cpp
Stmt.cpp
- StmtDumper.cpp
StmtIterator.cpp
StmtPrinter.cpp
StmtProfile.cpp
@@ -64,10 +64,13 @@ add_dependencies(clangAST
ClangAttrClasses
ClangAttrList
ClangAttrImpl
+ ClangAttrDump
ClangCommentCommandInfo
+ ClangCommentCommandList
ClangCommentNodes
ClangCommentHTMLTags
ClangCommentHTMLTagsProperties
+ ClangCommentHTMLNamedCharacterReferences
ClangDeclNodes
ClangDiagnosticAST
ClangDiagnosticComment
diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h
index 0d9c869d87ca..6d67d9a12b55 100644
--- a/lib/AST/CXXABI.h
+++ b/lib/AST/CXXABI.h
@@ -27,9 +27,9 @@ class CXXABI {
public:
virtual ~CXXABI();
- /// Returns the size of a member pointer in multiples of the target
- /// pointer size.
- virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0;
+ /// Returns the width and alignment of a member pointer in bits.
+ virtual std::pair<uint64_t, unsigned>
+ getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const = 0;
/// Returns the default calling convention for C++ methods.
virtual CallingConv getDefaultMethodCallConv(bool isVariadic) const = 0;
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 213b214a4e4c..0e0b35d92adf 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecordLayout.h"
#include "llvm/ADT/SetVector.h"
#include <algorithm>
#include <set>
@@ -28,7 +28,7 @@ void CXXBasePaths::ComputeDeclsFound() {
llvm::SetVector<NamedDecl *, SmallVector<NamedDecl *, 8> > Decls;
for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path)
- Decls.insert(*Path->Decls.first);
+ Decls.insert(Path->Decls.front());
NumDeclsFound = Decls.size();
DeclsFound = new NamedDecl * [NumDeclsFound];
@@ -118,7 +118,19 @@ static bool BaseIsNot(const CXXRecordDecl *Base, void *OpaqueTarget) {
}
bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const {
- return forallBases(BaseIsNot, (void*) Base->getCanonicalDecl());
+ return forallBases(BaseIsNot,
+ const_cast<CXXRecordDecl *>(Base->getCanonicalDecl()));
+}
+
+bool
+CXXRecordDecl::isCurrentInstantiation(const DeclContext *CurContext) const {
+ assert(isDependentContext());
+
+ for (; !CurContext->isFileContext(); CurContext = CurContext->getParent())
+ if (CurContext->Equals(this))
+ return true;
+
+ return false;
}
bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
@@ -140,7 +152,9 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches,
CXXRecordDecl *Base =
cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition());
- if (!Base) {
+ if (!Base ||
+ (Base->isDependentContext() &&
+ !Base->isCurrentInstantiation(Record))) {
if (AllowShortCircuit) return false;
AllMatches = false;
continue;
@@ -384,9 +398,9 @@ bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
- if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
+ if (Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag))
return true;
}
@@ -402,9 +416,9 @@ bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member;
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
- if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS))
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
+ if (Path.Decls.front()->isInIdentifierNamespace(IDNS))
return true;
}
@@ -420,11 +434,11 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
for (Path.Decls = BaseRecord->lookup(N);
- Path.Decls.first != Path.Decls.second;
- ++Path.Decls.first) {
+ !Path.Decls.empty();
+ Path.Decls = Path.Decls.slice(1)) {
// FIXME: Refactor the "is it a nested-name-specifier?" check
- if (isa<TypedefNameDecl>(*Path.Decls.first) ||
- (*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag))
+ if (isa<TypedefNameDecl>(Path.Decls.front()) ||
+ Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag))
return true;
}
@@ -725,4 +739,3 @@ CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const {
AddIndirectPrimaryBases(BaseDecl, Context, Bases);
}
}
-
diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp
index 361f8ac61c2a..db55c045449d 100644
--- a/lib/AST/Comment.cpp
+++ b/lib/AST/Comment.cpp
@@ -32,20 +32,6 @@ const char *Comment::getCommentKindName() const {
llvm_unreachable("Unknown comment kind!");
}
-void Comment::dump() const {
- // It is important that Comment::dump() is defined in a different TU than
- // Comment::dump(raw_ostream, SourceManager). If both functions were defined
- // in CommentDumper.cpp, that object file would be removed by linker because
- // none of its functions are referenced by other object files, despite the
- // LLVM_ATTRIBUTE_USED.
- dump(llvm::errs(), NULL, NULL);
-}
-
-void Comment::dump(const ASTContext &Context) const {
- dump(llvm::errs(), &Context.getCommentCommandTraits(),
- &Context.getSourceManager());
-}
-
namespace {
struct good {};
struct bad {};
@@ -255,32 +241,32 @@ void DeclInfo::fill() {
while (true) {
TL = TL.IgnoreParens();
// Look through qualified types.
- if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) {
- TL = QualifiedTL->getUnqualifiedLoc();
+ if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) {
+ TL = QualifiedTL.getUnqualifiedLoc();
continue;
}
// Look through pointer types.
- if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) {
- TL = PointerTL->getPointeeLoc().getUnqualifiedLoc();
+ if (PointerTypeLoc PointerTL = TL.getAs<PointerTypeLoc>()) {
+ TL = PointerTL.getPointeeLoc().getUnqualifiedLoc();
continue;
}
- if (BlockPointerTypeLoc *BlockPointerTL =
- dyn_cast<BlockPointerTypeLoc>(&TL)) {
- TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc();
+ if (BlockPointerTypeLoc BlockPointerTL =
+ TL.getAs<BlockPointerTypeLoc>()) {
+ TL = BlockPointerTL.getPointeeLoc().getUnqualifiedLoc();
continue;
}
- if (MemberPointerTypeLoc *MemberPointerTL =
- dyn_cast<MemberPointerTypeLoc>(&TL)) {
- TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc();
+ if (MemberPointerTypeLoc MemberPointerTL =
+ TL.getAs<MemberPointerTypeLoc>()) {
+ TL = MemberPointerTL.getPointeeLoc().getUnqualifiedLoc();
continue;
}
// Is this a typedef for a function type?
- if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) {
+ if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) {
Kind = FunctionKind;
- ArrayRef<ParmVarDecl *> Params = FTL->getParams();
+ ArrayRef<ParmVarDecl *> Params = FTL.getParams();
ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(),
Params.size());
- ResultType = FTL->getResultLoc().getType();
+ ResultType = FTL.getResultLoc().getType();
break;
}
break;
diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp
index 95daa7e3f809..090b9211d4c1 100644
--- a/lib/AST/CommentBriefParser.cpp
+++ b/lib/AST/CommentBriefParser.cpp
@@ -78,7 +78,7 @@ std::string BriefParser::Parse() {
continue;
}
- if (Tok.is(tok::command)) {
+ if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) {
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
if (Info->IsBriefCommand) {
FirstParagraphOrBrief.clear();
diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp
index e7e40fd1090f..e24d542c9623 100644
--- a/lib/AST/CommentCommandTraits.cpp
+++ b/lib/AST/CommentCommandTraits.cpp
@@ -15,9 +15,21 @@ namespace comments {
#include "clang/AST/CommentCommandInfo.inc"
-CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator) :
- NextID(llvm::array_lengthof(Commands)), Allocator(Allocator)
-{ }
+CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator,
+ const CommentOptions &CommentOptions) :
+ NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) {
+ registerCommentOptions(CommentOptions);
+}
+
+void CommandTraits::registerCommentOptions(
+ const CommentOptions &CommentOptions) {
+ for (CommentOptions::BlockCommandNamesTy::const_iterator
+ I = CommentOptions.BlockCommandNames.begin(),
+ E = CommentOptions.BlockCommandNames.end();
+ I != E; I++) {
+ registerBlockCommand(*I);
+ }
+}
const CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const {
if (const CommandInfo *Info = getBuiltinCommandInfo(Name))
@@ -31,7 +43,7 @@ const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const {
return getRegisteredCommandInfo(CommandID);
}
-const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName) {
+CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {
char *Name = Allocator.Allocate<char>(CommandName.size() + 1);
memcpy(Name, CommandName.data(), CommandName.size());
Name[CommandName.size()] = '\0';
@@ -40,13 +52,25 @@ const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName)
CommandInfo *Info = new (Allocator) CommandInfo();
Info->Name = Name;
Info->ID = NextID++;
- Info->IsUnknownCommand = true;
RegisteredCommands.push_back(Info);
return Info;
}
+const CommandInfo *CommandTraits::registerUnknownCommand(
+ StringRef CommandName) {
+ CommandInfo *Info = createCommandInfoWithName(CommandName);
+ Info->IsUnknownCommand = true;
+ return Info;
+}
+
+const CommandInfo *CommandTraits::registerBlockCommand(StringRef CommandName) {
+ CommandInfo *Info = createCommandInfoWithName(CommandName);
+ Info->IsBlockCommand = true;
+ return Info;
+}
+
const CommandInfo *CommandTraits::getBuiltinCommandInfo(
unsigned CommandID) {
if (CommandID < llvm::array_lengthof(Commands))
diff --git a/lib/AST/CommentDumper.cpp b/lib/AST/CommentDumper.cpp
deleted file mode 100644
index 19d24b2f3a03..000000000000
--- a/lib/AST/CommentDumper.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-//===--- CommentDumper.cpp - Dumping implementation for Comment ASTs ------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/CommentVisitor.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace clang {
-namespace comments {
-
-namespace {
-class CommentDumper: public comments::ConstCommentVisitor<CommentDumper> {
- raw_ostream &OS;
- const CommandTraits *Traits;
- const SourceManager *SM;
-
- /// The \c FullComment parent of the comment being dumped.
- const FullComment *FC;
-
- unsigned IndentLevel;
-
-public:
- CommentDumper(raw_ostream &OS,
- const CommandTraits *Traits,
- const SourceManager *SM,
- const FullComment *FC) :
- OS(OS), Traits(Traits), SM(SM), FC(FC), IndentLevel(0)
- { }
-
- void dumpIndent() const {
- for (unsigned i = 1, e = IndentLevel; i < e; ++i)
- OS << " ";
- }
-
- void dumpLocation(SourceLocation Loc) {
- if (SM)
- Loc.print(OS, *SM);
- }
-
- void dumpSourceRange(const Comment *C);
-
- void dumpComment(const Comment *C);
-
- void dumpSubtree(const Comment *C);
-
- // Inline content.
- void visitTextComment(const TextComment *C);
- void visitInlineCommandComment(const InlineCommandComment *C);
- void visitHTMLStartTagComment(const HTMLStartTagComment *C);
- void visitHTMLEndTagComment(const HTMLEndTagComment *C);
-
- // Block content.
- void visitParagraphComment(const ParagraphComment *C);
- void visitBlockCommandComment(const BlockCommandComment *C);
- void visitParamCommandComment(const ParamCommandComment *C);
- void visitTParamCommandComment(const TParamCommandComment *C);
- void visitVerbatimBlockComment(const VerbatimBlockComment *C);
- void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
- void visitVerbatimLineComment(const VerbatimLineComment *C);
-
- void visitFullComment(const FullComment *C);
-
- const char *getCommandName(unsigned CommandID) {
- if (Traits)
- return Traits->getCommandInfo(CommandID)->Name;
- const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
- if (Info)
- return Info->Name;
- return "<not a builtin command>";
- }
-};
-
-void CommentDumper::dumpSourceRange(const Comment *C) {
- if (!SM)
- return;
-
- SourceRange SR = C->getSourceRange();
-
- OS << " <";
- dumpLocation(SR.getBegin());
- if (SR.getBegin() != SR.getEnd()) {
- OS << ", ";
- dumpLocation(SR.getEnd());
- }
- OS << ">";
-}
-
-void CommentDumper::dumpComment(const Comment *C) {
- dumpIndent();
- OS << "(" << C->getCommentKindName()
- << " " << (const void *) C;
- dumpSourceRange(C);
-}
-
-void CommentDumper::dumpSubtree(const Comment *C) {
- ++IndentLevel;
- if (C) {
- visit(C);
- for (Comment::child_iterator I = C->child_begin(),
- E = C->child_end();
- I != E; ++I) {
- OS << '\n';
- dumpSubtree(*I);
- }
- OS << ')';
- } else {
- dumpIndent();
- OS << "<<<NULL>>>";
- }
- --IndentLevel;
-}
-
-void CommentDumper::visitTextComment(const TextComment *C) {
- dumpComment(C);
-
- OS << " Text=\"" << C->getText() << "\"";
-}
-
-void CommentDumper::visitInlineCommandComment(const InlineCommandComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
- switch (C->getRenderKind()) {
- case InlineCommandComment::RenderNormal:
- OS << " RenderNormal";
- break;
- case InlineCommandComment::RenderBold:
- OS << " RenderBold";
- break;
- case InlineCommandComment::RenderMonospaced:
- OS << " RenderMonospaced";
- break;
- case InlineCommandComment::RenderEmphasized:
- OS << " RenderEmphasized";
- break;
- }
-
- for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
- OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
-}
-
-void CommentDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << C->getTagName() << "\"";
- if (C->getNumAttrs() != 0) {
- OS << " Attrs: ";
- for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
- const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
- OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
- }
- }
- if (C->isSelfClosing())
- OS << " SelfClosing";
-}
-
-void CommentDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << C->getTagName() << "\"";
-}
-
-void CommentDumper::visitParagraphComment(const ParagraphComment *C) {
- dumpComment(C);
-}
-
-void CommentDumper::visitBlockCommandComment(const BlockCommandComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"";
- for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
- OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
-}
-
-void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) {
- dumpComment(C);
-
- OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection());
-
- if (C->isDirectionExplicit())
- OS << " explicitly";
- else
- OS << " implicitly";
-
- if (C->hasParamName()) {
- if (C->isParamIndexValid())
- OS << " Param=\"" << C->getParamName(FC) << "\"";
- else
- OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
- }
-
- if (C->isParamIndexValid())
- OS << " ParamIndex=" << C->getParamIndex();
-}
-
-void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) {
- dumpComment(C);
-
- if (C->hasParamName()) {
- if (C->isPositionValid())
- OS << " Param=\"" << C->getParamName(FC) << "\"";
- else
- OS << " Param=\"" << C->getParamNameAsWritten() << "\"";
- }
-
- if (C->isPositionValid()) {
- OS << " Position=<";
- for (unsigned i = 0, e = C->getDepth(); i != e; ++i) {
- OS << C->getIndex(i);
- if (i != e - 1)
- OS << ", ";
- }
- OS << ">";
- }
-}
-
-void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
- dumpComment(C);
-
- OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""
- " CloseName=\"" << C->getCloseName() << "\"";
-}
-
-void CommentDumper::visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C) {
- dumpComment(C);
-
- OS << " Text=\"" << C->getText() << "\"";
-}
-
-void CommentDumper::visitVerbatimLineComment(const VerbatimLineComment *C) {
- dumpComment(C);
-
- OS << " Text=\"" << C->getText() << "\"";
-}
-
-void CommentDumper::visitFullComment(const FullComment *C) {
- dumpComment(C);
-}
-
-} // unnamed namespace
-
-void Comment::dump(llvm::raw_ostream &OS, const CommandTraits *Traits,
- const SourceManager *SM) const {
- const FullComment *FC = dyn_cast<FullComment>(this);
- CommentDumper D(llvm::errs(), Traits, SM, FC);
- D.dumpSubtree(this);
- llvm::errs() << '\n';
-}
-
-} // end namespace comments
-} // end namespace clang
-
diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp
index 31a09f71d993..1194520bf360 100644
--- a/lib/AST/CommentLexer.cpp
+++ b/lib/AST/CommentLexer.cpp
@@ -1,7 +1,9 @@
#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentCommandTraits.h"
-#include "clang/Basic/ConvertUTF.h"
+#include "clang/Basic/CharInfo.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/ErrorHandling.h"
namespace clang {
@@ -13,34 +15,46 @@ void Token::dump(const Lexer &L, const SourceManager &SM) const {
llvm::errs() << " " << Length << " \"" << L.getSpelling(*this, SM) << "\"\n";
}
-namespace {
-bool isHTMLNamedCharacterReferenceCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z');
+static inline bool isHTMLNamedCharacterReferenceCharacter(char C) {
+ return isLetter(C);
}
-bool isHTMLDecimalCharacterReferenceCharacter(char C) {
- return C >= '0' && C <= '9';
+static inline bool isHTMLDecimalCharacterReferenceCharacter(char C) {
+ return isDigit(C);
}
-bool isHTMLHexCharacterReferenceCharacter(char C) {
- return (C >= '0' && C <= '9') ||
- (C >= 'a' && C <= 'f') ||
- (C >= 'A' && C <= 'F');
+static inline bool isHTMLHexCharacterReferenceCharacter(char C) {
+ return isHexDigit(C);
}
+static inline StringRef convertCodePointToUTF8(
+ llvm::BumpPtrAllocator &Allocator,
+ unsigned CodePoint) {
+ char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT);
+ char *ResolvedPtr = Resolved;
+ if (llvm::ConvertCodePointToUTF8(CodePoint, ResolvedPtr))
+ return StringRef(Resolved, ResolvedPtr - Resolved);
+ else
+ return StringRef();
+}
+
+namespace {
+
#include "clang/AST/CommentHTMLTags.inc"
+#include "clang/AST/CommentHTMLNamedCharacterReferences.inc"
} // unnamed namespace
StringRef Lexer::resolveHTMLNamedCharacterReference(StringRef Name) const {
+ // Fast path, first check a few most widely used named character references.
return llvm::StringSwitch<StringRef>(Name)
.Case("amp", "&")
.Case("lt", "<")
.Case("gt", ">")
.Case("quot", "\"")
.Case("apos", "\'")
- .Default("");
+ // Slow path.
+ .Default(translateHTMLNamedCharacterReferenceToUTF8(Name));
}
StringRef Lexer::resolveHTMLDecimalCharacterReference(StringRef Name) const {
@@ -50,13 +64,7 @@ StringRef Lexer::resolveHTMLDecimalCharacterReference(StringRef Name) const {
CodePoint *= 10;
CodePoint += Name[i] - '0';
}
-
- char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT);
- char *ResolvedPtr = Resolved;
- if (ConvertCodePointToUTF8(CodePoint, ResolvedPtr))
- return StringRef(Resolved, ResolvedPtr - Resolved);
- else
- return StringRef();
+ return convertCodePointToUTF8(Allocator, CodePoint);
}
StringRef Lexer::resolveHTMLHexCharacterReference(StringRef Name) const {
@@ -65,20 +73,9 @@ StringRef Lexer::resolveHTMLHexCharacterReference(StringRef Name) const {
CodePoint *= 16;
const char C = Name[i];
assert(isHTMLHexCharacterReferenceCharacter(C));
- if (C >= '0' && C <= '9')
- CodePoint += Name[i] - '0';
- else if (C >= 'a' && C <= 'f')
- CodePoint += Name[i] - 'a' + 10;
- else
- CodePoint += Name[i] - 'A' + 10;
+ CodePoint += llvm::hexDigitValue(C);
}
-
- char *Resolved = Allocator.Allocate<char>(UNI_MAX_UTF8_BYTES_PER_CODE_POINT);
- char *ResolvedPtr = Resolved;
- if (ConvertCodePointToUTF8(CodePoint, ResolvedPtr))
- return StringRef(Resolved, ResolvedPtr - Resolved);
- else
- return StringRef();
+ return convertCodePointToUTF8(Allocator, CodePoint);
}
void Lexer::skipLineStartingDecorations() {
@@ -99,7 +96,7 @@ void Lexer::skipLineStartingDecorations() {
return;
char C = *NewBufferPtr;
- while (C == ' ' || C == '\t' || C == '\f' || C == '\v') {
+ while (isHorizontalWhitespace(C)) {
NewBufferPtr++;
if (NewBufferPtr == CommentEnd)
return;
@@ -119,8 +116,7 @@ namespace {
/// Returns pointer to the first newline character in the string.
const char *findNewline(const char *BufferPtr, const char *BufferEnd) {
for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
- const char C = *BufferPtr;
- if (C == '\n' || C == '\r')
+ if (isVerticalWhitespace(*BufferPtr))
return BufferPtr;
}
return BufferEnd;
@@ -169,14 +165,11 @@ const char *skipHexCharacterReference(const char *BufferPtr,
}
bool isHTMLIdentifierStartingCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z');
+ return isLetter(C);
}
bool isHTMLIdentifierCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z') ||
- (C >= '0' && C <= '9');
+ return isAlphanumeric(C);
}
const char *skipHTMLIdentifier(const char *BufferPtr, const char *BufferEnd) {
@@ -205,15 +198,6 @@ const char *skipHTMLQuotedString(const char *BufferPtr, const char *BufferEnd)
return BufferEnd;
}
-bool isHorizontalWhitespace(char C) {
- return C == ' ' || C == '\t' || C == '\f' || C == '\v';
-}
-
-bool isWhitespace(char C) {
- return C == ' ' || C == '\n' || C == '\r' ||
- C == '\t' || C == '\f' || C == '\v';
-}
-
const char *skipWhitespace(const char *BufferPtr, const char *BufferEnd) {
for ( ; BufferPtr != BufferEnd; ++BufferPtr) {
if (!isWhitespace(*BufferPtr))
@@ -227,14 +211,11 @@ bool isWhitespace(const char *BufferPtr, const char *BufferEnd) {
}
bool isCommandNameStartCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z');
+ return isLetter(C);
}
bool isCommandNameCharacter(char C) {
- return (C >= 'a' && C <= 'z') ||
- (C >= 'A' && C <= 'Z') ||
- (C >= '0' && C <= '9');
+ return isAlphanumeric(C);
}
const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) {
@@ -250,12 +231,10 @@ const char *skipCommandName(const char *BufferPtr, const char *BufferEnd) {
const char *findBCPLCommentEnd(const char *BufferPtr, const char *BufferEnd) {
const char *CurPtr = BufferPtr;
while (CurPtr != BufferEnd) {
- char C = *CurPtr;
- while (C != '\n' && C != '\r') {
+ while (!isVerticalWhitespace(*CurPtr)) {
CurPtr++;
if (CurPtr == BufferEnd)
return BufferEnd;
- C = *CurPtr;
}
// We found a newline, check if it is escaped.
const char *EscapePtr = CurPtr - 1;
@@ -319,6 +298,11 @@ void Lexer::lexCommentText(Token &T) {
switch(*TokenPtr) {
case '\\':
case '@': {
+ // Commands that start with a backslash and commands that start with
+ // 'at' have equivalent semantics. But we keep information about the
+ // exact syntax in AST for comments.
+ tok::TokenKind CommandKind =
+ (*TokenPtr == '@') ? tok::at_command : tok::backslash_command;
TokenPtr++;
if (TokenPtr == CommentEnd) {
formTextToken(T, TokenPtr);
@@ -379,7 +363,7 @@ void Lexer::lexCommentText(Token &T) {
setupAndLexVerbatimLine(T, TokenPtr, Info);
return;
}
- formTokenWithChars(T, TokenPtr, tok::command);
+ formTokenWithChars(T, TokenPtr, CommandKind);
T.setCommandID(Info->getID());
return;
}
@@ -415,15 +399,12 @@ void Lexer::lexCommentText(Token &T) {
return;
default: {
- while (true) {
- TokenPtr++;
- if (TokenPtr == CommentEnd)
- break;
- const char C = *TokenPtr;
- if(C == '\n' || C == '\r' ||
- C == '\\' || C == '@' || C == '&' || C == '<')
- break;
- }
+ size_t End = StringRef(TokenPtr, CommentEnd - TokenPtr).
+ find_first_of("\n\r\\@&<");
+ if (End != StringRef::npos)
+ TokenPtr += End;
+ else
+ TokenPtr = CommentEnd;
formTextToken(T, TokenPtr);
return;
}
@@ -446,13 +427,11 @@ void Lexer::setupAndLexVerbatimBlock(Token &T,
// If there is a newline following the verbatim opening command, skip the
// newline so that we don't create an tok::verbatim_block_line with empty
// text content.
- if (BufferPtr != CommentEnd) {
- const char C = *BufferPtr;
- if (C == '\n' || C == '\r') {
- BufferPtr = skipNewline(BufferPtr, CommentEnd);
- State = LS_VerbatimBlockBody;
- return;
- }
+ if (BufferPtr != CommentEnd &&
+ isVerticalWhitespace(*BufferPtr)) {
+ BufferPtr = skipNewline(BufferPtr, CommentEnd);
+ State = LS_VerbatimBlockBody;
+ return;
}
State = LS_VerbatimBlockFirstLine;
diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp
index d0a84741b6f2..09912c618864 100644
--- a/lib/AST/CommentParser.cpp
+++ b/lib/AST/CommentParser.cpp
@@ -8,9 +8,10 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CommentParser.h"
-#include "clang/AST/CommentSema.h"
-#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentDiagnostic.h"
+#include "clang/AST/CommentSema.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/ErrorHandling.h"
@@ -109,11 +110,6 @@ class TextTokenRetokenizer {
return true;
}
- static bool isWhitespace(char C) {
- return C == ' ' || C == '\n' || C == '\r' ||
- C == '\t' || C == '\f' || C == '\v';
- }
-
void consumeWhitespace() {
while (!isEnd()) {
if (isWhitespace(peek()))
@@ -175,8 +171,7 @@ public:
memcpy(TextPtr, WordText.c_str(), Length + 1);
StringRef Text = StringRef(TextPtr, Length);
- formTokenWithChars(Tok, Loc, WordBegin,
- Pos.BufferPtr - WordBegin, Text);
+ formTokenWithChars(Tok, Loc, WordBegin, Length, Text);
return true;
}
@@ -305,7 +300,7 @@ void Parser::parseBlockCommandArgs(BlockCommandComment *BC,
}
BlockCommandComment *Parser::parseBlockCommand() {
- assert(Tok.is(tok::command));
+ assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
ParamCommandComment *PC;
TParamCommandComment *TPC;
@@ -313,25 +308,29 @@ BlockCommandComment *Parser::parseBlockCommand() {
bool IsParam = false;
bool IsTParam = false;
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
+ CommandMarkerKind CommandMarker =
+ Tok.is(tok::backslash_command) ? CMK_Backslash : CMK_At;
if (Info->IsParamCommand) {
IsParam = true;
PC = S.actOnParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
- } if (Info->IsTParamCommand) {
+ Tok.getCommandID(),
+ CommandMarker);
+ } else if (Info->IsTParamCommand) {
IsTParam = true;
TPC = S.actOnTParamCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
+ Tok.getCommandID(),
+ CommandMarker);
} else {
BC = S.actOnBlockCommandStart(Tok.getLocation(),
Tok.getEndLocation(),
- Tok.getCommandID());
+ Tok.getCommandID(),
+ CommandMarker);
}
consumeToken();
- if (Tok.is(tok::command) &&
- Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand) {
+ if (isTokBlockCommand()) {
// Block command ahead. We can't nest block commands, so pretend that this
// command has an empty argument.
ParagraphComment *Paragraph = S.actOnParagraphComment(
@@ -363,10 +362,28 @@ BlockCommandComment *Parser::parseBlockCommand() {
Retokenizer.putBackLeftoverTokens();
}
- BlockContentComment *Block = parseParagraphOrBlockCommand();
- // Since we have checked for a block command, we should have parsed a
- // paragraph.
- ParagraphComment *Paragraph = cast<ParagraphComment>(Block);
+ // If there's a block command ahead, we will attach an empty paragraph to
+ // this command.
+ bool EmptyParagraph = false;
+ if (isTokBlockCommand())
+ EmptyParagraph = true;
+ else if (Tok.is(tok::newline)) {
+ Token PrevTok = Tok;
+ consumeToken();
+ EmptyParagraph = isTokBlockCommand();
+ putBack(PrevTok);
+ }
+
+ ParagraphComment *Paragraph;
+ if (EmptyParagraph)
+ Paragraph = S.actOnParagraphComment(ArrayRef<InlineContentComment *>());
+ else {
+ BlockContentComment *Block = parseParagraphOrBlockCommand();
+ // Since we have checked for a block command, we should have parsed a
+ // paragraph.
+ Paragraph = cast<ParagraphComment>(Block);
+ }
+
if (IsParam) {
S.actOnParamCommandFinish(PC, Paragraph);
return PC;
@@ -380,7 +397,7 @@ BlockCommandComment *Parser::parseBlockCommand() {
}
InlineCommandComment *Parser::parseInlineCommand() {
- assert(Tok.is(tok::command));
+ assert(Tok.is(tok::backslash_command) || Tok.is(tok::at_command));
const Token CommandTok = Tok;
consumeToken();
@@ -547,7 +564,8 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
consumeToken();
continue;
- case tok::command: {
+ case tok::backslash_command:
+ case tok::at_command: {
const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
if (Info->IsBlockCommand) {
if (Content.size() == 0)
@@ -557,6 +575,7 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() {
if (Info->IsVerbatimBlockEndCommand) {
Diag(Tok.getLocation(),
diag::warn_verbatim_block_end_without_start)
+ << Tok.is(tok::at_command)
<< Info->Name
<< SourceRange(Tok.getLocation(), Tok.getEndLocation());
consumeToken();
@@ -694,7 +713,8 @@ BlockContentComment *Parser::parseBlockContent() {
switch (Tok.getKind()) {
case tok::text:
case tok::unknown_command:
- case tok::command:
+ case tok::backslash_command:
+ case tok::at_command:
case tok::html_start_tag:
case tok::html_end_tag:
return parseParagraphOrBlockCommand();
diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp
index 08ecb3a994d7..e0138d5f3f27 100644
--- a/lib/AST/CommentSema.cpp
+++ b/lib/AST/CommentSema.cpp
@@ -8,14 +8,15 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CommentSema.h"
-#include "clang/AST/CommentDiagnostic.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentDiagnostic.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
namespace clang {
namespace comments {
@@ -28,7 +29,8 @@ Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
DiagnosticsEngine &Diags, CommandTraits &Traits,
const Preprocessor *PP) :
Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
- PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) {
+ PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL),
+ HeaderfileCommand(NULL) {
}
void Sema::setDecl(const Decl *D) {
@@ -45,10 +47,16 @@ ParagraphComment *Sema::actOnParagraphComment(
return new (Allocator) ParagraphComment(Content);
}
-BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
- return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID);
+BlockCommandComment *Sema::actOnBlockCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
+ BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
+ CommandID,
+ CommandMarker);
+ checkContainerDecl(BC);
+ return BC;
}
void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
@@ -65,20 +73,139 @@ void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
checkDeprecatedCommand(Command);
}
-ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
+ParamCommandComment *Sema::actOnParamCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
ParamCommandComment *Command =
- new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID);
+ new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
+ CommandMarker);
if (!isFunctionDecl())
Diag(Command->getLocation(),
diag::warn_doc_param_not_attached_to_a_function_decl)
+ << CommandMarker
<< Command->getCommandNameRange(Traits);
return Command;
}
+void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsFunctionDeclarationCommand)
+ return;
+
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_function:
+ DiagSelect = !isAnyFunctionDecl() ? 1 : 0;
+ break;
+ case CommandTraits::KCI_functiongroup:
+ DiagSelect = !isAnyFunctionDecl() ? 2 : 0;
+ break;
+ case CommandTraits::KCI_method:
+ DiagSelect = !isObjCMethodDecl() ? 3 : 0;
+ break;
+ case CommandTraits::KCI_methodgroup:
+ DiagSelect = !isObjCMethodDecl() ? 4 : 0;
+ break;
+ case CommandTraits::KCI_callback:
+ DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1) << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
+void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsRecordLikeDeclarationCommand)
+ return;
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_class:
+ DiagSelect = !isClassOrStructDecl() ? 1 : 0;
+ break;
+ case CommandTraits::KCI_interface:
+ DiagSelect = !isObjCInterfaceDecl() ? 2 : 0;
+ break;
+ case CommandTraits::KCI_protocol:
+ DiagSelect = !isObjCProtocolDecl() ? 3 : 0;
+ break;
+ case CommandTraits::KCI_struct:
+ DiagSelect = !isClassOrStructDecl() ? 4 : 0;
+ break;
+ case CommandTraits::KCI_union:
+ DiagSelect = !isUnionDecl() ? 5 : 0;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1) << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
+void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
+ const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
+ if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl())
+ return;
+ unsigned DiagSelect;
+ switch (Comment->getCommandID()) {
+ case CommandTraits::KCI_classdesign:
+ DiagSelect = 1;
+ break;
+ case CommandTraits::KCI_coclass:
+ DiagSelect = 2;
+ break;
+ case CommandTraits::KCI_dependency:
+ DiagSelect = 3;
+ break;
+ case CommandTraits::KCI_helper:
+ DiagSelect = 4;
+ break;
+ case CommandTraits::KCI_helperclass:
+ DiagSelect = 5;
+ break;
+ case CommandTraits::KCI_helps:
+ DiagSelect = 6;
+ break;
+ case CommandTraits::KCI_instancesize:
+ DiagSelect = 7;
+ break;
+ case CommandTraits::KCI_ownership:
+ DiagSelect = 8;
+ break;
+ case CommandTraits::KCI_performance:
+ DiagSelect = 9;
+ break;
+ case CommandTraits::KCI_security:
+ DiagSelect = 10;
+ break;
+ case CommandTraits::KCI_superclass:
+ DiagSelect = 11;
+ break;
+ default:
+ DiagSelect = 0;
+ break;
+ }
+ if (DiagSelect)
+ Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
+ << Comment->getCommandMarker()
+ << (DiagSelect-1)
+ << Comment->getSourceRange();
+}
+
void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
SourceLocation ArgLocBegin,
SourceLocation ArgLocEnd,
@@ -158,15 +285,19 @@ void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
checkBlockCommandEmptyParagraph(Command);
}
-TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin,
- SourceLocation LocEnd,
- unsigned CommandID) {
+TParamCommandComment *Sema::actOnTParamCommandStart(
+ SourceLocation LocBegin,
+ SourceLocation LocEnd,
+ unsigned CommandID,
+ CommandMarkerKind CommandMarker) {
TParamCommandComment *Command =
- new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID);
+ new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
+ CommandMarker);
if (!isTemplateOrSpecialization())
Diag(Command->getLocation(),
diag::warn_doc_tparam_not_attached_to_a_template_decl)
+ << CommandMarker
<< Command->getCommandNameRange(Traits);
return Command;
@@ -324,12 +455,15 @@ VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
unsigned CommandID,
SourceLocation TextBegin,
StringRef Text) {
- return new (Allocator) VerbatimLineComment(
+ VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
LocBegin,
TextBegin.getLocWithOffset(Text.size()),
CommandID,
TextBegin,
Text);
+ checkFunctionDeclVerbatimLine(VL);
+ checkContainerDeclVerbatimLine(VL);
+ return VL;
}
HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
@@ -430,6 +564,7 @@ void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
if (!DiagLoc.isValid())
DiagLoc = Command->getCommandNameRange(Traits).getEnd();
Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< Command->getSourceRange();
}
@@ -457,14 +592,19 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
}
Diag(Command->getLocation(),
diag::warn_doc_returns_attached_to_a_void_function)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< DiagKind
<< Command->getSourceRange();
}
return;
}
+ else if (isObjCPropertyDecl())
+ return;
+
Diag(Command->getLocation(),
diag::warn_doc_returns_not_attached_to_a_function_decl)
+ << Command->getCommandMarker()
<< Command->getCommandName(Traits)
<< Command->getSourceRange();
}
@@ -484,6 +624,12 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
return;
}
PrevCommand = ReturnsCommand;
+ } else if (Info->IsHeaderfileCommand) {
+ if (!HeaderfileCommand) {
+ HeaderfileCommand = Command;
+ return;
+ }
+ PrevCommand = HeaderfileCommand;
} else {
// We don't want to check this command for duplicates.
return;
@@ -491,15 +637,18 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
StringRef CommandName = Command->getCommandName(Traits);
StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
+ << Command->getCommandMarker()
<< CommandName
<< Command->getSourceRange();
if (CommandName == PrevCommandName)
Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
+ << PrevCommand->getCommandMarker()
<< PrevCommandName
<< PrevCommand->getSourceRange();
else
Diag(PrevCommand->getLocation(),
diag::note_doc_block_command_previous_alias)
+ << PrevCommand->getCommandMarker()
<< PrevCommandName
<< CommandName;
}
@@ -559,11 +708,11 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) {
return;
}
- llvm::SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
+ SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
// Comment AST nodes that correspond to \c ParamVars for which we have
// found a \\param command or NULL if no documentation was found so far.
- llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs;
+ SmallVector<ParamCommandComment *, 8> ParamVarDocs;
ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
ParamVarDocs.resize(ParamVars.size(), NULL);
@@ -596,7 +745,7 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) {
}
// Find parameter declarations that have no corresponding \\param.
- llvm::SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
+ SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
if (!ParamVarDocs[i])
OrphanedParamDecls.push_back(ParamVars[i]);
@@ -645,6 +794,40 @@ bool Sema::isFunctionDecl() {
return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
}
+bool Sema::isAnyFunctionDecl() {
+ return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
+ isa<FunctionDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+bool Sema::isObjCMethodDecl() {
+ return isFunctionDecl() && ThisDeclInfo->CurrentDecl &&
+ isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+/// isFunctionPointerVarDecl - returns 'true' if declaration is a pointer to
+/// function decl.
+bool Sema::isFunctionPointerVarDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
+ if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
+ QualType QT = VD->getType();
+ return QT->isFunctionPointerType();
+ }
+ }
+ return false;
+}
+
+bool Sema::isObjCPropertyDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
+}
+
bool Sema::isTemplateOrSpecialization() {
if (!ThisDeclInfo)
return false;
@@ -653,6 +836,54 @@ bool Sema::isTemplateOrSpecialization() {
return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
}
+bool Sema::isRecordLikeDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return isUnionDecl() || isClassOrStructDecl()
+ || isObjCInterfaceDecl() || isObjCProtocolDecl();
+}
+
+bool Sema::isUnionDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ if (const RecordDecl *RD =
+ dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
+ return RD->isUnion();
+ return false;
+}
+
+bool Sema::isClassOrStructDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<RecordDecl>(ThisDeclInfo->CurrentDecl) &&
+ !isUnionDecl();
+}
+
+bool Sema::isObjCInterfaceDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
+}
+
+bool Sema::isObjCProtocolDecl() {
+ if (!ThisDeclInfo)
+ return false;
+ if (!ThisDeclInfo->IsFilled)
+ inspectThisDecl();
+ return ThisDeclInfo->CurrentDecl &&
+ isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
+}
+
ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
if (!ThisDeclInfo->IsFilled)
inspectThisDecl();
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 7b13755979f1..bf807aeb1d69 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -12,23 +12,24 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Decl.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/TypeLoc.h"
-#include "clang/AST/Stmt.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
-#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/ErrorHandling.h"
-
+#include "llvm/Support/type_traits.h"
#include <algorithm>
using namespace clang;
@@ -37,17 +38,163 @@ using namespace clang;
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
-static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
+// Visibility rules aren't rigorously externally specified, but here
+// are the basic principles behind what we implement:
+//
+// 1. An explicit visibility attribute is generally a direct expression
+// of the user's intent and should be honored. Only the innermost
+// visibility attribute applies. If no visibility attribute applies,
+// global visibility settings are considered.
+//
+// 2. There is one caveat to the above: on or in a template pattern,
+// an explicit visibility attribute is just a default rule, and
+// visibility can be decreased by the visibility of template
+// arguments. But this, too, has an exception: an attribute on an
+// explicit specialization or instantiation causes all the visibility
+// restrictions of the template arguments to be ignored.
+//
+// 3. A variable that does not otherwise have explicit visibility can
+// be restricted by the visibility of its type.
+//
+// 4. A visibility restriction is explicit if it comes from an
+// attribute (or something like it), not a global visibility setting.
+// When emitting a reference to an external symbol, visibility
+// restrictions are ignored unless they are explicit.
+//
+// 5. When computing the visibility of a non-type, including a
+// non-type member of a class, only non-type visibility restrictions
+// are considered: the 'visibility' attribute, global value-visibility
+// settings, and a few special cases like __private_extern.
+//
+// 6. When computing the visibility of a type, including a type member
+// of a class, only type visibility restrictions are considered:
+// the 'type_visibility' attribute and global type-visibility settings.
+// However, a 'visibility' attribute counts as a 'type_visibility'
+// attribute on any declaration that only has the former.
+//
+// The visibility of a "secondary" entity, like a template argument,
+// is computed using the kind of that entity, not the kind of the
+// primary entity for which we are computing visibility. For example,
+// the visibility of a specialization of either of these templates:
+// template <class T, bool (&compare)(T, X)> bool has_match(list<T>, X);
+// template <class T, bool (&compare)(T, X)> class matcher;
+// is restricted according to the type visibility of the argument 'T',
+// the type visibility of 'bool(&)(T,X)', and the value visibility of
+// the argument function 'compare'. That 'has_match' is a value
+// and 'matcher' is a type only matters when looking for attributes
+// and settings from the immediate context.
+
+const unsigned IgnoreExplicitVisibilityBit = 2;
+
+/// Kinds of LV computation. The linkage side of the computation is
+/// always the same, but different things can change how visibility is
+/// computed.
+enum LVComputationKind {
+ /// Do an LV computation for, ultimately, a type.
+ /// Visibility may be restricted by type visibility settings and
+ /// the visibility of template arguments.
+ LVForType = NamedDecl::VisibilityForType,
+
+ /// Do an LV computation for, ultimately, a non-type declaration.
+ /// Visibility may be restricted by value visibility settings and
+ /// the visibility of template arguments.
+ LVForValue = NamedDecl::VisibilityForValue,
+
+ /// Do an LV computation for, ultimately, a type that already has
+ /// some sort of explicit visibility. Visibility may only be
+ /// restricted by the visibility of template arguments.
+ LVForExplicitType = (LVForType | IgnoreExplicitVisibilityBit),
+
+ /// Do an LV computation for, ultimately, a non-type declaration
+ /// that already has some sort of explicit visibility. Visibility
+ /// may only be restricted by the visibility of template arguments.
+ LVForExplicitValue = (LVForValue | IgnoreExplicitVisibilityBit)
+};
+
+/// Does this computation kind permit us to consider additional
+/// visibility settings from attributes and the like?
+static bool hasExplicitVisibilityAlready(LVComputationKind computation) {
+ return ((unsigned(computation) & IgnoreExplicitVisibilityBit) != 0);
+}
+
+/// Given an LVComputationKind, return one of the same type/value sort
+/// that records that it already has explicit visibility.
+static LVComputationKind
+withExplicitVisibilityAlready(LVComputationKind oldKind) {
+ LVComputationKind newKind =
+ static_cast<LVComputationKind>(unsigned(oldKind) |
+ IgnoreExplicitVisibilityBit);
+ assert(oldKind != LVForType || newKind == LVForExplicitType);
+ assert(oldKind != LVForValue || newKind == LVForExplicitValue);
+ assert(oldKind != LVForExplicitType || newKind == LVForExplicitType);
+ assert(oldKind != LVForExplicitValue || newKind == LVForExplicitValue);
+ return newKind;
+}
+
+static Optional<Visibility> getExplicitVisibility(const NamedDecl *D,
+ LVComputationKind kind) {
+ assert(!hasExplicitVisibilityAlready(kind) &&
+ "asking for explicit visibility when we shouldn't be");
+ return D->getExplicitVisibility((NamedDecl::ExplicitVisibilityKind) kind);
+}
+
+/// Is the given declaration a "type" or a "value" for the purposes of
+/// visibility computation?
+static bool usesTypeVisibility(const NamedDecl *D) {
+ return isa<TypeDecl>(D) ||
+ isa<ClassTemplateDecl>(D) ||
+ isa<ObjCInterfaceDecl>(D);
+}
+
+/// Does the given declaration have member specialization information,
+/// and if so, is it an explicit specialization?
+template <class T> static typename
+llvm::enable_if_c<!llvm::is_base_of<RedeclarableTemplateDecl, T>::value,
+ bool>::type
+isExplicitMemberSpecialization(const T *D) {
+ if (const MemberSpecializationInfo *member =
+ D->getMemberSpecializationInfo()) {
+ return member->isExplicitSpecialization();
+ }
+ return false;
+}
+
+/// For templates, this question is easier: a member template can't be
+/// explicitly instantiated, so there's a single bit indicating whether
+/// or not this is an explicit member specialization.
+static bool isExplicitMemberSpecialization(const RedeclarableTemplateDecl *D) {
+ return D->isMemberSpecialization();
+}
+
+/// Given a visibility attribute, return the explicit visibility
+/// associated with it.
+template <class T>
+static Visibility getVisibilityFromAttr(const T *attr) {
+ switch (attr->getVisibility()) {
+ case T::Default:
+ return DefaultVisibility;
+ case T::Hidden:
+ return HiddenVisibility;
+ case T::Protected:
+ return ProtectedVisibility;
+ }
+ llvm_unreachable("bad visibility kind");
+}
+
+/// Return the explicit visibility of the given declaration.
+static Optional<Visibility> getVisibilityOf(const NamedDecl *D,
+ NamedDecl::ExplicitVisibilityKind kind) {
+ // If we're ultimately computing the visibility of a type, look for
+ // a 'type_visibility' attribute before looking for 'visibility'.
+ if (kind == NamedDecl::VisibilityForType) {
+ if (const TypeVisibilityAttr *A = D->getAttr<TypeVisibilityAttr>()) {
+ return getVisibilityFromAttr(A);
+ }
+ }
+
// If this declaration has an explicit visibility attribute, use it.
if (const VisibilityAttr *A = D->getAttr<VisibilityAttr>()) {
- switch (A->getVisibility()) {
- case VisibilityAttr::Default:
- return DefaultVisibility;
- case VisibilityAttr::Hidden:
- return HiddenVisibility;
- case VisibilityAttr::Protected:
- return ProtectedVisibility;
- }
+ return getVisibilityFromAttr(A);
}
// If we're on Mac OS X, an 'availability' for Mac OS X attribute
@@ -61,43 +208,61 @@ static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) {
return DefaultVisibility;
}
- return llvm::Optional<Visibility>();
-}
-
-typedef NamedDecl::LinkageInfo LinkageInfo;
-
-static LinkageInfo getLVForType(QualType T) {
- std::pair<Linkage,Visibility> P = T->getLinkageAndVisibility();
- return LinkageInfo(P.first, P.second, T->isVisibilityExplicit());
+ return None;
}
/// \brief Get the most restrictive linkage for the types in the given
-/// template parameter list.
+/// template parameter list. For visibility purposes, template
+/// parameters are part of the signature of a template.
static LinkageInfo
-getLVForTemplateParameterList(const TemplateParameterList *Params) {
- LinkageInfo LV(ExternalLinkage, DefaultVisibility, false);
- for (TemplateParameterList::const_iterator P = Params->begin(),
- PEnd = Params->end();
+getLVForTemplateParameterList(const TemplateParameterList *params) {
+ LinkageInfo LV;
+ for (TemplateParameterList::const_iterator P = params->begin(),
+ PEnd = params->end();
P != PEnd; ++P) {
+
+ // Template type parameters are the most common and never
+ // contribute to visibility, pack or not.
+ if (isa<TemplateTypeParmDecl>(*P))
+ continue;
+
+ // Non-type template parameters can be restricted by the value type, e.g.
+ // template <enum X> class A { ... };
+ // We have to be careful here, though, because we can be dealing with
+ // dependent types.
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(getLVForType(T));
+ // Handle the non-pack case first.
+ if (!NTTP->isExpandedParameterPack()) {
+ if (!NTTP->getType()->isDependentType()) {
+ LV.merge(NTTP->getType()->getLinkageAndVisibility());
}
continue;
}
- if (!NTTP->getType()->isDependentType()) {
- LV.merge(getLVForType(NTTP->getType()));
- continue;
+ // Look at all the types in an expanded pack.
+ for (unsigned i = 0, n = NTTP->getNumExpansionTypes(); i != n; ++i) {
+ QualType type = NTTP->getExpansionType(i);
+ if (!type->isDependentType())
+ LV.merge(type->getLinkageAndVisibility());
}
+ continue;
}
- if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(*P)) {
+ // Template template parameters can be restricted by their
+ // template parameters, recursively.
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);
+
+ // Handle the non-pack case first.
+ if (!TTP->isExpandedParameterPack()) {
LV.merge(getLVForTemplateParameterList(TTP->getTemplateParameters()));
+ continue;
+ }
+
+ // Look at all expansions in an expanded pack.
+ for (unsigned i = 0, n = TTP->getNumExpansionTemplateParameters();
+ i != n; ++i) {
+ LV.merge(getLVForTemplateParameterList(
+ TTP->getExpansionTemplateParameters(i)));
}
}
@@ -105,67 +270,177 @@ getLVForTemplateParameterList(const TemplateParameterList *Params) {
}
/// getLVForDecl - Get the linkage and visibility for the given declaration.
-static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate);
+static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation);
/// \brief Get the most restrictive linkage for the types and
/// declarations in the given template argument list.
-static LinkageInfo getLVForTemplateArgumentList(const TemplateArgument *Args,
- unsigned NumArgs,
- bool OnlyTemplate) {
- LinkageInfo LV(ExternalLinkage, DefaultVisibility, false);
+///
+/// Note that we don't take an LVComputationKind because we always
+/// want to honor the visibility of template arguments in the same way.
+static LinkageInfo
+getLVForTemplateArgumentList(ArrayRef<TemplateArgument> args) {
+ LinkageInfo LV;
- for (unsigned I = 0; I != NumArgs; ++I) {
- switch (Args[I].getKind()) {
+ for (unsigned i = 0, e = args.size(); i != e; ++i) {
+ const TemplateArgument &arg = args[i];
+ switch (arg.getKind()) {
case TemplateArgument::Null:
case TemplateArgument::Integral:
case TemplateArgument::Expression:
- break;
+ continue;
case TemplateArgument::Type:
- LV.mergeWithMin(getLVForType(Args[I].getAsType()));
- break;
+ LV.merge(arg.getAsType()->getLinkageAndVisibility());
+ continue;
case TemplateArgument::Declaration:
- if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl()))
- LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate));
- break;
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(arg.getAsDecl())) {
+ assert(!usesTypeVisibility(ND));
+ LV.merge(getLVForDecl(ND, LVForValue));
+ }
+ continue;
case TemplateArgument::NullPtr:
- LV.mergeWithMin(getLVForType(Args[I].getNullPtrType()));
- break;
+ LV.merge(arg.getNullPtrType()->getLinkageAndVisibility());
+ continue;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
if (TemplateDecl *Template
- = Args[I].getAsTemplateOrTemplatePattern().getAsTemplateDecl())
- LV.mergeWithMin(getLVForDecl(Template, OnlyTemplate));
- break;
+ = arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl())
+ LV.merge(getLVForDecl(Template, LVForValue));
+ continue;
case TemplateArgument::Pack:
- LV.mergeWithMin(getLVForTemplateArgumentList(Args[I].pack_begin(),
- Args[I].pack_size(),
- OnlyTemplate));
- break;
+ LV.merge(getLVForTemplateArgumentList(arg.getPackAsArray()));
+ continue;
}
+ llvm_unreachable("bad template argument kind");
}
return LV;
}
static LinkageInfo
-getLVForTemplateArgumentList(const TemplateArgumentList &TArgs,
- bool OnlyTemplate) {
- return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), OnlyTemplate);
+getLVForTemplateArgumentList(const TemplateArgumentList &TArgs) {
+ return getLVForTemplateArgumentList(TArgs.asArray());
}
-static bool shouldConsiderTemplateVis(const FunctionDecl *fn,
- const FunctionTemplateSpecializationInfo *spec) {
- return !fn->hasAttr<VisibilityAttr>() || spec->isExplicitSpecialization();
+static bool shouldConsiderTemplateVisibility(const FunctionDecl *fn,
+ const FunctionTemplateSpecializationInfo *specInfo) {
+ // Include visibility from the template parameters and arguments
+ // only if this is not an explicit instantiation or specialization
+ // with direct explicit visibility. (Implicit instantiations won't
+ // have a direct attribute.)
+ if (!specInfo->isExplicitInstantiationOrSpecialization())
+ return true;
+
+ return !fn->hasAttr<VisibilityAttr>();
+}
+
+/// Merge in template-related linkage and visibility for the given
+/// function template specialization.
+///
+/// We don't need a computation kind here because we can assume
+/// LVForValue.
+///
+/// \param[out] LV the computation to use for the parent
+static void
+mergeTemplateLV(LinkageInfo &LV, const FunctionDecl *fn,
+ const FunctionTemplateSpecializationInfo *specInfo) {
+ bool considerVisibility =
+ shouldConsiderTemplateVisibility(fn, specInfo);
+
+ // Merge information from the template parameters.
+ FunctionTemplateDecl *temp = specInfo->getTemplate();
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
+
+ // Merge information from the template arguments.
+ const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs);
+ LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
+}
+
+/// Does the given declaration have a direct visibility attribute
+/// that would match the given rules?
+static bool hasDirectVisibilityAttribute(const NamedDecl *D,
+ LVComputationKind computation) {
+ switch (computation) {
+ case LVForType:
+ case LVForExplicitType:
+ if (D->hasAttr<TypeVisibilityAttr>())
+ return true;
+ // fallthrough
+ case LVForValue:
+ case LVForExplicitValue:
+ if (D->hasAttr<VisibilityAttr>())
+ return true;
+ return false;
+ }
+ llvm_unreachable("bad visibility computation kind");
+}
+
+/// Should we consider visibility associated with the template
+/// arguments and parameters of the given class template specialization?
+static bool shouldConsiderTemplateVisibility(
+ const ClassTemplateSpecializationDecl *spec,
+ LVComputationKind computation) {
+ // Include visibility from the template parameters and arguments
+ // only if this is not an explicit instantiation or specialization
+ // with direct explicit visibility (and note that implicit
+ // instantiations won't have a direct attribute).
+ //
+ // Furthermore, we want to ignore template parameters and arguments
+ // for an explicit specialization when computing the visibility of a
+ // member thereof with explicit visibility.
+ //
+ // This is a bit complex; let's unpack it.
+ //
+ // An explicit class specialization is an independent, top-level
+ // declaration. As such, if it or any of its members has an
+ // explicit visibility attribute, that must directly express the
+ // user's intent, and we should honor it. The same logic applies to
+ // an explicit instantiation of a member of such a thing.
+
+ // Fast path: if this is not an explicit instantiation or
+ // specialization, we always want to consider template-related
+ // visibility restrictions.
+ if (!spec->isExplicitInstantiationOrSpecialization())
+ return true;
+
+ // This is the 'member thereof' check.
+ if (spec->isExplicitSpecialization() &&
+ hasExplicitVisibilityAlready(computation))
+ return false;
+
+ return !hasDirectVisibilityAttribute(spec, computation);
}
-static bool
-shouldConsiderTemplateVis(const ClassTemplateSpecializationDecl *d) {
- return !d->hasAttr<VisibilityAttr>() || d->isExplicitSpecialization();
+/// Merge in template-related linkage and visibility for the given
+/// class template specialization.
+static void mergeTemplateLV(LinkageInfo &LV,
+ const ClassTemplateSpecializationDecl *spec,
+ LVComputationKind computation) {
+ bool considerVisibility = shouldConsiderTemplateVisibility(spec, computation);
+
+ // Merge information from the template parameters, but ignore
+ // visibility if we're only considering template arguments.
+
+ ClassTemplateDecl *temp = spec->getSpecializedTemplate();
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ LV.mergeMaybeWithVisibility(tempLV,
+ considerVisibility && !hasExplicitVisibilityAlready(computation));
+
+ // Merge information from the template arguments. We ignore
+ // template-argument visibility if we've got an explicit
+ // instantiation with a visibility attribute.
+ const TemplateArgumentList &templateArgs = spec->getTemplateArgs();
+ LinkageInfo argsLV = getLVForTemplateArgumentList(templateArgs);
+ LV.mergeMaybeWithVisibility(argsLV, considerVisibility);
}
static bool useInlineVisibilityHidden(const NamedDecl *D) {
@@ -196,8 +471,13 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) {
FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>();
}
+template <typename T> static bool isInExternCContext(T *D) {
+ const T *First = D->getFirstDeclaration();
+ return First->getDeclContext()->isExternCContext();
+}
+
static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
- bool OnlyTemplate) {
+ LVComputationKind computation) {
assert(D->getDeclContext()->getRedeclContext()->isFileContext() &&
"Not a name having namespace scope");
ASTContext &Context = D->getASTContext();
@@ -218,26 +498,24 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// declared to have external linkage; or (there is no equivalent in C99)
if (Context.getLangOpts().CPlusPlus &&
Var->getType().isConstQualified() &&
- !Var->getType().isVolatileQualified() &&
- Var->getStorageClass() != SC_Extern &&
- Var->getStorageClass() != SC_PrivateExtern) {
- bool FoundExtern = false;
- for (const VarDecl *PrevVar = Var->getPreviousDecl();
- PrevVar && !FoundExtern;
- PrevVar = PrevVar->getPreviousDecl())
- if (isExternalLinkage(PrevVar->getLinkage()))
- FoundExtern = true;
-
- if (!FoundExtern)
- return LinkageInfo::internal();
- }
- if (Var->getStorageClass() == SC_None) {
+ !Var->getType().isVolatileQualified()) {
const VarDecl *PrevVar = Var->getPreviousDecl();
- for (; PrevVar; PrevVar = PrevVar->getPreviousDecl())
- if (PrevVar->getStorageClass() == SC_PrivateExtern)
- break;
if (PrevVar)
return PrevVar->getLinkageAndVisibility();
+
+ if (Var->getStorageClass() != SC_Extern &&
+ Var->getStorageClass() != SC_PrivateExtern)
+ return LinkageInfo::internal();
+ }
+
+ for (const VarDecl *PrevVar = Var->getPreviousDecl(); PrevVar;
+ PrevVar = PrevVar->getPreviousDecl()) {
+ if (PrevVar->getStorageClass() == SC_PrivateExtern &&
+ Var->getStorageClass() == SC_None)
+ return PrevVar->getLinkageAndVisibility();
+ // Explicitly declared static.
+ if (PrevVar->getStorageClass() == SC_Static)
+ return LinkageInfo::internal();
}
} else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
// C++ [temp]p4:
@@ -251,7 +529,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
Function = cast<FunctionDecl>(D);
// Explicitly declared static.
- if (Function->getStorageClass() == SC_Static)
+ if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
return LinkageInfo(InternalLinkage, DefaultVisibility, false);
} else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
// - a data member of an anonymous union.
@@ -262,8 +540,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (D->isInAnonymousNamespace()) {
const VarDecl *Var = dyn_cast<VarDecl>(D);
const FunctionDecl *Func = dyn_cast<FunctionDecl>(D);
- if ((!Var || !Var->getDeclContext()->isExternCContext()) &&
- (!Func || !Func->getDeclContext()->isExternCContext()))
+ if ((!Var || !isInExternCContext(Var)) &&
+ (!Func || !isInExternCContext(Func)))
return LinkageInfo::uniqueExternal();
}
@@ -275,31 +553,41 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// external.
LinkageInfo LV;
- if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(D, computation)) {
LV.mergeVisibility(*Vis, true);
} else {
// If we're declared in a namespace with a visibility attribute,
- // use that namespace's visibility, but don't call it explicit.
+ // use that namespace's visibility, and it still counts as explicit.
for (const DeclContext *DC = D->getDeclContext();
!isa<TranslationUnitDecl>(DC);
DC = DC->getParent()) {
const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
if (!ND) continue;
- if (llvm::Optional<Visibility> Vis = ND->getExplicitVisibility()) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(ND, computation)) {
LV.mergeVisibility(*Vis, true);
break;
}
}
}
- }
- if (!OnlyTemplate) {
- LV.mergeVisibility(Context.getLangOpts().getVisibilityMode());
- // If we're paying attention to global visibility, apply
- // -finline-visibility-hidden if this is an inline method.
- if (!LV.visibilityExplicit() && useInlineVisibilityHidden(D))
- LV.mergeVisibility(HiddenVisibility, true);
+ // Add in global settings if the above didn't give us direct visibility.
+ if (!LV.isVisibilityExplicit()) {
+ // Use global type/value visibility as appropriate.
+ Visibility globalVisibility;
+ if (computation == LVForValue) {
+ globalVisibility = Context.getLangOpts().getValueVisibilityMode();
+ } else {
+ assert(computation == LVForType);
+ globalVisibility = Context.getLangOpts().getTypeVisibilityMode();
+ }
+ LV.mergeVisibility(globalVisibility, /*explicit*/ false);
+
+ // If we're paying attention to global visibility, apply
+ // -finline-visibility-hidden if this is an inline method.
+ if (useInlineVisibilityHidden(D))
+ LV.mergeVisibility(HiddenVisibility, true);
+ }
}
// C++ [basic.link]p4:
@@ -330,12 +618,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
//
// Note that we don't want to make the variable non-external
// because of this, but unique-external linkage suits us.
- if (Context.getLangOpts().CPlusPlus &&
- !Var->getDeclContext()->isExternCContext()) {
- LinkageInfo TypeLV = getLVForType(Var->getType());
- if (TypeLV.linkage() != ExternalLinkage)
+ if (Context.getLangOpts().CPlusPlus && !isInExternCContext(Var)) {
+ LinkageInfo TypeLV = Var->getType()->getLinkageAndVisibility();
+ if (TypeLV.getLinkage() != ExternalLinkage)
return LinkageInfo::uniqueExternal();
- LV.mergeVisibility(TypeLV);
+ if (!LV.isVisibilityExplicit())
+ LV.mergeVisibility(TypeLV);
}
if (Var->getStorageClass() == SC_PrivateExtern)
@@ -355,30 +643,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
if (Function->getStorageClass() == SC_PrivateExtern)
LV.mergeVisibility(HiddenVisibility, true);
- // C99 6.2.2p5:
- // If the declaration of an identifier for a function has no
- // storage-class specifier, its linkage is determined exactly
- // as if it were declared with the storage-class specifier
- // extern.
- if (!Context.getLangOpts().CPlusPlus &&
- (Function->getStorageClass() == SC_Extern ||
- Function->getStorageClass() == SC_PrivateExtern ||
- Function->getStorageClass() == SC_None)) {
- // C99 6.2.2p4:
- // For an identifier declared with the storage-class specifier
- // extern in a scope in which a prior declaration of that
- // identifier is visible, if the prior declaration specifies
- // internal or external linkage, the linkage of the identifier
- // at the later declaration is the same as the linkage
- // specified at the prior declaration. If no prior declaration
- // is visible, or if the prior declaration specifies no
- // linkage, then the identifier has external linkage.
- if (const FunctionDecl *PrevFunc = Function->getPreviousDecl()) {
- LinkageInfo PrevLV = getLVForDecl(PrevFunc, OnlyTemplate);
- if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
- LV.mergeVisibility(PrevLV);
- }
- }
+ // Note that Sema::MergeCompatibleFunctionDecls already takes care of
+ // merging storage classes and visibility attributes, so we don't have to
+ // look at previous decls in here.
// In C++, then if the type of the function uses a type with
// unique-external linkage, it's not legally usable from outside
@@ -389,21 +656,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
Function->getType()->getLinkage() == UniqueExternalLinkage)
return LinkageInfo::uniqueExternal();
- // Consider LV from the template and the template arguments unless
- // this is an explicit specialization with a visibility attribute.
+ // Consider LV from the template and the template arguments.
+ // We're at file scope, so we do not need to worry about nested
+ // specializations.
if (FunctionTemplateSpecializationInfo *specInfo
= Function->getTemplateSpecializationInfo()) {
- LinkageInfo TempLV = getLVForDecl(specInfo->getTemplate(), true);
- const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(templateArgs,
- OnlyTemplate);
- if (shouldConsiderTemplateVis(Function, specInfo)) {
- LV.mergeWithMin(TempLV);
- LV.mergeWithMin(ArgsLV);
- } else {
- LV.mergeLinkage(TempLV);
- LV.mergeLinkage(ArgsLV);
- }
+ mergeTemplateLV(LV, Function, specInfo);
}
// - a named class (Clause 9), or an unnamed class defined in a
@@ -414,41 +672,33 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// has the typedef name for linkage purposes (7.1.3); or
} else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) {
// Unnamed tags have no linkage.
- if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl())
+ if (!Tag->hasNameForLinkage())
return LinkageInfo::none();
// If this is a class template specialization, consider the
- // linkage of the template and template arguments.
+ // linkage of the template and template arguments. We're at file
+ // scope, so we do not need to worry about nested specializations.
if (const ClassTemplateSpecializationDecl *spec
= dyn_cast<ClassTemplateSpecializationDecl>(Tag)) {
- // From the template.
- LinkageInfo TempLV = getLVForDecl(spec->getSpecializedTemplate(), true);
-
- // The arguments at which the template was instantiated.
- const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs();
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs,
- OnlyTemplate);
- if (shouldConsiderTemplateVis(spec)) {
- LV.mergeWithMin(TempLV);
- LV.mergeWithMin(ArgsLV);
- } else {
- LV.mergeLinkage(TempLV);
- LV.mergeLinkage(ArgsLV);
- }
+ mergeTemplateLV(LV, spec, computation);
}
// - an enumerator belonging to an enumeration with external linkage;
} else if (isa<EnumConstantDecl>(D)) {
LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()),
- OnlyTemplate);
- if (!isExternalLinkage(EnumLV.linkage()))
+ computation);
+ if (!isExternalLinkage(EnumLV.getLinkage()))
return LinkageInfo::none();
LV.merge(EnumLV);
// - a template, unless it is a function template that has
// internal linkage (Clause 14);
} else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
- LV.merge(getLVForTemplateParameterList(temp->getTemplateParameters()));
+ bool considerVisibility = !hasExplicitVisibilityAlready(computation);
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
+
// - a namespace (7.3), unless it is declared within an unnamed
// namespace.
} else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) {
@@ -466,13 +716,14 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D,
// If we ended up with non-external linkage, visibility should
// always be default.
- if (LV.linkage() != ExternalLinkage)
- return LinkageInfo(LV.linkage(), DefaultVisibility, false);
+ if (LV.getLinkage() != ExternalLinkage)
+ return LinkageInfo(LV.getLinkage(), DefaultVisibility, false);
return LV;
}
-static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) {
+static LinkageInfo getLVForClassMember(const NamedDecl *D,
+ LVComputationKind computation) {
// 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
@@ -480,46 +731,45 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) {
if (!(isa<CXXMethodDecl>(D) ||
isa<VarDecl>(D) ||
isa<FieldDecl>(D) ||
- (isa<TagDecl>(D) &&
- (D->getDeclName() || cast<TagDecl>(D)->getTypedefNameForAnonDecl()))))
+ isa<TagDecl>(D)))
return LinkageInfo::none();
LinkageInfo LV;
// If we have an explicit visibility attribute, merge that in.
- if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility())
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(D, computation))
LV.mergeVisibility(*Vis, true);
// If we're paying attention to global visibility, apply
// -finline-visibility-hidden if this is an inline method.
//
// Note that we do this before merging information about
// the class visibility.
- if (!LV.visibilityExplicit() && useInlineVisibilityHidden(D))
+ if (!LV.isVisibilityExplicit() && useInlineVisibilityHidden(D))
LV.mergeVisibility(HiddenVisibility, true);
}
// If this class member has an explicit visibility attribute, the only
// thing that can change its visibility is the template arguments, so
// only look for them when processing the class.
- bool ClassOnlyTemplate = LV.visibilityExplicit() ? true : OnlyTemplate;
-
- // If this member has an visibility attribute, ClassF will exclude
- // attributes on the class or command line options, keeping only information
- // about the template instantiation. If the member has no visibility
- // attributes, mergeWithMin behaves like merge, so in both cases mergeWithMin
- // produces the desired result.
- LV.mergeWithMin(getLVForDecl(cast<RecordDecl>(D->getDeclContext()),
- ClassOnlyTemplate));
- if (!isExternalLinkage(LV.linkage()))
+ LVComputationKind classComputation = computation;
+ if (LV.isVisibilityExplicit())
+ classComputation = withExplicitVisibilityAlready(computation);
+
+ LinkageInfo classLV =
+ getLVForDecl(cast<RecordDecl>(D->getDeclContext()), classComputation);
+ if (!isExternalLinkage(classLV.getLinkage()))
return LinkageInfo::none();
// If the class already has unique-external linkage, we can't improve.
- if (LV.linkage() == UniqueExternalLinkage)
+ if (classLV.getLinkage() == UniqueExternalLinkage)
return LinkageInfo::uniqueExternal();
- if (!OnlyTemplate)
- LV.mergeVisibility(D->getASTContext().getLangOpts().getVisibilityMode());
+ // Otherwise, don't merge in classLV yet, because in certain cases
+ // we need to completely ignore the visibility from it.
+
+ // Specifically, if this decl exists and has an explicit attribute.
+ const NamedDecl *explicitSpecSuppressor = 0;
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
// If the type of the function uses a type with unique-external
@@ -531,192 +781,269 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, bool OnlyTemplate) {
// the template parameters and arguments.
if (FunctionTemplateSpecializationInfo *spec
= MD->getTemplateSpecializationInfo()) {
- const TemplateArgumentList &TemplateArgs = *spec->TemplateArguments;
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs,
- OnlyTemplate);
- TemplateParameterList *TemplateParams =
- spec->getTemplate()->getTemplateParameters();
- LinkageInfo ParamsLV = getLVForTemplateParameterList(TemplateParams);
- if (shouldConsiderTemplateVis(MD, spec)) {
- LV.mergeWithMin(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeWithMin(ParamsLV);
- } else {
- LV.mergeLinkage(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeLinkage(ParamsLV);
+ mergeTemplateLV(LV, MD, spec);
+ if (spec->isExplicitSpecialization()) {
+ explicitSpecSuppressor = MD;
+ } else if (isExplicitMemberSpecialization(spec->getTemplate())) {
+ explicitSpecSuppressor = spec->getTemplate()->getTemplatedDecl();
}
+ } else if (isExplicitMemberSpecialization(MD)) {
+ explicitSpecSuppressor = MD;
}
- // 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.
- const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs();
- LinkageInfo ArgsLV = getLVForTemplateArgumentList(TemplateArgs,
- OnlyTemplate);
- TemplateParameterList *TemplateParams =
- spec->getSpecializedTemplate()->getTemplateParameters();
- LinkageInfo ParamsLV = getLVForTemplateParameterList(TemplateParams);
- if (shouldConsiderTemplateVis(spec)) {
- LV.mergeWithMin(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeWithMin(ParamsLV);
+ mergeTemplateLV(LV, spec, computation);
+ if (spec->isExplicitSpecialization()) {
+ explicitSpecSuppressor = spec;
} else {
- LV.mergeLinkage(ArgsLV);
- if (!OnlyTemplate)
- LV.mergeLinkage(ParamsLV);
+ const ClassTemplateDecl *temp = spec->getSpecializedTemplate();
+ if (isExplicitMemberSpecialization(temp)) {
+ explicitSpecSuppressor = temp->getTemplatedDecl();
+ }
}
+ } else if (isExplicitMemberSpecialization(RD)) {
+ explicitSpecSuppressor = RD;
}
// 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.
- LinkageInfo TypeLV = getLVForType(VD->getType());
- if (TypeLV.linkage() != ExternalLinkage)
- LV.mergeLinkage(UniqueExternalLinkage);
- LV.mergeVisibility(TypeLV);
- }
+ LinkageInfo typeLV = VD->getType()->getLinkageAndVisibility();
+ LV.mergeMaybeWithVisibility(typeLV,
+ !LV.isVisibilityExplicit() && !classLV.isVisibilityExplicit());
- return LV;
-}
+ if (isExplicitMemberSpecialization(VD)) {
+ explicitSpecSuppressor = VD;
+ }
-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();
+ // Template members.
+ } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) {
+ bool considerVisibility =
+ (!LV.isVisibilityExplicit() &&
+ !classLV.isVisibilityExplicit() &&
+ !hasExplicitVisibilityAlready(computation));
+ LinkageInfo tempLV =
+ getLVForTemplateParameterList(temp->getTemplateParameters());
+ LV.mergeMaybeWithVisibility(tempLV, considerVisibility);
+
+ if (const RedeclarableTemplateDecl *redeclTemp =
+ dyn_cast<RedeclarableTemplateDecl>(temp)) {
+ if (isExplicitMemberSpecialization(redeclTemp)) {
+ explicitSpecSuppressor = temp->getTemplatedDecl();
+ }
+ }
}
-}
-void NamedDecl::anchor() { }
+ // We should never be looking for an attribute directly on a template.
+ assert(!explicitSpecSuppressor || !isa<TemplateDecl>(explicitSpecSuppressor));
-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.
+ // If this member is an explicit member specialization, and it has
+ // an explicit attribute, ignore visibility from the parent.
+ bool considerClassVisibility = true;
+ if (explicitSpecSuppressor &&
+ // optimization: hasDVA() is true only with explicit visibility.
+ LV.isVisibilityExplicit() &&
+ classLV.getVisibility() != DefaultVisibility &&
+ hasDirectVisibilityAttribute(explicitSpecSuppressor, computation)) {
+ considerClassVisibility = false;
+ }
- HasCachedLinkage = 0;
+ // Finally, merge in information from the class.
+ LV.mergeMaybeWithVisibility(classLV, considerClassVisibility);
+ return LV;
+}
- // 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);
+void NamedDecl::anchor() { }
- 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);
+bool NamedDecl::isLinkageValid() const {
+ if (!HasCachedLinkage)
+ return true;
- // 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();
- }
+ return getLVForDecl(this, LVForExplicitValue).getLinkage() ==
+ Linkage(CachedLinkage);
+}
- // Clear cached linkage for function template decls, too.
- if (FunctionTemplateDecl *temp =
- dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) {
- temp->getTemplatedDecl()->ClearLinkageCache();
- for (FunctionTemplateDecl::spec_iterator
- i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i)
- i->ClearLinkageCache();
- }
-
+bool NamedDecl::hasExternalLinkageUncached() const {
+ return getLVForDecl(this, LVForExplicitValue).getLinkage() == ExternalLinkage;
}
Linkage NamedDecl::getLinkage() const {
- if (HasCachedLinkage) {
- assert(Linkage(CachedLinkage) ==
- getLVForDecl(this, true).linkage());
+ if (HasCachedLinkage)
return Linkage(CachedLinkage);
- }
- CachedLinkage = getLVForDecl(this, true).linkage();
+ // We don't care about visibility here, so ask for the cheapest
+ // possible visibility analysis.
+ CachedLinkage = getLVForDecl(this, LVForExplicitValue).getLinkage();
HasCachedLinkage = 1;
+
+#ifndef NDEBUG
+ verifyLinkage();
+#endif
+
return Linkage(CachedLinkage);
}
LinkageInfo NamedDecl::getLinkageAndVisibility() const {
- LinkageInfo LI = getLVForDecl(this, false);
- assert(!HasCachedLinkage || Linkage(CachedLinkage) == LI.linkage());
+ LVComputationKind computation =
+ (usesTypeVisibility(this) ? LVForType : LVForValue);
+ LinkageInfo LI = getLVForDecl(this, computation);
+ if (HasCachedLinkage) {
+ assert(Linkage(CachedLinkage) == LI.getLinkage());
+ return LI;
+ }
HasCachedLinkage = 1;
- CachedLinkage = LI.linkage();
+ CachedLinkage = LI.getLinkage();
+
+#ifndef NDEBUG
+ verifyLinkage();
+#endif
+
return LI;
}
-llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const {
- // Use the most recent declaration of a variable.
- if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
- if (llvm::Optional<Visibility> V =
- getVisibilityOf(Var->getMostRecentDecl()))
- return V;
+void NamedDecl::verifyLinkage() const {
+ // In C (because of gnu inline) and in c++ with microsoft extensions an
+ // static can follow an extern, so we can have two decls with different
+ // linkages.
+ const LangOptions &Opts = getASTContext().getLangOpts();
+ if (!Opts.CPlusPlus || Opts.MicrosoftExt)
+ return;
+
+ // We have just computed the linkage for this decl. By induction we know
+ // that all other computed linkages match, check that the one we just computed
+ // also does.
+ NamedDecl *D = NULL;
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
+ NamedDecl *T = cast<NamedDecl>(*I);
+ if (T == this)
+ continue;
+ if (T->HasCachedLinkage != 0) {
+ D = T;
+ break;
+ }
+ }
+ assert(!D || D->CachedLinkage == CachedLinkage);
+}
+
+Optional<Visibility>
+NamedDecl::getExplicitVisibility(ExplicitVisibilityKind kind) const {
+ // Check the declaration itself first.
+ if (Optional<Visibility> V = getVisibilityOf(this, kind))
+ return V;
+
+ // If this is a member class of a specialization of a class template
+ // and the corresponding decl has explicit visibility, use that.
+ if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
+ CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
+ if (InstantiatedFrom)
+ return getVisibilityOf(InstantiatedFrom, kind);
+ }
+
+ // 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>(this))
+ return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl(),
+ kind);
+ // Use the most recent declaration.
+ const NamedDecl *MostRecent = cast<NamedDecl>(this->getMostRecentDecl());
+ if (MostRecent != this)
+ return MostRecent->getExplicitVisibility(kind);
+
+ if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
if (Var->isStaticDataMember()) {
VarDecl *InstantiatedFrom = Var->getInstantiatedFromStaticDataMember();
if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom);
+ return getVisibilityOf(InstantiatedFrom, kind);
}
- return llvm::Optional<Visibility>();
+ return None;
}
- // Use the most recent declaration of a function, and also handle
- // function template specializations.
+ // Also handle function template specializations.
if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) {
- if (llvm::Optional<Visibility> V
- = getVisibilityOf(fn->getMostRecentDecl()))
- return V;
-
// If the function is a specialization of a template with an
// explicit visibility attribute, use that.
if (FunctionTemplateSpecializationInfo *templateInfo
= fn->getTemplateSpecializationInfo())
- return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl());
+ return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl(),
+ kind);
// If the function is a member of a specialization of a class template
// and the corresponding decl has explicit visibility, use that.
FunctionDecl *InstantiatedFrom = fn->getInstantiatedFromMemberFunction();
if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom);
+ return getVisibilityOf(InstantiatedFrom, kind);
- return llvm::Optional<Visibility>();
+ return None;
}
- // Otherwise, just check the declaration itself first.
- if (llvm::Optional<Visibility> V = getVisibilityOf(this))
- return V;
-
// The visibility of a template is stored in the templated decl.
if (const TemplateDecl *TD = dyn_cast<TemplateDecl>(this))
- return getVisibilityOf(TD->getTemplatedDecl());
+ return getVisibilityOf(TD->getTemplatedDecl(), kind);
- // 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>(this))
- return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl());
+ return None;
+}
- // If this is a member class of a specialization of a class template
- // and the corresponding decl has explicit visibility, use that.
- if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(this)) {
- CXXRecordDecl *InstantiatedFrom = RD->getInstantiatedFromMemberClass();
- if (InstantiatedFrom)
- return getVisibilityOf(InstantiatedFrom);
+static LinkageInfo getLVForLocalDecl(const NamedDecl *D,
+ LVComputationKind computation) {
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ if (Function->isInAnonymousNamespace() &&
+ !Function->getDeclContext()->isExternCContext())
+ return LinkageInfo::uniqueExternal();
+
+ // This is a "void f();" which got merged with a file static.
+ if (Function->getCanonicalDecl()->getStorageClass() == SC_Static)
+ return LinkageInfo::internal();
+
+ LinkageInfo LV;
+ if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis =
+ getExplicitVisibility(Function, computation))
+ LV.mergeVisibility(*Vis, true);
+ }
+
+ // Note that Sema::MergeCompatibleFunctionDecls already takes care of
+ // merging storage classes and visibility attributes, so we don't have to
+ // look at previous decls in here.
+
+ return LV;
}
- return llvm::Optional<Visibility>();
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ if (Var->hasExternalStorage()) {
+ if (Var->isInAnonymousNamespace() &&
+ !Var->getDeclContext()->isExternCContext())
+ return LinkageInfo::uniqueExternal();
+
+ LinkageInfo LV;
+ if (Var->getStorageClass() == SC_PrivateExtern)
+ LV.mergeVisibility(HiddenVisibility, true);
+ else if (!hasExplicitVisibilityAlready(computation)) {
+ if (Optional<Visibility> Vis = getExplicitVisibility(Var, computation))
+ LV.mergeVisibility(*Vis, true);
+ }
+
+ if (const VarDecl *Prev = Var->getPreviousDecl()) {
+ LinkageInfo PrevLV = getLVForDecl(Prev, computation);
+ if (PrevLV.getLinkage())
+ LV.setLinkage(PrevLV.getLinkage());
+ LV.mergeVisibility(PrevLV);
+ }
+
+ return LV;
+ }
+ }
+
+ return LinkageInfo::none();
}
-static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
+static LinkageInfo getLVForDecl(const NamedDecl *D,
+ LVComputationKind computation) {
// Objective-C: treat all Objective-C declarations as having external
// linkage.
switch (D->getKind()) {
@@ -751,12 +1078,11 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
if (isa<ParmVarDecl>(ContextDecl))
DC = ContextDecl->getDeclContext()->getRedeclContext();
else
- return getLVForDecl(cast<NamedDecl>(ContextDecl),
- OnlyTemplate);
+ return getLVForDecl(cast<NamedDecl>(ContextDecl), computation);
}
if (const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
- return getLVForDecl(ND, OnlyTemplate);
+ return getLVForDecl(ND, computation);
return LinkageInfo::external();
}
@@ -767,7 +1093,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
// Handle linkage for namespace-scope names.
if (D->getDeclContext()->getRedeclContext()->isFileContext())
- return getLVForNamespaceScopeDecl(D, OnlyTemplate);
+ return getLVForNamespaceScopeDecl(D, computation);
// C++ [basic.link]p5:
// In addition, a member function, static data member, a named
@@ -777,7 +1103,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
// purposes (7.1.3), has external linkage if the name of the class
// has external linkage.
if (D->getDeclContext()->isRecord())
- return getLVForClassMember(D, OnlyTemplate);
+ return getLVForClassMember(D, computation);
// C++ [basic.link]p6:
// The name of a function declared in block scope and the name of
@@ -790,48 +1116,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) {
// one such matching entity, the program is ill-formed. Otherwise,
// if no matching entity is found, the block scope entity receives
// external linkage.
- if (D->getLexicalDeclContext()->isFunctionOrMethod()) {
- if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
- if (Function->isInAnonymousNamespace() &&
- !Function->getDeclContext()->isExternCContext())
- return LinkageInfo::uniqueExternal();
-
- LinkageInfo LV;
- if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = Function->getExplicitVisibility())
- LV.mergeVisibility(*Vis, true);
- }
-
- if (const FunctionDecl *Prev = Function->getPreviousDecl()) {
- LinkageInfo PrevLV = getLVForDecl(Prev, OnlyTemplate);
- if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage());
- LV.mergeVisibility(PrevLV);
- }
-
- return LV;
- }
-
- if (const VarDecl *Var = dyn_cast<VarDecl>(D))
- if (Var->getStorageClass() == SC_Extern ||
- Var->getStorageClass() == SC_PrivateExtern) {
- if (Var->isInAnonymousNamespace() &&
- !Var->getDeclContext()->isExternCContext())
- return LinkageInfo::uniqueExternal();
-
- LinkageInfo LV;
- if (Var->getStorageClass() == SC_PrivateExtern)
- LV.mergeVisibility(HiddenVisibility, true);
- else if (!OnlyTemplate) {
- if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility())
- LV.mergeVisibility(*Vis, true);
- }
-
- // Note that Sema::MergeVarDecl already takes care of implementing
- // C99 6.2.2p4 and propagating the visibility attribute, so we don't
- // have to do it here.
- return LV;
- }
- }
+ if (D->getDeclContext()->isFunctionOrMethod())
+ return getLVForLocalDecl(D, computation);
// C++ [basic.link]p6:
// Names not covered by these rules have no linkage.
@@ -843,10 +1129,24 @@ std::string NamedDecl::getQualifiedNameAsString() const {
}
std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
+ std::string QualName;
+ llvm::raw_string_ostream OS(QualName);
+ printQualifiedName(OS, P);
+ return OS.str();
+}
+
+void NamedDecl::printQualifiedName(raw_ostream &OS) const {
+ printQualifiedName(OS, getASTContext().getPrintingPolicy());
+}
+
+void NamedDecl::printQualifiedName(raw_ostream &OS,
+ const PrintingPolicy &P) const {
const DeclContext *Ctx = getDeclContext();
- if (Ctx->isFunctionOrMethod())
- return getNameAsString();
+ if (Ctx->isFunctionOrMethod()) {
+ printName(OS);
+ return;
+ }
typedef SmallVector<const DeclContext *, 8> ContextsTy;
ContextsTy Contexts;
@@ -855,22 +1155,18 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
while (Ctx && isa<NamedDecl>(Ctx)) {
Contexts.push_back(Ctx);
Ctx = Ctx->getParent();
- };
-
- std::string QualName;
- llvm::raw_string_ostream OS(QualName);
+ }
for (ContextsTy::reverse_iterator I = Contexts.rbegin(), E = Contexts.rend();
I != E; ++I) {
if (const ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(*I)) {
+ OS << Spec->getName();
const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.data(),
- TemplateArgs.size(),
- P);
- OS << Spec->getName() << TemplateArgsStr;
+ TemplateSpecializationType::PrintTemplateArgumentList(OS,
+ TemplateArgs.data(),
+ TemplateArgs.size(),
+ P);
} else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(*I)) {
if (ND->isAnonymousNamespace())
OS << "<anonymous namespace>";
@@ -912,8 +1208,15 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const {
OS << *this;
else
OS << "<anonymous>";
+}
- return OS.str();
+void NamedDecl::getNameForDiagnostic(raw_ostream &OS,
+ const PrintingPolicy &Policy,
+ bool Qualified) const {
+ if (Qualified)
+ printQualifiedName(OS, Policy);
+ else
+ printName(OS);
}
bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
@@ -1166,45 +1469,80 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) {
VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartL, SourceLocation IdL,
IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten) {
- return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S, SCAsWritten);
+ StorageClass S) {
+ return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S);
}
VarDecl *VarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarDecl));
return new (Mem) VarDecl(Var, 0, SourceLocation(), SourceLocation(), 0,
- QualType(), 0, SC_None, SC_None);
+ QualType(), 0, SC_None);
}
void VarDecl::setStorageClass(StorageClass SC) {
assert(isLegalForVariable(SC));
- if (getStorageClass() != SC)
- ClearLinkageCache();
-
VarDeclBits.SClass = SC;
}
SourceRange VarDecl::getSourceRange() const {
if (const Expr *Init = getInit()) {
SourceLocation InitEnd = Init->getLocEnd();
- if (InitEnd.isValid())
+ // If Init is implicit, ignore its source range and fallback on
+ // DeclaratorDecl::getSourceRange() to handle postfix elements.
+ if (InitEnd.isValid() && InitEnd != getLocation())
return SourceRange(getOuterLocStart(), InitEnd);
}
return DeclaratorDecl::getSourceRange();
}
-bool VarDecl::isExternC() const {
- if (getLinkage() != ExternalLinkage)
- return false;
+template<typename T>
+static LanguageLinkage getLanguageLinkageTemplate(const T &D) {
+ // C++ [dcl.link]p1: All function types, function names with external linkage,
+ // and variable names with external linkage have a language linkage.
+ if (!isExternalLinkage(D.getLinkage()))
+ return NoLanguageLinkage;
+
+ // Language linkage is a C++ concept, but saying that everything else in C has
+ // C language linkage fits the implementation nicely.
+ ASTContext &Context = D.getASTContext();
+ if (!Context.getLangOpts().CPlusPlus)
+ return CLanguageLinkage;
- const DeclContext *DC = getDeclContext();
+ // C++ [dcl.link]p4: A C language linkage is ignored in determining the
+ // language linkage of the names of class members and the function type of
+ // class member functions.
+ const DeclContext *DC = D.getDeclContext();
if (DC->isRecord())
+ return CXXLanguageLinkage;
+
+ // If the first decl is in an extern "C" context, any other redeclaration
+ // will have C language linkage. If the first one is not in an extern "C"
+ // context, we would have reported an error for any other decl being in one.
+ const T *First = D.getFirstDeclaration();
+ if (First->getDeclContext()->isExternCContext())
+ return CLanguageLinkage;
+ return CXXLanguageLinkage;
+}
+
+template<typename T>
+static bool isExternCTemplate(const T &D) {
+ // Since the context is ignored for class members, they can only have C++
+ // language linkage or no language linkage.
+ const DeclContext *DC = D.getDeclContext();
+ if (DC->isRecord()) {
+ assert(D.getASTContext().getLangOpts().CPlusPlus);
return false;
+ }
- ASTContext &Context = getASTContext();
- if (!Context.getLangOpts().CPlusPlus)
- return true;
- return DC->isExternCContext();
+ return D.getLanguageLinkage() == CLanguageLinkage;
+}
+
+LanguageLinkage VarDecl::getLanguageLinkage() const {
+ return getLanguageLinkageTemplate(*this);
+}
+
+bool VarDecl::isExternC() const {
+ return isExternCTemplate(*this);
}
VarDecl *VarDecl::getCanonicalDecl() {
@@ -1241,12 +1579,11 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition(
// AST for 'extern "C" int foo;' is annotated with 'extern'.
if (hasExternalStorage())
return DeclarationOnly;
-
- if (getStorageClassAsWritten() == SC_Extern ||
- getStorageClassAsWritten() == SC_PrivateExtern) {
+
+ if (hasExternalStorage()) {
for (const VarDecl *PrevVar = getPreviousDecl();
PrevVar; PrevVar = PrevVar->getPreviousDecl()) {
- if (PrevVar->getLinkage() == InternalLinkage && PrevVar->hasInit())
+ if (PrevVar->getLinkage() == InternalLinkage)
return DeclarationOnly;
}
}
@@ -1375,7 +1712,7 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
// In C++11, any variable of reference type can be used in a constant
// expression if it is initialized by a constant expression.
- if (Lang.CPlusPlus0x && getType()->isReferenceType())
+ if (Lang.CPlusPlus11 && getType()->isReferenceType())
return true;
// Only const objects can be used in constant expressions in C++. C++98 does
@@ -1391,7 +1728,7 @@ bool VarDecl::isUsableInConstantExpressions(ASTContext &C) const {
// Additionally, in C++11, non-volatile constexpr variables can be used in
// constant expressions.
- return Lang.CPlusPlus0x && isConstexpr();
+ return Lang.CPlusPlus11 && isConstexpr();
}
/// Convert the initializer for this declaration to the elaborated EvaluatedStmt
@@ -1409,12 +1746,12 @@ EvaluatedStmt *VarDecl::ensureEvaluatedStmt() const {
}
APValue *VarDecl::evaluateValue() const {
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
return evaluateValue(Notes);
}
APValue *VarDecl::evaluateValue(
- llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
EvaluatedStmt *Eval = ensureEvaluatedStmt();
// We only produce notes indicating why an initializer is non-constant the
@@ -1447,7 +1784,7 @@ APValue *VarDecl::evaluateValue(
// In C++11, we have determined whether the initializer was a constant
// expression as a side-effect.
- if (getASTContext().getLangOpts().CPlusPlus0x && !Eval->CheckedICE) {
+ if (getASTContext().getLangOpts().CPlusPlus11 && !Eval->CheckedICE) {
Eval->CheckedICE = true;
Eval->IsICE = Result && Notes.empty();
}
@@ -1471,8 +1808,8 @@ bool VarDecl::checkInitIsICE() const {
// In C++11, evaluate the initializer to check whether it's a constant
// expression.
- if (getASTContext().getLangOpts().CPlusPlus0x) {
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ if (getASTContext().getLangOpts().CPlusPlus11) {
+ SmallVector<PartialDiagnosticAt, 8> Notes;
evaluateValue(Notes);
return Eval->IsICE;
}
@@ -1541,16 +1878,15 @@ ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
- StorageClass S, StorageClass SCAsWritten,
- Expr *DefArg) {
+ StorageClass S, Expr *DefArg) {
return new (C) ParmVarDecl(ParmVar, DC, StartLoc, IdLoc, Id, T, TInfo,
- S, SCAsWritten, DefArg);
+ S, DefArg);
}
ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ParmVarDecl));
return new (Mem) ParmVarDecl(ParmVar, 0, SourceLocation(), SourceLocation(),
- 0, QualType(), 0, SC_None, SC_None, 0);
+ 0, QualType(), 0, SC_None, 0);
}
SourceRange ParmVarDecl::getSourceRange() const {
@@ -1602,17 +1938,13 @@ unsigned ParmVarDecl::getParameterIndexLarge() const {
// FunctionDecl Implementation
//===----------------------------------------------------------------------===//
-void FunctionDecl::getNameForDiagnostic(std::string &S,
- const PrintingPolicy &Policy,
- bool Qualified) const {
- NamedDecl::getNameForDiagnostic(S, Policy, Qualified);
+void FunctionDecl::getNameForDiagnostic(
+ raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(OS, Policy, Qualified);
const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs();
if (TemplateArgs)
- S += TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs->data(),
- TemplateArgs->size(),
- Policy);
-
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, TemplateArgs->data(), TemplateArgs->size(), Policy);
}
bool FunctionDecl::isVariadic() const {
@@ -1684,13 +2016,6 @@ void FunctionDecl::setPure(bool P) {
Parent->markedVirtualFunctionPure();
}
-void FunctionDecl::setConstexpr(bool IC) {
- IsConstexpr = IC;
- CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(this);
- if (IC && CD)
- CD->getParent()->markedConstructorConstexpr(CD);
-}
-
bool FunctionDecl::isMain() const {
const TranslationUnitDecl *tunit =
dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext());
@@ -1722,29 +2047,25 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy);
}
-bool FunctionDecl::isExternC() const {
- if (getLinkage() != ExternalLinkage)
- return false;
-
- if (getAttr<OverloadableAttr>())
- return false;
-
- const DeclContext *DC = getDeclContext();
- if (DC->isRecord())
- return false;
+LanguageLinkage FunctionDecl::getLanguageLinkage() const {
+ // Users expect to be able to write
+ // extern "C" void *__builtin_alloca (size_t);
+ // so consider builtins as having C language linkage.
+ if (getBuiltinID())
+ return CLanguageLinkage;
- ASTContext &Context = getASTContext();
- if (!Context.getLangOpts().CPlusPlus)
- return true;
+ return getLanguageLinkageTemplate(*this);
+}
- return isMain() || DC->isExternCContext();
+bool FunctionDecl::isExternC() const {
+ return isExternCTemplate(*this);
}
bool FunctionDecl::isGlobal() const {
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this))
return Method->isStatic();
- if (getStorageClass() == SC_Static)
+ if (getCanonicalDecl()->getStorageClass() == SC_Static)
return false;
for (const DeclContext *DC = getDeclContext();
@@ -1760,6 +2081,12 @@ bool FunctionDecl::isGlobal() const {
return true;
}
+bool FunctionDecl::isNoReturn() const {
+ return hasAttr<NoReturnAttr>() || hasAttr<CXX11NoReturnAttr>() ||
+ hasAttr<C11NoReturnAttr>() ||
+ getType()->getAs<FunctionType>()->getNoReturnAttr();
+}
+
void
FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
redeclarable_base::setPreviousDeclaration(PrevDecl);
@@ -1783,14 +2110,6 @@ 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.
///
@@ -1851,7 +2170,7 @@ unsigned FunctionDecl::getNumParams() const {
}
void FunctionDecl::setParams(ASTContext &C,
- llvm::ArrayRef<ParmVarDecl *> NewParamInfo) {
+ ArrayRef<ParmVarDecl *> NewParamInfo) {
assert(ParamInfo == 0 && "Already has param info!");
assert(NewParamInfo.size() == getNumParams() && "Parameter count mismatch!");
@@ -1862,13 +2181,13 @@ void FunctionDecl::setParams(ASTContext &C,
}
}
-void FunctionDecl::setDeclsInPrototypeScope(llvm::ArrayRef<NamedDecl *> NewDecls) {
+void FunctionDecl::setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls) {
assert(DeclsInPrototypeScope.empty() && "Already has prototype decls!");
if (!NewDecls.empty()) {
NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()];
std::copy(NewDecls.begin(), NewDecls.end(), A);
- DeclsInPrototypeScope = llvm::ArrayRef<NamedDecl*>(A, NewDecls.size());
+ DeclsInPrototypeScope = ArrayRef<NamedDecl *>(A, NewDecls.size());
}
}
@@ -1907,38 +2226,6 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
return NumRequiredArgs;
}
-bool FunctionDecl::isInlined() const {
- if (IsInline)
- return true;
-
- if (isa<CXXMethodDecl>(this)) {
- if (!isOutOfLine() || getCanonicalDecl()->isInlineSpecified())
- return true;
- }
-
- switch (getTemplateSpecializationKind()) {
- case TSK_Undeclared:
- case TSK_ExplicitSpecialization:
- return false;
-
- case TSK_ImplicitInstantiation:
- case TSK_ExplicitInstantiationDeclaration:
- case TSK_ExplicitInstantiationDefinition:
- // Handle below.
- break;
- }
-
- const FunctionDecl *PatternDecl = getTemplateInstantiationPattern();
- bool HasPattern = false;
- if (PatternDecl)
- HasPattern = PatternDecl->hasBody(PatternDecl);
-
- if (HasPattern && PatternDecl)
- return PatternDecl->isInlined();
-
- return false;
-}
-
static bool RedeclForcesDefC99(const FunctionDecl *Redecl) {
// Only consider file-scope declarations in this test.
if (!Redecl->getLexicalDeclContext()->isTranslationUnit())
@@ -1973,7 +2260,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
//
// FIXME: What happens if gnu_inline gets added on after the first
// declaration?
- if (!isInlineSpecified() || getStorageClassAsWritten() == SC_Extern)
+ if (!isInlineSpecified() || getStorageClass() == SC_Extern)
return false;
const FunctionDecl *Prev = this;
@@ -1985,10 +2272,10 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
// If it's not the case that both 'inline' and 'extern' are
// specified on the definition, then it is always externally visible.
if (!Prev->isInlineSpecified() ||
- Prev->getStorageClassAsWritten() != SC_Extern)
+ Prev->getStorageClass() != SC_Extern)
return false;
} else if (Prev->isInlineSpecified() &&
- Prev->getStorageClassAsWritten() != SC_Extern) {
+ Prev->getStorageClass() != SC_Extern) {
return false;
}
}
@@ -2014,8 +2301,8 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
return FoundBody;
}
-/// \brief For an inline function definition in C or C++, determine whether the
-/// definition will be externally visible.
+/// \brief For an inline function definition in C, or for a gnu_inline function
+/// in C++, determine whether the definition will be externally visible.
///
/// Inline function definitions are always available for inlining optimizations.
/// However, depending on the language dialect, declaration specifiers, and
@@ -2043,7 +2330,7 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
// 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))
+ if (!(isInlineSpecified() && getStorageClass() == SC_Extern))
return true;
// If any declaration is 'inline' but not 'extern', then this definition
@@ -2052,13 +2339,17 @@ bool FunctionDecl::isInlineDefinitionExternallyVisible() const {
Redecl != RedeclEnd;
++Redecl) {
if (Redecl->isInlineSpecified() &&
- Redecl->getStorageClassAsWritten() != SC_Extern)
+ Redecl->getStorageClass() != SC_Extern)
return true;
}
return false;
}
+ // The rest of this function is C-only.
+ assert(!Context.getLangOpts().CPlusPlus &&
+ "should not use C inline rules in C++");
+
// C99 6.7.4p6:
// [...] If all of the file scope declarations for a function in a
// translation unit include the inline function specifier without extern,
@@ -2118,10 +2409,6 @@ FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
return 0;
}
-MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const {
- return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>();
-}
-
void
FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C,
FunctionDecl *FD,
@@ -2553,18 +2840,17 @@ TagDecl* TagDecl::getCanonicalDecl() {
return getFirstDeclaration();
}
-void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
- TypedefNameDeclOrQualifier = TDD;
+void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) {
+ TypedefNameDeclOrQualifier = TDD;
if (TypeForDecl)
- const_cast<Type*>(TypeForDecl)->ClearLinkageCache();
- ClearLinkageCache();
+ assert(TypeForDecl->isLinkageValid());
+ assert(isLinkageValid());
}
void TagDecl::startDefinition() {
IsBeingDefined = true;
- if (isa<CXXRecordDecl>(this)) {
- CXXRecordDecl *D = cast<CXXRecordDecl>(this);
+ if (CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(this)) {
struct CXXRecordDecl::DefinitionData *Data =
new (getASTContext()) struct CXXRecordDecl::DefinitionData(D);
for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
@@ -2587,6 +2873,16 @@ void TagDecl::completeDefinition() {
TagDecl *TagDecl::getDefinition() const {
if (isCompleteDefinition())
return const_cast<TagDecl *>(this);
+
+ // If it's possible for us to have an out-of-date definition, check now.
+ if (MayHaveOutOfDateDef) {
+ if (IdentifierInfo *II = getIdentifier()) {
+ if (II->isOutOfDate()) {
+ updateOutOfDate(*II);
+ }
+ }
+ }
+
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this))
return CXXRD->getDefinition();
@@ -2643,14 +2939,17 @@ EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC,
bool IsScopedUsingClassTag, bool IsFixed) {
EnumDecl *Enum = new (C) EnumDecl(DC, StartLoc, IdLoc, Id, PrevDecl,
IsScoped, IsScopedUsingClassTag, IsFixed);
+ Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules;
C.getTypeDeclType(Enum, PrevDecl);
return Enum;
}
EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EnumDecl));
- return new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0,
- false, false, false);
+ EnumDecl *Enum = new (Mem) EnumDecl(0, SourceLocation(), SourceLocation(),
+ 0, 0, false, false, false);
+ Enum->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+ return Enum;
}
void EnumDecl::completeDefinition(QualType NewType,
@@ -2708,6 +3007,7 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC,
HasFlexibleArrayMember = false;
AnonymousStructOrUnion = false;
HasObjectMember = false;
+ HasVolatileMember = false;
LoadedFieldsFromExternalStorage = false;
assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!");
}
@@ -2717,14 +3017,18 @@ RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC,
IdentifierInfo *Id, RecordDecl* PrevDecl) {
RecordDecl* R = new (C) RecordDecl(Record, TK, DC, StartLoc, IdLoc, Id,
PrevDecl);
+ R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+
C.getTypeDeclType(R, PrevDecl);
return R;
}
RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(RecordDecl));
- return new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
- SourceLocation(), 0, 0);
+ RecordDecl *R = new (Mem) RecordDecl(Record, TTK_Struct, 0, SourceLocation(),
+ SourceLocation(), 0, 0);
+ R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
+ return R;
}
bool RecordDecl::isInjectedClassName() const {
@@ -2793,7 +3097,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const {
// BlockDecl Implementation
//===----------------------------------------------------------------------===//
-void BlockDecl::setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo) {
+void BlockDecl::setParams(ArrayRef<ParmVarDecl *> NewParamInfo) {
assert(ParamInfo == 0 && "Already has param info!");
// Zero params -> null pointer.
@@ -2871,6 +3175,14 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void ValueDecl::anchor() { }
+bool ValueDecl::isWeak() const {
+ for (attr_iterator I = attr_begin(), E = attr_end(); I != E; ++I)
+ if (isa<WeakAttr>(*I) || isa<WeakRefAttr>(*I))
+ return true;
+
+ return isWeakImported();
+}
+
void ImplicitParamDecl::anchor() { }
ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC,
@@ -2890,12 +3202,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- StorageClass SC, StorageClass SCAsWritten,
+ StorageClass SC,
bool isInlineSpecified,
bool hasWrittenPrototype,
bool isConstexprSpecified) {
FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo,
- T, TInfo, SC, SCAsWritten,
+ T, TInfo, SC,
isInlineSpecified,
isConstexprSpecified);
New->HasWrittenPrototype = hasWrittenPrototype;
@@ -2906,7 +3218,7 @@ FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FunctionDecl));
return new (Mem) FunctionDecl(Function, 0, SourceLocation(),
DeclarationNameInfo(), QualType(), 0,
- SC_None, SC_None, false, false);
+ SC_None, false, false);
}
BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
@@ -3013,6 +3325,17 @@ FileScopeAsmDecl *FileScopeAsmDecl::CreateDeserialized(ASTContext &C,
return new (Mem) FileScopeAsmDecl(0, 0, SourceLocation(), SourceLocation());
}
+void EmptyDecl::anchor() {}
+
+EmptyDecl *EmptyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) {
+ return new (C) EmptyDecl(DC, L);
+}
+
+EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
+ void *Mem = AllocateDeserializedDecl(C, ID, sizeof(EmptyDecl));
+ return new (Mem) EmptyDecl(0, SourceLocation());
+}
+
//===----------------------------------------------------------------------===//
// ImportDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 4400d503f263..bd6d99cd59ea 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -12,19 +12,21 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclBase.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
-#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExternalASTSource.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/Type.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
@@ -39,6 +41,10 @@ using namespace clang;
#define ABSTRACT_DECL(DECL)
#include "clang/AST/DeclNodes.inc"
+void Decl::updateOutOfDate(IdentifierInfo &II) const {
+ getASTContext().getExternalSource()->updateOutOfDateIdentifier(II);
+}
+
void *Decl::AllocateDeserializedDecl(const ASTContext &Context,
unsigned ID,
unsigned Size) {
@@ -58,6 +64,11 @@ void *Decl::AllocateDeserializedDecl(const ASTContext &Context,
return Result;
}
+Module *Decl::getOwningModuleSlow() const {
+ assert(isFromASTFile() && "Not from AST file?");
+ return getASTContext().getExternalSource()->getModule(getOwningModuleID());
+}
+
const char *Decl::getDeclKindName() const {
switch (DeclKind) {
default: llvm_unreachable("Declaration not in DeclNodes.inc!");
@@ -180,8 +191,11 @@ void PrettyStackTraceDecl::print(raw_ostream &OS) const {
OS << Message;
- if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl))
- OS << " '" << DN->getQualifiedNameAsString() << '\'';
+ if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl)) {
+ OS << " '";
+ DN->printQualifiedName(OS);
+ OS << '\'';
+ }
OS << '\n';
}
@@ -253,6 +267,19 @@ ASTMutationListener *Decl::getASTMutationListener() const {
return getASTContext().getASTMutationListener();
}
+unsigned Decl::getMaxAlignment() const {
+ if (!hasAttrs())
+ return 0;
+
+ unsigned Align = 0;
+ const AttrVec &V = getAttrs();
+ ASTContext &Ctx = getASTContext();
+ specific_attr_iterator<AlignedAttr> I(V.begin()), E(V.end());
+ for (; I != E; ++I)
+ Align = std::max(Align, I->getAlignment(Ctx));
+ return Align;
+}
+
bool Decl::isUsed(bool CheckUsedAttr) const {
if (Used)
return true;
@@ -260,13 +287,7 @@ bool Decl::isUsed(bool CheckUsedAttr) const {
// Check for used attribute.
if (CheckUsedAttr && hasAttr<UsedAttr>())
return true;
-
- // Check redeclarations for used attribute.
- for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
- if ((CheckUsedAttr && I->hasAttr<UsedAttr>()) || I->Used)
- return true;
- }
-
+
return false;
}
@@ -414,7 +435,7 @@ bool Decl::canBeWeakImported(bool &IsDefinition) const {
// Variables, if they aren't definitions.
if (const VarDecl *Var = dyn_cast<VarDecl>(this)) {
- if (!Var->hasExternalStorage() || Var->getInit()) {
+ if (Var->isThisDeclarationADefinition()) {
IsDefinition = true;
return false;
}
@@ -541,6 +562,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCCategory:
case ObjCCategoryImpl:
case Import:
+ case OMPThreadPrivate:
+ case Empty:
// Never looked up by name.
return 0;
}
@@ -789,6 +812,17 @@ bool DeclContext::isExternCContext() const {
return false;
}
+bool DeclContext::isExternCXXContext() const {
+ const DeclContext *DC = this;
+ while (DC->DeclKind != Decl::TranslationUnit) {
+ if (DC->DeclKind == Decl::LinkageSpec)
+ return cast<LinkageSpecDecl>(DC)->getLanguage()
+ == LinkageSpecDecl::lang_cxx;
+ DC = DC->getParent();
+ }
+ return false;
+}
+
bool DeclContext::Encloses(const DeclContext *DC) const {
if (getPrimaryContext() != this)
return getPrimaryContext()->Encloses(DC);
@@ -862,7 +896,7 @@ DeclContext *DeclContext::getPrimaryContext() {
}
void
-DeclContext::collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts){
+DeclContext::collectAllContexts(SmallVectorImpl<DeclContext *> &Contexts){
Contexts.clear();
if (DeclKind != Decl::Namespace) {
@@ -900,6 +934,21 @@ DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls,
return std::make_pair(FirstNewDecl, PrevDecl);
}
+/// \brief We have just acquired external visible storage, and we already have
+/// built a lookup map. For every name in the map, pull in the new names from
+/// the external storage.
+void DeclContext::reconcileExternalVisibleStorage() {
+ assert(NeedToReconcileExternalVisibleStorage && LookupPtr.getPointer());
+ NeedToReconcileExternalVisibleStorage = false;
+
+ StoredDeclsMap &Map = *LookupPtr.getPointer();
+ ExternalASTSource *Source = getParentASTContext().getExternalSource();
+ for (StoredDeclsMap::iterator I = Map.begin(); I != Map.end(); ++I) {
+ I->second.removeExternalDecls();
+ Source->FindExternalVisibleDeclsByName(this, I->first);
+ }
+}
+
/// \brief Load the declarations within this lexical storage from an
/// external source.
void
@@ -950,9 +999,8 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC,
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
- StoredDeclsList &List = (*Map)[Name];
- assert(List.isNull());
- (void) List;
+ // Add an entry to the map for this name, if it's not already present.
+ (*Map)[Name];
return DeclContext::lookup_result();
}
@@ -962,7 +1010,6 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
DeclarationName Name,
ArrayRef<NamedDecl*> Decls) {
ASTContext &Context = DC->getParentASTContext();
-
StoredDeclsMap *Map;
if (!(Map = DC->LookupPtr.getPointer()))
Map = DC->CreateStoredDeclsMap(Context);
@@ -973,6 +1020,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
if (List.isNull())
List.setOnlyValue(*I);
else
+ // FIXME: Need declarationReplaces handling for redeclarations in modules.
List.AddSubsequentDecl(*I);
}
@@ -1114,16 +1162,18 @@ static bool shouldBeHidden(NamedDecl *D) {
StoredDeclsMap *DeclContext::buildLookup() {
assert(this == getPrimaryContext() && "buildLookup called on non-primary DC");
+ // FIXME: Should we keep going if hasExternalVisibleStorage?
if (!LookupPtr.getInt())
return LookupPtr.getPointer();
- llvm::SmallVector<DeclContext *, 2> Contexts;
+ SmallVector<DeclContext *, 2> Contexts;
collectAllContexts(Contexts);
for (unsigned I = 0, N = Contexts.size(); I != N; ++I)
buildLookupImpl(Contexts[I]);
// We no longer have any lazy decls.
LookupPtr.setInt(false);
+ NeedToReconcileExternalVisibleStorage = false;
return LookupPtr.getPointer();
}
@@ -1162,18 +1212,33 @@ DeclContext::lookup(DeclarationName Name) {
return PrimaryContext->lookup(Name);
if (hasExternalVisibleStorage()) {
- // If a PCH has a result for this name, and we have a local declaration, we
- // will have imported the PCH result when adding the local declaration.
- // FIXME: For modules, we could have had more declarations added by module
- // imoprts since we saw the declaration of the local name.
- if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
- StoredDeclsMap::iterator I = Map->find(Name);
- if (I != Map->end())
- return I->second.getLookupResult();
- }
+ StoredDeclsMap *Map = LookupPtr.getPointer();
+ if (LookupPtr.getInt())
+ Map = buildLookup();
+ else if (NeedToReconcileExternalVisibleStorage)
+ reconcileExternalVisibleStorage();
+
+ if (!Map)
+ Map = CreateStoredDeclsMap(getParentASTContext());
+
+ // If a PCH/module has a result for this name, and we have a local
+ // declaration, we will have imported the PCH/module result when adding the
+ // local declaration or when reconciling the module.
+ std::pair<StoredDeclsMap::iterator, bool> R =
+ Map->insert(std::make_pair(Name, StoredDeclsList()));
+ if (!R.second)
+ return R.first->second.getLookupResult();
ExternalASTSource *Source = getParentASTContext().getExternalSource();
- return Source->FindExternalVisibleDeclsByName(this, Name);
+ if (Source->FindExternalVisibleDeclsByName(this, Name)) {
+ if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
+ StoredDeclsMap::iterator I = Map->find(Name);
+ if (I != Map->end())
+ return I->second.getLookupResult();
+ }
+ }
+
+ return lookup_result(lookup_iterator(0), lookup_iterator(0));
}
StoredDeclsMap *Map = LookupPtr.getPointer();
@@ -1190,26 +1255,26 @@ DeclContext::lookup(DeclarationName Name) {
return I->second.getLookupResult();
}
-void DeclContext::localUncachedLookup(DeclarationName Name,
- llvm::SmallVectorImpl<NamedDecl *> &Results) {
+void DeclContext::localUncachedLookup(DeclarationName Name,
+ SmallVectorImpl<NamedDecl *> &Results) {
Results.clear();
// If there's no external storage, just perform a normal lookup and copy
// the results.
if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage() && Name) {
lookup_result LookupResults = lookup(Name);
- Results.insert(Results.end(), LookupResults.first, LookupResults.second);
+ Results.insert(Results.end(), LookupResults.begin(), LookupResults.end());
return;
}
// If we have a lookup table, check there first. Maybe we'll get lucky.
- if (Name) {
+ if (Name && !LookupPtr.getInt()) {
if (StoredDeclsMap *Map = LookupPtr.getPointer()) {
StoredDeclsMap::iterator Pos = Map->find(Name);
if (Pos != Map->end()) {
Results.insert(Results.end(),
- Pos->second.getLookupResult().first,
- Pos->second.getLookupResult().second);
+ Pos->second.getLookupResult().begin(),
+ Pos->second.getLookupResult().end());
return;
}
}
@@ -1361,8 +1426,8 @@ DeclContext::getUsingDirectives() const {
// FIXME: Use something more efficient than normal lookup for using
// directives. In C++, using directives are looked up more than anything else.
lookup_const_result Result = lookup(UsingDirectiveDecl::getName());
- return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first),
- reinterpret_cast<udir_iterator>(Result.second));
+ return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.begin()),
+ reinterpret_cast<udir_iterator>(Result.end()));
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 82e630acefba..ffad9ae93cc8 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#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/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
@@ -36,28 +36,33 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
}
CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
- : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
- UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false),
- UserDeclaredMoveAssignment(false), UserDeclaredDestructor(false),
+ : UserDeclaredConstructor(false), UserDeclaredSpecialMembers(0),
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true),
HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false),
HasMutableFields(false), HasOnlyCMembers(true),
- HasInClassInitializer(false),
- HasTrivialDefaultConstructor(true),
+ HasInClassInitializer(false), HasUninitializedReferenceMember(false),
+ NeedOverloadResolutionForMoveConstructor(false),
+ NeedOverloadResolutionForMoveAssignment(false),
+ NeedOverloadResolutionForDestructor(false),
+ DefaultedMoveConstructorIsDeleted(false),
+ DefaultedMoveAssignmentIsDeleted(false),
+ DefaultedDestructorIsDeleted(false),
+ HasTrivialSpecialMembers(SMF_All),
+ DeclaredNonTrivialSpecialMembers(0),
+ HasIrrelevantDestructor(true),
HasConstexprNonCopyMoveConstructor(false),
DefaultedDefaultConstructorIsConstexpr(true),
- HasConstexprDefaultConstructor(false), HasTrivialCopyConstructor(true),
- HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true),
- HasTrivialMoveAssignment(true), HasTrivialDestructor(true),
- HasIrrelevantDestructor(true),
+ HasConstexprDefaultConstructor(false),
HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false),
- UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false),
- DeclaredCopyConstructor(false), DeclaredMoveConstructor(false),
- DeclaredCopyAssignment(false), DeclaredMoveAssignment(false),
- DeclaredDestructor(false), FailedImplicitMoveConstructor(false),
- FailedImplicitMoveAssignment(false), IsLambda(false), NumBases(0),
- NumVBases(0), Bases(), VBases(), Definition(D), FirstFriend(0) {
+ UserProvidedDefaultConstructor(false), DeclaredSpecialMembers(0),
+ ImplicitCopyConstructorHasConstParam(true),
+ ImplicitCopyAssignmentHasConstParam(true),
+ HasDeclaredCopyConstructorWithConstParam(false),
+ HasDeclaredCopyAssignmentWithConstParam(false),
+ FailedImplicitMoveConstructor(false), FailedImplicitMoveAssignment(false),
+ IsLambda(false), NumBases(0), NumVBases(0), Bases(), VBases(),
+ Definition(D), FirstFriend(0) {
}
CXXBaseSpecifier *CXXRecordDecl::DefinitionData::getBasesSlowCase() const {
@@ -82,6 +87,7 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK,
bool DelayTypeCreation) {
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, StartLoc, IdLoc,
Id, PrevDecl);
+ R->MayHaveOutOfDateDef = C.getLangOpts().Modules;
// FIXME: DelayTypeCreation seems like such a hack
if (!DelayTypeCreation)
@@ -96,6 +102,7 @@ CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
0, 0);
R->IsBeingDefined = true;
R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent);
+ R->MayHaveOutOfDateDef = false;
C.getTypeDeclType(R, /*PrevDecl=*/0);
return R;
}
@@ -103,8 +110,11 @@ CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC,
CXXRecordDecl *
CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXRecordDecl));
- return new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(),
- SourceLocation(), 0, 0);
+ CXXRecordDecl *R = new (Mem) CXXRecordDecl(CXXRecord, TTK_Struct, 0,
+ SourceLocation(), SourceLocation(),
+ 0, 0);
+ R->MayHaveOutOfDateDef = false;
+ return R;
}
void
@@ -184,38 +194,35 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
BaseClassDecl->vbases_begin(),
E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) {
// Add this base if it's not already in the list.
- if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType())))
+ if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType()))) {
VBases.push_back(VBase);
+
+ // C++11 [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if each [...] virtual base class B of X
+ // has a copy constructor whose first parameter is of type
+ // 'const B&' or 'const volatile B&' [...]
+ if (CXXRecordDecl *VBaseDecl = VBase->getType()->getAsCXXRecordDecl())
+ if (!VBaseDecl->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+ }
}
if (Base->isVirtual()) {
// Add this base if it's not already in the list.
if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)))
- VBases.push_back(Base);
-
+ 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 default constructor is trivial [...] if:
- // -- its class has [...] no virtual bases
- data().HasTrivialDefaultConstructor = false;
-
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is neither
- // user-provided nor deleted and if
- // -- class X has no virtual functions and no virtual base classes, and
- data().HasTrivialCopyConstructor = false;
- data().HasTrivialMoveConstructor = false;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted and if
- // -- class X has no virtual functions and no virtual base classes, and
- data().HasTrivialCopyAssignment = false;
- data().HasTrivialMoveAssignment = false;
+ // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [default constructor, copy/move constructor, or copy/move assignment
+ // operator for a class X] is trivial [...] if:
+ // -- class X has [...] no virtual base classes
+ data().HasTrivialSpecialMembers &= SMF_Destructor;
// C++0x [class]p7:
// A standard-layout class is a class that: [...]
@@ -232,36 +239,35 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// -- all the direct base classes of its class have trivial default
// constructors.
if (!BaseClassDecl->hasTrivialDefaultConstructor())
- data().HasTrivialDefaultConstructor = false;
-
+ data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
+
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
// [...]
// -- the constructor selected to copy/move each direct base class
// subobject is trivial, and
- // FIXME: C++0x: We need to only consider the selected constructor
- // instead of all of them. For now, we treat a move constructor as being
- // non-trivial if it calls anything other than a trivial move constructor.
if (!BaseClassDecl->hasTrivialCopyConstructor())
- data().HasTrivialCopyConstructor = false;
- if (!BaseClassDecl->hasTrivialMoveConstructor() ||
- !(BaseClassDecl->hasDeclaredMoveConstructor() ||
- BaseClassDecl->needsImplicitMoveConstructor()))
- data().HasTrivialMoveConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
+ // If the base class doesn't have a simple move constructor, we'll eagerly
+ // declare it and perform overload resolution to determine which function
+ // it actually calls. If it does have a simple move constructor, this
+ // check is correct.
+ if (!BaseClassDecl->hasTrivialMoveConstructor())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
// C++0x [class.copy]p27:
// A copy/move assignment operator for class X is trivial if [...]
// [...]
// -- the assignment operator selected to copy/move each direct base
// class subobject is trivial, and
- // FIXME: C++0x: We need to only consider the selected operator instead
- // of all of them.
if (!BaseClassDecl->hasTrivialCopyAssignment())
- data().HasTrivialCopyAssignment = false;
- if (!BaseClassDecl->hasTrivialMoveAssignment() ||
- !(BaseClassDecl->hasDeclaredMoveAssignment() ||
- BaseClassDecl->needsImplicitMoveAssignment()))
- data().HasTrivialMoveAssignment = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment;
+ // If the base class doesn't have a simple move assignment, we'll eagerly
+ // declare it and perform overload resolution to determine which function
+ // it actually calls. If it does have a simple move assignment, this
+ // check is correct.
+ if (!BaseClassDecl->hasTrivialMoveAssignment())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
// C++11 [class.ctor]p6:
// If that user-written default constructor would satisfy the
@@ -270,24 +276,48 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
if (!BaseClassDecl->hasConstexprDefaultConstructor())
data().DefaultedDefaultConstructorIsConstexpr = 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;
+ data().HasTrivialSpecialMembers &= ~SMF_Destructor;
if (!BaseClassDecl->hasIrrelevantDestructor())
data().HasIrrelevantDestructor = false;
+ // C++11 [class.copy]p18:
+ // The implicitly-declared copy assignment oeprator for a class X will
+ // have the form 'X& X::operator=(const X&)' if each direct base class B
+ // of X has a copy assignment operator whose parameter is of type 'const
+ // B&', 'const volatile B&', or 'B' [...]
+ if (!BaseClassDecl->hasCopyAssignmentWithConstParam())
+ data().ImplicitCopyAssignmentHasConstParam = false;
+
+ // C++11 [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if each direct [...] base class B of X
+ // has a copy constructor whose first parameter is of type
+ // 'const B&' or 'const volatile B&' [...]
+ if (!BaseClassDecl->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+
// A class has an Objective-C object member if... or any of its bases
// has an Objective-C object member.
if (BaseClassDecl->hasObjectMember())
setHasObjectMember(true);
+
+ if (BaseClassDecl->hasVolatileMember())
+ setHasVolatileMember(true);
// Keep track of the presence of mutable fields.
if (BaseClassDecl->hasMutableFields())
data().HasMutableFields = true;
+
+ if (BaseClassDecl->hasUninitializedReferenceMember())
+ data().HasUninitializedReferenceMember = true;
+
+ addedClassSubobject(BaseClassDecl);
}
if (VBases.empty())
@@ -296,8 +326,44 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
// Create base specifier for any direct or indirect virtual bases.
data().VBases = new (C) CXXBaseSpecifier[VBases.size()];
data().NumVBases = VBases.size();
- for (int I = 0, E = VBases.size(); I != E; ++I)
+ for (int I = 0, E = VBases.size(); I != E; ++I) {
+ QualType Type = VBases[I]->getType();
+ if (!Type->isDependentType())
+ addedClassSubobject(Type->getAsCXXRecordDecl());
data().getVBases()[I] = *VBases[I];
+ }
+}
+
+void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
+ // C++11 [class.copy]p11:
+ // A defaulted copy/move constructor for a class X is defined as
+ // deleted if X has:
+ // -- a direct or virtual base class B that cannot be copied/moved [...]
+ // -- a non-static data member of class type M (or array thereof)
+ // that cannot be copied or moved [...]
+ if (!Subobj->hasSimpleMoveConstructor())
+ data().NeedOverloadResolutionForMoveConstructor = true;
+
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined as
+ // deleted if X has:
+ // -- a direct or virtual base class B that cannot be copied/moved [...]
+ // -- a non-static data member of class type M (or array thereof)
+ // that cannot be copied or moved [...]
+ if (!Subobj->hasSimpleMoveAssignment())
+ data().NeedOverloadResolutionForMoveAssignment = true;
+
+ // C++11 [class.ctor]p5, C++11 [class.copy]p11, C++11 [class.dtor]p5:
+ // A defaulted [ctor or dtor] for a class X is defined as
+ // deleted if X has:
+ // -- any direct or virtual base class [...] has a type with a destructor
+ // that is deleted or inaccessible from the defaulted [ctor or dtor].
+ // -- any non-static data member has a type with a destructor
+ // that is deleted or inaccessible from the defaulted [ctor or dtor].
+ if (!Subobj->hasSimpleDestructor()) {
+ data().NeedOverloadResolutionForMoveConstructor = true;
+ data().NeedOverloadResolutionForDestructor = true;
+ }
}
/// Callback function for CXXRecordDecl::forallBases that acknowledges
@@ -313,161 +379,29 @@ bool CXXRecordDecl::hasAnyDependentBases() const {
return !forallBases(SawBase, 0);
}
-bool CXXRecordDecl::hasConstCopyConstructor() const {
- return getCopyConstructor(Qualifiers::Const) != 0;
-}
-
bool CXXRecordDecl::isTriviallyCopyable() const {
// C++0x [class]p5:
// A trivially copyable class is a class that:
// -- has no non-trivial copy constructors,
- if (!hasTrivialCopyConstructor()) return false;
+ if (hasNonTrivialCopyConstructor()) return false;
// -- has no non-trivial move constructors,
- if (!hasTrivialMoveConstructor()) return false;
+ if (hasNonTrivialMoveConstructor()) return false;
// -- has no non-trivial copy assignment operators,
- if (!hasTrivialCopyAssignment()) return false;
+ if (hasNonTrivialCopyAssignment()) return false;
// -- has no non-trivial move assignment operators, and
- if (!hasTrivialMoveAssignment()) return false;
+ if (hasNonTrivialMoveAssignment()) return false;
// -- has a trivial destructor.
if (!hasTrivialDestructor()) return false;
return true;
}
-/// \brief Perform a simplistic form of overload resolution that only considers
-/// cv-qualifiers on a single parameter, and return the best overload candidate
-/// (if there is one).
-static CXXMethodDecl *
-GetBestOverloadCandidateSimple(
- const SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) {
- if (Cands.empty())
- return 0;
- if (Cands.size() == 1)
- return Cands[0].first;
-
- unsigned Best = 0, N = Cands.size();
- for (unsigned I = 1; I != N; ++I)
- if (Cands[Best].second.compatiblyIncludes(Cands[I].second))
- Best = I;
-
- for (unsigned I = 0; I != N; ++I)
- if (I != Best && Cands[Best].second.compatiblyIncludes(Cands[I].second))
- return 0;
-
- return Cands[Best].first;
-}
-
-CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{
- ASTContext &Context = getASTContext();
- QualType ClassType
- = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this));
- DeclarationName ConstructorName
- = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(ClassType));
- unsigned FoundTQs;
- SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
- DeclContext::lookup_const_iterator Con, ConEnd;
- for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName);
- Con != ConEnd; ++Con) {
- // C++ [class.copy]p2:
- // A non-template constructor for class X is a copy constructor if [...]
- if (isa<FunctionTemplateDecl>(*Con))
- continue;
-
- CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con);
- if (Constructor->isCopyConstructor(FoundTQs)) {
- if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) ||
- (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const)))
- Found.push_back(std::make_pair(
- const_cast<CXXConstructorDecl *>(Constructor),
- Qualifiers::fromCVRMask(FoundTQs)));
- }
- }
-
- return cast_or_null<CXXConstructorDecl>(
- GetBestOverloadCandidateSimple(Found));
-}
-
-CXXConstructorDecl *CXXRecordDecl::getMoveConstructor() const {
- for (ctor_iterator I = ctor_begin(), E = ctor_end(); I != E; ++I)
- if (I->isMoveConstructor())
- return *I;
-
- return 0;
-}
-
-CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const {
- ASTContext &Context = getASTContext();
- QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
- DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal);
-
- SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found;
- DeclContext::lookup_const_iterator Op, OpEnd;
- for (llvm::tie(Op, OpEnd) = this->lookup(Name); Op != OpEnd; ++Op) {
- // C++ [class.copy]p9:
- // A user-declared copy assignment operator is a non-static non-template
- // member function of class X with exactly one parameter of type X, X&,
- // const X&, volatile X& or const volatile X&.
- const CXXMethodDecl* Method = dyn_cast<CXXMethodDecl>(*Op);
- if (!Method || Method->isStatic() || Method->getPrimaryTemplate())
- continue;
-
- const FunctionProtoType *FnType
- = Method->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Overloaded operator has no prototype.");
- // Don't assert on this; an invalid decl might have been left in the AST.
- if (FnType->getNumArgs() != 1 || FnType->isVariadic())
- continue;
-
- QualType ArgType = FnType->getArgType(0);
- Qualifiers Quals;
- if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) {
- ArgType = Ref->getPointeeType();
- // If we have a const argument and we have a reference to a non-const,
- // this function does not match.
- if (ArgIsConst && !ArgType.isConstQualified())
- continue;
-
- Quals = ArgType.getQualifiers();
- } else {
- // By-value copy-assignment operators are treated like const X&
- // copy-assignment operators.
- Quals = Qualifiers::fromCVRMask(Qualifiers::Const);
- }
-
- if (!Context.hasSameUnqualifiedType(ArgType, Class))
- continue;
-
- // Save this copy-assignment operator. It might be "the one".
- Found.push_back(std::make_pair(const_cast<CXXMethodDecl *>(Method), Quals));
- }
-
- // Use a simplistic form of overload resolution to find the candidate.
- return GetBestOverloadCandidateSimple(Found);
-}
-
-CXXMethodDecl *CXXRecordDecl::getMoveAssignmentOperator() const {
- for (method_iterator I = method_begin(), E = method_end(); I != E; ++I)
- if (I->isMoveAssignmentOperator())
- return *I;
-
- return 0;
-}
-
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::markedConstructorConstexpr(CXXConstructorDecl *CD) {
- if (!CD->isCopyOrMoveConstructor())
- data().HasConstexprNonCopyMoveConstructor = true;
-
- if (CD->isDefaultConstructor())
- data().HasConstexprDefaultConstructor = true;
-}
-
void CXXRecordDecl::addedMember(Decl *D) {
if (!D->isImplicit() &&
!isa<FieldDecl>(D) &&
@@ -502,75 +436,41 @@ void CXXRecordDecl::addedMember(Decl *D) {
// A class that declares or inherits a virtual function is called a
// polymorphic class.
data().Polymorphic = true;
-
- // C++0x [class.ctor]p5
- // A default constructor is trivial [...] if:
- // -- its class has no virtual functions [...]
- data().HasTrivialDefaultConstructor = false;
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if [...]
+ // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25:
+ // A [default constructor, copy/move constructor, or copy/move
+ // assignment operator for a class X] is trivial [...] if:
// -- class X has no virtual functions [...]
- data().HasTrivialCopyConstructor = false;
- data().HasTrivialMoveConstructor = false;
+ data().HasTrivialSpecialMembers &= SMF_Destructor;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if [...]
- // -- class X has no virtual functions [...]
- data().HasTrivialCopyAssignment = false;
- data().HasTrivialMoveAssignment = false;
-
// C++0x [class]p7:
// A standard-layout class is a class that: [...]
// -- has no virtual functions
data().IsStandardLayout = false;
}
}
-
- 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 this is a special member function, note that it was added and then
- // return early.
- if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- if (Constructor->isDefaultConstructor()) {
- data().DeclaredDefaultConstructor = true;
- if (Constructor->isConstexpr()) {
- data().HasConstexprDefaultConstructor = true;
- data().HasConstexprNonCopyMoveConstructor = true;
- }
- } else if (Constructor->isCopyConstructor()) {
- data().DeclaredCopyConstructor = true;
- } else if (Constructor->isMoveConstructor()) {
- data().DeclaredMoveConstructor = true;
- } else
- goto NotASpecialMember;
- return;
- } else if (isa<CXXDestructorDecl>(D)) {
- data().DeclaredDestructor = true;
- return;
- } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
- if (Method->isCopyAssignmentOperator())
- data().DeclaredCopyAssignment = true;
- else if (Method->isMoveAssignmentOperator())
- data().DeclaredMoveAssignment = true;
- else
- goto NotASpecialMember;
- return;
- }
-NotASpecialMember:;
- // Any other implicit declarations are handled like normal declarations.
- }
-
- // Handle (user-declared) constructors.
+ // Notify the listener if an implicit member was added after the definition
+ // was completed.
+ if (!isBeingDefined() && D->isImplicit())
+ if (ASTMutationListener *L = getASTMutationListener())
+ L->AddedCXXImplicitMember(data().Definition, D);
+
+ // The kind of special member this declaration is, if any.
+ unsigned SMKind = 0;
+
+ // Handle constructors.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
- // Note that we have a user-declared constructor.
- data().UserDeclaredConstructor = true;
+ if (!Constructor->isImplicit()) {
+ // Note that we have a user-declared constructor.
+ data().UserDeclaredConstructor = true;
+
+ // C++ [class]p4:
+ // A POD-struct is an aggregate class [...]
+ // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
+ // type is technically an aggregate in C++0x since it wouldn't be in 03.
+ data().PlainOldData = false;
+ }
// Technically, "user-provided" is only defined for special member
// functions, but the intent of the standard is clearly that it should apply
@@ -578,47 +478,29 @@ NotASpecialMember:;
bool UserProvided = Constructor->isUserProvided();
if (Constructor->isDefaultConstructor()) {
- data().DeclaredDefaultConstructor = true;
- if (UserProvided) {
- // C++0x [class.ctor]p5:
- // A default constructor is trivial if it is not user-provided [...]
- data().HasTrivialDefaultConstructor = false;
+ SMKind |= SMF_DefaultConstructor;
+
+ if (UserProvided)
data().UserProvidedDefaultConstructor = true;
- }
- if (Constructor->isConstexpr()) {
+ if (Constructor->isConstexpr())
data().HasConstexprDefaultConstructor = true;
- data().HasConstexprNonCopyMoveConstructor = true;
- }
}
- // Note when we have a user-declared copy or move constructor, which will
- // suppress the implicit declaration of those constructors.
if (!FunTmpl) {
- if (Constructor->isCopyConstructor()) {
- data().UserDeclaredCopyConstructor = true;
- data().DeclaredCopyConstructor = true;
-
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is not
- // user-provided [...]
- if (UserProvided)
- data().HasTrivialCopyConstructor = false;
- } else if (Constructor->isMoveConstructor()) {
- data().UserDeclaredMoveConstructor = true;
- data().DeclaredMoveConstructor = true;
-
- // C++0x [class.copy]p13:
- // A copy/move constructor for class X is trivial if it is not
- // user-provided [...]
- if (UserProvided)
- data().HasTrivialMoveConstructor = false;
- }
+ unsigned Quals;
+ if (Constructor->isCopyConstructor(Quals)) {
+ SMKind |= SMF_CopyConstructor;
+
+ if (Quals & Qualifiers::Const)
+ data().HasDeclaredCopyConstructorWithConstParam = true;
+ } else if (Constructor->isMoveConstructor())
+ SMKind |= SMF_MoveConstructor;
}
- if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor()) {
- // Record if we see any constexpr constructors which are neither copy
- // nor move constructors.
+
+ // Record if we see any constexpr constructors which are neither copy
+ // nor move constructors.
+ if (Constructor->isConstexpr() && !Constructor->isCopyOrMoveConstructor())
data().HasConstexprNonCopyMoveConstructor = true;
- }
// C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class with no user-declared
@@ -626,106 +508,99 @@ NotASpecialMember:;
// C++0x [dcl.init.aggr]p1:
// An aggregate is an array or a class with no user-provided
// constructors [...].
- if (!getASTContext().getLangOpts().CPlusPlus0x || UserProvided)
+ if (getASTContext().getLangOpts().CPlusPlus11
+ ? UserProvided : !Constructor->isImplicit())
data().Aggregate = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class [...]
- // Since the POD bit is meant to be C++03 POD-ness, clear it even if the
- // type is technically an aggregate in C++0x since it wouldn't be in 03.
- data().PlainOldData = false;
-
- return;
}
- // Handle (user-declared) destructors.
+ // Handle destructors.
if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) {
- data().DeclaredDestructor = true;
- data().UserDeclaredDestructor = true;
- data().HasIrrelevantDestructor = false;
-
- // C++ [class]p4:
- // A POD-struct is an aggregate class that has [...] no user-defined
- // destructor.
- // This bit is the C++03 POD bit, not the 0x one.
- data().PlainOldData = false;
-
- // C++11 [class.dtor]p5:
- // A destructor is trivial if it is not user-provided and if
- // -- the destructor is not virtual.
- if (DD->isUserProvided() || DD->isVirtual())
- data().HasTrivialDestructor = false;
+ SMKind |= SMF_Destructor;
- return;
+ if (!DD->isImplicit())
+ data().HasIrrelevantDestructor = false;
+
+ // C++11 [class.dtor]p5:
+ // A destructor is trivial if [...] the destructor is not virtual.
+ if (DD->isVirtual())
+ data().HasTrivialSpecialMembers &= ~SMF_Destructor;
}
-
- // Handle (user-declared) member functions.
+
+ // Handle member functions.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
if (Method->isCopyAssignmentOperator()) {
- // C++ [class]p4:
- // A POD-struct is an aggregate class that [...] has no user-defined
- // copy assignment operator [...].
- // This is the C++03 bit only.
- data().PlainOldData = false;
+ SMKind |= SMF_CopyAssignment;
- // This is a copy assignment operator.
-
- // Suppress the implicit declaration of a copy constructor.
- data().UserDeclaredCopyAssignment = true;
- data().DeclaredCopyAssignment = true;
-
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- if (Method->isUserProvided())
- data().HasTrivialCopyAssignment = false;
-
- return;
+ const ReferenceType *ParamTy =
+ Method->getParamDecl(0)->getType()->getAs<ReferenceType>();
+ if (!ParamTy || ParamTy->getPointeeType().isConstQualified())
+ data().HasDeclaredCopyAssignmentWithConstParam = true;
}
-
- if (Method->isMoveAssignmentOperator()) {
- // This is an extension in C++03 mode, but we'll keep consistency by
- // taking a move assignment operator to induce non-POD-ness
- data().PlainOldData = false;
-
- // This is a move assignment operator.
- data().UserDeclaredMoveAssignment = true;
- data().DeclaredMoveAssignment = true;
- // C++0x [class.copy]p27:
- // A copy/move assignment operator for class X is trivial if it is
- // neither user-provided nor deleted [...]
- if (Method->isUserProvided())
- data().HasTrivialMoveAssignment = false;
- }
+ if (Method->isMoveAssignmentOperator())
+ SMKind |= SMF_MoveAssignment;
// 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 (FunTmpl) {
+ if (Conversion->getPrimaryTemplate()) {
+ // We don't record specializations.
+ } else if (FunTmpl) {
if (FunTmpl->getPreviousDecl())
data().Conversions.replace(FunTmpl->getPreviousDecl(),
FunTmpl);
else
- data().Conversions.addDecl(FunTmpl);
+ data().Conversions.addDecl(getASTContext(), FunTmpl);
} else {
if (Conversion->getPreviousDecl())
data().Conversions.replace(Conversion->getPreviousDecl(),
Conversion);
else
- data().Conversions.addDecl(Conversion);
+ data().Conversions.addDecl(getASTContext(), Conversion);
}
}
-
+
+ if (SMKind) {
+ // If this is the first declaration of a special member, we no longer have
+ // an implicit trivial special member.
+ data().HasTrivialSpecialMembers &=
+ data().DeclaredSpecialMembers | ~SMKind;
+
+ if (!Method->isImplicit() && !Method->isUserProvided()) {
+ // This method is user-declared but not user-provided. We can't work out
+ // whether it's trivial yet (not until we get to the end of the class).
+ // We'll handle this method in finishedDefaultedOrDeletedMember.
+ } else if (Method->isTrivial())
+ data().HasTrivialSpecialMembers |= SMKind;
+ else
+ data().DeclaredNonTrivialSpecialMembers |= SMKind;
+
+ // Note when we have declared a declared special member, and suppress the
+ // implicit declaration of this special member.
+ data().DeclaredSpecialMembers |= SMKind;
+
+ if (!Method->isImplicit()) {
+ data().UserDeclaredSpecialMembers |= SMKind;
+
+ // C++03 [class]p4:
+ // A POD-struct is an aggregate class that has [...] no user-defined
+ // copy assignment operator and no user-defined destructor.
+ //
+ // Since the POD bit is meant to be C++03 POD-ness, and in C++03,
+ // aggregates could not have any constructors, clear it even for an
+ // explicitly defaulted or deleted constructor.
+ // type is technically an aggregate in C++0x since it wouldn't be in 03.
+ //
+ // Also, a user-declared move assignment operator makes a class non-POD.
+ // This is an extension in C++03.
+ data().PlainOldData = false;
+ }
+ }
+
return;
}
-
+
// Handle non-static data members.
if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
// C++ [class.bit]p2:
@@ -785,7 +660,8 @@ NotASpecialMember:;
data().PlainOldData = false;
if (T->isReferenceType()) {
- data().HasTrivialDefaultConstructor = false;
+ if (!Field->hasInClassInitializer())
+ data().HasUninitializedReferenceMember = true;
// C++0x [class]p7:
// A standard-layout class is a class that:
@@ -803,7 +679,7 @@ NotASpecialMember:;
// C++11 [class]p5:
// A default constructor is trivial if [...] no non-static data member
// of its class has a brace-or-equal-initializer.
- data().HasTrivialDefaultConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
// C++11 [dcl.init.aggr]p1:
// An aggregate is a [...] class with [...] no
@@ -815,16 +691,39 @@ NotASpecialMember:;
data().PlainOldData = false;
}
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined
+ // as deleted if X has:
+ // -- a non-static data member of reference type
+ if (T->isReferenceType())
+ data().DefaultedMoveAssignmentIsDeleted = true;
+
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
if (FieldRec->getDefinition()) {
+ addedClassSubobject(FieldRec);
+
+ // C++11 [class.ctor]p5, C++11 [class.copy]p11:
+ // A defaulted [special member] for a class X is defined as
+ // deleted if:
+ // -- X is a union-like class that has a variant member with a
+ // non-trivial [corresponding special member]
+ if (isUnion()) {
+ if (FieldRec->hasNonTrivialMoveConstructor())
+ data().DefaultedMoveConstructorIsDeleted = true;
+ if (FieldRec->hasNonTrivialMoveAssignment())
+ data().DefaultedMoveAssignmentIsDeleted = true;
+ if (FieldRec->hasNonTrivialDestructor())
+ data().DefaultedDestructorIsDeleted = true;
+ }
+
// C++0x [class.ctor]p5:
// A default constructor is trivial [...] if:
// -- for all the non-static data members of its class that are of
// class type (or array thereof), each such class has a trivial
// default constructor.
if (!FieldRec->hasTrivialDefaultConstructor())
- data().HasTrivialDefaultConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_DefaultConstructor;
// C++0x [class.copy]p13:
// A copy/move constructor for class X is trivial if [...]
@@ -832,13 +731,13 @@ NotASpecialMember:;
// -- for each non-static data member of X that is of class type (or
// an array thereof), the constructor selected to copy/move that
// member is trivial;
- // FIXME: C++0x: We don't correctly model 'selected' constructors.
if (!FieldRec->hasTrivialCopyConstructor())
- data().HasTrivialCopyConstructor = false;
- if (!FieldRec->hasTrivialMoveConstructor() ||
- !(FieldRec->hasDeclaredMoveConstructor() ||
- FieldRec->needsImplicitMoveConstructor()))
- data().HasTrivialMoveConstructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyConstructor;
+ // If the field doesn't have a simple move constructor, we'll eagerly
+ // declare the move constructor for this class and we'll decide whether
+ // it's trivial then.
+ if (!FieldRec->hasTrivialMoveConstructor())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveConstructor;
// C++0x [class.copy]p27:
// A copy/move assignment operator for class X is trivial if [...]
@@ -846,20 +745,22 @@ NotASpecialMember:;
// -- for each non-static data member of X that is of class type (or
// an array thereof), the assignment operator selected to
// copy/move that member is trivial;
- // FIXME: C++0x: We don't correctly model 'selected' operators.
if (!FieldRec->hasTrivialCopyAssignment())
- data().HasTrivialCopyAssignment = false;
- if (!FieldRec->hasTrivialMoveAssignment() ||
- !(FieldRec->hasDeclaredMoveAssignment() ||
- FieldRec->needsImplicitMoveAssignment()))
- data().HasTrivialMoveAssignment = false;
+ data().HasTrivialSpecialMembers &= ~SMF_CopyAssignment;
+ // If the field doesn't have a simple move assignment, we'll eagerly
+ // declare the move assignment for this class and we'll decide whether
+ // it's trivial then.
+ if (!FieldRec->hasTrivialMoveAssignment())
+ data().HasTrivialSpecialMembers &= ~SMF_MoveAssignment;
if (!FieldRec->hasTrivialDestructor())
- data().HasTrivialDestructor = false;
+ data().HasTrivialSpecialMembers &= ~SMF_Destructor;
if (!FieldRec->hasIrrelevantDestructor())
data().HasIrrelevantDestructor = false;
if (FieldRec->hasObjectMember())
setHasObjectMember(true);
+ if (FieldRec->hasVolatileMember())
+ setHasVolatileMember(true);
// C++0x [class]p7:
// A standard-layout class is a class that:
@@ -910,12 +811,42 @@ NotASpecialMember:;
// The standard requires any in-class initializer to be a constant
// expression. We consider this to be a defect.
data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ // C++11 [class.copy]p8:
+ // The implicitly-declared copy constructor for a class X will have
+ // the form 'X::X(const X&)' if [...] for all the non-static data
+ // members of X that are of a class type M (or array thereof), each
+ // such class type has a copy constructor whose first parameter is
+ // of type 'const M&' or 'const volatile M&'.
+ if (!FieldRec->hasCopyConstructorWithConstParam())
+ data().ImplicitCopyConstructorHasConstParam = false;
+
+ // C++11 [class.copy]p18:
+ // The implicitly-declared copy assignment oeprator for a class X will
+ // have the form 'X& X::operator=(const X&)' if [...] for all the
+ // non-static data members of X that are of a class type M (or array
+ // thereof), each such class type has a copy assignment operator whose
+ // parameter is of type 'const M&', 'const volatile M&' or 'M'.
+ if (!FieldRec->hasCopyAssignmentWithConstParam())
+ data().ImplicitCopyAssignmentHasConstParam = false;
+
+ if (FieldRec->hasUninitializedReferenceMember() &&
+ !Field->hasInClassInitializer())
+ data().HasUninitializedReferenceMember = true;
}
} else {
// Base element type of field is a non-class type.
if (!T->isLiteralType() ||
(!Field->hasInClassInitializer() && !isUnion()))
data().DefaultedDefaultConstructorIsConstexpr = false;
+
+ // C++11 [class.copy]p23:
+ // A defaulted copy/move assignment operator for a class X is defined
+ // as deleted if X has:
+ // -- a non-static data member of const non-class type (or array
+ // thereof)
+ if (T.isConstQualified())
+ data().DefaultedMoveAssignmentIsDeleted = true;
}
// C++0x [class]p7:
@@ -943,7 +874,41 @@ NotASpecialMember:;
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D))
if (Shadow->getDeclName().getNameKind()
== DeclarationName::CXXConversionFunctionName)
- data().Conversions.addDecl(Shadow, Shadow->getAccess());
+ data().Conversions.addDecl(getASTContext(), Shadow, Shadow->getAccess());
+}
+
+void CXXRecordDecl::finishedDefaultedOrDeletedMember(CXXMethodDecl *D) {
+ assert(!D->isImplicit() && !D->isUserProvided());
+
+ // The kind of special member this declaration is, if any.
+ unsigned SMKind = 0;
+
+ if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
+ if (Constructor->isDefaultConstructor()) {
+ SMKind |= SMF_DefaultConstructor;
+ if (Constructor->isConstexpr())
+ data().HasConstexprDefaultConstructor = true;
+ }
+ if (Constructor->isCopyConstructor())
+ SMKind |= SMF_CopyConstructor;
+ else if (Constructor->isMoveConstructor())
+ SMKind |= SMF_MoveConstructor;
+ else if (Constructor->isConstexpr())
+ // We may now know that the constructor is constexpr.
+ data().HasConstexprNonCopyMoveConstructor = true;
+ } else if (isa<CXXDestructorDecl>(D))
+ SMKind |= SMF_Destructor;
+ else if (D->isCopyAssignmentOperator())
+ SMKind |= SMF_CopyAssignment;
+ else if (D->isMoveAssignmentOperator())
+ SMKind |= SMF_MoveAssignment;
+
+ // Update which trivial / non-trivial special members we have.
+ // addedMember will have skipped this step for this member.
+ if (D->isTrivial())
+ data().HasTrivialSpecialMembers |= SMKind;
+ else
+ data().DeclaredNonTrivialSpecialMembers |= SMKind;
}
bool CXXRecordDecl::isCLike() const {
@@ -1004,7 +969,7 @@ static void CollectVisibleConversions(ASTContext &Context,
bool InVirtual,
AccessSpecifier Access,
const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes,
- UnresolvedSetImpl &Output,
+ ASTUnresolvedSet &Output,
UnresolvedSetImpl &VOutput,
llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) {
// The set of types which have conversions in this class or its
@@ -1015,12 +980,13 @@ static void CollectVisibleConversions(ASTContext &Context,
// Collect the direct conversions and figure out which conversions
// will be hidden in the subclasses.
- UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
- if (!Cs.empty()) {
+ CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin();
+ CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end();
+ if (ConvI != ConvE) {
HiddenTypesBuffer = ParentHiddenTypes;
HiddenTypes = &HiddenTypesBuffer;
- for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) {
+ for (CXXRecordDecl::conversion_iterator I = ConvI; I != ConvE; ++I) {
CanQualType ConvType(GetConversionType(Context, I.getDecl()));
bool Hidden = ParentHiddenTypes.count(ConvType);
if (!Hidden)
@@ -1039,7 +1005,7 @@ static void CollectVisibleConversions(ASTContext &Context,
if (InVirtual)
VOutput.addDecl(I.getDecl(), IAccess);
else
- Output.addDecl(I.getDecl(), IAccess);
+ Output.addDecl(Context, I.getDecl(), IAccess);
}
}
}
@@ -1066,7 +1032,7 @@ static void CollectVisibleConversions(ASTContext &Context,
/// bases. It might be worth special-casing that, really.
static void CollectVisibleConversions(ASTContext &Context,
CXXRecordDecl *Record,
- UnresolvedSetImpl &Output) {
+ ASTUnresolvedSet &Output) {
// The collection of all conversions in virtual bases that we've
// found. These will be added to the output as long as they don't
// appear in the hidden-conversions set.
@@ -1081,10 +1047,11 @@ static void CollectVisibleConversions(ASTContext &Context,
// Go ahead and collect the direct conversions and add them to the
// hidden-types set.
- UnresolvedSetImpl &Cs = *Record->getConversionFunctions();
- Output.append(Cs.begin(), Cs.end());
- for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I)
- HiddenTypes.insert(GetConversionType(Context, I.getDecl()));
+ CXXRecordDecl::conversion_iterator ConvI = Record->conversion_begin();
+ CXXRecordDecl::conversion_iterator ConvE = Record->conversion_end();
+ Output.append(Context, ConvI, ConvE);
+ for (; ConvI != ConvE; ++ConvI)
+ HiddenTypes.insert(GetConversionType(Context, ConvI.getDecl()));
// Recursively collect conversions from base classes.
for (CXXRecordDecl::base_class_iterator
@@ -1101,22 +1068,24 @@ static void CollectVisibleConversions(ASTContext &Context,
for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end();
I != E; ++I) {
if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())))
- Output.addDecl(I.getDecl(), I.getAccess());
+ Output.addDecl(Context, I.getDecl(), I.getAccess());
}
}
/// getVisibleConversionFunctions - get all conversion functions visible
/// in current class; including conversion function templates.
-const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
+std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator>
+CXXRecordDecl::getVisibleConversionFunctions() {
// If root class, all conversions are visible.
if (bases_begin() == bases_end())
- return &data().Conversions;
+ return std::make_pair(data().Conversions.begin(), data().Conversions.end());
// If visible conversion list is already evaluated, return it.
- if (data().ComputedVisibleConversions)
- return &data().VisibleConversions;
- CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
- data().ComputedVisibleConversions = true;
- return &data().VisibleConversions;
+ if (!data().ComputedVisibleConversions) {
+ CollectVisibleConversions(getASTContext(), this, data().VisibleConversions);
+ data().ComputedVisibleConversions = true;
+ }
+ return std::make_pair(data().VisibleConversions.begin(),
+ data().VisibleConversions.end());
}
void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
@@ -1131,7 +1100,7 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) {
// with sufficiently large numbers of directly-declared conversions
// that asymptotic behavior matters.
- UnresolvedSetImpl &Convs = *getConversionFunctions();
+ ASTUnresolvedSet &Convs = data().Conversions;
for (unsigned I = 0, E = Convs.size(); I != E; ++I) {
if (Convs[I].getDecl() == ConvDecl) {
Convs.erase(I);
@@ -1151,10 +1120,6 @@ CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
return 0;
}
-MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const {
- return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>();
-}
-
void
CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD,
TemplateSpecializationKind TSK) {
@@ -1200,12 +1165,11 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
= Context.DeclarationNames.getCXXDestructorName(
Context.getCanonicalType(ClassType));
- DeclContext::lookup_const_iterator I, E;
- llvm::tie(I, E) = lookup(Name);
- if (I == E)
+ DeclContext::lookup_const_result R = lookup(Name);
+ if (R.empty())
return 0;
- CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
+ CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(R.front());
return Dtor;
}
@@ -1225,12 +1189,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
// non-trivial.
struct DefinitionData &Data = data();
Data.PlainOldData = false;
- Data.HasTrivialDefaultConstructor = false;
- Data.HasTrivialCopyConstructor = false;
- Data.HasTrivialMoveConstructor = false;
- Data.HasTrivialCopyAssignment = false;
- Data.HasTrivialMoveAssignment = false;
- Data.HasTrivialDestructor = false;
+ Data.HasTrivialSpecialMembers = 0;
Data.HasIrrelevantDestructor = false;
}
@@ -1270,7 +1229,7 @@ void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) {
for (UnresolvedSetIterator I = data().Conversions.begin(),
E = data().Conversions.end();
I != E; ++I)
- data().Conversions.setAccess(I, (*I)->getAccess());
+ I.setAccess((*I)->getAccess());
}
bool CXXRecordDecl::mayBeAbstract() const {
@@ -1292,6 +1251,42 @@ bool CXXRecordDecl::mayBeAbstract() const {
void CXXMethodDecl::anchor() { }
+bool CXXMethodDecl::isStatic() const {
+ const CXXMethodDecl *MD = this;
+ for (;;) {
+ const CXXMethodDecl *C = MD->getCanonicalDecl();
+ if (C != MD) {
+ MD = C;
+ continue;
+ }
+
+ FunctionTemplateSpecializationInfo *Info =
+ MD->getTemplateSpecializationInfo();
+ if (!Info)
+ break;
+ MD = cast<CXXMethodDecl>(Info->getTemplate()->getTemplatedDecl());
+ }
+
+ if (MD->getStorageClass() == SC_Static)
+ return true;
+
+ DeclarationName Name = getDeclName();
+ // [class.free]p1:
+ // Any allocation function for a class T is a static member
+ // (even if not explicitly declared static).
+ if (Name.getCXXOverloadedOperator() == OO_New ||
+ Name.getCXXOverloadedOperator() == OO_Array_New)
+ return true;
+
+ // [class.free]p6 Any deallocation function for a class X is a static member
+ // (even if not explicitly declared static).
+ if (Name.getCXXOverloadedOperator() == OO_Delete ||
+ Name.getCXXOverloadedOperator() == OO_Array_Delete)
+ return true;
+
+ return false;
+}
+
static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD,
const CXXMethodDecl *BaseMD) {
for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(),
@@ -1324,7 +1319,7 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD,
}
lookup_const_result Candidates = RD->lookup(getDeclName());
- for (NamedDecl * const * I = Candidates.first; I != Candidates.second; ++I) {
+ for (NamedDecl * const * I = Candidates.begin(); I != Candidates.end(); ++I) {
CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*I);
if (!MD)
continue;
@@ -1353,10 +1348,10 @@ CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
- bool isStatic, StorageClass SCAsWritten, bool isInline,
+ StorageClass SC, bool isInline,
bool isConstexpr, SourceLocation EndLocation) {
return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo,
- isStatic, SCAsWritten, isInline, isConstexpr,
+ SC, isInline, isConstexpr,
EndLocation);
}
@@ -1364,7 +1359,7 @@ CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXMethodDecl));
return new (Mem) CXXMethodDecl(CXXMethod, 0, SourceLocation(),
DeclarationNameInfo(), QualType(),
- 0, false, SC_None, false, false,
+ 0, SC_None, false, false,
SourceLocation());
}
@@ -1399,9 +1394,10 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const {
// This function is a usual deallocation function if there are no
// single-parameter deallocation functions of the same kind.
- for (DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName());
- R.first != R.second; ++R.first) {
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*R.first))
+ DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName());
+ for (DeclContext::lookup_const_result::iterator I = R.begin(), E = R.end();
+ I != E; ++I) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I))
if (FD->getNumParams() == 1)
return false;
}
diff --git a/lib/AST/DeclFriend.cpp b/lib/AST/DeclFriend.cpp
index 553d170fc3d5..37a812e71aae 100644
--- a/lib/AST/DeclFriend.cpp
+++ b/lib/AST/DeclFriend.cpp
@@ -27,7 +27,8 @@ FriendDecl *FriendDecl::getNextFriendSlowCase() {
FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
FriendUnion Friend,
- SourceLocation FriendL) {
+ SourceLocation FriendL,
+ ArrayRef<TemplateParameterList*> FriendTypeTPLists) {
#ifndef NDEBUG
if (Friend.is<NamedDecl*>()) {
NamedDecl *D = Friend.get<NamedDecl*>();
@@ -40,15 +41,25 @@ FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC,
// to the original declaration when instantiating members.
assert(D->getFriendObjectKind() ||
(cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind()));
+ // These template parameters are for friend types only.
+ assert(FriendTypeTPLists.size() == 0);
}
#endif
- FriendDecl *FD = new (C) FriendDecl(DC, L, Friend, FriendL);
+ std::size_t Size = sizeof(FriendDecl)
+ + FriendTypeTPLists.size() * sizeof(TemplateParameterList*);
+ void *Mem = C.Allocate(Size);
+ FriendDecl *FD = new (Mem) FriendDecl(DC, L, Friend, FriendL,
+ FriendTypeTPLists);
cast<CXXRecordDecl>(DC)->pushFriendDecl(FD);
return FD;
}
-FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
- void *Mem = AllocateDeserializedDecl(C, ID, sizeof(FriendDecl));
- return new (Mem) FriendDecl(EmptyShell());
+FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, unsigned ID,
+ unsigned FriendTypeNumTPLists) {
+ std::size_t Size = sizeof(FriendDecl)
+ + FriendTypeNumTPLists * sizeof(TemplateParameterList*);
+ void *Mem = AllocateDeserializedDecl(C, ID, Size);
+ return new (Mem) FriendDecl(EmptyShell(), FriendTypeNumTPLists);
}
+
diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp
index 036acc2d77a5..9861f2278f9a 100644
--- a/lib/AST/DeclGroup.cpp
+++ b/lib/AST/DeclGroup.cpp
@@ -12,8 +12,8 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclGroup.h"
-#include "clang/AST/Decl.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
#include "llvm/Support/Allocator.h"
using namespace clang;
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 65a987836ff8..5f5ba52947d6 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -13,8 +13,9 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/Stmt.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Stmt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@@ -53,8 +54,9 @@ void ObjCContainerDecl::anchor() { }
///
ObjCIvarDecl *
ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const {
- lookup_const_iterator Ivar, IvarEnd;
- for (llvm::tie(Ivar, IvarEnd) = lookup(Id); Ivar != IvarEnd; ++Ivar) {
+ lookup_const_result R = lookup(Id);
+ for (lookup_const_iterator Ivar = R.begin(), IvarEnd = R.end();
+ Ivar != IvarEnd; ++Ivar) {
if (ObjCIvarDecl *ivar = dyn_cast<ObjCIvarDecl>(*Ivar))
return ivar;
}
@@ -63,7 +65,16 @@ ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const {
// Get the local instance/class method declared in this interface.
ObjCMethodDecl *
-ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
+ObjCContainerDecl::getMethod(Selector Sel, bool isInstance,
+ bool AllowHidden) const {
+ // If this context is a hidden protocol definition, don't find any
+ // methods there.
+ if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
+ if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+ if (Def->isHidden() && !AllowHidden)
+ return 0;
+ }
+
// Since instance & class methods can have the same name, the loop below
// ensures we get the correct method.
//
@@ -72,8 +83,9 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
// + (float) class_method;
// @end
//
- lookup_const_iterator Meth, MethEnd;
- for (llvm::tie(Meth, MethEnd) = lookup(Sel); Meth != MethEnd; ++Meth) {
+ lookup_const_result R = lookup(Sel);
+ for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end();
+ Meth != MethEnd; ++Meth) {
ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
if (MD && MD->isInstanceMethod() == isInstance)
return MD;
@@ -81,13 +93,86 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) const {
return 0;
}
+/// HasUserDeclaredSetterMethod - This routine returns 'true' if a user declared setter
+/// method was found in the class, its protocols, its super classes or categories.
+/// It also returns 'true' if one of its categories has declared a 'readwrite' property.
+/// This is because, user must provide a setter method for the category's 'readwrite'
+/// property.
+bool
+ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property) const {
+ Selector Sel = Property->getSetterName();
+ lookup_const_result R = lookup(Sel);
+ for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end();
+ Meth != MethEnd; ++Meth) {
+ ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
+ if (MD && MD->isInstanceMethod() && !MD->isImplicit())
+ return true;
+ }
+
+ if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(this)) {
+ // Also look into categories, including class extensions, looking
+ // for a user declared instance method.
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = ID->visible_categories_begin(),
+ CatEnd = ID->visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ if (ObjCMethodDecl *MD = Cat->getInstanceMethod(Sel))
+ if (!MD->isImplicit())
+ return true;
+ if (Cat->IsClassExtension())
+ continue;
+ // Also search through the categories looking for a 'readwrite' declaration
+ // of this property. If one found, presumably a setter will be provided
+ // (properties declared in categories will not get auto-synthesized).
+ for (ObjCContainerDecl::prop_iterator P = Cat->prop_begin(),
+ E = Cat->prop_end(); P != E; ++P)
+ if (P->getIdentifier() == Property->getIdentifier()) {
+ if (P->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite)
+ return true;
+ break;
+ }
+ }
+
+ // Also look into protocols, for a user declared instance method.
+ for (ObjCInterfaceDecl::all_protocol_iterator P =
+ ID->all_referenced_protocol_begin(),
+ PE = ID->all_referenced_protocol_end(); P != PE; ++P) {
+ ObjCProtocolDecl *Proto = (*P);
+ if (Proto->HasUserDeclaredSetterMethod(Property))
+ return true;
+ }
+ // And in its super class.
+ ObjCInterfaceDecl *OSC = ID->getSuperClass();
+ while (OSC) {
+ if (OSC->HasUserDeclaredSetterMethod(Property))
+ return true;
+ OSC = OSC->getSuperClass();
+ }
+ }
+ if (const ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(this))
+ for (ObjCProtocolDecl::protocol_iterator PI = PD->protocol_begin(),
+ E = PD->protocol_end(); PI != E; ++PI) {
+ if ((*PI)->HasUserDeclaredSetterMethod(Property))
+ return true;
+ }
+ return false;
+}
+
ObjCPropertyDecl *
ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC,
IdentifierInfo *propertyID) {
+ // If this context is a hidden protocol definition, don't find any
+ // property.
+ if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(DC)) {
+ if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+ if (Def->isHidden())
+ return 0;
+ }
- DeclContext::lookup_const_iterator I, E;
- llvm::tie(I, E) = DC->lookup(propertyID);
- for ( ; I != E; ++I)
+ DeclContext::lookup_const_result R = DC->lookup(propertyID);
+ for (DeclContext::lookup_const_iterator I = R.begin(), E = R.end(); I != E;
+ ++I)
if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I))
return PD;
@@ -108,6 +193,12 @@ ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const {
/// in 'PropertyId' and returns it. It returns 0, if not found.
ObjCPropertyDecl *
ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
+ // Don't find properties within hidden protocol definitions.
+ if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) {
+ if (const ObjCProtocolDecl *Def = Proto->getDefinition())
+ if (Def->isHidden())
+ return 0;
+ }
if (ObjCPropertyDecl *PD =
ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId))
@@ -126,12 +217,15 @@ ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const {
}
case Decl::ObjCInterface: {
const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this);
- // Look through categories.
- for (ObjCCategoryDecl *Cat = OID->getCategoryList();
- Cat; Cat = Cat->getNextClassCategory())
+ // Look through categories (but not extensions).
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = OID->visible_categories_begin(),
+ CatEnd = OID->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
if (!Cat->IsClassExtension())
if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId))
return P;
+ }
// Look through protocols.
for (ObjCInterfaceDecl::all_protocol_iterator
@@ -190,21 +284,43 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass(
return 0;
}
-void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM) const {
+void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM,
+ PropertyDeclOrder &PO) const {
for (ObjCContainerDecl::prop_iterator P = prop_begin(),
E = prop_end(); P != E; ++P) {
ObjCPropertyDecl *Prop = *P;
PM[Prop->getIdentifier()] = Prop;
+ PO.push_back(Prop);
}
for (ObjCInterfaceDecl::all_protocol_iterator
PI = all_referenced_protocol_begin(),
E = all_referenced_protocol_end(); PI != E; ++PI)
- (*PI)->collectPropertiesToImplement(PM);
+ (*PI)->collectPropertiesToImplement(PM, PO);
// Note, the properties declared only in class extensions are still copied
// into the main @interface's property list, and therefore we don't
// explicitly, have to search class extension properties.
}
+bool ObjCInterfaceDecl::isArcWeakrefUnavailable() const {
+ const ObjCInterfaceDecl *Class = this;
+ while (Class) {
+ if (Class->hasAttr<ArcWeakrefUnavailableAttr>())
+ return true;
+ Class = Class->getSuperClass();
+ }
+ return false;
+}
+
+const ObjCInterfaceDecl *ObjCInterfaceDecl::isObjCRequiresPropertyDefs() const {
+ const ObjCInterfaceDecl *Class = this;
+ while (Class) {
+ if (Class->hasAttr<ObjCRequiresPropertyDefsAttr>())
+ return Class;
+ Class = Class->getSuperClass();
+ }
+ return 0;
+}
+
void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
ASTContext &C)
@@ -254,8 +370,8 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
void ObjCInterfaceDecl::allocateDefinitionData() {
assert(!hasDefinition() && "ObjC class already has a definition");
- Data = new (getASTContext()) DefinitionData();
- Data->Definition = this;
+ Data.setPointer(new (getASTContext()) DefinitionData());
+ Data.getPointer()->Definition = this;
// Make the type point at the definition, now that we have one.
if (TypeForDecl)
@@ -273,24 +389,6 @@ void ObjCInterfaceDecl::startDefinition() {
}
}
-/// getFirstClassExtension - Find first class extension of the given class.
-ObjCCategoryDecl* ObjCInterfaceDecl::getFirstClassExtension() const {
- for (ObjCCategoryDecl *CDecl = getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory())
- if (CDecl->IsClassExtension())
- return CDecl;
- return 0;
-}
-
-/// getNextClassCategory - Find next class extension in list of categories.
-const ObjCCategoryDecl* ObjCCategoryDecl::getNextClassExtension() const {
- for (const ObjCCategoryDecl *CDecl = getNextClassCategory(); CDecl;
- CDecl = CDecl->getNextClassCategory())
- if (CDecl->IsClassExtension())
- return CDecl;
- return 0;
-}
-
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
ObjCInterfaceDecl *&clsDeclared) {
// FIXME: Should make sure no callers ever do this.
@@ -306,9 +404,12 @@ ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
clsDeclared = ClassDecl;
return I;
}
- for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension();
- CDecl; CDecl = CDecl->getNextClassExtension()) {
- if (ObjCIvarDecl *I = CDecl->getIvarDecl(ID)) {
+
+ for (ObjCInterfaceDecl::visible_extensions_iterator
+ Ext = ClassDecl->visible_extensions_begin(),
+ ExtEnd = ClassDecl->visible_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (ObjCIvarDecl *I = Ext->getIvarDecl(ID)) {
clsDeclared = ClassDecl;
return I;
}
@@ -367,21 +468,22 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel,
return MethodDecl;
// Didn't find one yet - now look through categories.
- ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList();
- while (CatDecl) {
- if ((MethodDecl = CatDecl->getMethod(Sel, isInstance)))
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = ClassDecl->visible_categories_begin(),
+ CatEnd = ClassDecl->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if ((MethodDecl = Cat->getMethod(Sel, isInstance)))
return MethodDecl;
if (!shallowCategoryLookup) {
// Didn't find one yet - look through protocols.
const ObjCList<ObjCProtocolDecl> &Protocols =
- CatDecl->getReferencedProtocols();
+ Cat->getReferencedProtocols();
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end(); I != E; ++I)
if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance)))
return MethodDecl;
}
- CatDecl = CatDecl->getNextClassCategory();
}
ClassDecl = ClassDecl->getSuperClass();
@@ -753,7 +855,8 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
if (MovedToSuper)
if (ObjCMethodDecl *
Overridden = Container->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
if (Method != Overridden) {
// We found an override at this category; there is no need to look
// into its protocols.
@@ -771,7 +874,8 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
// Check whether we have a matching method at this level.
if (const ObjCMethodDecl *
Overridden = Container->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
if (Method != Overridden) {
// We found an override at this level; there is no need to look
// into other protocols or categories.
@@ -793,10 +897,13 @@ static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container,
P != PEnd; ++P)
CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper);
- for (const ObjCCategoryDecl *Category = Interface->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- CollectOverriddenMethodsRecurse(Category, Method, Methods,
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Interface->known_categories_begin(),
+ CatEnd = Interface->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ CollectOverriddenMethodsRecurse(*Cat, Method, Methods,
MovedToSuper);
+ }
if (const ObjCInterfaceDecl *Super = Interface->getSuperClass())
return CollectOverriddenMethodsRecurse(Super, Method, Methods,
@@ -827,7 +934,8 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method,
// Start searching for overridden methods using the method from the
// interface as starting point.
if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
Method = IFaceMeth;
CollectOverriddenMethods(ID, Method, overridden);
@@ -839,7 +947,8 @@ static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method,
// Start searching for overridden methods using the method from the
// interface as starting point.
if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(),
- Method->isInstanceMethod()))
+ Method->isInstanceMethod(),
+ /*AllowHidden=*/true))
Method = IFaceMeth;
CollectOverriddenMethods(ID, Method, overridden);
@@ -858,11 +967,14 @@ static void collectOnCategoriesAfterLocation(SourceLocation Loc,
if (!Class)
return;
- for (const ObjCCategoryDecl *Category = Class->getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation()))
- CollectOverriddenMethodsRecurse(Category, Method, Methods, true);
-
+ for (ObjCInterfaceDecl::known_categories_iterator
+ Cat = Class->known_categories_begin(),
+ CatEnd = Class->known_categories_end();
+ Cat != CatEnd; ++Cat) {
+ if (SM.isBeforeInTranslationUnit(Loc, Cat->getLocation()))
+ CollectOverriddenMethodsRecurse(*Cat, Method, Methods, true);
+ }
+
collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM,
Method, Methods);
}
@@ -924,6 +1036,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const {
if (isPropertyAccessor()) {
const ObjCContainerDecl *Container = cast<ObjCContainerDecl>(getParent());
+ // If container is class extension, find its primary class.
+ if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(Container))
+ if (CatDecl->IsClassExtension())
+ Container = CatDecl->getClassInterface();
+
bool IsGetter = (NumArgs == 0);
for (ObjCContainerDecl::prop_iterator I = Container->prop_begin(),
@@ -967,6 +1084,7 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
bool isInternal){
ObjCInterfaceDecl *Result = new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc,
PrevDecl, isInternal);
+ Result->Data.setInt(!C.getLangOpts().Modules);
C.getObjCInterfaceType(Result, PrevDecl);
return Result;
}
@@ -974,8 +1092,11 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C,
ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCInterfaceDecl));
- return new (Mem) ObjCInterfaceDecl(0, SourceLocation(), 0, SourceLocation(),
- 0, false);
+ ObjCInterfaceDecl *Result = new (Mem) ObjCInterfaceDecl(0, SourceLocation(),
+ 0, SourceLocation(),
+ 0, false);
+ Result->Data.setInt(!C.getLangOpts().Modules);
+ return Result;
}
ObjCInterfaceDecl::
@@ -1026,49 +1147,96 @@ void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) {
getASTContext().setObjCImplementation(getDefinition(), ImplD);
}
+namespace {
+ struct SynthesizeIvarChunk {
+ uint64_t Size;
+ ObjCIvarDecl *Ivar;
+ SynthesizeIvarChunk(uint64_t size, ObjCIvarDecl *ivar)
+ : Size(size), Ivar(ivar) {}
+ };
+
+ bool operator<(const SynthesizeIvarChunk & LHS,
+ const SynthesizeIvarChunk &RHS) {
+ return LHS.Size < RHS.Size;
+ }
+}
+
/// all_declared_ivar_begin - return first ivar declared in this class,
/// its extensions and its implementation. Lazily build the list on first
/// access.
+///
+/// Caveat: The list returned by this method reflects the current
+/// state of the parser. The cache will be updated for every ivar
+/// added by an extension or the implementation when they are
+/// encountered.
+/// See also ObjCIvarDecl::Create().
ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() {
// FIXME: Should make sure no callers ever do this.
if (!hasDefinition())
return 0;
- if (data().IvarList)
- return data().IvarList;
-
ObjCIvarDecl *curIvar = 0;
- if (!ivar_empty()) {
- ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
- data().IvarList = *I; ++I;
- for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
- curIvar->setNextIvar(*I);
- }
-
- for (const ObjCCategoryDecl *CDecl = getFirstClassExtension(); CDecl;
- CDecl = CDecl->getNextClassExtension()) {
- if (!CDecl->ivar_empty()) {
- ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(),
- E = CDecl->ivar_end();
- if (!data().IvarList) {
- data().IvarList = *I; ++I;
- curIvar = data().IvarList;
- }
- for ( ;I != E; curIvar = *I, ++I)
+ if (!data().IvarList) {
+ if (!ivar_empty()) {
+ ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
+ data().IvarList = *I; ++I;
+ for (curIvar = data().IvarList; I != E; curIvar = *I, ++I)
curIvar->setNextIvar(*I);
}
+
+ for (ObjCInterfaceDecl::known_extensions_iterator
+ Ext = known_extensions_begin(),
+ ExtEnd = known_extensions_end();
+ Ext != ExtEnd; ++Ext) {
+ if (!Ext->ivar_empty()) {
+ ObjCCategoryDecl::ivar_iterator
+ I = Ext->ivar_begin(),
+ E = Ext->ivar_end();
+ if (!data().IvarList) {
+ data().IvarList = *I; ++I;
+ curIvar = data().IvarList;
+ }
+ for ( ;I != E; curIvar = *I, ++I)
+ curIvar->setNextIvar(*I);
+ }
+ }
+ data().IvarListMissingImplementation = true;
}
+
+ // cached and complete!
+ if (!data().IvarListMissingImplementation)
+ return data().IvarList;
if (ObjCImplementationDecl *ImplDecl = getImplementation()) {
+ data().IvarListMissingImplementation = false;
if (!ImplDecl->ivar_empty()) {
- ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
- E = ImplDecl->ivar_end();
- if (!data().IvarList) {
- data().IvarList = *I; ++I;
- curIvar = data().IvarList;
+ SmallVector<SynthesizeIvarChunk, 16> layout;
+ for (ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(),
+ E = ImplDecl->ivar_end(); I != E; ++I) {
+ ObjCIvarDecl *IV = *I;
+ if (IV->getSynthesize() && !IV->isInvalidDecl()) {
+ layout.push_back(SynthesizeIvarChunk(
+ IV->getASTContext().getTypeSize(IV->getType()), IV));
+ continue;
+ }
+ if (!data().IvarList)
+ data().IvarList = *I;
+ else
+ curIvar->setNextIvar(*I);
+ curIvar = *I;
+ }
+
+ if (!layout.empty()) {
+ // Order synthesized ivars by their size.
+ std::stable_sort(layout.begin(), layout.end());
+ unsigned Ix = 0, EIx = layout.size();
+ if (!data().IvarList) {
+ data().IvarList = layout[0].Ivar; Ix++;
+ curIvar = data().IvarList;
+ }
+ for ( ; Ix != EIx; curIvar = layout[Ix].Ivar, Ix++)
+ curIvar->setNextIvar(layout[Ix].Ivar);
}
- for ( ;I != E; curIvar = *I, ++I)
- curIvar->setNextIvar(*I);
}
}
return data().IvarList;
@@ -1087,29 +1255,41 @@ ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const {
if (data().ExternallyCompleted)
LoadExternalDefinition();
- for (ObjCCategoryDecl *Category = getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (Category->getIdentifier() == CategoryId)
- return Category;
+ for (visible_categories_iterator Cat = visible_categories_begin(),
+ CatEnd = visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ if (Cat->getIdentifier() == CategoryId)
+ return *Cat;
+ }
+
return 0;
}
ObjCMethodDecl *
ObjCInterfaceDecl::getCategoryInstanceMethod(Selector Sel) const {
- for (ObjCCategoryDecl *Category = getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (ObjCCategoryImplDecl *Impl = Category->getImplementation())
+ for (visible_categories_iterator Cat = visible_categories_begin(),
+ CatEnd = visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ if (ObjCCategoryImplDecl *Impl = Cat->getImplementation())
if (ObjCMethodDecl *MD = Impl->getInstanceMethod(Sel))
return MD;
+ }
+
return 0;
}
ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const {
- for (ObjCCategoryDecl *Category = getCategoryList();
- Category; Category = Category->getNextClassCategory())
- if (ObjCCategoryImplDecl *Impl = Category->getImplementation())
+ for (visible_categories_iterator Cat = visible_categories_begin(),
+ CatEnd = visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ if (ObjCCategoryImplDecl *Impl = Cat->getImplementation())
if (ObjCMethodDecl *MD = Impl->getClassMethod(Sel))
return MD;
+ }
+
return 0;
}
@@ -1141,10 +1321,13 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto,
// 2nd, look up the category.
if (lookupCategory)
- for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl;
- CDecl = CDecl->getNextClassCategory()) {
- for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(),
- E = CDecl->protocol_end(); PI != E; ++PI)
+ for (visible_categories_iterator Cat = visible_categories_begin(),
+ CatEnd = visible_categories_end();
+ Cat != CatEnd;
+ ++Cat) {
+ for (ObjCCategoryDecl::protocol_iterator PI = Cat->protocol_begin(),
+ E = Cat->protocol_end();
+ PI != E; ++PI)
if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI))
return true;
}
@@ -1274,15 +1457,17 @@ ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC,
ObjCProtocolDecl *PrevDecl) {
ObjCProtocolDecl *Result
= new (C) ObjCProtocolDecl(DC, Id, nameLoc, atStartLoc, PrevDecl);
-
+ Result->Data.setInt(!C.getLangOpts().Modules);
return Result;
}
ObjCProtocolDecl *ObjCProtocolDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(ObjCProtocolDecl));
- return new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(), SourceLocation(),
- 0);
+ ObjCProtocolDecl *Result = new (Mem) ObjCProtocolDecl(0, 0, SourceLocation(),
+ SourceLocation(), 0);
+ Result->Data.setInt(!C.getLangOpts().Modules);
+ return Result;
}
ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) {
@@ -1304,6 +1489,12 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
bool isInstance) const {
ObjCMethodDecl *MethodDecl = NULL;
+ // If there is no definition or the definition is hidden, we don't find
+ // anything.
+ const ObjCProtocolDecl *Def = getDefinition();
+ if (!Def || Def->isHidden())
+ return NULL;
+
if ((MethodDecl = getMethod(Sel, isInstance)))
return MethodDecl;
@@ -1314,9 +1505,9 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
}
void ObjCProtocolDecl::allocateDefinitionData() {
- assert(!Data && "Protocol already has a definition!");
- Data = new (getASTContext()) DefinitionData;
- Data->Definition = this;
+ assert(!Data.getPointer() && "Protocol already has a definition!");
+ Data.setPointer(new (getASTContext()) DefinitionData);
+ Data.getPointer()->Definition = this;
}
void ObjCProtocolDecl::startDefinition() {
@@ -1328,17 +1519,22 @@ void ObjCProtocolDecl::startDefinition() {
RD->Data = this->Data;
}
-void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM) const {
- for (ObjCProtocolDecl::prop_iterator P = prop_begin(),
- E = prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = *P;
- // Insert into PM if not there already.
- PM.insert(std::make_pair(Prop->getIdentifier(), Prop));
+void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM,
+ PropertyDeclOrder &PO) const {
+
+ if (const ObjCProtocolDecl *PDecl = getDefinition()) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = *P;
+ // Insert into PM if not there already.
+ PM.insert(std::make_pair(Prop->getIdentifier(), Prop));
+ PO.push_back(Prop);
+ }
+ // Scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ (*PI)->collectPropertiesToImplement(PM, PO);
}
- // Scan through protocol's protocols.
- for (ObjCProtocolDecl::protocol_iterator PI = protocol_begin(),
- E = protocol_end(); PI != E; ++PI)
- (*PI)->collectPropertiesToImplement(PM);
}
@@ -1362,9 +1558,9 @@ ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
IvarLBraceLoc, IvarRBraceLoc);
if (IDecl) {
// Link this category into its class's category list.
- CatDecl->NextClassCategory = IDecl->getCategoryList();
+ CatDecl->NextClassCategory = IDecl->getCategoryListRaw();
if (IDecl->hasDefinition()) {
- IDecl->setCategoryList(CatDecl);
+ IDecl->setCategoryListRaw(CatDecl);
if (ASTMutationListener *L = C.getASTMutationListener())
L->AddedObjCCategoryToInterface(CatDecl, IDecl);
}
@@ -1450,7 +1646,7 @@ void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) {
}
/// FindPropertyImplIvarDecl - This method lookup the ivar in the list of
-/// properties implemented in this category \@implementation block and returns
+/// properties implemented in this \@implementation block and returns
/// the implemented property that uses it.
///
ObjCPropertyImplDecl *ObjCImplDecl::
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
new file mode 100644
index 000000000000..c0d10a0f418c
--- /dev/null
+++ b/lib/AST/DeclOpenMP.cpp
@@ -0,0 +1,60 @@
+//===--- DeclOpenMP.cpp - Declaration OpenMP AST Node Implementation ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief This file implements OMPThreadPrivateDecl class.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclOpenMP.h"
+#include "clang/AST/Expr.h"
+
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// OMPThreadPrivateDecl Implementation.
+//===----------------------------------------------------------------------===//
+
+void OMPThreadPrivateDecl::anchor() { }
+
+OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
+ DeclContext *DC,
+ SourceLocation L,
+ ArrayRef<DeclRefExpr *> VL) {
+ unsigned Size = sizeof(OMPThreadPrivateDecl) +
+ (VL.size() * sizeof(DeclRefExpr *));
+
+ void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>());
+ OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
+ DC, L);
+ D->NumVars = VL.size();
+ D->setVars(VL);
+ return D;
+}
+
+OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID,
+ unsigned N) {
+ unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *));
+
+ void *Mem = AllocateDeserializedDecl(C, ID, Size);
+ OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
+ 0, SourceLocation());
+ D->NumVars = N;
+ return D;
+}
+
+void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) {
+ assert(VL.size() == NumVars &&
+ "Number of variables is not the same as the preallocated buffer");
+ DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1);
+ std::copy(VL.begin(), VL.end(), Vars);
+}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 386ad66c9917..c3bf8f89b297 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -7,15 +7,16 @@
//
//===----------------------------------------------------------------------===//
//
-// This file implements the Decl::dump method, which pretty print the
+// This file implements the Decl::print method, which pretty prints the
// AST back out to C/Objective-C/C++/Objective-C++ code.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/PrettyPrinter.h"
@@ -50,7 +51,9 @@ namespace {
void VisitEnumDecl(EnumDecl *D);
void VisitRecordDecl(RecordDecl *D);
void VisitEnumConstantDecl(EnumConstantDecl *D);
+ void VisitEmptyDecl(EmptyDecl *D);
void VisitFunctionDecl(FunctionDecl *D);
+ void VisitFriendDecl(FriendDecl *D);
void VisitFieldDecl(FieldDecl *D);
void VisitVarDecl(VarDecl *D);
void VisitLabelDecl(LabelDecl *D);
@@ -79,9 +82,10 @@ namespace {
void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
+ void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
void PrintTemplateParameters(const TemplateParameterList *Params,
- const TemplateArgumentList *Args);
+ const TemplateArgumentList *Args = 0);
void prettyPrintAttributes(Decl *D);
};
}
@@ -174,16 +178,6 @@ void DeclContext::dumpDeclContext() const {
Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false);
}
-void Decl::dump() const {
- dump(llvm::errs());
-}
-
-void Decl::dump(raw_ostream &Out) const {
- PrintingPolicy Policy = getASTContext().getPrintingPolicy();
- Policy.DumpSourceManager = &getASTContext().getSourceManager();
- print(Out, Policy, /*Indentation*/ 0, /*PrintInstantiation*/ true);
-}
-
raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
for (unsigned i = 0; i != Indentation; ++i)
Out << " ";
@@ -191,7 +185,7 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
}
void DeclPrinter::prettyPrintAttributes(Decl *D) {
- if (Policy.SuppressAttributes)
+ if (Policy.PolishForDeclaration)
return;
if (D->hasAttrs()) {
@@ -240,18 +234,18 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
if (isa<ObjCIvarDecl>(*D))
continue;
- if (!Policy.DumpSourceManager) {
- // Skip over implicit declarations in pretty-printing mode.
- if (D->isImplicit()) continue;
- // FIXME: Ugly hack so we don't pretty-print the builtin declaration
- // of __builtin_va_list or __[u]int128_t. There should be some other way
- // to check that.
- if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
- if (IdentifierInfo *II = ND->getIdentifier()) {
- if (II->isStr("__builtin_va_list") ||
- II->isStr("__int128_t") || II->isStr("__uint128_t"))
- continue;
- }
+ // Skip over implicit declarations in pretty-printing mode.
+ if (D->isImplicit())
+ continue;
+
+ // FIXME: Ugly hack so we don't pretty-print the builtin declaration
+ // of __builtin_va_list or __[u]int128_t. There should be some other way
+ // to check that.
+ if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) {
+ if (IdentifierInfo *II = ND->getIdentifier()) {
+ if (II->isStr("__builtin_va_list") ||
+ II->isStr("__int128_t") || II->isStr("__uint128_t"))
+ continue;
}
}
@@ -298,8 +292,10 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
// FIXME: Need to be able to tell the DeclPrinter when
const char *Terminator = 0;
- if (isa<FunctionDecl>(*D) &&
- cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
+ if (isa<OMPThreadPrivateDecl>(*D))
+ Terminator = 0;
+ else if (isa<FunctionDecl>(*D) &&
+ cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
Terminator = 0;
else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody())
Terminator = 0;
@@ -395,8 +391,9 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
}
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
+ CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D);
if (!Policy.SuppressSpecifiers) {
- switch (D->getStorageClassAsWritten()) {
+ switch (D->getStorageClass()) {
case SC_None: break;
case SC_Extern: Out << "extern "; break;
case SC_Static: Out << "static "; break;
@@ -408,6 +405,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isInlineSpecified()) Out << "inline ";
if (D->isVirtualAsWritten()) Out << "virtual ";
if (D->isModulePrivate()) Out << "__module_private__ ";
+ if (CDecl && CDecl->isExplicitSpecified())
+ Out << "explicit ";
}
PrintingPolicy SubPolicy(Policy);
@@ -483,7 +482,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
}
- if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) {
+ if (CDecl) {
bool HasInitializerList = false;
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
E = CDecl->init_end();
@@ -545,9 +544,15 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
Out << ")";
}
- }
- else
+ if (!Proto.empty())
+ Out << Proto;
+ } else {
+ if (FT && FT->hasTrailingReturn()) {
+ Out << "auto " << Proto << " -> ";
+ Proto.clear();
+ }
AFT->getResultType().print(Out, Policy, Proto);
+ }
} else {
Ty.print(Out, Policy, Proto);
}
@@ -558,6 +563,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
Out << " = 0";
else if (D->isDeletedAsWritten())
Out << " = delete";
+ else if (D->isExplicitlyDefaulted())
+ Out << " = default";
else if (D->doesThisDeclarationHaveABody() && !Policy.TerseOutput) {
if (!D->hasPrototype() && D->getNumParams()) {
// This is a K&R function definition, so we need to print the
@@ -579,6 +586,31 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
}
+void DeclPrinter::VisitFriendDecl(FriendDecl *D) {
+ if (TypeSourceInfo *TSI = D->getFriendType()) {
+ unsigned NumTPLists = D->getFriendTypeNumTemplateParameterLists();
+ for (unsigned i = 0; i < NumTPLists; ++i)
+ PrintTemplateParameters(D->getFriendTypeTemplateParameterList(i));
+ Out << "friend ";
+ Out << " " << TSI->getType().getAsString(Policy);
+ }
+ else if (FunctionDecl *FD =
+ dyn_cast<FunctionDecl>(D->getFriendDecl())) {
+ Out << "friend ";
+ VisitFunctionDecl(FD);
+ }
+ else if (FunctionTemplateDecl *FTD =
+ dyn_cast<FunctionTemplateDecl>(D->getFriendDecl())) {
+ Out << "friend ";
+ VisitFunctionTemplateDecl(FTD);
+ }
+ else if (ClassTemplateDecl *CTD =
+ dyn_cast<ClassTemplateDecl>(D->getFriendDecl())) {
+ Out << "friend ";
+ VisitRedeclarableTemplateDecl(CTD);
+ }
+}
+
void DeclPrinter::VisitFieldDecl(FieldDecl *D) {
if (!Policy.SuppressSpecifiers && D->isMutable())
Out << "mutable ";
@@ -609,9 +641,9 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) {
void DeclPrinter::VisitVarDecl(VarDecl *D) {
- StorageClass SCAsWritten = D->getStorageClassAsWritten();
- if (!Policy.SuppressSpecifiers && SCAsWritten != SC_None)
- Out << VarDecl::getStorageClassSpecifierString(SCAsWritten) << " ";
+ StorageClass SC = D->getStorageClass();
+ if (!Policy.SuppressSpecifiers && SC != SC_None)
+ Out << VarDecl::getStorageClassSpecifierString(SC) << " ";
if (!Policy.SuppressSpecifiers && D->isThreadSpecified())
Out << "__thread ";
@@ -625,9 +657,14 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) {
Expr *Init = D->getInit();
if (!Policy.SuppressInitializers && Init) {
bool ImplicitInit = false;
- if (CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init))
- ImplicitInit = D->getInitStyle() == VarDecl::CallInit &&
- Construct->getNumArgs() == 0 && !Construct->isListInitialization();
+ if (CXXConstructExpr *Construct =
+ dyn_cast<CXXConstructExpr>(Init->IgnoreImplicit())) {
+ if (D->getInitStyle() == VarDecl::CallInit &&
+ !Construct->isListInitialization()) {
+ ImplicitInit = Construct->getNumArgs() == 0 ||
+ Construct->getArg(0)->isDefaultArgument();
+ }
+ }
if (!ImplicitInit) {
if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init))
Out << "(";
@@ -653,7 +690,7 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) {
}
void DeclPrinter::VisitImportDecl(ImportDecl *D) {
- Out << "@__experimental_modules_import " << D->getImportedModule()->getFullModuleName()
+ Out << "@import " << D->getImportedModule()->getFullModuleName()
<< ";\n";
}
@@ -690,6 +727,10 @@ void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
Out << *D->getAliasedNamespace();
}
+void DeclPrinter::VisitEmptyDecl(EmptyDecl *D) {
+ prettyPrintAttributes(D);
+}
+
void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
if (!Policy.SuppressSpecifiers && D->isModulePrivate())
Out << "__module_private__ ";
@@ -746,8 +787,8 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
Visit(*D->decls_begin());
}
-void DeclPrinter::PrintTemplateParameters(
- const TemplateParameterList *Params, const TemplateArgumentList *Args = 0) {
+void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params,
+ const TemplateArgumentList *Args) {
assert(Params);
assert(!Args || Params->size() == Args->size());
@@ -882,6 +923,8 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
OMD->getBody()->printPretty(Out, 0, Policy);
Out << '\n';
}
+ else if (Policy.PolishForDeclaration)
+ Out << ';';
}
void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
@@ -892,7 +935,17 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) {
Out << "@implementation " << I << " : " << *SID;
else
Out << "@implementation " << I;
- Out << "\n";
+
+ if (OID->ivar_size() > 0) {
+ Out << "{\n";
+ Indentation += Policy.Indentation;
+ for (ObjCImplementationDecl::ivar_iterator I = OID->ivar_begin(),
+ E = OID->ivar_end(); I != E; ++I) {
+ Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n";
+ }
+ Indentation -= Policy.Indentation;
+ Out << "}\n";
+ }
VisitDeclContext(OID, false);
Out << "@end";
}
@@ -905,7 +958,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Out << "@class " << I << ";";
return;
}
-
+ bool eolnOut = false;
if (SID)
Out << "@interface " << I << " : " << *SID;
else
@@ -917,13 +970,12 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
E = Protocols.end(); I != E; ++I)
Out << (I == Protocols.begin() ? '<' : ',') << **I;
- }
-
- if (!Protocols.empty())
Out << "> ";
+ }
if (OID->ivar_size() > 0) {
Out << "{\n";
+ eolnOut = true;
Indentation += Policy.Indentation;
for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(),
E = OID->ivar_end(); I != E; ++I) {
@@ -932,19 +984,33 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) {
Indentation -= Policy.Indentation;
Out << "}\n";
}
+ else if (SID) {
+ Out << "\n";
+ eolnOut = true;
+ }
VisitDeclContext(OID, false);
+ if (!eolnOut)
+ Out << ' ';
Out << "@end";
// FIXME: implement the rest...
}
void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) {
if (!PID->isThisDeclarationADefinition()) {
- Out << "@protocol " << PID->getIdentifier() << ";\n";
+ Out << "@protocol " << *PID << ";\n";
return;
}
-
- Out << "@protocol " << *PID << '\n';
+ // Protocols?
+ const ObjCList<ObjCProtocolDecl> &Protocols = PID->getReferencedProtocols();
+ if (!Protocols.empty()) {
+ Out << "@protocol " << *PID;
+ for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(),
+ E = Protocols.end(); I != E; ++I)
+ Out << (I == Protocols.begin() ? '<' : ',') << **I;
+ Out << ">\n";
+ } else
+ Out << "@protocol " << *PID << '\n';
VisitDeclContext(PID, false);
Out << "@end";
}
@@ -959,6 +1025,17 @@ void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) {
void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) {
Out << "@interface " << *PID->getClassInterface() << '(' << *PID << ")\n";
+ if (PID->ivar_size() > 0) {
+ Out << "{\n";
+ Indentation += Policy.Indentation;
+ for (ObjCCategoryDecl::ivar_iterator I = PID->ivar_begin(),
+ E = PID->ivar_end(); I != E; ++I) {
+ Indent() << I->getType().getAsString(Policy) << ' ' << **I << ";\n";
+ }
+ Indentation -= Policy.Indentation;
+ Out << "}\n";
+ }
+
VisitDeclContext(PID, false);
Out << "@end";
@@ -1040,6 +1117,8 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) {
Out << " )";
}
Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << *PDecl;
+ if (Policy.PolishForDeclaration)
+ Out << ';';
}
void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
@@ -1068,9 +1147,23 @@ DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
Out << "using ";
D->getQualifier()->print(Out, Policy);
- Out << D->getDeclName();
+ Out << D->getName();
}
void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
// ignore
}
+
+void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
+ Out << "#pragma omp threadprivate";
+ if (!D->varlist_empty()) {
+ for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
+ E = D->varlist_end();
+ I != E; ++I) {
+ Out << (I == D->varlist_begin() ? '(' : ',')
+ << *cast<NamedDecl>((*I)->getDecl());
+ }
+ Out << ")";
+ }
+}
+
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index a70983f4c962..0b94f7d2c49b 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/DeclCXX.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>
@@ -128,12 +128,12 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params,
// RedeclarableTemplateDecl Implementation
//===----------------------------------------------------------------------===//
-RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() {
+RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() const {
if (!Common) {
// Walk the previous-declaration chain until we either find a declaration
// with a common pointer or we run out of previous declarations.
- llvm::SmallVector<RedeclarableTemplateDecl *, 2> PrevDecls;
- for (RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
+ SmallVector<const RedeclarableTemplateDecl *, 2> PrevDecls;
+ for (const RedeclarableTemplateDecl *Prev = getPreviousDecl(); Prev;
Prev = Prev->getPreviousDecl()) {
if (Prev->Common) {
Common = Prev->Common;
@@ -184,9 +184,8 @@ static void GenerateInjectedTemplateArgs(ASTContext &Context,
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
QualType ArgType = Context.getTypeDeclType(TTP);
if (TTP->isParameterPack())
- ArgType = Context.getPackExpansionType(ArgType,
- llvm::Optional<unsigned>());
-
+ ArgType = Context.getPackExpansionType(ArgType, None);
+
Arg = TemplateArgument(ArgType);
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
@@ -197,13 +196,12 @@ static void GenerateInjectedTemplateArgs(ASTContext &Context,
if (NTTP->isParameterPack())
E = new (Context) PackExpansionExpr(Context.DependentTy, E,
- NTTP->getLocation(),
- llvm::Optional<unsigned>());
+ NTTP->getLocation(), None);
Arg = TemplateArgument(E);
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
if (TTP->isParameterPack())
- Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>());
+ Arg = TemplateArgument(TemplateName(TTP), Optional<unsigned>());
else
Arg = TemplateArgument(TemplateName(TTP));
}
@@ -241,7 +239,7 @@ FunctionTemplateDecl *FunctionTemplateDecl::CreateDeserialized(ASTContext &C,
}
RedeclarableTemplateDecl::CommonBase *
-FunctionTemplateDecl::newCommon(ASTContext &C) {
+FunctionTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
@@ -304,7 +302,7 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C,
return new (Mem) ClassTemplateDecl(EmptyShell());
}
-void ClassTemplateDecl::LoadLazySpecializations() {
+void ClassTemplateDecl::LoadLazySpecializations() const {
Common *CommonPtr = getCommonPtr();
if (CommonPtr->LazySpecializations) {
ASTContext &Context = getASTContext();
@@ -316,7 +314,7 @@ void ClassTemplateDecl::LoadLazySpecializations() {
}
llvm::FoldingSetVector<ClassTemplateSpecializationDecl> &
-ClassTemplateDecl::getSpecializations() {
+ClassTemplateDecl::getSpecializations() const {
LoadLazySpecializations();
return getCommonPtr()->Specializations;
}
@@ -328,7 +326,7 @@ ClassTemplateDecl::getPartialSpecializations() {
}
RedeclarableTemplateDecl::CommonBase *
-ClassTemplateDecl::newCommon(ASTContext &C) {
+ClassTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
@@ -620,7 +618,7 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id,
TemplateParameterList *Params,
- llvm::ArrayRef<TemplateParameterList*> Expansions) {
+ ArrayRef<TemplateParameterList *> Expansions) {
void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) +
sizeof(TemplateParameterList*) * Expansions.size());
return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params,
@@ -728,6 +726,8 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK,
SpecializedTemplate,
Args, NumArgs,
PrevDecl);
+ Result->MayHaveOutOfDateDef = false;
+
Context.getTypeDeclType(Result, PrevDecl);
return Result;
}
@@ -737,20 +737,19 @@ ClassTemplateSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID,
sizeof(ClassTemplateSpecializationDecl));
- return new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
+ ClassTemplateSpecializationDecl *Result =
+ new (Mem) ClassTemplateSpecializationDecl(ClassTemplateSpecialization);
+ Result->MayHaveOutOfDateDef = false;
+ return Result;
}
-void
-ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S,
- const PrintingPolicy &Policy,
- bool Qualified) const {
- NamedDecl::getNameForDiagnostic(S, Policy, Qualified);
+void ClassTemplateSpecializationDecl::getNameForDiagnostic(
+ raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const {
+ NamedDecl::getNameForDiagnostic(OS, Policy, Qualified);
const TemplateArgumentList &TemplateArgs = getTemplateArgs();
- S += TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.data(),
- TemplateArgs.size(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, TemplateArgs.data(), TemplateArgs.size(), Policy);
}
ClassTemplateDecl *
@@ -857,6 +856,7 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC,
PrevDecl,
SequenceNumber);
Result->setSpecializationKind(TSK_ExplicitSpecialization);
+ Result->MayHaveOutOfDateDef = false;
Context.getInjectedClassNameType(Result, CanonInjectedType);
return Result;
@@ -867,7 +867,10 @@ ClassTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID,
sizeof(ClassTemplatePartialSpecializationDecl));
- return new (Mem) ClassTemplatePartialSpecializationDecl();
+ ClassTemplatePartialSpecializationDecl *Result
+ = new (Mem) ClassTemplatePartialSpecializationDecl();
+ Result->MayHaveOutOfDateDef = false;
+ return Result;
}
//===----------------------------------------------------------------------===//
@@ -919,7 +922,7 @@ void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) {
static_cast<Common *>(Ptr)->~Common();
}
RedeclarableTemplateDecl::CommonBase *
-TypeAliasTemplateDecl::newCommon(ASTContext &C) {
+TypeAliasTemplateDecl::newCommon(ASTContext &C) const {
Common *CommonPtr = new (C) Common;
C.AddDeallocation(DeallocateCommon, CommonPtr);
return CommonPtr;
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 28188d91c10a..e4a41b6ffb50 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -364,6 +364,21 @@ DeclarationNameTable::~DeclarationNameTable() {
delete LiteralNames;
}
+DeclarationName DeclarationNameTable::getCXXConstructorName(CanQualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXConstructorName,
+ Ty.getUnqualifiedType());
+}
+
+DeclarationName DeclarationNameTable::getCXXDestructorName(CanQualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXDestructorName,
+ Ty.getUnqualifiedType());
+}
+
+DeclarationName
+DeclarationNameTable::getCXXConversionFunctionName(CanQualType Ty) {
+ return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty);
+}
+
DeclarationName
DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind,
CanQualType Ty) {
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 5f43fbc251a0..be22ae450b62 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -17,6 +17,7 @@
// Only pay for this in code size in assertions-enabled builds.
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
@@ -37,8 +38,6 @@
#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/SmallString.h"
using namespace clang;
@@ -500,8 +499,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
for (FunctionDecl::param_iterator
I = D->param_begin(), E = D->param_end(); I != E; ++I)
dispatch(*I);
- for (llvm::ArrayRef<NamedDecl*>::iterator
- I = D->getDeclsInPrototypeScope().begin(), E = D->getDeclsInPrototypeScope().end();
+ for (ArrayRef<NamedDecl *>::iterator I = D->getDeclsInPrototypeScope().begin(),
+ E = D->getDeclsInPrototypeScope().end();
I != E; ++I)
dispatch(*I);
if (D->doesThisDeclarationHaveABody())
@@ -749,14 +748,6 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
visitDeclContext(D);
}
- // 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->isThisDeclarationADefinition());
@@ -771,7 +762,17 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I)
visitDeclRef(*I);
}
- visitCategoryList(D->getCategoryList());
+
+ if (!D->visible_categories_empty()) {
+ TemporaryContainer C(*this, "categories");
+
+ for (ObjCInterfaceDecl::visible_categories_iterator
+ Cat = D->visible_categories_begin(),
+ CatEnd = D->visible_categories_end();
+ Cat != CatEnd; ++Cat) {
+ visitDeclRef(*Cat);
+ }
+ }
}
void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) {
visitDeclContext(D);
@@ -923,6 +924,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
case CC_AAPCS: return set("cc", "aapcs");
case CC_AAPCS_VFP: return set("cc", "aapcs_vfp");
case CC_PnaclCall: return set("cc", "pnaclcall");
+ case CC_IntelOclBicc: return set("cc", "intel_ocl_bicc");
}
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index f3a2e0563872..b97f4d1d3a9a 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -11,22 +11,24 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/EvaluatedExprVisitor.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
-#include "clang/Lex/LiteralSupport.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Basic/Builtins.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/LiteralSupport.h"
+#include "clang/Sema/SemaDiagnostic.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -277,7 +279,7 @@ static void computeDeclRefDependence(ASTContext &Ctx, NamedDecl *D, QualType T,
// - an entity with reference type and is initialized with an
// expression that is value-dependent [C++11]
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
- if ((Ctx.getLangOpts().CPlusPlus0x ?
+ if ((Ctx.getLangOpts().CPlusPlus11 ?
Var->getType()->isLiteralType() :
Var->getType()->isIntegralOrEnumerationType()) &&
(Var->getType().isConstQualified() ||
@@ -444,14 +446,6 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
return new (Mem) DeclRefExpr(EmptyShell());
}
-SourceRange DeclRefExpr::getSourceRange() const {
- SourceRange R = getNameInfo().getSourceRange();
- if (hasQualifier())
- R.setBegin(getQualifierLoc().getBeginLoc());
- if (hasExplicitTemplateArgs())
- R.setEnd(getRAngleLoc());
- return R;
-}
SourceLocation DeclRefExpr::getLocStart() const {
if (hasQualifier())
return getQualifierLoc().getBeginLoc();
@@ -483,8 +477,9 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
}
PrintingPolicy Policy(Context.getLangOpts());
- std::string Proto = FD->getQualifiedNameAsString(Policy);
+ std::string Proto;
llvm::raw_string_ostream POut(Proto);
+ FD->printQualifiedName(POut, Policy);
const FunctionDecl *Decl = FD;
if (const FunctionDecl* Pattern = FD->getTemplateInstantiationPattern())
@@ -509,7 +504,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) {
POut << ")";
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
- const FunctionType *FT = cast<FunctionType>(MD->getType().getTypePtr());
+ const FunctionType *FT = MD->getType()->castAs<FunctionType>();
if (FT->isConst())
POut << " const";
if (FT->isVolatile())
@@ -653,16 +648,14 @@ FloatingLiteral::FloatingLiteral(ASTContext &C, const llvm::APFloat &V,
bool isexact, QualType Type, SourceLocation L)
: Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false,
false, false), Loc(L) {
- FloatingLiteralBits.IsIEEE =
- &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad;
+ setSemantics(V.getSemantics());
FloatingLiteralBits.IsExact = isexact;
setValue(C, V);
}
FloatingLiteral::FloatingLiteral(ASTContext &C, EmptyShell Empty)
: Expr(FloatingLiteralClass, Empty) {
- FloatingLiteralBits.IsIEEE =
- &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad;
+ setRawSemantics(IEEEhalf);
FloatingLiteralBits.IsExact = false;
}
@@ -677,6 +670,41 @@ FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) {
return new (C) FloatingLiteral(C, Empty);
}
+const llvm::fltSemantics &FloatingLiteral::getSemantics() const {
+ switch(FloatingLiteralBits.Semantics) {
+ case IEEEhalf:
+ return llvm::APFloat::IEEEhalf;
+ case IEEEsingle:
+ return llvm::APFloat::IEEEsingle;
+ case IEEEdouble:
+ return llvm::APFloat::IEEEdouble;
+ case x87DoubleExtended:
+ return llvm::APFloat::x87DoubleExtended;
+ case IEEEquad:
+ return llvm::APFloat::IEEEquad;
+ case PPCDoubleDouble:
+ return llvm::APFloat::PPCDoubleDouble;
+ }
+ llvm_unreachable("Unrecognised floating semantics");
+}
+
+void FloatingLiteral::setSemantics(const llvm::fltSemantics &Sem) {
+ if (&Sem == &llvm::APFloat::IEEEhalf)
+ FloatingLiteralBits.Semantics = IEEEhalf;
+ else if (&Sem == &llvm::APFloat::IEEEsingle)
+ FloatingLiteralBits.Semantics = IEEEsingle;
+ else if (&Sem == &llvm::APFloat::IEEEdouble)
+ FloatingLiteralBits.Semantics = IEEEdouble;
+ else if (&Sem == &llvm::APFloat::x87DoubleExtended)
+ FloatingLiteralBits.Semantics = x87DoubleExtended;
+ else if (&Sem == &llvm::APFloat::IEEEquad)
+ FloatingLiteralBits.Semantics = IEEEquad;
+ else if (&Sem == &llvm::APFloat::PPCDoubleDouble)
+ FloatingLiteralBits.Semantics = PPCDoubleDouble;
+ else
+ llvm_unreachable("Unknown floating semantics");
+}
+
/// getValueAsApproximateDouble - This returns the value as an inaccurate
/// double. Note that this may cause loss of precision, but is useful for
/// debugging dumps, etc.
@@ -745,7 +773,7 @@ StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) {
return SL;
}
-void StringLiteral::outputString(raw_ostream &OS) {
+void StringLiteral::outputString(raw_ostream &OS) const {
switch (getKind()) {
case Ascii: break; // no prefix.
case Wide: OS << 'L'; break;
@@ -818,7 +846,7 @@ void StringLiteral::outputString(raw_ostream &OS) {
assert(Char <= 0xff &&
"Characters above 0xff should already have been handled.");
- if (isprint(Char))
+ if (isPrintable(Char))
OS << (char)Char;
else // Output anything hard as an octal escape.
OS << '\\'
@@ -1144,6 +1172,12 @@ unsigned CallExpr::isBuiltinCall() const {
return FDecl->getBuiltinID();
}
+bool CallExpr::isUnevaluatedBuiltinCall(ASTContext &Ctx) const {
+ if (unsigned BI = isBuiltinCall())
+ return Ctx.BuiltinInfo.isUnevaluated(BI);
+ return false;
+}
+
QualType CallExpr::getCallReturnType() const {
QualType CalleeType = getCallee()->getType();
if (const PointerType *FnTypePtr = CalleeType->getAs<PointerType>())
@@ -1158,21 +1192,9 @@ QualType CallExpr::getCallReturnType() const {
return FnType->getResultType();
}
-SourceRange CallExpr::getSourceRange() const {
- if (isa<CXXOperatorCallExpr>(this))
- return cast<CXXOperatorCallExpr>(this)->getSourceRange();
-
- SourceLocation begin = getCallee()->getLocStart();
- if (begin.isInvalid() && getNumArgs() > 0)
- begin = getArg(0)->getLocStart();
- SourceLocation end = getRParenLoc();
- if (end.isInvalid() && getNumArgs() > 0)
- end = getArg(getNumArgs() - 1)->getLocEnd();
- return SourceRange(begin, end);
-}
SourceLocation CallExpr::getLocStart() const {
if (isa<CXXOperatorCallExpr>(this))
- return cast<CXXOperatorCallExpr>(this)->getSourceRange().getBegin();
+ return cast<CXXOperatorCallExpr>(this)->getLocStart();
SourceLocation begin = getCallee()->getLocStart();
if (begin.isInvalid() && getNumArgs() > 0)
@@ -1181,7 +1203,7 @@ SourceLocation CallExpr::getLocStart() const {
}
SourceLocation CallExpr::getLocEnd() const {
if (isa<CXXOperatorCallExpr>(this))
- return cast<CXXOperatorCallExpr>(this)->getSourceRange().getEnd();
+ return cast<CXXOperatorCallExpr>(this)->getLocEnd();
SourceLocation end = getRParenLoc();
if (end.isInvalid() && getNumArgs() > 0)
@@ -1309,9 +1331,6 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
return E;
}
-SourceRange MemberExpr::getSourceRange() const {
- return SourceRange(getLocStart(), getLocEnd());
-}
SourceLocation MemberExpr::getLocStart() const {
if (isImplicitAccess()) {
if (hasQualifier())
@@ -1416,6 +1435,7 @@ void CastExpr::CheckCastConsistency() const {
case CK_ARCConsumeObject:
case CK_ARCReclaimReturnedObject:
case CK_ARCExtendBlockObject:
+ case CK_ZeroToOCLEvent:
assert(!getType()->isBooleanType() && "unheralded conversion to bool");
goto CheckNoBasePath;
@@ -1547,6 +1567,8 @@ const char *CastExpr::getCastKindName() const {
return "CopyAndAutoreleaseBlockObject";
case CK_BuiltinFnToFnPtr:
return "BuiltinFnToFnPtr";
+ case CK_ZeroToOCLEvent:
+ return "ZeroToOCLEvent";
}
llvm_unreachable("Unhandled cast kind!");
@@ -1807,10 +1829,10 @@ bool InitListExpr::isStringLiteralInit() const {
return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init);
}
-SourceRange InitListExpr::getSourceRange() const {
+SourceLocation InitListExpr::getLocStart() const {
if (InitListExpr *SyntacticForm = getSyntacticForm())
- return SyntacticForm->getSourceRange();
- SourceLocation Beg = LBraceLoc, End = RBraceLoc;
+ return SyntacticForm->getLocStart();
+ SourceLocation Beg = LBraceLoc;
if (Beg.isInvalid()) {
// Find the first non-null initializer.
for (InitExprsTy::const_iterator I = InitExprs.begin(),
@@ -1822,18 +1844,25 @@ SourceRange InitListExpr::getSourceRange() const {
}
}
}
+ return Beg;
+}
+
+SourceLocation InitListExpr::getLocEnd() const {
+ if (InitListExpr *SyntacticForm = getSyntacticForm())
+ return SyntacticForm->getLocEnd();
+ SourceLocation End = RBraceLoc;
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) {
+ E = InitExprs.rend();
+ I != E; ++I) {
if (Stmt *S = *I) {
- End = S->getSourceRange().getEnd();
+ End = S->getLocEnd();
break;
- }
+ }
}
}
- return SourceRange(Beg, End);
+ return End;
}
/// getFunctionType - Return the underlying function type for this block.
@@ -2115,10 +2144,6 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
return false;
}
- // Ignore casts within macro expansions.
- if (getExprLoc().isMacroID())
- return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx);
-
// If this is a cast to a constructor conversion, check the operand.
// Otherwise, the result of the cast is unused.
if (CE->getCastKind() == CK_ConstructorConversion)
@@ -2581,7 +2606,7 @@ bool Expr::isImplicitCXXThis() const {
/// hasAnyTypeDependentArguments - Determines if any of the expressions
/// in Exprs is type-dependent.
-bool Expr::hasAnyTypeDependentArguments(llvm::ArrayRef<Expr *> Exprs) {
+bool Expr::hasAnyTypeDependentArguments(ArrayRef<Expr *> Exprs) {
for (unsigned I = 0; I < Exprs.size(); ++I)
if (Exprs[I]->isTypeDependent())
return true;
@@ -3025,9 +3050,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return Source->isNullPointerConstant(Ctx, NPC);
}
- // C++0x nullptr_t is always a null pointer constant.
+ // C++11 nullptr_t is always a null pointer constant.
if (getType()->isNullPtrType())
- return NPCK_CXX0X_nullptr;
+ return NPCK_CXX11_nullptr;
if (const RecordType *UT = getType()->getAsUnionType())
if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>())
@@ -3045,7 +3070,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
// test for the value 0. Don't use the C++11 constant expression semantics
// for this, for now; once the dust settles on core issue 903, we might only
// allow a literal 0 here in C++11 mode.
- if (Ctx.getLangOpts().CPlusPlus0x) {
+ if (Ctx.getLangOpts().CPlusPlus11) {
if (!isCXX98IntegralConstantExpr(Ctx))
return NPCK_NotNull;
} else {
@@ -3683,11 +3708,11 @@ SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const {
DesignatedInitExpr *DIE = const_cast<DesignatedInitExpr*>(this);
if (size() == 1)
return DIE->getDesignator(0)->getSourceRange();
- return SourceRange(DIE->getDesignator(0)->getStartLocation(),
- DIE->getDesignator(size()-1)->getEndLocation());
+ return SourceRange(DIE->getDesignator(0)->getLocStart(),
+ DIE->getDesignator(size()-1)->getLocEnd());
}
-SourceRange DesignatedInitExpr::getSourceRange() const {
+SourceLocation DesignatedInitExpr::getLocStart() const {
SourceLocation StartLoc;
Designator &First =
*const_cast<DesignatedInitExpr*>(this)->designators_begin();
@@ -3699,30 +3724,37 @@ SourceRange DesignatedInitExpr::getSourceRange() const {
} else
StartLoc =
SourceLocation::getFromRawEncoding(First.ArrayOrRange.LBracketLoc);
- return SourceRange(StartLoc, getInit()->getSourceRange().getEnd());
+ return StartLoc;
+}
+
+SourceLocation DesignatedInitExpr::getLocEnd() const {
+ return getInit()->getLocEnd();
}
-Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) {
+Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) const {
assert(D.Kind == Designator::ArrayDesignator && "Requires array designator");
- char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ char *Ptr = static_cast<char *>(
+ const_cast<void *>(static_cast<const void *>(this)));
Ptr += sizeof(DesignatedInitExpr);
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
}
-Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) {
+Expr *DesignatedInitExpr::getArrayRangeStart(const Designator &D) const {
assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
- char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ char *Ptr = static_cast<char *>(
+ const_cast<void *>(static_cast<const void *>(this)));
Ptr += sizeof(DesignatedInitExpr);
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1));
}
-Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
+Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator &D) const {
assert(D.Kind == Designator::ArrayRangeDesignator &&
"Requires array range designator");
- char* Ptr = static_cast<char*>(static_cast<void *>(this));
+ char *Ptr = static_cast<char *>(
+ const_cast<void *>(static_cast<const void *>(this)));
Ptr += sizeof(DesignatedInitExpr);
Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr));
return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2));
@@ -3895,7 +3927,7 @@ Stmt::child_range ObjCMessageExpr::children() {
reinterpret_cast<Stmt **>(getArgs() + getNumArgs()));
}
-ObjCArrayLiteral::ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements,
+ObjCArrayLiteral::ObjCArrayLiteral(ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl *Method,
SourceRange SR)
: Expr(ObjCArrayLiteralClass, T, VK_RValue, OK_Ordinary,
@@ -3916,7 +3948,7 @@ ObjCArrayLiteral::ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements,
}
ObjCArrayLiteral *ObjCArrayLiteral::Create(ASTContext &C,
- llvm::ArrayRef<Expr *> Elements,
+ ArrayRef<Expr *> Elements,
QualType T, ObjCMethodDecl * Method,
SourceRange SR) {
void *Mem = C.Allocate(sizeof(ObjCArrayLiteral)
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 55722a2a99af..12a47fcd7829 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -11,12 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/IdentifierTable.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/TypeLoc.h"
+#include "clang/Basic/IdentifierTable.h"
using namespace clang;
@@ -72,11 +73,8 @@ UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) {
}
// CXXScalarValueInitExpr
-SourceRange CXXScalarValueInitExpr::getSourceRange() const {
- SourceLocation Start = RParenLoc;
- if (TypeInfo)
- Start = TypeInfo->getTypeLoc().getBeginLoc();
- return SourceRange(Start, RParenLoc);
+SourceLocation CXXScalarValueInitExpr::getLocStart() const {
+ return TypeInfo ? TypeInfo->getTypeLoc().getBeginLoc() : RParenLoc;
}
// CXXNewExpr
@@ -180,7 +178,8 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
- Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
+ Context.getPointerType(Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(),
FunctionProtoType::ExtProtoInfo())),
VK_RValue, OK_Ordinary,
/*isTypeDependent=*/(Base->isTypeDependent() ||
@@ -217,11 +216,11 @@ QualType CXXPseudoDestructorExpr::getDestroyedType() const {
return QualType();
}
-SourceRange CXXPseudoDestructorExpr::getSourceRange() const {
+SourceLocation CXXPseudoDestructorExpr::getLocEnd() const {
SourceLocation End = DestroyedType.getLocation();
if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo())
End = TInfo->getTypeLoc().getLocalSourceRange().getEnd();
- return SourceRange(Base->getLocStart(), End);
+ return End;
}
// UnresolvedLookupExpr
@@ -419,12 +418,18 @@ DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C,
return E;
}
-SourceRange CXXConstructExpr::getSourceRange() const {
+SourceLocation CXXConstructExpr::getLocStart() const {
if (isa<CXXTemporaryObjectExpr>(this))
- return cast<CXXTemporaryObjectExpr>(this)->getSourceRange();
+ return cast<CXXTemporaryObjectExpr>(this)->getLocStart();
+ return Loc;
+}
+
+SourceLocation CXXConstructExpr::getLocEnd() const {
+ if (isa<CXXTemporaryObjectExpr>(this))
+ return cast<CXXTemporaryObjectExpr>(this)->getLocEnd();
if (ParenRange.isValid())
- return SourceRange(Loc, ParenRange.getEnd());
+ return ParenRange.getEnd();
SourceLocation End = Loc;
for (unsigned I = getNumArgs(); I > 0; --I) {
@@ -438,7 +443,7 @@ SourceRange CXXConstructExpr::getSourceRange() const {
}
}
- return SourceRange(Loc, End);
+ return End;
}
SourceRange CXXOperatorCallExpr::getSourceRangeImpl() const {
@@ -522,13 +527,14 @@ CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
SourceLocation L,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(sizeof(CXXStaticCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXStaticCastExpr *E =
new (Buffer) CXXStaticCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
- RParenLoc);
+ RParenLoc, AngleBrackets);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -546,13 +552,14 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy,
SourceLocation L,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer = C.Allocate(sizeof(CXXDynamicCastExpr)
+ PathSize * sizeof(CXXBaseSpecifier*));
CXXDynamicCastExpr *E =
new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
- RParenLoc);
+ RParenLoc, AngleBrackets);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -602,13 +609,14 @@ CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK,
CastKind K, Expr *Op,
const CXXCastPath *BasePath,
TypeSourceInfo *WrittenTy, SourceLocation L,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
unsigned PathSize = (BasePath ? BasePath->size() : 0);
void *Buffer =
C.Allocate(sizeof(CXXReinterpretCastExpr) + PathSize * sizeof(CXXBaseSpecifier*));
CXXReinterpretCastExpr *E =
new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L,
- RParenLoc);
+ RParenLoc, AngleBrackets);
if (PathSize) E->setCastPath(*BasePath);
return E;
}
@@ -624,8 +632,9 @@ CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T,
ExprValueKind VK, Expr *Op,
TypeSourceInfo *WrittenTy,
SourceLocation L,
- SourceLocation RParenLoc) {
- return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc);
+ SourceLocation RParenLoc,
+ SourceRange AngleBrackets) {
+ return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc, AngleBrackets);
}
CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) {
@@ -716,19 +725,24 @@ CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C,
ArrayRef<Expr*> Args,
SourceRange parenRange,
bool HadMultipleCandidates,
+ bool ListInitialization,
bool ZeroInitialization)
: CXXConstructExpr(C, CXXTemporaryObjectExprClass,
Type->getType().getNonReferenceType(),
Type->getTypeLoc().getBeginLoc(),
Cons, false, Args,
- HadMultipleCandidates, /*FIXME*/false, ZeroInitialization,
+ HadMultipleCandidates,
+ ListInitialization, ZeroInitialization,
CXXConstructExpr::CK_Complete, parenRange),
Type(Type) {
}
-SourceRange CXXTemporaryObjectExpr::getSourceRange() const {
- return SourceRange(Type->getTypeLoc().getBeginLoc(),
- getParenRange().getEnd());
+SourceLocation CXXTemporaryObjectExpr::getLocStart() const {
+ return Type->getTypeLoc().getBeginLoc();
+}
+
+SourceLocation CXXTemporaryObjectExpr::getLocEnd() const {
+ return getParenRange().getEnd();
}
CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T,
@@ -963,9 +977,9 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const {
DeclarationName Name
= Record->getASTContext().DeclarationNames.getCXXOperatorName(OO_Call);
DeclContext::lookup_result Calls = Record->lookup(Name);
- assert(Calls.first != Calls.second && "Missing lambda call operator!");
- CXXMethodDecl *Result = cast<CXXMethodDecl>(*Calls.first++);
- assert(Calls.first == Calls.second && "More than lambda one call operator?");
+ assert(!Calls.empty() && "Missing lambda call operator!");
+ assert(Calls.size() == 1 && "More than one lambda call operator!");
+ CXXMethodDecl *Result = cast<CXXMethodDecl>(Calls.front());
return Result;
}
@@ -1057,8 +1071,8 @@ CXXUnresolvedConstructExpr::CreateEmpty(ASTContext &C, unsigned NumArgs) {
return new (Mem) CXXUnresolvedConstructExpr(Empty, NumArgs);
}
-SourceRange CXXUnresolvedConstructExpr::getSourceRange() const {
- return SourceRange(Type->getTypeLoc().getBeginLoc(), RParenLoc);
+SourceLocation CXXUnresolvedConstructExpr::getLocStart() const {
+ return Type->getTypeLoc().getBeginLoc();
}
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
@@ -1330,7 +1344,7 @@ FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack,
FunctionParmPackExpr *
FunctionParmPackExpr::Create(ASTContext &Context, QualType T,
ParmVarDecl *ParamPack, SourceLocation NameLoc,
- llvm::ArrayRef<Decl*> Params) {
+ ArrayRef<Decl *> Params) {
return new (Context.Allocate(sizeof(FunctionParmPackExpr) +
sizeof(ParmVarDecl*) * Params.size()))
FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data());
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 24ec6bb02074..61bc3e2de5ce 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -11,14 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/ErrorHandling.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/ExprCXX.h"
-#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
typedef Expr::Classification Cl;
@@ -34,21 +34,6 @@ static Cl::Kinds ClassifyConditional(ASTContext &Ctx,
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.");
-}
-
Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const {
assert(!TR->isReferenceType() && "Expressions can't have reference type.");
@@ -100,6 +85,20 @@ static Cl::Kinds ClassifyTemporary(QualType T) {
return Cl::CL_PRValue;
}
+static Cl::Kinds ClassifyExprValueKind(const LangOptions &Lang,
+ const Expr *E,
+ ExprValueKind Kind) {
+ switch (Kind) {
+ case VK_RValue:
+ return Lang.CPlusPlus ? ClassifyTemporary(E->getType()) : 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.");
+}
+
static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
// This function takes the first stab at classifying expressions.
const LangOptions &Lang = Ctx.getLangOpts();
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 6e0b5fca60c0..ae86150ee2a4 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -35,15 +35,16 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/CharUnits.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeLoc.h"
-#include "clang/AST/ASTDiagnostic.h"
-#include "clang/AST/Expr.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstring>
#include <functional>
@@ -317,7 +318,7 @@ namespace {
OptionalDiagnostic &operator<<(const APSInt &I) {
if (Diag) {
- llvm::SmallVector<char, 32> Buffer;
+ SmallVector<char, 32> Buffer;
I.toString(Buffer);
*Diag << StringRef(Buffer.data(), Buffer.size());
}
@@ -326,7 +327,7 @@ namespace {
OptionalDiagnostic &operator<<(const APFloat &F) {
if (Diag) {
- llvm::SmallVector<char, 32> Buffer;
+ SmallVector<char, 32> Buffer;
F.toString(Buffer);
*Diag << StringRef(Buffer.data(), Buffer.size());
}
@@ -383,13 +384,17 @@ namespace {
/// expression is a potential constant expression? If so, some diagnostics
/// are suppressed.
bool CheckingPotentialConstantExpression;
+
+ bool IntOverflowCheckMode;
- EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
+ EvalInfo(const ASTContext &C, Expr::EvalStatus &S,
+ bool OverflowCheckMode=false)
: Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
CallStackDepth(0), NextCallIndex(1),
BottomFrame(*this, SourceLocation(), 0, 0, 0),
EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false),
- CheckingPotentialConstantExpression(false) {}
+ CheckingPotentialConstantExpression(false),
+ IntOverflowCheckMode(OverflowCheckMode) {}
void setEvaluatingDecl(const VarDecl *VD, APValue &Value) {
EvaluatingDecl = VD;
@@ -473,6 +478,8 @@ namespace {
return OptionalDiagnostic();
}
+ bool getIntOverflowCheckMode() { return IntOverflowCheckMode; }
+
/// Diagnose that the evaluation does not produce a C++11 core constant
/// expression.
template<typename LocArg>
@@ -505,8 +512,11 @@ namespace {
/// Should we continue evaluation as much as possible after encountering a
/// construct which can't be folded?
bool keepEvaluatingAfterFailure() {
- return CheckingPotentialConstantExpression &&
- EvalStatus.Diag && EvalStatus.Diag->empty();
+ // Should return true in IntOverflowCheckMode, so that we check for
+ // overflow even if some subexpressions can't be evaluated as constants.
+ return IntOverflowCheckMode ||
+ (CheckingPotentialConstantExpression &&
+ EvalStatus.Diag && EvalStatus.Diag->empty());
}
};
@@ -534,8 +544,7 @@ namespace {
public:
SpeculativeEvaluationRAII(EvalInfo &Info,
- llvm::SmallVectorImpl<PartialDiagnosticAt>
- *NewDiag = 0)
+ SmallVectorImpl<PartialDiagnosticAt> *NewDiag = 0)
: Info(Info), Old(Info.EvalStatus) {
Info.EvalStatus.Diag = NewDiag;
}
@@ -586,7 +595,7 @@ CallStackFrame::~CallStackFrame() {
}
/// Produce a string describing the given constexpr call.
-static void describeCall(CallStackFrame *Frame, llvm::raw_ostream &Out) {
+static void describeCall(CallStackFrame *Frame, raw_ostream &Out) {
unsigned ArgIndex = 0;
bool IsMemberCall = isa<CXXMethodDecl>(Frame->Callee) &&
!isa<CXXConstructorDecl>(Frame->Callee) &&
@@ -634,7 +643,7 @@ void EvalInfo::addCallStack(unsigned Limit) {
continue;
}
- llvm::SmallVector<char, 128> Buffer;
+ SmallVector<char, 128> Buffer;
llvm::raw_svector_ostream Out(Buffer);
describeCall(Frame, Out);
addDiag(Frame->CallLoc, diag::note_constexpr_call_here) << Out.str();
@@ -737,7 +746,7 @@ namespace {
bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
// Outside C++11, do not build a designator referring to a subobject of
// any object: we won't use such a designator for anything.
- if (!Info.getLangOpts().CPlusPlus0x)
+ if (!Info.getLangOpts().CPlusPlus11)
Designator.setInvalid();
return checkNullPointer(Info, E, CSK) &&
Designator.checkSubobject(Info, E, CSK);
@@ -971,7 +980,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
// manufacture when checking potential constant expressions is conservatively
// assumed to be global here.
if (!IsGlobalLValue(Base)) {
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
Info.Diag(Loc, diag::note_constexpr_non_global, 1)
<< IsReferenceType << !Designator.Entries.empty()
@@ -1025,7 +1034,7 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
return true;
// Prvalue constant expressions must be of literal types.
- if (Info.getLangOpts().CPlusPlus0x)
+ if (Info.getLangOpts().CPlusPlus11)
Info.Diag(E, diag::note_constexpr_nonliteral)
<< E->getType();
else
@@ -1462,7 +1471,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// Check that we can fold the initializer. In C++, we will have already done
// this in the cases where it matters for conformance.
- llvm::SmallVector<PartialDiagnosticAt, 8> Notes;
+ SmallVector<PartialDiagnosticAt, 8> Notes;
if (!VD->evaluateValue(Notes)) {
Info.Diag(E, diag::note_constexpr_var_init_non_constant,
Notes.size() + 1) << VD;
@@ -1526,7 +1535,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
// A diagnostic will have already been produced.
return false;
if (Sub.isOnePastTheEnd()) {
- Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ Info.Diag(E, Info.getLangOpts().CPlusPlus11 ?
(unsigned)diag::note_constexpr_read_past_end :
(unsigned)diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -1548,7 +1557,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
if (CAT->getSize().ule(Index)) {
// Note, it should not be possible to form a pointer with a valid
// designator which points more than one past the end of the array.
- Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ Info.Diag(E, Info.getLangOpts().CPlusPlus11 ?
(unsigned)diag::note_constexpr_read_past_end :
(unsigned)diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -1570,7 +1579,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
// Next subobject is a complex number.
uint64_t Index = Sub.Entries[I].ArrayIndex;
if (Index > 1) {
- Info.Diag(E, Info.getLangOpts().CPlusPlus0x ?
+ Info.Diag(E, Info.getLangOpts().CPlusPlus11 ?
(unsigned)diag::note_constexpr_read_past_end :
(unsigned)diag::note_invalid_subexpr_in_const_expr);
return false;
@@ -1795,7 +1804,7 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
// We support folding of const floating-point types, in order to make
// static const data members of such types (supported as an extension)
// more useful.
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
Info.CCEDiag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -1803,7 +1812,7 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
}
} else {
// FIXME: Allow folding of values of any literal type in all languages.
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
Info.Diag(Conv, diag::note_constexpr_ltor_non_constexpr, 1) << VD;
Info.Note(VD->getLocation(), diag::note_declared_at);
} else {
@@ -2080,7 +2089,7 @@ static bool CheckTrivialDefaultConstructor(EvalInfo &Info, SourceLocation Loc,
// call is a core constant expression whether or not the constructor is
// constexpr.
if (!CD->isConstexpr() && !IsValueInitialization) {
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
// FIXME: If DiagDecl is an implicitly-declared special member function,
// we should be much more explicit about why it's not constexpr.
Info.CCEDiag(Loc, diag::note_constexpr_invalid_function, 1)
@@ -2108,7 +2117,7 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc,
if (Definition && Definition->isConstexpr() && !Definition->isInvalidDecl())
return true;
- if (Info.getLangOpts().CPlusPlus0x) {
+ if (Info.getLangOpts().CPlusPlus11) {
const FunctionDecl *DiagDecl = Definition ? Definition : Declaration;
// FIXME: If DiagDecl is an implicitly-declared special member function, we
// should be much more explicit about why it's not constexpr.
@@ -2311,7 +2320,7 @@ private:
// Speculatively evaluate both arms.
{
- llvm::SmallVector<PartialDiagnosticAt, 8> Diag;
+ SmallVector<PartialDiagnosticAt, 8> Diag;
SpeculativeEvaluationRAII Speculate(Info, &Diag);
StmtVisitorTy::Visit(E->getFalseExpr());
@@ -2482,7 +2491,7 @@ public:
const FunctionDecl *FD = 0;
LValue *This = 0, ThisVal;
- llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
bool HasQualifier = false;
// Extract function decl and 'this' pointer from the callee.
@@ -3487,7 +3496,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
if (ZeroInit && !ZeroInitialization(E))
return false;
- llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E->getExprLoc(), This, Args,
cast<CXXConstructorDecl>(Definition), Info,
Result);
@@ -3629,7 +3638,6 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
SmallVector<APValue, 4> Elts;
if (EltTy->isRealFloatingType()) {
const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(EltTy);
- bool isIEESem = &Sem != &APFloat::PPCDoubleDouble;
unsigned FloatEltSize = EltSize;
if (&Sem == &APFloat::x87DoubleExtended)
FloatEltSize = 80;
@@ -3639,7 +3647,7 @@ bool VectorExprEvaluator::VisitCastExpr(const CastExpr* E) {
Elt = SValInt.rotl(i*EltSize+FloatEltSize).trunc(FloatEltSize);
else
Elt = SValInt.rotr(i*EltSize).trunc(FloatEltSize);
- Elts.push_back(APValue(APFloat(Elt, isIEESem)));
+ Elts.push_back(APValue(APFloat(Sem, Elt)));
}
} else if (EltTy->isIntegerType()) {
for (unsigned i = 0; i < NElts; i++) {
@@ -3898,7 +3906,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) {
return false;
}
- llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
+ ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs());
return HandleConstructorCall(E->getExprLoc(), Subobject, Args,
cast<CXXConstructorDecl>(Definition),
Info, *Value);
@@ -4317,7 +4325,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BIstrlen:
// A call to strlen is not a constant expression.
- if (Info.getLangOpts().CPlusPlus0x)
+ if (Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_invalid_function)
<< /*isConstexpr*/0 << /*isConstructor*/0 << "'strlen'";
else
@@ -4419,8 +4427,14 @@ static APSInt CheckedIntArithmetic(EvalInfo &Info, const Expr *E,
APSInt Value(Op(LHS.extend(BitWidth), RHS.extend(BitWidth)), false);
APSInt Result = Value.trunc(LHS.getBitWidth());
- if (Result.extend(BitWidth) != Value)
- HandleOverflow(Info, E, Value, E->getType());
+ if (Result.extend(BitWidth) != Value) {
+ if (Info.getIntOverflowCheckMode())
+ Info.Ctx.getDiagnostics().Report(E->getExprLoc(),
+ diag::warn_integer_constant_overflow)
+ << Result.toString(10) << E->getType();
+ else
+ HandleOverflow(Info, E, Value, E->getType());
+ }
return Result;
}
@@ -4707,9 +4721,14 @@ bool DataRecursiveIntBinOpEvaluator::
return Success(E->getOpcode() == BO_Rem ? LHS % RHS : LHS / RHS, E,
Result);
case BO_Shl: {
- // During constant-folding, a negative shift is an opposite shift. Such
- // a shift is not a constant expression.
- if (RHS.isSigned() && RHS.isNegative()) {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such
+ // a shift is not a constant expression.
CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
RHS = -RHS;
goto shift_right;
@@ -4734,9 +4753,14 @@ bool DataRecursiveIntBinOpEvaluator::
return Success(LHS << SA, E, Result);
}
case BO_Shr: {
- // During constant-folding, a negative shift is an opposite shift. Such a
- // shift is not a constant expression.
- if (RHS.isSigned() && RHS.isNegative()) {
+ if (Info.getLangOpts().OpenCL)
+ // OpenCL 6.3j: shift values are effectively % word size of LHS.
+ RHS &= APSInt(llvm::APInt(RHS.getBitWidth(),
+ static_cast<uint64_t>(LHS.getBitWidth() - 1)),
+ RHS.isUnsigned());
+ else if (RHS.isSigned() && RHS.isNegative()) {
+ // During constant-folding, a negative shift is an opposite shift. Such a
+ // shift is not a constant expression.
CCEDiag(E, diag::note_constexpr_negative_shift) << RHS;
RHS = -RHS;
goto shift_left;
@@ -5362,6 +5386,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_IntegralComplexCast:
case CK_IntegralComplexToFloatingComplex:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
llvm_unreachable("invalid cast kind for integral value");
case CK_BitCast:
@@ -5849,6 +5874,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) {
case CK_ARCExtendBlockObject:
case CK_CopyAndAutoreleaseBlockObject:
case CK_BuiltinFnToFnPtr:
+ case CK_ZeroToOCLEvent:
llvm_unreachable("invalid cast kind for complex value");
case CK_LValueToRValue:
@@ -6191,12 +6217,12 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
return false;
Result = Info.CurrentCall->Temporaries[E];
} else if (E->getType()->isVoidType()) {
- if (!Info.getLangOpts().CPlusPlus0x)
+ if (!Info.getLangOpts().CPlusPlus11)
Info.CCEDiag(E, diag::note_constexpr_nonliteral)
<< E->getType();
if (!EvaluateVoid(E, Info))
return false;
- } else if (Info.getLangOpts().CPlusPlus0x) {
+ } else if (Info.getLangOpts().CPlusPlus11) {
Info.Diag(E, diag::note_constexpr_nonliteral) << E->getType();
return false;
} else {
@@ -6249,26 +6275,39 @@ static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result);
}
-/// EvaluateAsRValue - 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. If this expression is a glvalue, an lvalue-to-rvalue conversion
-/// will be applied to the result.
-bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const {
+static bool FastEvaluateAsRValue(const Expr *Exp, Expr::EvalResult &Result,
+ const ASTContext &Ctx, bool &IsConst) {
// Fast-path evaluations of integer literals, since we sometimes see files
// containing vast quantities of these.
- if (const IntegerLiteral *L = dyn_cast<IntegerLiteral>(this)) {
+ if (const IntegerLiteral *L = dyn_cast<IntegerLiteral>(Exp)) {
Result.Val = APValue(APSInt(L->getValue(),
L->getType()->isUnsignedIntegerType()));
+ IsConst = true;
return true;
}
-
+
// FIXME: Evaluating values of large array and record types can cause
// performance problems. Only do so in C++11 for now.
- if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
- !Ctx.getLangOpts().CPlusPlus0x)
- return false;
+ if (Exp->isRValue() && (Exp->getType()->isArrayType() ||
+ Exp->getType()->isRecordType()) &&
+ !Ctx.getLangOpts().CPlusPlus11) {
+ IsConst = false;
+ return true;
+ }
+ return false;
+}
+
+/// EvaluateAsRValue - 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. If this expression is a glvalue, an lvalue-to-rvalue conversion
+/// will be applied to the result.
+bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const {
+ bool IsConst;
+ if (FastEvaluateAsRValue(this, Result, Ctx, IsConst))
+ return IsConst;
+
EvalInfo Info(Ctx, Result);
return ::EvaluateAsRValue(Info, this, Result.Val);
}
@@ -6309,11 +6348,11 @@ bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx,
const VarDecl *VD,
- llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
+ SmallVectorImpl<PartialDiagnosticAt> &Notes) const {
// FIXME: Evaluating initializers for large array and record types can cause
// performance problems. Only do so in C++11 for now.
if (isRValue() && (getType()->isArrayType() || getType()->isRecordType()) &&
- !Ctx.getLangOpts().CPlusPlus0x)
+ !Ctx.getLangOpts().CPlusPlus11)
return false;
Expr::EvalStatus EStatus;
@@ -6353,8 +6392,10 @@ bool Expr::isEvaluatable(const ASTContext &Ctx) const {
return EvaluateAsRValue(Result, Ctx) && !Result.HasSideEffects;
}
-APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
+APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx,
+ SmallVectorImpl<PartialDiagnosticAt> *Diag) const {
EvalResult EvalResult;
+ EvalResult.Diag = Diag;
bool Result = EvaluateAsRValue(EvalResult, Ctx);
(void)Result;
assert(Result && "Could not evaluate expression");
@@ -6363,6 +6404,17 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
return EvalResult.Val.getInt();
}
+void Expr::EvaluateForOverflow(const ASTContext &Ctx,
+ SmallVectorImpl<PartialDiagnosticAt> *Diags) const {
+ bool IsConst;
+ EvalResult EvalResult;
+ EvalResult.Diag = Diags;
+ if (!FastEvaluateAsRValue(this, EvalResult, Ctx, IsConst)) {
+ EvalInfo Info(Ctx, EvalResult, true);
+ (void)::EvaluateAsRValue(Info, this, EvalResult.Val);
+ }
+}
+
bool Expr::EvalResult::isGlobalLValue() const {
assert(Val.isLValue());
return IsGlobalLValue(Val.getLValueBase());
@@ -6374,54 +6426,55 @@ APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero,
/// comma, etc
-///
-/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof
-/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer
-/// cast+dereference.
// CheckICE - This function does the fundamental ICE checking: the returned
-// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation.
+// ICEDiag contains an ICEKind indicating whether the expression is an ICE,
+// and a (possibly null) SourceLocation indicating the location of the problem.
+//
// Note that to reduce code duplication, this helper does no evaluation
// itself; the caller checks whether the expression is evaluatable, and
// in the rare cases where CheckICE actually cares about the evaluated
// value, it calls into Evalute.
-//
-// Meanings of Val:
-// 0: This expression is an ICE.
-// 1: This expression is not an ICE, but if it isn't evaluated, it's
-// a legal subexpression for an ICE. This return value is used to handle
-// the comma operator in C99 mode.
-// 2: This expression is not an ICE, and is not a legal subexpression for one.
namespace {
+enum ICEKind {
+ /// This expression is an ICE.
+ IK_ICE,
+ /// This expression is not an ICE, but if it isn't evaluated, it's
+ /// a legal subexpression for an ICE. This return value is used to handle
+ /// the comma operator in C99 mode, and non-constant subexpressions.
+ IK_ICEIfUnevaluated,
+ /// This expression is not an ICE, and is not a legal subexpression for one.
+ IK_NotICE
+};
+
struct ICEDiag {
- unsigned Val;
+ ICEKind Kind;
SourceLocation Loc;
- public:
- ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {}
- ICEDiag() : Val(0) {}
+ ICEDiag(ICEKind IK, SourceLocation l) : Kind(IK), Loc(l) {}
};
}
-static ICEDiag NoDiag() { return ICEDiag(); }
+static ICEDiag NoDiag() { return ICEDiag(IK_ICE, SourceLocation()); }
+
+static ICEDiag Worst(ICEDiag A, ICEDiag B) { return A.Kind >= B.Kind ? A : B; }
static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
Expr::EvalResult EVResult;
if (!E->EvaluateAsRValue(EVResult, Ctx) || EVResult.HasSideEffects ||
- !EVResult.Val.isInt()) {
- return ICEDiag(2, E->getLocStart());
- }
+ !EVResult.Val.isInt())
+ return ICEDiag(IK_NotICE, E->getLocStart());
+
return NoDiag();
}
static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
assert(!E->isValueDependent() && "Should not see value dependent exprs!");
- if (!E->getType()->isIntegralOrEnumerationType()) {
- return ICEDiag(2, E->getLocStart());
- }
+ if (!E->getType()->isIntegralOrEnumerationType())
+ return ICEDiag(IK_NotICE, E->getLocStart());
switch (E->getStmtClass()) {
#define ABSTRACT_STMT(Node)
@@ -6490,7 +6543,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::AtomicExprClass:
case Expr::InitListExprClass:
case Expr::LambdaExprClass:
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case Expr::SizeOfPackExprClass:
case Expr::GNUNullExprClass:
@@ -6525,7 +6578,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
const CallExpr *CE = cast<CallExpr>(E);
if (CE->isBuiltinCall())
return CheckEvalInICE(E, Ctx);
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
case Expr::DeclRefExprClass: {
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
@@ -6537,14 +6590,14 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// getAnyInitializer() can find a default argument, which leads
// to chaos.
if (isa<ParmVarDecl>(D))
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
// C++ 7.1.5.1p2
// A variable of non-volatile const-qualified integral or enumeration
// type initialized by an ICE can be used in ICEs.
if (const VarDecl *Dcl = dyn_cast<VarDecl>(D)) {
if (!Dcl->getType()->isIntegralOrEnumerationType())
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
const VarDecl *VD;
// Look for a declaration of this variable that has an initializer, and
@@ -6552,10 +6605,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (Dcl->getAnyInitializer(VD) && VD->checkInitIsICE())
return NoDiag();
else
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
}
}
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
case Expr::UnaryOperatorClass: {
const UnaryOperator *Exp = cast<UnaryOperator>(E);
@@ -6569,7 +6622,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// C99 6.6/3 allows increment and decrement within unevaluated
// subexpressions of constant expressions, but they can never be ICEs
// because an ICE cannot contain an lvalue operand.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case UO_Extension:
case UO_LNot:
case UO_Plus:
@@ -6579,23 +6632,23 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case UO_Imag:
return CheckICE(Exp->getSubExpr(), Ctx);
}
-
+
// OffsetOf falls through here.
}
case Expr::OffsetOfExprClass: {
- // Note that per C99, offsetof must be an ICE. And AFAIK, using
- // EvaluateAsRValue matches the proposed gcc behavior for cases like
- // "offsetof(struct s{int x[4];}, x[1.0])". This doesn't affect
- // compliance: we should warn earlier for offsetof expressions with
- // array subscripts that aren't ICEs, and if the array subscripts
- // are ICEs, the value of the offsetof must be an integer constant.
- return CheckEvalInICE(E, Ctx);
+ // Note that per C99, offsetof must be an ICE. And AFAIK, using
+ // EvaluateAsRValue matches the proposed gcc behavior for cases like
+ // "offsetof(struct s{int x[4];}, x[1.0])". This doesn't affect
+ // compliance: we should warn earlier for offsetof expressions with
+ // array subscripts that aren't ICEs, and if the array subscripts
+ // are ICEs, the value of the offsetof must be an integer constant.
+ return CheckEvalInICE(E, Ctx);
}
case Expr::UnaryExprOrTypeTraitExprClass: {
const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E);
if ((Exp->getKind() == UETT_SizeOf) &&
Exp->getTypeOfArgument()->isVariableArrayType())
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
return NoDiag();
}
case Expr::BinaryOperatorClass: {
@@ -6617,7 +6670,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
// C99 6.6/3 allows assignments within unevaluated subexpressions of
// constant expressions, but they can never be ICEs because an ICE cannot
// contain an lvalue operand.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case BO_Mul:
case BO_Div:
@@ -6642,14 +6695,14 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
Exp->getOpcode() == BO_Rem) {
// EvaluateAsRValue gives an error for undefined Div/Rem, so make sure
// we don't evaluate one.
- if (LHSResult.Val == 0 && RHSResult.Val == 0) {
+ if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE) {
llvm::APSInt REval = Exp->getRHS()->EvaluateKnownConstInt(Ctx);
if (REval == 0)
- return ICEDiag(1, E->getLocStart());
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
if (REval.isSigned() && REval.isAllOnesValue()) {
llvm::APSInt LEval = Exp->getLHS()->EvaluateKnownConstInt(Ctx);
if (LEval.isMinSignedValue())
- return ICEDiag(1, E->getLocStart());
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
}
}
}
@@ -6657,22 +6710,20 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (Ctx.getLangOpts().C99) {
// C99 6.6p3 introduces a strange edge case: comma can be in an ICE
// if it isn't evaluated.
- if (LHSResult.Val == 0 && RHSResult.Val == 0)
- return ICEDiag(1, E->getLocStart());
+ if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE)
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
} else {
// In both C89 and C++, commas in ICEs are illegal.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
}
- if (LHSResult.Val >= RHSResult.Val)
- return LHSResult;
- return RHSResult;
+ return Worst(LHSResult, RHSResult);
}
case BO_LAnd:
case BO_LOr: {
ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
- if (LHSResult.Val == 0 && RHSResult.Val == 1) {
+ if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICEIfUnevaluated) {
// Rare case where the RHS has a comma "side-effect"; we need
// to actually check the condition to see whether the side
// with the comma is evaluated.
@@ -6682,9 +6733,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
return NoDiag();
}
- if (LHSResult.Val >= RHSResult.Val)
- return LHSResult;
- return RHSResult;
+ return Worst(LHSResult, RHSResult);
}
}
}
@@ -6709,7 +6758,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (FL->getValue().convertToInteger(IgnoredVal,
llvm::APFloat::rmTowardZero,
&Ignored) & APFloat::opInvalidOp)
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
return NoDiag();
}
}
@@ -6722,18 +6771,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case CK_IntegralCast:
return CheckICE(SubExpr, Ctx);
default:
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
}
case Expr::BinaryConditionalOperatorClass: {
const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E);
ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx);
- if (CommonResult.Val == 2) return CommonResult;
+ if (CommonResult.Kind == IK_NotICE) 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()->EvaluateKnownConstInt(Ctx) == 0) return NoDiag();
+ if (FalseResult.Kind == IK_NotICE) return FalseResult;
+ if (CommonResult.Kind == IK_ICEIfUnevaluated) return CommonResult;
+ if (FalseResult.Kind == IK_ICEIfUnevaluated &&
+ Exp->getCommon()->EvaluateKnownConstInt(Ctx) != 0) return NoDiag();
return FalseResult;
}
case Expr::ConditionalOperatorClass: {
@@ -6747,26 +6796,25 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p)
return CheckEvalInICE(E, Ctx);
ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
- if (CondResult.Val == 2)
+ if (CondResult.Kind == IK_NotICE)
return CondResult;
ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
- if (TrueResult.Val == 2)
+ if (TrueResult.Kind == IK_NotICE)
return TrueResult;
- if (FalseResult.Val == 2)
+ if (FalseResult.Kind == IK_NotICE)
return FalseResult;
- if (CondResult.Val == 1)
+ if (CondResult.Kind == IK_ICEIfUnevaluated)
return CondResult;
- if (TrueResult.Val == 0 && FalseResult.Val == 0)
+ if (TrueResult.Kind == IK_ICE && FalseResult.Kind == IK_ICE)
return NoDiag();
// Rare case where the diagnostics depend on which side is evaluated
// Note that if we get here, CondResult is 0, and at least one of
// TrueResult and FalseResult is non-zero.
- if (Exp->getCond()->EvaluateKnownConstInt(Ctx) == 0) {
+ if (Exp->getCond()->EvaluateKnownConstInt(Ctx) == 0)
return FalseResult;
- }
return TrueResult;
}
case Expr::CXXDefaultArgExprClass:
@@ -6799,12 +6847,12 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(ASTContext &Ctx,
}
bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
- if (Ctx.getLangOpts().CPlusPlus0x)
+ if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, 0, Loc);
- ICEDiag d = CheckICE(this, Ctx);
- if (d.Val != 0) {
- if (Loc) *Loc = d.Loc;
+ ICEDiag D = CheckICE(this, Ctx);
+ if (D.Kind != IK_ICE) {
+ if (Loc) *Loc = D.Loc;
return false;
}
return true;
@@ -6812,7 +6860,7 @@ bool Expr::isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
SourceLocation *Loc, bool isEvaluated) const {
- if (Ctx.getLangOpts().CPlusPlus0x)
+ if (Ctx.getLangOpts().CPlusPlus11)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, &Value, Loc);
if (!isIntegerConstantExpr(Ctx, Loc))
@@ -6823,7 +6871,7 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Value, ASTContext &Ctx,
}
bool Expr::isCXX98IntegralConstantExpr(ASTContext &Ctx) const {
- return CheckICE(this, Ctx).Val == 0;
+ return CheckICE(this, Ctx).Kind == IK_ICE;
}
bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
@@ -6834,7 +6882,7 @@ bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
// Build evaluation settings.
Expr::EvalStatus Status;
- llvm::SmallVector<PartialDiagnosticAt, 8> Diags;
+ SmallVector<PartialDiagnosticAt, 8> Diags;
Status.Diag = &Diags;
EvalInfo Info(Ctx, Status);
@@ -6853,7 +6901,7 @@ bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,
}
bool Expr::isPotentialConstantExpr(const FunctionDecl *FD,
- llvm::SmallVectorImpl<
+ SmallVectorImpl<
PartialDiagnosticAt> &Diags) {
// FIXME: It would be useful to check constexpr function templates, but at the
// moment the constant expression evaluator cannot cope with the non-rigorous
diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp
index 6b9fe26ccc94..96ebe92ce3ab 100644
--- a/lib/AST/ExternalASTSource.cpp
+++ b/lib/AST/ExternalASTSource.cpp
@@ -43,10 +43,10 @@ ExternalASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) {
return 0;
}
-DeclContextLookupResult
+bool
ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
- return DeclContext::lookup_result();
+ return false;
}
void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {
diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp
index b70520f44dc5..e03632a71e0e 100644
--- a/lib/AST/InheritViz.cpp
+++ b/lib/AST/InheritViz.cpp
@@ -134,7 +134,7 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type,
/// viewInheritance - Display the inheritance hierarchy of this C++
/// class using GraphViz.
void CXXRecordDecl::viewInheritance(ASTContext& Context) const {
- QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this));
+ QualType Self = Context.getTypeDeclType(this);
std::string ErrMsg;
sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
if (Filename.isEmpty()) {
diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp
index ce1244c54272..894eb3bff5fd 100644
--- a/lib/AST/ItaniumCXXABI.cpp
+++ b/lib/AST/ItaniumCXXABI.cpp
@@ -19,8 +19,8 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
@@ -33,10 +33,15 @@ protected:
public:
ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { }
- unsigned getMemberPointerSize(const MemberPointerType *MPT) const {
- QualType Pointee = MPT->getPointeeType();
- if (Pointee->isFunctionType()) return 2;
- return 1;
+ std::pair<uint64_t, unsigned>
+ getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const {
+ const TargetInfo &Target = Context.getTargetInfo();
+ TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0);
+ uint64_t Width = Target.getTypeWidth(PtrDiff);
+ unsigned Align = Target.getTypeAlign(PtrDiff);
+ if (MPT->getPointeeType()->isFunctionType())
+ Width = 2 * Width;
+ return std::make_pair(Width, Align);
}
CallingConv getDefaultMethodCallConv(bool isVariadic) const {
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index 851944a42b6e..21c499317f5e 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -16,6 +16,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -27,8 +28,8 @@
#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"
+#include "llvm/Support/raw_ostream.h"
#define MANGLE_CHECKER 0
@@ -355,17 +356,6 @@ private:
}
-static bool isInCLinkageSpecification(const Decl *D) {
- D = D->getCanonicalDecl();
- for (const DeclContext *DC = getEffectiveDeclContext(D);
- !DC->isTranslationUnit(); DC = getEffectiveParentContext(DC)) {
- 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().getLangOpts().CPlusPlus && !D->hasAttrs())
@@ -376,20 +366,38 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
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;
+ if (FD) {
+ LanguageLinkage L = FD->getLanguageLinkage();
+ // Overloadable functions need mangling.
+ if (FD->hasAttr<OverloadableAttr>())
+ return true;
+
+ // "main" is not mangled.
+ if (FD->isMain())
+ return false;
+
+ // C++ functions and those whose names are not a simple identifier need
+ // mangling.
+ if (!FD->getDeclName().isIdentifier() || L == CXXLanguageLinkage)
+ return true;
+
+ // C functions are not mangled.
+ if (L == CLanguageLinkage)
+ return false;
+ }
// Otherwise, no mangling is done outside C++ mode.
if (!getASTContext().getLangOpts().CPlusPlus)
return false;
- // Variables at global scope with non-internal linkage are not mangled
- if (!FD) {
+ const VarDecl *VD = dyn_cast<VarDecl>(D);
+ if (VD) {
+ // C variables are not mangled.
+ if (VD->isExternC())
+ return false;
+
+ // Variables at global scope with non-internal linkage are not mangled
const DeclContext *DC = getEffectiveDeclContext(D);
// Check for extern variable declared locally.
if (DC->isFunctionOrMethod() && D->hasLinkage())
@@ -399,14 +407,6 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) {
return false;
}
- // Class members are always mangled.
- if (getEffectiveDeclContext(D)->isRecord())
- return true;
-
- // C functions and "main" are not mangled.
- if ((FD && FD->isMain()) || isInCLinkageSpecification(D))
- return false;
-
return true;
}
@@ -656,7 +656,7 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) {
assert(numCharacters != 0);
// Allocate a buffer of the right number of characters.
- llvm::SmallVector<char, 20> buffer;
+ SmallVector<char, 20> buffer;
buffer.set_size(numCharacters);
// Fill the buffer left-to-right.
@@ -1117,7 +1117,16 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
break;
}
}
-
+
+ int UnnamedMangle = Context.getASTContext().getUnnamedTagManglingNumber(TD);
+ if (UnnamedMangle != -1) {
+ Out << "Ut";
+ if (UnnamedMangle != 0)
+ Out << llvm::utostr(UnnamedMangle - 1);
+ Out << '_';
+ break;
+ }
+
// Get a unique id for the anonymous struct.
uint64_t AnonStructId = Context.getAnonymousStructId(TD);
@@ -1658,7 +1667,8 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals) {
// where <address-space-number> is a source name consisting of 'AS'
// followed by the address space <number>.
SmallString<64> ASString;
- ASString = "AS" + llvm::utostr_32(Quals.getAddressSpace());
+ ASString = "AS" + llvm::utostr_32(
+ Context.getASTContext().getTargetAddressSpace(Quals.getAddressSpace()));
Out << 'U' << ASString.size() << ASString;
}
@@ -1870,6 +1880,14 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
case BuiltinType::ObjCId: Out << "11objc_object"; break;
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
case BuiltinType::ObjCSel: Out << "13objc_selector"; break;
+ case BuiltinType::OCLImage1d: Out << "11ocl_image1d"; break;
+ case BuiltinType::OCLImage1dArray: Out << "16ocl_image1darray"; break;
+ case BuiltinType::OCLImage1dBuffer: Out << "17ocl_image1dbuffer"; break;
+ case BuiltinType::OCLImage2d: Out << "11ocl_image2d"; break;
+ case BuiltinType::OCLImage2dArray: Out << "16ocl_image2darray"; break;
+ case BuiltinType::OCLImage3d: Out << "11ocl_image3d"; break;
+ case BuiltinType::OCLSampler: Out << "11ocl_sampler"; break;
+ case BuiltinType::OCLEvent: Out << "9ocl_event"; break;
}
}
diff --git a/lib/AST/LambdaMangleContext.cpp b/lib/AST/LambdaMangleContext.cpp
index 6f4fe2d4b4eb..54f445df4b64 100644
--- a/lib/AST/LambdaMangleContext.cpp
+++ b/lib/AST/LambdaMangleContext.cpp
@@ -23,10 +23,11 @@ unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) {
= CallOperator->getType()->getAs<FunctionProtoType>();
ASTContext &Context = CallOperator->getASTContext();
- QualType Key = Context.getFunctionType(Context.VoidTy,
- Proto->arg_type_begin(),
- Proto->getNumArgs(),
- FunctionProtoType::ExtProtoInfo());
+ QualType Key =
+ Context.getFunctionType(Context.VoidTy,
+ ArrayRef<QualType>(Proto->arg_type_begin(),
+ Proto->getNumArgs()),
+ FunctionProtoType::ExtProtoInfo());
Key = Context.getCanonicalType(Key);
return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
}
diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp
index d5f83719ec62..eb794124490a 100644
--- a/lib/AST/Mangle.cpp
+++ b/lib/AST/Mangle.cpp
@@ -20,8 +20,8 @@
#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"
+#include "llvm/Support/raw_ostream.h"
#define MANGLE_CHECKER 0
diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp
index 51308ea0c0f5..6553e9d74943 100644
--- a/lib/AST/MicrosoftCXXABI.cpp
+++ b/lib/AST/MicrosoftCXXABI.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "CXXABI.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/RecordLayout.h"
@@ -27,13 +28,14 @@ class MicrosoftCXXABI : public CXXABI {
public:
MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { }
- unsigned getMemberPointerSize(const MemberPointerType *MPT) const;
+ std::pair<uint64_t, unsigned>
+ getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const;
CallingConv getDefaultMethodCallConv(bool isVariadic) const {
- if (!isVariadic && Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
+ if (!isVariadic &&
+ Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86)
return CC_X86ThisCall;
- else
- return CC_C;
+ return CC_C;
}
bool isNearlyEmpty(const CXXRecordDecl *RD) const {
@@ -52,17 +54,121 @@ public:
};
}
-unsigned MicrosoftCXXABI::getMemberPointerSize(const MemberPointerType *MPT) const {
- QualType Pointee = MPT->getPointeeType();
- CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
- if (RD->getNumVBases() > 0) {
- if (Pointee->isFunctionType())
- return 3;
- else
- return 2;
- } else if (RD->getNumBases() > 1 && Pointee->isFunctionType())
- return 2;
- return 1;
+// getNumBases() seems to only give us the number of direct bases, and not the
+// total. This function tells us if we inherit from anybody that uses MI, or if
+// we have a non-primary base class, which uses the multiple inheritance model.
+static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
+ while (RD->getNumBases() > 0) {
+ if (RD->getNumBases() > 1)
+ return true;
+ assert(RD->getNumBases() == 1);
+ const CXXRecordDecl *Base =
+ RD->bases_begin()->getType()->getAsCXXRecordDecl();
+ if (RD->isPolymorphic() && !Base->isPolymorphic())
+ return true;
+ RD = Base;
+ }
+ return false;
+}
+
+static MSInheritanceModel MSInheritanceAttrToModel(attr::Kind Kind) {
+ switch (Kind) {
+ default: llvm_unreachable("expected MS inheritance attribute");
+ case attr::SingleInheritance: return MSIM_Single;
+ case attr::MultipleInheritance: return MSIM_Multiple;
+ case attr::VirtualInheritance: return MSIM_Virtual;
+ case attr::UnspecifiedInheritance: return MSIM_Unspecified;
+ }
+}
+
+MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const {
+ if (Attr *IA = this->getAttr<MSInheritanceAttr>())
+ return MSInheritanceAttrToModel(IA->getKind());
+ // If there was no explicit attribute, the record must be defined already, and
+ // we can figure out the inheritance model from its other properties.
+ if (this->getNumVBases() > 0)
+ return MSIM_Virtual;
+ if (usesMultipleInheritanceModel(this))
+ return MSIM_Multiple;
+ return MSIM_Single;
+}
+
+// Returns the number of pointer and integer slots used to represent a member
+// pointer in the MS C++ ABI.
+//
+// Member function pointers have the following general form; however, fields
+// are dropped as permitted (under the MSVC interpretation) by the inheritance
+// model of the actual class.
+//
+// struct {
+// // A pointer to the member function to call. If the member function is
+// // virtual, this will be a thunk that forwards to the appropriate vftable
+// // slot.
+// void *FunctionPointerOrVirtualThunk;
+//
+// // An offset to add to the address of the vbtable pointer after (possibly)
+// // selecting the virtual base but before resolving and calling the function.
+// // Only needed if the class has any virtual bases or bases at a non-zero
+// // offset.
+// int NonVirtualBaseAdjustment;
+//
+// // An offset within the vb-table that selects the virtual base containing
+// // the member. Loading from this offset produces a new offset that is
+// // added to the address of the vb-table pointer to produce the base.
+// int VirtualBaseAdjustmentOffset;
+//
+// // The offset of the vb-table pointer within the object. Only needed for
+// // incomplete types.
+// int VBTableOffset;
+// };
+std::pair<unsigned, unsigned>
+MemberPointerType::getMSMemberPointerSlots() const {
+ const CXXRecordDecl *RD = this->getClass()->getAsCXXRecordDecl();
+ MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+ unsigned Ptrs;
+ unsigned Ints = 0;
+ if (this->isMemberFunctionPointer()) {
+ // Member function pointers are a struct of a function pointer followed by a
+ // variable number of ints depending on the inheritance model used. The
+ // function pointer is a real function if it is non-virtual and a vftable
+ // slot thunk if it is virtual. The ints select the object base passed for
+ // the 'this' pointer.
+ Ptrs = 1; // First slot is always a function pointer.
+ switch (Inheritance) {
+ case MSIM_Unspecified: ++Ints; // VBTableOffset
+ case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset
+ case MSIM_Multiple: ++Ints; // NonVirtualBaseAdjustment
+ case MSIM_Single: break; // Nothing
+ }
+ } else {
+ // Data pointers are an aggregate of ints. The first int is an offset
+ // followed by vbtable-related offsets.
+ Ptrs = 0;
+ switch (Inheritance) {
+ case MSIM_Unspecified: ++Ints; // VBTableOffset
+ case MSIM_Virtual: ++Ints; // VirtualBaseAdjustmentOffset
+ case MSIM_Multiple: // Nothing
+ case MSIM_Single: ++Ints; // Field offset
+ }
+ }
+ return std::make_pair(Ptrs, Ints);
+}
+
+std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign(
+ const MemberPointerType *MPT) const {
+ const TargetInfo &Target = Context.getTargetInfo();
+ assert(Target.getTriple().getArch() == llvm::Triple::x86 ||
+ Target.getTriple().getArch() == llvm::Triple::x86_64);
+ unsigned Ptrs, Ints;
+ llvm::tie(Ptrs, Ints) = MPT->getMSMemberPointerSlots();
+ // The nominal struct is laid out with pointers followed by ints and aligned
+ // to a pointer width if any are present and an int width otherwise.
+ unsigned PtrSize = Target.getPointerWidth(0);
+ unsigned IntSize = Target.getIntWidth();
+ uint64_t Width = Ptrs * PtrSize + Ints * IntSize;
+ unsigned Align = Ptrs > 0 ? Target.getPointerAlign(0) : Target.getIntAlign();
+ Width = llvm::RoundUpToAlignment(Width, Align);
+ return std::make_pair(Width, Align);
}
CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) {
diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp
index 5d5b83d9a30b..40f8730e61af 100644
--- a/lib/AST/MicrosoftMangle.cpp
+++ b/lib/AST/MicrosoftMangle.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/Mangle.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
@@ -21,19 +22,31 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/ABI.h"
#include "clang/Basic/DiagnosticOptions.h"
-
#include <map>
using namespace clang;
namespace {
+static const FunctionDecl *getStructor(const FunctionDecl *fn) {
+ if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate())
+ return ftd->getTemplatedDecl();
+
+ return fn;
+}
+
/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the
/// Microsoft Visual C++ ABI.
class MicrosoftCXXNameMangler {
MangleContext &Context;
raw_ostream &Out;
+ /// The "structor" is the top-level declaration being mangled, if
+ /// that's not a template specialization; otherwise it's the pattern
+ /// for that specialization.
+ const NamedDecl *Structor;
+ unsigned StructorType;
+
// FIXME: audit the performance of BackRefMap as it might do way too many
// copying of strings.
typedef std::map<std::string, unsigned> BackRefMap;
@@ -47,7 +60,15 @@ class MicrosoftCXXNameMangler {
public:
MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_)
- : Context(C), Out(Out_), UseNameBackReferences(true) { }
+ : Context(C), Out(Out_),
+ Structor(0), StructorType(-1),
+ UseNameBackReferences(true) { }
+
+ MicrosoftCXXNameMangler(MangleContext &C, raw_ostream &Out_,
+ const CXXDestructorDecl *D, CXXDtorType Type)
+ : Context(C), Out(Out_),
+ Structor(getStructor(D)), StructorType(Type),
+ UseNameBackReferences(true) { }
raw_ostream &getStream() const { return Out; }
@@ -68,12 +89,13 @@ private:
void mangleSourceName(const IdentifierInfo *II);
void manglePostfix(const DeclContext *DC, bool NoFunction=false);
void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc);
+ void mangleCXXDtorType(CXXDtorType T);
void mangleQualifiers(Qualifiers Quals, bool IsMember);
void manglePointerQualifiers(Qualifiers Quals);
void mangleUnscopedTemplateName(const TemplateDecl *ND);
void mangleTemplateInstantiationName(const TemplateDecl *TD,
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs);
+ const TemplateArgumentList &TemplateArgs);
void mangleObjCMethodName(const ObjCMethodDecl *MD);
void mangleLocalName(const FunctionDecl *FD);
@@ -96,12 +118,12 @@ private:
void mangleExtraDimensions(QualType T);
void mangleFunctionClass(const FunctionDecl *FD);
void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false);
- void mangleIntegerLiteral(QualType T, const llvm::APSInt &Number);
+ void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean);
void mangleExpression(const Expr *E);
void mangleThrowSpecification(const FunctionProtoType *T);
- void mangleTemplateArgs(
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs);
+ void mangleTemplateArgs(const TemplateDecl *TD,
+ const TemplateArgumentList &TemplateArgs);
};
@@ -345,47 +367,19 @@ void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
}
static const TemplateDecl *
-isTemplate(const NamedDecl *ND,
- SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+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()) {
- if (FD->getTemplateSpecializationArgsAsWritten()) {
- const ASTTemplateArgumentListInfo *ArgList =
- FD->getTemplateSpecializationArgsAsWritten();
- TemplateArgs.append(ArgList->getTemplateArgs(),
- ArgList->getTemplateArgs() +
- ArgList->NumTemplateArgs);
- } else {
- const TemplateArgumentList *ArgList =
- FD->getTemplateSpecializationArgs();
- TemplateArgumentListInfo LI;
- for (unsigned i = 0, e = ArgList->size(); i != e; ++i)
- TemplateArgs.push_back(TemplateArgumentLoc(ArgList->get(i),
- FD->getTypeSourceInfo()));
- }
+ TemplateArgs = FD->getTemplateSpecializationArgs();
return TD;
}
}
// Check if we have a class template.
if (const ClassTemplateSpecializationDecl *Spec =
- dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
- TypeSourceInfo *TSI = Spec->getTypeAsWritten();
- if (TSI) {
- TemplateSpecializationTypeLoc TSTL =
- cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc());
- TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc());
- for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i)
- TemplateArgs.push_back(TSTL.getArgLoc(i));
- } else {
- TemplateArgumentListInfo LI;
- const TemplateArgumentList &ArgList =
- Spec->getTemplateArgs();
- for (unsigned i = 0, e = ArgList.size(); i != e; ++i)
- TemplateArgs.push_back(TemplateArgumentLoc(ArgList[i],
- TemplateArgumentLocInfo()));
- }
+ dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
+ TemplateArgs = &Spec->getTemplateArgs();
return Spec->getSpecializedTemplate();
}
@@ -399,8 +393,9 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
// ::= <ctor-dtor-name>
// ::= <source-name>
// ::= <template-name>
- SmallVector<TemplateArgumentLoc, 2> TemplateArgs;
+
// Check if we have a template.
+ const TemplateArgumentList *TemplateArgs = 0;
if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
// We have a template.
// Here comes the tricky thing: if we need to mangle something like
@@ -430,7 +425,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
Found = NameBackReferences.find(BackReferenceKey);
}
if (!UseNameBackReferences || Found == NameBackReferences.end()) {
- mangleTemplateInstantiationName(TD, TemplateArgs);
+ mangleTemplateInstantiationName(TD, *TemplateArgs);
if (UseNameBackReferences && NameBackReferences.size() < 10) {
size_t Size = NameBackReferences.size();
NameBackReferences[BackReferenceKey] = Size;
@@ -453,7 +448,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
if (NS->isAnonymousNamespace()) {
- Out << "?A";
+ Out << "?A@";
break;
}
}
@@ -481,11 +476,22 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND,
llvm_unreachable("Can't mangle Objective-C selector names here!");
case DeclarationName::CXXConstructorName:
+ if (ND == Structor) {
+ assert(StructorType == Ctor_Complete &&
+ "Should never be asked to mangle a ctor other than complete");
+ }
Out << "?0";
break;
case DeclarationName::CXXDestructorName:
- Out << "?1";
+ 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:
@@ -543,6 +549,23 @@ void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC,
}
}
+void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
+ switch (T) {
+ case Dtor_Deleting:
+ Out << "?_G";
+ return;
+ case Dtor_Base:
+ // FIXME: We should be asked to mangle base dtors.
+ // However, fixing this would require larger changes to the CodeGenModule.
+ // Please put llvm_unreachable here when CGM is changed.
+ // For now, just mangle a base dtor the same way as a complete dtor...
+ case Dtor_Complete:
+ Out << "?1";
+ return;
+ }
+ llvm_unreachable("Unsupported dtor type?");
+}
+
void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO,
SourceLocation Loc) {
switch (OO) {
@@ -736,19 +759,23 @@ void MicrosoftCXXNameMangler::mangleLocalName(const FunctionDecl *FD) {
void MicrosoftCXXNameMangler::mangleTemplateInstantiationName(
const TemplateDecl *TD,
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+ const TemplateArgumentList &TemplateArgs) {
// <template-name> ::= <unscoped-template-name> <template-args>
// ::= <substitution>
// Always start with the unqualified name.
// Templates have their own context for back references.
- BackRefMap TemplateContext;
- NameBackReferences.swap(TemplateContext);
+ ArgBackRefMap OuterArgsContext;
+ BackRefMap OuterTemplateContext;
+ NameBackReferences.swap(OuterTemplateContext);
+ TypeBackReferences.swap(OuterArgsContext);
mangleUnscopedTemplateName(TD);
- mangleTemplateArgs(TemplateArgs);
+ mangleTemplateArgs(TD, TemplateArgs);
- NameBackReferences.swap(TemplateContext);
+ // Restore the previous back reference contexts.
+ NameBackReferences.swap(OuterTemplateContext);
+ TypeBackReferences.swap(OuterArgsContext);
}
void
@@ -759,13 +786,13 @@ MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) {
}
void
-MicrosoftCXXNameMangler::mangleIntegerLiteral(QualType T,
- const llvm::APSInt &Value) {
+MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value,
+ bool IsBoolean) {
// <integer-literal> ::= $0 <number>
Out << "$0";
// Make sure booleans are encoded as 0/1.
- if (T->isBooleanType())
- Out << (Value.getBoolValue() ? "0" : "A@");
+ if (IsBoolean && Value.getBoolValue())
+ mangleNumber(1);
else
mangleNumber(Value);
}
@@ -775,7 +802,7 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
// See if this is a constant expression.
llvm::APSInt Value;
if (E->isIntegerConstantExpr(Value, Context.getASTContext())) {
- mangleIntegerLiteral(E->getType(), Value);
+ mangleIntegerLiteral(Value, E->getType()->isBooleanType());
return;
}
@@ -788,39 +815,42 @@ MicrosoftCXXNameMangler::mangleExpression(const Expr *E) {
}
void
-MicrosoftCXXNameMangler::mangleTemplateArgs(
- const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) {
+MicrosoftCXXNameMangler::mangleTemplateArgs(const TemplateDecl *TD,
+ const TemplateArgumentList &TemplateArgs) {
// <template-args> ::= {<type> | <integer-literal>}+ @
unsigned NumTemplateArgs = TemplateArgs.size();
for (unsigned i = 0; i < NumTemplateArgs; ++i) {
- const TemplateArgumentLoc &TAL = TemplateArgs[i];
- const TemplateArgument &TA = TAL.getArgument();
+ const TemplateArgument &TA = TemplateArgs[i];
switch (TA.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Can't mangle null template arguments!");
case TemplateArgument::Type:
- mangleType(TA.getAsType(), TAL.getSourceRange());
+ mangleType(TA.getAsType(), SourceRange());
+ break;
+ case TemplateArgument::Declaration:
+ mangle(cast<NamedDecl>(TA.getAsDecl()), "$1?");
break;
case TemplateArgument::Integral:
- mangleIntegerLiteral(TA.getIntegralType(), TA.getAsIntegral());
+ mangleIntegerLiteral(TA.getAsIntegral(),
+ TA.getIntegralType()->isBooleanType());
break;
case TemplateArgument::Expression:
mangleExpression(TA.getAsExpr());
break;
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
- case TemplateArgument::Declaration:
case TemplateArgument::NullPtr:
case TemplateArgument::Pack: {
// Issue a diagnostic.
DiagnosticsEngine &Diags = Context.getDiags();
unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this %select{ERROR|ERROR|pointer/reference|nullptr|"
- "integral|template|template pack expansion|ERROR|parameter pack}0 "
- "template argument yet");
- Diags.Report(TAL.getLocation(), DiagID)
+ "cannot mangle template argument %0 of kind %select{ERROR|ERROR|"
+ "pointer/reference|nullptr|integral|template|template pack expansion|"
+ "ERROR|parameter pack}1 yet");
+ Diags.Report(TD->getLocation(), DiagID)
+ << i + 1
<< TA.getKind()
- << TAL.getSourceRange();
+ << TD->getSourceRange();
}
}
}
@@ -1048,6 +1078,15 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T,
case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break;
case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break;
case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break;
+
+ case BuiltinType::OCLImage1d: Out << "PAUocl_image1d@@"; break;
+ case BuiltinType::OCLImage1dArray: Out << "PAUocl_image1darray@@"; break;
+ case BuiltinType::OCLImage1dBuffer: Out << "PAUocl_image1dbuffer@@"; break;
+ case BuiltinType::OCLImage2d: Out << "PAUocl_image2d@@"; break;
+ case BuiltinType::OCLImage2dArray: Out << "PAUocl_image2darray@@"; break;
+ case BuiltinType::OCLImage3d: Out << "PAUocl_image3d@@"; break;
+ case BuiltinType::OCLSampler: Out << "PAUocl_sampler@@"; break;
+ case BuiltinType::OCLEvent: Out << "PAUocl_event@@"; break;
case BuiltinType::NullPtr: Out << "$$T"; break;
@@ -1096,9 +1135,18 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionType *T,
// <return-type> ::= <type>
// ::= @ # structors (they have no declared return type)
- if (IsStructor)
+ if (IsStructor) {
+ if (isa<CXXDestructorDecl>(D) && D == Structor &&
+ StructorType == Dtor_Deleting) {
+ // The scalar deleting destructor takes an extra int argument.
+ // However, the FunctionType generated has 0 arguments.
+ // FIXME: This is a temporary hack.
+ // Maybe should fix the FunctionType creation instead?
+ Out << "PAXI@Z";
+ return;
+ }
Out << '@';
- else {
+ } else {
QualType Result = Proto->getResultType();
const Type* RT = Result.getTypePtr();
if (!RT->isAnyPointerType() && !RT->isReferenceType()) {
@@ -1471,12 +1519,38 @@ void MicrosoftCXXNameMangler::mangleType(const ComplexType *T,
void MicrosoftCXXNameMangler::mangleType(const VectorType *T,
SourceRange Range) {
- DiagnosticsEngine &Diags = Context.getDiags();
- unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
- "cannot mangle this vector type yet");
- Diags.Report(Range.getBegin(), DiagID)
- << Range;
+ const BuiltinType *ET = T->getElementType()->getAs<BuiltinType>();
+ assert(ET && "vectors with non-builtin elements are unsupported");
+ uint64_t Width = getASTContext().getTypeSize(T);
+ // Pattern match exactly the typedefs in our intrinsic headers. Anything that
+ // doesn't match the Intel types uses a custom mangling below.
+ bool IntelVector = true;
+ if (Width == 64 && ET->getKind() == BuiltinType::LongLong) {
+ Out << "T__m64";
+ } else if (Width == 128 || Width == 256) {
+ if (ET->getKind() == BuiltinType::Float)
+ Out << "T__m" << Width;
+ else if (ET->getKind() == BuiltinType::LongLong)
+ Out << "T__m" << Width << 'i';
+ else if (ET->getKind() == BuiltinType::Double)
+ Out << "U__m" << Width << 'd';
+ else
+ IntelVector = false;
+ } else {
+ IntelVector = false;
+ }
+
+ if (!IntelVector) {
+ // The MS ABI doesn't have a special mangling for vector types, so we define
+ // our own mangling to handle uses of __vector_size__ on user-specified
+ // types, and for extensions like __v4sf.
+ Out << "T__clang_vec" << T->getNumElements() << '_';
+ mangleType(ET, Range);
+ }
+
+ Out << "@@";
}
+
void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T,
SourceRange Range) {
DiagnosticsEngine &Diags = Context.getDiags();
@@ -1697,7 +1771,7 @@ void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D,
void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D,
CXXDtorType Type,
raw_ostream & Out) {
- MicrosoftCXXNameMangler mangler(*this, Out);
+ MicrosoftCXXNameMangler mangler(*this, Out, D, Type);
mangler.mangle(D);
}
void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *VD,
diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp
index 0837509194bc..a862630bbf8d 100644
--- a/lib/AST/NSAPI.cpp
+++ b/lib/AST/NSAPI.cpp
@@ -67,7 +67,7 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
return NSStringSelectors[MK];
}
-llvm::Optional<NSAPI::NSStringMethodKind>
+Optional<NSAPI::NSStringMethodKind>
NSAPI::getNSStringMethodKind(Selector Sel) const {
for (unsigned i = 0; i != NumNSStringMethods; ++i) {
NSStringMethodKind MK = NSStringMethodKind(i);
@@ -75,7 +75,7 @@ NSAPI::getNSStringMethodKind(Selector Sel) const {
return MK;
}
- return llvm::Optional<NSStringMethodKind>();
+ return None;
}
Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
@@ -126,15 +126,14 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
return NSArraySelectors[MK];
}
-llvm::Optional<NSAPI::NSArrayMethodKind>
-NSAPI::getNSArrayMethodKind(Selector Sel) {
+Optional<NSAPI::NSArrayMethodKind> NSAPI::getNSArrayMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
NSArrayMethodKind MK = NSArrayMethodKind(i);
if (Sel == getNSArraySelector(MK))
return MK;
}
- return llvm::Optional<NSArrayMethodKind>();
+ return None;
}
Selector NSAPI::getNSDictionarySelector(
@@ -186,6 +185,14 @@ Selector NSAPI::getNSDictionarySelector(
Sel = Ctx.Selectors.getUnarySelector(
&Ctx.Idents.get("initWithObjectsAndKeys"));
break;
+ case NSDict_initWithObjectsForKeys: {
+ IdentifierInfo *KeyIdents[] = {
+ &Ctx.Idents.get("initWithObjects"),
+ &Ctx.Idents.get("forKeys")
+ };
+ Sel = Ctx.Selectors.getSelector(2, KeyIdents);
+ break;
+ }
case NSDict_objectForKey:
Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
break;
@@ -204,7 +211,7 @@ Selector NSAPI::getNSDictionarySelector(
return NSDictionarySelectors[MK];
}
-llvm::Optional<NSAPI::NSDictionaryMethodKind>
+Optional<NSAPI::NSDictionaryMethodKind>
NSAPI::getNSDictionaryMethodKind(Selector Sel) {
for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
@@ -212,7 +219,7 @@ NSAPI::getNSDictionaryMethodKind(Selector Sel) {
return MK;
}
- return llvm::Optional<NSDictionaryMethodKind>();
+ return None;
}
Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
@@ -267,7 +274,7 @@ Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
return Sels[MK];
}
-llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+Optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
@@ -275,14 +282,14 @@ NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
return MK;
}
- return llvm::Optional<NSNumberLiteralMethodKind>();
+ return None;
}
-llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
+Optional<NSAPI::NSNumberLiteralMethodKind>
NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
const BuiltinType *BT = T->getAs<BuiltinType>();
if (!BT)
- return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
+ return None;
const TypedefType *TDT = T->getAs<TypedefType>();
if (TDT) {
@@ -337,6 +344,14 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
case BuiltinType::ObjCClass:
case BuiltinType::ObjCId:
case BuiltinType::ObjCSel:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
case BuiltinType::BoundMember:
case BuiltinType::Dependent:
case BuiltinType::Overload:
@@ -348,7 +363,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
break;
}
- return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
+ return None;
}
/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 49b119b8e05c..79cc21a062c8 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -57,7 +57,8 @@ NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier *
NestedNameSpecifier::Create(const ASTContext &Context,
- NestedNameSpecifier *Prefix, NamespaceDecl *NS) {
+ NestedNameSpecifier *Prefix,
+ const NamespaceDecl *NS) {
assert(NS && "Namespace cannot be NULL");
assert((!Prefix ||
(Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
@@ -65,7 +66,7 @@ NestedNameSpecifier::Create(const ASTContext &Context,
NestedNameSpecifier Mockup;
Mockup.Prefix.setPointer(Prefix);
Mockup.Prefix.setInt(StoredNamespaceOrAlias);
- Mockup.Specifier = NS;
+ Mockup.Specifier = const_cast<NamespaceDecl *>(NS);
return FindOrInsert(Context, Mockup);
}
@@ -248,7 +249,6 @@ NestedNameSpecifier::print(raw_ostream &OS,
// Fall through to print the type.
case TypeSpec: {
- std::string TypeStr;
const Type *T = getAsType();
PrintingPolicy InnerPolicy(Policy);
@@ -270,15 +270,12 @@ NestedNameSpecifier::print(raw_ostream &OS,
SpecType->getTemplateName().print(OS, InnerPolicy, true);
// Print the template argument list.
- TypeStr = TemplateSpecializationType::PrintTemplateArgumentList(
- SpecType->getArgs(),
- SpecType->getNumArgs(),
- InnerPolicy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, SpecType->getArgs(), SpecType->getNumArgs(), InnerPolicy);
} else {
// Print the type normally
- TypeStr = QualType(T, 0).getAsString(InnerPolicy);
+ QualType(T, 0).print(OS, InnerPolicy);
}
- OS << TypeStr;
break;
}
}
diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp
index 80b627293e42..f2386a56fcc7 100644
--- a/lib/AST/RawCommentList.cpp
+++ b/lib/AST/RawCommentList.cpp
@@ -10,11 +10,11 @@
#include "clang/AST/RawCommentList.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Comment.h"
-#include "clang/AST/CommentLexer.h"
#include "clang/AST/CommentBriefParser.h"
-#include "clang/AST/CommentSema.h"
-#include "clang/AST/CommentParser.h"
#include "clang/AST/CommentCommandTraits.h"
+#include "clang/AST/CommentLexer.h"
+#include "clang/AST/CommentParser.h"
+#include "clang/AST/CommentSema.h"
#include "llvm/ADT/STLExtras.h"
using namespace clang;
diff --git a/lib/AST/RecordLayout.cpp b/lib/AST/RecordLayout.cpp
index 2ae0aab19f69..f6cfe63cd34e 100644
--- a/lib/AST/RecordLayout.cpp
+++ b/lib/AST/RecordLayout.cpp
@@ -75,10 +75,9 @@ ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx,
#ifndef NDEBUG
if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) {
if (isPrimaryBaseVirtual()) {
- // Microsoft ABI doesn't have primary virtual base
- if (Ctx.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
- assert(getVBaseClassOffset(PrimaryBase).isZero() &&
- "Primary virtual base must be at offset 0!");
+ if (Ctx.getTargetInfo().getCXXABI().hasPrimaryVBases()) {
+ assert(getVBaseClassOffset(PrimaryBase).isZero() &&
+ "Primary virtual base must be at offset 0!");
}
} else {
assert(getBaseClassOffset(PrimaryBase).isZero() &&
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 4dfffc45e49c..42c3ba31bc76 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -7,6 +7,7 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/RecordLayout.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
#include "clang/AST/CXXInheritance.h"
@@ -14,13 +15,12 @@
#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"
#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/MathExtras.h"
using namespace clang;
@@ -676,8 +676,12 @@ protected:
bool FieldPacked, const FieldDecl *D);
void LayoutBitField(const FieldDecl *D);
+ TargetCXXABI getCXXABI() const {
+ return Context.getTargetInfo().getCXXABI();
+ }
+
bool isMicrosoftCXXABI() const {
- return Context.getTargetInfo().getCXXABI() == CXXABI_Microsoft;
+ return getCXXABI().isMicrosoft();
}
void MSLayoutVirtualBases(const CXXRecordDecl *RD);
@@ -791,8 +795,6 @@ protected:
RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION;
-public:
- static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD);
};
} // end anonymous namespace
@@ -2343,8 +2345,8 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
<< D->getIdentifier();
}
-const CXXMethodDecl *
-RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
+static const CXXMethodDecl *computeKeyFunction(ASTContext &Context,
+ const CXXRecordDecl *RD) {
// If a class isn't polymorphic it doesn't have a key function.
if (!RD->isPolymorphic())
return 0;
@@ -2362,6 +2364,9 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
TSK == TSK_ExplicitInstantiationDefinition)
return 0;
+ bool allowInlineFunctions =
+ Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline();
+
for (CXXRecordDecl::method_iterator I = RD->method_begin(),
E = RD->method_end(); I != E; ++I) {
const CXXMethodDecl *MD = *I;
@@ -2387,6 +2392,13 @@ RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
if (!MD->isUserProvided())
continue;
+ // In certain ABIs, ignore functions with out-of-line inline definitions.
+ if (!allowInlineFunctions) {
+ const FunctionDecl *Def;
+ if (MD->hasBody(Def) && Def->isInlineSpecified())
+ continue;
+ }
+
// We found it.
return MD;
}
@@ -2399,6 +2411,48 @@ RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) {
return Context.getDiagnostics().Report(Loc, DiagID);
}
+/// Does the target C++ ABI require us to skip over the tail-padding
+/// of the given class (considering it as a base class) when allocating
+/// objects?
+static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) {
+ switch (ABI.getTailPaddingUseRules()) {
+ case TargetCXXABI::AlwaysUseTailPadding:
+ return false;
+
+ case TargetCXXABI::UseTailPaddingUnlessPOD03:
+ // FIXME: To the extent that this is meant to cover the Itanium ABI
+ // rules, we should implement the restrictions about over-sized
+ // bitfields:
+ //
+ // http://mentorembedded.github.com/cxx-abi/abi.html#POD :
+ // In general, a type is considered a POD for the purposes of
+ // layout if it is a POD type (in the sense of ISO C++
+ // [basic.types]). However, a POD-struct or POD-union (in the
+ // sense of ISO C++ [class]) with a bitfield member whose
+ // declared width is wider than the declared type of the
+ // bitfield is not a POD for the purpose of layout. Similarly,
+ // an array type is not a POD for the purpose of layout if the
+ // element type of the array is not a POD for the purpose of
+ // layout.
+ //
+ // Where references to the ISO C++ are made in this paragraph,
+ // the Technical Corrigendum 1 version of the standard is
+ // intended.
+ return RD->isPOD();
+
+ case TargetCXXABI::UseTailPaddingUnlessPOD11:
+ // This is equivalent to RD->getTypeForDecl().isCXX11PODType(),
+ // but with a lot of abstraction penalty stripped off. This does
+ // assume that these properties are set correctly even in C++98
+ // mode; fortunately, that is true because we want to assign
+ // consistently semantics to the type-traits intrinsics (or at
+ // least as many of them as possible).
+ return RD->isTrivial() && RD->isStandardLayout();
+ }
+
+ llvm_unreachable("bad tail-padding use kind");
+}
+
/// getASTRecordLayout - Get or compute information about the layout of the
/// specified record (struct/union/class), which indicates its size and field
/// position information.
@@ -2443,18 +2497,17 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
Builder.Layout(RD);
}
- // FIXME: This is not always correct. See the part about bitfields at
- // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info.
- // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout.
- // This does not affect the calculations of MSVC layouts
- bool IsPODForThePurposeOfLayout =
- (!Builder.isMicrosoftCXXABI() && cast<CXXRecordDecl>(D)->isPOD());
+ // In certain situations, we are allowed to lay out objects in the
+ // tail-padding of base classes. This is ABI-dependent.
+ // FIXME: this should be stored in the record layout.
+ bool skipTailPadding =
+ mustSkipTailPadding(getTargetInfo().getCXXABI(), cast<CXXRecordDecl>(D));
// FIXME: This should be done in FinalizeLayout.
CharUnits DataSize =
- IsPODForThePurposeOfLayout ? Builder.getSize() : Builder.getDataSize();
+ skipTailPadding ? Builder.getSize() : Builder.getDataSize();
CharUnits NonVirtualSize =
- IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
+ skipTailPadding ? DataSize : Builder.NonVirtualSize;
NewEntry =
new (*this) ASTRecordLayout(*this, Builder.getSize(),
@@ -2492,15 +2545,37 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const {
return *NewEntry;
}
-const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) {
+const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) {
+ assert(RD->getDefinition() && "Cannot get key function for forward decl!");
RD = cast<CXXRecordDecl>(RD->getDefinition());
- assert(RD && "Cannot get key function for forward declarations!");
- const CXXMethodDecl *&Entry = KeyFunctions[RD];
- if (!Entry)
- Entry = RecordLayoutBuilder::ComputeKeyFunction(RD);
+ const CXXMethodDecl *&entry = KeyFunctions[RD];
+ if (!entry) {
+ entry = computeKeyFunction(*this, RD);
+ }
- return Entry;
+ return entry;
+}
+
+void ASTContext::setNonKeyFunction(const CXXMethodDecl *method) {
+ assert(method == method->getFirstDeclaration() &&
+ "not working with method declaration from class definition");
+
+ // Look up the cache entry. Since we're working with the first
+ // declaration, its parent must be the class definition, which is
+ // the correct key for the KeyFunctions hash.
+ llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*>::iterator
+ i = KeyFunctions.find(method->getParent());
+
+ // If it's not cached, there's nothing to do.
+ if (i == KeyFunctions.end()) return;
+
+ // If it is cached, check whether it's the target method, and if so,
+ // remove it from the cache.
+ if (i->second == method) {
+ // FIXME: remember that we did this for module / chained PCH state?
+ KeyFunctions.erase(i);
+ }
}
static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD) {
@@ -2577,6 +2652,11 @@ static void PrintOffset(raw_ostream &OS,
OS.indent(IndentLevel * 2);
}
+static void PrintIndentNoOffset(raw_ostream &OS, unsigned IndentLevel) {
+ OS << " | ";
+ OS.indent(IndentLevel * 2);
+}
+
static void DumpCXXRecordLayout(raw_ostream &OS,
const CXXRecordDecl *RD, const ASTContext &C,
CharUnits Offset,
@@ -2601,7 +2681,7 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
// Vtable pointer.
if (RD->isDynamicClass() && !PrimaryBase &&
- C.getTargetInfo().getCXXABI() != CXXABI_Microsoft) {
+ !C.getTargetInfo().getCXXABI().isMicrosoft()) {
PrintOffset(OS, Offset, IndentLevel);
OS << '(' << *RD << " vtable pointer)\n";
}
@@ -2680,11 +2760,14 @@ static void DumpCXXRecordLayout(raw_ostream &OS,
/*IncludeVirtualBases=*/false);
}
- OS << " sizeof=" << Layout.getSize().getQuantity();
+ PrintIndentNoOffset(OS, IndentLevel - 1);
+ 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';
+
+ PrintIndentNoOffset(OS, IndentLevel - 1);
+ OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity();
+ OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << "]\n";
OS << '\n';
}
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index eafcf92eee82..2ae5a1266c18 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -11,15 +11,17 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/Stmt.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/Type.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTDiagnostic.h"
+#include "clang/Basic/CharInfo.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Token.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -46,6 +48,16 @@ static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) {
return StmtClassInfo[E];
}
+void *Stmt::operator new(size_t bytes, ASTContext& C,
+ unsigned alignment) throw() {
+ return ::operator new(bytes, C, alignment);
+}
+
+void *Stmt::operator new(size_t bytes, ASTContext* C,
+ unsigned alignment) throw() {
+ return ::operator new(bytes, *C, alignment);
+}
+
const char *Stmt::getStmtClassName() const {
return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name;
}
@@ -131,18 +143,28 @@ namespace {
return bad();
}
- typedef SourceRange getSourceRange_t() const;
- template <class T> good implements_getSourceRange(getSourceRange_t T::*) {
+ typedef SourceLocation getLocStart_t() const;
+ template <class T> good implements_getLocStart(getLocStart_t T::*) {
return good();
}
- static inline bad implements_getSourceRange(getSourceRange_t Stmt::*) {
+ static inline bad implements_getLocStart(getLocStart_t Stmt::*) {
+ return bad();
+ }
+
+ typedef SourceLocation getLocEnd_t() const;
+ template <class T> good implements_getLocEnd(getLocEnd_t T::*) {
+ return good();
+ }
+ static inline bad implements_getLocEnd(getLocEnd_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)))
+#define ASSERT_IMPLEMENTS_getLocStart(type) \
+ (void) sizeof(is_good(implements_getLocStart(&type::getLocStart)))
+#define ASSERT_IMPLEMENTS_getLocEnd(type) \
+ (void) sizeof(is_good(implements_getLocEnd(&type::getLocEnd)))
}
/// Check whether the various Stmt classes implement their member
@@ -151,7 +173,8 @@ static inline void check_implementations() {
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
ASSERT_IMPLEMENTS_children(type); \
- ASSERT_IMPLEMENTS_getSourceRange(type);
+ ASSERT_IMPLEMENTS_getLocStart(type); \
+ ASSERT_IMPLEMENTS_getLocEnd(type);
#include "clang/AST/StmtNodes.inc"
}
@@ -167,67 +190,51 @@ Stmt::child_range Stmt::children() {
llvm_unreachable("unknown statement kind!");
}
-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!");
-}
-
// Amusing macro metaprogramming hack: check whether a class provides
-// a more specific implementation of getLocStart() and getLocEnd().
+// a more specific implementation of getSourceRange.
//
// See also Expr.cpp:getExprLoc().
namespace {
/// This implementation is used when a class provides a custom
- /// implementation of getLocStart.
+ /// implementation of getSourceRange.
template <class S, class T>
- SourceLocation getLocStartImpl(const Stmt *stmt,
- SourceLocation (T::*v)() const) {
- return static_cast<const S*>(stmt)->getLocStart();
+ SourceRange getSourceRangeImpl(const Stmt *stmt,
+ SourceRange (T::*v)() const) {
+ return static_cast<const S*>(stmt)->getSourceRange();
}
/// This implementation is used when a class doesn't provide a custom
- /// implementation of getLocStart. Overload resolution should pick it over
+ /// implementation of getSourceRange. Overload resolution should pick it over
/// the implementation above because it's more specialized according to
/// function template partial ordering.
template <class S>
- SourceLocation getLocStartImpl(const Stmt *stmt,
- SourceLocation (Stmt::*v)() const) {
- return static_cast<const S*>(stmt)->getSourceRange().getBegin();
- }
-
- /// This implementation is used when a class provides a custom
- /// implementation of getLocEnd.
- template <class S, class T>
- SourceLocation getLocEndImpl(const Stmt *stmt,
- SourceLocation (T::*v)() const) {
- return static_cast<const S*>(stmt)->getLocEnd();
+ SourceRange getSourceRangeImpl(const Stmt *stmt,
+ SourceRange (Stmt::*v)() const) {
+ return SourceRange(static_cast<const S*>(stmt)->getLocStart(),
+ static_cast<const S*>(stmt)->getLocEnd());
}
+}
- /// This implementation is used when a class doesn't provide a custom
- /// implementation of getLocEnd. Overload resolution should pick it over
- /// the implementation above because it's more specialized according to
- /// function template partial ordering.
- template <class S>
- SourceLocation getLocEndImpl(const Stmt *stmt,
- SourceLocation (Stmt::*v)() const) {
- return static_cast<const S*>(stmt)->getSourceRange().getEnd();
+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 getSourceRangeImpl<type>(this, &type::getSourceRange);
+#include "clang/AST/StmtNodes.inc"
}
+ llvm_unreachable("unknown statement kind!");
}
SourceLocation Stmt::getLocStart() const {
+// llvm::errs() << "getLocStart() for " << getStmtClassName() << "\n";
switch (getStmtClass()) {
case Stmt::NoStmtClass: llvm_unreachable("statement without class");
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
case Stmt::type##Class: \
- return getLocStartImpl<type>(this, &type::getLocStart);
+ return static_cast<const type*>(this)->getLocStart();
#include "clang/AST/StmtNodes.inc"
}
llvm_unreachable("unknown statement kind");
@@ -239,26 +246,26 @@ SourceLocation Stmt::getLocEnd() const {
#define ABSTRACT_STMT(type)
#define STMT(type, base) \
case Stmt::type##Class: \
- return getLocEndImpl<type>(this, &type::getLocEnd);
+ return static_cast<const type*>(this)->getLocEnd();
#include "clang/AST/StmtNodes.inc"
}
llvm_unreachable("unknown statement kind");
}
-CompoundStmt::CompoundStmt(ASTContext &C, Stmt **StmtStart, unsigned NumStmts,
+CompoundStmt::CompoundStmt(ASTContext &C, ArrayRef<Stmt*> Stmts,
SourceLocation LB, SourceLocation RB)
: Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) {
- CompoundStmtBits.NumStmts = NumStmts;
- assert(CompoundStmtBits.NumStmts == NumStmts &&
+ CompoundStmtBits.NumStmts = Stmts.size();
+ assert(CompoundStmtBits.NumStmts == Stmts.size() &&
"NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!");
- if (NumStmts == 0) {
+ if (Stmts.size() == 0) {
Body = 0;
return;
}
- Body = new (C) Stmt*[NumStmts];
- memcpy(Body, StmtStart, NumStmts * sizeof(*Body));
+ Body = new (C) Stmt*[Stmts.size()];
+ std::copy(Stmts.begin(), Stmts.end(), Body);
}
void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) {
@@ -291,14 +298,6 @@ AttributedStmt *AttributedStmt::CreateEmpty(ASTContext &C, unsigned NumAttrs) {
return new (Mem) AttributedStmt(EmptyShell(), NumAttrs);
}
-// This is defined here to avoid polluting Stmt.h with importing Expr.h
-SourceRange ReturnStmt::getSourceRange() const {
- if (RetExpr)
- return SourceRange(RetLoc, RetExpr->getLocEnd());
- else
- return SourceRange(RetLoc);
-}
-
bool Stmt::hasImplicitControlFlow() const {
switch (StmtBits.sClass) {
default:
@@ -541,7 +540,7 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
// Handle %x4 and %x[foo] by capturing x as the modifier character.
char Modifier = '\0';
- if (isalpha(EscapedChar)) {
+ if (isLetter(EscapedChar)) {
if (CurPtr == StrEnd) { // Premature end.
DiagOffs = CurPtr-StrStart-1;
return diag::err_asm_invalid_escape;
@@ -550,12 +549,12 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces,
EscapedChar = *CurPtr++;
}
- if (isdigit(EscapedChar)) {
+ if (isDigit(EscapedChar)) {
// %n - Assembler operand n
unsigned N = 0;
--CurPtr;
- while (CurPtr != StrEnd && isdigit(*CurPtr))
+ while (CurPtr != StrEnd && isDigit(*CurPtr))
N = N*10 + ((*CurPtr++)-'0');
unsigned NumOperands =
@@ -762,26 +761,21 @@ ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context,
return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally);
}
-SourceRange ObjCAtTryStmt::getSourceRange() const {
- SourceLocation EndLoc;
+SourceLocation ObjCAtTryStmt::getLocEnd() const {
if (HasFinally)
- EndLoc = getFinallyStmt()->getLocEnd();
- else if (NumCatchStmts)
- EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd();
- else
- EndLoc = getTryBody()->getLocEnd();
-
- return SourceRange(AtTryLoc, EndLoc);
+ return getFinallyStmt()->getLocEnd();
+ if (NumCatchStmts)
+ return getCatchStmt(NumCatchStmts - 1)->getLocEnd();
+ return getTryBody()->getLocEnd();
}
CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc,
- Stmt *tryBlock, Stmt **handlers,
- unsigned numHandlers) {
+ Stmt *tryBlock, ArrayRef<Stmt*> handlers) {
std::size_t Size = sizeof(CXXTryStmt);
- Size += ((numHandlers + 1) * sizeof(Stmt));
+ Size += ((handlers.size() + 1) * sizeof(Stmt));
void *Mem = C.Allocate(Size, llvm::alignOf<CXXTryStmt>());
- return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers);
+ return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers);
}
CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty,
@@ -794,11 +788,11 @@ CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty,
}
CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock,
- Stmt **handlers, unsigned numHandlers)
- : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) {
+ ArrayRef<Stmt*> handlers)
+ : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(handlers.size()) {
Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1);
Stmts[0] = tryBlock;
- std::copy(handlers, handlers + NumHandlers, Stmts + 1);
+ std::copy(handlers.begin(), handlers.end(), Stmts + 1);
}
CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt,
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
deleted file mode 100644
index fbc990f6b3c2..000000000000
--- a/lib/AST/StmtDumper.cpp
+++ /dev/null
@@ -1,760 +0,0 @@
-//===--- StmtDumper.cpp - Dumping implementation for Stmt ASTs ------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the Stmt::dump method, which dumps out the
-// AST in a form that exposes type details and other fields.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/StmtVisitor.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/PrettyPrinter.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-
-//===----------------------------------------------------------------------===//
-// StmtDumper Visitor
-//===----------------------------------------------------------------------===//
-
-namespace {
- class StmtDumper : public StmtVisitor<StmtDumper> {
- SourceManager *SM;
- raw_ostream &OS;
- unsigned IndentLevel;
- bool IsFirstLine;
-
- /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump
- /// the first few levels of an AST. This keeps track of how many ast levels
- /// are left.
- unsigned MaxDepth;
-
- /// LastLocFilename/LastLocLine - Keep track of the last location we print
- /// out so that we can print out deltas from then on out.
- const char *LastLocFilename;
- unsigned LastLocLine;
-
- class IndentScope {
- StmtDumper &Dumper;
- public:
- IndentScope(StmtDumper &Dumper) : Dumper(Dumper) {
- Dumper.indent();
- }
- ~IndentScope() {
- Dumper.unindent();
- }
- };
-
- public:
- StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth)
- : SM(sm), OS(os), IndentLevel(0), IsFirstLine(true), MaxDepth(maxDepth) {
- LastLocFilename = "";
- LastLocLine = ~0U;
- }
-
- ~StmtDumper() {
- OS << "\n";
- }
-
- void DumpSubTree(Stmt *S) {
- // Prune the recursion if not using dump all.
- if (MaxDepth == 0) return;
-
- IndentScope Indent(*this);
-
- if (!S) {
- OS << "<<<NULL>>>";
- return;
- }
-
- if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) {
- VisitDeclStmt(DS);
- return;
- }
-
- Visit(S);
- for (Stmt::child_range CI = S->children(); CI; CI++)
- DumpSubTree(*CI);
- }
-
- void DumpDeclarator(Decl *D);
-
- void indent() {
- if (IsFirstLine)
- IsFirstLine = false;
- else
- OS << "\n";
- OS.indent(IndentLevel * 2);
- OS << "(";
- IndentLevel++;
- }
-
- void unindent() {
- OS << ")";
- IndentLevel--;
- }
-
- void DumpType(QualType T) {
- SplitQualType T_split = T.split();
- OS << "'" << QualType::getAsString(T_split) << "'";
-
- if (!T.isNull()) {
- // If the type is sugared, also dump a (shallow) desugared type.
- SplitQualType D_split = T.getSplitDesugaredType();
- if (T_split != D_split)
- OS << ":'" << QualType::getAsString(D_split) << "'";
- }
- }
- void DumpDeclRef(Decl *node);
- void DumpStmt(const Stmt *Node) {
- OS << Node->getStmtClassName()
- << " " << (const 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_ObjCSubscript: OS << " objcsubscript"; 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);
-
- // Stmts.
- void VisitStmt(Stmt *Node);
- void VisitDeclStmt(DeclStmt *Node);
- void VisitLabelStmt(LabelStmt *Node);
- void VisitGotoStmt(GotoStmt *Node);
-
- // Exprs
- void VisitExpr(Expr *Node);
- void VisitCastExpr(CastExpr *Node);
- void VisitDeclRefExpr(DeclRefExpr *Node);
- void VisitPredefinedExpr(PredefinedExpr *Node);
- void VisitCharacterLiteral(CharacterLiteral *Node);
- void VisitIntegerLiteral(IntegerLiteral *Node);
- void VisitFloatingLiteral(FloatingLiteral *Node);
- void VisitStringLiteral(StringLiteral *Str);
- void VisitUnaryOperator(UnaryOperator *Node);
- void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node);
- void VisitMemberExpr(MemberExpr *Node);
- void VisitExtVectorElementExpr(ExtVectorElementExpr *Node);
- void VisitBinaryOperator(BinaryOperator *Node);
- void VisitCompoundAssignOperator(CompoundAssignOperator *Node);
- void VisitAddrLabelExpr(AddrLabelExpr *Node);
- void VisitBlockExpr(BlockExpr *Node);
- void VisitOpaqueValueExpr(OpaqueValueExpr *Node);
-
- // C++
- void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node);
- void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node);
- void VisitCXXThisExpr(CXXThisExpr *Node);
- void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node);
- void VisitCXXConstructExpr(CXXConstructExpr *Node);
- void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node);
- void VisitExprWithCleanups(ExprWithCleanups *Node);
- void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node);
- void DumpCXXTemporary(CXXTemporary *Temporary);
-
- // ObjC
- void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node);
- void VisitObjCEncodeExpr(ObjCEncodeExpr *Node);
- void VisitObjCMessageExpr(ObjCMessageExpr* Node);
- void VisitObjCBoxedExpr(ObjCBoxedExpr* Node);
- void VisitObjCSelectorExpr(ObjCSelectorExpr *Node);
- void VisitObjCProtocolExpr(ObjCProtocolExpr *Node);
- void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node);
- void VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node);
- void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node);
- void VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node);
- };
-}
-
-//===----------------------------------------------------------------------===//
-// Utilities
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::DumpLocation(SourceLocation Loc) {
- SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
-
- // 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();
- LastLocFilename = PLoc.getFilename();
- LastLocLine = PLoc.getLine();
- } else if (PLoc.getLine() != LastLocLine) {
- OS << "line" << ':' << PLoc.getLine()
- << ':' << PLoc.getColumn();
- LastLocLine = PLoc.getLine();
- } else {
- OS << "col" << ':' << PLoc.getColumn();
- }
-}
-
-void StmtDumper::DumpSourceRange(const Stmt *Node) {
- // Can't translate locations if a SourceManager isn't available.
- if (SM == 0) return;
-
- // TODO: If the parent expression is available, we can print a delta vs its
- // location.
- SourceRange R = Node->getSourceRange();
-
- OS << " <";
- DumpLocation(R.getBegin());
- if (R.getBegin() != R.getEnd()) {
- OS << ", ";
- DumpLocation(R.getEnd());
- }
- OS << ">";
-
- // <t2.c:123:421[blah], t2.c:412:321>
-
-}
-
-
-//===----------------------------------------------------------------------===//
-// Stmt printing methods.
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitStmt(Stmt *Node) {
- DumpStmt(Node);
-}
-
-void StmtDumper::DumpDeclarator(Decl *D) {
- // FIXME: Need to complete/beautify this... this code simply shows the
- // nodes are where they need to be.
- if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) {
- OS << "\"typedef " << localType->getUnderlyingType().getAsString()
- << ' ' << *localType << '"';
- } else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) {
- OS << "\"using " << *localType << " = "
- << localType->getUnderlyingType().getAsString() << '"';
- } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
- OS << "\"";
- // Emit storage class for vardecls.
- if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
- if (V->getStorageClass() != SC_None)
- OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass())
- << " ";
- }
-
- std::string Name = VD->getNameAsString();
- VD->getType().getAsStringInternal(Name,
- PrintingPolicy(VD->getASTContext().getLangOpts()));
- OS << Name;
-
- // If this is a vardecl with an initializer, emit it.
- if (VarDecl *V = dyn_cast<VarDecl>(VD)) {
- if (V->getInit()) {
- OS << " =";
- DumpSubTree(V->getInit());
- }
- }
- OS << '"';
- } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
- // print a free standing tag decl (e.g. "struct x;").
- const char *tagname;
- if (const IdentifierInfo *II = TD->getIdentifier())
- tagname = II->getNameStart();
- else
- tagname = "<anonymous>";
- OS << '"' << TD->getKindName() << ' ' << tagname << ";\"";
- // FIXME: print tag bodies.
- } else if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(D)) {
- // print using-directive decl (e.g. "using namespace x;")
- const char *ns;
- if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier())
- ns = II->getNameStart();
- else
- ns = "<anonymous>";
- OS << '"' << UD->getDeclKindName() << ns << ";\"";
- } else if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) {
- // print using decl (e.g. "using std::string;")
- const char *tn = UD->isTypeName() ? "typename " : "";
- OS << '"' << UD->getDeclKindName() << tn;
- UD->getQualifier()->print(OS,
- PrintingPolicy(UD->getASTContext().getLangOpts()));
- OS << ";\"";
- } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) {
- OS << "label " << *LD;
- } else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) {
- OS << "\"static_assert(";
- DumpSubTree(SAD->getAssertExpr());
- OS << ",";
- DumpSubTree(SAD->getMessage());
- OS << ");\"";
- } else {
- llvm_unreachable("Unexpected decl");
- }
-}
-
-void StmtDumper::VisitDeclStmt(DeclStmt *Node) {
- DumpStmt(Node);
- for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end();
- DI != DE; ++DI) {
- IndentScope Indent(*this);
- Decl* D = *DI;
- OS << (void*) D << " ";
- DumpDeclarator(D);
- }
-}
-
-void StmtDumper::VisitLabelStmt(LabelStmt *Node) {
- DumpStmt(Node);
- OS << " '" << Node->getName() << "'";
-}
-
-void StmtDumper::VisitGotoStmt(GotoStmt *Node) {
- DumpStmt(Node);
- OS << " '" << Node->getLabel()->getName()
- << "':" << (void*)Node->getLabel();
-}
-
-//===----------------------------------------------------------------------===//
-// Expr printing methods.
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitExpr(Expr *Node) {
- DumpExpr(Node);
-}
-
-static void DumpBasePath(raw_ostream &OS, CastExpr *Node) {
- if (Node->path_empty())
- return;
-
- OS << " (";
- bool First = true;
- for (CastExpr::path_iterator
- I = Node->path_begin(), E = Node->path_end(); I != E; ++I) {
- const CXXBaseSpecifier *Base = *I;
- if (!First)
- OS << " -> ";
-
- const CXXRecordDecl *RD =
- cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
-
- if (Base->isVirtual())
- OS << "virtual ";
- OS << RD->getName();
- First = false;
- }
-
- OS << ')';
-}
-
-void StmtDumper::VisitCastExpr(CastExpr *Node) {
- DumpExpr(Node);
- OS << " <" << Node->getCastKindName();
- DumpBasePath(OS, Node);
- OS << ">";
-}
-
-void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
- DumpExpr(Node);
-
- OS << " ";
- DumpDeclRef(Node->getDecl());
- if (Node->getDecl() != Node->getFoundDecl()) {
- OS << " (";
- DumpDeclRef(Node->getFoundDecl());
- OS << ")";
- }
-}
-
-void StmtDumper::DumpDeclRef(Decl *d) {
- OS << d->getDeclKindName() << ' ' << (void*) d;
-
- if (NamedDecl *nd = dyn_cast<NamedDecl>(d)) {
- OS << " '";
- nd->getDeclName().printName(OS);
- OS << "'";
- }
-
- if (ValueDecl *vd = dyn_cast<ValueDecl>(d)) {
- OS << ' '; DumpType(vd->getType());
- }
-}
-
-void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
- DumpExpr(Node);
- OS << " (";
- if (!Node->requiresADL()) OS << "no ";
- OS << "ADL) = '" << Node->getName() << '\'';
-
- UnresolvedLookupExpr::decls_iterator
- I = Node->decls_begin(), E = Node->decls_end();
- if (I == E) OS << " empty";
- for (; I != E; ++I)
- OS << " " << (void*) *I;
-}
-
-void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
- DumpExpr(Node);
-
- OS << " " << Node->getDecl()->getDeclKindName()
- << "Decl='" << *Node->getDecl()
- << "' " << (void*)Node->getDecl();
- if (Node->isFreeIvar())
- OS << " isFreeIvar";
-}
-
-void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) {
- DumpExpr(Node);
- switch (Node->getIdentType()) {
- default: llvm_unreachable("unknown case");
- case PredefinedExpr::Func: OS << " __func__"; break;
- case PredefinedExpr::Function: OS << " __FUNCTION__"; break;
- case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break;
- case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break;
- }
-}
-
-void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) {
- DumpExpr(Node);
- OS << " " << Node->getValue();
-}
-
-void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) {
- DumpExpr(Node);
-
- bool isSigned = Node->getType()->isSignedIntegerType();
- OS << " " << Node->getValue().toString(10, isSigned);
-}
-void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) {
- DumpExpr(Node);
- OS << " " << Node->getValueAsApproximateDouble();
-}
-
-void StmtDumper::VisitStringLiteral(StringLiteral *Str) {
- DumpExpr(Str);
- OS << " ";
- Str->outputString(OS);
-}
-
-void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) {
- DumpExpr(Node);
- OS << " " << (Node->isPostfix() ? "postfix" : "prefix")
- << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
-}
-void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) {
- DumpExpr(Node);
- switch(Node->getKind()) {
- case UETT_SizeOf:
- OS << " sizeof ";
- break;
- case UETT_AlignOf:
- OS << " alignof ";
- break;
- case UETT_VecStep:
- OS << " vec_step ";
- break;
- }
- if (Node->isArgumentType())
- DumpType(Node->getArgumentType());
-}
-
-void StmtDumper::VisitMemberExpr(MemberExpr *Node) {
- DumpExpr(Node);
- OS << " " << (Node->isArrow() ? "->" : ".")
- << *Node->getMemberDecl() << ' '
- << (void*)Node->getMemberDecl();
-}
-void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
- DumpExpr(Node);
- OS << " " << Node->getAccessor().getNameStart();
-}
-void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) {
- DumpExpr(Node);
- OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'";
-}
-void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) {
- DumpExpr(Node);
- OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode())
- << "' ComputeLHSTy=";
- DumpType(Node->getComputationLHSType());
- OS << " ComputeResultTy=";
- DumpType(Node->getComputationResultType());
-}
-
-void StmtDumper::VisitBlockExpr(BlockExpr *Node) {
- DumpExpr(Node);
-
- BlockDecl *block = Node->getBlockDecl();
- OS << " decl=" << block;
-
- if (block->capturesCXXThis()) {
- IndentScope Indent(*this);
- OS << "capture this";
- }
- for (BlockDecl::capture_iterator
- i = block->capture_begin(), e = block->capture_end(); i != e; ++i) {
- IndentScope Indent(*this);
- OS << "capture ";
- if (i->isByRef()) OS << "byref ";
- if (i->isNested()) OS << "nested ";
- if (i->getVariable())
- DumpDeclRef(i->getVariable());
- if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr());
- }
-
- DumpSubTree(block->getBody());
-}
-
-void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
- DumpExpr(Node);
-
- if (Expr *Source = Node->getSourceExpr())
- DumpSubTree(Source);
-}
-
-// GNU extensions.
-
-void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) {
- DumpExpr(Node);
- OS << " " << Node->getLabel()->getName()
- << " " << (void*)Node->getLabel();
-}
-
-//===----------------------------------------------------------------------===//
-// C++ Expressions
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
- DumpExpr(Node);
- OS << " " << Node->getCastName()
- << "<" << Node->getTypeAsWritten().getAsString() << ">"
- << " <" << Node->getCastKindName();
- DumpBasePath(OS, Node);
- OS << ">";
-}
-
-void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) {
- DumpExpr(Node);
- OS << " " << (Node->getValue() ? "true" : "false");
-}
-
-void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) {
- DumpExpr(Node);
- OS << " this";
-}
-
-void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
- DumpExpr(Node);
- OS << " functional cast to " << Node->getTypeAsWritten().getAsString()
- << " <" << Node->getCastKindName() << ">";
-}
-
-void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) {
- DumpExpr(Node);
- CXXConstructorDecl *Ctor = Node->getConstructor();
- DumpType(Ctor->getType());
- if (Node->isElidable())
- OS << " elidable";
- if (Node->requiresZeroInitialization())
- OS << " zeroing";
-}
-
-void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
- DumpExpr(Node);
- OS << " ";
- DumpCXXTemporary(Node->getTemporary());
-}
-
-void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) {
- DumpExpr(Node);
- for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) {
- IndentScope Indent(*this);
- OS << "cleanup ";
- DumpDeclRef(Node->getObject(i));
- }
-}
-
-void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) {
- OS << "(CXXTemporary " << (void *)Temporary << ")";
-}
-
-//===----------------------------------------------------------------------===//
-// Obj-C Expressions
-//===----------------------------------------------------------------------===//
-
-void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) {
- DumpExpr(Node);
- OS << " selector=" << Node->getSelector().getAsString();
- switch (Node->getReceiverKind()) {
- case ObjCMessageExpr::Instance:
- break;
-
- case ObjCMessageExpr::Class:
- OS << " class=";
- DumpType(Node->getClassReceiver());
- break;
-
- case ObjCMessageExpr::SuperInstance:
- OS << " super (instance)";
- break;
-
- case ObjCMessageExpr::SuperClass:
- OS << " super (class)";
- break;
- }
-}
-
-void StmtDumper::VisitObjCBoxedExpr(ObjCBoxedExpr* Node) {
- DumpExpr(Node);
- OS << " selector=" << Node->getBoxingMethod()->getSelector().getAsString();
-}
-
-void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) {
- DumpStmt(Node);
- if (VarDecl *CatchParam = Node->getCatchParamDecl()) {
- OS << " catch parm = ";
- DumpDeclarator(CatchParam);
- } else {
- OS << " catch all";
- }
-}
-
-void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
- DumpExpr(Node);
- OS << " ";
- DumpType(Node->getEncodedType());
-}
-
-void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
- DumpExpr(Node);
-
- OS << " " << Node->getSelector().getAsString();
-}
-
-void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) {
- DumpExpr(Node);
-
- OS << ' ' <<* Node->getProtocol();
-}
-
-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 << "\" Setter=\"";
- if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter())
- OS << Setter->getSelector().getAsString();
- else
- OS << "(null)";
- OS << "\"";
- } else {
- OS << " Kind=PropertyRef Property=\"" << *Node->getExplicitProperty() <<'"';
- }
-
- if (Node->isSuperReceiver())
- OS << " super";
-
- OS << " Messaging=";
- if (Node->isMessagingGetter() && Node->isMessagingSetter())
- OS << "Getter&Setter";
- else if (Node->isMessagingGetter())
- OS << "Getter";
- else if (Node->isMessagingSetter())
- OS << "Setter";
-}
-
-void StmtDumper::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) {
- DumpExpr(Node);
- if (Node->isArraySubscriptRefExpr())
- OS << " Kind=ArraySubscript GetterForArray=\"";
- else
- OS << " Kind=DictionarySubscript GetterForDictionary=\"";
- if (Node->getAtIndexMethodDecl())
- OS << Node->getAtIndexMethodDecl()->getSelector().getAsString();
- else
- OS << "(null)";
-
- if (Node->isArraySubscriptRefExpr())
- OS << "\" SetterForArray=\"";
- else
- OS << "\" SetterForDictionary=\"";
- if (Node->setAtIndexMethodDecl())
- OS << Node->setAtIndexMethodDecl()->getSelector().getAsString();
- else
- OS << "(null)";
-}
-
-void StmtDumper::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *Node) {
- DumpExpr(Node);
- OS << " " << (Node->getValue() ? "__objc_yes" : "__objc_no");
-}
-
-//===----------------------------------------------------------------------===//
-// Stmt method implementations
-//===----------------------------------------------------------------------===//
-
-/// dump - This does a local dump of the specified AST fragment. It dumps the
-/// specified node and a few nodes underneath it, but not the whole subtree.
-/// This is useful in a debugger.
-void Stmt::dump(SourceManager &SM) const {
- dump(llvm::errs(), SM);
-}
-
-void Stmt::dump(raw_ostream &OS, SourceManager &SM) const {
- StmtDumper P(&SM, OS, 4);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
-
-/// dump - This does a local dump of the specified AST fragment. It dumps the
-/// specified node and a few nodes underneath it, but not the whole subtree.
-/// This is useful in a debugger.
-void Stmt::dump() const {
- StmtDumper P(0, llvm::errs(), 4);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
-
-/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
-void Stmt::dumpAll(SourceManager &SM) const {
- StmtDumper P(&SM, llvm::errs(), ~0U);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
-
-/// dumpAll - This does a dump of the specified AST fragment and all subtrees.
-void Stmt::dumpAll() const {
- StmtDumper P(0, llvm::errs(), ~0U);
- P.DumpSubTree(const_cast<Stmt*>(this));
-}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 57eb1a95181c..7df7fdb92bf2 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -13,14 +13,17 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
-#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Format.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -583,10 +586,8 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitDependentScopeDeclRefExpr(
@@ -597,10 +598,8 @@ void StmtPrinter::VisitDependentScopeDeclRefExpr(
OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
@@ -610,10 +609,8 @@ void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
OS << "template ";
OS << Node->getNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
@@ -709,15 +706,14 @@ void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) {
OS << "'\\v'";
break;
default:
- if (value < 256 && isprint(value)) {
+ if (value < 256 && isPrintable((unsigned char)value))
OS << "'" << (char)value << "'";
- } else if (value < 256) {
- OS << "'\\x";
- OS.write_hex(value) << "'";
- } else {
- // FIXME what to really do here?
- OS << value;
- }
+ else if (value < 256)
+ OS << "'\\x" << llvm::format("%02x", value) << "'";
+ else if (value <= 0xFFFF)
+ OS << "'\\u" << llvm::format("%04x", value) << "'";
+ else
+ OS << "'\\U" << llvm::format("%08x", value) << "'";
}
}
@@ -810,7 +806,8 @@ void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) {
void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) {
OS << "__builtin_offsetof(";
- OS << Node->getTypeSourceInfo()->getType().getAsString(Policy) << ", ";
+ Node->getTypeSourceInfo()->getType().print(OS, Policy);
+ OS << ", ";
bool PrintedSomething = false;
for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) {
OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i);
@@ -858,9 +855,11 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
OS << "vec_step";
break;
}
- if (Node->isArgumentType())
- OS << "(" << Node->getArgumentType().getAsString(Policy) << ")";
- else {
+ if (Node->isArgumentType()) {
+ OS << '(';
+ Node->getArgumentType().print(OS, Policy);
+ OS << ')';
+ } else {
OS << " ";
PrintExpr(Node->getArgumentExpr());
}
@@ -875,7 +874,7 @@ void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
if (T.isNull())
OS << "default";
else
- OS << T.getAsString(Policy);
+ T.print(OS, Policy);
OS << ": ";
PrintExpr(Node->getAssocExpr(i));
}
@@ -910,20 +909,26 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
// FIXME: Suppress printing implicit bases (like "this")
PrintExpr(Node->getBase());
+
+ MemberExpr *ParentMember = dyn_cast<MemberExpr>(Node->getBase());
+ FieldDecl *ParentDecl = ParentMember
+ ? dyn_cast<FieldDecl>(ParentMember->getMemberDecl()) : NULL;
+
+ if (!ParentDecl || !ParentDecl->isAnonymousStructOrUnion())
+ OS << (Node->isArrow() ? "->" : ".");
+
if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
if (FD->isAnonymousStructOrUnion())
return;
- OS << (Node->isArrow() ? "->" : ".");
+
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
if (Node->hasExplicitTemplateArgs())
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) {
PrintExpr(Node->getBase());
@@ -936,11 +941,15 @@ void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
OS << Node->getAccessor().getName();
}
void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) {
- OS << "(" << Node->getTypeAsWritten().getAsString(Policy) << ")";
+ OS << '(';
+ Node->getTypeAsWritten().print(OS, Policy);
+ OS << ')';
PrintExpr(Node->getSubExpr());
}
void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) {
- OS << "(" << Node->getType().getAsString(Policy) << ")";
+ OS << '(';
+ Node->getType().print(OS, Policy);
+ OS << ')';
PrintExpr(Node->getInitializer());
}
void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
@@ -1059,10 +1068,14 @@ void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) {
}
void StmtPrinter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) {
- if (Policy.LangOpts.CPlusPlus)
- OS << "/*implicit*/" << Node->getType().getAsString(Policy) << "()";
- else {
- OS << "/*implicit*/(" << Node->getType().getAsString(Policy) << ")";
+ if (Policy.LangOpts.CPlusPlus) {
+ OS << "/*implicit*/";
+ Node->getType().print(OS, Policy);
+ OS << "()";
+ } else {
+ OS << "/*implicit*/(";
+ Node->getType().print(OS, Policy);
+ OS << ')';
if (Node->getType()->isRecordType())
OS << "{}";
else
@@ -1074,7 +1087,7 @@ void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) {
OS << "__builtin_va_arg(";
PrintExpr(Node->getSubExpr());
OS << ", ";
- OS << Node->getType().getAsString(Policy);
+ Node->getType().print(OS, Policy);
OS << ")";
}
@@ -1183,7 +1196,8 @@ void StmtPrinter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *Node) {
void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) {
OS << Node->getCastName() << '<';
- OS << Node->getTypeAsWritten().getAsString(Policy) << ">(";
+ Node->getTypeAsWritten().print(OS, Policy);
+ OS << ">(";
PrintExpr(Node->getSubExpr());
OS << ")";
}
@@ -1207,7 +1221,7 @@ void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) {
void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
OS << "typeid(";
if (Node->isTypeOperand()) {
- OS << Node->getTypeOperand().getAsString(Policy);
+ Node->getTypeOperand().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
@@ -1217,7 +1231,7 @@ void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) {
void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) {
OS << "__uuidof(";
if (Node->isTypeOperand()) {
- OS << Node->getTypeOperand().getAsString(Policy);
+ Node->getTypeOperand().print(OS, Policy);
} else {
PrintExpr(Node->getExprOperand());
}
@@ -1288,7 +1302,7 @@ void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) {
}
void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
- OS << Node->getType().getAsString(Policy);
+ Node->getType().print(OS, Policy);
OS << "(";
PrintExpr(Node->getSubExpr());
OS << ")";
@@ -1299,7 +1313,7 @@ void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) {
}
void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) {
- OS << Node->getType().getAsString(Policy);
+ Node->getType().print(OS, Policy);
OS << "(";
for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(),
ArgEnd = Node->arg_end();
@@ -1369,8 +1383,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
NeedComma = true;
}
std::string ParamStr = (*P)->getNameAsString();
- (*P)->getOriginalType().getAsStringInternal(ParamStr, Policy);
- OS << ParamStr;
+ (*P)->getOriginalType().print(OS, Policy, ParamStr);
}
if (Method->isVariadic()) {
if (NeedComma)
@@ -1384,17 +1397,15 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
const FunctionProtoType *Proto
= Method->getType()->getAs<FunctionProtoType>();
- {
- std::string ExceptionSpec;
- Proto->printExceptionSpecification(ExceptionSpec, Policy);
- OS << ExceptionSpec;
- }
+ Proto->printExceptionSpecification(OS, Policy);
// FIXME: Attributes
// Print the trailing return type if it was specified in the source.
- if (Node->hasExplicitResultType())
- OS << " -> " << Proto->getResultType().getAsString(Policy);
+ if (Node->hasExplicitResultType()) {
+ OS << " -> ";
+ Proto->getResultType().print(OS, Policy);
+ }
}
// Print the body.
@@ -1405,9 +1416,10 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) {
void StmtPrinter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) {
if (TypeSourceInfo *TSInfo = Node->getTypeSourceInfo())
- OS << TSInfo->getType().getAsString(Policy) << "()";
+ TSInfo->getType().print(OS, Policy);
else
- OS << Node->getType().getAsString(Policy) << "()";
+ Node->getType().print(OS, Policy);
+ OS << "()";
}
void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
@@ -1431,12 +1443,11 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
std::string TypeS;
if (Expr *Size = E->getArraySize()) {
llvm::raw_string_ostream s(TypeS);
+ s << '[';
Size->printPretty(s, Helper, Policy);
- s.flush();
- TypeS = "[" + TypeS + "]";
+ s << ']';
}
- E->getAllocatedType().getAsStringInternal(TypeS, Policy);
- OS << TypeS;
+ E->getAllocatedType().print(OS, Policy, TypeS);
if (E->isParenTypeId())
OS << ")";
@@ -1469,15 +1480,16 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
E->getQualifier()->print(OS, Policy);
OS << "~";
- std::string TypeS;
if (IdentifierInfo *II = E->getDestroyedTypeIdentifier())
OS << II->getName();
else
- E->getDestroyedType().getAsStringInternal(TypeS, Policy);
- OS << TypeS;
+ E->getDestroyedType().print(OS, Policy);
}
void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ if (E->isListInitialization())
+ OS << "{ ";
+
for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) {
if (isa<CXXDefaultArgExpr>(E->getArg(i))) {
// Don't print any defaulted arguments
@@ -1487,6 +1499,9 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
if (i) OS << ", ";
PrintExpr(E->getArg(i));
}
+
+ if (E->isListInitialization())
+ OS << " }";
}
void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
@@ -1497,7 +1512,7 @@ void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) {
void
StmtPrinter::VisitCXXUnresolvedConstructExpr(
CXXUnresolvedConstructExpr *Node) {
- OS << Node->getTypeAsWritten().getAsString(Policy);
+ Node->getTypeAsWritten().print(OS, Policy);
OS << "(";
for (CXXUnresolvedConstructExpr::arg_iterator Arg = Node->arg_begin(),
ArgEnd = Node->arg_end();
@@ -1520,12 +1535,9 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr(
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
- if (Node->hasExplicitTemplateArgs()) {
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
- }
+ if (Node->hasExplicitTemplateArgs())
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
@@ -1538,20 +1550,20 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
if (Node->hasTemplateKeyword())
OS << "template ";
OS << Node->getMemberNameInfo();
- if (Node->hasExplicitTemplateArgs()) {
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
- Node->getNumTemplateArgs(),
- Policy);
- }
+ if (Node->hasExplicitTemplateArgs())
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Node->getTemplateArgs(), Node->getNumTemplateArgs(), Policy);
}
static const char *getTypeTraitName(UnaryTypeTrait UTT) {
switch (UTT) {
case UTT_HasNothrowAssign: return "__has_nothrow_assign";
+ case UTT_HasNothrowMoveAssign: return "__has_nothrow_move_assign";
case UTT_HasNothrowConstructor: return "__has_nothrow_constructor";
case UTT_HasNothrowCopy: return "__has_nothrow_copy";
case UTT_HasTrivialAssign: return "__has_trivial_assign";
+ case UTT_HasTrivialMoveAssign: return "__has_trivial_move_assign";
+ case UTT_HasTrivialMoveConstructor: return "__has_trivial_move_constructor";
case UTT_HasTrivialDefaultConstructor: return "__has_trivial_constructor";
case UTT_HasTrivialCopy: return "__has_trivial_copy";
case UTT_HasTrivialDestructor: return "__has_trivial_destructor";
@@ -1631,14 +1643,17 @@ static const char *getExpressionTraitName(ExpressionTrait ET) {
}
void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) {
- OS << getTypeTraitName(E->getTrait()) << "("
- << E->getQueriedType().getAsString(Policy) << ")";
+ OS << getTypeTraitName(E->getTrait()) << '(';
+ E->getQueriedType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) {
- OS << getTypeTraitName(E->getTrait()) << "("
- << E->getLhsType().getAsString(Policy) << ","
- << E->getRhsType().getAsString(Policy) << ")";
+ OS << getTypeTraitName(E->getTrait()) << '(';
+ E->getLhsType().print(OS, Policy);
+ OS << ',';
+ E->getRhsType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) {
@@ -1646,20 +1661,21 @@ void StmtPrinter::VisitTypeTraitExpr(TypeTraitExpr *E) {
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) {
if (I > 0)
OS << ", ";
- OS << E->getArg(I)->getType().getAsString(Policy);
+ E->getArg(I)->getType().print(OS, Policy);
}
OS << ")";
}
void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
- OS << getTypeTraitName(E->getTrait()) << "("
- << E->getQueriedType().getAsString(Policy) << ")";
+ OS << getTypeTraitName(E->getTrait()) << '(';
+ E->getQueriedType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) {
- OS << getExpressionTraitName(E->getTrait()) << "(";
- PrintExpr(E->getQueriedExpression());
- OS << ")";
+ OS << getExpressionTraitName(E->getTrait()) << '(';
+ PrintExpr(E->getQueriedExpression());
+ OS << ')';
}
void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
@@ -1738,7 +1754,9 @@ void StmtPrinter::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) {
}
void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) {
- OS << "@encode(" << Node->getEncodedType().getAsString(Policy) << ')';
+ OS << "@encode(";
+ Node->getEncodedType().print(OS, Policy);
+ OS << ')';
}
void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) {
@@ -1757,7 +1775,7 @@ void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) {
break;
case ObjCMessageExpr::Class:
- OS << Mess->getClassReceiver().getAsString(Policy);
+ Mess->getClassReceiver().print(OS, Policy);
break;
case ObjCMessageExpr::SuperInstance:
@@ -1798,8 +1816,9 @@ StmtPrinter::VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) {
void
StmtPrinter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
- OS << "(" << E->getBridgeKindName() << E->getType().getAsString(Policy)
- << ")";
+ OS << '(' << E->getBridgeKindName();
+ E->getType().print(OS, Policy);
+ OS << ')';
PrintExpr(E->getSubExpr());
}
@@ -1813,13 +1832,11 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
OS << "()";
} else if (!BD->param_empty() || cast<FunctionProtoType>(AFT)->isVariadic()) {
OS << '(';
- std::string ParamStr;
for (BlockDecl::param_iterator AI = BD->param_begin(),
E = BD->param_end(); AI != E; ++AI) {
if (AI != BD->param_begin()) OS << ", ";
- ParamStr = (*AI)->getNameAsString();
- (*AI)->getType().getAsStringInternal(ParamStr, Policy);
- OS << ParamStr;
+ std::string ParamStr = (*AI)->getNameAsString();
+ (*AI)->getType().print(OS, Policy, ParamStr);
}
const FunctionProtoType *FT = cast<FunctionProtoType>(AFT);
@@ -1829,6 +1846,7 @@ void StmtPrinter::VisitBlockExpr(BlockExpr *Node) {
}
OS << ')';
}
+ OS << "{ }";
}
void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
@@ -1838,7 +1856,8 @@ void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {
void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
OS << "__builtin_astype(";
PrintExpr(Node->getSrcExpr());
- OS << ", " << Node->getType().getAsString();
+ OS << ", ";
+ Node->getType().print(OS, Policy);
OS << ")";
}
@@ -1859,11 +1878,6 @@ void Stmt::printPretty(raw_ostream &OS,
return;
}
- if (Policy.DumpSourceManager) {
- dump(OS, *Policy.DumpSourceManager);
- return;
- }
-
StmtPrinter P(OS, Helper, Policy, Indentation);
P.Visit(const_cast<Stmt*>(this));
}
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index e9ee385457f8..d68b95edb730 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -23,8 +23,8 @@
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
-#include <cctype>
using namespace clang;
@@ -224,12 +224,12 @@ bool TemplateArgument::containsUnexpandedParameterPack() const {
return false;
}
-llvm::Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
+Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const {
assert(Kind == TemplateExpansion);
if (TemplateArg.NumExpansions)
return TemplateArg.NumExpansions - 1;
- return llvm::Optional<unsigned>();
+ return None;
}
void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
@@ -347,9 +347,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy,
case Type: {
PrintingPolicy SubPolicy(Policy);
SubPolicy.SuppressStrongLifetime = true;
- std::string TypeStr;
- getAsType().getAsStringInternal(TypeStr, SubPolicy);
- Out << TypeStr;
+ getAsType().print(Out, SubPolicy);
break;
}
@@ -451,10 +449,9 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
llvm_unreachable("Invalid TemplateArgument Kind!");
}
-TemplateArgumentLoc
-TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
- llvm::Optional<unsigned> &NumExpansions,
- ASTContext &Context) const {
+TemplateArgumentLoc TemplateArgumentLoc::getPackExpansionPattern(
+ SourceLocation &Ellipsis, Optional<unsigned> &NumExpansions,
+ ASTContext &Context) const {
assert(Argument.isPackExpansion());
switch (Argument.getKind()) {
@@ -466,8 +463,8 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
ExpansionTSInfo = Context.getTrivialTypeSourceInfo(
getArgument().getAsType(),
Ellipsis);
- PackExpansionTypeLoc Expansion
- = cast<PackExpansionTypeLoc>(ExpansionTSInfo->getTypeLoc());
+ PackExpansionTypeLoc Expansion =
+ ExpansionTSInfo->getTypeLoc().castAs<PackExpansionTypeLoc>();
Ellipsis = Expansion.getEllipsisLoc();
TypeLoc Pattern = Expansion.getPatternLoc();
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index e89ba5399b6b..8767c635f675 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -1,4 +1,4 @@
-//===--- TemplateName.h - C++ Template Name Representation-------*- C++ -*-===//
+//===--- TemplateName.cpp - C++ Template Name Representation---------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -12,10 +12,10 @@
//===----------------------------------------------------------------------===//
#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"
+#include "clang/AST/TemplateBase.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/Support/raw_ostream.h"
@@ -163,14 +163,20 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
LangOptions LO;
LO.CPlusPlus = true;
LO.Bool = true;
+ OS << '\'';
N.print(OS, PrintingPolicy(LO));
+ OS << '\'';
OS.flush();
return DB << NameStr;
}
-void TemplateName::dump() const {
+void TemplateName::dump(raw_ostream &OS) const {
LangOptions LO; // FIXME!
LO.CPlusPlus = true;
LO.Bool = true;
- print(llvm::errs(), PrintingPolicy(LO));
+ print(OS, PrintingPolicy(LO));
+}
+
+void TemplateName::dump() const {
+ dump(llvm::errs());
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 580ec50ca1f8..0c5636d84067 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -12,13 +12,14 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/CharUnits.h"
-#include "clang/AST/Type.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyPrinter.h"
+#include "clang/AST/Type.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/APSInt.h"
@@ -75,16 +76,35 @@ bool QualType::isConstant(QualType T, ASTContext &Ctx) {
unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context,
QualType ElementType,
const llvm::APInt &NumElements) {
+ uint64_t ElementSize = Context.getTypeSizeInChars(ElementType).getQuantity();
+
+ // Fast path the common cases so we can avoid the conservative computation
+ // below, which in common cases allocates "large" APSInt values, which are
+ // slow.
+
+ // If the element size is a power of 2, we can directly compute the additional
+ // number of addressing bits beyond those required for the element count.
+ if (llvm::isPowerOf2_64(ElementSize)) {
+ return NumElements.getActiveBits() + llvm::Log2_64(ElementSize);
+ }
+
+ // If both the element count and element size fit in 32-bits, we can do the
+ // computation directly in 64-bits.
+ if ((ElementSize >> 32) == 0 && NumElements.getBitWidth() <= 64 &&
+ (NumElements.getZExtValue() >> 32) == 0) {
+ uint64_t TotalSize = NumElements.getZExtValue() * ElementSize;
+ return 64 - llvm::CountLeadingZeros_64(TotalSize);
+ }
+
+ // Otherwise, use APSInt to handle arbitrary sized values.
llvm::APSInt SizeExtended(NumElements, true);
unsigned SizeTypeBits = Context.getTypeSize(Context.getSizeType());
SizeExtended = SizeExtended.extend(std::max(SizeTypeBits,
SizeExtended.getBitWidth()) * 2);
- uint64_t ElementSize
- = Context.getTypeSizeInChars(ElementType).getQuantity();
llvm::APSInt TotalSize(llvm::APInt(SizeExtended.getBitWidth(), ElementSize));
TotalSize *= SizeExtended;
-
+
return TotalSize.getActiveBits();
}
@@ -939,7 +959,7 @@ bool Type::isIncompleteType(NamedDecl **Def) const {
bool QualType::isPODType(ASTContext &Context) const {
// C++11 has a more relaxed definition of POD.
- if (Context.getLangOpts().CPlusPlus0x)
+ if (Context.getLangOpts().CPlusPlus11)
return isCXX11PODType(Context);
return isCXX98PODType(Context);
@@ -1052,11 +1072,13 @@ bool QualType::isTrivialType(ASTContext &Context) const {
if (const RecordType *RT = CanonicalType->getAs<RecordType>()) {
if (const CXXRecordDecl *ClassDecl =
dyn_cast<CXXRecordDecl>(RT->getDecl())) {
- // C++0x [class]p5:
- // A trivial class is a class that has a trivial default constructor
- if (!ClassDecl->hasTrivialDefaultConstructor()) return false;
- // and is trivially copyable.
- if (!ClassDecl->isTriviallyCopyable()) return false;
+ // C++11 [class]p6:
+ // A trivial class is a class that has a default constructor,
+ // has no non-trivial default constructors, and is trivially
+ // copyable.
+ return ClassDecl->hasDefaultConstructor() &&
+ !ClassDecl->hasNonTrivialDefaultConstructor() &&
+ ClassDecl->isTriviallyCopyable();
}
return true;
@@ -1509,6 +1531,14 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const {
case ObjCId: return "id";
case ObjCClass: return "Class";
case ObjCSel: return "SEL";
+ case OCLImage1d: return "image1d_t";
+ case OCLImage1dArray: return "image1d_array_t";
+ case OCLImage1dBuffer: return "image1d_buffer_t";
+ case OCLImage2d: return "image2d_t";
+ case OCLImage2dArray: return "image2d_array_t";
+ case OCLImage3d: return "image3d_t";
+ case OCLSampler: return "sampler_t";
+ case OCLEvent: return "event_t";
}
llvm_unreachable("Invalid builtin type.");
@@ -1543,29 +1573,33 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
case CC_AAPCS: return "aapcs";
case CC_AAPCS_VFP: return "aapcs-vfp";
case CC_PnaclCall: return "pnaclcall";
+ case CC_IntelOclBicc: return "intel_ocl_bicc";
}
llvm_unreachable("Invalid calling convention.");
}
-FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
- unsigned numArgs, QualType canonical,
+FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> args,
+ QualType canonical,
const ExtProtoInfo &epi)
- : FunctionType(FunctionProto, result, epi.TypeQuals, epi.RefQualifier,
+ : FunctionType(FunctionProto, result, epi.TypeQuals,
canonical,
result->isDependentType(),
result->isInstantiationDependentType(),
result->isVariablyModifiedType(),
result->containsUnexpandedParameterPack(),
epi.ExtInfo),
- NumArgs(numArgs), NumExceptions(epi.NumExceptions),
+ NumArgs(args.size()), NumExceptions(epi.NumExceptions),
ExceptionSpecType(epi.ExceptionSpecType),
HasAnyConsumedArgs(epi.ConsumedArguments != 0),
- Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn)
+ Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn),
+ RefQualifier(epi.RefQualifier)
{
+ assert(NumArgs == args.size() && "function has too many parameters");
+
// Fill in the trailing argument array.
QualType *argSlot = reinterpret_cast<QualType*>(this+1);
- for (unsigned i = 0; i != numArgs; ++i) {
+ for (unsigned i = 0; i != NumArgs; ++i) {
if (args[i]->isDependentType())
setDependent();
else if (args[i]->isInstantiationDependentType())
@@ -1579,7 +1613,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
if (getExceptionSpecType() == EST_Dynamic) {
// Fill in the exception array.
- QualType *exnSlot = argSlot + numArgs;
+ QualType *exnSlot = argSlot + NumArgs;
for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) {
if (epi.Exceptions[i]->isDependentType())
setDependent();
@@ -1593,7 +1627,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
}
} else if (getExceptionSpecType() == EST_ComputedNoexcept) {
// Store the noexcept expression and context.
- Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs);
+ Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + NumArgs);
*noexSlot = epi.NoexceptExpr;
if (epi.NoexceptExpr) {
@@ -1606,7 +1640,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
} else if (getExceptionSpecType() == EST_Uninstantiated) {
// Store the function decl from which we will resolve our
// exception specification.
- FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);
+ FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + NumArgs);
slot[0] = epi.ExceptionSpecDecl;
slot[1] = epi.ExceptionSpecTemplate;
// This exception specification doesn't make the type dependent, because
@@ -1614,13 +1648,13 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
} else if (getExceptionSpecType() == EST_Unevaluated) {
// Store the function decl from which we will resolve our
// exception specification.
- FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);
+ FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + NumArgs);
slot[0] = epi.ExceptionSpecDecl;
}
if (epi.ConsumedArguments) {
bool *consumedArgs = const_cast<bool*>(getConsumedArgsBuffer());
- for (unsigned i = 0; i != numArgs; ++i)
+ for (unsigned i = 0; i != NumArgs; ++i)
consumedArgs[i] = epi.ConsumedArguments[i];
}
}
@@ -1987,22 +2021,18 @@ namespace {
/// \brief The cached properties of a type.
class CachedProperties {
- NamedDecl::LinkageInfo LV;
+ Linkage L;
bool local;
-
+
public:
- CachedProperties(NamedDecl::LinkageInfo LV, bool local)
- : LV(LV), local(local) {}
-
- Linkage getLinkage() const { return LV.linkage(); }
- Visibility getVisibility() const { return LV.visibility(); }
- bool isVisibilityExplicit() const { return LV.visibilityExplicit(); }
+ CachedProperties(Linkage L, bool local) : L(L), local(local) {}
+
+ Linkage getLinkage() const { return L; }
bool hasLocalOrUnnamedType() const { return local; }
-
+
friend CachedProperties merge(CachedProperties L, CachedProperties R) {
- NamedDecl::LinkageInfo MergedLV = L.LV;
- MergedLV.merge(R.LV);
- return CachedProperties(MergedLV,
+ Linkage MergedLinkage = minLinkage(L.L, R.L);
+ return CachedProperties(MergedLinkage,
L.hasLocalOrUnnamedType() | R.hasLocalOrUnnamedType());
}
};
@@ -2022,10 +2052,8 @@ public:
static CachedProperties get(const Type *T) {
ensure(T);
- NamedDecl::LinkageInfo LV(T->TypeBits.getLinkage(),
- T->TypeBits.getVisibility(),
- T->TypeBits.isVisibilityExplicit());
- return CachedProperties(LV, T->TypeBits.hasLocalOrUnnamedType());
+ return CachedProperties(T->TypeBits.getLinkage(),
+ T->TypeBits.hasLocalOrUnnamedType());
}
static void ensure(const Type *T) {
@@ -2037,10 +2065,7 @@ public:
if (!T->isCanonicalUnqualified()) {
const Type *CT = T->getCanonicalTypeInternal().getTypePtr();
ensure(CT);
- T->TypeBits.CacheValidAndVisibility =
- CT->TypeBits.CacheValidAndVisibility;
- T->TypeBits.CachedExplicitVisibility =
- CT->TypeBits.CachedExplicitVisibility;
+ T->TypeBits.CacheValid = true;
T->TypeBits.CachedLinkage = CT->TypeBits.CachedLinkage;
T->TypeBits.CachedLocalOrUnnamed = CT->TypeBits.CachedLocalOrUnnamed;
return;
@@ -2048,10 +2073,7 @@ public:
// Compute the cached properties and then set the cache.
CachedProperties Result = computeCachedProperties(T);
- T->TypeBits.CacheValidAndVisibility = Result.getVisibility() + 1U;
- T->TypeBits.CachedExplicitVisibility = Result.isVisibilityExplicit();
- assert(T->TypeBits.isCacheValid() &&
- T->TypeBits.getVisibility() == Result.getVisibility());
+ T->TypeBits.CacheValid = true;
T->TypeBits.CachedLinkage = Result.getLinkage();
T->TypeBits.CachedLocalOrUnnamed = Result.hasLocalOrUnnamedType();
}
@@ -2077,13 +2099,13 @@ static CachedProperties computeCachedProperties(const Type *T) {
#include "clang/AST/TypeNodes.def"
// Treat instantiation-dependent types as external.
assert(T->isInstantiationDependentType());
- return CachedProperties(NamedDecl::LinkageInfo(), false);
+ return CachedProperties(ExternalLinkage, 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(NamedDecl::LinkageInfo(), false);
+ return CachedProperties(ExternalLinkage, false);
case Type::Record:
case Type::Enum: {
@@ -2093,11 +2115,11 @@ static CachedProperties computeCachedProperties(const Type *T) {
// - it is a class or enumeration type that is named (or has a name
// for linkage purposes (7.1.3)) and the name has linkage; or
// - it is a specialization of a class template (14); or
- NamedDecl::LinkageInfo LV = Tag->getLinkageAndVisibility();
+ Linkage L = Tag->getLinkage();
bool IsLocalOrUnnamed =
Tag->getDeclContext()->isFunctionOrMethod() ||
- (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl());
- return CachedProperties(LV, IsLocalOrUnnamed);
+ !Tag->hasNameForLinkage();
+ return CachedProperties(L, IsLocalOrUnnamed);
}
// C++ [basic.link]p8:
@@ -2135,9 +2157,8 @@ static CachedProperties computeCachedProperties(const Type *T) {
return result;
}
case Type::ObjCInterface: {
- NamedDecl::LinkageInfo LV =
- cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility();
- return CachedProperties(LV, false);
+ Linkage L = cast<ObjCInterfaceType>(T)->getDecl()->getLinkage();
+ return CachedProperties(L, false);
}
case Type::ObjCObject:
return Cache::get(cast<ObjCObjectType>(T)->getBaseType());
@@ -2156,31 +2177,99 @@ Linkage Type::getLinkage() const {
return TypeBits.getLinkage();
}
-/// \brief Determine the linkage of this type.
-Visibility Type::getVisibility() const {
+bool Type::hasUnnamedOrLocalType() const {
Cache::ensure(this);
- return TypeBits.getVisibility();
+ return TypeBits.hasLocalOrUnnamedType();
}
-bool Type::isVisibilityExplicit() const {
- Cache::ensure(this);
- return TypeBits.isVisibilityExplicit();
+static LinkageInfo computeLinkageInfo(QualType T);
+
+static LinkageInfo computeLinkageInfo(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 instantiation-dependent types as external.
+ assert(T->isInstantiationDependentType());
+ return LinkageInfo::external();
+
+ case Type::Builtin:
+ return LinkageInfo::external();
+
+ case Type::Record:
+ case Type::Enum:
+ return cast<TagType>(T)->getDecl()->getLinkageAndVisibility();
+
+ case Type::Complex:
+ return computeLinkageInfo(cast<ComplexType>(T)->getElementType());
+ case Type::Pointer:
+ return computeLinkageInfo(cast<PointerType>(T)->getPointeeType());
+ case Type::BlockPointer:
+ return computeLinkageInfo(cast<BlockPointerType>(T)->getPointeeType());
+ case Type::LValueReference:
+ case Type::RValueReference:
+ return computeLinkageInfo(cast<ReferenceType>(T)->getPointeeType());
+ case Type::MemberPointer: {
+ const MemberPointerType *MPT = cast<MemberPointerType>(T);
+ LinkageInfo LV = computeLinkageInfo(MPT->getClass());
+ LV.merge(computeLinkageInfo(MPT->getPointeeType()));
+ return LV;
+ }
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ return computeLinkageInfo(cast<ArrayType>(T)->getElementType());
+ case Type::Vector:
+ case Type::ExtVector:
+ return computeLinkageInfo(cast<VectorType>(T)->getElementType());
+ case Type::FunctionNoProto:
+ return computeLinkageInfo(cast<FunctionType>(T)->getResultType());
+ case Type::FunctionProto: {
+ const FunctionProtoType *FPT = cast<FunctionProtoType>(T);
+ LinkageInfo LV = computeLinkageInfo(FPT->getResultType());
+ for (FunctionProtoType::arg_type_iterator ai = FPT->arg_type_begin(),
+ ae = FPT->arg_type_end(); ai != ae; ++ai)
+ LV.merge(computeLinkageInfo(*ai));
+ return LV;
+ }
+ case Type::ObjCInterface:
+ return cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility();
+ case Type::ObjCObject:
+ return computeLinkageInfo(cast<ObjCObjectType>(T)->getBaseType());
+ case Type::ObjCObjectPointer:
+ return computeLinkageInfo(cast<ObjCObjectPointerType>(T)->getPointeeType());
+ case Type::Atomic:
+ return computeLinkageInfo(cast<AtomicType>(T)->getValueType());
+ }
+
+ llvm_unreachable("unhandled type class");
}
-bool Type::hasUnnamedOrLocalType() const {
- Cache::ensure(this);
- return TypeBits.hasLocalOrUnnamedType();
+static LinkageInfo computeLinkageInfo(QualType T) {
+ return computeLinkageInfo(T.getTypePtr());
}
-std::pair<Linkage,Visibility> Type::getLinkageAndVisibility() const {
- Cache::ensure(this);
- return std::make_pair(TypeBits.getLinkage(), TypeBits.getVisibility());
+bool Type::isLinkageValid() const {
+ if (!TypeBits.isCacheValid())
+ return true;
+
+ return computeLinkageInfo(getCanonicalTypeInternal()).getLinkage() ==
+ TypeBits.getLinkage();
}
-void Type::ClearLinkageCache() {
- TypeBits.CacheValidAndVisibility = 0;
- if (QualType(this, 0) != CanonicalType)
- CanonicalType->TypeBits.CacheValidAndVisibility = 0;
+LinkageInfo Type::getLinkageAndVisibility() const {
+ if (!isCanonicalUnqualified())
+ return computeLinkageInfo(getCanonicalTypeInternal());
+
+ LinkageInfo LV = computeLinkageInfo(this);
+ assert(LV.getLinkage() == getLinkage());
+ return LV;
}
Qualifiers::ObjCLifetime Type::getObjCARCImplicitLifetime() const {
@@ -2296,25 +2385,3 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
return DK_none;
}
-
-bool QualType::hasTrivialAssignment(ASTContext &Context, bool Copying) const {
- switch (getObjCLifetime()) {
- case Qualifiers::OCL_None:
- break;
-
- case Qualifiers::OCL_ExplicitNone:
- return true;
-
- case Qualifiers::OCL_Autoreleasing:
- case Qualifiers::OCL_Strong:
- case Qualifiers::OCL_Weak:
- return !Context.getLangOpts().ObjCAutoRefCount;
- }
-
- if (const CXXRecordDecl *Record
- = getTypePtr()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl())
- return Copying ? Record->hasTrivialCopyAssignment() :
- Record->hasTrivialMoveAssignment();
-
- return true;
-}
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 58c4cbd00c8a..03d40309f53a 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -11,11 +11,12 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/Support/raw_ostream.h"
-#include "clang/AST/TypeLocVisitor.h"
+#include "clang/AST/TypeLoc.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/TypeLocVisitor.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -85,7 +86,7 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL,
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
case CLASS: { \
- CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \
+ CLASS##TypeLoc TLCasted = TL.castAs<CLASS##TypeLoc>(); \
TLCasted.initializeLocal(Context, Loc); \
TL = TLCasted.getNextTypeLoc(); \
if (!TL) return; \
@@ -105,7 +106,8 @@ SourceLocation TypeLoc::getBeginLoc() const {
LeftMost = Cur;
break;
case FunctionProto:
- if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) {
+ if (Cur.castAs<FunctionProtoTypeLoc>().getTypePtr()
+ ->hasTrailingReturn()) {
LeftMost = Cur;
break;
}
@@ -150,7 +152,7 @@ SourceLocation TypeLoc::getEndLoc() const {
Last = Cur;
break;
case FunctionProto:
- if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn())
+ if (Cur.castAs<FunctionProtoTypeLoc>().getTypePtr()->hasTrailingReturn())
Last = TypeLoc();
else
Last = Cur;
@@ -197,9 +199,9 @@ namespace {
/// because it's a convenient base class. Ideally we would not accept
/// those here, but ideally we would have better implementations for
/// them.
-bool TypeSpecTypeLoc::classof(const TypeLoc *TL) {
- if (TL->getType().hasLocalQualifiers()) return false;
- return TSTChecker().Visit(*TL);
+bool TypeSpecTypeLoc::isKind(const TypeLoc &TL) {
+ if (TL.getType().hasLocalQualifiers()) return false;
+ return TSTChecker().Visit(TL);
}
// Reimplemented to account for GNU/C++ extension
@@ -261,6 +263,14 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
case BuiltinType::ObjCSel:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
case BuiltinType::BuiltinFn:
return TST_unspecified;
}
@@ -269,8 +279,8 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
}
TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) {
- while (ParenTypeLoc* PTL = dyn_cast<ParenTypeLoc>(&TL))
- TL = PTL->getInnerLoc();
+ while (ParenTypeLoc PTL = TL.getAs<ParenTypeLoc>())
+ TL = PTL.getInnerLoc();
return TL;
}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index 90b2ca9cce15..9d1717a220cd 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -11,19 +11,19 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/PrettyPrinter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
-#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
@@ -647,6 +647,9 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T,
case CC_PnaclCall:
OS << " __attribute__((pnaclcall))";
break;
+ case CC_IntelOclBicc:
+ OS << " __attribute__((intel_ocl_bicc))";
+ break;
}
if (Info.getNoReturn())
OS << " __attribute__((noreturn))";
@@ -1168,6 +1171,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
break;
}
case AttributedType::attr_pnaclcall: OS << "pnaclcall"; break;
+ case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break;
}
OS << "))";
}
@@ -1344,132 +1348,6 @@ PrintTemplateArgumentList(raw_ostream &OS,
OS << '>';
}
-void
-FunctionProtoType::printExceptionSpecification(std::string &S,
- const PrintingPolicy &Policy)
- const {
-
- if (hasDynamicExceptionSpec()) {
- S += " throw(";
- if (getExceptionSpecType() == EST_MSAny)
- S += "...";
- else
- for (unsigned I = 0, N = getNumExceptions(); I != N; ++I) {
- if (I)
- S += ", ";
-
- S += getExceptionType(I).getAsString(Policy);
- }
- S += ")";
- } else if (isNoexceptExceptionSpec(getExceptionSpecType())) {
- S += " noexcept";
- if (getExceptionSpecType() == EST_ComputedNoexcept) {
- S += "(";
- llvm::raw_string_ostream EOut(S);
- getNoexceptExpr()->printPretty(EOut, 0, Policy);
- EOut.flush();
- S += EOut.str();
- S += ")";
- }
- }
-}
-
-std::string TemplateSpecializationType::
- PrintTemplateArgumentList(const TemplateArgumentListInfo &Args,
- const PrintingPolicy &Policy) {
- return PrintTemplateArgumentList(Args.getArgumentArray(),
- Args.size(),
- Policy);
-}
-
-std::string
-TemplateSpecializationType::PrintTemplateArgumentList(
- const TemplateArgument *Args,
- unsigned NumArgs,
- const PrintingPolicy &Policy,
- bool SkipBrackets) {
- std::string SpecString;
- if (!SkipBrackets)
- SpecString += '<';
-
- for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (SpecString.size() > unsigned(!SkipBrackets))
- SpecString += ", ";
-
- // Print the argument into a string.
- std::string ArgString;
- 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 '<:'.
- if (!Arg && !ArgString.empty() && ArgString[0] == ':')
- SpecString += ' ';
-
- SpecString += ArgString;
- }
-
- // 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.empty() && SpecString[SpecString.size() - 1] == '>')
- SpecString += ' ';
-
- if (!SkipBrackets)
- SpecString += '>';
-
- return SpecString;
-}
-
-// Sadly, repeat all that with TemplateArgLoc.
-std::string TemplateSpecializationType::
-PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs,
- const PrintingPolicy &Policy) {
- std::string SpecString;
- SpecString += '<';
- for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (SpecString.size() > 1)
- SpecString += ", ";
-
- // Print the argument into a string.
- std::string ArgString;
- 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
- // to avoid printing the diagraph '<:'.
- if (!Arg && !ArgString.empty() && ArgString[0] == ':')
- SpecString += ' ';
-
- SpecString += ArgString;
- }
-
- // 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] == '>')
- SpecString += ' ';
-
- SpecString += '>';
-
- return SpecString;
-}
-
void QualType::dump(const char *msg) const {
if (msg)
llvm::errs() << msg << ": ";
@@ -1599,11 +1477,7 @@ void QualType::print(const Type *ty, Qualifiers qs,
raw_ostream &OS, const PrintingPolicy &policy,
const Twine &PlaceHolder) {
SmallString<128> PHBuf;
- StringRef PH;
- if (PlaceHolder.isSingleStringRef())
- PH = PlaceHolder.getSingleStringRef();
- else
- PH = PlaceHolder.toStringRef(PHBuf);
+ StringRef PH = PlaceHolder.toStringRef(PHBuf);
TypePrinter(policy).print(ty, qs, OS, PH);
}
diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp
index 33dad40c0c50..f80232f44c98 100644
--- a/lib/AST/VTableBuilder.cpp
+++ b/lib/AST/VTableBuilder.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstdio>
@@ -256,11 +257,9 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context,
const CXXRecordDecl *DerivedRD) {
CXXBasePaths Paths(/*FindAmbiguities=*/false,
/*RecordPaths=*/true, /*DetectVirtual=*/false);
-
- if (!const_cast<CXXRecordDecl *>(DerivedRD)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+
+ if (!DerivedRD->isDerivedFrom(BaseRD, Paths))
llvm_unreachable("Class must be derived from the passed in base class!");
- }
return ComputeBaseOffset(Context, DerivedRD, Paths.front());
}
@@ -1001,6 +1000,10 @@ public:
dumpLayout(llvm::errs());
}
+ bool isMicrosoftABI() const {
+ return VTables.isMicrosoftABI();
+ }
+
uint64_t getNumThunks() const {
return Thunks.size();
}
@@ -1157,6 +1160,8 @@ void VTableBuilder::ComputeThisAdjustments() {
break;
case VTableComponent::CK_DeletingDtorPointer:
// We've already added the thunk when we saw the complete dtor pointer.
+ // FIXME: check how this works in the Microsoft ABI
+ // while working on the multiple inheritance patch.
continue;
}
@@ -1197,10 +1202,8 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base,
CXXBasePaths Paths(/*FindAmbiguities=*/true,
/*RecordPaths=*/true, /*DetectVirtual=*/true);
- if (!const_cast<CXXRecordDecl *>(DerivedRD)->
- isDerivedFrom(const_cast<CXXRecordDecl *>(BaseRD), Paths)) {
+ if (!DerivedRD->isDerivedFrom(BaseRD, Paths))
llvm_unreachable("Class must be derived from the passed in base class!");
- }
// We have to go through all the paths, and see which one leads us to the
// right base subobject.
@@ -1295,9 +1298,15 @@ VTableBuilder::AddMethod(const CXXMethodDecl *MD,
assert(ReturnAdjustment.isEmpty() &&
"Destructor can't have return adjustment!");
- // Add both the complete destructor and the deleting destructor.
- Components.push_back(VTableComponent::MakeCompleteDtor(DD));
- Components.push_back(VTableComponent::MakeDeletingDtor(DD));
+ // FIXME: Should probably add a layer of abstraction for vtable generation.
+ if (!isMicrosoftABI()) {
+ // Add both the complete destructor and the deleting destructor.
+ Components.push_back(VTableComponent::MakeCompleteDtor(DD));
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
+ } else {
+ // Add the scalar deleting destructor.
+ Components.push_back(VTableComponent::MakeDeletingDtor(DD));
+ }
} else {
// Add the return adjustment if necessary.
if (!ReturnAdjustment.isEmpty())
@@ -1612,14 +1621,19 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base,
if (Base.getBase() == MostDerivedClass)
VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets();
- // Add the offset to top.
- CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
- Components.push_back(
- VTableComponent::MakeOffsetToTop(OffsetToTop));
-
- // Next, add the RTTI.
- Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
-
+ // FIXME: Should probably add a layer of abstraction for vtable generation.
+ if (!isMicrosoftABI()) {
+ // Add the offset to top.
+ CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass;
+ Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop));
+
+ // Next, add the RTTI.
+ Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
+ } else {
+ // FIXME: unclear what to do with RTTI in MS ABI as emitting it anywhere
+ // breaks the vftable layout. Just skip RTTI for now, can't mangle anyway.
+ }
+
uint64_t AddressPoint = Components.size();
// Now go through all virtual member functions and add them.
@@ -1936,6 +1950,8 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
Out << DD->getQualifiedNameAsString();
if (IsComplete)
Out << "() [complete]";
+ else if (isMicrosoftABI())
+ Out << "() [scalar deleting]";
else
Out << "() [deleting]";
@@ -2120,10 +2136,16 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) {
MD);
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] =
- MethodName + " [complete]";
- IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] =
- MethodName + " [deleting]";
+ // FIXME: Should add a layer of abstraction for vtable generation.
+ if (!isMicrosoftABI()) {
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))]
+ = MethodName + " [complete]";
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
+ = MethodName + " [deleting]";
+ } else {
+ IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))]
+ = MethodName + " [scalar deleting]";
+ }
} else {
IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName;
}
@@ -2154,12 +2176,14 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
const VTableComponent *VTableComponents,
uint64_t NumVTableThunks,
const VTableThunkTy *VTableThunks,
- const AddressPointsMapTy &AddressPoints)
+ const AddressPointsMapTy &AddressPoints,
+ bool IsMicrosoftABI)
: NumVTableComponents(NumVTableComponents),
VTableComponents(new VTableComponent[NumVTableComponents]),
NumVTableThunks(NumVTableThunks),
VTableThunks(new VTableThunkTy[NumVTableThunks]),
- AddressPoints(AddressPoints) {
+ AddressPoints(AddressPoints),
+ IsMicrosoftABI(IsMicrosoftABI) {
std::copy(VTableComponents, VTableComponents+NumVTableComponents,
this->VTableComponents.get());
std::copy(VTableThunks, VTableThunks+NumVTableThunks,
@@ -2168,6 +2192,11 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
VTableLayout::~VTableLayout() { }
+VTableContext::VTableContext(ASTContext &Context)
+ : Context(Context),
+ IsMicrosoftABI(Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+}
+
VTableContext::~VTableContext() {
llvm::DeleteContainerSeconds(VTableLayouts);
}
@@ -2239,12 +2268,18 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
const CXXDestructorDecl *OverriddenDD =
cast<CXXDestructorDecl>(OverriddenMD);
-
- // Add both the complete and deleting entries.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
- getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+
+ if (!isMicrosoftABI()) {
+ // Add both the complete and deleting entries.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ } else {
+ // Add the scalar deleting destructor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVTableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ }
} else {
MethodVTableIndices[MD] = getMethodVTableIndex(OverriddenMD);
}
@@ -2262,11 +2297,16 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
continue;
}
- // Add the complete dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
-
- // Add the deleting dtor.
- MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ if (!isMicrosoftABI()) {
+ // Add the complete dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
+
+ // Add the deleting dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ } else {
+ // Add the scalar deleting dtor.
+ MethodVTableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ }
} else {
// Add the entry.
MethodVTableIndices[MD] = CurrentIndex++;
@@ -2278,6 +2318,11 @@ void VTableContext::ComputeMethodVTableIndices(const CXXRecordDecl *RD) {
// If a class has an implicitly-defined virtual destructor,
// its entries come after the declared virtual function pointers.
+ if (isMicrosoftABI()) {
+ ErrorUnsupported("implicit virtual destructor in the Microsoft ABI",
+ ImplicitVirtualDtor->getLocation());
+ }
+
// Add the complete dtor.
MethodVTableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
CurrentIndex++;
@@ -2357,7 +2402,8 @@ static VTableLayout *CreateVTableLayout(const VTableBuilder &Builder) {
Builder.vtable_component_begin(),
VTableThunks.size(),
VTableThunks.data(),
- Builder.getAddressPoints());
+ Builder.getAddressPoints(),
+ Builder.isMicrosoftABI());
}
void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
@@ -2397,6 +2443,14 @@ void VTableContext::ComputeVTableRelatedInformation(const CXXRecordDecl *RD) {
}
}
+void VTableContext::ErrorUnsupported(StringRef Feature,
+ SourceLocation Location) {
+ clang::DiagnosticsEngine &Diags = Context.getDiagnostics();
+ unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
+ "v-table layout for %0 is not supported yet");
+ Diags.Report(Context.getFullLoc(Location), DiagID) << Feature;
+}
+
VTableLayout *VTableContext::createConstructionVTableLayout(
const CXXRecordDecl *MostDerivedClass,
CharUnits MostDerivedClassOffset,