diff options
author | dim <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2012-12-02 13:20:44 +0000 |
commit | 056abd2059c65a3e908193aeae16fad98017437c (patch) | |
tree | 2732d02d7d51218d6eed98ac7fcfc5b8794896b5 /lib/AST | |
parent | cc73504950eb7b5dff2dded9bedd67bc36d64641 (diff) | |
download | FreeBSD-src-056abd2059c65a3e908193aeae16fad98017437c.zip FreeBSD-src-056abd2059c65a3e908193aeae16fad98017437c.tar.gz |
Vendor import of clang release_32 branch r168974 (effectively, 3.2 RC2):
http://llvm.org/svn/llvm-project/cfe/branches/release_32@168974
Diffstat (limited to 'lib/AST')
39 files changed, 2855 insertions, 1198 deletions
diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp index 1672bc8..a4e17c0 100644 --- a/lib/AST/ASTConsumer.cpp +++ b/lib/AST/ASTConsumer.cpp @@ -13,6 +13,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclGroup.h" +#include "clang/AST/Decl.h" using namespace clang; bool ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) { @@ -24,3 +25,7 @@ void ASTConsumer::HandleInterestingDecl(DeclGroupRef D) { } void ASTConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {} + +void ASTConsumer::HandleImplicitImportDecl(ImportDecl *D) { + HandleTopLevelDecl(DeclGroupRef(D)); +} diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c021323..74c68ae 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -24,6 +24,7 @@ #include "clang/AST/ASTMutationListener.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Mangle.h" +#include "clang/AST/Comment.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -72,6 +73,22 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { return NULL; } + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->isStaticDataMember() && + VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) + return NULL; + } + + if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) { + if (CRD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) + return NULL; + } + + if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) { + if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) + return NULL; + } + // TODO: handle comments for function parameters properly. if (isa<ParmVarDecl>(D)) return NULL; @@ -196,15 +213,72 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { namespace { /// If we have a 'templated' declaration for a template, adjust 'D' to /// refer to the actual template. +/// If we have an implicit instantiation, adjust 'D' to refer to template. const Decl *adjustDeclToTemplate(const Decl *D) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // Is this function declaration part of a function template? if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) - D = FTD; - } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { - if (const ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) - D = CTD; + return FTD; + + // Nothing to do if function is not an implicit instantiation. + if (FD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) + return D; + + // Function is an implicit instantiation of a function template? + if (const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) + return FTD; + + // Function is instantiated from a member definition of a class template? + if (const FunctionDecl *MemberDecl = + FD->getInstantiatedFromMemberFunction()) + return MemberDecl; + + return D; } - // FIXME: Alias templates? + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + // Static data member is instantiated from a member definition of a class + // template? + if (VD->isStaticDataMember()) + if (const VarDecl *MemberDecl = VD->getInstantiatedFromStaticDataMember()) + return MemberDecl; + + return D; + } + if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) { + // Is this class declaration part of a class template? + if (const ClassTemplateDecl *CTD = CRD->getDescribedClassTemplate()) + return CTD; + + // Class is an implicit instantiation of a class template or partial + // specialization? + if (const ClassTemplateSpecializationDecl *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(CRD)) { + if (CTSD->getSpecializationKind() != TSK_ImplicitInstantiation) + return D; + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + PU = CTSD->getSpecializedTemplateOrPartial(); + return PU.is<ClassTemplateDecl*>() ? + static_cast<const Decl*>(PU.get<ClassTemplateDecl *>()) : + static_cast<const Decl*>( + PU.get<ClassTemplatePartialSpecializationDecl *>()); + } + + // Class is instantiated from a member definition of a class template? + if (const MemberSpecializationInfo *Info = + CRD->getMemberSpecializationInfo()) + return Info->getInstantiatedFrom(); + + return D; + } + if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) { + // Enum is instantiated from a member definition of a class template? + if (const EnumDecl *MemberDecl = ED->getInstantiatedFromMemberEnum()) + return MemberDecl; + + return D; + } + // FIXME: Adjust alias templates? return D; } } // unnamed namespace @@ -282,23 +356,83 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl( return RC; } -comments::FullComment *ASTContext::getCommentForDecl(const Decl *D) const { +static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod, + SmallVectorImpl<const NamedDecl *> &Redeclared) { + const DeclContext *DC = ObjCMethod->getDeclContext(); + if (const ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(DC)) { + const ObjCInterfaceDecl *ID = IMD->getClassInterface(); + if (!ID) + return; + // Add redeclared method here. + for (const ObjCCategoryDecl *ClsExtDecl = ID->getFirstClassExtension(); + ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) { + if (ObjCMethodDecl *RedeclaredMethod = + ClsExtDecl->getMethod(ObjCMethod->getSelector(), + ObjCMethod->isInstanceMethod())) + Redeclared.push_back(RedeclaredMethod); + } + } +} + +comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC, + const Decl *D) const { + comments::DeclInfo *ThisDeclInfo = new (*this) comments::DeclInfo; + ThisDeclInfo->CommentDecl = D; + ThisDeclInfo->IsFilled = false; + ThisDeclInfo->fill(); + ThisDeclInfo->CommentDecl = FC->getDecl(); + comments::FullComment *CFC = + new (*this) comments::FullComment(FC->getBlocks(), + ThisDeclInfo); + return CFC; + +} + +comments::FullComment *ASTContext::getCommentForDecl( + const Decl *D, + const Preprocessor *PP) const { D = adjustDeclToTemplate(D); + const Decl *Canonical = D->getCanonicalDecl(); llvm::DenseMap<const Decl *, comments::FullComment *>::iterator Pos = ParsedComments.find(Canonical); - if (Pos != ParsedComments.end()) + + if (Pos != ParsedComments.end()) { + if (Canonical != D) { + comments::FullComment *FC = Pos->second; + comments::FullComment *CFC = cloneFullComment(FC, D); + return CFC; + } return Pos->second; - + } + const Decl *OriginalDecl; + const RawComment *RC = getRawCommentForAnyRedecl(D, &OriginalDecl); - if (!RC) + if (!RC) { + if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) { + SmallVector<const NamedDecl*, 8> Overridden; + if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) + 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; + } + } + } return NULL; - + } + + // If the RawComment was attached to other redeclaration of this Decl, we + // should parse the comment in context of that other Decl. This is important + // because comments can contain references to parameter names which can be + // different across redeclarations. if (D != OriginalDecl) - return getCommentForDecl(OriginalDecl); + return getCommentForDecl(OriginalDecl, PP); - comments::FullComment *FC = RC->parse(*this, D); + comments::FullComment *FC = RC->parse(*this, PP, D); ParsedComments[Canonical] = FC; return FC; } @@ -481,6 +615,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, Int128Decl(0), UInt128Decl(0), BuiltinVaListDecl(0), ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0), + BOOLDecl(0), CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), sigjmp_bufDecl(0), ucontext_tDecl(0), @@ -495,6 +630,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, DeclarationNames(*this), ExternalSource(0), Listener(0), Comments(SM), CommentsLoaded(false), + CommentCommandTraits(BumpAlloc), LastSDM(0, 0), UniqueBlockByRefTypeID(0) { @@ -683,12 +819,12 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { InitBuiltinType(Int128Ty, BuiltinType::Int128); InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); - if (LangOpts.CPlusPlus) { // C++ 3.9.1p5 + if (LangOpts.CPlusPlus && LangOpts.WChar) { // C++ 3.9.1p5 if (TargetInfo::isTypeSigned(Target.getWCharType())) InitBuiltinType(WCharTy, BuiltinType::WChar_S); else // -fshort-wchar makes wchar_t be unsigned. InitBuiltinType(WCharTy, BuiltinType::WChar_U); - } else // C99 + } else // C99 (or C++ using -fno-wchar) WCharTy = getFromTargetType(Target.getWCharType()); WIntTy = getFromTargetType(Target.getWIntType()); @@ -725,6 +861,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { // Placeholder type for unbridged ARC casts. InitBuiltinType(ARCUnbridgedCastTy, BuiltinType::ARCUnbridgedCast); + // Placeholder type for builtin functions. + InitBuiltinType(BuiltinFnTy, BuiltinType::BuiltinFn); + // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); DoubleComplexTy = getComplexType(DoubleTy); @@ -909,7 +1048,7 @@ bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD, ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos - = OverriddenMethods.find(Method); + = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return 0; @@ -919,7 +1058,7 @@ ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos - = OverriddenMethods.find(Method); + = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return 0; @@ -929,7 +1068,7 @@ ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const { unsigned ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos - = OverriddenMethods.find(Method); + = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return 0; @@ -938,9 +1077,30 @@ ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const { void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method, const CXXMethodDecl *Overridden) { + assert(Method->isCanonicalDecl() && Overridden->isCanonicalDecl()); OverriddenMethods[Method].push_back(Overridden); } +void ASTContext::getOverriddenMethods( + const NamedDecl *D, + SmallVectorImpl<const NamedDecl *> &Overridden) const { + assert(D); + + if (const CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) { + Overridden.append(CXXMethod->begin_overridden_methods(), + CXXMethod->end_overridden_methods()); + return; + } + + const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D); + if (!Method) + return; + + SmallVector<const ObjCMethodDecl *, 8> OverDecls; + Method->getOverriddenMethods(OverDecls); + Overridden.append(OverDecls.begin(), OverDecls.end()); +} + void ASTContext::addedLocalImportDecl(ImportDecl *Import) { assert(!Import->NextLocalImport && "Import declaration already in the chain"); assert(!Import->isFromASTFile() && "Non-local import declaration"); @@ -1062,6 +1222,27 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { return toCharUnitsFromBits(Align); } +// getTypeInfoDataSizeInChars - Return the size of a type, in +// chars. If the type is a record, its data size is returned. This is +// the size of the memcpy that's performed when assigning this type +// using a trivial copy/move assignment operator. +std::pair<CharUnits, CharUnits> +ASTContext::getTypeInfoDataSizeInChars(QualType T) const { + std::pair<CharUnits, CharUnits> sizeAndAlign = getTypeInfoInChars(T); + + // In C++, objects can sometimes be allocated into the tail padding + // of a base-class subobject. We decide whether that's possible + // during class layout, so here we can just trust the layout results. + if (getLangOpts().CPlusPlus) { + if (const RecordType *RT = T->getAs<RecordType>()) { + const ASTRecordLayout &layout = getASTRecordLayout(RT->getDecl()); + sizeAndAlign.first = layout.getDataSize(); + } + } + + return sizeAndAlign; +} + std::pair<CharUnits, CharUnits> ASTContext::getTypeInfoInChars(const Type *T) const { std::pair<uint64_t, unsigned> Info = getTypeInfo(T); @@ -3353,6 +3534,12 @@ QualType ASTContext::getPointerDiffType() const { return getFromTargetType(Target->getPtrDiffType(0)); } +/// \brief Return the unique type for "pid_t" defined in +/// <sys/types.h>. We need this to compute the correct type for vfork(). +QualType ASTContext::getProcessIDType() const { + return getFromTargetType(Target->getProcessIDType()); +} + //===----------------------------------------------------------------------===// // Type Operators //===----------------------------------------------------------------------===// @@ -3581,11 +3768,14 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { return Arg; case TemplateArgument::Declaration: { - if (Decl *D = Arg.getAsDecl()) - return TemplateArgument(D->getCanonicalDecl()); - return TemplateArgument((Decl*)0); + ValueDecl *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl()); + return TemplateArgument(D, Arg.isDeclForReferenceParam()); } + case TemplateArgument::NullPtr: + return TemplateArgument(getCanonicalType(Arg.getNullPtrType()), + /*isNullPtr*/true); + case TemplateArgument::Template: return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate())); @@ -4297,7 +4487,13 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { QualType BlockTy = Expr->getType()->getAs<BlockPointerType>()->getPointeeType(); // Encode result type. - getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getResultType(), S); + if (getLangOpts().EncodeExtendedBlockSig) + getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None, + BlockTy->getAs<FunctionType>()->getResultType(), + S, true /*Extended*/); + else + getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getResultType(), + S); // Compute size of all parameters. // Start with computing size of a pointer in number of bytes. // FIXME: There might(should) be a better way of doing this computation! @@ -4332,7 +4528,11 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { PType = PVDecl->getType(); } else if (PType->isFunctionType()) PType = PVDecl->getType(); - getObjCEncodingForType(PType, S); + if (getLangOpts().EncodeExtendedBlockSig) + getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None, PType, + S, true /*Extended*/); + else + getObjCEncodingForType(PType, S); S += charUnitsToString(ParmOffset); ParmOffset += getObjCEncodingTypeSize(PType); } @@ -5393,6 +5593,65 @@ static TypedefDecl *CreatePNaClABIBuiltinVaListDecl(const ASTContext *Context) { return VaListTypedefDecl; } +static TypedefDecl * +CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) { + RecordDecl *VaListDecl; + 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); + + VaListDecl = CXXRecordDecl::Create(*Context, TTK_Struct, + Context->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Context->Idents.get("__va_list")); + + VaListDecl->setDeclContext(NS); + + } else { + // struct __va_list { + VaListDecl = CreateRecordDecl(*Context, TTK_Struct, + Context->getTranslationUnitDecl(), + &Context->Idents.get("__va_list")); + } + + VaListDecl->startDefinition(); + + // void * __ap; + FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context), + VaListDecl, + SourceLocation(), + SourceLocation(), + &Context->Idents.get("__ap"), + Context->getPointerType(Context->VoidTy), + /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + ICIS_NoInit); + Field->setAccess(AS_public); + VaListDecl->addDecl(Field); + + // }; + VaListDecl->completeDefinition(); + + // typedef struct __va_list __builtin_va_list; + TypeSourceInfo *TInfo + = Context->getTrivialTypeSourceInfo(Context->getRecordType(VaListDecl)); + + TypedefDecl *VaListTypeDecl + = TypedefDecl::Create(const_cast<ASTContext &>(*Context), + Context->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Context->Idents.get("__builtin_va_list"), + TInfo); + + return VaListTypeDecl; +} + static TypedefDecl *CreateVaListDecl(const ASTContext *Context, TargetInfo::BuiltinVaListKind Kind) { switch (Kind) { @@ -5406,6 +5665,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context, return CreateX86_64ABIBuiltinVaListDecl(Context); case TargetInfo::PNaClABIBuiltinVaList: return CreatePNaClABIBuiltinVaListDecl(Context); + case TargetInfo::AAPCSABIBuiltinVaList: + return CreateAAPCSABIBuiltinVaListDecl(Context); } llvm_unreachable("Unhandled __builtin_va_list type kind"); @@ -5702,7 +5963,7 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, return false; } -/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...> +/// QualifiedIdConformsQualifiedId - compare id<pr,...> with id<pr1,...> /// return true if lhs's protocols conform to rhs's protocol; false /// otherwise. bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { @@ -5711,8 +5972,8 @@ bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { return false; } -/// ObjCQualifiedClassTypesAreCompatible - compare Class<p,...> and -/// Class<p1, ...>. +/// ObjCQualifiedClassTypesAreCompatible - compare Class<pr,...> and +/// Class<pr1, ...>. bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs, QualType rhs) { const ObjCObjectPointerType *lhsQID = lhs->getAs<ObjCObjectPointerType>(); @@ -6315,10 +6576,13 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, for (unsigned i = 0; i < proto_nargs; ++i) { QualType argTy = proto->getArgType(i); - // Look at the promotion type of enum types, since that is the type used + // Look at the converted type of enum types, since that is the type used // to pass enum values. - if (const EnumType *Enum = argTy->getAs<EnumType>()) - argTy = Enum->getDecl()->getPromotionType(); + if (const EnumType *Enum = argTy->getAs<EnumType>()) { + argTy = Enum->getDecl()->getIntegerType(); + if (argTy.isNull()) + return QualType(); + } if (argTy->isPromotableIntegerType() || getCanonicalType(argTy).getUnqualifiedType() == FloatTy) @@ -6725,7 +6989,7 @@ unsigned ASTContext::getIntWidth(QualType T) const { return (unsigned)getTypeSize(T); } -QualType ASTContext::getCorrespondingUnsignedType(QualType T) { +QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { assert(T->hasSignedIntegerRepresentation() && "Unexpected type"); // Turn <4 x signed int> -> <4 x unsigned int> @@ -6959,6 +7223,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, return QualType(); } break; + case 'p': + Type = Context.getProcessIDType(); + break; } // If there are modifiers and if we're allowed to parse them, go for it. diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index a605f1a..0b9c524 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -430,6 +430,15 @@ class TemplateDiff { /// arguments or the type arguments that are templates. TemplateDecl *FromTD, *ToTD; + /// FromQual, ToQual - Qualifiers for template types. + Qualifiers FromQual, ToQual; + + /// FromInt, ToInt - APSInt's for integral arguments. + llvm::APSInt FromInt, ToInt; + + /// IsValidFromInt, IsValidToInt - Whether the APSInt's are valid. + bool IsValidFromInt, IsValidToInt; + /// FromDefault, ToDefault - Whether the argument is a default argument. bool FromDefault, ToDefault; @@ -480,6 +489,21 @@ class TemplateDiff { FlatTree[CurrentNode].ToExpr = ToExpr; } + /// SetNode - Set FromInt and ToInt of the current node. + void SetNode(llvm::APSInt FromInt, llvm::APSInt ToInt, + bool IsValidFromInt, bool IsValidToInt) { + FlatTree[CurrentNode].FromInt = FromInt; + FlatTree[CurrentNode].ToInt = ToInt; + FlatTree[CurrentNode].IsValidFromInt = IsValidFromInt; + FlatTree[CurrentNode].IsValidToInt = IsValidToInt; + } + + /// SetNode - Set FromQual and ToQual of the current node. + void SetNode(Qualifiers FromQual, Qualifiers ToQual) { + FlatTree[CurrentNode].FromQual = FromQual; + FlatTree[CurrentNode].ToQual = ToQual; + } + /// SetSame - Sets the same flag of the current node. void SetSame(bool Same) { FlatTree[CurrentNode].Same = Same; @@ -557,6 +581,12 @@ class TemplateDiff { (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; @@ -575,6 +605,21 @@ class TemplateDiff { ToTD = FlatTree[ReadNode].ToTD; } + /// GetNode - Gets the FromInt and ToInt. + void GetNode(llvm::APSInt &FromInt, llvm::APSInt &ToInt, + bool &IsValidFromInt, bool &IsValidToInt) { + FromInt = FlatTree[ReadNode].FromInt; + ToInt = FlatTree[ReadNode].ToInt; + IsValidFromInt = FlatTree[ReadNode].IsValidFromInt; + IsValidToInt = FlatTree[ReadNode].IsValidToInt; + } + + /// GetNode - Gets the FromQual and ToQual. + void GetNode(Qualifiers &FromQual, Qualifiers &ToQual) { + FromQual = FlatTree[ReadNode].FromQual; + ToQual = FlatTree[ReadNode].ToQual; + } + /// NodeIsSame - Returns true the arguments are the same. bool NodeIsSame() { return FlatTree[ReadNode].Same; @@ -778,18 +823,21 @@ class TemplateDiff { if (Context.hasSameType(FromType, ToType)) { Tree.SetSame(true); } else { + Qualifiers FromQual = FromType.getQualifiers(), + ToQual = ToType.getQualifiers(); const TemplateSpecializationType *FromArgTST = GetTemplateSpecializationType(Context, FromType); const TemplateSpecializationType *ToArgTST = GetTemplateSpecializationType(Context, ToType); - if (FromArgTST && ToArgTST) { - bool SameTemplate = hasSameTemplate(FromArgTST, ToArgTST); - if (SameTemplate) { - Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(), - ToArgTST->getTemplateName().getAsTemplateDecl()); - DiffTemplate(FromArgTST, ToArgTST); - } + if (FromArgTST && ToArgTST && + hasSameTemplate(FromArgTST, ToArgTST)) { + FromQual -= QualType(FromArgTST, 0).getQualifiers(); + ToQual -= QualType(ToArgTST, 0).getQualifiers(); + Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(), + ToArgTST->getTemplateName().getAsTemplateDecl()); + Tree.SetNode(FromQual, ToQual); + DiffTemplate(FromArgTST, ToArgTST); } } } @@ -799,12 +847,41 @@ class TemplateDiff { if (NonTypeTemplateParmDecl *DefaultNTTPD = dyn_cast<NonTypeTemplateParmDecl>(ParamND)) { Expr *FromExpr, *ToExpr; - GetExpr(FromIter, DefaultNTTPD, FromExpr); - GetExpr(ToIter, DefaultNTTPD, ToExpr); - Tree.SetNode(FromExpr, ToExpr); - Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr)); - Tree.SetDefault(FromIter.isEnd() && FromExpr, - ToIter.isEnd() && ToExpr); + llvm::APSInt FromInt, ToInt; + bool HasFromInt = !FromIter.isEnd() && + FromIter->getKind() == TemplateArgument::Integral; + bool HasToInt = !ToIter.isEnd() && + ToIter->getKind() == TemplateArgument::Integral; + //bool IsValidFromInt = false, IsValidToInt = false; + if (HasFromInt) + FromInt = FromIter->getAsIntegral(); + else + GetExpr(FromIter, DefaultNTTPD, FromExpr); + + if (HasToInt) + ToInt = ToIter->getAsIntegral(); + else + GetExpr(ToIter, DefaultNTTPD, ToExpr); + + if (!HasFromInt && !HasToInt) { + Tree.SetNode(FromExpr, ToExpr); + Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr)); + Tree.SetDefault(FromIter.isEnd() && FromExpr, + ToIter.isEnd() && ToExpr); + } else { + if (!HasFromInt && FromExpr) { + FromInt = FromExpr->EvaluateKnownConstInt(Context); + HasFromInt = true; + } + if (!HasToInt && ToExpr) { + ToInt = ToExpr->EvaluateKnownConstInt(Context); + HasToInt = true; + } + Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt); + Tree.SetSame(llvm::APSInt::isSameValue(FromInt, ToInt)); + Tree.SetDefault(FromIter.isEnd() && HasFromInt, + ToIter.isEnd() && HasToInt); + } } // Handle Templates @@ -824,6 +901,26 @@ class TemplateDiff { } } + /// makeTemplateList - Dump every template alias into the vector. + static void makeTemplateList( + SmallVector<const TemplateSpecializationType*, 1> &TemplateList, + const TemplateSpecializationType *TST) { + while (TST) { + TemplateList.push_back(TST); + if (!TST->isTypeAlias()) + return; + TST = TST->getAliasedType()->getAs<TemplateSpecializationType>(); + } + } + + /// hasSameBaseTemplate - Returns true when the base templates are the same, + /// 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(); + } + /// hasSameTemplate - Returns true if both types are specialized from the /// same template declaration. If they come from different template aliases, /// do a parallel ascension search to determine the highest template alias in @@ -831,49 +928,29 @@ class TemplateDiff { static bool hasSameTemplate(const TemplateSpecializationType *&FromTST, const TemplateSpecializationType *&ToTST) { // Check the top templates if they are the same. - if (FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() == - ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier()) + if (hasSameBaseTemplate(FromTST, ToTST)) return true; // Create vectors of template aliases. SmallVector<const TemplateSpecializationType*, 1> FromTemplateList, ToTemplateList; - const TemplateSpecializationType *TempToTST = ToTST, *TempFromTST = FromTST; - FromTemplateList.push_back(FromTST); - ToTemplateList.push_back(ToTST); - - // Dump every template alias into the vectors. - while (TempFromTST->isTypeAlias()) { - TempFromTST = - TempFromTST->getAliasedType()->getAs<TemplateSpecializationType>(); - if (!TempFromTST) - break; - FromTemplateList.push_back(TempFromTST); - } - while (TempToTST->isTypeAlias()) { - TempToTST = - TempToTST->getAliasedType()->getAs<TemplateSpecializationType>(); - if (!TempToTST) - break; - ToTemplateList.push_back(TempToTST); - } + makeTemplateList(FromTemplateList, FromTST); + makeTemplateList(ToTemplateList, ToTST); SmallVector<const TemplateSpecializationType*, 1>::reverse_iterator FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(), ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend(); // Check if the lowest template types are the same. If not, return. - if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() != - (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier()) + if (!hasSameBaseTemplate(*FromIter, *ToIter)) return false; // Begin searching up the template aliases. The bottom most template // matches so move up until one pair does not match. Use the template // right before that one. for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) { - if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() != - (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier()) + if (!hasSameBaseTemplate(*FromIter, *ToIter)) break; } @@ -923,7 +1000,9 @@ class TemplateDiff { bool isVariadic = DefaultTTPD->isParameterPack(); TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument(); - TemplateDecl *DefaultTD = TA.getAsTemplate().getAsTemplateDecl(); + TemplateDecl *DefaultTD = 0; + if (TA.getKind() != TemplateArgument::Null) + DefaultTD = TA.getAsTemplate().getAsTemplateDecl(); if (!Iter.isEnd()) ArgDecl = Iter->getAsTemplate().getAsTemplateDecl(); @@ -1018,6 +1097,15 @@ class TemplateDiff { Tree.ToDefault(), Tree.NodeIsSame()); return; } + + if (Tree.NodeIsAPSInt()) { + llvm::APSInt FromInt, ToInt; + bool IsValidFromInt, IsValidToInt; + Tree.GetNode(FromInt, ToInt, IsValidFromInt, IsValidToInt); + PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt, + Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); + return; + } llvm_unreachable("Unable to deduce template difference."); } @@ -1027,6 +1115,10 @@ class TemplateDiff { assert(Tree.HasChildren() && "Template difference not found in diff tree."); + Qualifiers FromQual, ToQual; + Tree.GetNode(FromQual, ToQual); + PrintQualifiers(FromQual, ToQual); + OS << FromTD->getNameAsString() << '<'; Tree.MoveToChild(); unsigned NumElideArgs = 0; @@ -1088,6 +1180,17 @@ class TemplateDiff { return; } + if (!FromType.isNull() && !ToType.isNull() && + FromType.getLocalUnqualifiedType() == + ToType.getLocalUnqualifiedType()) { + Qualifiers FromQual = FromType.getLocalQualifiers(), + ToQual = ToType.getLocalQualifiers(), + CommonQual; + PrintQualifiers(FromQual, ToQual); + FromType.getLocalUnqualifiedType().print(OS, Policy); + return; + } + std::string FromTypeStr = FromType.isNull() ? "(no argument)" : FromType.getAsString(); std::string ToTypeStr = ToType.isNull() ? "(no argument)" @@ -1177,6 +1280,34 @@ 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) { + assert((IsValidFromInt || IsValidToInt) && + "Only one integral argument may be missing."); + + if (Same) { + OS << FromInt.toString(10); + } else if (!PrintTree) { + OS << (FromDefault ? "(default) " : ""); + Bold(); + OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)"); + Unbold(); + } else { + OS << (FromDefault ? "[(default) " : "["); + Bold(); + OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)"); + Unbold(); + OS << " != " << (ToDefault ? "(default) " : ""); + Bold(); + OS << (IsValidToInt ? ToInt.toString(10) : "(no argument)"); + Unbold(); + OS << ']'; + } + } + // Prints the appropriate placeholder for elided template arguments. void PrintElideArgs(unsigned NumElideArgs, unsigned Indent) { if (PrintTree) { @@ -1191,6 +1322,68 @@ class TemplateDiff { OS << "[" << NumElideArgs << " * ...]"; } + // Prints and highlights differences in Qualifiers. + void PrintQualifiers(Qualifiers FromQual, Qualifiers ToQual) { + // Both types have no qualifiers + if (FromQual.empty() && ToQual.empty()) + return; + + // Both types have same qualifiers + if (FromQual == ToQual) { + PrintQualifier(FromQual, /*ApplyBold*/false); + return; + } + + // Find common qualifiers and strip them from FromQual and ToQual. + Qualifiers CommonQual = Qualifiers::removeCommonQualifiers(FromQual, + ToQual); + + // The qualifiers are printed before the template name. + // Inline printing: + // The common qualifiers are printed. Then, qualifiers only in this type + // are printed and highlighted. Finally, qualifiers only in the other + // type are printed and highlighted inside parentheses after "missing". + // Tree printing: + // Qualifiers are printed next to each other, inside brackets, and + // separated by "!=". The printing order is: + // common qualifiers, highlighted from qualifiers, "!=", + // common qualifiers, highlighted to qualifiers + if (PrintTree) { + OS << "["; + if (CommonQual.empty() && FromQual.empty()) { + Bold(); + OS << "(no qualifiers) "; + Unbold(); + } else { + PrintQualifier(CommonQual, /*ApplyBold*/false); + PrintQualifier(FromQual, /*ApplyBold*/true); + } + OS << "!= "; + if (CommonQual.empty() && ToQual.empty()) { + Bold(); + OS << "(no qualifiers)"; + Unbold(); + } else { + PrintQualifier(CommonQual, /*ApplyBold*/false, + /*appendSpaceIfNonEmpty*/!ToQual.empty()); + PrintQualifier(ToQual, /*ApplyBold*/true, + /*appendSpaceIfNonEmpty*/false); + } + OS << "] "; + } else { + PrintQualifier(CommonQual, /*ApplyBold*/false); + PrintQualifier(FromQual, /*ApplyBold*/true); + } + } + + void PrintQualifier(Qualifiers Q, bool ApplyBold, + bool AppendSpaceIfNonEmpty = true) { + if (Q.empty()) return; + if (ApplyBold) Bold(); + Q.print(OS, Policy, AppendSpaceIfNonEmpty); + if (ApplyBold) Unbold(); + } + public: TemplateDiff(ASTContext &Context, QualType FromType, QualType ToType, @@ -1210,6 +1403,9 @@ public: /// DiffTemplate - Start the template type diffing. void DiffTemplate() { + Qualifiers FromQual = FromType.getQualifiers(), + ToQual = ToType.getQualifiers(); + const TemplateSpecializationType *FromOrigTST = GetTemplateSpecializationType(Context, FromType); const TemplateSpecializationType *ToOrigTST = @@ -1224,7 +1420,10 @@ public: return; } + FromQual -= QualType(FromOrigTST, 0).getQualifiers(); + ToQual -= QualType(ToOrigTST, 0).getQualifiers(); Tree.SetNode(FromType, ToType); + Tree.SetNode(FromQual, ToQual); // Same base template, but different arguments. Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(), diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 3e952ac..0d4f303 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -228,16 +228,12 @@ namespace { public: DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) { - if (!Complain) - return DiagnosticBuilder::getEmpty(); - + assert(Complain && "Not allowed to complain"); return C1.getDiagnostics().Report(Loc, DiagID); } DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) { - if (!Complain) - return DiagnosticBuilder::getEmpty(); - + assert(Complain && "Not allowed to complain"); return C2.getDiagnostics().Report(Loc, DiagID); } }; @@ -288,7 +284,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, case TemplateArgument::Type: return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType()); - + case TemplateArgument::Integral: if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(), Arg2.getIntegralType())) @@ -297,10 +293,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return llvm::APSInt::isSameValue(Arg1.getAsIntegral(), Arg2.getAsIntegral()); case TemplateArgument::Declaration: - if (!Arg1.getAsDecl() || !Arg2.getAsDecl()) - return !Arg1.getAsDecl() && !Arg2.getAsDecl(); return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl()); - + + case TemplateArgument::NullPtr: + return true; // FIXME: Is this correct? + case TemplateArgument::Template: return IsStructurallyEquivalent(Context, Arg1.getAsTemplate(), @@ -822,33 +819,47 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, FieldDecl *Field1, FieldDecl *Field2) { RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext()); - - if (!IsStructurallyEquivalent(Context, + + // For anonymous structs/unions, match up the anonymous struct/union type + // declarations directly, so that we don't go off searching for anonymous + // types + if (Field1->isAnonymousStructOrUnion() && + Field2->isAnonymousStructOrUnion()) { + RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl(); + RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl(); + return IsStructurallyEquivalent(Context, D1, D2); + } + + if (!IsStructurallyEquivalent(Context, Field1->getType(), Field2->getType())) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - Context.Diag2(Field2->getLocation(), diag::note_odr_field) - << Field2->getDeclName() << Field2->getType(); - Context.Diag1(Field1->getLocation(), diag::note_odr_field) - << Field1->getDeclName() << Field1->getType(); + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(Owner2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + } return false; } if (Field1->isBitField() != Field2->isBitField()) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - if (Field1->isBitField()) { - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() - << Field1->getBitWidthValue(Context.C1); - Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) - << Field2->getDeclName(); - } else { - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() - << Field2->getBitWidthValue(Context.C2); - Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field) - << Field1->getDeclName(); + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(Owner2); + if (Field1->isBitField()) { + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() + << Field1->getBitWidthValue(Context.C1); + Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) + << Field2->getDeclName(); + } else { + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() + << Field2->getBitWidthValue(Context.C2); + Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field) + << Field1->getDeclName(); + } } return false; } @@ -859,12 +870,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, unsigned Bits2 = Field2->getBitWidthValue(Context.C2); if (Bits1 != Bits2) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() << Bits2; - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() << Bits1; + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(Owner2); + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() << Bits2; + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() << Bits1; + } return false; } } @@ -872,17 +885,65 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; } +/// \brief Find the index of the given anonymous struct/union within its +/// context. +/// +/// \returns Returns the index of this anonymous struct/union in its 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) { + ASTContext &Context = Anon->getASTContext(); + QualType AnonTy = Context.getRecordType(Anon); + + RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext()); + if (!Owner) + return llvm::Optional<unsigned>(); + + unsigned Index = 0; + for (DeclContext::decl_iterator D = Owner->noload_decls_begin(), + DEnd = Owner->noload_decls_end(); + D != DEnd; ++D) { + FieldDecl *F = dyn_cast<FieldDecl>(*D); + if (!F || !F->isAnonymousStructOrUnion()) + continue; + + if (Context.hasSameType(F->getType(), AnonTy)) + break; + + ++Index; + } + + return Index; +} + /// \brief Determine structural equivalence of two records. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2) { if (D1->isUnion() != D2->isUnion()) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) - << D1->getDeclName() << (unsigned)D1->getTagKind(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) + << D1->getDeclName() << (unsigned)D1->getTagKind(); + } return false; } - + + 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 (*Index1 != *Index2) + return false; + } + } + } + // If both declarations are class template specializations, we know // the ODR applies, so check the template and template arguments. ClassTemplateSpecializationDecl *Spec1 @@ -920,12 +981,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) { if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) { if (D1CXX->getNumBases() != D2CXX->getNumBases()) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) - << D2CXX->getNumBases(); - Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) - << D1CXX->getNumBases(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) + << D2CXX->getNumBases(); + Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) + << D1CXX->getNumBases(); + } return false; } @@ -937,38 +1000,44 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, ++Base1, ++Base2) { if (!IsStructurallyEquivalent(Context, Base1->getType(), Base2->getType())) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Base2->getLocStart(), diag::note_odr_base) - << Base2->getType() - << Base2->getSourceRange(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->getType() - << Base1->getSourceRange(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Base2->getLocStart(), diag::note_odr_base) + << Base2->getType() + << Base2->getSourceRange(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->getType() + << Base1->getSourceRange(); + } return false; } // Check virtual vs. non-virtual inheritance mismatch. if (Base1->isVirtual() != Base2->isVirtual()) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Base2->getLocStart(), - diag::note_odr_virtual_base) - << Base2->isVirtual() << Base2->getSourceRange(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->isVirtual() - << Base1->getSourceRange(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Base2->getLocStart(), + diag::note_odr_virtual_base) + << Base2->isVirtual() << Base2->getSourceRange(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->isVirtual() + << Base1->getSourceRange(); + } return false; } } } else if (D1CXX->getNumBases() > 0) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->getType() - << Base1->getSourceRange(); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_base); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->getType() + << Base1->getSourceRange(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_base); + } return false; } } @@ -981,11 +1050,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Field1 != Field1End; ++Field1, ++Field2) { if (Field2 == Field2End) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(Field1->getLocation(), diag::note_odr_field) - << Field1->getDeclName() << Field1->getType(); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); + } return false; } @@ -994,11 +1065,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } if (Field2 != Field2End) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Field2->getLocation(), diag::note_odr_field) - << Field2->getDeclName() << Field2->getType(); - Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); + } return false; } @@ -1014,12 +1087,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, EC1End = D1->enumerator_end(); EC1 != EC1End; ++EC1, ++EC2) { if (EC2 == EC2End) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) - << EC1->getDeclName() - << EC1->getInitVal().toString(10); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() + << EC1->getInitVal().toString(10); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); + } return false; } @@ -1027,25 +1102,29 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, llvm::APSInt Val2 = EC2->getInitVal(); if (!llvm::APSInt::isSameValue(Val1, Val2) || !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() + << EC2->getInitVal().toString(10); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() + << EC1->getInitVal().toString(10); + } + return false; + } + } + + if (EC2 != EC2End) { + if (Context.Complain) { Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) << Context.C2.getTypeDeclType(D2); Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) << EC2->getDeclName() << EC2->getInitVal().toString(10); - Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) - << EC1->getDeclName() - << EC1->getInitVal().toString(10); - return false; + Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); } - } - - if (EC2 != EC2End) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) - << EC2->getDeclName() - << EC2->getInitVal().toString(10); - Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); return false; } @@ -1056,20 +1135,24 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, TemplateParameterList *Params1, TemplateParameterList *Params2) { if (Params1->size() != Params2->size()) { - Context.Diag2(Params2->getTemplateLoc(), - diag::err_odr_different_num_template_parameters) - << Params1->size() << Params2->size(); - Context.Diag1(Params1->getTemplateLoc(), - diag::note_odr_template_parameter_list); + if (Context.Complain) { + Context.Diag2(Params2->getTemplateLoc(), + diag::err_odr_different_num_template_parameters) + << Params1->size() << Params2->size(); + Context.Diag1(Params1->getTemplateLoc(), + diag::note_odr_template_parameter_list); + } return false; } for (unsigned I = 0, N = Params1->size(); I != N; ++I) { if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) { - Context.Diag2(Params2->getParam(I)->getLocation(), - diag::err_odr_different_template_parameter_kind); - Context.Diag1(Params1->getParam(I)->getLocation(), - diag::note_odr_template_parameter_here); + if (Context.Complain) { + Context.Diag2(Params2->getParam(I)->getLocation(), + diag::err_odr_different_template_parameter_kind); + Context.Diag1(Params1->getParam(I)->getLocation(), + diag::note_odr_template_parameter_here); + } return false; } @@ -1087,10 +1170,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, TemplateTypeParmDecl *D1, TemplateTypeParmDecl *D2) { if (D1->isParameterPack() != D2->isParameterPack()) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } return false; } @@ -1100,24 +1185,25 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, NonTypeTemplateParmDecl *D1, NonTypeTemplateParmDecl *D2) { - // FIXME: Enable once we have variadic templates. -#if 0 if (D1->isParameterPack() != D2->isParameterPack()) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } return false; } -#endif // Check types. if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) { - Context.Diag2(D2->getLocation(), - diag::err_odr_non_type_parameter_type_inconsistent) - << D2->getType() << D1->getType(); - Context.Diag1(D1->getLocation(), diag::note_odr_value_here) - << D1->getType(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), + diag::err_odr_non_type_parameter_type_inconsistent) + << D2->getType() << D1->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_value_here) + << D1->getType(); + } return false; } @@ -1127,17 +1213,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, TemplateTemplateParmDecl *D1, TemplateTemplateParmDecl *D2) { - // FIXME: Enable once we have variadic templates. -#if 0 if (D1->isParameterPack() != D2->isParameterPack()) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } return false; } -#endif - + // Check template parameter lists. return IsStructurallyEquivalent(Context, D1->getTemplateParameters(), D2->getTemplateParameters()); @@ -1509,11 +1594,26 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { ExceptionTypes.push_back(ExceptionType); } - FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); - EPI.Exceptions = ExceptionTypes.data(); - + FunctionProtoType::ExtProtoInfo FromEPI = T->getExtProtoInfo(); + FunctionProtoType::ExtProtoInfo ToEPI; + + ToEPI.ExtInfo = FromEPI.ExtInfo; + ToEPI.Variadic = FromEPI.Variadic; + ToEPI.HasTrailingReturn = FromEPI.HasTrailingReturn; + ToEPI.TypeQuals = FromEPI.TypeQuals; + ToEPI.RefQualifier = FromEPI.RefQualifier; + ToEPI.NumExceptions = ExceptionTypes.size(); + ToEPI.Exceptions = ExceptionTypes.data(); + ToEPI.ConsumedArguments = FromEPI.ConsumedArguments; + ToEPI.ExceptionSpecType = FromEPI.ExceptionSpecType; + ToEPI.NoexceptExpr = Importer.Import(FromEPI.NoexceptExpr); + ToEPI.ExceptionSpecDecl = cast_or_null<FunctionDecl>( + Importer.Import(FromEPI.ExceptionSpecDecl)); + ToEPI.ExceptionSpecTemplate = cast_or_null<FunctionDecl>( + Importer.Import(FromEPI.ExceptionSpecTemplate)); + return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(), - ArgTypes.size(), EPI); + ArgTypes.size(), ToEPI); } QualType ASTNodeImporter::VisitParenType(const ParenType *T) { @@ -1961,11 +2061,20 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { return TemplateArgument(From, ToType); } - case TemplateArgument::Declaration: - if (Decl *To = Importer.Import(From.getAsDecl())) - return TemplateArgument(To); + case TemplateArgument::Declaration: { + ValueDecl *FromD = From.getAsDecl(); + if (ValueDecl *To = cast_or_null<ValueDecl>(Importer.Import(FromD))) + return TemplateArgument(To, From.isDeclForReferenceParam()); return TemplateArgument(); - + } + + case TemplateArgument::NullPtr: { + QualType ToType = Importer.Import(From.getNullPtrType()); + if (ToType.isNull()) + return TemplateArgument(); + return TemplateArgument(ToType, /*isNullPtr*/true); + } + case TemplateArgument::Template: { TemplateName ToTemplate = Importer.Import(From.getAsTemplate()); if (ToTemplate.isNull()) @@ -2318,6 +2427,20 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { } if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) { + if (D->isAnonymousStructOrUnion() && + 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 + = findAnonymousStructOrUnionIndex(D)) { + if (llvm::Optional<unsigned> Index2 + = findAnonymousStructOrUnionIndex(FoundRecord)) { + if (*Index1 != *Index2) + continue; + } + } + } + if (RecordDecl *FoundDef = FoundRecord->getDefinition()) { if ((SearchName && !D->isCompleteDefinition()) || (D->isCompleteDefinition() && @@ -2491,8 +2614,30 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // Import additional name location/type info. ImportDeclarationNameLoc(D->getNameInfo(), NameInfo); + QualType FromTy = D->getType(); + bool usedDifferentExceptionSpec = false; + + if (const FunctionProtoType * + FromFPT = D->getType()->getAs<FunctionProtoType>()) { + FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo(); + // FunctionProtoType::ExtProtoInfo's ExceptionSpecDecl can point to the + // FunctionDecl that we are importing the FunctionProtoType for. + // To avoid an infinite recursion when importing, create the FunctionDecl + // with a simplified function type and update it afterwards. + if (FromEPI.ExceptionSpecDecl || FromEPI.ExceptionSpecTemplate || + FromEPI.NoexceptExpr) { + FunctionProtoType::ExtProtoInfo DefaultEPI; + FromTy = Importer.getFromContext().getFunctionType( + FromFPT->getResultType(), + FromFPT->arg_type_begin(), + FromFPT->arg_type_end() - FromFPT->arg_type_begin(), + DefaultEPI); + usedDifferentExceptionSpec = true; + } + } + // Import the type. - QualType T = Importer.Import(D->getType()); + QualType T = Importer.Import(FromTy); if (T.isNull()) return 0; @@ -2572,6 +2717,14 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } ToFunction->setParams(Parameters); + if (usedDifferentExceptionSpec) { + // Update FunctionProtoType::ExtProtoInfo. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + ToFunction->setType(T); + } + // FIXME: Other bits to merge? // Add this function to the lexical context. @@ -2596,6 +2749,25 @@ Decl *ASTNodeImporter::VisitCXXConversionDecl(CXXConversionDecl *D) { return VisitCXXMethodDecl(D); } +static unsigned getFieldIndex(Decl *F) { + RecordDecl *Owner = dyn_cast<RecordDecl>(F->getDeclContext()); + if (!Owner) + return 0; + + unsigned Index = 1; + for (DeclContext::decl_iterator D = Owner->noload_decls_begin(), + DEnd = Owner->noload_decls_end(); + D != DEnd; ++D) { + if (*D == F) + return Index; + + if (isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D)) + ++Index; + } + + return Index; +} + Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { // Import the major distinguishing characteristics of a variable. DeclContext *DC, *LexicalDC; @@ -2609,6 +2781,10 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { DC->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (FieldDecl *FoundField = dyn_cast<FieldDecl>(FoundDecls[I])) { + // For anonymous fields, match up by index. + if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) + continue; + if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType())) { Importer.Imported(D, FoundField); @@ -2642,6 +2818,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { ToField->setLexicalDeclContext(LexicalDC); if (ToField->hasInClassInitializer()) ToField->setInClassInitializer(D->getInClassInitializer()); + ToField->setImplicit(D->isImplicit()); Importer.Imported(D, ToField); LexicalDC->addDeclInternal(ToField); return ToField; @@ -2661,6 +2838,10 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (IndirectFieldDecl *FoundField = dyn_cast<IndirectFieldDecl>(FoundDecls[I])) { + // For anonymous indirect fields, match up by index. + if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) + continue; + if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType(), Name)) { @@ -3025,7 +3206,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { ResultTy, ResultTInfo, DC, D->isInstanceMethod(), D->isVariadic(), - D->isSynthesized(), + D->isPropertyAccessor(), D->isImplicit(), D->isDefined(), D->getImplementationControl(), @@ -4027,7 +4208,8 @@ Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) { return new (Importer.getToContext()) BinaryOperator(LHS, RHS, E->getOpcode(), T, E->getValueKind(), E->getObjectKind(), - Importer.Import(E->getOperatorLoc())); + Importer.Import(E->getOperatorLoc()), + E->isFPContractable()); } Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { @@ -4056,7 +4238,8 @@ Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { T, E->getValueKind(), E->getObjectKind(), CompLHSType, CompResultType, - Importer.Import(E->getOperatorLoc())); + Importer.Import(E->getOperatorLoc()), + E->isFPContractable()); } static bool ImportCastPath(CastExpr *E, CXXCastPath &Path) { @@ -4479,7 +4662,8 @@ FileID ASTImporter::Import(FileID FromID) { llvm::MemoryBuffer *ToBuf = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), FromBuf->getBufferIdentifier()); - ToID = ToSM.createFileIDForMemBuffer(ToBuf); + ToID = ToSM.createFileIDForMemBuffer(ToBuf, + FromSLoc.getFile().getFileCharacteristic()); } diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index bcc96f9..d20d77e 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -64,7 +64,10 @@ add_dependencies(clangAST ClangAttrClasses ClangAttrList ClangAttrImpl + ClangCommentCommandInfo ClangCommentNodes + ClangCommentHTMLTags + ClangCommentHTMLTagsProperties ClangDeclNodes ClangDiagnosticAST ClangDiagnosticComment diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index cf3913b..213b214 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/DeclCXX.h" +#include "llvm/ADT/SetVector.h" #include <algorithm> #include <set> @@ -25,13 +26,9 @@ void CXXBasePaths::ComputeDeclsFound() { assert(NumDeclsFound == 0 && !DeclsFound && "Already computed the set of declarations"); - SmallVector<NamedDecl *, 8> Decls; + llvm::SetVector<NamedDecl *, SmallVector<NamedDecl *, 8> > Decls; for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path) - Decls.push_back(*Path->Decls.first); - - // Eliminate duplicated decls. - llvm::array_pod_sort(Decls.begin(), Decls.end()); - Decls.erase(std::unique(Decls.begin(), Decls.end()), Decls.end()); + Decls.insert(*Path->Decls.first); NumDeclsFound = Decls.size(); DeclsFound = new NamedDecl * [NumDeclsFound]; @@ -258,7 +255,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, } } else if (VisitBase) { CXXRecordDecl *BaseRecord - = cast<CXXRecordDecl>(BaseSpec->getType()->getAs<RecordType>() + = cast<CXXRecordDecl>(BaseSpec->getType()->castAs<RecordType>() ->getDecl()); if (lookupInBases(Context, BaseRecord, BaseMatches, UserData)) { // C++ [class.member.lookup]p2: @@ -365,8 +362,8 @@ bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier, void *BaseRecord) { assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord && "User data for FindBaseClass is not canonical!"); - return Specifier->getType()->getAs<RecordType>()->getDecl() - ->getCanonicalDecl() == BaseRecord; + return Specifier->getType()->castAs<RecordType>()->getDecl() + ->getCanonicalDecl() == BaseRecord; } bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier, @@ -375,14 +372,15 @@ bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier, assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord && "User data for FindBaseClass is not canonical!"); return Specifier->isVirtual() && - Specifier->getType()->getAs<RecordType>()->getDecl() - ->getCanonicalDecl() == BaseRecord; + Specifier->getType()->castAs<RecordType>()->getDecl() + ->getCanonicalDecl() == BaseRecord; } bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { - RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + RecordDecl *BaseRecord = + Specifier->getType()->castAs<RecordType>()->getDecl(); DeclarationName N = DeclarationName::getFromOpaquePtr(Name); for (Path.Decls = BaseRecord->lookup(N); @@ -398,7 +396,8 @@ bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier, bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { - RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + RecordDecl *BaseRecord = + Specifier->getType()->castAs<RecordType>()->getDecl(); const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member; DeclarationName N = DeclarationName::getFromOpaquePtr(Name); @@ -416,7 +415,8 @@ bool CXXRecordDecl:: FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { - RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + RecordDecl *BaseRecord = + Specifier->getType()->castAs<RecordType>()->getDecl(); DeclarationName N = DeclarationName::getFromOpaquePtr(Name); for (Path.Decls = BaseRecord->lookup(N); @@ -694,7 +694,7 @@ AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context, "Cannot get indirect primary bases for class with dependent bases."); const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl()); // Only bases with virtual bases participate in computing the // indirect primary virtual base classes. @@ -717,7 +717,7 @@ CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const { "Cannot get indirect primary bases for class with dependent bases."); const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl()); // Only bases with virtual bases participate in computing the // indirect primary virtual base classes. diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index 8a711f0..361f8ac 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/ASTContext.h" #include "clang/AST/Comment.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -37,11 +38,12 @@ void Comment::dump() const { // 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); + dump(llvm::errs(), NULL, NULL); } -void Comment::dump(SourceManager &SM) const { - dump(llvm::errs(), &SM); +void Comment::dump(const ASTContext &Context) const { + dump(llvm::errs(), &Context.getCommentCommandTraits(), + &Context.getSourceManager()); } namespace { @@ -149,13 +151,14 @@ void DeclInfo::fill() { ParamVars = ArrayRef<const ParmVarDecl *>(); TemplateParameters = NULL; - if (!ThisDecl) { + if (!CommentDecl) { // If there is no declaration, the defaults is our only guess. IsFilled = true; return; } - - Decl::Kind K = ThisDecl->getKind(); + CurrentDecl = CommentDecl; + + Decl::Kind K = CommentDecl->getKind(); switch (K) { default: // Defaults are should be good for declarations we don't handle explicitly. @@ -165,7 +168,7 @@ void DeclInfo::fill() { case Decl::CXXConstructor: case Decl::CXXDestructor: case Decl::CXXConversion: { - const FunctionDecl *FD = cast<FunctionDecl>(ThisDecl); + const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl); Kind = FunctionKind; ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(), FD->getNumParams()); @@ -179,14 +182,14 @@ void DeclInfo::fill() { if (K == Decl::CXXMethod || K == Decl::CXXConstructor || K == Decl::CXXDestructor || K == Decl::CXXConversion) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(ThisDecl); + const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl); IsInstanceMethod = MD->isInstance(); IsClassMethod = !IsInstanceMethod; } break; } case Decl::ObjCMethod: { - const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(ThisDecl); + const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); Kind = FunctionKind; ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(), MD->param_size()); @@ -197,7 +200,7 @@ void DeclInfo::fill() { break; } case Decl::FunctionTemplate: { - const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(ThisDecl); + const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl); Kind = FunctionKind; TemplateKind = Template; const FunctionDecl *FD = FTD->getTemplatedDecl(); @@ -208,7 +211,7 @@ void DeclInfo::fill() { break; } case Decl::ClassTemplate: { - const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(ThisDecl); + const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl); Kind = ClassKind; TemplateKind = Template; TemplateParameters = CTD->getTemplateParameters(); @@ -216,7 +219,7 @@ void DeclInfo::fill() { } case Decl::ClassTemplatePartialSpecialization: { const ClassTemplatePartialSpecializationDecl *CTPSD = - cast<ClassTemplatePartialSpecializationDecl>(ThisDecl); + cast<ClassTemplatePartialSpecializationDecl>(CommentDecl); Kind = ClassKind; TemplateKind = TemplatePartialSpecialization; TemplateParameters = CTPSD->getTemplateParameters(); @@ -240,12 +243,55 @@ void DeclInfo::fill() { case Decl::Namespace: Kind = NamespaceKind; break; - case Decl::Typedef: + case Decl::Typedef: { + Kind = TypedefKind; + // If this is a typedef to something we consider a function, extract + // arguments and return type. + const TypedefDecl *TD = cast<TypedefDecl>(CommentDecl); + const TypeSourceInfo *TSI = TD->getTypeSourceInfo(); + if (!TSI) + break; + TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); + while (true) { + TL = TL.IgnoreParens(); + // Look through qualified types. + if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) { + TL = QualifiedTL->getUnqualifiedLoc(); + continue; + } + // Look through pointer types. + if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) { + TL = PointerTL->getPointeeLoc().getUnqualifiedLoc(); + continue; + } + if (BlockPointerTypeLoc *BlockPointerTL = + dyn_cast<BlockPointerTypeLoc>(&TL)) { + TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc(); + continue; + } + if (MemberPointerTypeLoc *MemberPointerTL = + dyn_cast<MemberPointerTypeLoc>(&TL)) { + TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc(); + continue; + } + // Is this a typedef for a function type? + if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) { + Kind = FunctionKind; + ArrayRef<ParmVarDecl *> Params = FTL->getParams(); + ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(), + Params.size()); + ResultType = FTL->getResultLoc().getType(); + break; + } + break; + } + break; + } case Decl::TypeAlias: Kind = TypedefKind; break; case Decl::TypeAliasTemplate: { - const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(ThisDecl); + const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl); Kind = TypedefKind; TemplateKind = Template; TemplateParameters = TAT->getTemplateParameters(); @@ -259,6 +305,25 @@ void DeclInfo::fill() { IsFilled = true; } +StringRef ParamCommandComment::getParamName(const FullComment *FC) const { + assert(isParamIndexValid()); + return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName(); +} + +StringRef TParamCommandComment::getParamName(const FullComment *FC) const { + assert(isPositionValid()); + const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters; + for (unsigned i = 0, e = getDepth(); i != e; ++i) { + if (i == e-1) + return TPL->getParam(getIndex(i))->getName(); + const NamedDecl *Param = TPL->getParam(getIndex(i)); + if (const TemplateTemplateParmDecl *TTP = + dyn_cast<TemplateTemplateParmDecl>(Param)) + TPL = TTP->getTemplateParameters(); + } + return ""; +} + } // end namespace comments } // end namespace clang diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp index 0aebc1e..95daa7e 100644 --- a/lib/AST/CommentBriefParser.cpp +++ b/lib/AST/CommentBriefParser.cpp @@ -15,6 +15,11 @@ namespace clang { namespace comments { namespace { +inline bool isWhitespace(char C) { + return C == ' ' || C == '\n' || C == '\r' || + C == '\t' || C == '\f' || C == '\v'; +} + /// Convert all whitespace into spaces, remove leading and trailing spaces, /// compress multiple spaces into one. void cleanupBrief(std::string &S) { @@ -23,8 +28,7 @@ void cleanupBrief(std::string &S) { for (std::string::iterator I = S.begin(), E = S.end(); I != E; ++I) { const char C = *I; - if (C == ' ' || C == '\n' || C == '\r' || - C == '\t' || C == '\v' || C == '\f') { + if (isWhitespace(C)) { if (!PrevWasSpace) { *O++ = ' '; PrevWasSpace = true; @@ -40,6 +44,15 @@ void cleanupBrief(std::string &S) { S.resize(O - S.begin()); } + +bool isWhitespace(StringRef Text) { + for (StringRef::const_iterator I = Text.begin(), E = Text.end(); + I != E; ++I) { + if (!isWhitespace(*I)) + return false; + } + return true; +} } // unnamed namespace BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) : @@ -66,19 +79,23 @@ std::string BriefParser::Parse() { } if (Tok.is(tok::command)) { - StringRef Name = Tok.getCommandName(); - if (Traits.isBriefCommand(Name)) { + const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); + if (Info->IsBriefCommand) { FirstParagraphOrBrief.clear(); InBrief = true; ConsumeToken(); continue; } - if (Traits.isReturnsCommand(Name)) { + if (Info->IsReturnsCommand) { InReturns = true; + InBrief = false; + InFirstParagraph = false; ReturnsParagraph += "Returns "; + ConsumeToken(); + continue; } // Block commands implicitly start a new paragraph. - if (Traits.isBlockCommand(Name)) { + if (Info->IsBlockCommand) { // We found an implicit paragraph end. InFirstParagraph = false; if (InBrief) @@ -93,13 +110,29 @@ std::string BriefParser::Parse() { ReturnsParagraph += ' '; ConsumeToken(); + // If the next token is a whitespace only text, ignore it. Thus we allow + // two paragraphs to be separated by line that has only whitespace in it. + // + // We don't need to add a space to the parsed text because we just added + // a space for the newline. + if (Tok.is(tok::text)) { + if (isWhitespace(Tok.getText())) + ConsumeToken(); + } + if (Tok.is(tok::newline)) { ConsumeToken(); - // We found a paragraph end. - InFirstParagraph = false; - InReturns = false; + // We found a paragraph end. This ends the brief description if + // \\brief command or its equivalent was explicitly used. + // Stop scanning text because an explicit \\brief paragraph is the + // preffered one. if (InBrief) break; + // End first paragraph if we found some non-whitespace text. + if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief)) + InFirstParagraph = false; + // End the \\returns paragraph because we found the paragraph end. + InReturns = false; } continue; } diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp index dc7a0bd..e7e40fd 100644 --- a/lib/AST/CommentCommandTraits.cpp +++ b/lib/AST/CommentCommandTraits.cpp @@ -8,125 +8,64 @@ //===----------------------------------------------------------------------===// #include "clang/AST/CommentCommandTraits.h" -#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/STLExtras.h" namespace clang { namespace comments { -// TODO: tablegen +#include "clang/AST/CommentCommandInfo.inc" -bool CommandTraits::isVerbatimBlockCommand(StringRef StartName, - StringRef &EndName) const { - const char *Result = llvm::StringSwitch<const char *>(StartName) - .Case("code", "endcode") - .Case("verbatim", "endverbatim") - .Case("htmlonly", "endhtmlonly") - .Case("latexonly", "endlatexonly") - .Case("xmlonly", "endxmlonly") - .Case("manonly", "endmanonly") - .Case("rtfonly", "endrtfonly") +CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator) : + NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) +{ } - .Case("dot", "enddot") - .Case("msc", "endmsc") - - .Case("f$", "f$") // Inline LaTeX formula - .Case("f[", "f]") // Displayed LaTeX formula - .Case("f{", "f}") // LaTeX environment - - .Default(NULL); - - if (Result) { - EndName = Result; - return true; - } - - for (VerbatimBlockCommandVector::const_iterator - I = VerbatimBlockCommands.begin(), - E = VerbatimBlockCommands.end(); - I != E; ++I) - if (I->StartName == StartName) { - EndName = I->EndName; - return true; - } - - return false; +const CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const { + if (const CommandInfo *Info = getBuiltinCommandInfo(Name)) + return Info; + return getRegisteredCommandInfo(Name); } -bool CommandTraits::isVerbatimLineCommand(StringRef Name) const { - bool Result = isDeclarationCommand(Name) || llvm::StringSwitch<bool>(Name) - .Case("defgroup", true) - .Case("ingroup", true) - .Case("addtogroup", true) - .Case("weakgroup", true) - .Case("name", true) - - .Case("section", true) - .Case("subsection", true) - .Case("subsubsection", true) - .Case("paragraph", true) - - .Case("mainpage", true) - .Case("subpage", true) - .Case("ref", true) +const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const { + if (const CommandInfo *Info = getBuiltinCommandInfo(CommandID)) + return Info; + return getRegisteredCommandInfo(CommandID); +} - .Default(false); +const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName) { + char *Name = Allocator.Allocate<char>(CommandName.size() + 1); + memcpy(Name, CommandName.data(), CommandName.size()); + Name[CommandName.size()] = '\0'; - if (Result) - return true; + // Value-initialize (=zero-initialize in this case) a new CommandInfo. + CommandInfo *Info = new (Allocator) CommandInfo(); + Info->Name = Name; + Info->ID = NextID++; + Info->IsUnknownCommand = true; - for (VerbatimLineCommandVector::const_iterator - I = VerbatimLineCommands.begin(), - E = VerbatimLineCommands.end(); - I != E; ++I) - if (I->Name == Name) - return true; + RegisteredCommands.push_back(Info); - return false; + return Info; } -bool CommandTraits::isDeclarationCommand(StringRef Name) const { - return llvm::StringSwitch<bool>(Name) - // Doxygen commands. - .Case("fn", true) - .Case("var", true) - .Case("property", true) - .Case("typedef", true) - - .Case("overload", true) - - // HeaderDoc commands. - .Case("class", true) - .Case("interface", true) - .Case("protocol", true) - .Case("category", true) - .Case("template", true) - .Case("function", true) - .Case("method", true) - .Case("callback", true) - .Case("var", true) - .Case("const", true) - .Case("constant", true) - .Case("property", true) - .Case("struct", true) - .Case("union", true) - .Case("typedef", true) - .Case("enum", true) - - .Default(false); +const CommandInfo *CommandTraits::getBuiltinCommandInfo( + unsigned CommandID) { + if (CommandID < llvm::array_lengthof(Commands)) + return &Commands[CommandID]; + return NULL; } -void CommandTraits::addVerbatimBlockCommand(StringRef StartName, - StringRef EndName) { - VerbatimBlockCommand VBC; - VBC.StartName = StartName; - VBC.EndName = EndName; - VerbatimBlockCommands.push_back(VBC); +const CommandInfo *CommandTraits::getRegisteredCommandInfo( + StringRef Name) const { + for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) { + if (RegisteredCommands[i]->Name == Name) + return RegisteredCommands[i]; + } + return NULL; } -void CommandTraits::addVerbatimLineCommand(StringRef Name) { - VerbatimLineCommand VLC; - VLC.Name = Name; - VerbatimLineCommands.push_back(VLC); +const CommandInfo *CommandTraits::getRegisteredCommandInfo( + unsigned CommandID) const { + return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)]; } } // end namespace comments diff --git a/lib/AST/CommentDumper.cpp b/lib/AST/CommentDumper.cpp index dffc823..19d24b2 100644 --- a/lib/AST/CommentDumper.cpp +++ b/lib/AST/CommentDumper.cpp @@ -16,12 +16,20 @@ namespace comments { namespace { class CommentDumper: public comments::ConstCommentVisitor<CommentDumper> { raw_ostream &OS; - SourceManager *SM; + 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, SourceManager *SM) : - OS(OS), SM(SM), IndentLevel(0) + 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 { @@ -56,6 +64,15 @@ public: 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) { @@ -107,7 +124,7 @@ void CommentDumper::visitTextComment(const TextComment *C) { void CommentDumper::visitInlineCommandComment(const InlineCommandComment *C) { dumpComment(C); - OS << " Name=\"" << C->getCommandName() << "\""; + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; switch (C->getRenderKind()) { case InlineCommandComment::RenderNormal: OS << " RenderNormal"; @@ -155,7 +172,7 @@ void CommentDumper::visitParagraphComment(const ParagraphComment *C) { void CommentDumper::visitBlockCommandComment(const BlockCommandComment *C) { dumpComment(C); - OS << " Name=\"" << C->getCommandName() << "\""; + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; } @@ -170,8 +187,12 @@ void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) { else OS << " implicitly"; - if (C->hasParamName()) - OS << " Param=\"" << C->getParamName() << "\""; + if (C->hasParamName()) { + if (C->isParamIndexValid()) + OS << " Param=\"" << C->getParamName(FC) << "\""; + else + OS << " Param=\"" << C->getParamNameAsWritten() << "\""; + } if (C->isParamIndexValid()) OS << " ParamIndex=" << C->getParamIndex(); @@ -181,7 +202,10 @@ void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) { dumpComment(C); if (C->hasParamName()) { - OS << " Param=\"" << C->getParamName() << "\""; + if (C->isPositionValid()) + OS << " Param=\"" << C->getParamName(FC) << "\""; + else + OS << " Param=\"" << C->getParamNameAsWritten() << "\""; } if (C->isPositionValid()) { @@ -198,7 +222,7 @@ void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) { void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) { dumpComment(C); - OS << " Name=\"" << C->getCommandName() << "\"" + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"" " CloseName=\"" << C->getCloseName() << "\""; } @@ -220,8 +244,10 @@ void CommentDumper::visitFullComment(const FullComment *C) { } // unnamed namespace -void Comment::dump(llvm::raw_ostream &OS, SourceManager *SM) const { - CommentDumper D(llvm::errs(), SM); +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'; } diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index b6516ec..31a09f7 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -28,6 +28,9 @@ bool isHTMLHexCharacterReferenceCharacter(char C) { (C >= 'a' && C <= 'f') || (C >= 'A' && C <= 'F'); } + +#include "clang/AST/CommentHTMLTags.inc" + } // unnamed namespace StringRef Lexer::resolveHTMLNamedCharacterReference(StringRef Name) const { @@ -223,6 +226,11 @@ bool isWhitespace(const char *BufferPtr, const char *BufferEnd) { return skipWhitespace(BufferPtr, BufferEnd) == BufferEnd; } +bool isCommandNameStartCharacter(char C) { + return (C >= 'a' && C <= 'z') || + (C >= 'A' && C <= 'Z'); +} + bool isCommandNameCharacter(char C) { return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') || @@ -337,7 +345,7 @@ void Lexer::lexCommentText(Token &T) { } // Don't make zero-length commands. - if (!isCommandNameCharacter(*TokenPtr)) { + if (!isCommandNameStartCharacter(*TokenPtr)) { formTextToken(T, TokenPtr); return; } @@ -356,18 +364,23 @@ void Lexer::lexCommentText(Token &T) { } const StringRef CommandName(BufferPtr + 1, Length); - StringRef EndName; - if (Traits.isVerbatimBlockCommand(CommandName, EndName)) { - setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, EndName); + const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName); + if (!Info) { + formTokenWithChars(T, TokenPtr, tok::unknown_command); + T.setUnknownCommandName(CommandName); + return; + } + if (Info->IsVerbatimBlockCommand) { + setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info); return; } - if (Traits.isVerbatimLineCommand(CommandName)) { - setupAndLexVerbatimLine(T, TokenPtr); + if (Info->IsVerbatimLineCommand) { + setupAndLexVerbatimLine(T, TokenPtr, Info); return; } formTokenWithChars(T, TokenPtr, tok::command); - T.setCommandName(CommandName); + T.setCommandID(Info->getID()); return; } @@ -420,14 +433,15 @@ void Lexer::lexCommentText(Token &T) { void Lexer::setupAndLexVerbatimBlock(Token &T, const char *TextBegin, - char Marker, StringRef EndName) { + char Marker, const CommandInfo *Info) { + assert(Info->IsVerbatimBlockCommand); + VerbatimBlockEndCommandName.clear(); VerbatimBlockEndCommandName.append(Marker == '\\' ? "\\" : "@"); - VerbatimBlockEndCommandName.append(EndName); + VerbatimBlockEndCommandName.append(Info->EndCommandName); - StringRef Name(BufferPtr + 1, TextBegin - (BufferPtr + 1)); formTokenWithChars(T, TextBegin, tok::verbatim_block_begin); - T.setVerbatimBlockName(Name); + T.setVerbatimBlockID(Info->getID()); // 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 @@ -468,7 +482,7 @@ again: const char *End = BufferPtr + VerbatimBlockEndCommandName.size(); StringRef Name(BufferPtr + 1, End - (BufferPtr + 1)); formTokenWithChars(T, End, tok::verbatim_block_end); - T.setVerbatimBlockName(Name); + T.setVerbatimBlockID(Traits.getCommandInfo(Name)->getID()); State = LS_Normal; return; } else { @@ -498,10 +512,11 @@ void Lexer::lexVerbatimBlockBody(Token &T) { lexVerbatimBlockFirstLine(T); } -void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin) { - const StringRef Name(BufferPtr + 1, TextBegin - BufferPtr - 1); +void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin, + const CommandInfo *Info) { + assert(Info->IsVerbatimLineCommand); formTokenWithChars(T, TextBegin, tok::verbatim_line_name); - T.setVerbatimLineName(Name); + T.setVerbatimLineID(Info->getID()); State = LS_VerbatimLineText; } @@ -585,8 +600,12 @@ void Lexer::setupAndLexHTMLStartTag(Token &T) { assert(BufferPtr[0] == '<' && isHTMLIdentifierStartingCharacter(BufferPtr[1])); const char *TagNameEnd = skipHTMLIdentifier(BufferPtr + 2, CommentEnd); - StringRef Name(BufferPtr + 1, TagNameEnd - (BufferPtr + 1)); + if (!isHTMLTagName(Name)) { + formTextToken(T, TagNameEnd); + return; + } + formTokenWithChars(T, TagNameEnd, tok::html_start_tag); T.setHTMLTagStartName(Name); @@ -665,11 +684,16 @@ void Lexer::setupAndLexHTMLEndTag(Token &T) { const char *TagNameBegin = skipWhitespace(BufferPtr + 2, CommentEnd); const char *TagNameEnd = skipHTMLIdentifier(TagNameBegin, CommentEnd); + StringRef Name(TagNameBegin, TagNameEnd - TagNameBegin); + if (!isHTMLTagName(Name)) { + formTextToken(T, TagNameEnd); + return; + } const char *End = skipWhitespace(TagNameEnd, CommentEnd); formTokenWithChars(T, End, tok::html_end_tag); - T.setHTMLTagEndName(StringRef(TagNameBegin, TagNameEnd - TagNameBegin)); + T.setHTMLTagEndName(Name); if (BufferPtr != CommentEnd && *BufferPtr == '>') State = LS_HTMLEndTag; @@ -683,11 +707,11 @@ void Lexer::lexHTMLEndTag(Token &T) { } Lexer::Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits, - SourceLocation FileLoc, const CommentOptions &CommOpts, + SourceLocation FileLoc, const char *BufferStart, const char *BufferEnd): Allocator(Allocator), Traits(Traits), BufferStart(BufferStart), BufferEnd(BufferEnd), - FileLoc(FileLoc), CommOpts(CommOpts), BufferPtr(BufferStart), + FileLoc(FileLoc), BufferPtr(BufferStart), CommentState(LCS_BeforeComment), State(LS_Normal) { } diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp index 43abf6a..d0a8474 100644 --- a/lib/AST/CommentParser.cpp +++ b/lib/AST/CommentParser.cpp @@ -132,8 +132,8 @@ class TextTokenRetokenizer { Result.setKind(tok::text); Result.setLength(TokLength); #ifndef NDEBUG - Result.TextPtr1 = "<UNSET>"; - Result.TextLen1 = 7; + Result.TextPtr = "<UNSET>"; + Result.IntVal = 7; #endif Result.setText(Text); } @@ -312,26 +312,26 @@ BlockCommandComment *Parser::parseBlockCommand() { BlockCommandComment *BC; bool IsParam = false; bool IsTParam = false; - unsigned NumArgs = 0; - if (Traits.isParamCommand(Tok.getCommandName())) { + const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); + if (Info->IsParamCommand) { IsParam = true; PC = S.actOnParamCommandStart(Tok.getLocation(), Tok.getEndLocation(), - Tok.getCommandName()); - } if (Traits.isTParamCommand(Tok.getCommandName())) { + Tok.getCommandID()); + } if (Info->IsTParamCommand) { IsTParam = true; TPC = S.actOnTParamCommandStart(Tok.getLocation(), Tok.getEndLocation(), - Tok.getCommandName()); + Tok.getCommandID()); } else { - NumArgs = Traits.getBlockCommandNumArgs(Tok.getCommandName()); BC = S.actOnBlockCommandStart(Tok.getLocation(), Tok.getEndLocation(), - Tok.getCommandName()); + Tok.getCommandID()); } consumeToken(); - if (Tok.is(tok::command) && Traits.isBlockCommand(Tok.getCommandName())) { + if (Tok.is(tok::command) && + Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand) { // Block command ahead. We can't nest block commands, so pretend that this // command has an empty argument. ParagraphComment *Paragraph = S.actOnParagraphComment( @@ -348,7 +348,7 @@ BlockCommandComment *Parser::parseBlockCommand() { } } - if (IsParam || IsTParam || NumArgs > 0) { + if (IsParam || IsTParam || Info->NumArgs > 0) { // In order to parse command arguments we need to retokenize a few // following text tokens. TextTokenRetokenizer Retokenizer(Allocator, *this); @@ -358,7 +358,7 @@ BlockCommandComment *Parser::parseBlockCommand() { else if (IsTParam) parseTParamCommandArgs(TPC, Retokenizer); else - parseBlockCommandArgs(BC, Retokenizer, NumArgs); + parseBlockCommandArgs(BC, Retokenizer, Info->NumArgs); Retokenizer.putBackLeftoverTokens(); } @@ -394,14 +394,14 @@ InlineCommandComment *Parser::parseInlineCommand() { if (ArgTokValid) { IC = S.actOnInlineCommand(CommandTok.getLocation(), CommandTok.getEndLocation(), - CommandTok.getCommandName(), + CommandTok.getCommandID(), ArgTok.getLocation(), ArgTok.getEndLocation(), ArgTok.getText()); } else { IC = S.actOnInlineCommand(CommandTok.getLocation(), CommandTok.getEndLocation(), - CommandTok.getCommandName()); + CommandTok.getCommandID()); } Retokenizer.putBackLeftoverTokens(); @@ -540,23 +540,39 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() { assert(Content.size() != 0); break; // Block content or EOF ahead, finish this parapgaph. - case tok::command: - if (Traits.isBlockCommand(Tok.getCommandName())) { + case tok::unknown_command: + Content.push_back(S.actOnUnknownCommand(Tok.getLocation(), + Tok.getEndLocation(), + Tok.getUnknownCommandName())); + consumeToken(); + continue; + + case tok::command: { + const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); + if (Info->IsBlockCommand) { if (Content.size() == 0) return parseBlockCommand(); break; // Block command ahead, finish this parapgaph. } - if (Traits.isInlineCommand(Tok.getCommandName())) { - Content.push_back(parseInlineCommand()); + if (Info->IsVerbatimBlockEndCommand) { + Diag(Tok.getLocation(), + diag::warn_verbatim_block_end_without_start) + << Info->Name + << SourceRange(Tok.getLocation(), Tok.getEndLocation()); + consumeToken(); continue; } - - // Not a block command, not an inline command ==> an unknown command. - Content.push_back(S.actOnUnknownCommand(Tok.getLocation(), - Tok.getEndLocation(), - Tok.getCommandName())); - consumeToken(); + if (Info->IsUnknownCommand) { + Content.push_back(S.actOnUnknownCommand(Tok.getLocation(), + Tok.getEndLocation(), + Info->getID())); + consumeToken(); + continue; + } + assert(Info->IsInlineCommand); + Content.push_back(parseInlineCommand()); continue; + } case tok::newline: { consumeToken(); @@ -606,7 +622,7 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() { VerbatimBlockComment *VB = S.actOnVerbatimBlockStart(Tok.getLocation(), - Tok.getVerbatimBlockName()); + Tok.getVerbatimBlockID()); consumeToken(); // Don't create an empty line if verbatim opening command is followed @@ -634,8 +650,9 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() { } if (Tok.is(tok::verbatim_block_end)) { + const CommandInfo *Info = Traits.getCommandInfo(Tok.getVerbatimBlockID()); S.actOnVerbatimBlockFinish(VB, Tok.getLocation(), - Tok.getVerbatimBlockName(), + Info->Name, S.copyArray(llvm::makeArrayRef(Lines))); consumeToken(); } else { @@ -666,7 +683,7 @@ VerbatimLineComment *Parser::parseVerbatimLine() { } VerbatimLineComment *VL = S.actOnVerbatimLine(NameTok.getLocation(), - NameTok.getVerbatimLineName(), + NameTok.getVerbatimLineID(), TextBegin, Text); consumeToken(); @@ -676,6 +693,7 @@ VerbatimLineComment *Parser::parseVerbatimLine() { BlockContentComment *Parser::parseBlockContent() { switch (Tok.getKind()) { case tok::text: + case tok::unknown_command: case tok::command: case tok::html_start_tag: case tok::html_end_tag: diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp index c39ee57..08ecb3a 100644 --- a/lib/AST/CommentSema.cpp +++ b/lib/AST/CommentSema.cpp @@ -13,15 +13,22 @@ #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" namespace clang { namespace comments { +namespace { +#include "clang/AST/CommentHTMLTagsProperties.inc" +} // unnamed namespace + Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr, - DiagnosticsEngine &Diags, const CommandTraits &Traits) : + DiagnosticsEngine &Diags, CommandTraits &Traits, + const Preprocessor *PP) : Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits), - ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) { + PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) { } void Sema::setDecl(const Decl *D) { @@ -29,7 +36,7 @@ void Sema::setDecl(const Decl *D) { return; ThisDeclInfo = new (Allocator) DeclInfo; - ThisDeclInfo->ThisDecl = D; + ThisDeclInfo->CommentDecl = D; ThisDeclInfo->IsFilled = false; } @@ -40,8 +47,8 @@ ParagraphComment *Sema::actOnParagraphComment( BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, - StringRef Name) { - return new (Allocator) BlockCommandComment(LocBegin, LocEnd, Name); + unsigned CommandID) { + return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID); } void Sema::actOnBlockCommandArgs(BlockCommandComment *Command, @@ -55,18 +62,19 @@ void Sema::actOnBlockCommandFinish(BlockCommandComment *Command, checkBlockCommandEmptyParagraph(Command); checkBlockCommandDuplicate(Command); checkReturnsCommand(Command); + checkDeprecatedCommand(Command); } ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, - StringRef Name) { + unsigned CommandID) { ParamCommandComment *Command = - new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name); + new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID); if (!isFunctionDecl()) Diag(Command->getLocation(), diag::warn_doc_param_not_attached_to_a_function_decl) - << Command->getCommandNameRange(); + << Command->getCommandNameRange(Traits); return Command; } @@ -142,56 +150,6 @@ void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command, ArgLocEnd), Arg); Command->setArgs(llvm::makeArrayRef(A, 1)); - - if (!isFunctionDecl()) { - // We already warned that this \\param is not attached to a function decl. - return; - } - - ArrayRef<const ParmVarDecl *> ParamVars = getParamVars(); - - // Check that referenced parameter name is in the function decl. - const unsigned ResolvedParamIndex = resolveParmVarReference(Arg, ParamVars); - if (ResolvedParamIndex != ParamCommandComment::InvalidParamIndex) { - Command->setParamIndex(ResolvedParamIndex); - if (ParamVarDocs[ResolvedParamIndex]) { - SourceRange ArgRange(ArgLocBegin, ArgLocEnd); - Diag(ArgLocBegin, diag::warn_doc_param_duplicate) - << Arg << ArgRange; - ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex]; - Diag(PrevCommand->getLocation(), diag::note_doc_param_previous) - << PrevCommand->getParamNameRange(); - } - ParamVarDocs[ResolvedParamIndex] = Command; - return; - } - - SourceRange ArgRange(ArgLocBegin, ArgLocEnd); - Diag(ArgLocBegin, diag::warn_doc_param_not_found) - << Arg << ArgRange; - - // No parameters -- can't suggest a correction. - if (ParamVars.size() == 0) - return; - - unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex; - if (ParamVars.size() == 1) { - // If function has only one parameter then only that parameter - // can be documented. - CorrectedParamIndex = 0; - } else { - // Do typo correction. - CorrectedParamIndex = correctTypoInParmVarReference(Arg, ParamVars); - } - if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) { - const ParmVarDecl *CorrectedPVD = ParamVars[CorrectedParamIndex]; - if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier()) - Diag(ArgLocBegin, diag::note_doc_param_name_suggestion) - << CorrectedII->getName() - << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName()); - } - - return; } void Sema::actOnParamCommandFinish(ParamCommandComment *Command, @@ -202,14 +160,14 @@ void Sema::actOnParamCommandFinish(ParamCommandComment *Command, TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, - StringRef Name) { + unsigned CommandID) { TParamCommandComment *Command = - new (Allocator) TParamCommandComment(LocBegin, LocEnd, Name); + new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID); if (!isTemplateOrSpecialization()) Diag(Command->getLocation(), diag::warn_doc_tparam_not_attached_to_a_template_decl) - << Command->getCommandNameRange(); + << Command->getCommandNameRange(Traits); return Command; } @@ -285,19 +243,20 @@ void Sema::actOnTParamCommandFinish(TParamCommandComment *Command, InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, SourceLocation CommandLocEnd, - StringRef CommandName) { + unsigned CommandID) { ArrayRef<InlineCommandComment::Argument> Args; + StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; return new (Allocator) InlineCommandComment( CommandLocBegin, CommandLocEnd, - CommandName, + CommandID, getInlineCommandRenderKind(CommandName), Args); } InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, SourceLocation CommandLocEnd, - StringRef CommandName, + unsigned CommandID, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg) { @@ -305,21 +264,29 @@ InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, ArgLocEnd), Arg); + StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; return new (Allocator) InlineCommandComment( CommandLocBegin, CommandLocEnd, - CommandName, + CommandID, getInlineCommandRenderKind(CommandName), llvm::makeArrayRef(A, 1)); } InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, - StringRef Name) { + StringRef CommandName) { + unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID(); + return actOnUnknownCommand(LocBegin, LocEnd, CommandID); +} + +InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID) { ArrayRef<InlineCommandComment::Argument> Args; return new (Allocator) InlineCommandComment( - LocBegin, LocEnd, Name, + LocBegin, LocEnd, CommandID, InlineCommandComment::RenderNormal, Args); } @@ -331,11 +298,12 @@ TextComment *Sema::actOnText(SourceLocation LocBegin, } VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc, - StringRef Name) { + unsigned CommandID) { + StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; return new (Allocator) VerbatimBlockComment( Loc, - Loc.getLocWithOffset(1 + Name.size()), - Name); + Loc.getLocWithOffset(1 + CommandName.size()), + CommandID); } VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc, @@ -353,13 +321,13 @@ void Sema::actOnVerbatimBlockFinish( } VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin, - StringRef Name, + unsigned CommandID, SourceLocation TextBegin, StringRef Text) { return new (Allocator) VerbatimLineComment( LocBegin, TextBegin.getLocWithOffset(Text.size()), - Name, + CommandID, TextBegin, Text); } @@ -445,30 +413,35 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin, FullComment *Sema::actOnFullComment( ArrayRef<BlockContentComment *> Blocks) { - return new (Allocator) FullComment(Blocks, ThisDeclInfo); + FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo); + resolveParamCommandIndexes(FC); + return FC; } void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) { + if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed) + return; + ParagraphComment *Paragraph = Command->getParagraph(); if (Paragraph->isWhitespace()) { SourceLocation DiagLoc; if (Command->getNumArgs() > 0) DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd(); if (!DiagLoc.isValid()) - DiagLoc = Command->getCommandNameRange().getEnd(); + DiagLoc = Command->getCommandNameRange(Traits).getEnd(); Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph) - << Command->getCommandName() + << Command->getCommandName(Traits) << Command->getSourceRange(); } } void Sema::checkReturnsCommand(const BlockCommandComment *Command) { - if (!Traits.isReturnsCommand(Command->getCommandName())) + if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand) return; if (isFunctionDecl()) { if (ThisDeclInfo->ResultType->isVoidType()) { unsigned DiagKind; - switch (ThisDeclInfo->ThisDecl->getKind()) { + switch (ThisDeclInfo->CommentDecl->getKind()) { default: if (ThisDeclInfo->IsObjCMethod) DiagKind = 3; @@ -484,7 +457,7 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) { } Diag(Command->getLocation(), diag::warn_doc_returns_attached_to_a_void_function) - << Command->getCommandName() + << Command->getCommandName(Traits) << DiagKind << Command->getSourceRange(); } @@ -492,20 +465,20 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) { } Diag(Command->getLocation(), diag::warn_doc_returns_not_attached_to_a_function_decl) - << Command->getCommandName() + << Command->getCommandName(Traits) << Command->getSourceRange(); } void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { - StringRef Name = Command->getCommandName(); + const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID()); const BlockCommandComment *PrevCommand = NULL; - if (Traits.isBriefCommand(Name)) { + if (Info->IsBriefCommand) { if (!BriefCommand) { BriefCommand = Command; return; } PrevCommand = BriefCommand; - } else if (Traits.isReturnsCommand(Name)) { + } else if (Info->IsReturnsCommand) { if (!ReturnsCommand) { ReturnsCommand = Command; return; @@ -515,18 +488,153 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { // We don't want to check this command for duplicates. return; } + StringRef CommandName = Command->getCommandName(Traits); + StringRef PrevCommandName = PrevCommand->getCommandName(Traits); Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate) - << Name + << CommandName << Command->getSourceRange(); - if (Name == PrevCommand->getCommandName()) + if (CommandName == PrevCommandName) Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous) - << PrevCommand->getCommandName() - << Command->getSourceRange(); + << PrevCommandName + << PrevCommand->getSourceRange(); else Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous_alias) - << PrevCommand->getCommandName() - << Name; + << PrevCommandName + << CommandName; +} + +void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) { + if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand) + return; + + const Decl *D = ThisDeclInfo->CommentDecl; + if (!D) + return; + + if (D->hasAttr<DeprecatedAttr>() || + D->hasAttr<AvailabilityAttr>() || + D->hasAttr<UnavailableAttr>()) + return; + + Diag(Command->getLocation(), + diag::warn_doc_deprecated_not_sync) + << Command->getSourceRange(); + + // Try to emit a fixit with a deprecation attribute. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // Don't emit a Fix-It for non-member function definitions. GCC does not + // accept attributes on them. + const DeclContext *Ctx = FD->getDeclContext(); + if ((!Ctx || !Ctx->isRecord()) && + FD->doesThisDeclarationHaveABody()) + return; + + StringRef AttributeSpelling = "__attribute__((deprecated))"; + if (PP) { + TokenValue Tokens[] = { + tok::kw___attribute, tok::l_paren, tok::l_paren, + PP->getIdentifierInfo("deprecated"), + tok::r_paren, tok::r_paren + }; + StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), + Tokens); + if (!MacroName.empty()) + AttributeSpelling = MacroName; + } + + SmallString<64> TextToInsert(" "); + TextToInsert += AttributeSpelling; + Diag(FD->getLocEnd(), + diag::note_add_deprecation_attr) + << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1), + TextToInsert); + } +} + +void Sema::resolveParamCommandIndexes(const FullComment *FC) { + if (!isFunctionDecl()) { + // We already warned that \\param commands are not attached to a function + // decl. + return; + } + + llvm::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; + + ArrayRef<const ParmVarDecl *> ParamVars = getParamVars(); + ParamVarDocs.resize(ParamVars.size(), NULL); + + // First pass over all \\param commands: resolve all parameter names. + for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end(); + I != E; ++I) { + ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I); + if (!PCC || !PCC->hasParamName()) + continue; + StringRef ParamName = PCC->getParamNameAsWritten(); + + // Check that referenced parameter name is in the function decl. + const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName, + ParamVars); + if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) { + UnresolvedParamCommands.push_back(PCC); + continue; + } + PCC->setParamIndex(ResolvedParamIndex); + if (ParamVarDocs[ResolvedParamIndex]) { + SourceRange ArgRange = PCC->getParamNameRange(); + Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate) + << ParamName << ArgRange; + ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex]; + Diag(PrevCommand->getLocation(), diag::note_doc_param_previous) + << PrevCommand->getParamNameRange(); + } + ParamVarDocs[ResolvedParamIndex] = PCC; + } + + // Find parameter declarations that have no corresponding \\param. + llvm::SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls; + for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) { + if (!ParamVarDocs[i]) + OrphanedParamDecls.push_back(ParamVars[i]); + } + + // Second pass over unresolved \\param commands: do typo correction. + // Suggest corrections from a set of parameter declarations that have no + // corresponding \\param. + for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) { + const ParamCommandComment *PCC = UnresolvedParamCommands[i]; + + SourceRange ArgRange = PCC->getParamNameRange(); + StringRef ParamName = PCC->getParamNameAsWritten(); + Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found) + << ParamName << ArgRange; + + // All parameters documented -- can't suggest a correction. + if (OrphanedParamDecls.size() == 0) + continue; + + unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex; + if (OrphanedParamDecls.size() == 1) { + // If one parameter is not documented then that parameter is the only + // possible suggestion. + CorrectedParamIndex = 0; + } else { + // Do typo correction. + CorrectedParamIndex = correctTypoInParmVarReference(ParamName, + OrphanedParamDecls); + } + if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) { + const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex]; + if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier()) + Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion) + << CorrectedII->getName() + << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName()); + } + } } bool Sema::isFunctionDecl() { @@ -553,7 +661,6 @@ ArrayRef<const ParmVarDecl *> Sema::getParamVars() { void Sema::inspectThisDecl() { ThisDeclInfo->fill(); - ParamVarDocs.resize(ThisDeclInfo->ParamVars.size(), NULL); } unsigned Sema::resolveParmVarReference(StringRef Name, @@ -629,7 +736,7 @@ unsigned Sema::correctTypoInParmVarReference( if (Corrector.getBestDecl()) return Corrector.getBestDeclIndex(); else - return ParamCommandComment::InvalidParamIndex;; + return ParamCommandComment::InvalidParamIndex; } namespace { @@ -700,7 +807,7 @@ StringRef Sema::correctTypoInTParamReference( InlineCommandComment::RenderKind Sema::getInlineCommandRenderKind(StringRef Name) const { - assert(Traits.isInlineCommand(Name)); + assert(Traits.getCommandInfo(Name)->IsInlineCommand); return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name) .Case("b", InlineCommandComment::RenderBold) @@ -709,31 +816,6 @@ Sema::getInlineCommandRenderKind(StringRef Name) const { .Default(InlineCommandComment::RenderNormal); } -bool Sema::isHTMLEndTagOptional(StringRef Name) { - return llvm::StringSwitch<bool>(Name) - .Case("p", true) - .Case("li", true) - .Case("dt", true) - .Case("dd", true) - .Case("tr", true) - .Case("th", true) - .Case("td", true) - .Case("thead", true) - .Case("tfoot", true) - .Case("tbody", true) - .Case("colgroup", true) - .Default(false); -} - -bool Sema::isHTMLEndTagForbidden(StringRef Name) { - return llvm::StringSwitch<bool>(Name) - .Case("br", true) - .Case("hr", true) - .Case("img", true) - .Case("col", true) - .Default(false); -} - } // end namespace comments } // end namespace clang diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d5b0be3..7b13755 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -126,12 +126,12 @@ static LinkageInfo getLVForTemplateArgumentList(const TemplateArgument *Args, break; case TemplateArgument::Declaration: - // The decl can validly be null as the representation of nullptr - // arguments, valid only in C++0x. - if (Decl *D = Args[I].getAsDecl()) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) - LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate)); - } + if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl())) + LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate)); + break; + + case TemplateArgument::NullPtr: + LV.mergeWithMin(getLVForType(Args[I].getNullPtrType())); break; case TemplateArgument::Template: @@ -193,7 +193,7 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) { // anyway. return TSK != TSK_ExplicitInstantiationDeclaration && TSK != TSK_ExplicitInstantiationDefinition && - FD->hasBody(Def) && Def->isInlined(); + FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>(); } static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, @@ -213,12 +213,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (Var->getStorageClass() == SC_Static) return LinkageInfo::internal(); - // - an object or reference that is explicitly declared const - // and neither explicitly declared extern nor previously - // declared to have external linkage; or - // (there is no equivalent in C99) + // - a non-volatile object or reference that is explicitly declared const + // or constexpr and neither explicitly declared extern nor previously + // declared to have external linkage; or (there is no equivalent in C99) if (Context.getLangOpts().CPlusPlus && - Var->getType().isConstant(Context) && + Var->getType().isConstQualified() && + !Var->getType().isVolatileQualified() && Var->getStorageClass() != SC_Extern && Var->getStorageClass() != SC_PrivateExtern) { bool FoundExtern = false; @@ -236,8 +236,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, for (; PrevVar; PrevVar = PrevVar->getPreviousDecl()) if (PrevVar->getStorageClass() == SC_PrivateExtern) break; - if (PrevVar) - return PrevVar->getLinkageAndVisibility(); + if (PrevVar) + return PrevVar->getLinkageAndVisibility(); } } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { // C++ [temp]p4: @@ -341,25 +341,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (Var->getStorageClass() == SC_PrivateExtern) LV.mergeVisibility(HiddenVisibility, true); - if (!Context.getLangOpts().CPlusPlus && - (Var->getStorageClass() == SC_Extern || - Var->getStorageClass() == SC_PrivateExtern)) { - - // C99 6.2.2p4: - // For an identifier declared with the storage-class specifier - // extern in a scope in which a prior declaration of that - // 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 VarDecl *PrevVar = Var->getPreviousDecl()) { - LinkageInfo PrevLV = getLVForDecl(PrevVar, OnlyTemplate); - if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); - LV.mergeVisibility(PrevLV); - } - } + // 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. // - a function, unless it has internal linkage; or } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { @@ -841,13 +825,10 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) { if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility()) LV.mergeVisibility(*Vis, true); } - - if (const VarDecl *Prev = Var->getPreviousDecl()) { - LinkageInfo PrevLV = getLVForDecl(Prev, OnlyTemplate); - if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); - LV.mergeVisibility(PrevLV); - } + // 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; } } @@ -903,7 +884,7 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { const FunctionProtoType *FT = 0; if (FD->hasWrittenPrototype()) - FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>()); + FT = dyn_cast<FunctionProtoType>(FD->getType()->castAs<FunctionType>()); OS << *FD << '('; if (FT) { @@ -1204,8 +1185,11 @@ void VarDecl::setStorageClass(StorageClass SC) { } SourceRange VarDecl::getSourceRange() const { - if (getInit()) - return SourceRange(getOuterLocStart(), getInit()->getLocEnd()); + if (const Expr *Init = getInit()) { + SourceLocation InitEnd = Init->getLocEnd(); + if (InitEnd.isValid()) + return SourceRange(getOuterLocStart(), InitEnd); + } return DeclaratorDecl::getSourceRange(); } @@ -1859,7 +1843,7 @@ unsigned FunctionDecl::getBuiltinID() const { /// based on its FunctionType. This is the length of the ParamInfo array /// after it has been created. unsigned FunctionDecl::getNumParams() const { - const FunctionType *FT = getType()->getAs<FunctionType>(); + const FunctionType *FT = getType()->castAs<FunctionType>(); if (isa<FunctionNoProtoType>(FT)) return 0; return cast<FunctionProtoType>(FT)->getNumArgs(); @@ -2514,7 +2498,7 @@ unsigned FieldDecl::getFieldIndex() const { unsigned Index = 0; const RecordDecl *RD = getParent(); const FieldDecl *LastFD = 0; - bool IsMsStruct = RD->hasAttr<MsStructAttr>(); + bool IsMsStruct = RD->isMsStruct(getASTContext()); for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++Index) { @@ -2762,6 +2746,17 @@ void RecordDecl::completeDefinition() { TagDecl::completeDefinition(); } +/// isMsStruct - Get whether or not this record uses ms_struct layout. +/// This which can be turned on with an attribute, pragma, or the +/// -mms-bitfields command-line option. +bool RecordDecl::isMsStruct(const ASTContext &C) const { + return hasAttr<MsStructAttr>() || C.getLangOpts().MSBitfields == 1; +} + +static bool isFieldOrIndirectField(Decl::Kind K) { + return FieldDecl::classofKind(K) || IndirectFieldDecl::classofKind(K); +} + void RecordDecl::LoadFieldsFromExternalStorage() const { ExternalASTSource *Source = getASTContext().getExternalSource(); assert(hasExternalLexicalStorage() && Source && "No external storage?"); @@ -2771,7 +2766,8 @@ void RecordDecl::LoadFieldsFromExternalStorage() const { SmallVector<Decl*, 64> Decls; LoadedFieldsFromExternalStorage = true; - switch (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls)) { + switch (Source->FindExternalLexicalDecls(this, isFieldOrIndirectField, + Decls)) { case ELR_Success: break; @@ -2783,7 +2779,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const { #ifndef NDEBUG // Check that all decls we got were FieldDecls. for (unsigned i=0, e=Decls.size(); i != e; ++i) - assert(isa<FieldDecl>(Decls[i])); + assert(isa<FieldDecl>(Decls[i]) || isa<IndirectFieldDecl>(Decls[i])); #endif if (Decls.empty()) diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index f9ce46d..4400d50 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -961,7 +961,7 @@ DeclContext::lookup_result ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, DeclarationName Name, ArrayRef<NamedDecl*> Decls) { - ASTContext &Context = DC->getParentASTContext();; + ASTContext &Context = DC->getParentASTContext(); StoredDeclsMap *Map; if (!(Map = DC->LookupPtr.getPointer())) diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 2f21e4c..82e630a 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -90,11 +90,12 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, } CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, - SourceLocation Loc, bool Dependent) { + TypeSourceInfo *Info, SourceLocation Loc, + bool Dependent) { CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc, 0, 0); R->IsBeingDefined = true; - R->DefinitionData = new (C) struct LambdaDefinitionData(R, Dependent); + R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent); C.getTypeDeclType(R, /*PrevDecl=*/0); return R; } @@ -239,10 +240,13 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // -- 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. + // 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()) + if (!BaseClassDecl->hasTrivialMoveConstructor() || + !(BaseClassDecl->hasDeclaredMoveConstructor() || + BaseClassDecl->needsImplicitMoveConstructor())) data().HasTrivialMoveConstructor = false; // C++0x [class.copy]p27: @@ -254,7 +258,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // of all of them. if (!BaseClassDecl->hasTrivialCopyAssignment()) data().HasTrivialCopyAssignment = false; - if (!BaseClassDecl->hasTrivialMoveAssignment()) + if (!BaseClassDecl->hasTrivialMoveAssignment() || + !(BaseClassDecl->hasDeclaredMoveAssignment() || + BaseClassDecl->needsImplicitMoveAssignment())) data().HasTrivialMoveAssignment = false; // C++11 [class.ctor]p6: @@ -466,7 +472,8 @@ void CXXRecordDecl::addedMember(Decl *D) { if (!D->isImplicit() && !isa<FieldDecl>(D) && !isa<IndirectFieldDecl>(D) && - (!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class)) + (!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class || + cast<TagDecl>(D)->getTagKind() == TTK_Interface)) data().HasOnlyCMembers = false; // Ignore friends and invalid declarations. @@ -828,7 +835,9 @@ NotASpecialMember:; // FIXME: C++0x: We don't correctly model 'selected' constructors. if (!FieldRec->hasTrivialCopyConstructor()) data().HasTrivialCopyConstructor = false; - if (!FieldRec->hasTrivialMoveConstructor()) + if (!FieldRec->hasTrivialMoveConstructor() || + !(FieldRec->hasDeclaredMoveConstructor() || + FieldRec->needsImplicitMoveConstructor())) data().HasTrivialMoveConstructor = false; // C++0x [class.copy]p27: @@ -840,7 +849,9 @@ NotASpecialMember:; // FIXME: C++0x: We don't correctly model 'selected' operators. if (!FieldRec->hasTrivialCopyAssignment()) data().HasTrivialCopyAssignment = false; - if (!FieldRec->hasTrivialMoveAssignment()) + if (!FieldRec->hasTrivialMoveAssignment() || + !(FieldRec->hasDeclaredMoveAssignment() || + FieldRec->needsImplicitMoveAssignment())) data().HasTrivialMoveAssignment = false; if (!FieldRec->hasTrivialDestructor()) @@ -936,7 +947,8 @@ NotASpecialMember:; } bool CXXRecordDecl::isCLike() const { - if (getTagKind() == TTK_Class || !TemplateOrInstantiation.isNull()) + if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface || + !TemplateOrInstantiation.isNull()) return false; if (!hasDefinition()) return true; diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 4d48ad8..65a9878 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Stmt.h" #include "clang/AST/ASTMutationListener.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -93,6 +94,16 @@ ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC, return 0; } +IdentifierInfo * +ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const { + SmallString<128> ivarName; + { + llvm::raw_svector_ostream os(ivarName); + os << '_' << getIdentifier()->getName(); + } + return &Ctx.Idents.get(ivarName.str()); +} + /// FindPropertyDeclaration - Finds declaration of the property given its name /// in 'PropertyId' and returns it. It returns 0, if not found. ObjCPropertyDecl * @@ -179,6 +190,21 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( return 0; } +void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM) const { + for (ObjCContainerDecl::prop_iterator P = prop_begin(), + E = prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = *P; + PM[Prop->getIdentifier()] = Prop; + } + for (ObjCInterfaceDecl::all_protocol_iterator + PI = all_referenced_protocol_begin(), + E = all_referenced_protocol_end(); PI != E; ++PI) + (*PI)->collectPropertiesToImplement(PM); + // Note, the properties declared only in class extensions are still copied + // into the main @interface's property list, and therefore we don't + // explicitly, have to search class extension properties. +} + void ObjCInterfaceDecl::mergeClassExtensionProtocolList( ObjCProtocolDecl *const* ExtList, unsigned ExtNum, ASTContext &C) @@ -414,16 +440,15 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, DeclContext *contextDecl, bool isInstance, bool isVariadic, - bool isSynthesized, + bool isPropertyAccessor, bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl, bool HasRelatedResultType) { return new (C) ObjCMethodDecl(beginLoc, endLoc, SelInfo, T, ResultTInfo, contextDecl, - isInstance, - isVariadic, isSynthesized, isImplicitlyDeclared, - isDefined, + isInstance, isVariadic, isPropertyAccessor, + isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType); } @@ -434,6 +459,10 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { Selector(), QualType(), 0, 0); } +Stmt *ObjCMethodDecl::getBody() const { + return Body.get(getASTContext().getExternalSource()); +} + void ObjCMethodDecl::setAsRedeclaration(const ObjCMethodDecl *PrevMethod) { assert(PrevMethod); getASTContext().setObjCMethodRedeclaration(PrevMethod, this); @@ -707,6 +736,224 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { llvm_unreachable("unknown method context"); } +static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, + const ObjCMethodDecl *Method, + SmallVectorImpl<const ObjCMethodDecl *> &Methods, + bool MovedToSuper) { + if (!Container) + return; + + // In categories look for overriden methods from protocols. A method from + // category is not "overriden" since it is considered as the "same" method + // (same USR) as the one from the interface. + if (const ObjCCategoryDecl * + Category = dyn_cast<ObjCCategoryDecl>(Container)) { + // Check whether we have a matching method at this category but only if we + // are at the super class level. + if (MovedToSuper) + if (ObjCMethodDecl * + Overridden = Container->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + if (Method != Overridden) { + // We found an override at this category; there is no need to look + // into its protocols. + Methods.push_back(Overridden); + return; + } + + for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(), + PEnd = Category->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); + return; + } + + // Check whether we have a matching method at this level. + if (const ObjCMethodDecl * + Overridden = Container->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + if (Method != Overridden) { + // We found an override at this level; there is no need to look + // into other protocols or categories. + Methods.push_back(Overridden); + return; + } + + if (const ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)){ + for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(), + PEnd = Protocol->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); + } + + if (const ObjCInterfaceDecl * + Interface = dyn_cast<ObjCInterfaceDecl>(Container)) { + for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(), + PEnd = Interface->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); + + for (const ObjCCategoryDecl *Category = Interface->getCategoryList(); + Category; Category = Category->getNextClassCategory()) + CollectOverriddenMethodsRecurse(Category, Method, Methods, + MovedToSuper); + + if (const ObjCInterfaceDecl *Super = Interface->getSuperClass()) + return CollectOverriddenMethodsRecurse(Super, Method, Methods, + /*MovedToSuper=*/true); + } +} + +static inline void CollectOverriddenMethods(const ObjCContainerDecl *Container, + const ObjCMethodDecl *Method, + SmallVectorImpl<const ObjCMethodDecl *> &Methods) { + CollectOverriddenMethodsRecurse(Container, Method, Methods, + /*MovedToSuper=*/false); +} + +static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, + SmallVectorImpl<const ObjCMethodDecl *> &overridden) { + assert(Method->isOverriding()); + + if (const ObjCProtocolDecl * + ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) { + CollectOverriddenMethods(ProtD, Method, overridden); + + } else if (const ObjCImplDecl * + IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) { + const ObjCInterfaceDecl *ID = IMD->getClassInterface(); + if (!ID) + return; + // 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 = IFaceMeth; + CollectOverriddenMethods(ID, Method, overridden); + + } else if (const ObjCCategoryDecl * + CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) { + const ObjCInterfaceDecl *ID = CatD->getClassInterface(); + if (!ID) + return; + // 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 = IFaceMeth; + CollectOverriddenMethods(ID, Method, overridden); + + } else { + CollectOverriddenMethods( + dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()), + Method, overridden); + } +} + +static void collectOnCategoriesAfterLocation(SourceLocation Loc, + const ObjCInterfaceDecl *Class, + SourceManager &SM, + const ObjCMethodDecl *Method, + SmallVectorImpl<const ObjCMethodDecl *> &Methods) { + if (!Class) + return; + + for (const ObjCCategoryDecl *Category = Class->getCategoryList(); + Category; Category = Category->getNextClassCategory()) + if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation())) + CollectOverriddenMethodsRecurse(Category, Method, Methods, true); + + collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM, + Method, Methods); +} + +/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding() +/// returns false. +/// You'd think that in that case there are no overrides but categories can +/// "introduce" new overridden methods that are missed by Sema because the +/// overrides lookup that it does for methods, inside implementations, will +/// stop at the interface level (if there is a method there) and not look +/// further in super classes. +/// Methods in an implementation can overide methods in super class's category +/// but not in current class's category. But, such methods +static void collectOverriddenMethodsFast(SourceManager &SM, + const ObjCMethodDecl *Method, + SmallVectorImpl<const ObjCMethodDecl *> &Methods) { + assert(!Method->isOverriding()); + + const ObjCContainerDecl * + ContD = cast<ObjCContainerDecl>(Method->getDeclContext()); + if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD)) + return; + const ObjCInterfaceDecl *Class = Method->getClassInterface(); + if (!Class) + return; + + collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(), + SM, Method, Methods); +} + +void ObjCMethodDecl::getOverriddenMethods( + SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const { + const ObjCMethodDecl *Method = this; + + if (Method->isRedeclaration()) { + Method = cast<ObjCContainerDecl>(Method->getDeclContext())-> + getMethod(Method->getSelector(), Method->isInstanceMethod()); + } + + if (!Method->isOverriding()) { + collectOverriddenMethodsFast(getASTContext().getSourceManager(), + Method, Overridden); + } else { + collectOverriddenMethodsSlow(Method, Overridden); + assert(!Overridden.empty() && + "ObjCMethodDecl's overriding bit is not as expected"); + } +} + +const ObjCPropertyDecl * +ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { + Selector Sel = getSelector(); + unsigned NumArgs = Sel.getNumArgs(); + if (NumArgs > 1) + return 0; + + if (!isInstanceMethod() || getMethodFamily() != OMF_None) + return 0; + + if (isPropertyAccessor()) { + const ObjCContainerDecl *Container = cast<ObjCContainerDecl>(getParent()); + bool IsGetter = (NumArgs == 0); + + for (ObjCContainerDecl::prop_iterator I = Container->prop_begin(), + E = Container->prop_end(); + I != E; ++I) { + Selector NextSel = IsGetter ? (*I)->getGetterName() + : (*I)->getSetterName(); + if (NextSel == Sel) + return *I; + } + + llvm_unreachable("Marked as a property accessor but no property found!"); + } + + if (!CheckOverrides) + return 0; + + typedef SmallVector<const ObjCMethodDecl *, 8> OverridesTy; + OverridesTy Overrides; + getOverriddenMethods(Overrides); + for (OverridesTy::const_iterator I = Overrides.begin(), E = Overrides.end(); + I != E; ++I) { + if (const ObjCPropertyDecl *Prop = (*I)->findPropertyDecl(false)) + return Prop; + } + + return 0; + +} + //===----------------------------------------------------------------------===// // ObjCInterfaceDecl //===----------------------------------------------------------------------===// @@ -1081,6 +1328,20 @@ 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)); + } + // Scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = protocol_begin(), + E = protocol_end(); PI != E; ++PI) + (*PI)->collectPropertiesToImplement(PM); +} + + //===----------------------------------------------------------------------===// // ObjCCategoryDecl //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 7f47604..386ad66 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -105,6 +105,8 @@ static QualType GetBaseType(QualType T) { break; else if (const PointerType* PTy = BaseType->getAs<PointerType>()) BaseType = PTy->getPointeeType(); + else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>()) + BaseType = BPy->getPointeeType(); else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType)) BaseType = ATy->getElementType(); else if (const FunctionType* FTy = BaseType->getAs<FunctionType>()) @@ -189,6 +191,9 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) { } void DeclPrinter::prettyPrintAttributes(Decl *D) { + if (Policy.SuppressAttributes) + return; + if (D->hasAttrs()) { AttrVec &Attrs = D->getAttrs(); for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) { @@ -220,6 +225,9 @@ void DeclPrinter::Print(AccessSpecifier AS) { //---------------------------------------------------------------------------- void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { + if (Policy.TerseOutput) + return; + if (Indent) Indentation += Policy.Indentation; @@ -459,7 +467,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (I) Proto += ", "; - Proto += FT->getExceptionType(I).getAsString(SubPolicy);; + Proto += FT->getExceptionType(I).getAsString(SubPolicy); } Proto += ")"; } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) { @@ -550,7 +558,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Out << " = 0"; else if (D->isDeletedAsWritten()) Out << " = delete"; - else if (D->doesThisDeclarationHaveABody()) { + else if (D->doesThisDeclarationHaveABody() && !Policy.TerseOutput) { if (!D->hasPrototype() && D->getNumParams()) { // This is a K&R function definition, so we need to print the // parameters. @@ -621,13 +629,13 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { ImplicitInit = D->getInitStyle() == VarDecl::CallInit && Construct->getNumArgs() == 0 && !Construct->isListInitialization(); if (!ImplicitInit) { - if (D->getInitStyle() == VarDecl::CallInit) + if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init)) Out << "("; else if (D->getInitStyle() == VarDecl::CInit) { Out << " = "; } Init->printPretty(Out, 0, Policy, Indentation); - if (D->getInitStyle() == VarDecl::CallInit) + if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init)) Out << ")"; } } @@ -869,7 +877,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { if (OMD->isVariadic()) Out << ", ..."; - if (OMD->getBody()) { + if (OMD->getBody() && !Policy.TerseOutput) { Out << ' '; OMD->getBody()->printPretty(Out, 0, Policy); Out << '\n'; diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index a7e8999..a70983f 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -32,9 +32,25 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, NamedDecl **Params, unsigned NumParams, SourceLocation RAngleLoc) : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), - NumParams(NumParams) { - for (unsigned Idx = 0; Idx < NumParams; ++Idx) - begin()[Idx] = Params[Idx]; + NumParams(NumParams), ContainsUnexpandedParameterPack(false) { + assert(this->NumParams == NumParams && "Too many template parameters"); + for (unsigned Idx = 0; Idx < NumParams; ++Idx) { + NamedDecl *P = Params[Idx]; + begin()[Idx] = P; + + if (!P->isTemplateParameterPack()) { + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) + if (NTTP->getType()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) + if (TTP->getTemplateParameters()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + + // FIXME: If a default argument contains an unexpanded parameter pack, the + // template parameter list does too. + } + } } TemplateParameterList * @@ -577,6 +593,19 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { void TemplateTemplateParmDecl::anchor() { } +TemplateTemplateParmDecl::TemplateTemplateParmDecl( + DeclContext *DC, SourceLocation L, unsigned D, unsigned P, + IdentifierInfo *Id, TemplateParameterList *Params, + unsigned NumExpansions, TemplateParameterList * const *Expansions) + : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), + TemplateParmPosition(D, P), DefaultArgument(), + DefaultArgumentWasInherited(false), ParameterPack(true), + ExpandedParameterPack(true), NumExpandedParams(NumExpansions) { + if (Expansions) + std::memcpy(reinterpret_cast<void*>(this + 1), Expansions, + sizeof(TemplateParameterList*) * NumExpandedParams); +} + TemplateTemplateParmDecl * TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, @@ -587,12 +616,35 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, } TemplateTemplateParmDecl * +TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, unsigned P, + IdentifierInfo *Id, + TemplateParameterList *Params, + llvm::ArrayRef<TemplateParameterList*> Expansions) { + void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) + + sizeof(TemplateParameterList*) * Expansions.size()); + return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params, + Expansions.size(), + Expansions.data()); +} + +TemplateTemplateParmDecl * TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTemplateParmDecl)); return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, false, 0, 0); } +TemplateTemplateParmDecl * +TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumExpansions) { + unsigned Size = sizeof(TemplateTemplateParmDecl) + + sizeof(TemplateParameterList*) * NumExpansions; + void *Mem = AllocateDeserializedDecl(C, ID, Size); + return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, 0, 0, + NumExpansions, 0); +} + //===----------------------------------------------------------------------===// // TemplateArgumentList Implementation //===----------------------------------------------------------------------===// @@ -712,13 +764,27 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const { SourceRange ClassTemplateSpecializationDecl::getSourceRange() const { if (ExplicitInfo) { - SourceLocation Begin = getExternLoc(); - if (Begin.isInvalid()) - Begin = getTemplateKeywordLoc(); - SourceLocation End = getRBraceLoc(); - if (End.isInvalid()) - End = getTypeAsWritten()->getTypeLoc().getEndLoc(); - return SourceRange(Begin, End); + SourceLocation Begin = getTemplateKeywordLoc(); + if (Begin.isValid()) { + // Here we have an explicit (partial) specialization or instantiation. + assert(getSpecializationKind() == TSK_ExplicitSpecialization || + getSpecializationKind() == TSK_ExplicitInstantiationDeclaration || + getSpecializationKind() == TSK_ExplicitInstantiationDefinition); + if (getExternLoc().isValid()) + Begin = getExternLoc(); + SourceLocation End = getRBraceLoc(); + if (End.isInvalid()) + End = getTypeAsWritten()->getTypeLoc().getEndLoc(); + return SourceRange(Begin, End); + } + // An implicit instantiation of a class template partial specialization + // uses ExplicitInfo to record the TypeAsWritten, but the source + // locations should be retrieved from the instantiation pattern. + typedef ClassTemplatePartialSpecializationDecl CTPSDecl; + CTPSDecl *ctpsd = const_cast<CTPSDecl*>(cast<CTPSDecl>(this)); + CTPSDecl *inst_from = ctpsd->getInstantiatedFromMember(); + assert(inst_from != 0); + return inst_from->getSourceRange(); } else { // No explicit info available. diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp index 84f3fc4..5f43fbc 100644 --- a/lib/AST/DumpXML.cpp +++ b/lib/AST/DumpXML.cpp @@ -1,4 +1,4 @@ -//===--- DumpXML.cpp - Detailed XML dumping ---------------------*- C++ -*-===// +//===--- DumpXML.cpp - Detailed XML dumping -------------------------------===// // // The LLVM Compiler Infrastructure // @@ -64,6 +64,8 @@ template <class Impl> struct XMLDeclVisitor { static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(D)) void dispatch(Decl *D) { + if (D->isUsed()) + static_cast<Impl*>(this)->set("used", "1"); switch (D->getKind()) { #define DECL(DERIVED, BASE) \ case Decl::DERIVED: \ @@ -316,12 +318,12 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, } case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: + case TemplateArgument::NullPtr: // FIXME: Implement! break; case TemplateArgument::Declaration: { - if (Decl *D = A.getAsDecl()) - visitDeclRef(D); + visitDeclRef(A.getAsDecl()); break; } case TemplateArgument::Integral: { @@ -841,7 +843,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, setFlag("instance", D->isInstanceMethod()); setFlag("variadic", D->isVariadic()); - setFlag("synthesized", D->isSynthesized()); + setFlag("property_accessor", D->isPropertyAccessor()); setFlag("defined", D->isDefined()); setFlag("related_result_type", D->hasRelatedResultType()); } @@ -920,6 +922,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, case CC_X86Pascal: return set("cc", "x86_pascal"); case CC_AAPCS: return set("cc", "aapcs"); case CC_AAPCS_VFP: return set("cc", "aapcs_vfp"); + case CC_PnaclCall: return set("cc", "pnaclcall"); } } @@ -974,6 +977,16 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, setFlag("const", T->isConst()); setFlag("volatile", T->isVolatile()); setFlag("restrict", T->isRestrict()); + switch (T->getExceptionSpecType()) { + case EST_None: break; + case EST_DynamicNone: set("exception_spec", "throw()"); break; + case EST_Dynamic: set("exception_spec", "throw(T)"); break; + case EST_MSAny: set("exception_spec", "throw(...)"); break; + case EST_BasicNoexcept: set("exception_spec", "noexcept"); break; + case EST_ComputedNoexcept: set("exception_spec", "noexcept(expr)"); break; + case EST_Unevaluated: set("exception_spec", "unevaluated"); break; + case EST_Uninstantiated: set("exception_spec", "uninstantiated"); break; + } } void visitFunctionProtoTypeChildren(FunctionProtoType *T) { push("parameters"); @@ -1023,7 +1036,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, } void Decl::dumpXML() const { - dump(llvm::errs()); + dumpXML(llvm::errs()); } void Decl::dumpXML(raw_ostream &out) const { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 24361ef..f3a2e05 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -48,6 +48,75 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const { return cast<CXXRecordDecl>(D); } +const Expr * +Expr::skipRValueSubobjectAdjustments( + SmallVectorImpl<SubobjectAdjustment> &Adjustments) const { + const Expr *E = this; + while (true) { + E = E->IgnoreParens(); + + if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { + if ((CE->getCastKind() == CK_DerivedToBase || + CE->getCastKind() == CK_UncheckedDerivedToBase) && + E->getType()->isRecordType()) { + E = CE->getSubExpr(); + CXXRecordDecl *Derived + = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); + Adjustments.push_back(SubobjectAdjustment(CE, Derived)); + continue; + } + + if (CE->getCastKind() == CK_NoOp) { + E = CE->getSubExpr(); + continue; + } + } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + if (!ME->isArrow() && ME->getBase()->isRValue()) { + assert(ME->getBase()->getType()->isRecordType()); + if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) { + E = ME->getBase(); + Adjustments.push_back(SubobjectAdjustment(Field)); + continue; + } + } + } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + if (BO->isPtrMemOp()) { + assert(BO->getRHS()->isRValue()); + E = BO->getLHS(); + const MemberPointerType *MPT = + BO->getRHS()->getType()->getAs<MemberPointerType>(); + Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS())); + } + } + + // Nothing changed. + break; + } + return E; +} + +const Expr * +Expr::findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const { + const Expr *E = this; + // Look through single-element init lists that claim to be lvalues. They're + // just syntactic wrappers in this case. + if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) { + if (ILE->getNumInits() == 1 && ILE->isGLValue()) + E = ILE->getInit(0); + } + + // Look through expressions for materialized temporaries (for now). + if (const MaterializeTemporaryExpr *M + = dyn_cast<MaterializeTemporaryExpr>(E)) { + MTE = M; + E = M->GetTemporaryExpr(); + } + + if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E)) + E = DAE->getExpr(); + return E; +} + /// isKnownToHaveBooleanValue - Return true if this is an integer expression /// that is known to return 0 or 1. This happens for _Bool/bool expressions /// but also int expressions which are produced by things like comparisons in @@ -784,19 +853,19 @@ void StringLiteral::setString(ASTContext &C, StringRef Str, switch(CharByteWidth) { case 1: { char *AStrData = new (C) char[Length]; - std::memcpy(AStrData,Str.data(),Str.size()); + std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData)); StrData.asChar = AStrData; break; } case 2: { uint16_t *AStrData = new (C) uint16_t[Length]; - std::memcpy(AStrData,Str.data(),Str.size()); + std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData)); StrData.asUInt16 = AStrData; break; } case 4: { uint32_t *AStrData = new (C) uint32_t[Length]; - std::memcpy(AStrData,Str.data(),Str.size()); + std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData)); StrData.asUInt32 = AStrData; break; } @@ -869,7 +938,7 @@ getLocationOfByte(unsigned ByteNo, const SourceManager &SM, /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "sizeof" or "[pre]++". -const char *UnaryOperator::getOpcodeStr(Opcode Op) { +StringRef UnaryOperator::getOpcodeStr(Opcode Op) { switch (Op) { case UO_PostInc: return "++"; case UO_PostDec: return "--"; @@ -923,18 +992,18 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { //===----------------------------------------------------------------------===// CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, - Expr **args, unsigned numargs, QualType t, ExprValueKind VK, + ArrayRef<Expr*> args, QualType t, ExprValueKind VK, SourceLocation rparenloc) : Expr(SC, t, VK, OK_Ordinary, fn->isTypeDependent(), fn->isValueDependent(), fn->isInstantiationDependent(), fn->containsUnexpandedParameterPack()), - NumArgs(numargs) { + NumArgs(args.size()) { - SubExprs = new (C) Stmt*[numargs+PREARGS_START+NumPreArgs]; + SubExprs = new (C) Stmt*[args.size()+PREARGS_START+NumPreArgs]; SubExprs[FN] = fn; - for (unsigned i = 0; i != numargs; ++i) { + for (unsigned i = 0; i != args.size(); ++i) { if (args[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) @@ -951,18 +1020,18 @@ CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, RParenLoc = rparenloc; } -CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, +CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t, ExprValueKind VK, SourceLocation rparenloc) : Expr(CallExprClass, t, VK, OK_Ordinary, fn->isTypeDependent(), fn->isValueDependent(), fn->isInstantiationDependent(), fn->containsUnexpandedParameterPack()), - NumArgs(numargs) { + NumArgs(args.size()) { - SubExprs = new (C) Stmt*[numargs+PREARGS_START]; + SubExprs = new (C) Stmt*[args.size()+PREARGS_START]; SubExprs[FN] = fn; - for (unsigned i = 0; i != numargs; ++i) { + for (unsigned i = 0; i != args.size(); ++i) { if (args[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) @@ -1123,15 +1192,15 @@ SourceLocation CallExpr::getLocEnd() const { OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, - OffsetOfNode* compsPtr, unsigned numComps, - Expr** exprsPtr, unsigned numExprs, + ArrayRef<OffsetOfNode> comps, + ArrayRef<Expr*> exprs, SourceLocation RParenLoc) { void *Mem = C.Allocate(sizeof(OffsetOfExpr) + - sizeof(OffsetOfNode) * numComps + - sizeof(Expr*) * numExprs); + sizeof(OffsetOfNode) * comps.size() + + sizeof(Expr*) * exprs.size()); - return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, compsPtr, numComps, - exprsPtr, numExprs, RParenLoc); + return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, comps, exprs, + RParenLoc); } OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, @@ -1144,8 +1213,7 @@ OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, - OffsetOfNode* compsPtr, unsigned numComps, - Expr** exprsPtr, unsigned numExprs, + ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs, SourceLocation RParenLoc) : Expr(OffsetOfExprClass, type, VK_RValue, OK_Ordinary, /*TypeDependent=*/false, @@ -1153,19 +1221,19 @@ OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, tsi->getType()->isInstantiationDependentType(), tsi->getType()->containsUnexpandedParameterPack()), OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi), - NumComps(numComps), NumExprs(numExprs) + NumComps(comps.size()), NumExprs(exprs.size()) { - for(unsigned i = 0; i < numComps; ++i) { - setComponent(i, compsPtr[i]); + for (unsigned i = 0; i != comps.size(); ++i) { + setComponent(i, comps[i]); } - for(unsigned i = 0; i < numExprs; ++i) { - if (exprsPtr[i]->isTypeDependent() || exprsPtr[i]->isValueDependent()) + for (unsigned i = 0; i != exprs.size(); ++i) { + if (exprs[i]->isTypeDependent() || exprs[i]->isValueDependent()) ExprBits.ValueDependent = true; - if (exprsPtr[i]->containsUnexpandedParameterPack()) + if (exprs[i]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; - setIndexExpr(i, exprsPtr[i]); + setIndexExpr(i, exprs[i]); } } @@ -1259,9 +1327,12 @@ SourceLocation MemberExpr::getLocStart() const { return MemberLoc; } SourceLocation MemberExpr::getLocEnd() const { + SourceLocation EndLoc = getMemberNameInfo().getEndLoc(); if (hasExplicitTemplateArgs()) - return getRAngleLoc(); - return getMemberNameInfo().getEndLoc(); + EndLoc = getRAngleLoc(); + else if (EndLoc.isInvalid()) + EndLoc = getBase()->getLocEnd(); + return EndLoc; } void CastExpr::CheckCastConsistency() const { @@ -1311,12 +1382,16 @@ void CastExpr::CheckCastConsistency() const { assert(getType()->isBlockPointerType()); assert(getSubExpr()->getType()->isBlockPointerType()); goto CheckNoBasePath; - + + case CK_FunctionToPointerDecay: + assert(getType()->isPointerType()); + assert(getSubExpr()->getType()->isFunctionType()); + goto CheckNoBasePath; + // These should not have an inheritance path. case CK_Dynamic: case CK_ToUnion: case CK_ArrayToPointerDecay: - case CK_FunctionToPointerDecay: case CK_NullToMemberPointer: case CK_NullToPointer: case CK_ConstructorConversion: @@ -1357,6 +1432,7 @@ void CastExpr::CheckCastConsistency() const { case CK_IntegralComplexToBoolean: case CK_LValueBitCast: // -> bool& case CK_UserDefinedConversion: // operator bool() + case CK_BuiltinFnToFnPtr: CheckNoBasePath: assert(path_empty() && "Cast kind should not have a base path!"); break; @@ -1469,6 +1545,8 @@ const char *CastExpr::getCastKindName() const { return "NonAtomicToAtomic"; case CK_CopyAndAutoreleaseBlockObject: return "CopyAndAutoreleaseBlockObject"; + case CK_BuiltinFnToFnPtr: + return "BuiltinFnToFnPtr"; } llvm_unreachable("Unhandled cast kind!"); @@ -1564,7 +1642,7 @@ CStyleCastExpr *CStyleCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". -const char *BinaryOperator::getOpcodeStr(Opcode Op) { +StringRef BinaryOperator::getOpcodeStr(Opcode Op) { switch (Op) { case BO_PtrMemD: return ".*"; case BO_PtrMemI: return "->*"; @@ -1666,16 +1744,15 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { } InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, - Expr **initExprs, unsigned numInits, - SourceLocation rbraceloc) + ArrayRef<Expr*> initExprs, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, false, false), - InitExprs(C, numInits), - LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0) + InitExprs(C, initExprs.size()), + LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true) { sawArrayRangeDesignator(false); setInitializesStdInitializerList(false); - for (unsigned I = 0; I != numInits; ++I) { + for (unsigned I = 0; I != initExprs.size(); ++I) { if (initExprs[I]->isTypeDependent()) ExprBits.TypeDependent = true; if (initExprs[I]->isValueDependent()) @@ -1686,7 +1763,7 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, ExprBits.ContainsUnexpandedParameterPack = true; } - InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits); + InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end()); } void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) { @@ -1723,15 +1800,15 @@ void InitListExpr::setArrayFiller(Expr *filler) { bool InitListExpr::isStringLiteralInit() const { if (getNumInits() != 1) return false; - const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(getType()); - if (!CAT || !CAT->getElementType()->isIntegerType()) + const ArrayType *AT = getType()->getAsArrayTypeUnsafe(); + if (!AT || !AT->getElementType()->isIntegerType()) return false; - const Expr *Init = getInit(0)->IgnoreParenImpCasts(); + const Expr *Init = getInit(0)->IgnoreParens(); return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init); } SourceRange InitListExpr::getSourceRange() const { - if (SyntacticForm) + if (InitListExpr *SyntacticForm = getSyntacticForm()) return SyntacticForm->getSourceRange(); SourceLocation Beg = LBraceLoc, End = RBraceLoc; if (Beg.isInvalid()) { @@ -1945,6 +2022,11 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, return false; } + // If we don't know precisely what we're looking at, let's not warn. + case UnresolvedLookupExprClass: + case CXXUnresolvedConstructExprClass: + return false; + case CXXTemporaryObjectExprClass: case CXXConstructExprClass: return false; @@ -2014,6 +2096,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, R1 = getSourceRange(); return true; } + case CXXFunctionalCastExprClass: case CStyleCastExprClass: { // Ignore an explicit cast to void unless the operand is a non-trivial // volatile lvalue. @@ -2032,6 +2115,10 @@ 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) @@ -2641,6 +2728,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case UnresolvedMemberExprClass: case PackExpansionExprClass: case SubstNonTypeTemplateParmPackExprClass: + case FunctionParmPackExprClass: llvm_unreachable("shouldn't see dependent / unresolved nodes here"); case DeclRefExprClass: @@ -2995,6 +3083,24 @@ const ObjCPropertyRefExpr *Expr::getObjCProperty() const { return cast<ObjCPropertyRefExpr>(E); } +bool Expr::isObjCSelfExpr() const { + const Expr *E = IgnoreParenImpCasts(); + + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E); + if (!DRE) + return false; + + const ImplicitParamDecl *Param = dyn_cast<ImplicitParamDecl>(DRE->getDecl()); + if (!Param) + return false; + + const ObjCMethodDecl *M = dyn_cast<ObjCMethodDecl>(Param->getDeclContext()); + if (!M) + return false; + + return M->getSelfDecl() == Param; +} + FieldDecl *Expr::getBitField() { Expr *E = this->IgnoreParens(); @@ -3339,33 +3445,29 @@ Selector ObjCMessageExpr::getSelector() const { return Selector(SelectorOrMethod); } -ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { +QualType ObjCMessageExpr::getReceiverType() const { switch (getReceiverKind()) { case Instance: - if (const ObjCObjectPointerType *Ptr - = getInstanceReceiver()->getType()->getAs<ObjCObjectPointerType>()) - return Ptr->getInterfaceDecl(); - break; - + return getInstanceReceiver()->getType(); case Class: - if (const ObjCObjectType *Ty - = getClassReceiver()->getAs<ObjCObjectType>()) - return Ty->getInterface(); - break; - + return getClassReceiver(); case SuperInstance: - if (const ObjCObjectPointerType *Ptr - = getSuperType()->getAs<ObjCObjectPointerType>()) - return Ptr->getInterfaceDecl(); - break; - case SuperClass: - if (const ObjCObjectType *Iface - = getSuperType()->getAs<ObjCObjectType>()) - return Iface->getInterface(); - break; + return getSuperType(); } + llvm_unreachable("unexpected receiver kind"); +} + +ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { + QualType T = getReceiverType(); + + if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>()) + return Ptr->getInterfaceDecl(); + + if (const ObjCObjectType *Ty = T->getAs<ObjCObjectType>()) + return Ty->getInterface(); + return 0; } @@ -3386,17 +3488,17 @@ bool ChooseExpr::isConditionTrue(const ASTContext &C) const { return getCond()->EvaluateKnownConstInt(C) != 0; } -ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr, +ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, QualType Type, SourceLocation BLoc, SourceLocation RP) : Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary, Type->isDependentType(), Type->isDependentType(), Type->isInstantiationDependentType(), Type->containsUnexpandedParameterPack()), - BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(nexpr) + BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(args.size()) { - SubExprs = new (C) Stmt*[nexpr]; - for (unsigned i = 0; i < nexpr; i++) { + SubExprs = new (C) Stmt*[args.size()]; + for (unsigned i = 0; i != args.size(); i++) { if (args[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) @@ -3421,8 +3523,9 @@ void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs, GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, - TypeSourceInfo **AssocTypes, Expr **AssocExprs, - unsigned NumAssocs, SourceLocation DefaultLoc, + ArrayRef<TypeSourceInfo*> AssocTypes, + ArrayRef<Expr*> AssocExprs, + SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack, unsigned ResultIndex) @@ -3434,19 +3537,21 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, AssocExprs[ResultIndex]->isValueDependent(), AssocExprs[ResultIndex]->isInstantiationDependent(), ContainsUnexpandedParameterPack), - AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]), - SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs), - ResultIndex(ResultIndex), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), - RParenLoc(RParenLoc) { + AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]), + SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]), + NumAssocs(AssocExprs.size()), ResultIndex(ResultIndex), + GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) { SubExprs[CONTROLLING] = ControllingExpr; - std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes); - std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR); + assert(AssocTypes.size() == AssocExprs.size()); + std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes); + std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR); } GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, - TypeSourceInfo **AssocTypes, Expr **AssocExprs, - unsigned NumAssocs, SourceLocation DefaultLoc, + ArrayRef<TypeSourceInfo*> AssocTypes, + ArrayRef<Expr*> AssocExprs, + SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack) : Expr(GenericSelectionExprClass, @@ -3457,13 +3562,14 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, /*isValueDependent=*/true, /*isInstantiationDependent=*/true, ContainsUnexpandedParameterPack), - AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]), - SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs), - ResultIndex(-1U), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), - RParenLoc(RParenLoc) { + AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]), + SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]), + NumAssocs(AssocExprs.size()), ResultIndex(-1U), GenericLoc(GenericLoc), + DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) { SubExprs[CONTROLLING] = ControllingExpr; - std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes); - std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR); + assert(AssocTypes.size() == AssocExprs.size()); + std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes); + std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR); } //===----------------------------------------------------------------------===// @@ -3483,8 +3589,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, const Designator *Designators, SourceLocation EqualOrColonLoc, bool GNUSyntax, - Expr **IndexExprs, - unsigned NumIndexExprs, + ArrayRef<Expr*> IndexExprs, Expr *Init) : Expr(DesignatedInitExprClass, Ty, Init->getValueKind(), Init->getObjectKind(), @@ -3492,7 +3597,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, Init->isInstantiationDependent(), Init->containsUnexpandedParameterPack()), EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), - NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { + NumDesignators(NumDesignators), NumSubExprs(IndexExprs.size() + 1) { this->Designators = new (C) Designator[NumDesignators]; // Record the initializer itself. @@ -3542,20 +3647,20 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, } } - assert(IndexIdx == NumIndexExprs && "Wrong number of index expressions"); + assert(IndexIdx == IndexExprs.size() && "Wrong number of index expressions"); } DesignatedInitExpr * DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, unsigned NumDesignators, - Expr **IndexExprs, unsigned NumIndexExprs, + ArrayRef<Expr*> IndexExprs, SourceLocation ColonOrEqualLoc, bool UsesColonSyntax, Expr *Init) { void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + - sizeof(Stmt *) * (NumIndexExprs + 1), 8); + sizeof(Stmt *) * (IndexExprs.size() + 1), 8); return new (Mem) DesignatedInitExpr(C, C.VoidTy, NumDesignators, Designators, ColonOrEqualLoc, UsesColonSyntax, - IndexExprs, NumIndexExprs, Init); + IndexExprs, Init); } DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, @@ -3651,13 +3756,13 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx, } ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, - Expr **exprs, unsigned nexprs, + ArrayRef<Expr*> exprs, SourceLocation rparenloc) : Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, false, false), - NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) { - Exprs = new (C) Stmt*[nexprs]; - for (unsigned i = 0; i != nexprs; ++i) { + NumExprs(exprs.size()), LParenLoc(lparenloc), RParenLoc(rparenloc) { + Exprs = new (C) Stmt*[exprs.size()]; + for (unsigned i = 0; i != exprs.size(); ++i) { if (exprs[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (exprs[i]->isValueDependent()) @@ -3902,14 +4007,14 @@ ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(ASTContext &C, getMethod, setMethod, RB); } -AtomicExpr::AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr, +AtomicExpr::AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args, QualType t, AtomicOp op, SourceLocation RP) : Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary, false, false, false, false), - NumSubExprs(nexpr), BuiltinLoc(BLoc), RParenLoc(RP), Op(op) + NumSubExprs(args.size()), BuiltinLoc(BLoc), RParenLoc(RP), Op(op) { - assert(nexpr == getNumSubExprs(op) && "wrong number of subexpressions"); - for (unsigned i = 0; i < nexpr; i++) { + assert(args.size() == getNumSubExprs(op) && "wrong number of subexpressions"); + for (unsigned i = 0; i != args.size(); i++) { if (args[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 3fa49e0..55722a2 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -51,6 +51,26 @@ QualType CXXUuidofExpr::getTypeOperand() const { .getUnqualifiedType(); } +// static +UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) { + // Optionally remove one level of pointer, reference or array indirection. + const Type *Ty = QT.getTypePtr(); + if (QT->isPointerType() || QT->isReferenceType()) + Ty = QT->getPointeeType().getTypePtr(); + else if (QT->isArrayType()) + Ty = cast<ArrayType>(QT)->getElementType().getTypePtr(); + + // Loop all record redeclaration looking for an uuid attribute. + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(), + E = RD->redecls_end(); I != E; ++I) { + if (UuidAttr *Uuid = I->getAttr<UuidAttr>()) + return Uuid; + } + + return 0; +} + // CXXScalarValueInitExpr SourceRange CXXScalarValueInitExpr::getSourceRange() const { SourceLocation Start = RParenLoc; @@ -63,24 +83,24 @@ SourceRange CXXScalarValueInitExpr::getSourceRange() const { CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize, - Expr **placementArgs, unsigned numPlaceArgs, + ArrayRef<Expr*> placementArgs, SourceRange typeIdParens, Expr *arraySize, InitializationStyle initializationStyle, Expr *initializer, QualType ty, TypeSourceInfo *allocatedTypeInfo, - SourceLocation startLoc, SourceRange directInitRange) + SourceRange Range, SourceRange directInitRange) : Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary, ty->isDependentType(), ty->isDependentType(), ty->isInstantiationDependentType(), ty->containsUnexpandedParameterPack()), SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete), AllocatedTypeInfo(allocatedTypeInfo), TypeIdParens(typeIdParens), - StartLoc(startLoc), DirectInitRange(directInitRange), + Range(Range), DirectInitRange(directInitRange), GlobalNew(globalNew), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) { assert((initializer != 0 || initializationStyle == NoInit) && "Only NoInit can have no initializer."); StoredInitializationStyle = initializer ? initializationStyle + 1 : 0; - AllocateArgsArray(C, arraySize != 0, numPlaceArgs, initializer != 0); + AllocateArgsArray(C, arraySize != 0, placementArgs.size(), initializer != 0); unsigned i = 0; if (Array) { if (arraySize->isInstantiationDependent()) @@ -102,7 +122,7 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, SubExprs[i++] = initializer; } - for (unsigned j = 0; j < NumPlacementArgs; ++j) { + for (unsigned j = 0; j != placementArgs.size(); ++j) { if (placementArgs[j]->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (placementArgs[j]->containsUnexpandedParameterPack()) @@ -110,6 +130,14 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, SubExprs[i++] = placementArgs[j]; } + + switch (getInitializationStyle()) { + case CallInit: + this->Range.setEnd(DirectInitRange.getEnd()); break; + case ListInit: + this->Range.setEnd(getInitializer()->getSourceRange().getEnd()); break; + default: break; + } } void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, @@ -127,18 +155,6 @@ bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const { castAs<FunctionProtoType>()->isNothrow(Ctx); } -SourceLocation CXXNewExpr::getEndLoc() const { - switch (getInitializationStyle()) { - case NoInit: - return AllocatedTypeInfo->getTypeLoc().getEndLoc(); - case CallInit: - return DirectInitRange.getEnd(); - case ListInit: - return getInitializer()->getSourceRange().getEnd(); - } - llvm_unreachable("bogus initialization style"); -} - // CXXDeleteExpr QualType CXXDeleteExpr::getDestroyedType() const { const Expr *Arg = getArgument(); @@ -227,7 +243,7 @@ UnresolvedLookupExpr::Create(ASTContext &C, return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, TemplateKWLoc, NameInfo, ADL, /*Overload*/ true, Args, - Begin, End, /*StdIsAssociated=*/false); + Begin, End); } UnresolvedLookupExpr * @@ -697,15 +713,14 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, TypeSourceInfo *Type, - Expr **Args, - unsigned NumArgs, + ArrayRef<Expr*> Args, SourceRange parenRange, bool HadMultipleCandidates, bool ZeroInitialization) : CXXConstructExpr(C, CXXTemporaryObjectExprClass, Type->getType().getNonReferenceType(), Type->getTypeLoc().getBeginLoc(), - Cons, false, Args, NumArgs, + Cons, false, Args, HadMultipleCandidates, /*FIXME*/false, ZeroInitialization, CXXConstructExpr::CK_Complete, parenRange), Type(Type) { @@ -719,14 +734,14 @@ SourceRange CXXTemporaryObjectExpr::getSourceRange() const { CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr*> Args, bool HadMultipleCandidates, bool ListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenRange) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, - Elidable, Args, NumArgs, + Elidable, Args, HadMultipleCandidates, ListInitialization, ZeroInitialization, ConstructKind, ParenRange); @@ -735,7 +750,7 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, - Expr **args, unsigned numargs, + ArrayRef<Expr*> args, bool HadMultipleCandidates, bool ListInitialization, bool ZeroInitialization, @@ -745,16 +760,16 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, T->isDependentType(), T->isDependentType(), T->isInstantiationDependentType(), T->containsUnexpandedParameterPack()), - Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(numargs), + Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(args.size()), Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates), ListInitialization(ListInitialization), ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), Args(0) { if (NumArgs) { - Args = new (C) Stmt*[NumArgs]; + Args = new (C) Stmt*[args.size()]; - for (unsigned i = 0; i != NumArgs; ++i) { + for (unsigned i = 0; i != args.size(); ++i) { assert(args[i] && "NULL argument in CXXConstructExpr"); if (args[i]->isValueDependent()) @@ -877,9 +892,12 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, QualType T = Context.getTypeDeclType(Class); unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (Captures.size() + 1); - if (!ArrayIndexVars.empty()) - Size += sizeof(VarDecl *) * ArrayIndexVars.size() - + sizeof(unsigned) * (Captures.size() + 1); + if (!ArrayIndexVars.empty()) { + Size += sizeof(unsigned) * (Captures.size() + 1); + // Realign for following VarDecl array. + Size = llvm::RoundUpToAlignment(Size, llvm::alignOf<VarDecl*>()); + Size += sizeof(VarDecl *) * ArrayIndexVars.size(); + } void *Mem = Context.Allocate(Size); return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault, Captures, ExplicitParams, ExplicitResultType, @@ -997,8 +1015,7 @@ ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, EmptyShell empty, CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, - Expr **Args, - unsigned NumArgs, + ArrayRef<Expr*> Args, SourceLocation RParenLoc) : Expr(CXXUnresolvedConstructExprClass, Type->getType().getNonReferenceType(), @@ -1011,9 +1028,9 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, Type(Type), LParenLoc(LParenLoc), RParenLoc(RParenLoc), - NumArgs(NumArgs) { + NumArgs(Args.size()) { Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1); - for (unsigned I = 0; I != NumArgs; ++I) { + for (unsigned I = 0; I != Args.size(); ++I) { if (Args[I]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -1025,13 +1042,11 @@ CXXUnresolvedConstructExpr * CXXUnresolvedConstructExpr::Create(ASTContext &C, TypeSourceInfo *Type, SourceLocation LParenLoc, - Expr **Args, - unsigned NumArgs, + ArrayRef<Expr*> Args, SourceLocation RParenLoc) { void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) + - sizeof(Expr *) * NumArgs); - return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc, - Args, NumArgs, RParenLoc); + sizeof(Expr *) * Args.size()); + return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc, Args, RParenLoc); } CXXUnresolvedConstructExpr * @@ -1300,6 +1315,34 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const { return TemplateArgument(Arguments, NumArguments); } +FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack, + SourceLocation NameLoc, + unsigned NumParams, + Decl * const *Params) + : Expr(FunctionParmPackExprClass, T, VK_LValue, OK_Ordinary, + true, true, true, true), + ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) { + if (Params) + std::uninitialized_copy(Params, Params + NumParams, + reinterpret_cast<Decl**>(this+1)); +} + +FunctionParmPackExpr * +FunctionParmPackExpr::Create(ASTContext &Context, QualType T, + ParmVarDecl *ParamPack, SourceLocation NameLoc, + llvm::ArrayRef<Decl*> Params) { + return new (Context.Allocate(sizeof(FunctionParmPackExpr) + + sizeof(ParmVarDecl*) * Params.size())) + FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data()); +} + +FunctionParmPackExpr * +FunctionParmPackExpr::CreateEmpty(ASTContext &Context, unsigned NumParams) { + return new (Context.Allocate(sizeof(FunctionParmPackExpr) + + sizeof(ParmVarDecl*) * NumParams)) + FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0); +} + TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, ArrayRef<TypeSourceInfo *> Args, SourceLocation RParenLoc, diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index f16d70b..24ec6bb 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -134,6 +134,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // ObjC instance variables are lvalues // FIXME: ObjC++0x might have different rules case Expr::ObjCIvarRefExprClass: + case Expr::FunctionParmPackExprClass: return Cl::CL_LValue; // C99 6.5.2.5p5 says that compound literals are lvalues. diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 06c41a2..6e0b5fc 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -953,7 +953,7 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) { if (VD) Info.Note(VD->getLocation(), diag::note_declared_at); else - Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(), + Info.Note(Base.get<const Expr*>()->getExprLoc(), diag::note_constexpr_temporary_here); } @@ -987,6 +987,14 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, LVal.getLValueCallIndex() == 0) && "have call index for global lvalue"); + // Check if this is a thread-local variable. + if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { + if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) { + if (Var->isThreadSpecified()) + return false; + } + } + // Allow address constant expressions to be past-the-end pointers. This is // an extension: the standard requires them to point to an object. if (!IsReferenceType) @@ -2586,7 +2594,7 @@ public: const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); if (!FD) return Error(E); assert(!FD->getType()->isReferenceType() && "prvalue reference?"); - assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() == + assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); SubobjectDesignator Designator(BaseTy); @@ -2665,7 +2673,7 @@ public: if (E->isArrow()) { if (!EvaluatePointer(E->getBase(), Result, this->Info)) return false; - BaseTy = E->getBase()->getType()->getAs<PointerType>()->getPointeeType(); + BaseTy = E->getBase()->getType()->castAs<PointerType>()->getPointeeType(); } else if (E->getBase()->isRValue()) { assert(E->getBase()->getType()->isRecordType()); if (!EvaluateTemporary(E->getBase(), Result, this->Info)) @@ -2878,19 +2886,13 @@ LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { } bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { - if (E->isTypeOperand()) + if (!E->isPotentiallyEvaluated()) return Success(E); - CXXRecordDecl *RD = E->getExprOperand()->getType()->getAsCXXRecordDecl(); - // FIXME: The standard says "a typeid expression whose operand is of a - // polymorphic class type" is not a constant expression, but it probably - // means "a typeid expression whose operand is potentially evaluated". - if (RD && RD->isPolymorphic()) { - Info.Diag(E, diag::note_constexpr_typeid_polymorphic) - << E->getExprOperand()->getType() - << E->getExprOperand()->getSourceRange(); - return false; - } - return Success(E); + + Info.Diag(E, diag::note_constexpr_typeid_polymorphic) + << E->getExprOperand()->getType() + << E->getExprOperand()->getSourceRange(); + return false; } bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { @@ -3036,7 +3038,7 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (E->getOpcode() == BO_Sub) AdditionalOffset = -AdditionalOffset; - QualType Pointee = PExp->getType()->getAs<PointerType>()->getPointeeType(); + QualType Pointee = PExp->getType()->castAs<PointerType>()->getPointeeType(); return HandleLValueArrayAdjustment(Info, E, Result, Pointee, AdditionalOffset); } @@ -4288,6 +4290,16 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { return Error(E); } + case Builtin::BI__builtin_bswap16: + case Builtin::BI__builtin_bswap32: + case Builtin::BI__builtin_bswap64: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + + return Success(Val.byteSwap(), E); + } + case Builtin::BI__builtin_classify_type: return Success(EvaluateBuiltinClassifyType(E), E); @@ -4902,7 +4914,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero()) return false; const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr*>(); - const Expr *RHSExpr = LHSValue.Base.dyn_cast<const Expr*>(); + const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr*>(); if (!LHSExpr || !RHSExpr) return false; const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr); @@ -5176,7 +5188,7 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( QualType Ty = E->getTypeOfArgument(); if (Ty->isVectorType()) { - unsigned n = Ty->getAs<VectorType>()->getNumElements(); + unsigned n = Ty->castAs<VectorType>()->getNumElements(); // The vec_step built-in functions that take a 3-component // vector return 4. (OpenCL 1.1 spec 6.11.12) @@ -5349,6 +5361,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_IntegralRealToComplex: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: + case CK_BuiltinFnToFnPtr: llvm_unreachable("invalid cast kind for integral value"); case CK_BitCast: @@ -5753,7 +5766,7 @@ static bool EvaluateComplex(const Expr *E, ComplexValue &Result, } bool ComplexExprEvaluator::ZeroInitialization(const Expr *E) { - QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType(); + QualType ElemTy = E->getType()->castAs<ComplexType>()->getElementType(); if (ElemTy->isRealFloatingType()) { Result.makeComplexFloat(); APFloat Zero = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(ElemTy)); @@ -5835,6 +5848,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: case CK_CopyAndAutoreleaseBlockObject: + case CK_BuiltinFnToFnPtr: llvm_unreachable("invalid cast kind for complex value"); case CK_LValueToRValue: @@ -5911,9 +5925,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { if (!Visit(E->getSubExpr())) return false; - QualType To = E->getType()->getAs<ComplexType>()->getElementType(); + QualType To = E->getType()->castAs<ComplexType>()->getElementType(); QualType From - = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType(); + = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType(); Result.makeComplexFloat(); return HandleIntToFloatCast(Info, E, From, Result.IntReal, To, Result.FloatReal) && @@ -6177,11 +6191,9 @@ 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().CPlusPlus0x) Info.CCEDiag(E, diag::note_constexpr_nonliteral) << E->getType(); - else - Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); if (!EvaluateVoid(E, Info)) return false; } else if (Info.getLangOpts().CPlusPlus0x) { @@ -6470,6 +6482,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::OpaqueValueExprClass: case Expr::PackExpansionExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::FunctionParmPackExprClass: case Expr::AsTypeExprClass: case Expr::ObjCIndirectCopyRestoreExprClass: case Expr::MaterializeTemporaryExprClass: diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 7c7a5e5..851944a 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -343,17 +343,10 @@ private: void mangleCXXDtorType(CXXDtorType T); void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs); - void mangleTemplateArgs(TemplateName Template, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs); - void mangleTemplateArgs(const TemplateParameterList &PL, - const TemplateArgument *TemplateArgs, + void mangleTemplateArgs(const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); - void mangleTemplateArgs(const TemplateParameterList &PL, - const TemplateArgumentList &AL); - void mangleTemplateArg(const NamedDecl *P, TemplateArgument A); - void mangleUnresolvedTemplateArgs(const TemplateArgument *args, - unsigned numArgs); + void mangleTemplateArgs(const TemplateArgumentList &AL); + void mangleTemplateArg(TemplateArgument A); void mangleTemplateParameter(unsigned Index); @@ -570,8 +563,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleUnscopedTemplateName(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + mangleTemplateArgs(*TemplateArgs); return; } @@ -593,8 +585,7 @@ void CXXNameMangler::mangleName(const TemplateDecl *TD, if (DC->isTranslationUnit() || isStdNamespace(DC)) { mangleUnscopedTemplateName(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs); + mangleTemplateArgs(TemplateArgs, NumTemplateArgs); } else { mangleNestedName(TD, TemplateArgs, NumTemplateArgs); } @@ -693,9 +684,10 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) { void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) { if (Value.isSigned() && Value.isNegative()) { Out << 'n'; - Value.abs().print(Out, true); - } else - Value.print(Out, Value.isSigned()); + Value.abs().print(Out, /*signed*/ false); + } else { + Value.print(Out, /*signed*/ false); + } } void CXXNameMangler::mangleNumber(int64_t Number) { @@ -737,8 +729,7 @@ void CXXNameMangler::manglePrefix(QualType type) { // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), - TST->getNumArgs()); + mangleTemplateArgs(TST->getArgs(), TST->getNumArgs()); addSubstitution(QualType(TST, 0)); } } else if (const DependentTemplateSpecializationType *DTST @@ -751,7 +742,7 @@ void CXXNameMangler::manglePrefix(QualType type) { // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs()); + mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs()); } else { // We use the QualType mangle type variant here because it handles // substitutions. @@ -942,7 +933,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, } } - mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs()); + mangleTemplateArgs(tst->getArgs(), tst->getNumArgs()); break; } @@ -959,7 +950,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, const DependentTemplateSpecializationType *tst = cast<DependentTemplateSpecializationType>(type); mangleSourceName(tst->getIdentifier()); - mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs()); + mangleTemplateArgs(tst->getArgs(), tst->getNumArgs()); break; } } @@ -1228,8 +1219,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND, const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleTemplatePrefix(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + mangleTemplateArgs(*TemplateArgs); } else { manglePrefix(DC, NoFunction); @@ -1246,8 +1236,7 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD, Out << 'N'; mangleTemplatePrefix(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs); + mangleTemplateArgs(TemplateArgs, NumTemplateArgs); Out << 'E'; } @@ -1341,11 +1330,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { } Out << "Ul"; - DeclarationName Name - = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); - const FunctionProtoType *Proto - = cast<CXXMethodDecl>(*Lambda->lookup(Name).first)->getType()-> - getAs<FunctionProtoType>(); + const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()-> + getAs<FunctionProtoType>(); mangleBareFunctionType(Proto, /*MangleReturnType=*/false); Out << "E"; @@ -1423,8 +1409,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleTemplatePrefix(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + mangleTemplateArgs(*TemplateArgs); } else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND))) return; @@ -2110,6 +2095,7 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { // ::= Dv [<dimension expression>] _ <element type> // <extended element type> ::= <element type> // ::= p # AltiVec vector pixel +// ::= b # Altivec vector bool void CXXNameMangler::mangleType(const VectorType *T) { if ((T->getVectorKind() == VectorType::NeonVector || T->getVectorKind() == VectorType::NeonPolyVector)) { @@ -2174,7 +2160,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs()); + mangleTemplateArgs(T->getArgs(), T->getNumArgs()); addSubstitution(QualType(T, 0)); } } @@ -2200,7 +2186,7 @@ void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) { // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs()); + mangleTemplateArgs(T->getArgs(), T->getNumArgs()); Out << 'E'; } @@ -2414,7 +2400,6 @@ recurse: case Expr::ExpressionTraitExprClass: case Expr::VAArgExprClass: case Expr::CXXUuidofExprClass: - case Expr::CXXNoexceptExprClass: case Expr::CUDAKernelCallExprClass: case Expr::AsTypeExprClass: case Expr::PseudoObjectExprClass: @@ -2606,6 +2591,11 @@ recurse: Out <<"_E"; break; + case Expr::CXXNoexceptExprClass: + Out << "nx"; + mangleExpression(cast<CXXNoexceptExpr>(E)->getOperand()); + break; + case Expr::UnaryExprOrTypeTraitExprClass: { const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E); @@ -2808,7 +2798,15 @@ recurse: // }; Out << "_SUBSTPACK_"; break; - + + case Expr::FunctionParmPackExprClass: { + // FIXME: not clear how to mangle this! + const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E); + Out << "v110_SUBSTPACK"; + mangleFunctionParam(FPPE->getParameterPack()); + break; + } + case Expr::DependentScopeDeclRefExprClass: { const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E); mangleUnresolvedName(DRE->getQualifier(), 0, DRE->getDeclName(), Arity); @@ -3043,50 +3041,28 @@ void CXXNameMangler::mangleTemplateArgs( // <template-args> ::= I <template-arg>+ E Out << 'I'; for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i) - mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[i].getArgument()); - Out << 'E'; -} - -void CXXNameMangler::mangleTemplateArgs(TemplateName Template, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs) { - if (TemplateDecl *TD = Template.getAsTemplateDecl()) - return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs, - NumTemplateArgs); - - mangleUnresolvedTemplateArgs(TemplateArgs, NumTemplateArgs); -} - -void CXXNameMangler::mangleUnresolvedTemplateArgs(const TemplateArgument *args, - unsigned numArgs) { - // <template-args> ::= I <template-arg>+ E - Out << 'I'; - for (unsigned i = 0; i != numArgs; ++i) - mangleTemplateArg(0, args[i]); + mangleTemplateArg(TemplateArgs.getTemplateArgs()[i].getArgument()); Out << 'E'; } -void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, - const TemplateArgumentList &AL) { +void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &AL) { // <template-args> ::= I <template-arg>+ E Out << 'I'; for (unsigned i = 0, e = AL.size(); i != e; ++i) - mangleTemplateArg(PL.getParam(i), AL[i]); + mangleTemplateArg(AL[i]); Out << 'E'; } -void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, - const TemplateArgument *TemplateArgs, +void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { // <template-args> ::= I <template-arg>+ E Out << 'I'; for (unsigned i = 0; i != NumTemplateArgs; ++i) - mangleTemplateArg(PL.getParam(i), TemplateArgs[i]); + mangleTemplateArg(TemplateArgs[i]); Out << 'E'; } -void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, - TemplateArgument A) { +void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { // <template-arg> ::= <type> # type or template // ::= X <expression> E # expression // ::= <expr-primary> # simple expressions @@ -3135,25 +3111,12 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, mangleIntegerLiteral(A.getIntegralType(), A.getAsIntegral()); break; case TemplateArgument::Declaration: { - assert(P && "Missing template parameter for declaration argument"); // <expr-primary> ::= L <mangled-name> E # external name - // <expr-primary> ::= L <type> 0 E // Clang produces AST's where pointer-to-member-function expressions // and pointer-to-function expressions are represented as a declaration not // an expression. We compensate for it here to produce the correct mangling. - const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P); - - // Handle NULL pointer arguments. - if (!A.getAsDecl()) { - Out << "L"; - mangleType(Parameter->getType()); - Out << "0E"; - break; - } - - - NamedDecl *D = cast<NamedDecl>(A.getAsDecl()); - bool compensateMangling = !Parameter->getType()->isReferenceType(); + ValueDecl *D = A.getAsDecl(); + bool compensateMangling = !A.isDeclForReferenceParam(); if (compensateMangling) { Out << 'X'; mangleOperatorName(OO_Amp, 1); @@ -3176,14 +3139,20 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, break; } - + case TemplateArgument::NullPtr: { + // <expr-primary> ::= L <type> 0 E + Out << 'L'; + mangleType(A.getNullPtrType()); + Out << "0E"; + break; + } case TemplateArgument::Pack: { // Note: proposal by Mike Herrick on 12/20/10 Out << 'J'; for (TemplateArgument::pack_iterator PA = A.pack_begin(), PAEnd = A.pack_end(); PA != PAEnd; ++PA) - mangleTemplateArg(P, *PA); + mangleTemplateArg(*PA); Out << 'E'; } } diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index e2cee7f..5d5b83d 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -20,6 +20,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/ABI.h" +#include "clang/Basic/DiagnosticOptions.h" #include <map> @@ -56,7 +57,7 @@ public: void mangleVariableEncoding(const VarDecl *VD); void mangleNumber(int64_t Number); void mangleNumber(const llvm::APSInt &Value); - void mangleType(QualType T, SourceRange Range); + void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true); private: void disableBackReferences() { UseNameBackReferences = false; } @@ -68,6 +69,7 @@ private: void manglePostfix(const DeclContext *DC, bool NoFunction=false); void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc); void mangleQualifiers(Qualifiers Quals, bool IsMember); + void manglePointerQualifiers(Qualifiers Quals); void mangleUnscopedTemplateName(const TemplateDecl *ND); void mangleTemplateInstantiationName(const TemplateDecl *TD, @@ -75,7 +77,7 @@ private: void mangleObjCMethodName(const ObjCMethodDecl *MD); void mangleLocalName(const FunctionDecl *FD); - void mangleTypeRepeated(QualType T, SourceRange Range); + void mangleArgumentType(QualType T, SourceRange Range); // Declare manglers for every type class. #define ABSTRACT_TYPE(CLASS, PARENT) @@ -95,6 +97,7 @@ private: void mangleFunctionClass(const FunctionDecl *FD); void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); void mangleIntegerLiteral(QualType T, const llvm::APSInt &Number); + void mangleExpression(const Expr *E); void mangleThrowSpecification(const FunctionProtoType *T); void mangleTemplateArgs( @@ -266,18 +269,18 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { Out << '4'; // Now mangle the type. // <variable-type> ::= <type> <cvr-qualifiers> - // ::= <type> A # pointers, references, arrays + // ::= <type> <pointee-cvr-qualifiers> # pointers, references // Pointers and references are odd. The type of 'int * const foo;' gets // mangled as 'QAHA' instead of 'PAHB', for example. TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc(); QualType Ty = TL.getType(); if (Ty->isPointerType() || Ty->isReferenceType()) { mangleType(Ty, TL.getSourceRange()); - Out << 'A'; + mangleQualifiers(Ty->getPointeeType().getQualifiers(), false); } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) { // Global arrays are funny, too. mangleType(AT, true); - Out << 'A'; + mangleQualifiers(Ty.getQualifiers(), false); } else { mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange()); mangleQualifiers(Ty.getLocalQualifiers(), false); @@ -304,39 +307,23 @@ void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { } void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { - // <number> ::= [?] <decimal digit> # 1 <= Number <= 10 - // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc... - // ::= [?] @ # 0 (alternate mangling, not emitted by VC) - if (Number < 0) { - Out << '?'; - Number = -Number; - } - // There's a special shorter mangling for 0, but Microsoft - // chose not to use it. Instead, 0 gets mangled as "A@". Oh well... - if (Number >= 1 && Number <= 10) - Out << Number-1; - else { - // We have to build up the encoding in reverse order, so it will come - // out right when we write it out. - char Encoding[16]; - char *EndPtr = Encoding+sizeof(Encoding); - char *CurPtr = EndPtr; - do { - *--CurPtr = 'A' + (Number % 16); - Number /= 16; - } while (Number); - Out.write(CurPtr, EndPtr-CurPtr); - Out << '@'; - } + llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false); + APSNumber = Number; + mangleNumber(APSNumber); } void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) { + // <number> ::= [?] <decimal digit> # 1 <= Number <= 10 + // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc... + // ::= [?] @ # 0 (alternate mangling, not emitted by VC) if (Value.isSigned() && Value.isNegative()) { Out << '?'; mangleNumber(llvm::APSInt(Value.abs())); return; } llvm::APSInt Temp(Value); + // There's a special shorter mangling for 0, but Microsoft + // chose not to use it. Instead, 0 gets mangled as "A@". Oh well... if (Value.uge(1) && Value.ule(10)) { --Temp; Temp.print(Out, false); @@ -348,10 +335,10 @@ void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) { char *CurPtr = EndPtr; llvm::APSInt NibbleMask(Value.getBitWidth(), Value.isUnsigned()); NibbleMask = 0xf; - for (int i = 0, e = Value.getActiveBits() / 4; i != e; ++i) { + do { *--CurPtr = 'A' + Temp.And(NibbleMask).getLimitedValue(0xf); Temp = Temp.lshr(4); - } + } while (Temp != 0); Out.write(CurPtr, EndPtr-CurPtr); Out << '@'; } @@ -386,7 +373,7 @@ isTemplate(const NamedDecl *ND, dyn_cast<ClassTemplateSpecializationDecl>(ND)) { TypeSourceInfo *TSI = Spec->getTypeAsWritten(); if (TSI) { - TemplateSpecializationTypeLoc &TSTL = + TemplateSpecializationTypeLoc TSTL = cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc()); TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc()); for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i) @@ -784,6 +771,23 @@ MicrosoftCXXNameMangler::mangleIntegerLiteral(QualType T, } void +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); + return; + } + + // As bad as this diagnostic is, it's better than crashing. + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot yet mangle expression type %0"); + Diags.Report(E->getExprLoc(), DiagID) + << E->getStmtClassName() << E->getSourceRange(); +} + +void MicrosoftCXXNameMangler::mangleTemplateArgs( const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { // <template-args> ::= {<type> | <integer-literal>}+ @ @@ -800,21 +804,19 @@ MicrosoftCXXNameMangler::mangleTemplateArgs( case TemplateArgument::Integral: mangleIntegerLiteral(TA.getIntegralType(), TA.getAsIntegral()); break; - case TemplateArgument::Expression: { - // See if this is a constant expression. - Expr *TAE = TA.getAsExpr(); - llvm::APSInt Value; - if (TAE->isIntegerConstantExpr(Value, Context.getASTContext())) { - mangleIntegerLiteral(TAE->getType(), Value); - break; - } - /* fallthrough */ - } default: { + 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|ERROR|" - "template|template pack expansion|expression|parameter pack}0 " + "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) << TA.getKind() @@ -879,43 +881,60 @@ void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, // ::= 3 # ? // ::= 4 # ? // ::= 5 # not really based + bool HasConst = Quals.hasConst(), + HasVolatile = Quals.hasVolatile(); if (!IsMember) { - if (!Quals.hasVolatile()) { - if (!Quals.hasConst()) - Out << 'A'; - else - Out << 'B'; + if (HasConst && HasVolatile) { + Out << 'D'; + } else if (HasVolatile) { + Out << 'C'; + } else if (HasConst) { + Out << 'B'; } else { - if (!Quals.hasConst()) - Out << 'C'; - else - Out << 'D'; + Out << 'A'; } } else { - if (!Quals.hasVolatile()) { - if (!Quals.hasConst()) - Out << 'Q'; - else - Out << 'R'; + if (HasConst && HasVolatile) { + Out << 'T'; + } else if (HasVolatile) { + Out << 'S'; + } else if (HasConst) { + Out << 'R'; } else { - if (!Quals.hasConst()) - Out << 'S'; - else - Out << 'T'; + Out << 'Q'; } } // FIXME: For now, just drop all extension qualifiers on the floor. } -void MicrosoftCXXNameMangler::mangleTypeRepeated(QualType T, SourceRange Range) { +void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) { + // <pointer-cvr-qualifiers> ::= P # no qualifiers + // ::= Q # const + // ::= R # volatile + // ::= S # const volatile + bool HasConst = Quals.hasConst(), + HasVolatile = Quals.hasVolatile(); + if (HasConst && HasVolatile) { + Out << 'S'; + } else if (HasVolatile) { + Out << 'R'; + } else if (HasConst) { + Out << 'Q'; + } else { + Out << 'P'; + } +} + +void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, + SourceRange Range) { void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr(); ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); if (Found == TypeBackReferences.end()) { size_t OutSizeBefore = Out.GetNumBytesInBuffer(); - mangleType(T,Range); + mangleType(T, Range, false); // See if it's worth creating a back reference. // Only types longer than 1 character are considered @@ -930,38 +949,30 @@ void MicrosoftCXXNameMangler::mangleTypeRepeated(QualType T, SourceRange Range) } } -void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range) { +void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, + bool MangleQualifiers) { // Only operate on the canonical type! T = getASTContext().getCanonicalType(T); - + Qualifiers Quals = T.getLocalQualifiers(); - if (Quals) { - // We have to mangle these now, while we still have enough information. - // <pointer-cvr-qualifiers> ::= P # pointer - // ::= Q # const pointer - // ::= R # volatile pointer - // ::= S # const volatile pointer - if (T->isAnyPointerType() || T->isMemberPointerType() || - T->isBlockPointerType()) { - if (!Quals.hasVolatile()) - Out << 'Q'; - else { - if (!Quals.hasConst()) - Out << 'R'; - else - Out << 'S'; - } - } else - // Just emit qualifiers like normal. - // NB: When we mangle a pointer/reference type, and the pointee - // type has no qualifiers, the lack of qualifier gets mangled - // in there. - mangleQualifiers(Quals, false); - } else if (T->isAnyPointerType() || T->isMemberPointerType() || - T->isBlockPointerType()) { - Out << 'P'; + // We have to mangle these now, while we still have enough information. + if (T->isAnyPointerType() || T->isMemberPointerType() || + T->isBlockPointerType()) { + manglePointerQualifiers(Quals); + } else if (Quals && MangleQualifiers) { + mangleQualifiers(Quals, false); } - switch (T->getTypeClass()) { + + SplitQualType split = T.split(); + const Type *ty = split.Ty; + + // If we're mangling a qualified array type, push the qualifiers to + // the element type. + if (split.Quals && isa<ArrayType>(T)) { + ty = Context.getASTContext().getAsArrayType(T); + } + + switch (ty->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ case Type::CLASS: \ @@ -969,7 +980,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range) { return; #define TYPE(CLASS, PARENT) \ case Type::CLASS: \ - mangleType(static_cast<const CLASS##Type*>(T.getTypePtr()), Range); \ + mangleType(cast<CLASS##Type>(ty), Range); \ break; #include "clang/AST/TypeNodes.def" #undef ABSTRACT_TYPE @@ -1059,6 +1070,8 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, SourceRange) { // Structors only appear in decls, so at this point we know it's not a // structor type. + // FIXME: This may not be lambda-friendly. + Out << "$$A6"; mangleType(T, NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, @@ -1117,14 +1130,14 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) { TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo(); QualType Type = TSI ? TSI->getType() : (*Parm)->getType(); - mangleTypeRepeated(Type, (*Parm)->getSourceRange()); + mangleArgumentType(Type, (*Parm)->getSourceRange()); } } else { // Happens for function pointer type arguments for example. for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), ArgEnd = Proto->arg_type_end(); Arg != ArgEnd; ++Arg) - mangleTypeRepeated(*Arg, SourceRange()); + mangleArgumentType(*Arg, SourceRange()); } // <builtin-type> ::= Z # ellipsis if (Proto->isVariadic()) @@ -1214,7 +1227,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, if (CC == CC_Default) { if (IsInstMethod) { const FunctionProtoType *FPT = - T->getCanonicalTypeUnqualified().getAs<FunctionProtoType>(); + T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>(); bool isVariadic = FPT->isVariadic(); CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic); } else { @@ -1260,10 +1273,10 @@ void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T, // <class-type> ::= V <name> // <enum-type> ::= W <size> <name> void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) { - mangleType(static_cast<const TagType*>(T)); + mangleType(cast<TagType>(T)); } void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) { - mangleType(static_cast<const TagType*>(T)); + mangleType(cast<TagType>(T)); } void MicrosoftCXXNameMangler::mangleType(const TagType *T) { switch (T->getDecl()->getTagKind()) { @@ -1271,6 +1284,7 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { Out << 'T'; break; case TTK_Struct: + case TTK_Interface: Out << 'U'; break; case TTK_Class: @@ -1286,37 +1300,39 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { } // <type> ::= <array-type> -// <array-type> ::= P <cvr-qualifiers> [Y <dimension-count> <dimension>+] -// <element-type> # as global +// <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> +// [Y <dimension-count> <dimension>+] +// <element-type> # as global // ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+] -// <element-type> # as param +// <element-type> # as param // It's supposed to be the other way around, but for some strange reason, it // isn't. Today this behavior is retained for the sole purpose of backwards // compatibility. void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { // This isn't a recursive mangling, so now we have to do it all in this // one call. - if (IsGlobal) - Out << 'P'; - else + if (IsGlobal) { + manglePointerQualifiers(T->getElementType().getQualifiers()); + } else { Out << 'Q'; + } mangleExtraDimensions(T->getElementType()); } void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, SourceRange) { - mangleType(static_cast<const ArrayType *>(T), false); + mangleType(cast<ArrayType>(T), false); } void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, SourceRange) { - mangleType(static_cast<const ArrayType *>(T), false); + mangleType(cast<ArrayType>(T), false); } void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T, SourceRange) { - mangleType(static_cast<const ArrayType *>(T), false); + mangleType(cast<ArrayType>(T), false); } void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T, SourceRange) { - mangleType(static_cast<const ArrayType *>(T), false); + mangleType(cast<ArrayType>(T), false); } void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { SmallVector<llvm::APInt, 3> Dimensions; @@ -1409,10 +1425,8 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Out << '6'; mangleType(FT, NULL, false, false); } else { - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); + mangleQualifiers(PointeeTy.getQualifiers(), false); + mangleType(PointeeTy, Range, false); } } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, @@ -1497,7 +1511,9 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, SourceRange Range) { Out << "_E"; - mangleType(T->getPointeeType(), Range); + + QualType pointee = T->getPointeeType(); + mangleType(pointee->castAs<FunctionProtoType>(), NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T, diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp index 39077d1..0837509 100644 --- a/lib/AST/NSAPI.cpp +++ b/lib/AST/NSAPI.cpp @@ -344,6 +344,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { case BuiltinType::ARCUnbridgedCast: case BuiltinType::Half: case BuiltinType::PseudoObject: + case BuiltinType::BuiltinFn: break; } diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp index fa87afd..1135928 100644 --- a/lib/AST/ParentMap.cpp +++ b/lib/AST/ParentMap.cpp @@ -20,22 +20,63 @@ using namespace clang; typedef llvm::DenseMap<Stmt*, Stmt*> MapTy; -static void BuildParentMap(MapTy& M, Stmt* S) { - for (Stmt::child_range I = S->children(); I; ++I) - if (*I) { - // Prefer the first time we see this statement in the traversal. - // This is important for PseudoObjectExprs. - Stmt *&Parent = M[*I]; - if (!Parent) { - Parent = S; - BuildParentMap(M, *I); +enum OpaqueValueMode { + OV_Transparent, + OV_Opaque +}; + +static void BuildParentMap(MapTy& M, Stmt* S, + OpaqueValueMode OVMode = OV_Transparent) { + + switch (S->getStmtClass()) { + case Stmt::PseudoObjectExprClass: { + assert(OVMode == OV_Transparent && "Should not appear alongside OVEs"); + PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S); + + M[POE->getSyntacticForm()] = S; + BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent); + + for (PseudoObjectExpr::semantics_iterator I = POE->semantics_begin(), + E = POE->semantics_end(); + I != E; ++I) { + M[*I] = S; + BuildParentMap(M, *I, OV_Opaque); + } + break; + } + case Stmt::BinaryConditionalOperatorClass: { + assert(OVMode == OV_Transparent && "Should not appear alongside OVEs"); + BinaryConditionalOperator *BCO = cast<BinaryConditionalOperator>(S); + + M[BCO->getCommon()] = S; + BuildParentMap(M, BCO->getCommon(), OV_Transparent); + + M[BCO->getCond()] = S; + BuildParentMap(M, BCO->getCond(), OV_Opaque); + + M[BCO->getTrueExpr()] = S; + BuildParentMap(M, BCO->getTrueExpr(), OV_Opaque); + + M[BCO->getFalseExpr()] = S; + BuildParentMap(M, BCO->getFalseExpr(), OV_Transparent); + + break; + } + case Stmt::OpaqueValueExprClass: + if (OVMode == OV_Transparent) { + OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S); + M[OVE->getSourceExpr()] = S; + BuildParentMap(M, OVE->getSourceExpr(), OV_Transparent); + } + break; + default: + for (Stmt::child_range I = S->children(); I; ++I) { + if (*I) { + M[*I] = S; + BuildParentMap(M, *I, OVMode); } } - - // Also include the source expr tree of an OpaqueValueExpr in the map. - if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) { - M[OVE->getSourceExpr()] = S; - BuildParentMap(M, OVE->getSourceExpr()); + break; } } diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp index a5a3287..80b6272 100644 --- a/lib/AST/RawCommentList.cpp +++ b/lib/AST/RawCommentList.cpp @@ -143,11 +143,10 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const { // a separate allocator for all temporary stuff. llvm::BumpPtrAllocator Allocator; - comments::CommandTraits Traits; - comments::Lexer L(Allocator, Traits, - Range.getBegin(), comments::CommentOptions(), + comments::Lexer L(Allocator, Context.getCommentCommandTraits(), + Range.getBegin(), RawText.begin(), RawText.end()); - comments::BriefParser P(L, Traits); + comments::BriefParser P(L, Context.getCommentCommandTraits()); const std::string Result = P.Parse(); const unsigned BriefTextLength = Result.size(); @@ -160,19 +159,22 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const { } comments::FullComment *RawComment::parse(const ASTContext &Context, + const Preprocessor *PP, const Decl *D) const { // Make sure that RawText is valid. getRawText(Context.getSourceManager()); - comments::CommandTraits Traits; - comments::Lexer L(Context.getAllocator(), Traits, - getSourceRange().getBegin(), comments::CommentOptions(), + comments::Lexer L(Context.getAllocator(), Context.getCommentCommandTraits(), + getSourceRange().getBegin(), RawText.begin(), RawText.end()); comments::Sema S(Context.getAllocator(), Context.getSourceManager(), - Context.getDiagnostics(), Traits); + Context.getDiagnostics(), + Context.getCommentCommandTraits(), + PP); S.setDecl(D); comments::Parser P(L, S, Context.getAllocator(), Context.getSourceManager(), - Context.getDiagnostics(), Traits); + Context.getDiagnostics(), + Context.getCommentCommandTraits()); return P.parseFullComment(); } @@ -182,26 +184,22 @@ bool containsOnlyWhitespace(StringRef Str) { return Str.find_first_not_of(" \t\f\v\r\n") == StringRef::npos; } -bool onlyWhitespaceBetweenComments(SourceManager &SM, - const RawComment &C1, const RawComment &C2) { - std::pair<FileID, unsigned> C1EndLocInfo = SM.getDecomposedLoc( - C1.getSourceRange().getEnd()); - std::pair<FileID, unsigned> C2BeginLocInfo = SM.getDecomposedLoc( - C2.getSourceRange().getBegin()); +bool onlyWhitespaceBetween(SourceManager &SM, + SourceLocation Loc1, SourceLocation Loc2) { + std::pair<FileID, unsigned> Loc1Info = SM.getDecomposedLoc(Loc1); + std::pair<FileID, unsigned> Loc2Info = SM.getDecomposedLoc(Loc2); - // Question does not make sense if comments are located in different files. - if (C1EndLocInfo.first != C2BeginLocInfo.first) + // Question does not make sense if locations are in different files. + if (Loc1Info.first != Loc2Info.first) return false; bool Invalid = false; - const char *Buffer = SM.getBufferData(C1EndLocInfo.first, &Invalid).data(); + const char *Buffer = SM.getBufferData(Loc1Info.first, &Invalid).data(); if (Invalid) return false; - StringRef TextBetweenComments(Buffer + C1EndLocInfo.second, - C2BeginLocInfo.second - C1EndLocInfo.second); - - return containsOnlyWhitespace(TextBetweenComments); + StringRef Text(Buffer + Loc1Info.second, Loc2Info.second - Loc1Info.second); + return containsOnlyWhitespace(Text); } } // unnamed namespace @@ -221,11 +219,13 @@ void RawCommentList::addComment(const RawComment &RC, } if (OnlyWhitespaceSeen) { - if (!onlyWhitespaceBetweenComments(SourceMgr, LastComment, RC)) + if (!onlyWhitespaceBetween(SourceMgr, + PrevCommentEndLoc, + RC.getSourceRange().getBegin())) OnlyWhitespaceSeen = false; } - LastComment = RC; + PrevCommentEndLoc = RC.getSourceRange().getEnd(); // Ordinary comments are not interesting for us. if (RC.isOrdinary()) @@ -244,15 +244,20 @@ void RawCommentList::addComment(const RawComment &RC, // Merge comments only if there is only whitespace between them. // Can't merge trailing and non-trailing comments. - // Merge trailing comments if they are on same or consecutive lines. + // Merge comments if they are on same or consecutive lines. + bool Merged = false; if (OnlyWhitespaceSeen && - (C1.isTrailingComment() == C2.isTrailingComment()) && - (!C1.isTrailingComment() || - C1.getEndLine(SourceMgr) + 1 >= C2.getBeginLine(SourceMgr))) { - SourceRange MergedRange(C1.getSourceRange().getBegin(), - C2.getSourceRange().getEnd()); - *Comments.back() = RawComment(SourceMgr, MergedRange, true); - } else + (C1.isTrailingComment() == C2.isTrailingComment())) { + unsigned C1EndLine = C1.getEndLine(SourceMgr); + unsigned C2BeginLine = C2.getBeginLine(SourceMgr); + if (C1EndLine + 1 == C2BeginLine || C1EndLine == C2BeginLine) { + SourceRange MergedRange(C1.getSourceRange().getBegin(), + C2.getSourceRange().getEnd()); + *Comments.back() = RawComment(SourceMgr, MergedRange, true); + Merged = true; + } + } + if (!Merged) Comments.push_back(new (Allocator) RawComment(RC)); OnlyWhitespaceSeen = true; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index d5df63f..4dfffc4 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -789,8 +789,8 @@ protected: void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); } void setDataSize(uint64_t NewSize) { DataSize = NewSize; } - RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT - void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT + RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION; + void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION; public: static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); }; @@ -1557,6 +1557,13 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { bool Allowed = EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset); (void)Allowed; assert(Allowed && "Base subobject externally placed at overlapping offset"); + + if (InferAlignment && Offset < getDataSize().RoundUpToAlignment(BaseAlign)){ + // The externally-supplied base offset is before the base offset we + // computed. Assume that the structure is packed. + Alignment = CharUnits::One(); + InferAlignment = false; + } } if (!Base->Class->isEmpty()) { @@ -1574,12 +1581,12 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { } void RecordLayoutBuilder::InitializeLayout(const Decl *D) { - if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) + if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) { IsUnion = RD->isUnion(); + IsMsStruct = RD->isMsStruct(Context); + } - Packed = D->hasAttr<PackedAttr>(); - - IsMsStruct = D->hasAttr<MsStructAttr>(); + Packed = D->hasAttr<PackedAttr>(); // Honor the default struct packing maximum alignment flag. if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) { @@ -1616,7 +1623,6 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) { if (ExternalLayout) { if (ExternalAlign > 0) { Alignment = Context.toCharUnitsFromBits(ExternalAlign); - UnpackedAlignment = Alignment; } else { // The external source didn't have alignment information; infer it. InferAlignment = true; @@ -2085,7 +2091,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { ZeroLengthBitfield = 0; } - if (Context.getLangOpts().MSBitfields || IsMsStruct) { + if (IsMsStruct) { // If MS bitfield layout is required, figure out what type is being // laid out and align the field to the width of that type. @@ -2166,11 +2172,6 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { } void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { - if (ExternalLayout) { - setSize(ExternalSize); - return; - } - // In C++, records cannot be of size 0. if (Context.getLangOpts().CPlusPlus && getSizeInBits() == 0) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { @@ -2184,20 +2185,37 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { setSize(CharUnits::One()); } + // Finally, round the size of the record up to the alignment of the + // record itself. + uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte; + uint64_t UnpackedSizeInBits = + llvm::RoundUpToAlignment(getSizeInBits(), + Context.toBits(UnpackedAlignment)); + CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits); + uint64_t RoundedSize + = llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment)); + + if (ExternalLayout) { + // If we're inferring alignment, and the external size is smaller than + // our size after we've rounded up to alignment, conservatively set the + // alignment to 1. + if (InferAlignment && ExternalSize < RoundedSize) { + Alignment = CharUnits::One(); + InferAlignment = false; + } + setSize(ExternalSize); + return; + } + + // MSVC doesn't round up to the alignment of the record with virtual bases. if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { if (isMicrosoftCXXABI() && RD->getNumVBases()) return; } - // Finally, round the size of the record up to the alignment of the - // record itself. - uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte; - uint64_t UnpackedSizeInBits = - llvm::RoundUpToAlignment(getSizeInBits(), - Context.toBits(UnpackedAlignment)); - CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits); - setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment))); + // Set the size to the final size. + setSize(RoundedSize); unsigned CharBitNum = Context.getTargetInfo().getCharWidth(); if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) { @@ -2255,7 +2273,7 @@ RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field, if (InferAlignment && ExternalFieldOffset < ComputedOffset) { // The externally-supplied field offset is before the field offset we // computed. Assume that the structure is packed. - Alignment = CharUnits::fromQuantity(1); + Alignment = CharUnits::One(); InferAlignment = false; } @@ -2263,6 +2281,20 @@ RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field, return ExternalFieldOffset; } +/// \brief Get diagnostic %select index for tag kind for +/// field padding diagnostic message. +/// WARNING: Indexes apply to particular diagnostics only! +/// +/// \returns diagnostic %select index. +static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) { + switch (Tag) { + case TTK_Struct: return 0; + case TTK_Interface: return 1; + case TTK_Class: return 2; + default: llvm_unreachable("Invalid tag kind for field padding diagnostic!"); + } +} + void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset, uint64_t UnpackedOffset, @@ -2291,14 +2323,14 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, } if (D->getIdentifier()) Diag(D->getLocation(), diag::warn_padded_struct_field) - << (D->getParent()->isStruct() ? 0 : 1) // struct|class + << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) << Context.getTypeDeclType(D->getParent()) << PadSize << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1) // plural or not << D->getIdentifier(); else Diag(D->getLocation(), diag::warn_padded_struct_anon_field) - << (D->getParent()->isStruct() ? 0 : 1) // struct|class + << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) << Context.getTypeDeclType(D->getParent()) << PadSize << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not @@ -2508,8 +2540,8 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, assert(D && D->isThisDeclarationADefinition() && "Invalid interface decl!"); // Look up this layout, if already laid out, return what we have. - ObjCContainerDecl *Key = - Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D; + const ObjCContainerDecl *Key = + Impl ? (const ObjCContainerDecl*) Impl : (const ObjCContainerDecl*) D; if (const ASTRecordLayout *Entry = ObjCLayouts[Key]) return *Entry; diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 77452c9..eafcf92 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -20,6 +20,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -320,15 +321,52 @@ bool Stmt::hasImplicitControlFlow() const { } } -Expr *AsmStmt::getOutputExpr(unsigned i) { - return cast<Expr>(Exprs[i]); +std::string AsmStmt::generateAsmString(ASTContext &C) const { + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->generateAsmString(C); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->generateAsmString(C); + llvm_unreachable("unknown asm statement kind!"); } -/// getOutputConstraint - Return the constraint string for the specified -/// output operand. All output constraints are known to be non-empty (either -/// '=' or '+'). StringRef AsmStmt::getOutputConstraint(unsigned i) const { - return getOutputConstraintLiteral(i)->getString(); + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->getOutputConstraint(i); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->getOutputConstraint(i); + llvm_unreachable("unknown asm statement kind!"); +} + +const Expr *AsmStmt::getOutputExpr(unsigned i) const { + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->getOutputExpr(i); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->getOutputExpr(i); + llvm_unreachable("unknown asm statement kind!"); +} + +StringRef AsmStmt::getInputConstraint(unsigned i) const { + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->getInputConstraint(i); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->getInputConstraint(i); + llvm_unreachable("unknown asm statement kind!"); +} + +const Expr *AsmStmt::getInputExpr(unsigned i) const { + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->getInputExpr(i); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->getInputExpr(i); + llvm_unreachable("unknown asm statement kind!"); +} + +StringRef AsmStmt::getClobber(unsigned i) const { + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->getClobber(i); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->getClobber(i); + llvm_unreachable("unknown asm statement kind!"); } /// getNumPlusOperands - Return the number of output operands that have a "+" @@ -341,22 +379,35 @@ unsigned AsmStmt::getNumPlusOperands() const { return Res; } -Expr *AsmStmt::getInputExpr(unsigned i) { +StringRef GCCAsmStmt::getClobber(unsigned i) const { + return getClobberStringLiteral(i)->getString(); +} + +Expr *GCCAsmStmt::getOutputExpr(unsigned i) { + return cast<Expr>(Exprs[i]); +} + +/// getOutputConstraint - Return the constraint string for the specified +/// output operand. All output constraints are known to be non-empty (either +/// '=' or '+'). +StringRef GCCAsmStmt::getOutputConstraint(unsigned i) const { + return getOutputConstraintLiteral(i)->getString(); +} + +Expr *GCCAsmStmt::getInputExpr(unsigned i) { return cast<Expr>(Exprs[i + NumOutputs]); } -void AsmStmt::setInputExpr(unsigned i, Expr *E) { +void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) { Exprs[i + NumOutputs] = E; } - /// getInputConstraint - Return the specified input constraint. Unlike output /// constraints, these can be empty. -StringRef AsmStmt::getInputConstraint(unsigned i) const { +StringRef GCCAsmStmt::getInputConstraint(unsigned i) const { return getInputConstraintLiteral(i)->getString(); } - -void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, +void GCCAsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, IdentifierInfo **Names, StringLiteral **Constraints, Stmt **Exprs, @@ -390,7 +441,7 @@ void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, /// getNamedOperand - Given a symbolic operand reference like %[foo], /// translate this into a numeric value needed to reference the same operand. /// This returns -1 if the operand name is invalid. -int AsmStmt::getNamedOperand(StringRef SymbolicName) const { +int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const { unsigned NumPlusOperands = 0; // Check if this is an output operand. @@ -410,7 +461,7 @@ int AsmStmt::getNamedOperand(StringRef SymbolicName) const { /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. -unsigned AsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, +unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, ASTContext &C, unsigned &DiagOffs) const { StringRef Str = getAsmString()->getString(); const char *StrStart = Str.begin(); @@ -548,6 +599,44 @@ unsigned AsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, } } +/// Assemble final IR asm string (GCC-style). +std::string GCCAsmStmt::generateAsmString(ASTContext &C) const { + // Analyze the asm string to decompose it into its pieces. We know that Sema + // has already done this, so it is guaranteed to be successful. + SmallVector<GCCAsmStmt::AsmStringPiece, 4> Pieces; + unsigned DiagOffs; + AnalyzeAsmString(Pieces, C, DiagOffs); + + std::string AsmString; + for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { + if (Pieces[i].isString()) + AsmString += Pieces[i].getString(); + else if (Pieces[i].getModifier() == '\0') + AsmString += '$' + llvm::utostr(Pieces[i].getOperandNo()); + else + AsmString += "${" + llvm::utostr(Pieces[i].getOperandNo()) + ':' + + Pieces[i].getModifier() + '}'; + } + return AsmString; +} + +/// Assemble final IR asm string (MS-style). +std::string MSAsmStmt::generateAsmString(ASTContext &C) const { + // FIXME: This needs to be translated into the IR string representation. + return AsmStr; +} + +Expr *MSAsmStmt::getOutputExpr(unsigned i) { + return cast<Expr>(Exprs[i]); +} + +Expr *MSAsmStmt::getInputExpr(unsigned i) { + return cast<Expr>(Exprs[i + NumOutputs]); +} +void MSAsmStmt::setInputExpr(unsigned i, Expr *E) { + Exprs[i + NumOutputs] = E; +} + QualType CXXCatchStmt::getCaughtType() const { if (ExceptionDecl) return ExceptionDecl->getType(); @@ -558,15 +647,14 @@ QualType CXXCatchStmt::getCaughtType() const { // Constructors //===----------------------------------------------------------------------===// -AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, - bool isvolatile, bool msasm, - unsigned numoutputs, unsigned numinputs, - IdentifierInfo **names, StringLiteral **constraints, - Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, - StringLiteral **clobbers, SourceLocation rparenloc) - : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr) - , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm) - , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { +GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, + bool isvolatile, unsigned numoutputs, unsigned numinputs, + IdentifierInfo **names, StringLiteral **constraints, + Expr **exprs, StringLiteral *asmstr, + unsigned numclobbers, StringLiteral **clobbers, + SourceLocation rparenloc) + : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, + numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) { unsigned NumExprs = NumOutputs + NumInputs; @@ -585,26 +673,37 @@ AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc, bool issimple, bool isvolatile, - ArrayRef<Token> asmtoks, ArrayRef<IdentifierInfo*> inputs, - ArrayRef<IdentifierInfo*> outputs, StringRef asmstr, - ArrayRef<StringRef> clobbers, SourceLocation endloc) - : Stmt(MSAsmStmtClass), AsmLoc(asmloc), LBraceLoc(lbraceloc), EndLoc(endloc), - AsmStr(asmstr.str()), IsSimple(issimple), IsVolatile(isvolatile), - NumAsmToks(asmtoks.size()), NumInputs(inputs.size()), - NumOutputs(outputs.size()), NumClobbers(clobbers.size()) { + ArrayRef<Token> asmtoks, unsigned numoutputs, + unsigned numinputs, ArrayRef<IdentifierInfo*> names, + ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs, + StringRef asmstr, ArrayRef<StringRef> clobbers, + SourceLocation endloc) + : AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, + numinputs, clobbers.size()), LBraceLoc(lbraceloc), + EndLoc(endloc), AsmStr(asmstr.str()), NumAsmToks(asmtoks.size()) { unsigned NumExprs = NumOutputs + NumInputs; Names = new (C) IdentifierInfo*[NumExprs]; - for (unsigned i = 0, e = NumOutputs; i != e; ++i) - Names[i] = outputs[i]; - for (unsigned i = NumOutputs, e = NumExprs; i != e; ++i) - Names[i] = inputs[i]; + for (unsigned i = 0, e = NumExprs; i != e; ++i) + Names[i] = names[i]; + + Exprs = new (C) Stmt*[NumExprs]; + for (unsigned i = 0, e = NumExprs; i != e; ++i) + Exprs[i] = exprs[i]; AsmToks = new (C) Token[NumAsmToks]; for (unsigned i = 0, e = NumAsmToks; i != e; ++i) AsmToks[i] = asmtoks[i]; + Constraints = new (C) StringRef[NumExprs]; + for (unsigned i = 0, e = NumExprs; i != e; ++i) { + size_t size = constraints[i].size(); + char *dest = new (C) char[size]; + std::strncpy(dest, constraints[i].data(), size); + Constraints[i] = StringRef(dest, size); + } + Clobbers = new (C) StringRef[NumClobbers]; for (unsigned i = 0, e = NumClobbers; i != e; ++i) { // FIXME: Avoid the allocation/copy if at all possible. diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 962e352..fbc990f 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements the Stmt::dump/Stmt::print methods, which dump out the +// This file implements the Stmt::dump method, which dumps out the // AST in a form that exposes type details and other fields. // //===----------------------------------------------------------------------===// @@ -30,6 +30,7 @@ namespace { 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 @@ -41,46 +42,64 @@ namespace { 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-1), MaxDepth(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; - ++IndentLevel; - if (S) { - if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) - VisitDeclStmt(DS); - else { - Visit(S); - - // Print out children. - Stmt::child_range CI = S->children(); - if (CI) { - while (CI) { - OS << '\n'; - DumpSubTree(*CI++); - } - } - } - OS << ')'; - } else { - Indent(); + IndentScope Indent(*this); + + if (!S) { OS << "<<<NULL>>>"; + return; + } + + if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) { + VisitDeclStmt(DS); + return; } - --IndentLevel; + + Visit(S); + for (Stmt::child_range CI = S->children(); CI; CI++) + DumpSubTree(*CI); } void DumpDeclarator(Decl *D); - void Indent() const { - for (int i = 0, e = IndentLevel; i < e; ++i) - OS << " "; + void indent() { + if (IsFirstLine) + IsFirstLine = false; + else + OS << "\n"; + OS.indent(IndentLevel * 2); + OS << "("; + IndentLevel++; + } + + void unindent() { + OS << ")"; + IndentLevel--; } void DumpType(QualType T) { @@ -96,9 +115,8 @@ namespace { } void DumpDeclRef(Decl *node); void DumpStmt(const Stmt *Node) { - Indent(); - OS << "(" << Node->getStmtClassName() - << " " << (void*)Node; + OS << Node->getStmtClassName() + << " " << (const void*)Node; DumpSourceRange(Node); } void DumpValueKind(ExprValueKind K) { @@ -262,7 +280,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { // If this is a vardecl with an initializer, emit it. if (VarDecl *V = dyn_cast<VarDecl>(VD)) { if (V->getInit()) { - OS << " =\n"; + OS << " ="; DumpSubTree(V->getInit()); } } @@ -294,9 +312,9 @@ void StmtDumper::DumpDeclarator(Decl *D) { } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) { OS << "label " << *LD; } else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) { - OS << "\"static_assert(\n"; + OS << "\"static_assert("; DumpSubTree(SAD->getAssertExpr()); - OS << ",\n"; + OS << ","; DumpSubTree(SAD->getMessage()); OS << ");\""; } else { @@ -306,17 +324,12 @@ void StmtDumper::DumpDeclarator(Decl *D) { void StmtDumper::VisitDeclStmt(DeclStmt *Node) { DumpStmt(Node); - OS << "\n"; for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end(); DI != DE; ++DI) { + IndentScope Indent(*this); Decl* D = *DI; - ++IndentLevel; - Indent(); OS << (void*) D << " "; DumpDeclarator(D); - if (DI+1 != DE) - OS << "\n"; - --IndentLevel; } } @@ -503,35 +516,29 @@ void StmtDumper::VisitBlockExpr(BlockExpr *Node) { BlockDecl *block = Node->getBlockDecl(); OS << " decl=" << block; - IndentLevel++; if (block->capturesCXXThis()) { - OS << '\n'; Indent(); OS << "(capture this)"; + IndentScope Indent(*this); + OS << "capture this"; } for (BlockDecl::capture_iterator i = block->capture_begin(), e = block->capture_end(); i != e; ++i) { - OS << '\n'; - Indent(); - OS << "(capture "; + 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()); - OS << ")"; } - IndentLevel--; - OS << '\n'; DumpSubTree(block->getBody()); } void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) { DumpExpr(Node); - if (Expr *Source = Node->getSourceExpr()) { - OS << '\n'; + if (Expr *Source = Node->getSourceExpr()) DumpSubTree(Source); - } } // GNU extensions. @@ -589,15 +596,11 @@ void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) { DumpExpr(Node); - ++IndentLevel; for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) { - OS << "\n"; - Indent(); - OS << "(cleanup "; + IndentScope Indent(*this); + OS << "cleanup "; DumpDeclRef(Node->getObject(i)); - OS << ")"; } - --IndentLevel; } void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { @@ -734,7 +737,6 @@ void Stmt::dump(SourceManager &SM) const { void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { StmtDumper P(&SM, OS, 4); P.DumpSubTree(const_cast<Stmt*>(this)); - OS << "\n"; } /// dump - This does a local dump of the specified AST fragment. It dumps the @@ -743,19 +745,16 @@ void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { void Stmt::dump() const { StmtDumper P(0, llvm::errs(), 4); P.DumpSubTree(const_cast<Stmt*>(this)); - llvm::errs() << "\n"; } /// 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)); - llvm::errs() << "\n"; } /// 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)); - llvm::errs() << "\n"; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index c0960ce..57eb1a9 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -61,7 +61,7 @@ namespace { void PrintRawCompoundStmt(CompoundStmt *S); void PrintRawDecl(Decl *D); - void PrintRawDeclStmt(DeclStmt *S); + void PrintRawDeclStmt(const DeclStmt *S); void PrintRawIfStmt(IfStmt *If); void PrintRawCXXCatchStmt(CXXCatchStmt *Catch); void PrintCallArgs(CallExpr *E); @@ -121,8 +121,8 @@ void StmtPrinter::PrintRawDecl(Decl *D) { D->print(OS, Policy, IndentLevel); } -void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) { - DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end(); +void StmtPrinter::PrintRawDeclStmt(const DeclStmt *S) { + DeclStmt::const_decl_iterator Begin = S->decl_begin(), End = S->decl_end(); SmallVector<Decl*, 2> Decls; for ( ; Begin != End; ++Begin) Decls.push_back(*Begin); @@ -187,7 +187,10 @@ void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) { void StmtPrinter::PrintRawIfStmt(IfStmt *If) { OS << "if ("; - PrintExpr(If->getCond()); + if (const DeclStmt *DS = If->getConditionVariableDeclStmt()) + PrintRawDeclStmt(DS); + else + PrintExpr(If->getCond()); OS << ')'; if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) { @@ -224,7 +227,10 @@ void StmtPrinter::VisitIfStmt(IfStmt *If) { void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { Indent() << "switch ("; - PrintExpr(Node->getCond()); + if (const DeclStmt *DS = Node->getConditionVariableDeclStmt()) + PrintRawDeclStmt(DS); + else + PrintExpr(Node->getCond()); OS << ")"; // Pretty print compoundstmt bodies (very common). @@ -240,7 +246,10 @@ void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { void StmtPrinter::VisitWhileStmt(WhileStmt *Node) { Indent() << "while ("; - PrintExpr(Node->getCond()); + if (const DeclStmt *DS = Node->getConditionVariableDeclStmt()) + PrintRawDeclStmt(DS); + else + PrintExpr(Node->getCond()); OS << ")\n"; PrintStmt(Node->getBody()); } @@ -366,7 +375,7 @@ void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) { } -void StmtPrinter::VisitAsmStmt(AsmStmt *Node) { +void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) { Indent() << "asm "; if (Node->isVolatile()) @@ -422,7 +431,7 @@ void StmtPrinter::VisitAsmStmt(AsmStmt *Node) { if (i != 0) OS << ", "; - VisitStringLiteral(Node->getClobber(i)); + VisitStringLiteral(Node->getClobberStringLiteral(i)); } OS << ");\n"; @@ -734,10 +743,30 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { case BuiltinType::UInt128: OS << "Ui128"; break; } } -void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) { + +static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node, + bool PrintSuffix) { SmallString<16> Str; Node->getValue().toString(Str); OS << Str; + if (Str.find_first_not_of("-0123456789") == StringRef::npos) + OS << '.'; // Trailing dot in order to separate from ints. + + if (!PrintSuffix) + return; + + // Emit suffixes. Float literals are always a builtin float type. + switch (Node->getType()->getAs<BuiltinType>()->getKind()) { + default: llvm_unreachable("Unexpected type for float literal!"); + case BuiltinType::Half: break; // FIXME: suffix? + case BuiltinType::Double: break; // no suffix. + case BuiltinType::Float: OS << 'F'; break; + case BuiltinType::LongDouble: OS << 'L'; break; + } +} + +void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) { + PrintFloatingLiteral(OS, Node, /*PrintSuffix=*/true); } void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) { @@ -907,7 +936,7 @@ void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { OS << Node->getAccessor().getName(); } void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { - OS << "(" << Node->getType().getAsString(Policy) << ")"; + OS << "(" << Node->getTypeAsWritten().getAsString(Policy) << ")"; PrintExpr(Node->getSubExpr()); } void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) { @@ -1110,6 +1139,8 @@ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { PrintExpr(Node->getArg(0)); OS << ' ' << OpStrings[Kind]; } + } else if (Kind == OO_Arrow) { + PrintExpr(Node->getArg(0)); } else if (Kind == OO_Call) { PrintExpr(Node->getArg(0)); OS << '('; @@ -1217,7 +1248,12 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) { OS << Int->getValue().toString(10, /*isSigned*/false); break; } - case UserDefinedLiteral::LOK_Floating: + case UserDefinedLiteral::LOK_Floating: { + // Print floating literal without suffix. + FloatingLiteral *Float = cast<FloatingLiteral>(Node->getCookedLiteral()); + PrintFloatingLiteral(OS, Float, /*PrintSuffix=*/false); + break; + } case UserDefinedLiteral::LOK_String: case UserDefinedLiteral::LOK_Character: PrintExpr(Node->getCookedLiteral()); @@ -1379,10 +1415,12 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) { OS << "::"; OS << "new "; unsigned NumPlace = E->getNumPlacementArgs(); - if (NumPlace > 0) { + if (NumPlace > 0 && !isa<CXXDefaultArgExpr>(E->getPlacementArg(0))) { OS << "("; PrintExpr(E->getPlacementArg(0)); for (unsigned i = 1; i < NumPlace; ++i) { + if (isa<CXXDefaultArgExpr>(E->getPlacementArg(i))) + break; OS << ", "; PrintExpr(E->getPlacementArg(i)); } @@ -1429,6 +1467,7 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { OS << '.'; if (E->getQualifier()) E->getQualifier()->print(OS, Policy); + OS << "~"; std::string TypeS; if (IdentifierInfo *II = E->getDestroyedTypeIdentifier()) @@ -1531,6 +1570,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) { case UTT_IsFunction: return "__is_function"; case UTT_IsFundamental: return "__is_fundamental"; case UTT_IsIntegral: return "__is_integral"; + case UTT_IsInterfaceClass: return "__is_interface_class"; case UTT_IsLiteral: return "__is_literal"; case UTT_IsLvalueReference: return "__is_lvalue_reference"; case UTT_IsMemberFunctionPointer: return "__is_member_function_pointer"; @@ -1647,6 +1687,10 @@ void StmtPrinter::VisitSubstNonTypeTemplateParmExpr( Visit(Node->getReplacement()); } +void StmtPrinter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { + OS << *E->getParameterPack(); +} + void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){ PrintExpr(Node->GetTemporaryExpr()); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 2168b64..bfd3132 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -158,7 +158,7 @@ void StmtProfiler::VisitReturnStmt(const ReturnStmt *S) { VisitStmt(S); } -void StmtProfiler::VisitAsmStmt(const AsmStmt *S) { +void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) { VisitStmt(S); ID.AddBoolean(S->isVolatile()); ID.AddBoolean(S->isSimple()); @@ -175,7 +175,7 @@ void StmtProfiler::VisitAsmStmt(const AsmStmt *S) { } ID.AddInteger(S->getNumClobbers()); for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) - VisitStringLiteral(S->getClobber(I)); + VisitStringLiteral(S->getClobberStringLiteral(I)); } void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) { @@ -973,6 +973,14 @@ void StmtProfiler::VisitSubstNonTypeTemplateParmExpr( Visit(E->getReplacement()); } +void StmtProfiler::VisitFunctionParmPackExpr(const FunctionParmPackExpr *S) { + VisitExpr(S); + VisitDecl(S->getParameterPack()); + ID.AddInteger(S->getNumExpansions()); + for (FunctionParmPackExpr::iterator I = S->begin(), E = S->end(); I != E; ++I) + VisitDecl(*I); +} + void StmtProfiler::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *S) { VisitExpr(S); @@ -1165,6 +1173,10 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { VisitDecl(Arg.getAsDecl()); break; + case TemplateArgument::NullPtr: + VisitType(Arg.getNullPtrType()); + break; + case TemplateArgument::Integral: Arg.getAsIntegral().Profile(ID); VisitType(Arg.getIntegralType()); diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index 95ff4ed..e9ee385 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -77,7 +77,7 @@ TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context, const TemplateArgument *Args, unsigned NumArgs) { if (NumArgs == 0) - return TemplateArgument(0, 0); + return getEmptyPack(); TemplateArgument *Storage = new (Context) TemplateArgument [NumArgs]; std::copy(Args, Args + NumArgs, Storage); @@ -99,12 +99,11 @@ bool TemplateArgument::isDependent() const { return true; case Declaration: - if (Decl *D = getAsDecl()) { - if (DeclContext *DC = dyn_cast<DeclContext>(D)) - return DC->isDependentContext(); - return D->getDeclContext()->isDependentContext(); - } - + if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl())) + return DC->isDependentContext(); + return getAsDecl()->getDeclContext()->isDependentContext(); + + case NullPtr: return false; case Integral: @@ -141,11 +140,11 @@ bool TemplateArgument::isInstantiationDependent() const { return true; case Declaration: - if (Decl *D = getAsDecl()) { - if (DeclContext *DC = dyn_cast<DeclContext>(D)) - return DC->isDependentContext(); - return D->getDeclContext()->isDependentContext(); - } + if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl())) + return DC->isDependentContext(); + return getAsDecl()->getDeclContext()->isDependentContext(); + + case NullPtr: return false; case Integral: @@ -174,6 +173,7 @@ bool TemplateArgument::isPackExpansion() const { case Integral: case Pack: case Template: + case NullPtr: return false; case TemplateExpansion: @@ -195,6 +195,7 @@ bool TemplateArgument::containsUnexpandedParameterPack() const { case Declaration: case Integral: case TemplateExpansion: + case NullPtr: break; case Type: @@ -286,12 +287,16 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const { switch (getKind()) { case Null: case Type: - case Declaration: case Expression: case Template: case TemplateExpansion: + case NullPtr: return TypeOrValue == Other.TypeOrValue; + case Declaration: + return getAsDecl() == Other.getAsDecl() && + isDeclForReferenceParam() && Other.isDeclForReferenceParam(); + case Integral: return getIntegralType() == Other.getIntegralType() && getAsIntegral() == Other.getAsIntegral(); @@ -319,12 +324,13 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const { case TemplateExpansion: return TemplateArgument(getAsTemplateOrTemplatePattern()); - + case Declaration: case Integral: case Pack: case Null: case Template: + case NullPtr: return TemplateArgument(); } @@ -348,18 +354,20 @@ void TemplateArgument::print(const PrintingPolicy &Policy, } case Declaration: { - if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getAsDecl())) { - if (ND->getDeclName()) { - Out << *ND; - } else { - Out << "<anonymous>"; - } + NamedDecl *ND = cast<NamedDecl>(getAsDecl()); + if (ND->getDeclName()) { + // FIXME: distinguish between pointer and reference args? + Out << *ND; } else { - Out << "nullptr"; + Out << "<anonymous>"; } break; } - + + case NullPtr: + Out << "nullptr"; + break; + case Template: getAsTemplate().print(Out, Policy); break; @@ -411,6 +419,9 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { case TemplateArgument::Declaration: return getSourceDeclExpression()->getSourceRange(); + case TemplateArgument::NullPtr: + return getSourceNullPtrExpression()->getSourceRange(); + case TemplateArgument::Type: if (TypeSourceInfo *TSI = getTypeSourceInfo()) return TSI->getTypeLoc().getSourceRange(); @@ -430,6 +441,8 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc()); case TemplateArgument::Integral: + return getSourceIntegralExpression()->getSourceRange(); + case TemplateArgument::Pack: case TemplateArgument::Null: return SourceRange(); @@ -490,6 +503,7 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis, getTemplateNameLoc()); case TemplateArgument::Declaration: + case TemplateArgument::NullPtr: case TemplateArgument::Template: case TemplateArgument::Integral: case TemplateArgument::Pack: @@ -512,8 +526,9 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, return DB << Arg.getAsType(); case TemplateArgument::Declaration: - if (Decl *D = Arg.getAsDecl()) - return DB << D; + return DB << Arg.getAsDecl(); + + case TemplateArgument::NullPtr: return DB << "nullptr"; case TemplateArgument::Integral: diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index abefae4..580ec50 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -288,18 +288,17 @@ QualType QualType::IgnoreParens(QualType T) { return T; } -/// \brief This will check for a TypedefType by removing any existing sugar -/// until it reaches a TypedefType or a non-sugared type. -template <> const TypedefType *Type::getAs() const { - const Type *Cur = this; - +/// \brief This will check for a T (which should be a Type which can act as +/// sugar, such as a TypedefType) by removing any existing sugar until it +/// reaches a T or a non-sugared type. +template<typename T> static const T *getAsSugar(const Type *Cur) { while (true) { - if (const TypedefType *TDT = dyn_cast<TypedefType>(Cur)) - return TDT; + if (const T *Sugar = dyn_cast<T>(Cur)) + return Sugar; switch (Cur->getTypeClass()) { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ - case Class: { \ + case Type::Class: { \ const Class##Type *Ty = cast<Class##Type>(Cur); \ if (!Ty->isSugared()) return 0; \ Cur = Ty->desugar().getTypePtr(); \ @@ -310,6 +309,14 @@ template <> const TypedefType *Type::getAs() const { } } +template <> const TypedefType *Type::getAs() const { + return getAsSugar<TypedefType>(this); +} + +template <> const TemplateSpecializationType *Type::getAs() const { + return getAsSugar<TemplateSpecializationType>(this); +} + /// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic /// sugar off the given type. This should produce an object of the /// same dynamic type as the canonical type. @@ -357,9 +364,15 @@ bool Type::isStructureType() const { return RT->getDecl()->isStruct(); return false; } +bool Type::isInterfaceType() const { + if (const RecordType *RT = getAs<RecordType>()) + return RT->getDecl()->isInterface(); + return false; +} bool Type::isStructureOrClassType() const { if (const RecordType *RT = getAs<RecordType>()) - return RT->getDecl()->isStruct() || RT->getDecl()->isClass(); + return RT->getDecl()->isStruct() || RT->getDecl()->isClass() || + RT->getDecl()->isInterface(); return false; } bool Type::isVoidPointerType() const { @@ -499,10 +512,18 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { return 0; } -const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const { +const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const { + QualType PointeeType; if (const PointerType *PT = getAs<PointerType>()) - if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) - return dyn_cast<CXXRecordDecl>(RT->getDecl()); + PointeeType = PT->getPointeeType(); + else if (const ReferenceType *RT = getAs<ReferenceType>()) + PointeeType = RT->getPointeeType(); + else + return 0; + + if (const RecordType *RT = PointeeType->getAs<RecordType>()) + return dyn_cast<CXXRecordDecl>(RT->getDecl()); + return 0; } @@ -1205,8 +1226,6 @@ bool QualType::isCXX11PODType(ASTContext &Context) const { return false; case Qualifiers::OCL_None: - if (ty->isObjCLifetimeType()) - return false; break; } } @@ -1317,6 +1336,7 @@ TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { case TST_typename: return ETK_Typename; case TST_class: return ETK_Class; case TST_struct: return ETK_Struct; + case TST_interface: return ETK_Interface; case TST_union: return ETK_Union; case TST_enum: return ETK_Enum; } @@ -1327,6 +1347,7 @@ TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) { switch(TypeSpec) { case TST_class: return TTK_Class; case TST_struct: return TTK_Struct; + case TST_interface: return TTK_Interface; case TST_union: return TTK_Union; case TST_enum: return TTK_Enum; } @@ -1339,6 +1360,7 @@ TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { switch (Kind) { case TTK_Class: return ETK_Class; case TTK_Struct: return ETK_Struct; + case TTK_Interface: return ETK_Interface; case TTK_Union: return ETK_Union; case TTK_Enum: return ETK_Enum; } @@ -1350,6 +1372,7 @@ TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ETK_Class: return TTK_Class; case ETK_Struct: return TTK_Struct; + case ETK_Interface: return TTK_Interface; case ETK_Union: return TTK_Union; case ETK_Enum: return TTK_Enum; case ETK_None: // Fall through. @@ -1367,6 +1390,7 @@ TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { return false; case ETK_Class: case ETK_Struct: + case ETK_Interface: case ETK_Union: case ETK_Enum: return true; @@ -1381,6 +1405,7 @@ TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { case ETK_Typename: return "typename"; case ETK_Class: return "class"; case ETK_Struct: return "struct"; + case ETK_Interface: return "__interface"; case ETK_Union: return "union"; case ETK_Enum: return "enum"; } @@ -1480,6 +1505,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { case Dependent: return "<dependent type>"; case UnknownAny: return "<unknown type>"; case ARCUnbridgedCast: return "<ARC unbridged cast type>"; + case BuiltinFn: return "<builtin fn type>"; case ObjCId: return "id"; case ObjCClass: return "Class"; case ObjCSel: return "SEL"; @@ -1516,6 +1542,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_X86Pascal: return "pascal"; case CC_AAPCS: return "aapcs"; case CC_AAPCS_VFP: return "aapcs-vfp"; + case CC_PnaclCall: return "pnaclcall"; } llvm_unreachable("Invalid calling convention."); diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index c7bb7da..58c4cbd 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -98,23 +98,38 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, SourceLocation TypeLoc::getBeginLoc() const { TypeLoc Cur = *this; + TypeLoc LeftMost = Cur; while (true) { switch (Cur.getTypeLocClass()) { - // FIXME: Currently QualifiedTypeLoc does not have a source range - // case Qualified: case Elaborated: - case DependentName: - case DependentTemplateSpecialization: + LeftMost = Cur; break; + case FunctionProto: + if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) { + LeftMost = Cur; + break; + } + /* Fall through */ + case FunctionNoProto: + case ConstantArray: + case DependentSizedArray: + case IncompleteArray: + case VariableArray: + // FIXME: Currently QualifiedTypeLoc does not have a source range + case Qualified: + Cur = Cur.getNextTypeLoc(); + continue; default: - TypeLoc Next = Cur.getNextTypeLoc(); - if (Next.isNull()) break; - Cur = Next; + if (!Cur.getLocalSourceRange().getBegin().isInvalid()) + LeftMost = Cur; + Cur = Cur.getNextTypeLoc(); + if (Cur.isNull()) + break; continue; - } + } // switch break; - } - return Cur.getLocalSourceRange().getBegin(); + } // while + return LeftMost.getLocalSourceRange().getBegin(); } SourceLocation TypeLoc::getEndLoc() const { @@ -131,10 +146,15 @@ SourceLocation TypeLoc::getEndLoc() const { case DependentSizedArray: case IncompleteArray: case VariableArray: - case FunctionProto: case FunctionNoProto: Last = Cur; break; + case FunctionProto: + if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) + Last = TypeLoc(); + else + Last = Cur; + break; case Pointer: case BlockPointer: case MemberPointer: @@ -241,6 +261,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: + case BuiltinType::BuiltinFn: return TST_unspecified; } @@ -300,7 +321,9 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, case TemplateArgument::Null: case TemplateArgument::Declaration: case TemplateArgument::Integral: - case TemplateArgument::Pack: + case TemplateArgument::NullPtr: + llvm_unreachable("Impossible TemplateArgument"); + case TemplateArgument::Expression: ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr()); break; @@ -310,7 +333,7 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, Context.getTrivialTypeSourceInfo(Args[i].getAsType(), Loc)); break; - + case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { NestedNameSpecifierLocBuilder Builder; @@ -327,7 +350,11 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, ? SourceLocation() : Loc); break; - } + } + + case TemplateArgument::Pack: + ArgInfos[i] = TemplateArgumentLocInfo(); + break; } } } diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index c42117c..90b2ca9 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -141,9 +141,6 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, raw_ostream &OS, OS << "NULL TYPE"; return; } - - if (Policy.SuppressSpecifiers && T->isSpecifierType()) - return; SaveAndRestore<bool> PHVal(HasEmptyPlaceHolder, PlaceHolder.empty()); @@ -556,7 +553,8 @@ void TypePrinter::printExtVectorAfter(const ExtVectorType *T, raw_ostream &OS) { void FunctionProtoType::printExceptionSpecification(raw_ostream &OS, - PrintingPolicy Policy) const { + const PrintingPolicy &Policy) + const { if (hasDynamicExceptionSpec()) { OS << " throw("; @@ -646,6 +644,9 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, case CC_AAPCS_VFP: OS << " __attribute__((pcs(\"aapcs-vfp\")))"; break; + case CC_PnaclCall: + OS << " __attribute__((pnaclcall))"; + break; } if (Info.getNoReturn()) OS << " __attribute__((noreturn))"; @@ -798,6 +799,7 @@ void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { } /// Appends the given scope to the end of a string. void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) { if (DC->isTranslationUnit()) return; + if (DC->isFunctionOrMethod()) return; AppendScope(DC->getParent(), OS); if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { @@ -1165,6 +1167,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, OS << ')'; break; } + case AttributedType::attr_pnaclcall: OS << "pnaclcall"; break; } OS << "))"; } @@ -1343,7 +1346,8 @@ PrintTemplateArgumentList(raw_ostream &OS, void FunctionProtoType::printExceptionSpecification(std::string &S, - PrintingPolicy Policy) const { + const PrintingPolicy &Policy) + const { if (hasDynamicExceptionSpec()) { S += " throw("; diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index 104530f..33dad40 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -1891,6 +1891,9 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { if (MD->isPure()) Out << " [pure]"; + if (MD->isDeleted()) + Out << " [deleted]"; + ThunkInfo Thunk = VTableThunks.lookup(I); if (!Thunk.isEmpty()) { // If this function pointer has a return adjustment, dump it. |