diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2011-05-02 19:39:53 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2011-05-02 19:39:53 +0000 |
commit | 01af97d3b23bded2b2b21af19bbc6e4cce49e5b3 (patch) | |
tree | 64a10f4c4154739d4a8191d7e1b52ce497f4ebd6 /lib | |
parent | c3b054d250cdca485c71845089c316e10610ebad (diff) | |
download | src-01af97d3b23bded2b2b21af19bbc6e4cce49e5b3.tar.gz src-01af97d3b23bded2b2b21af19bbc6e4cce49e5b3.zip |
Vendor import of clang trunk r130700:vendor/clang/clang-r130700
Notes
Notes:
svn path=/vendor/clang/dist/; revision=221339
svn path=/vendor/clang/clang-r130700/; revision=221340; tag=vendor/clang/clang-r130700
Diffstat (limited to 'lib')
306 files changed, 29868 insertions, 15140 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 9c2455034d68..8316ea68e9e4 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -107,7 +107,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) CanonParams.push_back( TemplateTypeParmDecl::Create(*this, getTranslationUnitDecl(), - SourceLocation(), TTP->getDepth(), + SourceLocation(), + SourceLocation(), + TTP->getDepth(), TTP->getIndex(), 0, false, TTP->isParameterPack())); else if (NonTypeTemplateParmDecl *NTTP @@ -125,7 +127,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( } Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), - SourceLocation(), + SourceLocation(), + SourceLocation(), NTTP->getDepth(), NTTP->getPosition(), 0, T, @@ -135,7 +138,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( ExpandedTInfos.data()); } else { Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), - SourceLocation(), + SourceLocation(), + SourceLocation(), NTTP->getDepth(), NTTP->getPosition(), 0, T, @@ -186,11 +190,28 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { return 0; } +static const LangAS::Map &getAddressSpaceMap(const TargetInfo &T, + const LangOptions &LOpts) { + if (LOpts.FakeAddressSpaceMap) { + // The fake address space map must have a distinct entry for each + // language-specific address space. + static const unsigned FakeAddrSpaceMap[] = { + 1, // opencl_global + 2, // opencl_local + 3 // opencl_constant + }; + return FakeAddrSpaceMap; + } else { + return T.getAddressSpaceMap(); + } +} + ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, const TargetInfo &t, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins, unsigned size_reserve) : + FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), GlobalNestedNameSpecifier(0), IsInt128Installed(false), @@ -199,7 +220,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0), NullTypeSourceInfo(QualType()), - SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), Target(t), + SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), + AddrSpaceMap(getAddressSpaceMap(t, LOpts)), Target(t), Idents(idents), Selectors(sels), BuiltinInfo(builtins), DeclarationNames(*this), @@ -353,7 +375,7 @@ void ASTContext::InitBuiltinTypes() { InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); if (LangOpts.CPlusPlus) { // C++ 3.9.1p5 - if (!LangOpts.ShortWChar) + if (TargetInfo::isTypeSigned(Target.getWCharType())) InitBuiltinType(WCharTy, BuiltinType::WChar_S); else // -fshort-wchar makes wchar_t be unsigned. InitBuiltinType(WCharTy, BuiltinType::WChar_U); @@ -380,6 +402,12 @@ void ASTContext::InitBuiltinTypes() { // Placeholder type for functions. InitBuiltinType(OverloadTy, BuiltinType::Overload); + // Placeholder type for bound members. + InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember); + + // "any" type; useful for debugger-like clients. + InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny); + // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); DoubleComplexTy = getComplexType(DoubleTy); @@ -429,7 +457,6 @@ void ASTContext::eraseDeclAttrs(const Decl *D) { } } - MemberSpecializationInfo * ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) { assert(Var->isStaticDataMember() && "Not a static data member"); @@ -509,6 +536,20 @@ void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl; } +bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const { + return (FD->isBitField() && LastFD && !LastFD->isBitField() && + FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0); + +} + +bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const { + return (FD->isBitField() && LastFD && LastFD->isBitField() && + FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0); + +} + ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos @@ -697,6 +738,7 @@ ASTContext::getTypeInfo(const Type *T) const { std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(CAT->getElementType()); Width = EltInfo.first*CAT->getSize().getZExtValue(); Align = EltInfo.second; + Width = llvm::RoundUpToAlignment(Width, Align); break; } case Type::ExtVector: @@ -801,7 +843,8 @@ ASTContext::getTypeInfo(const Type *T) const { Align = Target.getPointerAlign(0); break; case Type::BlockPointer: { - unsigned AS = cast<BlockPointerType>(T)->getPointeeType().getAddressSpace(); + unsigned AS = getTargetAddressSpace( + cast<BlockPointerType>(T)->getPointeeType()); Width = Target.getPointerWidth(AS); Align = Target.getPointerAlign(AS); break; @@ -810,13 +853,14 @@ ASTContext::getTypeInfo(const Type *T) const { case Type::RValueReference: { // alignof and sizeof should never enter this code path here, so we go // the pointer route. - unsigned AS = cast<ReferenceType>(T)->getPointeeType().getAddressSpace(); + unsigned AS = getTargetAddressSpace( + cast<ReferenceType>(T)->getPointeeType()); Width = Target.getPointerWidth(AS); Align = Target.getPointerAlign(AS); break; } case Type::Pointer: { - unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace(); + unsigned AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType()); Width = Target.getPointerWidth(AS); Align = Target.getPointerAlign(AS); break; @@ -852,8 +896,8 @@ ASTContext::getTypeInfo(const Type *T) const { const TagType *TT = cast<TagType>(T); if (TT->getDecl()->isInvalidDecl()) { - Width = 1; - Align = 1; + Width = 8; + Align = 8; break; } @@ -881,7 +925,7 @@ ASTContext::getTypeInfo(const Type *T) const { return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr()); case Type::Typedef: { - const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl(); + const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl(); std::pair<uint64_t, unsigned> Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); // If the typedef has an aligned attribute on it, it overrides any computed @@ -1463,7 +1507,7 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, // the target. llvm::APInt ArySize(ArySizeIn); ArySize = - ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); + ArySize.zextOrTrunc(Target.getPointerWidth(getTargetAddressSpace(EltTy))); llvm::FoldingSetNodeID ID; ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals); @@ -1862,7 +1906,9 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType, QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, const FunctionType::ExtInfo &Info) const { - const CallingConv CallConv = Info.getCC(); + const CallingConv DefaultCC = Info.getCC(); + const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ? + CC_X86StdCall : DefaultCC; // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; @@ -1886,8 +1932,9 @@ ASTContext::getFunctionNoProtoType(QualType ResultTy, assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } + FunctionProtoType::ExtInfo newInfo = Info.withCallingConv(CallConv); FunctionNoProtoType *New = new (*this, TypeAlignment) - FunctionNoProtoType(ResultTy, Canonical, Info); + FunctionNoProtoType(ResultTy, Canonical, newInfo); Types.push_back(New); FunctionNoProtoTypes.InsertNode(New, InsertPos); return QualType(New, 0); @@ -1902,7 +1949,7 @@ ASTContext::getFunctionType(QualType ResultTy, // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; - FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI); + FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI, *this); void *InsertPos = 0; if (FunctionProtoType *FTP = @@ -1910,12 +1957,14 @@ ASTContext::getFunctionType(QualType ResultTy, return QualType(FTP, 0); // Determine whether the type being created is already canonical or not. - bool isCanonical = !EPI.HasExceptionSpec && ResultTy.isCanonical(); + bool isCanonical= EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical(); for (unsigned i = 0; i != NumArgs && isCanonical; ++i) if (!ArgArray[i].isCanonicalAsParam()) isCanonical = false; - const CallingConv CallConv = EPI.ExtInfo.getCC(); + const CallingConv DefaultCC = EPI.ExtInfo.getCC(); + const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ? + CC_X86StdCall : DefaultCC; // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. @@ -1927,11 +1976,8 @@ ASTContext::getFunctionType(QualType ResultTy, CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i])); FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI; - if (CanonicalEPI.HasExceptionSpec) { - CanonicalEPI.HasExceptionSpec = false; - CanonicalEPI.HasAnyExceptionSpec = false; - CanonicalEPI.NumExceptions = 0; - } + CanonicalEPI.ExceptionSpecType = EST_None; + CanonicalEPI.NumExceptions = 0; CanonicalEPI.ExtInfo = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv)); @@ -1947,12 +1993,19 @@ ASTContext::getFunctionType(QualType ResultTy, // FunctionProtoType objects are allocated with extra bytes after them // for two variable size arrays (for parameter and exception types) at the - // end of them. + // end of them. Instead of the exception types, there could be a noexcept + // expression and a context pointer. size_t Size = sizeof(FunctionProtoType) + - NumArgs * sizeof(QualType) + - EPI.NumExceptions * sizeof(QualType); + NumArgs * sizeof(QualType); + if (EPI.ExceptionSpecType == EST_Dynamic) + Size += EPI.NumExceptions * sizeof(QualType); + else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { + Size += sizeof(Expr*); + } FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); - new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, EPI); + FunctionProtoType::ExtProtoInfo newEPI = EPI; + newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv); + new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); @@ -1997,7 +2050,7 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const { assert(Decl && "Passed null for Decl param"); assert(!Decl->TypeForDecl && "TypeForDecl present in slow case"); - if (const TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl)) + if (const TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Decl)) return getTypedefType(Typedef); assert(!isa<TemplateTypeParmDecl>(Decl) && @@ -2024,9 +2077,10 @@ QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const { } /// getTypedefType - Return the unique reference to the type for the -/// specified typename decl. +/// specified typedef name decl. QualType -ASTContext::getTypedefType(const TypedefDecl *Decl, QualType Canonical) const { +ASTContext::getTypedefType(const TypedefNameDecl *Decl, + QualType Canonical) const { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); if (Canonical.isNull()) @@ -2149,9 +2203,9 @@ QualType ASTContext::getSubstTemplateTypeParmPackType( /// name. QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, bool ParameterPack, - IdentifierInfo *Name) const { + TemplateTypeParmDecl *TTPDecl) const { llvm::FoldingSetNodeID ID; - TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, Name); + TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, TTPDecl); void *InsertPos = 0; TemplateTypeParmType *TypeParm = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); @@ -2159,10 +2213,9 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, if (TypeParm) return QualType(TypeParm, 0); - if (Name) { + if (TTPDecl) { QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack); - TypeParm = new (*this, TypeAlignment) - TemplateTypeParmType(Depth, Index, ParameterPack, Name, Canon); + TypeParm = new (*this, TypeAlignment) TemplateTypeParmType(TTPDecl, Canon); TemplateTypeParmType *TypeCheck = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); @@ -2183,6 +2236,8 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &Args, QualType CanonType) const { + assert(!Name.getAsDependentTemplateName() && + "No dependent template names here!"); QualType TST = getTemplateSpecializationType(Name, Args, CanonType); TypeSourceInfo *DI = CreateTypeSourceInfo(TST); @@ -2200,6 +2255,9 @@ QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgumentListInfo &Args, QualType Canon) const { + assert(!Template.getAsDependentTemplateName() && + "No dependent template names here!"); + unsigned NumArgs = Args.size(); llvm::SmallVector<TemplateArgument, 4> ArgVec; @@ -2216,6 +2274,12 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, QualType Canon) const { + assert(!Template.getAsDependentTemplateName() && + "No dependent template names here!"); + // Look through qualified template names. + if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + Template = TemplateName(QTN->getTemplateDecl()); + if (!Canon.isNull()) Canon = getCanonicalType(Canon); else @@ -2240,6 +2304,12 @@ QualType ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs) const { + assert(!Template.getAsDependentTemplateName() && + "No dependent template names here!"); + // Look through qualified template names. + if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + Template = TemplateName(QTN->getTemplateDecl()); + // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); llvm::SmallVector<TemplateArgument, 4> CanonArgs; @@ -2377,7 +2447,8 @@ ASTContext::getDependentTemplateSpecializationType( const IdentifierInfo *Name, unsigned NumArgs, const TemplateArgument *Args) const { - assert(NNS->isDependent() && "nested-name-specifier must be dependent"); + assert((!NNS || NNS->isDependent()) && + "nested-name-specifier must be dependent"); llvm::FoldingSetNodeID ID; DependentTemplateSpecializationType::Profile(ID, *this, Keyword, NNS, @@ -2701,6 +2772,22 @@ QualType ASTContext::getAutoType(QualType DeducedType) const { return QualType(AT, 0); } +/// getAutoDeductType - Get type pattern for deducing against 'auto'. +QualType ASTContext::getAutoDeductType() const { + if (AutoDeductTy.isNull()) + AutoDeductTy = getAutoType(QualType()); + assert(!AutoDeductTy.isNull() && "can't build 'auto' pattern"); + return AutoDeductTy; +} + +/// getAutoRRefDeductType - Get type pattern for deducing against 'auto &&'. +QualType ASTContext::getAutoRRefDeductType() const { + if (AutoRRefDeductTy.isNull()) + AutoRRefDeductTy = getRValueReferenceType(getAutoDeductType()); + assert(!AutoRRefDeductTy.isNull() && "can't build 'auto &&' pattern"); + return AutoRRefDeductTy; +} + /// getTagDeclType - Return the unique reference to the type for the /// specified TagDecl (struct/union/class/enum) decl. QualType ASTContext::getTagDeclType(const TagDecl *Decl) const { @@ -3014,10 +3101,11 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { = T->getAs<DependentTemplateSpecializationType>()) { NestedNameSpecifier *Prefix = getCanonicalNestedNameSpecifier(DTST->getQualifier()); - TemplateName Name - = getDependentTemplateName(Prefix, DTST->getIdentifier()); - T = getTemplateSpecializationType(Name, - DTST->getArgs(), DTST->getNumArgs()); + + T = getDependentTemplateSpecializationType(DTST->getKeyword(), + Prefix, DTST->getIdentifier(), + DTST->getNumArgs(), + DTST->getArgs()); T = getCanonicalType(T); } @@ -3334,19 +3422,20 @@ int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) const { } static RecordDecl * -CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id) { +CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK, + DeclContext *DC, IdentifierInfo *Id) { + SourceLocation Loc; if (Ctx.getLangOptions().CPlusPlus) - return CXXRecordDecl::Create(Ctx, TK, DC, L, Id); + return CXXRecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id); else - return RecordDecl::Create(Ctx, TK, DC, L, Id); + return RecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id); } - + // getCFConstantStringType - Return the type used for constant CFStrings. QualType ASTContext::getCFConstantStringType() const { if (!CFConstantStringTypeDecl) { CFConstantStringTypeDecl = - CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), + CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get("NSConstantString")); CFConstantStringTypeDecl->startDefinition(); @@ -3364,6 +3453,7 @@ QualType ASTContext::getCFConstantStringType() const { // Create fields for (unsigned i = 0; i < 4; ++i) { FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl, + SourceLocation(), SourceLocation(), 0, FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, @@ -3388,7 +3478,7 @@ void ASTContext::setCFConstantStringType(QualType T) { QualType ASTContext::getNSConstantStringType() const { if (!NSConstantStringTypeDecl) { NSConstantStringTypeDecl = - CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), + CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get("__builtin_NSString")); NSConstantStringTypeDecl->startDefinition(); @@ -3404,6 +3494,7 @@ QualType ASTContext::getNSConstantStringType() const { // Create fields for (unsigned i = 0; i < 3; ++i) { FieldDecl *Field = FieldDecl::Create(*this, NSConstantStringTypeDecl, + SourceLocation(), SourceLocation(), 0, FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, @@ -3427,7 +3518,7 @@ void ASTContext::setNSConstantStringType(QualType T) { QualType ASTContext::getObjCFastEnumerationStateType() const { if (!ObjCFastEnumerationStateTypeDecl) { ObjCFastEnumerationStateTypeDecl = - CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), + CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get("__objcFastEnumerationState")); ObjCFastEnumerationStateTypeDecl->startDefinition(); @@ -3442,6 +3533,7 @@ QualType ASTContext::getObjCFastEnumerationStateType() const { for (size_t i = 0; i < 4; ++i) { FieldDecl *Field = FieldDecl::Create(*this, ObjCFastEnumerationStateTypeDecl, + SourceLocation(), SourceLocation(), 0, FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, @@ -3462,7 +3554,7 @@ QualType ASTContext::getBlockDescriptorType() const { RecordDecl *T; // FIXME: Needs the FlagAppleBlock bit. - T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), + T = CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get("__block_descriptor")); T->startDefinition(); @@ -3477,8 +3569,7 @@ QualType ASTContext::getBlockDescriptorType() const { }; for (size_t i = 0; i < 2; ++i) { - FieldDecl *Field = FieldDecl::Create(*this, - T, + FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), SourceLocation(), &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, @@ -3507,7 +3598,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { RecordDecl *T; // FIXME: Needs the FlagAppleBlock bit. - T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), + T = CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get("__block_descriptor_withcopydispose")); T->startDefinition(); @@ -3526,8 +3617,7 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { }; for (size_t i = 0; i < 4; ++i) { - FieldDecl *Field = FieldDecl::Create(*this, - T, + FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), SourceLocation(), &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, @@ -3586,8 +3676,7 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const { llvm::raw_svector_ostream(Name) << "__Block_byref_" << ++UniqueBlockByRefTypeID << '_' << DeclName; RecordDecl *T; - T = CreateRecordDecl(*this, TTK_Struct, TUDecl, SourceLocation(), - &Idents.get(Name.str())); + T = CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get(Name.str())); T->startDefinition(); QualType Int32Ty = IntTy; assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported"); @@ -3615,6 +3704,7 @@ ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const { if (!HasCopyAndDispose && i >=4 && i <= 5) continue; FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), + SourceLocation(), &Idents.get(FieldNames[i]), FieldTypes[i], /*TInfo=*/0, /*BitWidth=*/0, /*Mutable=*/false); @@ -4367,6 +4457,8 @@ TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, TemplateDecl *Template) const { + assert(NNS && "Missing nested-name-specifier in qualified template name"); + // FIXME: Canonicalization? llvm::FoldingSetNodeID ID; QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); @@ -4503,7 +4595,7 @@ CanQualType ASTContext::getFromTargetType(unsigned Type) const { /// bool ASTContext::isObjCNSObjectType(QualType Ty) const { if (const TypedefType *TDT = dyn_cast<TypedefType>(Ty)) { - if (TypedefDecl *TD = TDT->getDecl()) + if (TypedefNameDecl *TD = TDT->getDecl()) if (TD->getAttr<ObjCNSObjectAttr>()) return true; } @@ -4795,13 +4887,14 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, } /// canAssignObjCInterfacesInBlockPointer - This routine is specifically written -/// for providing type-safty for objective-c pointers used to pass/return +/// for providing type-safety for objective-c pointers used to pass/return /// arguments in block literals. When passed as arguments, passing 'A*' where /// 'id' is expected is not OK. Passing 'Sub *" where 'Super *" is expected is /// not OK. For the return type, the opposite is not OK. bool ASTContext::canAssignObjCInterfacesInBlockPointer( const ObjCObjectPointerType *LHSOPT, - const ObjCObjectPointerType *RHSOPT) { + const ObjCObjectPointerType *RHSOPT, + bool BlockReturnType) { if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType()) return true; @@ -4819,9 +4912,9 @@ bool ASTContext::canAssignObjCInterfacesInBlockPointer( if (LHS && RHS) { // We have 2 user-defined types. if (LHS != RHS) { if (LHS->getDecl()->isSuperClassOf(RHS->getDecl())) - return false; + return BlockReturnType; if (RHS->getDecl()->isSuperClassOf(LHS->getDecl())) - return true; + return !BlockReturnType; } else return true; @@ -4887,10 +4980,10 @@ QualType ASTContext::areCommonBaseCompatible( const ObjCObjectType *RHS = Rptr->getObjectType(); const ObjCInterfaceDecl* LDecl = LHS->getInterface(); const ObjCInterfaceDecl* RDecl = RHS->getInterface(); - if (!LDecl || !RDecl) + if (!LDecl || !RDecl || (LDecl == RDecl)) return QualType(); - while ((LDecl = LDecl->getSuperClass())) { + do { LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl)); if (canAssignObjCInterfaces(LHS, RHS)) { llvm::SmallVector<ObjCProtocolDecl *, 8> Protocols; @@ -4902,7 +4995,7 @@ QualType ASTContext::areCommonBaseCompatible( Result = getObjCObjectPointerType(Result); return Result; } - } + } while ((LDecl = LDecl->getSuperClass())); return QualType(); } @@ -4922,10 +5015,47 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, if (LHS->getNumProtocols() == 0) return true; - // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, then it - // isn't a superset. - if (RHS->getNumProtocols() == 0) - return true; // FIXME: should return false! + // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, + // more detailed analysis is required. + if (RHS->getNumProtocols() == 0) { + // OK, if LHS is a superclass of RHS *and* + // this superclass is assignment compatible with LHS. + // false otherwise. + bool IsSuperClass = + LHS->getInterface()->isSuperClassOf(RHS->getInterface()); + if (IsSuperClass) { + // OK if conversion of LHS to SuperClass results in narrowing of types + // ; i.e., SuperClass may implement at least one of the protocols + // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok. + // But not SuperObj<P1,P2,P3> = lhs<P1,P2>. + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> SuperClassInheritedProtocols; + CollectInheritedProtocols(RHS->getInterface(), SuperClassInheritedProtocols); + // If super class has no protocols, it is not a match. + if (SuperClassInheritedProtocols.empty()) + return false; + + for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(), + LHSPE = LHS->qual_end(); + LHSPI != LHSPE; LHSPI++) { + bool SuperImplementsProtocol = false; + ObjCProtocolDecl *LHSProto = (*LHSPI); + + for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I = + SuperClassInheritedProtocols.begin(), + E = SuperClassInheritedProtocols.end(); I != E; ++I) { + ObjCProtocolDecl *SuperClassProto = (*I); + if (SuperClassProto->lookupProtocolNamed(LHSProto->getIdentifier())) { + SuperImplementsProtocol = true; + break; + } + } + if (!SuperImplementsProtocol) + return false; + } + return true; + } + return false; + } for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(), LHSPE = LHS->qual_end(); @@ -5045,7 +5175,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, bool UnqualifiedResult = Unqualified; if (!UnqualifiedResult) UnqualifiedResult = (!RHS.hasQualifiers() && LHS.hasQualifiers()); - retType = mergeTypes(RHS, LHS, true, UnqualifiedResult); + retType = mergeTypes(LHS, RHS, true, UnqualifiedResult, true); } else retType = mergeTypes(lbase->getResultType(), rbase->getResultType(), false, @@ -5079,6 +5209,8 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, return QualType(); // Regparm is part of the calling convention. + if (lbaseInfo.getHasRegParm() != rbaseInfo.getHasRegParm()) + return QualType(); if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm()) return QualType(); @@ -5091,6 +5223,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, allRTypes = false; FunctionType::ExtInfo einfo(NoReturn, + lbaseInfo.getHasRegParm(), lbaseInfo.getRegParm(), lbaseInfo.getCC()); @@ -5185,7 +5318,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, - bool Unqualified) { + bool Unqualified, bool BlockReturnType) { // C++ [expr]: If an expression initially has the type "reference to T", the // type is adjusted to "T" prior to any further analysis, the expression // designates the object or function denoted by the reference, and the @@ -5419,7 +5552,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, if (OfBlockPointer) { if (canAssignObjCInterfacesInBlockPointer( LHS->getAs<ObjCObjectPointerType>(), - RHS->getAs<ObjCObjectPointerType>())) + RHS->getAs<ObjCObjectPointerType>(), + BlockReturnType)) return LHS; return QualType(); } @@ -5557,10 +5691,6 @@ QualType ASTContext::getCorrespondingUnsignedType(QualType T) { } } -ExternalASTSource::~ExternalASTSource() { } - -void ExternalASTSource::PrintStats() { } - ASTMutationListener::~ASTMutationListener() { } @@ -6015,3 +6145,19 @@ MangleContext *ASTContext::createMangleContext() { } CXXABI::~CXXABI() {} + +size_t ASTContext::getSideTableAllocatedMemory() const { + size_t bytes = 0; + bytes += ASTRecordLayouts.getMemorySize(); + bytes += ObjCLayouts.getMemorySize(); + bytes += KeyFunctions.getMemorySize(); + bytes += ObjCImpls.getMemorySize(); + bytes += BlockVarCopyInits.getMemorySize(); + bytes += DeclAttrs.getMemorySize(); + bytes += InstantiatedFromStaticDataMember.getMemorySize(); + bytes += InstantiatedFromUsingDecl.getMemorySize(); + bytes += InstantiatedFromUsingShadowDecl.getMemorySize(); + bytes += InstantiatedFromUnnamedFieldDecl.getMemorySize(); + return bytes; +} + diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 5bf8a38199b6..897b4a4c1f27 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -43,6 +43,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) { QT = ST->desugar(); continue; } + // ...or an attributed type... + if (const AttributedType *AT = dyn_cast<AttributedType>(Ty)) { + QT = AT->desugar(); + continue; + } // ... or an auto type. if (const AutoType *AT = dyn_cast<AutoType>(Ty)) { if (!AT->isSugared()) @@ -95,7 +100,7 @@ break; \ // Don't desugar through the primary typedef of an anonymous type. if (const TagType *UTT = Underlying->getAs<TagType>()) if (const TypedefType *QTT = dyn_cast<TypedefType>(QT)) - if (UTT->getDecl()->getTypedefForAnonDecl() == QTT->getDecl()) + if (UTT->getDecl()->getTypedefNameForAnonDecl() == QTT->getDecl()) break; // Record that we actually looked through an opaque type here. diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 21f10fb7ad99..dc881ba86960 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -97,7 +97,9 @@ namespace { bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); Decl *VisitDecl(Decl *D); Decl *VisitNamespaceDecl(NamespaceDecl *D); + Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias); Decl *VisitTypedefDecl(TypedefDecl *D); + Decl *VisitTypeAliasDecl(TypeAliasDecl *D); Decl *VisitEnumDecl(EnumDecl *D); Decl *VisitRecordDecl(RecordDecl *D); Decl *VisitEnumConstantDecl(EnumConstantDecl *D); @@ -139,7 +141,7 @@ namespace { Expr *VisitCharacterLiteral(CharacterLiteral *E); Expr *VisitParenExpr(ParenExpr *E); Expr *VisitUnaryOperator(UnaryOperator *E); - Expr *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + Expr *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); Expr *VisitBinaryOperator(BinaryOperator *E); Expr *VisitCompoundAssignOperator(CompoundAssignOperator *E); Expr *VisitImplicitCastExpr(ImplicitCastExpr *E); @@ -521,16 +523,21 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } if (Proto1->isVariadic() != Proto2->isVariadic()) return false; - if (Proto1->hasExceptionSpec() != Proto2->hasExceptionSpec()) + if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType()) return false; - if (Proto1->hasAnyExceptionSpec() != Proto2->hasAnyExceptionSpec()) - return false; - if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) - return false; - for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { + if (Proto1->getExceptionSpecType() == EST_Dynamic) { + if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) + return false; + for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Proto1->getExceptionType(I), + Proto2->getExceptionType(I))) + return false; + } + } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) { if (!IsStructurallyEquivalent(Context, - Proto1->getExceptionType(I), - Proto2->getExceptionType(I))) + Proto1->getNoexceptExpr(), + Proto2->getNoexceptExpr())) return false; } if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) @@ -830,7 +837,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; } // If one is a class template specialization and the other is not, these - // structures are diferent. + // structures are different. else if (Spec1 || Spec2) return false; @@ -1189,11 +1196,11 @@ bool StructuralEquivalenceContext::Finish() { if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) { // Check for equivalent structure names. IdentifierInfo *Name1 = Record1->getIdentifier(); - if (!Name1 && Record1->getTypedefForAnonDecl()) - Name1 = Record1->getTypedefForAnonDecl()->getIdentifier(); + if (!Name1 && Record1->getTypedefNameForAnonDecl()) + Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier(); IdentifierInfo *Name2 = Record2->getIdentifier(); - if (!Name2 && Record2->getTypedefForAnonDecl()) - Name2 = Record2->getTypedefForAnonDecl()->getIdentifier(); + if (!Name2 && Record2->getTypedefNameForAnonDecl()) + Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier(); if (!::IsStructurallyEquivalent(Name1, Name2) || !::IsStructurallyEquivalent(*this, Record1, Record2)) Equivalent = false; @@ -1205,11 +1212,11 @@ bool StructuralEquivalenceContext::Finish() { if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) { // Check for equivalent enum names. IdentifierInfo *Name1 = Enum1->getIdentifier(); - if (!Name1 && Enum1->getTypedefForAnonDecl()) - Name1 = Enum1->getTypedefForAnonDecl()->getIdentifier(); + if (!Name1 && Enum1->getTypedefNameForAnonDecl()) + Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier(); IdentifierInfo *Name2 = Enum2->getIdentifier(); - if (!Name2 && Enum2->getTypedefForAnonDecl()) - Name2 = Enum2->getTypedefForAnonDecl()->getIdentifier(); + if (!Name2 && Enum2->getTypedefNameForAnonDecl()) + Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier(); if (!::IsStructurallyEquivalent(Name1, Name2) || !::IsStructurallyEquivalent(*this, Enum1, Enum2)) Equivalent = false; @@ -1217,8 +1224,8 @@ bool StructuralEquivalenceContext::Finish() { // Enum/non-enum mismatch Equivalent = false; } - } else if (TypedefDecl *Typedef1 = dyn_cast<TypedefDecl>(D1)) { - if (TypedefDecl *Typedef2 = dyn_cast<TypedefDecl>(D2)) { + } else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) { + if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) { if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(), Typedef2->getIdentifier()) || !::IsStructurallyEquivalent(*this, @@ -1355,6 +1362,8 @@ QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) { case BuiltinType::Overload: return Importer.getToContext().OverloadTy; case BuiltinType::Dependent: return Importer.getToContext().DependentTy; + case BuiltinType::UnknownAny: return Importer.getToContext().UnknownAnyTy; + case BuiltinType::BoundMember: return Importer.getToContext().BoundMemberTy; case BuiltinType::ObjCId: // FIXME: Make sure that the "to" context supports Objective-C! @@ -1530,8 +1539,8 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { } QualType ASTNodeImporter::VisitTypedefType(const TypedefType *T) { - TypedefDecl *ToDecl - = dyn_cast_or_null<TypedefDecl>(Importer.Import(T->getDecl())); + TypedefNameDecl *ToDecl + = dyn_cast_or_null<TypedefNameDecl>(Importer.Import(T->getDecl())); if (!ToDecl) return QualType(); @@ -1967,8 +1976,9 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { // Create the "to" namespace, if needed. NamespaceDecl *ToNamespace = MergeWithNamespace; if (!ToNamespace) { - ToNamespace = NamespaceDecl::Create(Importer.getToContext(), DC, Loc, - Name.getAsIdentifierInfo()); + ToNamespace = NamespaceDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getLocStart()), + Loc, Name.getAsIdentifierInfo()); ToNamespace->setLexicalDeclContext(LexicalDC); LexicalDC->addDecl(ToNamespace); @@ -1988,7 +1998,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { return ToNamespace; } -Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) { +Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { // Import the major distinguishing characteristics of this typedef. DeclContext *DC, *LexicalDC; DeclarationName Name; @@ -2007,7 +2017,8 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) { ++Lookup.first) { if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) continue; - if (TypedefDecl *FoundTypedef = dyn_cast<TypedefDecl>(*Lookup.first)) { + if (TypedefNameDecl *FoundTypedef = + dyn_cast<TypedefNameDecl>(*Lookup.first)) { if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(), FoundTypedef->getUnderlyingType())) return Importer.Imported(D, FoundTypedef); @@ -2032,9 +2043,18 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) { // Create the new typedef node. TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); - TypedefDecl *ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC, - Loc, Name.getAsIdentifierInfo(), - TInfo); + SourceLocation StartL = Importer.Import(D->getLocStart()); + TypedefNameDecl *ToTypedef; + if (IsAlias) + ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC, + StartL, Loc, + Name.getAsIdentifierInfo(), + TInfo); + else + ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC, + StartL, Loc, + Name.getAsIdentifierInfo(), + TInfo); ToTypedef->setAccess(D->getAccess()); ToTypedef->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToTypedef); @@ -2043,6 +2063,14 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) { return ToTypedef; } +Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) { + return VisitTypedefNameDecl(D, /*IsAlias=*/false); +} + +Decl *ASTNodeImporter::VisitTypeAliasDecl(TypeAliasDecl *D) { + return VisitTypedefNameDecl(D, /*IsAlias=*/true); +} + Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { // Import the major distinguishing characteristics of this enum. DeclContext *DC, *LexicalDC; @@ -2054,8 +2082,8 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { // Figure out what enum name we're looking for. unsigned IDNS = Decl::IDNS_Tag; DeclarationName SearchName = Name; - if (!SearchName && D->getTypedefForAnonDecl()) { - SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName()); + if (!SearchName && D->getTypedefNameForAnonDecl()) { + SearchName = Importer.Import(D->getTypedefNameForAnonDecl()->getDeclName()); IDNS = Decl::IDNS_Ordinary; } else if (Importer.getToContext().getLangOptions().CPlusPlus) IDNS |= Decl::IDNS_Ordinary; @@ -2070,7 +2098,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { continue; Decl *Found = *Lookup.first; - if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) { + if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) { if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) Found = Tag->getDecl(); } @@ -2091,9 +2119,9 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { } // Create the enum declaration. - EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, Loc, - Name.getAsIdentifierInfo(), - Importer.Import(D->getTagKeywordLoc()), 0, + EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getLocStart()), + Loc, Name.getAsIdentifierInfo(), 0, D->isScoped(), D->isScopedUsingClassTag(), D->isFixed()); // Import the qualifier, if any. @@ -2155,8 +2183,8 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { // Figure out what structure name we're looking for. unsigned IDNS = Decl::IDNS_Tag; DeclarationName SearchName = Name; - if (!SearchName && D->getTypedefForAnonDecl()) { - SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName()); + if (!SearchName && D->getTypedefNameForAnonDecl()) { + SearchName = Importer.Import(D->getTypedefNameForAnonDecl()->getDeclName()); IDNS = Decl::IDNS_Ordinary; } else if (Importer.getToContext().getLangOptions().CPlusPlus) IDNS |= Decl::IDNS_Ordinary; @@ -2172,7 +2200,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { continue; Decl *Found = *Lookup.first; - if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) { + if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) { if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) Found = Tag->getDecl(); } @@ -2206,20 +2234,18 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { // Create the record declaration. RecordDecl *D2 = AdoptDecl; + SourceLocation StartLoc = Importer.Import(D->getLocStart()); if (!D2) { if (isa<CXXRecordDecl>(D)) { CXXRecordDecl *D2CXX = CXXRecordDecl::Create(Importer.getToContext(), D->getTagKind(), - DC, Loc, - Name.getAsIdentifierInfo(), - Importer.Import(D->getTagKeywordLoc())); + DC, StartLoc, Loc, + Name.getAsIdentifierInfo()); D2 = D2CXX; D2->setAccess(D->getAccess()); } else { D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(), - DC, Loc, - Name.getAsIdentifierInfo(), - Importer.Import(D->getTagKeywordLoc())); + DC, StartLoc, Loc, Name.getAsIdentifierInfo()); } D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); @@ -2367,6 +2393,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (CXXConstructorDecl *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) { ToFunction = CXXConstructorDecl::Create(Importer.getToContext(), cast<CXXRecordDecl>(DC), + D->getInnerLocStart(), NameInfo, T, TInfo, FromConstructor->isExplicit(), D->isInlineSpecified(), @@ -2374,6 +2401,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } else if (isa<CXXDestructorDecl>(D)) { ToFunction = CXXDestructorDecl::Create(Importer.getToContext(), cast<CXXRecordDecl>(DC), + D->getInnerLocStart(), NameInfo, T, TInfo, D->isInlineSpecified(), D->isImplicit()); @@ -2381,18 +2409,23 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { = dyn_cast<CXXConversionDecl>(D)) { ToFunction = CXXConversionDecl::Create(Importer.getToContext(), cast<CXXRecordDecl>(DC), + D->getInnerLocStart(), NameInfo, T, TInfo, D->isInlineSpecified(), - FromConversion->isExplicit()); + FromConversion->isExplicit(), + Importer.Import(D->getLocEnd())); } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { ToFunction = CXXMethodDecl::Create(Importer.getToContext(), cast<CXXRecordDecl>(DC), + D->getInnerLocStart(), NameInfo, T, TInfo, Method->isStatic(), Method->getStorageClassAsWritten(), - Method->isInlineSpecified()); + Method->isInlineSpecified(), + Importer.Import(D->getLocEnd())); } else { ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, + D->getInnerLocStart(), NameInfo, T, TInfo, D->getStorageClass(), D->getStorageClassAsWritten(), D->isInlineSpecified(), @@ -2457,7 +2490,8 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { if (!BitWidth && D->getBitWidth()) return 0; - FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC, + FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), T, TInfo, BitWidth, D->isMutable()); ToField->setAccess(D->getAccess()); @@ -2542,6 +2576,7 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { ObjCIvarDecl *ToIvar = ObjCIvarDecl::Create(Importer.getToContext(), cast<ObjCContainerDecl>(DC), + Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getAccessControl(), BitWidth, D->getSynthesize()); @@ -2650,8 +2685,10 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { // Create the imported variable. TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); - VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc, - Name.getAsIdentifierInfo(), T, TInfo, + VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getInnerLocStart()), + Loc, Name.getAsIdentifierInfo(), + T, TInfo, D->getStorageClass(), D->getStorageClassAsWritten()); ToVar->setQualifierInfo(Importer.Import(D->getQualifierLoc())); @@ -2718,6 +2755,7 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { // Create the imported parameter. TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getInnerLocStart()), Loc, Name.getAsIdentifierInfo(), T, TInfo, D->getStorageClass(), D->getStorageClassAsWritten(), @@ -3444,6 +3482,7 @@ Decl *ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { // FIXME: Import default argument. return TemplateTypeParmDecl::Create(Importer.getToContext(), Importer.getToContext().getTranslationUnitDecl(), + Importer.Import(D->getLocStart()), Importer.Import(D->getLocation()), D->getDepth(), D->getIndex(), @@ -3476,6 +3515,7 @@ ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { return NonTypeTemplateParmDecl::Create(Importer.getToContext(), Importer.getToContext().getTranslationUnitDecl(), + Importer.Import(D->getInnerLocStart()), Loc, D->getDepth(), D->getPosition(), Name.getAsIdentifierInfo(), T, D->isParameterPack(), TInfo); @@ -3567,12 +3607,12 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { CXXRecordDecl *DTemplated = D->getTemplatedDecl(); // Create the declaration that is being templated. + SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart()); + SourceLocation IdLoc = Importer.Import(DTemplated->getLocation()); CXXRecordDecl *D2Templated = CXXRecordDecl::Create(Importer.getToContext(), DTemplated->getTagKind(), - DC, - Importer.Import(DTemplated->getLocation()), - Name.getAsIdentifierInfo(), - Importer.Import(DTemplated->getTagKeywordLoc())); + DC, StartLoc, IdLoc, + Name.getAsIdentifierInfo()); D2Templated->setAccess(DTemplated->getAccess()); D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc())); D2Templated->setLexicalDeclContext(LexicalDC); @@ -3637,7 +3677,8 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( } // Import the location of this declaration. - SourceLocation Loc = Importer.Import(D->getLocation()); + SourceLocation StartLoc = Importer.Import(D->getLocStart()); + SourceLocation IdLoc = Importer.Import(D->getLocation()); // Import template arguments. llvm::SmallVector<TemplateArgument, 2> TemplateArgs; @@ -3669,7 +3710,8 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( // Create a new specialization. D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(), D->getTagKind(), DC, - Loc, ClassTemplate, + StartLoc, IdLoc, + ClassTemplate, TemplateArgs.data(), TemplateArgs.size(), /*PrevDecl=*/0); @@ -3713,26 +3755,27 @@ Expr *ASTNodeImporter::VisitExpr(Expr *E) { } Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { - NestedNameSpecifier *Qualifier = 0; - if (E->getQualifier()) { - Qualifier = Importer.Import(E->getQualifier()); - if (!E->getQualifier()) - return 0; - } - ValueDecl *ToD = cast_or_null<ValueDecl>(Importer.Import(E->getDecl())); if (!ToD) return 0; + + NamedDecl *FoundD = 0; + if (E->getDecl() != E->getFoundDecl()) { + FoundD = cast_or_null<NamedDecl>(Importer.Import(E->getFoundDecl())); + if (!FoundD) + return 0; + } QualType T = Importer.Import(E->getType()); if (T.isNull()) return 0; - return DeclRefExpr::Create(Importer.getToContext(), Qualifier, - Importer.Import(E->getQualifierRange()), + return DeclRefExpr::Create(Importer.getToContext(), + Importer.Import(E->getQualifierLoc()), ToD, Importer.Import(E->getLocation()), T, E->getValueKind(), + FoundD, /*FIXME:TemplateArgs=*/0); } @@ -3782,7 +3825,8 @@ Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) { Importer.Import(E->getOperatorLoc())); } -Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *E) { QualType ResultType = Importer.Import(E->getType()); if (E->isArgumentType()) { @@ -3790,8 +3834,8 @@ Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (!TInfo) return 0; - return new (Importer.getToContext()) SizeOfAlignOfExpr(E->isSizeOf(), - TInfo, ResultType, + return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(), + TInfo, ResultType, Importer.Import(E->getOperatorLoc()), Importer.Import(E->getRParenLoc())); } @@ -3800,8 +3844,8 @@ Expr *ASTNodeImporter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (!SubExpr) return 0; - return new (Importer.getToContext()) SizeOfAlignOfExpr(E->isSizeOf(), - SubExpr, ResultType, + return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(), + SubExpr, ResultType, Importer.Import(E->getOperatorLoc()), Importer.Import(E->getRParenLoc())); } @@ -3854,7 +3898,7 @@ Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { Importer.Import(E->getOperatorLoc())); } -bool ImportCastPath(CastExpr *E, CXXCastPath &Path) { +static bool ImportCastPath(CastExpr *E, CXXCastPath &Path) { if (E->path_empty()) return false; // TODO: import cast paths @@ -3973,19 +4017,19 @@ Decl *ASTImporter::Import(Decl *FromD) { if (TagDecl *FromTag = dyn_cast<TagDecl>(FromD)) { // Keep track of anonymous tags that have an associated typedef. - if (FromTag->getTypedefForAnonDecl()) + if (FromTag->getTypedefNameForAnonDecl()) AnonTagsWithPendingTypedefs.push_back(FromTag); - } else if (TypedefDecl *FromTypedef = dyn_cast<TypedefDecl>(FromD)) { + } else if (TypedefNameDecl *FromTypedef = dyn_cast<TypedefNameDecl>(FromD)) { // When we've finished transforming a typedef, see whether it was the // typedef for an anonymous tag. for (llvm::SmallVector<TagDecl *, 4>::iterator FromTag = AnonTagsWithPendingTypedefs.begin(), FromTagEnd = AnonTagsWithPendingTypedefs.end(); FromTag != FromTagEnd; ++FromTag) { - if ((*FromTag)->getTypedefForAnonDecl() == FromTypedef) { + if ((*FromTag)->getTypedefNameForAnonDecl() == FromTypedef) { if (TagDecl *ToTag = cast_or_null<TagDecl>(Import(*FromTag))) { // We found the typedef for an anonymous tag; link them. - ToTag->setTypedefForAnonDecl(cast<TypedefDecl>(ToD)); + ToTag->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(ToD)); AnonTagsWithPendingTypedefs.erase(FromTag); break; } @@ -4034,7 +4078,46 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) { if (!FromNNS) return 0; - // FIXME: Implement! + NestedNameSpecifier *prefix = Import(FromNNS->getPrefix()); + + switch (FromNNS->getKind()) { + case NestedNameSpecifier::Identifier: + if (IdentifierInfo *II = Import(FromNNS->getAsIdentifier())) { + return NestedNameSpecifier::Create(ToContext, prefix, II); + } + return 0; + + case NestedNameSpecifier::Namespace: + if (NamespaceDecl *NS = + cast<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) { + return NestedNameSpecifier::Create(ToContext, prefix, NS); + } + return 0; + + case NestedNameSpecifier::NamespaceAlias: + if (NamespaceAliasDecl *NSAD = + cast<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) { + return NestedNameSpecifier::Create(ToContext, prefix, NSAD); + } + return 0; + + case NestedNameSpecifier::Global: + return NestedNameSpecifier::GlobalSpecifier(ToContext); + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + QualType T = Import(QualType(FromNNS->getAsType(), 0u)); + if (!T.isNull()) { + bool bTemplate = FromNNS->getKind() == + NestedNameSpecifier::TypeSpecWithTemplate; + return NestedNameSpecifier::Create(ToContext, prefix, + bTemplate, T.getTypePtr()); + } + } + return 0; + } + + llvm_unreachable("Invalid nested name specifier kind"); return 0; } @@ -4156,12 +4239,12 @@ FileID ASTImporter::Import(FileID FromID) { // Map the FileID for to the "to" source manager. FileID ToID; const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache(); - if (Cache->Entry) { + if (Cache->OrigEntry) { // FIXME: We probably want to use getVirtualFile(), so we don't hit the // disk again // FIXME: We definitely want to re-use the existing MemoryBuffer, rather // than mmap the files several times. - const FileEntry *Entry = ToFileManager.getFile(Cache->Entry->getName()); + const FileEntry *Entry = ToFileManager.getFile(Cache->OrigEntry->getName()); ToID = ToSM.createFileID(Entry, ToIncludeLoc, FromSLoc.getFile().getFileCharacteristic()); } else { diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 9fe18407a839..63583a02bfd1 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -24,6 +24,7 @@ add_clang_library(clangAST ExprClassification.cpp ExprConstant.cpp ExprCXX.cpp + ExternalASTSource.cpp InheritViz.cpp ItaniumCXXABI.cpp ItaniumMangle.cpp diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index ca9ec18b3997..9ffe1f865689 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -415,7 +415,7 @@ FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, Path.Decls.first != Path.Decls.second; ++Path.Decls.first) { // FIXME: Refactor the "is it a nested-name-specifier?" check - if (isa<TypedefDecl>(*Path.Decls.first) || + if (isa<TypedefNameDecl>(*Path.Decls.first) || (*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag)) return true; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 73fe117b1e4e..b21ba9a65e76 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -25,6 +25,7 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetInfo.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -33,53 +34,33 @@ using namespace clang; // NamedDecl Implementation //===----------------------------------------------------------------------===// -static const VisibilityAttr *GetExplicitVisibility(const Decl *d) { - // Use the most recent declaration of a variable. - if (const VarDecl *var = dyn_cast<VarDecl>(d)) - return var->getMostRecentDeclaration()->getAttr<VisibilityAttr>(); - - // Use the most recent declaration of a function, and also handle - // function template specializations. - if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(d)) { - if (const VisibilityAttr *attr - = fn->getMostRecentDeclaration()->getAttr<VisibilityAttr>()) - return attr; - - // If the function is a specialization of a template with an - // explicit visibility attribute, use that. - if (FunctionTemplateSpecializationInfo *templateInfo - = fn->getTemplateSpecializationInfo()) - return templateInfo->getTemplate()->getTemplatedDecl() - ->getAttr<VisibilityAttr>(); +static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) { + // If this declaration has an explicit visibility attribute, use it. + if (const VisibilityAttr *A = D->getAttr<VisibilityAttr>()) { + switch (A->getVisibility()) { + case VisibilityAttr::Default: + return DefaultVisibility; + case VisibilityAttr::Hidden: + return HiddenVisibility; + case VisibilityAttr::Protected: + return ProtectedVisibility; + } - return 0; + return DefaultVisibility; } - // Otherwise, just check the declaration itself first. - if (const VisibilityAttr *attr = d->getAttr<VisibilityAttr>()) - return attr; - - // If there wasn't explicit visibility there, and this is a - // specialization of a class template, check for visibility - // on the pattern. - if (const ClassTemplateSpecializationDecl *spec - = dyn_cast<ClassTemplateSpecializationDecl>(d)) - return spec->getSpecializedTemplate()->getTemplatedDecl() - ->getAttr<VisibilityAttr>(); - - return 0; -} - -static Visibility GetVisibilityFromAttr(const VisibilityAttr *A) { - switch (A->getVisibility()) { - case VisibilityAttr::Default: - return DefaultVisibility; - case VisibilityAttr::Hidden: - return HiddenVisibility; - case VisibilityAttr::Protected: - return ProtectedVisibility; + // If we're on Mac OS X, an 'availability' for Mac OS X attribute + // implies visibility(default). + if (D->getASTContext().Target.getTriple().isOSDarwin()) { + for (specific_attr_iterator<AvailabilityAttr> + A = D->specific_attr_begin<AvailabilityAttr>(), + AEnd = D->specific_attr_end<AvailabilityAttr>(); + A != AEnd; ++A) + if ((*A)->getPlatform()->getName().equals("macosx")) + return DefaultVisibility; } - return DefaultVisibility; + + return llvm::Optional<Visibility>(); } typedef NamedDecl::LinkageInfo LinkageInfo; @@ -100,9 +81,11 @@ namespace { struct LVFlags { bool ConsiderGlobalVisibility; bool ConsiderVisibilityAttributes; + bool ConsiderTemplateParameterTypes; LVFlags() : ConsiderGlobalVisibility(true), - ConsiderVisibilityAttributes(true) { + ConsiderVisibilityAttributes(true), + ConsiderTemplateParameterTypes(true) { } /// \brief Returns a set of flags that is only useful for computing the @@ -111,6 +94,7 @@ struct LVFlags { LVFlags F; F.ConsiderGlobalVisibility = false; F.ConsiderVisibilityAttributes = false; + F.ConsiderTemplateParameterTypes = false; return F; } @@ -120,6 +104,7 @@ struct LVFlags { LVFlags F = *this; F.ConsiderGlobalVisibility = false; F.ConsiderVisibilityAttributes = false; + F.ConsiderTemplateParameterTypes = false; return F; } }; @@ -282,8 +267,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { LinkageInfo LV; if (F.ConsiderVisibilityAttributes) { - if (const VisibilityAttr *VA = GetExplicitVisibility(D)) { - LV.setVisibility(GetVisibilityFromAttr(VA), true); + if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) { + LV.setVisibility(*Vis, true); F.ConsiderGlobalVisibility = false; } else { // If we're declared in a namespace with a visibility attribute, @@ -292,9 +277,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { !isa<TranslationUnitDecl>(DC); DC = DC->getParent()) { if (!isa<NamespaceDecl>(DC)) continue; - if (const VisibilityAttr *VA = - cast<NamespaceDecl>(DC)->getAttr<VisibilityAttr>()) { - LV.setVisibility(GetVisibilityFromAttr(VA), false); + if (llvm::Optional<Visibility> Vis + = cast<NamespaceDecl>(DC)->getExplicitVisibility()) { + LV.setVisibility(*Vis, false); F.ConsiderGlobalVisibility = false; break; } @@ -420,7 +405,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { // has the typedef name for linkage purposes (7.1.3); or } else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) { // Unnamed tags have no linkage. - if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl()) + if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl()) return LinkageInfo::none(); // If this is a class template specialization, consider the @@ -451,8 +436,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { // - a template, unless it is a function template that has // internal linkage (Clause 14); - } else if (const TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) { - LV.merge(getLVForTemplateParameterList(Template->getTemplateParameters())); + } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) { + if (F.ConsiderTemplateParameterTypes) + LV.merge(getLVForTemplateParameterList(temp->getTemplateParameters())); // - a namespace (7.3), unless it is declared within an unnamed // namespace. @@ -491,7 +477,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { isa<VarDecl>(D) || isa<FieldDecl>(D) || (isa<TagDecl>(D) && - (D->getDeclName() || cast<TagDecl>(D)->getTypedefForAnonDecl())))) + (D->getDeclName() || cast<TagDecl>(D)->getTypedefNameForAnonDecl())))) return LinkageInfo::none(); LinkageInfo LV; @@ -501,8 +487,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { // If we have an explicit visibility attribute, merge that in. if (F.ConsiderVisibilityAttributes) { - if (const VisibilityAttr *VA = GetExplicitVisibility(D)) { - LV.mergeVisibility(GetVisibilityFromAttr(VA), true); + if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) { + LV.mergeVisibility(*Vis, true); // Ignore global visibility later, but not this attribute. F.ConsiderGlobalVisibility = false; @@ -536,7 +522,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { if (FunctionTemplateSpecializationInfo *Spec = MD->getTemplateSpecializationInfo()) { LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments, F)); - LV.merge(getLVForTemplateParameterList( + if (F.ConsiderTemplateParameterTypes) + LV.merge(getLVForTemplateParameterList( Spec->getTemplate()->getTemplateParameters())); TSK = Spec->getTemplateSpecializationKind(); @@ -571,7 +558,8 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { // Merge template argument/parameter information for member // class template specializations. LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs(), F)); - LV.merge(getLVForTemplateParameterList( + if (F.ConsiderTemplateParameterTypes) + LV.merge(getLVForTemplateParameterList( Spec->getSpecializedTemplate()->getTemplateParameters())); } @@ -632,10 +620,12 @@ void NamedDecl::ClearLinkageCache() { // Clear cached linkage for function template decls, too. if (FunctionTemplateDecl *temp = - dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) + dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) { + temp->getTemplatedDecl()->ClearLinkageCache(); for (FunctionTemplateDecl::spec_iterator i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) i->ClearLinkageCache(); + } } @@ -660,6 +650,41 @@ LinkageInfo NamedDecl::getLinkageAndVisibility() const { return LI; } +llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const { + // Use the most recent declaration of a variable. + if (const VarDecl *var = dyn_cast<VarDecl>(this)) + return getVisibilityOf(var->getMostRecentDeclaration()); + + // Use the most recent declaration of a function, and also handle + // function template specializations. + if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) { + if (llvm::Optional<Visibility> V + = getVisibilityOf(fn->getMostRecentDeclaration())) + return V; + + // If the function is a specialization of a template with an + // explicit visibility attribute, use that. + if (FunctionTemplateSpecializationInfo *templateInfo + = fn->getTemplateSpecializationInfo()) + return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl()); + + return llvm::Optional<Visibility>(); + } + + // Otherwise, just check the declaration itself first. + if (llvm::Optional<Visibility> V = getVisibilityOf(this)) + return V; + + // If there wasn't explicit visibility there, and this is a + // specialization of a class template, check for visibility + // on the pattern. + if (const ClassTemplateSpecializationDecl *spec + = dyn_cast<ClassTemplateSpecializationDecl>(this)) + return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl()); + + return llvm::Optional<Visibility>(); +} + static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { // Objective-C: treat all Objective-C declarations as having external // linkage. @@ -713,8 +738,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { LinkageInfo LV; if (Flags.ConsiderVisibilityAttributes) { - if (const VisibilityAttr *VA = GetExplicitVisibility(Function)) - LV.setVisibility(GetVisibilityFromAttr(VA)); + if (llvm::Optional<Visibility> Vis = Function->getExplicitVisibility()) + LV.setVisibility(*Vis); } if (const FunctionDecl *Prev = Function->getPreviousDeclaration()) { @@ -736,8 +761,8 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { if (Var->getStorageClass() == SC_PrivateExtern) LV.setVisibility(HiddenVisibility); else if (Flags.ConsiderVisibilityAttributes) { - if (const VisibilityAttr *VA = GetExplicitVisibility(Var)) - LV.setVisibility(GetVisibilityFromAttr(VA)); + if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility()) + LV.setVisibility(*Vis); } if (const VarDecl *Prev = Var->getPreviousDeclaration()) { @@ -954,28 +979,97 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { else { // Here Qualifier == 0, i.e., we are removing the qualifier (if any). if (hasExtInfo()) { - // Save type source info pointer. - TypeSourceInfo *savedTInfo = getExtInfo()->TInfo; - // Deallocate the extended decl info. - getASTContext().Deallocate(getExtInfo()); - // Restore savedTInfo into (non-extended) decl info. - DeclInfo = savedTInfo; + if (getExtInfo()->NumTemplParamLists == 0) { + // Save type source info pointer. + TypeSourceInfo *savedTInfo = getExtInfo()->TInfo; + // Deallocate the extended decl info. + getASTContext().Deallocate(getExtInfo()); + // Restore savedTInfo into (non-extended) decl info. + DeclInfo = savedTInfo; + } + else + getExtInfo()->QualifierLoc = QualifierLoc; } } } +void +DeclaratorDecl::setTemplateParameterListsInfo(ASTContext &Context, + unsigned NumTPLists, + TemplateParameterList **TPLists) { + assert(NumTPLists > 0); + // Make sure the extended decl info is allocated. + if (!hasExtInfo()) { + // Save (non-extended) type source info pointer. + TypeSourceInfo *savedTInfo = DeclInfo.get<TypeSourceInfo*>(); + // Allocate external info struct. + DeclInfo = new (getASTContext()) ExtInfo; + // Restore savedTInfo into (extended) decl info. + getExtInfo()->TInfo = savedTInfo; + } + // Set the template parameter lists info. + getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists); +} + SourceLocation DeclaratorDecl::getOuterLocStart() const { return getTemplateOrInnerLocStart(this); } +namespace { + +// Helper function: returns true if QT is or contains a type +// having a postfix component. +bool typeIsPostfix(clang::QualType QT) { + while (true) { + const Type* T = QT.getTypePtr(); + switch (T->getTypeClass()) { + default: + return false; + case Type::Pointer: + QT = cast<PointerType>(T)->getPointeeType(); + break; + case Type::BlockPointer: + QT = cast<BlockPointerType>(T)->getPointeeType(); + break; + case Type::MemberPointer: + QT = cast<MemberPointerType>(T)->getPointeeType(); + break; + case Type::LValueReference: + case Type::RValueReference: + QT = cast<ReferenceType>(T)->getPointeeType(); + break; + case Type::PackExpansion: + QT = cast<PackExpansionType>(T)->getPattern(); + break; + case Type::Paren: + case Type::ConstantArray: + case Type::DependentSizedArray: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::FunctionProto: + case Type::FunctionNoProto: + return true; + } + } +} + +} // namespace + +SourceRange DeclaratorDecl::getSourceRange() const { + SourceLocation RangeEnd = getLocation(); + if (TypeSourceInfo *TInfo = getTypeSourceInfo()) { + if (typeIsPostfix(TInfo->getType())) + RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd(); + } + return SourceRange(getOuterLocStart(), RangeEnd); +} + void QualifierInfo::setTemplateParameterListsInfo(ASTContext &Context, unsigned NumTPLists, TemplateParameterList **TPLists) { assert((NumTPLists == 0 || TPLists != 0) && "Empty array of template parameters with positive size!"); - assert((NumTPLists == 0 || QualifierLoc) && - "Nonempty array of template parameters with no qualifier!"); // Free previous template parameters (if any). if (NumTemplParamLists > 0) { @@ -1010,10 +1104,11 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { return 0; } -VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, +VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartL, SourceLocation IdL, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, StorageClass SCAsWritten) { - return new (C) VarDecl(Var, DC, L, Id, T, TInfo, S, SCAsWritten); + return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S, SCAsWritten); } void VarDecl::setStorageClass(StorageClass SC) { @@ -1021,20 +1116,13 @@ void VarDecl::setStorageClass(StorageClass SC) { if (getStorageClass() != SC) ClearLinkageCache(); - SClass = SC; -} - -SourceLocation VarDecl::getInnerLocStart() const { - SourceLocation Start = getTypeSpecStartLoc(); - if (Start.isInvalid()) - Start = getLocation(); - return Start; + VarDeclBits.SClass = SC; } SourceRange VarDecl::getSourceRange() const { if (getInit()) return SourceRange(getOuterLocStart(), getInit()->getLocEnd()); - return SourceRange(getOuterLocStart(), getLocation()); + return DeclaratorDecl::getSourceRange(); } bool VarDecl::isExternC() const { @@ -1250,11 +1338,12 @@ void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, //===----------------------------------------------------------------------===// ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, StorageClass SCAsWritten, Expr *DefArg) { - return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, TInfo, + return new (C) ParmVarDecl(ParmVar, DC, StartLoc, IdLoc, Id, T, TInfo, S, SCAsWritten, DefArg); } @@ -1324,7 +1413,7 @@ bool FunctionDecl::isVariadic() const { bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const { for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { - if (I->Body) { + if (I->Body || I->IsLateTemplateParsed) { Definition = *I; return true; } @@ -1338,6 +1427,9 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { if (I->Body) { Definition = *I; return I->Body.get(getASTContext().getExternalSource()); + } else if (I->IsLateTemplateParsed) { + Definition = *I; + return 0; } } @@ -1804,7 +1896,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C, // Insert this function template specialization into the set of known // function template specializations. if (InsertPos) - Template->getSpecializations().InsertNode(Info, InsertPos); + Template->addSpecialization(Info, InsertPos); else { // Try to insert the new node. If there is an existing node, leave it, the // set will contain the canonical decls while @@ -1925,14 +2017,20 @@ bool FunctionDecl::isOutOfLine() const { return false; } +SourceRange FunctionDecl::getSourceRange() const { + return SourceRange(getOuterLocStart(), EndRangeLoc); +} + //===----------------------------------------------------------------------===// // FieldDecl Implementation //===----------------------------------------------------------------------===// FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, QualType T, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable) { - return new (C) FieldDecl(Decl::Field, DC, L, Id, T, TInfo, BW, Mutable); + return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo, + BW, Mutable); } bool FieldDecl::isAnonymousStructOrUnion() const { @@ -1949,13 +2047,25 @@ unsigned FieldDecl::getFieldIndex() const { if (CachedFieldIndex) return CachedFieldIndex - 1; unsigned index = 0; - RecordDecl::field_iterator - i = getParent()->field_begin(), e = getParent()->field_end(); + const RecordDecl *RD = getParent(); + const FieldDecl *LastFD = 0; + bool IsMsStruct = RD->hasAttr<MsStructAttr>(); + + RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); while (true) { assert(i != e && "failed to find field in parent!"); if (*i == this) break; + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are ignored. + if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD) || + getASTContext().ZeroBitfieldFollowsBitfield((*i), LastFD)) { + ++i; + continue; + } + LastFD = (*i); + } ++i; ++index; } @@ -1964,6 +2074,12 @@ unsigned FieldDecl::getFieldIndex() const { return index; } +SourceRange FieldDecl::getSourceRange() const { + if (isBitField()) + return SourceRange(getInnerLocStart(), BitWidth->getLocEnd()); + return DeclaratorDecl::getSourceRange(); +} + //===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// @@ -1981,8 +2097,8 @@ TagDecl* TagDecl::getCanonicalDecl() { return getFirstDeclaration(); } -void TagDecl::setTypedefForAnonDecl(TypedefDecl *TDD) { - TypedefDeclOrQualifier = TDD; +void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { + TypedefNameDeclOrQualifier = TDD; if (TypeForDecl) const_cast<Type*>(TypeForDecl)->ClearLinkageCache(); ClearLinkageCache(); @@ -2030,35 +2146,52 @@ void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { if (QualifierLoc) { // Make sure the extended qualifier info is allocated. if (!hasExtInfo()) - TypedefDeclOrQualifier = new (getASTContext()) ExtInfo; + TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo; // Set qualifier info. getExtInfo()->QualifierLoc = QualifierLoc; } else { // Here Qualifier == 0, i.e., we are removing the qualifier (if any). if (hasExtInfo()) { - getASTContext().Deallocate(getExtInfo()); - TypedefDeclOrQualifier = (TypedefDecl*) 0; + if (getExtInfo()->NumTemplParamLists == 0) { + getASTContext().Deallocate(getExtInfo()); + TypedefNameDeclOrQualifier = (TypedefNameDecl*) 0; + } + else + getExtInfo()->QualifierLoc = QualifierLoc; } } } +void TagDecl::setTemplateParameterListsInfo(ASTContext &Context, + unsigned NumTPLists, + TemplateParameterList **TPLists) { + assert(NumTPLists > 0); + // Make sure the extended decl info is allocated. + if (!hasExtInfo()) + // Allocate external info struct. + TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo; + // Set the template parameter lists info. + getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists); +} + //===----------------------------------------------------------------------===// // EnumDecl Implementation //===----------------------------------------------------------------------===// -EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, SourceLocation TKL, +EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, EnumDecl *PrevDecl, bool IsScoped, bool IsScopedUsingClassTag, bool IsFixed) { - EnumDecl *Enum = new (C) EnumDecl(DC, L, Id, PrevDecl, TKL, + EnumDecl *Enum = new (C) EnumDecl(DC, StartLoc, IdLoc, Id, PrevDecl, IsScoped, IsScopedUsingClassTag, IsFixed); C.getTypeDeclType(Enum, PrevDecl); return Enum; } EnumDecl *EnumDecl::Create(ASTContext &C, EmptyShell Empty) { - return new (C) EnumDecl(0, SourceLocation(), 0, 0, SourceLocation(), + return new (C) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0, false, false, false); } @@ -2079,10 +2212,10 @@ void EnumDecl::completeDefinition(QualType NewType, // RecordDecl Implementation //===----------------------------------------------------------------------===// -RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, RecordDecl *PrevDecl, - SourceLocation TKL) - : TagDecl(DK, TK, DC, L, Id, PrevDecl, TKL) { +RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, RecordDecl *PrevDecl) + : TagDecl(DK, TK, DC, IdLoc, Id, PrevDecl, StartLoc) { HasFlexibleArrayMember = false; AnonymousStructOrUnion = false; HasObjectMember = false; @@ -2091,17 +2224,17 @@ RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, } RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - SourceLocation TKL, RecordDecl* PrevDecl) { - - RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id, PrevDecl, TKL); + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, RecordDecl* PrevDecl) { + RecordDecl* R = new (C) RecordDecl(Record, TK, DC, StartLoc, IdLoc, Id, + PrevDecl); C.getTypeDeclType(R, PrevDecl); return R; } RecordDecl *RecordDecl::Create(const ASTContext &C, EmptyShell Empty) { - return new (C) RecordDecl(Record, TTK_Struct, 0, SourceLocation(), 0, 0, - SourceLocation()); + return new (C) RecordDecl(Record, TTK_Struct, 0, SourceLocation(), + SourceLocation(), 0, 0); } bool RecordDecl::isInjectedClassName() const { @@ -2200,14 +2333,22 @@ TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { } LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *II) { - return new (C) LabelDecl(DC, L, II, 0); + SourceLocation IdentL, IdentifierInfo *II) { + return new (C) LabelDecl(DC, IdentL, II, 0, IdentL); +} + +LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation IdentL, IdentifierInfo *II, + SourceLocation GnuLabelL) { + assert(GnuLabelL != IdentL && "Use this only for GNU local labels"); + return new (C) LabelDecl(DC, IdentL, II, 0, GnuLabelL); } NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id) { - return new (C) NamespaceDecl(DC, L, Id); + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id) { + return new (C) NamespaceDecl(DC, StartLoc, IdLoc, Id); } NamespaceDecl *NamespaceDecl::getNextNamespace() { @@ -2216,20 +2357,22 @@ NamespaceDecl *NamespaceDecl::getNextNamespace() { } ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation loc, - IdentifierInfo *name, - QualType type) { - return new (C) ImplicitParamDecl(DC, loc, name, type); + SourceLocation IdLoc, + IdentifierInfo *Id, + QualType Type) { + return new (C) ImplicitParamDecl(DC, IdLoc, Id, Type); } FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - StorageClass S, StorageClass SCAsWritten, + StorageClass SC, StorageClass SCAsWritten, bool isInlineSpecified, bool hasWrittenPrototype) { - FunctionDecl *New = new (C) FunctionDecl(Function, DC, NameInfo, T, TInfo, - S, SCAsWritten, isInlineSpecified); + FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo, + T, TInfo, SC, SCAsWritten, + isInlineSpecified); New->HasWrittenPrototype = hasWrittenPrototype; return New; } @@ -2260,13 +2403,37 @@ SourceRange EnumConstantDecl::getSourceRange() const { } TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - TypeSourceInfo *TInfo) { - return new (C) TypedefDecl(DC, L, Id, TInfo); + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo) { + return new (C) TypedefDecl(DC, StartLoc, IdLoc, Id, TInfo); +} + +TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + TypeSourceInfo *TInfo) { + return new (C) TypeAliasDecl(DC, StartLoc, IdLoc, Id, TInfo); +} + +SourceRange TypedefDecl::getSourceRange() const { + SourceLocation RangeEnd = getLocation(); + if (TypeSourceInfo *TInfo = getTypeSourceInfo()) { + if (typeIsPostfix(TInfo->getType())) + RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd(); + } + return SourceRange(getLocStart(), RangeEnd); +} + +SourceRange TypeAliasDecl::getSourceRange() const { + SourceLocation RangeEnd = getLocStart(); + if (TypeSourceInfo *TInfo = getTypeSourceInfo()) + RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd(); + return SourceRange(getLocStart(), RangeEnd); } FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - StringLiteral *Str) { - return new (C) FileScopeAsmDecl(DC, L, Str); + StringLiteral *Str, + SourceLocation AsmLoc, + SourceLocation RParenLoc) { + return new (C) FileScopeAsmDecl(DC, Str, AsmLoc, RParenLoc); } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 81df00d6c7e8..6d517c544089 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -25,11 +25,11 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/Basic/TargetInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstdio> -#include <vector> using namespace clang; //===----------------------------------------------------------------------===// @@ -173,9 +173,6 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { Decl::~Decl() { } void Decl::setDeclContext(DeclContext *DC) { - if (isOutOfSemaDC()) - delete getMultipleDC(); - DeclCtx = DC; } @@ -244,6 +241,177 @@ bool Decl::isUsed(bool CheckUsedAttr) const { return false; } +bool Decl::isReferenced() const { + if (Referenced) + return true; + + // Check redeclarations. + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) + if (I->Referenced) + return true; + + return false; +} + +/// \brief Determine the availability of the given declaration based on +/// the target platform. +/// +/// When it returns an availability result other than \c AR_Available, +/// if the \p Message parameter is non-NULL, it will be set to a +/// string describing why the entity is unavailable. +/// +/// FIXME: Make these strings localizable, since they end up in +/// diagnostics. +static AvailabilityResult CheckAvailability(ASTContext &Context, + const AvailabilityAttr *A, + std::string *Message) { + llvm::StringRef TargetPlatform = Context.Target.getPlatformName(); + llvm::StringRef PrettyPlatformName + = AvailabilityAttr::getPrettyPlatformName(TargetPlatform); + if (PrettyPlatformName.empty()) + PrettyPlatformName = TargetPlatform; + + VersionTuple TargetMinVersion = Context.Target.getPlatformMinVersion(); + if (TargetMinVersion.empty()) + return AR_Available; + + // Match the platform name. + if (A->getPlatform()->getName() != TargetPlatform) + return AR_Available; + + // Make sure that this declaration has not been marked 'unavailable'. + if (A->getUnavailable()) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "not available on " << PrettyPlatformName; + } + + return AR_Unavailable; + } + + // Make sure that this declaration has already been introduced. + if (!A->getIntroduced().empty() && + TargetMinVersion < A->getIntroduced()) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "introduced in " << PrettyPlatformName << ' ' + << A->getIntroduced(); + } + + return AR_NotYetIntroduced; + } + + // Make sure that this declaration hasn't been obsoleted. + if (!A->getObsoleted().empty() && TargetMinVersion >= A->getObsoleted()) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "obsoleted in " << PrettyPlatformName << ' ' + << A->getObsoleted(); + } + + return AR_Unavailable; + } + + // Make sure that this declaration hasn't been deprecated. + if (!A->getDeprecated().empty() && TargetMinVersion >= A->getDeprecated()) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "first deprecated in " << PrettyPlatformName << ' ' + << A->getDeprecated(); + } + + return AR_Deprecated; + } + + return AR_Available; +} + +AvailabilityResult Decl::getAvailability(std::string *Message) const { + AvailabilityResult Result = AR_Available; + std::string ResultMessage; + + for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) { + if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) { + if (Result >= AR_Deprecated) + continue; + + if (Message) + ResultMessage = Deprecated->getMessage(); + + Result = AR_Deprecated; + continue; + } + + if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) { + if (Message) + *Message = Unavailable->getMessage(); + return AR_Unavailable; + } + + if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) { + AvailabilityResult AR = CheckAvailability(getASTContext(), Availability, + Message); + + if (AR == AR_Unavailable) + return AR_Unavailable; + + if (AR > Result) { + Result = AR; + if (Message) + ResultMessage.swap(*Message); + } + continue; + } + } + + if (Message) + Message->swap(ResultMessage); + return Result; +} + +bool Decl::canBeWeakImported(bool &IsDefinition) const { + IsDefinition = false; + if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { + if (!Var->hasExternalStorage() || Var->getInit()) { + IsDefinition = true; + return false; + } + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) { + if (FD->hasBody()) { + IsDefinition = true; + return false; + } + } else if (isa<ObjCPropertyDecl>(this) || isa<ObjCMethodDecl>(this)) + return false; + else if (!(getASTContext().getLangOptions().ObjCNonFragileABI && + isa<ObjCInterfaceDecl>(this))) + return false; + + return true; +} + +bool Decl::isWeakImported() const { + bool IsDefinition; + if (!canBeWeakImported(IsDefinition)) + return false; + + for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) { + if (isa<WeakImportAttr>(*A)) + return true; + + if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) { + if (CheckAvailability(getASTContext(), Availability, 0) + == AR_NotYetIntroduced) + return true; + } + } + + return false; +} unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { switch (DeclKind) { @@ -270,6 +438,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { return IDNS_Ordinary | IDNS_Type; case Typedef: + case TypeAlias: case UnresolvedUsingTypename: case TemplateTypeParm: return IDNS_Ordinary | IDNS_Type; @@ -960,7 +1129,7 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { // FIXME: This feels like a hack. Should DeclarationName support // template-ids, or is there a better way to keep specializations // from being visible? - if (isa<ClassTemplateSpecializationDecl>(D)) + if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter()) return; if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) if (FD->isFunctionTemplateSpecialization()) @@ -999,7 +1168,7 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { // FIXME: This feels like a hack. Should DeclarationName support // template-ids, or is there a better way to keep specializations // from being visible? - if (isa<ClassTemplateSpecializationDecl>(D)) + if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter()) return; ASTContext *C = 0; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 46768c12d879..9099cd524f1a 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -31,9 +31,13 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false), Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), - Abstract(false), HasTrivialConstructor(true), - HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true), - HasTrivialDestructor(true), ComputedVisibleConversions(false), + Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), + HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), + HasTrivialConstructor(true), HasConstExprNonCopyMoveConstructor(false), + HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true), + HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true), + HasTrivialDestructor(true), HasNonLiteralTypeFieldsOrBases(false), + ComputedVisibleConversions(false), DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false), DeclaredCopyAssignment(false), DeclaredDestructor(false), NumBases(0), NumVBases(0), Bases(), VBases(), @@ -41,20 +45,19 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) } CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - CXXRecordDecl *PrevDecl, - SourceLocation TKL) - : RecordDecl(K, TK, DC, L, Id, PrevDecl, TKL), + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, CXXRecordDecl *PrevDecl) + : RecordDecl(K, TK, DC, StartLoc, IdLoc, Id, PrevDecl), DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0), TemplateOrInstantiation() { } CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, - DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, SourceLocation TKL, + DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, CXXRecordDecl* PrevDecl, bool DelayTypeCreation) { - CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id, - PrevDecl, TKL); + CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, StartLoc, IdLoc, + Id, PrevDecl); // FIXME: DelayTypeCreation seems like such a hack if (!DelayTypeCreation) @@ -63,8 +66,8 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, } CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, EmptyShell Empty) { - return new (C) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(), 0, 0, - SourceLocation()); + return new (C) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(), + SourceLocation(), 0, 0); } void @@ -109,14 +112,38 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // A class with a non-empty base class is not empty. // FIXME: Standard ref? - if (!BaseClassDecl->isEmpty()) + if (!BaseClassDecl->isEmpty()) { + if (!data().Empty) { + // C++0x [class]p7: + // A standard-layout class is a class that: + // [...] + // -- either has no non-static data members in the most derived + // class and at most one base class with non-static data members, + // or has no base classes with non-static data members, and + // If this is the second non-empty base, then neither of these two + // clauses can be true. + data().IsStandardLayout = false; + } + data().Empty = false; + data().HasNoNonEmptyBases = false; + } // C++ [class.virtual]p1: // A class that declares or inherits a virtual function is called a // polymorphic class. if (BaseClassDecl->isPolymorphic()) data().Polymorphic = true; + + // C++0x [class]p7: + // A standard-layout class is a class that: [...] + // -- has no non-standard-layout base classes + if (!BaseClassDecl->isStandardLayout()) + data().IsStandardLayout = false; + + // Record if this base is the first non-literal field or base. + if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType()) + data().HasNonLiteralTypeFieldsOrBases = true; // Now go through all virtual bases of this base and add them. for (CXXRecordDecl::base_class_iterator VBase = @@ -140,16 +167,25 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // C++ [class.ctor]p5: // A constructor is trivial if its class has no virtual base classes. data().HasTrivialConstructor = false; - - // C++ [class.copy]p6: - // A copy constructor is trivial if its class has no virtual base - // classes. + + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if it is neither + // user-provided nor deleted and if + // -- class X has no virtual functions and no virtual base classes, and data().HasTrivialCopyConstructor = false; - - // C++ [class.copy]p11: - // A copy assignment operator is trivial if its class has no virtual - // base classes. + data().HasTrivialMoveConstructor = false; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if it is + // neither user-provided nor deleted and if + // -- class X has no virtual functions and no virtual base classes, and data().HasTrivialCopyAssignment = false; + data().HasTrivialMoveAssignment = false; + + // C++0x [class]p7: + // A standard-layout class is a class that: [...] + // -- has [...] no virtual base classes + data().IsStandardLayout = false; } else { // C++ [class.ctor]p5: // A constructor is trivial if all the direct base classes of its @@ -157,17 +193,29 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (!BaseClassDecl->hasTrivialConstructor()) data().HasTrivialConstructor = false; - // C++ [class.copy]p6: - // A copy constructor is trivial if all the direct base classes of its - // class have trivial copy constructors. + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if [...] + // [...] + // -- the constructor selected to copy/move each direct base class + // subobject is trivial, and + // FIXME: C++0x: We need to only consider the selected constructor + // instead of all of them. if (!BaseClassDecl->hasTrivialCopyConstructor()) data().HasTrivialCopyConstructor = false; - - // C++ [class.copy]p11: - // A copy assignment operator is trivial if all the direct base classes - // of its class have trivial copy assignment operators. + if (!BaseClassDecl->hasTrivialMoveConstructor()) + data().HasTrivialMoveConstructor = false; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if [...] + // [...] + // -- the assignment operator selected to copy/move each direct base + // class subobject is trivial, and + // FIXME: C++0x: We need to only consider the selected operator instead + // of all of them. if (!BaseClassDecl->hasTrivialCopyAssignment()) data().HasTrivialCopyAssignment = false; + if (!BaseClassDecl->hasTrivialMoveAssignment()) + data().HasTrivialMoveAssignment = false; } // C++ [class.ctor]p3: @@ -218,6 +266,23 @@ bool CXXRecordDecl::hasConstCopyConstructor(const ASTContext &Context) const { return getCopyConstructor(Context, Qualifiers::Const) != 0; } +bool CXXRecordDecl::isTriviallyCopyable() const { + // C++0x [class]p5: + // A trivially copyable class is a class that: + // -- has no non-trivial copy constructors, + if (!hasTrivialCopyConstructor()) return false; + // -- has no non-trivial move constructors, + if (!hasTrivialMoveConstructor()) return false; + // -- has no non-trivial copy assignment operators, + if (!hasTrivialCopyAssignment()) return false; + // -- has no non-trivial move assignment operators, and + if (!hasTrivialMoveAssignment()) return false; + // -- has a trivial destructor. + if (!hasTrivialDestructor()) return false; + + return true; +} + /// \brief Perform a simplistic form of overload resolution that only considers /// cv-qualifiers on a single parameter, and return the best overload candidate /// (if there is one). @@ -231,11 +296,11 @@ GetBestOverloadCandidateSimple( unsigned Best = 0, N = Cands.size(); for (unsigned I = 1; I != N; ++I) - if (Cands[Best].second.isSupersetOf(Cands[I].second)) + if (Cands[Best].second.compatiblyIncludes(Cands[I].second)) Best = I; for (unsigned I = 1; I != N; ++I) - if (Cands[Best].second.isSupersetOf(Cands[I].second)) + if (Cands[Best].second.compatiblyIncludes(Cands[I].second)) return 0; return Cands[Best].first; @@ -358,9 +423,24 @@ void CXXRecordDecl::addedMember(Decl *D) { // None of the special member functions are trivial. data().HasTrivialConstructor = false; + + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if [...] + // -- class X has no virtual functions [...] data().HasTrivialCopyConstructor = false; + data().HasTrivialMoveConstructor = false; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if [...] + // -- class X has no virtual functions [...] data().HasTrivialCopyAssignment = false; + data().HasTrivialMoveAssignment = false; // FIXME: Destructor? + + // C++0x [class]p7: + // A standard-layout class is a class that: [...] + // -- has no virtual functions + data().IsStandardLayout = false; } } @@ -423,18 +503,33 @@ void CXXRecordDecl::addedMember(Decl *D) { // FIXME: C++0x: don't do this for "= default" default constructors. data().HasTrivialConstructor = false; - // Note when we have a user-declared copy constructor, which will - // suppress the implicit declaration of a copy constructor. - if (!FunTmpl && Constructor->isCopyConstructor()) { - data().UserDeclaredCopyConstructor = true; - data().DeclaredCopyConstructor = true; - - // C++ [class.copy]p6: - // A copy constructor is trivial if it is implicitly declared. - // FIXME: C++0x: don't do this for "= default" copy constructors. - data().HasTrivialCopyConstructor = false; + // Note when we have a user-declared copy or move constructor, which will + // suppress the implicit declaration of those constructors. + if (!FunTmpl) { + if (Constructor->isCopyConstructor()) { + data().UserDeclaredCopyConstructor = true; + data().DeclaredCopyConstructor = true; + + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if it is neither + // user-provided nor deleted + // FIXME: C++0x: don't do this for "= default" copy constructors. + data().HasTrivialCopyConstructor = false; + } else if (Constructor->isMoveConstructor()) { + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if it is neither + // user-provided nor deleted + // FIXME: C++0x: don't do this for "= default" move constructors. + data().HasTrivialMoveConstructor = false; + } } - + if (Constructor->isConstExpr() && + !Constructor->isCopyOrMoveConstructor()) { + // Record if we see any constexpr constructors which are niether copy + // nor move constructors. + data().HasConstExprNonCopyMoveConstructor = true; + } + return; } @@ -472,35 +567,53 @@ void CXXRecordDecl::addedMember(Decl *D) { return; ASTContext &Context = getASTContext(); - QualType ArgType = FnType->getArgType(0); - if (const LValueReferenceType *Ref =ArgType->getAs<LValueReferenceType>()) - ArgType = Ref->getPointeeType(); - - ArgType = ArgType.getUnqualifiedType(); QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast<CXXRecordDecl*>(this))); - + + bool isRValueRefArg = false; + QualType ArgType = FnType->getArgType(0); + if (const LValueReferenceType *Ref = + ArgType->getAs<LValueReferenceType>()) { + ArgType = Ref->getPointeeType(); + } else if (const RValueReferenceType *Ref = + ArgType->getAs<RValueReferenceType>()) { + ArgType = Ref->getPointeeType(); + isRValueRefArg = true; + } if (!Context.hasSameUnqualifiedType(ClassType, ArgType)) return; - - // This is a copy assignment operator. - // FIXME: Move assignment operators. - - // Suppress the implicit declaration of a copy constructor. - data().UserDeclaredCopyAssignment = true; - data().DeclaredCopyAssignment = true; - - // C++ [class.copy]p11: - // A copy assignment operator is trivial if it is implicitly declared. - // FIXME: C++0x: don't do this for "= default" copy operators. - data().HasTrivialCopyAssignment = false; - + // C++ [class]p4: - // A POD-struct is an aggregate class that [...] has no user-defined copy - // assignment operator [...]. + // A POD-struct is an aggregate class that [...] has no user-defined + // copy assignment operator [...]. + // FIXME: This should be probably determined dynamically in terms of + // other more precise attributes to correctly model how it is specified + // in C++0x. Setting it here happens to do the right thing. data().PlainOldData = false; + + if (!isRValueRefArg) { + // This is a copy assignment operator. + + // Suppress the implicit declaration of a copy constructor. + data().UserDeclaredCopyAssignment = true; + data().DeclaredCopyAssignment = true; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if it is + // neither user-provided nor deleted [...] + // FIXME: C++0x: don't do this for "= default" copy operators. + data().HasTrivialCopyAssignment = false; + } else { + // This is a move assignment operator. + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if it is + // neither user-provided nor deleted [...] + // FIXME: C++0x: don't do this for "= default" copy operators. + data().HasTrivialMoveAssignment = false; + } } - + // Keep the list of conversion functions up-to-date. if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { // We don't record specializations. @@ -539,8 +652,22 @@ void CXXRecordDecl::addedMember(Decl *D) { data().Aggregate = false; data().PlainOldData = false; } - - // C++ [class]p9: + + // C++0x [class]p7: + // A standard-layout class is a class that: + // [...] + // -- has the same access control for all non-static data members, + switch (D->getAccess()) { + case AS_private: data().HasPrivateFields = true; break; + case AS_protected: data().HasProtectedFields = true; break; + case AS_public: data().HasPublicFields = true; break; + case AS_none: assert(0 && "Invalid access specifier"); + }; + if ((data().HasPrivateFields + data().HasProtectedFields + + data().HasPublicFields) > 1) + data().IsStandardLayout = false; + + // C++0x [class]p9: // A POD struct is a class that is both a trivial class and a // standard-layout class, and has no non-static data members of type // non-POD struct, non-POD union (or array of such types). @@ -548,23 +675,98 @@ void CXXRecordDecl::addedMember(Decl *D) { QualType T = Context.getBaseElementType(Field->getType()); if (!T->isPODType()) data().PlainOldData = false; - if (T->isReferenceType()) + if (T->isReferenceType()) { data().HasTrivialConstructor = false; - + + // C++0x [class]p7: + // A standard-layout class is a class that: + // -- has no non-static data members of type [...] reference, + data().IsStandardLayout = false; + } + + // Record if this field is the first non-literal field or base. + if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType()) + data().HasNonLiteralTypeFieldsOrBases = true; + if (const RecordType *RecordTy = T->getAs<RecordType>()) { CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); if (FieldRec->getDefinition()) { if (!FieldRec->hasTrivialConstructor()) data().HasTrivialConstructor = false; + + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if [...] + // [...] + // -- for each non-static data member of X that is of class type (or + // an array thereof), the constructor selected to copy/move that + // member is trivial; + // FIXME: C++0x: We don't correctly model 'selected' constructors. if (!FieldRec->hasTrivialCopyConstructor()) data().HasTrivialCopyConstructor = false; + if (!FieldRec->hasTrivialMoveConstructor()) + data().HasTrivialMoveConstructor = false; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if [...] + // [...] + // -- for each non-static data member of X that is of class type (or + // an array thereof), the assignment operator selected to + // copy/move that member is trivial; + // FIXME: C++0x: We don't correctly model 'selected' operators. if (!FieldRec->hasTrivialCopyAssignment()) data().HasTrivialCopyAssignment = false; + if (!FieldRec->hasTrivialMoveAssignment()) + data().HasTrivialMoveAssignment = false; + if (!FieldRec->hasTrivialDestructor()) data().HasTrivialDestructor = false; + + // C++0x [class]p7: + // A standard-layout class is a class that: + // -- has no non-static data members of type non-standard-layout + // class (or array of such types) [...] + if (!FieldRec->isStandardLayout()) + data().IsStandardLayout = false; + + // C++0x [class]p7: + // A standard-layout class is a class that: + // [...] + // -- has no base classes of the same type as the first non-static + // data member. + // We don't want to expend bits in the state of the record decl + // tracking whether this is the first non-static data member so we + // cheat a bit and use some of the existing state: the empty bit. + // Virtual bases and virtual methods make a class non-empty, but they + // also make it non-standard-layout so we needn't check here. + // A non-empty base class may leave the class standard-layout, but not + // if we have arrived here, and have at least on non-static data + // member. If IsStandardLayout remains true, then the first non-static + // data member must come through here with Empty still true, and Empty + // will subsequently be set to false below. + if (data().IsStandardLayout && data().Empty) { + for (CXXRecordDecl::base_class_const_iterator BI = bases_begin(), + BE = bases_end(); + BI != BE; ++BI) { + if (Context.hasSameUnqualifiedType(BI->getType(), T)) { + data().IsStandardLayout = false; + break; + } + } + } } } - + + // C++0x [class]p7: + // A standard-layout class is a class that: + // [...] + // -- either has no non-static data members in the most derived + // class and at most one base class with non-static data members, + // or has no base classes with non-static data members, and + // At this point we know that we have a non-static data member, so the last + // clause holds. + if (!data().HasNoNonEmptyBases) + data().IsStandardLayout = false; + // If this is not a zero-length bit-field, then the class is not empty. if (data().Empty) { if (!Field->getBitWidth()) @@ -814,8 +1016,6 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const { return 0; CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I); - assert(++I == E && "Found more than one destructor!"); - return Dtor; } @@ -884,11 +1084,13 @@ bool CXXRecordDecl::mayBeAbstract() const { CXXMethodDecl * CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isStatic, StorageClass SCAsWritten, bool isInline) { - return new (C) CXXMethodDecl(CXXMethod, RD, NameInfo, T, TInfo, - isStatic, SCAsWritten, isInline); + bool isStatic, StorageClass SCAsWritten, bool isInline, + SourceLocation EndLocation) { + return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo, + isStatic, SCAsWritten, isInline, EndLocation); } bool CXXMethodDecl::isUsualDeallocationFunction() const { @@ -1033,6 +1235,16 @@ CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, } CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, + SourceLocation D, SourceLocation L, + CXXConstructorDecl *Target, Expr *Init, + SourceLocation R) + : Initializee(Target), MemberOrEllipsisLocation(D), Init(Init), + LParenLoc(L), RParenLoc(R), IsVirtual(false), + IsWritten(false), SourceOrderOrNumArrayIndices(0) +{ +} + +CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, FieldDecl *Member, SourceLocation MemberLoc, SourceLocation L, Expr *Init, @@ -1076,7 +1288,7 @@ const Type *CXXCtorInitializer::getBaseClass() const { } SourceLocation CXXCtorInitializer::getSourceLocation() const { - if (isAnyMemberInitializer()) + if (isAnyMemberInitializer() || isDelegatingInitializer()) return getMemberLocation(); return getBaseClassLoc().getLocalSourceRange().getBegin(); @@ -1088,12 +1300,13 @@ SourceRange CXXCtorInitializer::getSourceRange() const { CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) { - return new (C) CXXConstructorDecl(0, DeclarationNameInfo(), + return new (C) CXXConstructorDecl(0, SourceLocation(), DeclarationNameInfo(), QualType(), 0, false, false, false); } CXXConstructorDecl * CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isExplicit, @@ -1102,8 +1315,8 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); - return new (C) CXXConstructorDecl(RD, NameInfo, T, TInfo, isExplicit, - isInline, isImplicitlyDeclared); + return new (C) CXXConstructorDecl(RD, StartLoc, NameInfo, T, TInfo, + isExplicit, isInline, isImplicitlyDeclared); } bool CXXConstructorDecl::isDefaultConstructor() const { @@ -1222,12 +1435,13 @@ CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){ CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) { - return new (C) CXXDestructorDecl(0, DeclarationNameInfo(), + return new (C) CXXDestructorDecl(0, SourceLocation(), DeclarationNameInfo(), QualType(), 0, false, false); } CXXDestructorDecl * CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isInline, @@ -1235,33 +1449,38 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, assert(NameInfo.getName().getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); - return new (C) CXXDestructorDecl(RD, NameInfo, T, TInfo, isInline, + return new (C) CXXDestructorDecl(RD, StartLoc, NameInfo, T, TInfo, isInline, isImplicitlyDeclared); } CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) { - return new (C) CXXConversionDecl(0, DeclarationNameInfo(), - QualType(), 0, false, false); + return new (C) CXXConversionDecl(0, SourceLocation(), DeclarationNameInfo(), + QualType(), 0, false, false, + SourceLocation()); } CXXConversionDecl * CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isExplicit) { + bool isInline, bool isExplicit, + SourceLocation EndLocation) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); - return new (C) CXXConversionDecl(RD, NameInfo, T, TInfo, - isInline, isExplicit); + return new (C) CXXConversionDecl(RD, StartLoc, NameInfo, T, TInfo, + isInline, isExplicit, EndLocation); } LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - LanguageIDs Lang, bool Braces) { - return new (C) LinkageSpecDecl(DC, L, Lang, Braces); + SourceLocation ExternLoc, + SourceLocation LangLoc, + LanguageIDs Lang, + SourceLocation RBraceLoc) { + return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, RBraceLoc); } UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, @@ -1364,9 +1583,12 @@ UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC, } StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, Expr *AssertExpr, - StringLiteral *Message) { - return new (C) StaticAssertDecl(DC, L, AssertExpr, Message); + SourceLocation StaticAssertLoc, + Expr *AssertExpr, + StringLiteral *Message, + SourceLocation RParenLoc) { + return new (C) StaticAssertDecl(DC, StaticAssertLoc, AssertExpr, Message, + RParenLoc); } static const char *getAccessName(AccessSpecifier AS) { diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 45f5188d4043..24d281e8b66d 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -398,6 +398,64 @@ ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() { return this; } +ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { + ObjCMethodFamily family = static_cast<ObjCMethodFamily>(Family); + if (family != static_cast<unsigned>(InvalidObjCMethodFamily)) + return family; + + // Check for an explicit attribute. + if (const ObjCMethodFamilyAttr *attr = getAttr<ObjCMethodFamilyAttr>()) { + // The unfortunate necessity of mapping between enums here is due + // to the attributes framework. + switch (attr->getFamily()) { + case ObjCMethodFamilyAttr::OMF_None: family = OMF_None; break; + case ObjCMethodFamilyAttr::OMF_alloc: family = OMF_alloc; break; + case ObjCMethodFamilyAttr::OMF_copy: family = OMF_copy; break; + case ObjCMethodFamilyAttr::OMF_init: family = OMF_init; break; + case ObjCMethodFamilyAttr::OMF_mutableCopy: family = OMF_mutableCopy; break; + case ObjCMethodFamilyAttr::OMF_new: family = OMF_new; break; + } + Family = static_cast<unsigned>(family); + return family; + } + + family = getSelector().getMethodFamily(); + switch (family) { + case OMF_None: break; + + // init only has a conventional meaning for an instance method, and + // it has to return an object. + case OMF_init: + if (!isInstanceMethod() || !getResultType()->isObjCObjectPointerType()) + family = OMF_None; + break; + + // alloc/copy/new have a conventional meaning for both class and + // instance methods, but they require an object return. + case OMF_alloc: + case OMF_copy: + case OMF_mutableCopy: + case OMF_new: + if (!getResultType()->isObjCObjectPointerType()) + family = OMF_None; + break; + + // These selectors have a conventional meaning only for instance methods. + case OMF_dealloc: + case OMF_retain: + case OMF_release: + case OMF_autorelease: + case OMF_retainCount: + if (!isInstanceMethod()) + family = OMF_None; + break; + } + + // Cache the result. + Family = static_cast<unsigned>(family); + return family; +} + void ObjCMethodDecl::createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *OID) { QualType selfTy; @@ -614,7 +672,8 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, //===----------------------------------------------------------------------===// ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, - SourceLocation L, IdentifierInfo *Id, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, bool synthesized) { @@ -651,7 +710,8 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, ID->setIvarList(0); } - return new (C) ObjCIvarDecl(DC, L, Id, T, TInfo, ac, BW, synthesized); + return new (C) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo, + ac, BW, synthesized); } const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { @@ -684,9 +744,10 @@ const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { //===----------------------------------------------------------------------===// ObjCAtDefsFieldDecl -*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, +*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, QualType T, Expr *BW) { - return new (C) ObjCAtDefsFieldDecl(DC, L, Id, T, BW); + return new (C) ObjCAtDefsFieldDecl(DC, StartLoc, IdLoc, Id, T, BW); } //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index c6ae128e42b5..2fd88d7c808d 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -45,6 +45,7 @@ namespace { void VisitTranslationUnitDecl(TranslationUnitDecl *D); void VisitTypedefDecl(TypedefDecl *D); + void VisitTypeAliasDecl(TypeAliasDecl *D); void VisitEnumDecl(EnumDecl *D); void VisitRecordDecl(RecordDecl *D); void VisitEnumConstantDecl(EnumConstantDecl *D); @@ -54,12 +55,13 @@ namespace { void VisitLabelDecl(LabelDecl *D); void VisitParmVarDecl(ParmVarDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); + void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); void VisitCXXRecordDecl(CXXRecordDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); - void VisitTemplateDecl(TemplateDecl *D); + void VisitTemplateDecl(const TemplateDecl *D); void VisitObjCMethodDecl(ObjCMethodDecl *D); void VisitObjCClassDecl(ObjCClassDecl *D); void VisitObjCImplementationDecl(ObjCImplementationDecl *D); @@ -109,7 +111,7 @@ static QualType GetBaseType(QualType T) { } static QualType getDeclType(Decl* D) { - if (TypedefDecl* TDD = dyn_cast<TypedefDecl>(D)) + if (TypedefNameDecl* TDD = dyn_cast<TypedefNameDecl>(D)) return TDD->getUnderlyingType(); if (ValueDecl* VD = dyn_cast<ValueDecl>(D)) return VD->getType(); @@ -307,6 +309,11 @@ void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { Out << S; } +void DeclPrinter::VisitTypeAliasDecl(TypeAliasDecl *D) { + Out << "using " << D->getNameAsString() << " = " + << D->getUnderlyingType().getAsString(Policy); +} + void DeclPrinter::VisitEnumDecl(EnumDecl *D) { Out << "enum "; if (D->isScoped()) { @@ -412,22 +419,32 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (TypeQuals & Qualifiers::Restrict) Proto += " restrict"; } - - if (FT && FT->hasExceptionSpec()) { + + if (FT && FT->hasDynamicExceptionSpec()) { Proto += " throw("; - if (FT->hasAnyExceptionSpec()) + if (FT->getExceptionSpecType() == EST_MSAny) Proto += "..."; else for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) { if (I) Proto += ", "; - - + std::string ExceptionType; FT->getExceptionType(I).getAsStringInternal(ExceptionType, SubPolicy); Proto += ExceptionType; } Proto += ")"; + } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) { + Proto += " noexcept"; + if (FT->getExceptionSpecType() == EST_ComputedNoexcept) { + Proto += "("; + llvm::raw_string_ostream EOut(Proto); + FT->getNoexceptExpr()->printPretty(EOut, Context, 0, SubPolicy, + Indentation); + EOut.flush(); + Proto += EOut.str(); + Proto += ")"; + } } if (D->hasAttr<NoReturnAttr>()) @@ -556,7 +573,8 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { T = Parm->getOriginalType(); T.getAsStringInternal(Name, Policy); Out << Name; - if (Expr *Init = D->getInit()) { + Expr *Init = D->getInit(); + if (!Policy.SuppressInitializers && Init) { if (D->hasCXXDirectInitializer()) Out << "("; else { @@ -580,6 +598,14 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { Out << ")"; } +void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) { + Out << "static_assert("; + D->getAssertExpr()->printPretty(Out, Context, 0, Policy, Indentation); + Out << ", "; + D->getMessage()->printPretty(Out, Context, 0, Policy, Indentation); + Out << ")"; +} + //---------------------------------------------------------------------------- // C++ declarations //---------------------------------------------------------------------------- @@ -624,6 +650,9 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { if (AS != AS_none) Print(AS); Out << " " << Base->getType().getAsString(Policy); + + if (Base->isPackExpansion()) + Out << "..."; } } @@ -654,7 +683,7 @@ void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { Visit(*D->decls_begin()); } -void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { +void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { Out << "template <"; TemplateParameterList *Params = D->getTemplateParameters(); @@ -666,9 +695,6 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { - QualType ParamType = - Context.getTypeDeclType(const_cast<TemplateTypeParmDecl*>(TTP)); - if (TTP->wasDeclaredWithTypename()) Out << "typename "; else @@ -677,7 +703,7 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { if (TTP->isParameterPack()) Out << "... "; - Out << ParamType.getAsString(Policy); + Out << TTP->getNameAsString(); if (TTP->hasDefaultArgument()) { Out << " = "; @@ -700,12 +726,17 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy, Indentation); } + } else if (const TemplateTemplateParmDecl *TTPD = + dyn_cast<TemplateTemplateParmDecl>(Param)) { + VisitTemplateDecl(TTPD); + // FIXME: print the default argument, if present. } } Out << "> "; - if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { + if (const TemplateTemplateParmDecl *TTP = + dyn_cast<TemplateTemplateParmDecl>(D)) { Out << "class "; if (TTP->isParameterPack()) Out << "..."; diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index a73deeab3a61..6272340691bf 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -95,6 +95,18 @@ unsigned TemplateParameterList::getDepth() const { return cast<TemplateTemplateParmDecl>(FirstParm)->getDepth(); } +static void AdoptTemplateParameterList(TemplateParameterList *Params, + DeclContext *Owner) { + for (TemplateParameterList::iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + (*P)->setDeclContext(Owner); + + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(*P)) + AdoptTemplateParameterList(TTP->getTemplateParameters(), Owner); + } +} + //===----------------------------------------------------------------------===// // RedeclarableTemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -151,6 +163,49 @@ RedeclarableTemplateDecl::findSpecializationImpl( return Entry ? SETraits::getMostRecentDeclaration(Entry) : 0; } +/// \brief Generate the injected template arguments for the given template +/// parameter list, e.g., for the injected-class-name of a class template. +static void GenerateInjectedTemplateArgs(ASTContext &Context, + TemplateParameterList *Params, + TemplateArgument *Args) { + for (TemplateParameterList::iterator Param = Params->begin(), + ParamEnd = Params->end(); + Param != ParamEnd; ++Param) { + TemplateArgument Arg; + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { + QualType ArgType = Context.getTypeDeclType(TTP); + if (TTP->isParameterPack()) + ArgType = Context.getPackExpansionType(ArgType, + llvm::Optional<unsigned>()); + + Arg = TemplateArgument(ArgType); + } else if (NonTypeTemplateParmDecl *NTTP = + dyn_cast<NonTypeTemplateParmDecl>(*Param)) { + Expr *E = new (Context) DeclRefExpr(NTTP, + NTTP->getType().getNonLValueExprType(Context), + Expr::getValueKindForType(NTTP->getType()), + NTTP->getLocation()); + + if (NTTP->isParameterPack()) + E = new (Context) PackExpansionExpr(Context.DependentTy, E, + NTTP->getLocation(), + llvm::Optional<unsigned>()); + Arg = TemplateArgument(E); + } else { + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); + if (TTP->isParameterPack()) + Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>()); + else + Arg = TemplateArgument(TemplateName(TTP)); + } + + if ((*Param)->isTemplateParameterPack()) + Arg = TemplateArgument::CreatePackCopy(Context, &Arg, 1); + + *Args++ = Arg; + } +} + //===----------------------------------------------------------------------===// // FunctionTemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -165,9 +220,15 @@ FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl) { + AdoptTemplateParameterList(Params, cast<DeclContext>(Decl)); return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl); } +FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, EmptyShell) { + return new (C) FunctionTemplateDecl(0, SourceLocation(), DeclarationName(), + 0, 0); +} + RedeclarableTemplateDecl::CommonBase * FunctionTemplateDecl::newCommon(ASTContext &C) { Common *CommonPtr = new (C) Common; @@ -181,6 +242,27 @@ FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args, return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos); } +void FunctionTemplateDecl::addSpecialization( + FunctionTemplateSpecializationInfo *Info, void *InsertPos) { + getSpecializations().InsertNode(Info, InsertPos); + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, Info->Function); +} + +std::pair<const TemplateArgument *, unsigned> +FunctionTemplateDecl::getInjectedTemplateArgs() { + TemplateParameterList *Params = getTemplateParameters(); + Common *CommonPtr = getCommonPtr(); + if (!CommonPtr->InjectedArgs) { + CommonPtr->InjectedArgs + = new (getASTContext()) TemplateArgument [Params->size()]; + GenerateInjectedTemplateArgs(getASTContext(), Params, + CommonPtr->InjectedArgs); + } + + return std::make_pair(CommonPtr->InjectedArgs, Params->size()); +} + //===----------------------------------------------------------------------===// // ClassTemplateDecl Implementation //===----------------------------------------------------------------------===// @@ -196,11 +278,16 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, TemplateParameterList *Params, NamedDecl *Decl, ClassTemplateDecl *PrevDecl) { + AdoptTemplateParameterList(Params, cast<DeclContext>(Decl)); ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl); New->setPreviousDeclaration(PrevDecl); return New; } +ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) ClassTemplateDecl(Empty); +} + void ClassTemplateDecl::LoadLazySpecializations() { Common *CommonPtr = getCommonPtr(); if (CommonPtr->LazySpecializations) { @@ -320,44 +407,8 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() { ASTContext &Context = getASTContext(); TemplateParameterList *Params = getTemplateParameters(); llvm::SmallVector<TemplateArgument, 16> TemplateArgs; - TemplateArgs.reserve(Params->size()); - for (TemplateParameterList::iterator Param = Params->begin(), - ParamEnd = Params->end(); - Param != ParamEnd; ++Param) { - TemplateArgument Arg; - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { - QualType ArgType = Context.getTypeDeclType(TTP); - if (TTP->isParameterPack()) - ArgType = Context.getPackExpansionType(ArgType, - llvm::Optional<unsigned>()); - - Arg = TemplateArgument(ArgType); - } else if (NonTypeTemplateParmDecl *NTTP = - dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - Expr *E = new (Context) DeclRefExpr(NTTP, - NTTP->getType().getNonLValueExprType(Context), - Expr::getValueKindForType(NTTP->getType()), - NTTP->getLocation()); - - if (NTTP->isParameterPack()) - E = new (Context) PackExpansionExpr(Context.DependentTy, E, - NTTP->getLocation(), - llvm::Optional<unsigned>()); - Arg = TemplateArgument(E); - } else { - TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); - if (TTP->isParameterPack()) - Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>()); - else - Arg = TemplateArgument(TemplateName(TTP)); - } - - if ((*Param)->isTemplateParameterPack()) - Arg = TemplateArgument::CreatePackCopy(Context, &Arg, 1); - - TemplateArgs.push_back(Arg); - } - + TemplateArgs.resize(Params->size()); + GenerateInjectedTemplateArgs(getASTContext(), Params, TemplateArgs.data()); CommonPtr->InjectedClassNameType = Context.getTemplateSpecializationType(TemplateName(this), &TemplateArgs[0], @@ -371,21 +422,34 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() { TemplateTypeParmDecl * TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC, - SourceLocation L, unsigned D, unsigned P, - IdentifierInfo *Id, bool Typename, - bool ParameterPack) { - QualType Type = C.getTemplateTypeParmType(D, P, ParameterPack, Id); - return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type, ParameterPack); + SourceLocation KeyLoc, SourceLocation NameLoc, + unsigned D, unsigned P, IdentifierInfo *Id, + bool Typename, bool ParameterPack) { + TemplateTypeParmDecl *TTPDecl = + new (C) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename); + QualType TTPType = C.getTemplateTypeParmType(D, P, ParameterPack, TTPDecl); + TTPDecl->TypeForDecl = TTPType.getTypePtr(); + return TTPDecl; } TemplateTypeParmDecl * TemplateTypeParmDecl::Create(const ASTContext &C, EmptyShell Empty) { - return new (C) TemplateTypeParmDecl(0, SourceLocation(), 0, false, - QualType(), false); + return new (C) TemplateTypeParmDecl(0, SourceLocation(), SourceLocation(), + 0, false); } SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const { - return DefaultArgument->getTypeLoc().getSourceRange().getBegin(); + return hasDefaultArgument() + ? DefaultArgument->getTypeLoc().getBeginLoc() + : SourceLocation(); +} + +SourceRange TemplateTypeParmDecl::getSourceRange() const { + if (hasDefaultArgument() && !defaultArgumentWasInherited()) + return SourceRange(getLocStart(), + DefaultArgument->getTypeLoc().getEndLoc()); + else + return TypeDecl::getSourceRange(); } unsigned TemplateTypeParmDecl::getDepth() const { @@ -396,19 +460,25 @@ unsigned TemplateTypeParmDecl::getIndex() const { return TypeForDecl->getAs<TemplateTypeParmType>()->getIndex(); } +bool TemplateTypeParmDecl::isParameterPack() const { + return TypeForDecl->getAs<TemplateTypeParmType>()->isParameterPack(); +} + //===----------------------------------------------------------------------===// // NonTypeTemplateParmDecl Method Implementations //===----------------------------------------------------------------------===// NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC, - SourceLocation L, unsigned D, - unsigned P, IdentifierInfo *Id, + SourceLocation StartLoc, + SourceLocation IdLoc, + unsigned D, unsigned P, + IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, const QualType *ExpandedTypes, unsigned NumExpandedTypes, TypeSourceInfo **ExpandedTInfos) - : DeclaratorDecl(NonTypeTemplateParm, DC, L, Id, T, TInfo), + : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false), ParameterPack(true), ExpandedParameterPack(true), NumExpandedTypes(NumExpandedTypes) @@ -424,16 +494,18 @@ NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC, NonTypeTemplateParmDecl * NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, - SourceLocation L, unsigned D, unsigned P, - IdentifierInfo *Id, QualType T, - bool ParameterPack, TypeSourceInfo *TInfo) { - return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, ParameterPack, - TInfo); + SourceLocation StartLoc, SourceLocation IdLoc, + unsigned D, unsigned P, IdentifierInfo *Id, + QualType T, bool ParameterPack, + TypeSourceInfo *TInfo) { + return new (C) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, + T, ParameterPack, TInfo); } NonTypeTemplateParmDecl * NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, - SourceLocation L, unsigned D, unsigned P, + SourceLocation StartLoc, SourceLocation IdLoc, + unsigned D, unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, const QualType *ExpandedTypes, @@ -442,20 +514,17 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, unsigned Size = sizeof(NonTypeTemplateParmDecl) + NumExpandedTypes * 2 * sizeof(void*); void *Mem = C.Allocate(Size); - return new (Mem) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, TInfo, + return new (Mem) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, + D, P, Id, T, TInfo, ExpandedTypes, NumExpandedTypes, ExpandedTInfos); } -SourceLocation NonTypeTemplateParmDecl::getInnerLocStart() const { - SourceLocation Start = getTypeSpecStartLoc(); - if (Start.isInvalid()) - Start = getLocation(); - return Start; -} - SourceRange NonTypeTemplateParmDecl::getSourceRange() const { - return SourceRange(getOuterLocStart(), getLocation()); + if (hasDefaultArgument() && !defaultArgumentWasInherited()) + return SourceRange(getOuterLocStart(), + getDefaultArgument()->getSourceRange().getEnd()); + return DeclaratorDecl::getSourceRange(); } SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { @@ -499,12 +568,13 @@ TemplateArgumentList::CreateCopy(ASTContext &Context, //===----------------------------------------------------------------------===// ClassTemplateSpecializationDecl:: ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK, - DeclContext *DC, SourceLocation L, + DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, ClassTemplateDecl *SpecializedTemplate, const TemplateArgument *Args, unsigned NumArgs, ClassTemplateSpecializationDecl *PrevDecl) - : CXXRecordDecl(DK, TK, DC, L, + : CXXRecordDecl(DK, TK, DC, StartLoc, IdLoc, SpecializedTemplate->getIdentifier(), PrevDecl), SpecializedTemplate(SpecializedTemplate), @@ -514,14 +584,16 @@ ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK, } ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(Kind DK) - : CXXRecordDecl(DK, TTK_Struct, 0, SourceLocation(), 0, 0), + : CXXRecordDecl(DK, TTK_Struct, 0, SourceLocation(), SourceLocation(), 0, 0), ExplicitInfo(0), SpecializationKind(TSK_Undeclared) { } ClassTemplateSpecializationDecl * ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK, - DeclContext *DC, SourceLocation L, + DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, ClassTemplateDecl *SpecializedTemplate, const TemplateArgument *Args, unsigned NumArgs, @@ -529,7 +601,7 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK, ClassTemplateSpecializationDecl *Result = new (Context)ClassTemplateSpecializationDecl(Context, ClassTemplateSpecialization, - TK, DC, L, + TK, DC, StartLoc, IdLoc, SpecializedTemplate, Args, NumArgs, PrevDecl); @@ -564,12 +636,51 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const { return SpecializedTemplate.get<ClassTemplateDecl*>(); } +SourceRange +ClassTemplateSpecializationDecl::getSourceRange() const { + if (!ExplicitInfo) + return SourceRange(); + SourceLocation Begin = getExternLoc(); + if (Begin.isInvalid()) + Begin = getTemplateKeywordLoc(); + SourceLocation End = getRBraceLoc(); + if (End.isInvalid()) + End = getTypeAsWritten()->getTypeLoc().getEndLoc(); + return SourceRange(Begin, End); +} + //===----------------------------------------------------------------------===// // ClassTemplatePartialSpecializationDecl Implementation //===----------------------------------------------------------------------===// +ClassTemplatePartialSpecializationDecl:: +ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK, + DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + TemplateArgumentLoc *ArgInfos, + unsigned NumArgInfos, + ClassTemplatePartialSpecializationDecl *PrevDecl, + unsigned SequenceNumber) + : ClassTemplateSpecializationDecl(Context, + ClassTemplatePartialSpecialization, + TK, DC, StartLoc, IdLoc, + SpecializedTemplate, + Args, NumArgs, PrevDecl), + TemplateParams(Params), ArgsAsWritten(ArgInfos), + NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber), + InstantiatedFromMember(0, false) +{ + AdoptTemplateParameterList(Params, this); +} + ClassTemplatePartialSpecializationDecl * ClassTemplatePartialSpecializationDecl:: -Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L, +Create(ASTContext &Context, TagKind TK,DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate, const TemplateArgument *Args, @@ -584,8 +695,9 @@ Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L, ClonedArgs[I] = ArgInfos[I]; ClassTemplatePartialSpecializationDecl *Result - = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, - DC, L, Params, + = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC, + StartLoc, IdLoc, + Params, SpecializedTemplate, Args, NumArgs, ClonedArgs, N, diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp index 9d828fcfb85a..7d593bc46f6c 100644 --- a/lib/AST/DumpXML.cpp +++ b/lib/AST/DumpXML.cpp @@ -543,12 +543,20 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, // TypedefDecl void visitTypedefDeclAttrs(TypedefDecl *D) { - visitRedeclarableAttrs(D); + visitRedeclarableAttrs<TypedefNameDecl>(D); } void visitTypedefDeclChildren(TypedefDecl *D) { dispatch(D->getTypeSourceInfo()->getTypeLoc()); } + // TypeAliasDecl + void visitTypeAliasDeclAttrs(TypeAliasDecl *D) { + visitRedeclarableAttrs<TypedefNameDecl>(D); + } + void visitTypeAliasDeclChildren(TypeAliasDecl *D) { + dispatch(D->getTypeSourceInfo()->getTypeLoc()); + } + // TagDecl void visitTagDeclAttrs(TagDecl *D) { visitRedeclarableAttrs(D); @@ -911,6 +919,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, case CC_X86StdCall: return set("cc", "x86_stdcall"); case CC_X86ThisCall: return set("cc", "x86_thiscall"); case CC_X86Pascal: return set("cc", "x86_pascal"); + case CC_AAPCS: return set("cc", "aapcs"); + case CC_AAPCS_VFP: return set("cc", "aapcs_vfp"); } } @@ -955,7 +965,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, void visitFunctionTypeAttrs(FunctionType *T) { setFlag("noreturn", T->getNoReturnAttr()); setCallingConv(T->getCallConv()); - if (T->getRegParmType()) setInteger("regparm", T->getRegParmType()); + if (T->getHasRegParm()) setInteger("regparm", T->getRegParmType()); } void visitFunctionTypeChildren(FunctionType *T) { dispatch(T->getResultType()); @@ -975,15 +985,16 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, dispatch(*I); pop(); - if (T->hasExceptionSpec()) { + if (T->hasDynamicExceptionSpec()) { push("exception_specifiers"); - setFlag("any", T->hasAnyExceptionSpec()); + setFlag("any", T->getExceptionSpecType() == EST_MSAny); completeAttrs(); for (FunctionProtoType::exception_iterator I = T->exception_begin(), E = T->exception_end(); I != E; ++I) dispatch(*I); pop(); } + // FIXME: noexcept specifier } void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 1c1061b5a229..6499f327b07e 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -35,18 +35,16 @@ using namespace clang; /// but also int expressions which are produced by things like comparisons in /// C. bool Expr::isKnownToHaveBooleanValue() const { + const Expr *E = IgnoreParens(); + // If this value has _Bool type, it is obvious 0/1. - if (getType()->isBooleanType()) return true; + if (E->getType()->isBooleanType()) return true; // If this is a non-scalar-integer type, we don't care enough to try. - if (!getType()->isIntegralOrEnumerationType()) return false; - - if (const ParenExpr *PE = dyn_cast<ParenExpr>(this)) - return PE->getSubExpr()->isKnownToHaveBooleanValue(); + if (!E->getType()->isIntegralOrEnumerationType()) return false; - if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(this)) { + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { switch (UO->getOpcode()) { case UO_Plus: - case UO_Extension: return UO->getSubExpr()->isKnownToHaveBooleanValue(); default: return false; @@ -55,10 +53,10 @@ bool Expr::isKnownToHaveBooleanValue() const { // Only look through implicit casts. If the user writes // '(int) (a && b)' treat it as an arbitrary int. - if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(this)) + if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) return CE->getSubExpr()->isKnownToHaveBooleanValue(); - if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(this)) { + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { switch (BO->getOpcode()) { default: return false; case BO_LT: // Relational operators. @@ -84,7 +82,7 @@ bool Expr::isKnownToHaveBooleanValue() const { } } - if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(this)) + if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) return CO->getTrueExpr()->isKnownToHaveBooleanValue() && CO->getFalseExpr()->isKnownToHaveBooleanValue(); @@ -276,44 +274,20 @@ void DeclRefExpr::computeDependence() { ExprBits.ContainsUnexpandedParameterPack = true; } -DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - ValueDecl *D, SourceLocation NameLoc, - const TemplateArgumentListInfo *TemplateArgs, - QualType T, ExprValueKind VK) - : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false), - DecoratedD(D, - (Qualifier? HasQualifierFlag : 0) | - (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)), - Loc(NameLoc) { - if (Qualifier) { - NameQualifier *NQ = getNameQualifier(); - NQ->NNS = Qualifier; - NQ->Range = QualifierRange; - } - - if (TemplateArgs) - getExplicitTemplateArgs().initializeFrom(*TemplateArgs); - - computeDependence(); -} - -DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, +DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc, ValueDecl *D, const DeclarationNameInfo &NameInfo, + NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK) : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false), - DecoratedD(D, - (Qualifier? HasQualifierFlag : 0) | - (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)), - Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) { - if (Qualifier) { - NameQualifier *NQ = getNameQualifier(); - NQ->NNS = Qualifier; - NQ->Range = QualifierRange; - } - + D(D), Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) { + DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0; + if (QualifierLoc) + getInternalQualifierLoc() = QualifierLoc; + DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0; + if (FoundD) + getInternalFoundDecl() = FoundD; + DeclRefExprBits.HasExplicitTemplateArgs = TemplateArgs ? 1 : 0; if (TemplateArgs) getExplicitTemplateArgs().initializeFrom(*TemplateArgs); @@ -321,49 +295,56 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier, } DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + NestedNameSpecifierLoc QualifierLoc, ValueDecl *D, SourceLocation NameLoc, QualType T, ExprValueKind VK, + NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) { - return Create(Context, Qualifier, QualifierRange, D, + return Create(Context, QualifierLoc, D, DeclarationNameInfo(D->getDeclName(), NameLoc), - T, VK, TemplateArgs); + T, VK, FoundD, TemplateArgs); } DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + NestedNameSpecifierLoc QualifierLoc, ValueDecl *D, const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, + NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) { + // Filter out cases where the found Decl is the same as the value refenenced. + if (D == FoundD) + FoundD = 0; + std::size_t Size = sizeof(DeclRefExpr); - if (Qualifier != 0) - Size += sizeof(NameQualifier); - + if (QualifierLoc != 0) + Size += sizeof(NestedNameSpecifierLoc); + if (FoundD) + Size += sizeof(NamedDecl *); if (TemplateArgs) Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); - + void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>()); - return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameInfo, - TemplateArgs, T, VK); + return new (Mem) DeclRefExpr(QualifierLoc, D, NameInfo, FoundD, TemplateArgs, + T, VK); } -DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, +DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, bool HasQualifier, + bool HasFoundDecl, bool HasExplicitTemplateArgs, unsigned NumTemplateArgs) { std::size_t Size = sizeof(DeclRefExpr); if (HasQualifier) - Size += sizeof(NameQualifier); - + Size += sizeof(NestedNameSpecifierLoc); + if (HasFoundDecl) + Size += sizeof(NamedDecl *); if (HasExplicitTemplateArgs) Size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); - + void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>()); return new (Mem) DeclRefExpr(EmptyShell()); } @@ -371,7 +352,7 @@ DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, SourceRange DeclRefExpr::getSourceRange() const { SourceRange R = getNameInfo().getSourceRange(); if (hasQualifier()) - R.setBegin(getQualifierRange().getBegin()); + R.setBegin(getQualifierLoc().getBeginLoc()); if (hasExplicitTemplateArgs()) R.setEnd(getRAngleLoc()); return R; @@ -518,7 +499,7 @@ double FloatingLiteral::getValueAsApproximateDouble() const { StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, unsigned ByteLength, bool Wide, - QualType Ty, + bool Pascal, QualType Ty, const SourceLocation *Loc, unsigned NumStrs) { // Allocate enough space for the StringLiteral plus an array of locations for @@ -534,6 +515,7 @@ StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, SL->StrData = AStrData; SL->ByteLength = ByteLength; SL->IsWide = Wide; + SL->IsPascal = Pascal; SL->TokLocs[0] = Loc[0]; SL->NumConcatenated = NumStrs; @@ -828,11 +810,11 @@ QualType CallExpr::getCallReturnType() const { CalleeType = FnTypePtr->getPointeeType(); else if (const BlockPointerType *BPT = CalleeType->getAs<BlockPointerType>()) CalleeType = BPT->getPointeeType(); - else if (const MemberPointerType *MPT - = CalleeType->getAs<MemberPointerType>()) - CalleeType = MPT->getPointeeType(); + else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember)) + // This should never be overloaded and so should never return null. + CalleeType = Expr::findBoundMemberType(getCallee()); - const FunctionType *FnType = CalleeType->getAs<FunctionType>(); + const FunctionType *FnType = CalleeType->castAs<FunctionType>(); return FnType->getResultType(); } @@ -906,8 +888,7 @@ IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const { } MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, - NestedNameSpecifier *qual, - SourceRange qualrange, + NestedNameSpecifierLoc QualifierLoc, ValueDecl *memberdecl, DeclAccessPair founddecl, DeclarationNameInfo nameinfo, @@ -917,7 +898,7 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, ExprObjectKind ok) { std::size_t Size = sizeof(MemberExpr); - bool hasQualOrFound = (qual != 0 || + bool hasQualOrFound = (QualifierLoc || founddecl.getDecl() != memberdecl || founddecl.getAccess() != memberdecl->getAccess()); if (hasQualOrFound) @@ -931,15 +912,15 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, ty, vk, ok); if (hasQualOrFound) { - if (qual && qual->isDependent()) { + // FIXME: Wrong. We should be looking at the member declaration we found. + if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) { E->setValueDependent(true); E->setTypeDependent(true); } E->HasQualifierOrFoundDecl = true; MemberNameQualifier *NQ = E->getMemberQualifier(); - NQ->NNS = qual; - NQ->Range = qualrange; + NQ->QualifierLoc = QualifierLoc; NQ->FoundDecl = founddecl; } @@ -951,6 +932,28 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, return E; } +SourceRange MemberExpr::getSourceRange() const { + SourceLocation StartLoc; + if (isImplicitAccess()) { + if (hasQualifier()) + StartLoc = getQualifierLoc().getBeginLoc(); + else + StartLoc = MemberLoc; + } else { + // FIXME: We don't want this to happen. Rather, we should be able to + // detect all kinds of implicit accesses more cleanly. + StartLoc = getBase()->getLocStart(); + if (StartLoc.isInvalid()) + StartLoc = MemberLoc; + } + + SourceLocation EndLoc = + HasExplicitTemplateArgumentList? getRAngleLoc() + : getMemberNameInfo().getEndLoc(); + + return SourceRange(StartLoc, EndLoc); +} + const char *CastExpr::getCastKindName() const { switch (getCastKind()) { case CK_Dependent: @@ -1241,7 +1244,7 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, false), InitExprs(C, numInits), LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), - UnionFieldInit(0), HadArrayRangeDesignator(false) + HadArrayRangeDesignator(false) { for (unsigned I = 0; I != numInits; ++I) { if (initExprs[I]->isTypeDependent()) @@ -1276,6 +1279,15 @@ Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) { return Result; } +void InitListExpr::setArrayFiller(Expr *filler) { + ArrayFillerOrUnionFieldInit = filler; + // Fill out any "holes" in the array due to designated initializers. + Expr **inits = getInits(); + for (unsigned i = 0, e = getNumInits(); i != e; ++i) + if (inits[i] == 0) + inits[i] = filler; +} + SourceRange InitListExpr::getSourceRange() const { if (SyntacticForm) return SyntacticForm->getSourceRange(); @@ -1348,6 +1360,9 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case ParenExprClass: return cast<ParenExpr>(this)->getSubExpr()-> isUnusedResultAWarning(Loc, R1, R2, Ctx); + case GenericSelectionExprClass: + return cast<GenericSelectionExpr>(this)->getResultExpr()-> + isUnusedResultAWarning(Loc, R1, R2, Ctx); case UnaryOperatorClass: { const UnaryOperator *UO = cast<UnaryOperator>(this); @@ -1412,13 +1427,15 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, return false; case ConditionalOperatorClass: { - // The condition must be evaluated, but if either the LHS or RHS is a - // warning, warn about them. + // If only one of the LHS or RHS is a warning, the operator might + // be being used for control flow. Only warn if both the LHS and + // RHS are warnings. const ConditionalOperator *Exp = cast<ConditionalOperator>(this); - if (Exp->getLHS() && - Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)) + if (!Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)) + return false; + if (!Exp->getLHS()) return true; - return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx); + return Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx); } case MemberExprClass: @@ -1556,21 +1573,20 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, /// isOBJCGCCandidate - Check if an expression is objc gc'able. /// returns true, if it is; false otherwise. bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { - switch (getStmtClass()) { + const Expr *E = IgnoreParens(); + switch (E->getStmtClass()) { default: return false; case ObjCIvarRefExprClass: return true; case Expr::UnaryOperatorClass: - return cast<UnaryOperator>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); - case ParenExprClass: - return cast<ParenExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); + return cast<UnaryOperator>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case ImplicitCastExprClass: - return cast<ImplicitCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); + return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case CStyleCastExprClass: - return cast<CStyleCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); + return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case DeclRefExprClass: { - const Decl *D = cast<DeclRefExpr>(this)->getDecl(); + const Decl *D = cast<DeclRefExpr>(E)->getDecl(); if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (VD->hasGlobalStorage()) return true; @@ -1583,11 +1599,11 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { return false; } case MemberExprClass: { - const MemberExpr *M = cast<MemberExpr>(this); + const MemberExpr *M = cast<MemberExpr>(E); return M->getBase()->isOBJCGCCandidate(Ctx); } case ArraySubscriptExprClass: - return cast<ArraySubscriptExpr>(this)->getBase()->isOBJCGCCandidate(Ctx); + return cast<ArraySubscriptExpr>(E)->getBase()->isOBJCGCCandidate(Ctx); } } @@ -1597,6 +1613,30 @@ bool Expr::isBoundMemberFunction(ASTContext &Ctx) const { return ClassifyLValue(Ctx) == Expr::LV_MemberFunction; } +QualType Expr::findBoundMemberType(const Expr *expr) { + assert(expr->getType()->isSpecificPlaceholderType(BuiltinType::BoundMember)); + + // Bound member expressions are always one of these possibilities: + // x->m x.m x->*y x.*y + // (possibly parenthesized) + + expr = expr->IgnoreParens(); + if (const MemberExpr *mem = dyn_cast<MemberExpr>(expr)) { + assert(isa<CXXMethodDecl>(mem->getMemberDecl())); + return mem->getMemberDecl()->getType(); + } + + if (const BinaryOperator *op = dyn_cast<BinaryOperator>(expr)) { + QualType type = op->getRHS()->getType()->castAs<MemberPointerType>() + ->getPointeeType(); + assert(type->isFunctionType()); + return type; + } + + assert(isa<UnresolvedMemberExpr>(expr)); + return QualType(); +} + static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1, Expr::CanThrowResult CT2) { // CanThrowResult constants are ordered so that the maximum is the correct @@ -1613,7 +1653,7 @@ static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) { return R; } -static Expr::CanThrowResult CanCalleeThrow(const Decl *D, +static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Decl *D, bool NullThrows = true) { if (!D) return NullThrows ? Expr::CT_Can : Expr::CT_Cannot; @@ -1643,7 +1683,7 @@ static Expr::CanThrowResult CanCalleeThrow(const Decl *D, if (!FT) return Expr::CT_Can; - return FT->hasEmptyExceptionSpec() ? Expr::CT_Cannot : Expr::CT_Can; + return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can; } static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) { @@ -1707,7 +1747,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { case CallExprClass: case CXXOperatorCallExprClass: case CXXMemberCallExprClass: { - CanThrowResult CT = CanCalleeThrow(cast<CallExpr>(this)->getCalleeDecl()); + CanThrowResult CT = CanCalleeThrow(C,cast<CallExpr>(this)->getCalleeDecl()); if (CT == CT_Can) return CT; return MergeCanThrow(CT, CanSubExprsThrow(C, this)); @@ -1715,7 +1755,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { case CXXConstructExprClass: case CXXTemporaryObjectExprClass: { - CanThrowResult CT = CanCalleeThrow( + CanThrowResult CT = CanCalleeThrow(C, cast<CXXConstructExpr>(this)->getConstructor()); if (CT == CT_Can) return CT; @@ -1724,8 +1764,8 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { case CXXNewExprClass: { CanThrowResult CT = MergeCanThrow( - CanCalleeThrow(cast<CXXNewExpr>(this)->getOperatorNew()), - CanCalleeThrow(cast<CXXNewExpr>(this)->getConstructor(), + CanCalleeThrow(C, cast<CXXNewExpr>(this)->getOperatorNew()), + CanCalleeThrow(C, cast<CXXNewExpr>(this)->getConstructor(), /*NullThrows*/false)); if (CT == CT_Can) return CT; @@ -1733,7 +1773,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { } case CXXDeleteExprClass: { - CanThrowResult CT = CanCalleeThrow( + CanThrowResult CT = CanCalleeThrow(C, cast<CXXDeleteExpr>(this)->getOperatorDelete()); if (CT == CT_Can) return CT; @@ -1743,7 +1783,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { Arg = Cast->getSubExpr(); if (const PointerType *PT = Arg->getType()->getAs<PointerType>()) { if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) { - CanThrowResult CT2 = CanCalleeThrow( + CanThrowResult CT2 = CanCalleeThrow(C, cast<CXXRecordDecl>(RT->getDecl())->getDestructor()); if (CT2 == CT_Can) return CT2; @@ -1755,7 +1795,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { case CXXBindTemporaryExprClass: { // The bound temporary has to be destroyed again, which might throw. - CanThrowResult CT = CanCalleeThrow( + CanThrowResult CT = CanCalleeThrow(C, cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor()); if (CT == CT_Can) return CT; @@ -1810,6 +1850,11 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { return CT_Dependent; return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C); + case GenericSelectionExprClass: + if (cast<GenericSelectionExpr>(this)->isResultDependent()) + return CT_Dependent; + return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C); + // Some expressions are always dependent. case DependentScopeDeclRefExprClass: case CXXUnresolvedConstructExprClass: @@ -1836,6 +1881,12 @@ Expr* Expr::IgnoreParens() { continue; } } + if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { + if (!P->isResultDependent()) { + E = P->getResultExpr(); + continue; + } + } return E; } } @@ -1859,6 +1910,12 @@ Expr *Expr::IgnoreParenCasts() { continue; } } + if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { + if (!P->isResultDependent()) { + E = P->getResultExpr(); + continue; + } + } return E; } } @@ -1883,6 +1940,11 @@ Expr *Expr::IgnoreParenLValueCasts() { E = P->getSubExpr(); continue; } + } else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { + if (!P->isResultDependent()) { + E = P->getResultExpr(); + continue; + } } break; } @@ -1906,6 +1968,12 @@ Expr *Expr::IgnoreParenImpCasts() { continue; } } + if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { + if (!P->isResultDependent()) { + E = P->getResultExpr(); + continue; + } + } return E; } } @@ -1948,6 +2016,13 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { } } + if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { + if (!P->isResultDependent()) { + E = P->getResultExpr(); + continue; + } + } + return E; } } @@ -2023,6 +2098,42 @@ bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const { return true; } +bool Expr::isImplicitCXXThis() const { + const Expr *E = this; + + // Strip away parentheses and casts we don't care about. + while (true) { + if (const ParenExpr *Paren = dyn_cast<ParenExpr>(E)) { + E = Paren->getSubExpr(); + continue; + } + + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->getCastKind() == CK_NoOp || + ICE->getCastKind() == CK_LValueToRValue || + ICE->getCastKind() == CK_DerivedToBase || + ICE->getCastKind() == CK_UncheckedDerivedToBase) { + E = ICE->getSubExpr(); + continue; + } + } + + if (const UnaryOperator* UnOp = dyn_cast<UnaryOperator>(E)) { + if (UnOp->getOpcode() == UO_Extension) { + E = UnOp->getSubExpr(); + continue; + } + } + + break; + } + + if (const CXXThisExpr *This = dyn_cast<CXXThisExpr>(E)) + return This->isImplicit(); + + return false; +} + /// hasAnyTypeDependentArguments - Determines if any of the expressions /// in Exprs is type-dependent. bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) { @@ -2103,6 +2214,11 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const { case ParenExprClass: return cast<ParenExpr>(this)->getSubExpr() ->isConstantInitializer(Ctx, IsForRef); + case GenericSelectionExprClass: + if (cast<GenericSelectionExpr>(this)->isResultDependent()) + return false; + return cast<GenericSelectionExpr>(this)->getResultExpr() + ->isConstantInitializer(Ctx, IsForRef); case ChooseExprClass: return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx) ->isConstantInitializer(Ctx, IsForRef); @@ -2189,6 +2305,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx, // Accept ((void*)0) as a null pointer constant, as many other // implementations do. return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC); + } else if (const GenericSelectionExpr *GE = + dyn_cast<GenericSelectionExpr>(this)) { + return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC); } else if (const CXXDefaultArgExpr *DefaultArg = dyn_cast<CXXDefaultArgExpr>(this)) { // See through default argument expressions @@ -2587,6 +2706,51 @@ void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs, memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs); } +GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, + SourceLocation GenericLoc, Expr *ControllingExpr, + TypeSourceInfo **AssocTypes, Expr **AssocExprs, + unsigned NumAssocs, SourceLocation DefaultLoc, + SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack, + unsigned ResultIndex) + : Expr(GenericSelectionExprClass, + AssocExprs[ResultIndex]->getType(), + AssocExprs[ResultIndex]->getValueKind(), + AssocExprs[ResultIndex]->getObjectKind(), + AssocExprs[ResultIndex]->isTypeDependent(), + AssocExprs[ResultIndex]->isValueDependent(), + ContainsUnexpandedParameterPack), + AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]), + SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs), + 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); +} + +GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, + SourceLocation GenericLoc, Expr *ControllingExpr, + TypeSourceInfo **AssocTypes, Expr **AssocExprs, + unsigned NumAssocs, SourceLocation DefaultLoc, + SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack) + : Expr(GenericSelectionExprClass, + Context.DependentTy, + VK_RValue, + OK_Ordinary, + /*isTypeDependent=*/ true, + /*isValueDependent=*/ true, + ContainsUnexpandedParameterPack), + AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]), + SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs), + 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); +} + //===----------------------------------------------------------------------===// // DesignatedInitExpr //===----------------------------------------------------------------------===// @@ -2688,6 +2852,14 @@ void DesignatedInitExpr::setDesignators(ASTContext &C, Designators[I] = Desigs[I]; } +SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const { + DesignatedInitExpr *DIE = const_cast<DesignatedInitExpr*>(this); + if (size() == 1) + return DIE->getDesignator(0)->getSourceRange(); + return SourceRange(DIE->getDesignator(0)->getStartLocation(), + DIE->getDesignator(size()-1)->getEndLocation()); +} + SourceRange DesignatedInitExpr::getSourceRange() const { SourceLocation StartLoc; Designator &First = @@ -2802,8 +2974,8 @@ const Expr* ConstExprIterator::operator->() const { return cast<Expr>(*I); } // Child Iterators for iterating over subexpressions/substatements //===----------------------------------------------------------------------===// -// SizeOfAlignOfExpr -Stmt::child_range SizeOfAlignOfExpr::children() { +// UnaryExprOrTypeTraitExpr +Stmt::child_range UnaryExprOrTypeTraitExpr::children() { // If this is of a type and the type is a VLA type (and not a typedef), the // size expression of the VLA needs to be treated as an executable expression. // Why isn't this weirdness documented better in StmtIterator? diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 4f4a6b4944d9..1a1a0a36a65b 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -100,6 +100,10 @@ void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, SubExprs = new (C) Stmt*[TotalSize]; } +bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const { + return getOperatorNew()->getType()-> + castAs<FunctionProtoType>()->isNothrow(Ctx); +} // CXXDeleteExpr QualType CXXDeleteExpr::getDestroyedType() const { @@ -174,8 +178,7 @@ SourceRange CXXPseudoDestructorExpr::getSourceRange() const { UnresolvedLookupExpr * UnresolvedLookupExpr::Create(ASTContext &C, CXXRecordDecl *NamingClass, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, bool ADL, const TemplateArgumentListInfo &Args, @@ -184,10 +187,9 @@ UnresolvedLookupExpr::Create(ASTContext &C, { void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) + ExplicitTemplateArgumentList::sizeFor(Args)); - return new (Mem) UnresolvedLookupExpr(C, NamingClass, - Qualifier, QualifierRange, NameInfo, + return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo, ADL, /*Overload*/ true, &Args, - Begin, End); + Begin, End, /*StdIsAssociated=*/false); } UnresolvedLookupExpr * @@ -204,7 +206,7 @@ UnresolvedLookupExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, } OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, - NestedNameSpecifier *Qualifier, SourceRange QRange, + NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, @@ -215,10 +217,11 @@ OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, KnownDependent, (KnownContainsUnexpandedParameterPack || NameInfo.containsUnexpandedParameterPack() || - (Qualifier && Qualifier->containsUnexpandedParameterPack()))), + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier() + ->containsUnexpandedParameterPack()))), Results(0), NumResults(End - Begin), NameInfo(NameInfo), - Qualifier(Qualifier), QualifierRange(QRange), - HasExplicitTemplateArgs(TemplateArgs != 0) + QualifierLoc(QualifierLoc), HasExplicitTemplateArgs(TemplateArgs != 0) { NumResults = End - Begin; if (NumResults) { @@ -365,8 +368,10 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const { getArg(0)->getSourceRange().getEnd()); else // Postfix operator - return SourceRange(getArg(0)->getSourceRange().getEnd(), + return SourceRange(getArg(0)->getSourceRange().getBegin(), getOperatorLoc()); + } else if (Kind == OO_Arrow) { + return getArg(0)->getSourceRange(); } else if (Kind == OO_Call) { return SourceRange(getArg(0)->getSourceRange().getBegin(), getRParenLoc()); } else if (Kind == OO_Subscript) { @@ -381,14 +386,25 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const { } } -Expr *CXXMemberCallExpr::getImplicitObjectArgument() { - if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) +Expr *CXXMemberCallExpr::getImplicitObjectArgument() const { + if (const MemberExpr *MemExpr = + dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) return MemExpr->getBase(); // FIXME: Will eventually need to cope with member pointers. return 0; } +CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const { + if (const MemberExpr *MemExpr = + dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) + return cast<CXXMethodDecl>(MemExpr->getMemberDecl()); + + // FIXME: Will eventually need to cope with member pointers. + return 0; +} + + CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() { Expr* ThisArg = getImplicitObjectArgument(); if (!ThisArg) @@ -466,6 +482,36 @@ CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C, return new (Buffer) CXXDynamicCastExpr(EmptyShell(), PathSize); } +/// isAlwaysNull - Return whether the result of the dynamic_cast is proven +/// to always be null. For example: +/// +/// struct A { }; +/// struct B final : A { }; +/// struct C { }; +/// +/// C *f(B* b) { return dynamic_cast<C*>(b); } +bool CXXDynamicCastExpr::isAlwaysNull() const +{ + QualType SrcType = getSubExpr()->getType(); + QualType DestType = getType(); + + if (const PointerType *SrcPTy = SrcType->getAs<PointerType>()) { + SrcType = SrcPTy->getPointeeType(); + DestType = DestType->castAs<PointerType>()->getPointeeType(); + } + + const CXXRecordDecl *SrcRD = + cast<CXXRecordDecl>(SrcType->castAs<RecordType>()->getDecl()); + + if (!SrcRD->hasAttr<FinalAttr>()) + return false; + + const CXXRecordDecl *DestRD = + cast<CXXRecordDecl>(DestType->castAs<RecordType>()->getDecl()); + + return !DestRD->isDerivedFrom(SrcRD); +} + CXXReinterpretCastExpr * CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, CastKind K, Expr *Op, @@ -689,20 +735,20 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + NestedNameSpecifierLoc QualifierLoc, NamedDecl *FirstQualifierFoundInScope, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, VK_LValue, OK_Ordinary, true, true, ((Base && Base->containsUnexpandedParameterPack()) || - (Qualifier && Qualifier->containsUnexpandedParameterPack()) || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier() + ->containsUnexpandedParameterPack()) || MemberNameInfo.containsUnexpandedParameterPack())), Base(Base), BaseType(BaseType), IsArrow(IsArrow), HasExplicitTemplateArgs(TemplateArgs != 0), - OperatorLoc(OperatorLoc), - Qualifier(Qualifier), QualifierRange(QualifierRange), + OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc), FirstQualifierFoundInScope(FirstQualifierFoundInScope), MemberNameInfo(MemberNameInfo) { if (TemplateArgs) { @@ -719,18 +765,19 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + NestedNameSpecifierLoc QualifierLoc, NamedDecl *FirstQualifierFoundInScope, DeclarationNameInfo MemberNameInfo) : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, VK_LValue, OK_Ordinary, true, true, ((Base && Base->containsUnexpandedParameterPack()) || - (Qualifier && Qualifier->containsUnexpandedParameterPack()) || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier()-> + containsUnexpandedParameterPack()) || MemberNameInfo.containsUnexpandedParameterPack())), Base(Base), BaseType(BaseType), IsArrow(IsArrow), HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc), - Qualifier(Qualifier), QualifierRange(QualifierRange), + QualifierLoc(QualifierLoc), FirstQualifierFoundInScope(FirstQualifierFoundInScope), MemberNameInfo(MemberNameInfo) { } @@ -738,15 +785,14 @@ CXXDependentScopeMemberExpr * CXXDependentScopeMemberExpr::Create(ASTContext &C, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + NestedNameSpecifierLoc QualifierLoc, NamedDecl *FirstQualifierFoundInScope, DeclarationNameInfo MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) { if (!TemplateArgs) return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType, IsArrow, OperatorLoc, - Qualifier, QualifierRange, + QualifierLoc, FirstQualifierFoundInScope, MemberNameInfo); @@ -757,7 +803,7 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C, void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>()); return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType, IsArrow, OperatorLoc, - Qualifier, QualifierRange, + QualifierLoc, FirstQualifierFoundInScope, MemberNameInfo, TemplateArgs); } @@ -768,8 +814,8 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, unsigned NumTemplateArgs) { if (!HasExplicitTemplateArgs) return new (C) CXXDependentScopeMemberExpr(C, 0, QualType(), - 0, SourceLocation(), 0, - SourceRange(), 0, + 0, SourceLocation(), + NestedNameSpecifierLoc(), 0, DeclarationNameInfo()); std::size_t size = sizeof(CXXDependentScopeMemberExpr) + @@ -777,26 +823,53 @@ CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>()); CXXDependentScopeMemberExpr *E = new (Mem) CXXDependentScopeMemberExpr(C, 0, QualType(), - 0, SourceLocation(), 0, - SourceRange(), 0, + 0, SourceLocation(), + NestedNameSpecifierLoc(), 0, DeclarationNameInfo(), 0); E->HasExplicitTemplateArgs = true; return E; } +bool CXXDependentScopeMemberExpr::isImplicitAccess() const { + if (Base == 0) + return true; + + return cast<Expr>(Base)->isImplicitCXXThis(); +} + +static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin, + UnresolvedSetIterator end) { + do { + NamedDecl *decl = *begin; + if (isa<UnresolvedUsingValueDecl>(decl)) + return false; + if (isa<UsingShadowDecl>(decl)) + decl = cast<UsingShadowDecl>(decl)->getUnderlyingDecl(); + + // Unresolved member expressions should only contain methods and + // method templates. + assert(isa<CXXMethodDecl>(decl) || isa<FunctionTemplateDecl>(decl)); + + if (isa<FunctionTemplateDecl>(decl)) + decl = cast<FunctionTemplateDecl>(decl)->getTemplatedDecl(); + if (cast<CXXMethodDecl>(decl)->isStatic()) + return false; + } while (++begin != end); + + return true; +} + UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End) - : OverloadExpr(UnresolvedMemberExprClass, C, - Qualifier, QualifierRange, MemberNameInfo, + : OverloadExpr(UnresolvedMemberExprClass, C, QualifierLoc, MemberNameInfo, TemplateArgs, Begin, End, // Dependent ((Base && Base->isTypeDependent()) || @@ -806,6 +879,18 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, BaseType->containsUnexpandedParameterPack())), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) { + + // Check whether all of the members are non-static member functions, + // and if so, mark give this bound-member type instead of overload type. + if (hasOnlyNonStaticMemberFunctions(Begin, End)) + setType(C.BoundMemberTy); +} + +bool UnresolvedMemberExpr::isImplicitAccess() const { + if (Base == 0) + return true; + + return cast<Expr>(Base)->isImplicitCXXThis(); } UnresolvedMemberExpr * @@ -813,8 +898,7 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool HasUnresolvedUsing, Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OperatorLoc, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, @@ -826,7 +910,7 @@ UnresolvedMemberExpr::Create(ASTContext &C, void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>()); return new (Mem) UnresolvedMemberExpr(C, HasUnresolvedUsing, Base, BaseType, - IsArrow, OperatorLoc, Qualifier, QualifierRange, + IsArrow, OperatorLoc, QualifierLoc, MemberNameInfo, TemplateArgs, Begin, End); } diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 890898a985e8..888a93c8aac0 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -61,8 +61,10 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const { if (TR->isFunctionType() || TR == Ctx.OverloadTy) kind = Cl::CL_Function; // No void either, but qualified void is OK because it is "other than void". - else if (TR->isVoidType() && !Ctx.getCanonicalType(TR).hasQualifiers()) - kind = Cl::CL_Void; + // Void "lvalues" are classified as addressable void values, which are void + // expressions whose address can be taken. + else if (TR->isVoidType() && !TR.hasQualifiers()) + kind = (kind == Cl::CL_LValue ? Cl::CL_AddressableVoid : Cl::CL_Void); } // Enable this assertion for testing. @@ -71,10 +73,12 @@ Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const { case Cl::CL_XValue: assert(getValueKind() == VK_XValue); break; case Cl::CL_Function: case Cl::CL_Void: + case Cl::CL_AddressableVoid: case Cl::CL_DuplicateVectorComponents: case Cl::CL_MemberFunction: case Cl::CL_SubObjCPropertySetting: case Cl::CL_ClassTemporary: + case Cl::CL_ObjCMessageRValue: case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break; } @@ -128,7 +132,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // Expressions that are prvalues. case Expr::CXXBoolLiteralExprClass: case Expr::CXXPseudoDestructorExprClass: - case Expr::SizeOfAlignOfExprClass: + case Expr::UnaryExprOrTypeTraitExprClass: case Expr::CXXNewExprClass: case Expr::CXXThisExprClass: case Expr::CXXNullPtrLiteralExprClass: @@ -148,6 +152,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXScalarValueInitExprClass: case Expr::UnaryTypeTraitExprClass: case Expr::BinaryTypeTraitExprClass: + case Expr::ArrayTypeTraitExprClass: + case Expr::ExpressionTraitExprClass: case Expr::ObjCSelectorExprClass: case Expr::ObjCProtocolExprClass: case Expr::ObjCStringLiteralClass: @@ -169,6 +175,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // C++ [expr.prim.general]p3: The result is an lvalue if the entity is a // function or variable and a prvalue otherwise. case Expr::DeclRefExprClass: + if (E->getType() == Ctx.UnknownAnyTy) + return isa<FunctionDecl>(cast<DeclRefExpr>(E)->getDecl()) + ? Cl::CL_PRValue : Cl::CL_LValue; return ClassifyDecl(Ctx, cast<DeclRefExpr>(E)->getDecl()); // We deal with names referenced from blocks the same way. case Expr::BlockDeclRefExprClass: @@ -229,6 +238,14 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::ParenExprClass: return ClassifyInternal(Ctx, cast<ParenExpr>(E)->getSubExpr()); + // C1X 6.5.1.1p4: [A generic selection] is an lvalue, a function designator, + // or a void expression if its result expression is, respectively, an + // lvalue, a function designator, or a void expression. + case Expr::GenericSelectionExprClass: + if (cast<GenericSelectionExpr>(E)->isResultDependent()) + return Cl::CL_PRValue; + return ClassifyInternal(Ctx,cast<GenericSelectionExpr>(E)->getResultExpr()); + case Expr::BinaryOperatorClass: case Expr::CompoundAssignOperatorClass: // C doesn't have any binary expressions that are lvalues. @@ -293,7 +310,8 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::ObjCMessageExprClass: if (const ObjCMethodDecl *Method = cast<ObjCMessageExpr>(E)->getMethodDecl()) { - return ClassifyUnnamed(Ctx, Method->getResultType()); + Cl::Kinds kind = ClassifyUnnamed(Ctx, Method->getResultType()); + return (kind == Cl::CL_PRValue) ? Cl::CL_ObjCMessageRValue : kind; } return Cl::CL_PRValue; @@ -373,6 +391,10 @@ static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T) { } static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) { + if (E->getType() == Ctx.UnknownAnyTy) + return (isa<FunctionDecl>(E->getMemberDecl()) + ? Cl::CL_PRValue : Cl::CL_LValue); + // Handle C first, it's easier. if (!Ctx.getLangOptions().CPlusPlus) { // C99 6.5.2.3p3 @@ -546,11 +568,13 @@ Expr::LValueClassification Expr::ClassifyLValue(ASTContext &Ctx) const { case Cl::CL_LValue: return LV_Valid; case Cl::CL_XValue: return LV_InvalidExpression; case Cl::CL_Function: return LV_NotObjectType; - case Cl::CL_Void: return LV_IncompleteVoidType; + case Cl::CL_Void: return LV_InvalidExpression; + case Cl::CL_AddressableVoid: return LV_IncompleteVoidType; case Cl::CL_DuplicateVectorComponents: return LV_DuplicateVectorComponents; case Cl::CL_MemberFunction: return LV_MemberFunction; case Cl::CL_SubObjCPropertySetting: return LV_SubObjCPropertySetting; case Cl::CL_ClassTemporary: return LV_ClassTemporary; + case Cl::CL_ObjCMessageRValue: return LV_InvalidMessageExpression; case Cl::CL_PRValue: return LV_InvalidExpression; } llvm_unreachable("Unhandled kind"); @@ -564,11 +588,13 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { case Cl::CL_LValue: break; case Cl::CL_XValue: return MLV_InvalidExpression; case Cl::CL_Function: return MLV_NotObjectType; - case Cl::CL_Void: return MLV_IncompleteVoidType; + case Cl::CL_Void: return MLV_InvalidExpression; + case Cl::CL_AddressableVoid: return MLV_IncompleteVoidType; case Cl::CL_DuplicateVectorComponents: return MLV_DuplicateVectorComponents; case Cl::CL_MemberFunction: return MLV_MemberFunction; case Cl::CL_SubObjCPropertySetting: return MLV_SubObjCPropertySetting; case Cl::CL_ClassTemporary: return MLV_ClassTemporary; + case Cl::CL_ObjCMessageRValue: return MLV_InvalidMessageExpression; case Cl::CL_PRValue: return VC.getModifiable() == Cl::CM_LValueCast ? MLV_LValueCast : MLV_InvalidExpression; diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 3a5eb66ea18f..c2caf8d40b16 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -42,25 +42,25 @@ using llvm::APFloat; /// rules. For example, the RHS of (0 && foo()) is not evaluated. We can /// evaluate the expression regardless of what the RHS is, but C only allows /// certain things in certain situations. -struct EvalInfo { - const ASTContext &Ctx; - - /// EvalResult - Contains information about the evaluation. - Expr::EvalResult &EvalResult; - - llvm::DenseMap<const OpaqueValueExpr*, APValue> OpaqueValues; - const APValue *getOpaqueValue(const OpaqueValueExpr *e) { - llvm::DenseMap<const OpaqueValueExpr*, APValue>::iterator - i = OpaqueValues.find(e); - if (i == OpaqueValues.end()) return 0; - return &i->second; - } +namespace { + struct EvalInfo { + const ASTContext &Ctx; + + /// EvalResult - Contains information about the evaluation. + Expr::EvalResult &EvalResult; + + typedef llvm::DenseMap<const OpaqueValueExpr*, APValue> MapTy; + MapTy OpaqueValues; + const APValue *getOpaqueValue(const OpaqueValueExpr *e) const { + MapTy::const_iterator i = OpaqueValues.find(e); + if (i == OpaqueValues.end()) return 0; + return &i->second; + } - EvalInfo(const ASTContext &ctx, Expr::EvalResult& evalresult) - : Ctx(ctx), EvalResult(evalresult) {} -}; + EvalInfo(const ASTContext &ctx, Expr::EvalResult &evalresult) + : Ctx(ctx), EvalResult(evalresult) {} + }; -namespace { struct ComplexValue { private: bool IsInt; @@ -175,7 +175,7 @@ static bool EvalPointerValueAsBool(LValue& Value, bool& Result) { const ValueDecl* Decl = DeclRef->getDecl(); if (Decl->hasAttr<WeakAttr>() || Decl->hasAttr<WeakRefAttr>() || - Decl->hasAttr<WeakImportAttr>()) + Decl->isWeakImported()) return false; return true; @@ -274,6 +274,9 @@ public: } bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { + return Visit(E->getResultExpr()); + } bool VisitDeclRefExpr(DeclRefExpr *E) { if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) return true; @@ -290,7 +293,8 @@ public: bool VisitFloatingLiteral(FloatingLiteral *E) { return false; } bool VisitStringLiteral(StringLiteral *E) { return false; } bool VisitCharacterLiteral(CharacterLiteral *E) { return false; } - bool VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return false; } + bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) + { return false; } bool VisitArraySubscriptExpr(ArraySubscriptExpr *E) { return Visit(E->getLHS()) || Visit(E->getRHS()); } bool VisitChooseExpr(ChooseExpr *E) @@ -315,6 +319,8 @@ public: bool VisitInitListExpr(InitListExpr *E) { for (unsigned i = 0, e = E->getNumInits(); i != e; ++i) if (Visit(E->getInit(i))) return true; + if (Expr *filler = E->getArrayFiller()) + return Visit(filler); return false; } @@ -371,6 +377,9 @@ public: } bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { + return Visit(E->getResultExpr()); + } bool VisitDeclRefExpr(DeclRefExpr *E); bool VisitPredefinedExpr(PredefinedExpr *E) { return Success(E); } bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E); @@ -500,6 +509,9 @@ public: } bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { + return Visit(E->getResultExpr()); + } bool VisitBinaryOperator(const BinaryOperator *E); bool VisitCastExpr(CastExpr* E); @@ -589,7 +601,6 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) { case CK_NoOp: case CK_BitCast: - case CK_LValueBitCast: case CK_AnyPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: return Visit(SubExpr); @@ -717,6 +728,8 @@ namespace { APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + APValue VisitGenericSelectionExpr(GenericSelectionExpr *E) + { return Visit(E->getResultExpr()); } APValue VisitUnaryExtension(const UnaryOperator *E) { return Visit(E->getSubExpr()); } APValue VisitUnaryPlus(const UnaryOperator *E) @@ -755,68 +768,61 @@ APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { const Expr* SE = E->getSubExpr(); QualType SETy = SE->getType(); - APValue Result = APValue(); - - // Check for vector->vector bitcast and scalar->vector splat. - if (SETy->isVectorType()) { - return this->Visit(const_cast<Expr*>(SE)); - } else if (SETy->isIntegerType()) { - APSInt IntResult; - if (!EvaluateInteger(SE, IntResult, Info)) - return APValue(); - Result = APValue(IntResult); - } else if (SETy->isRealFloatingType()) { - APFloat F(0.0); - if (!EvaluateFloat(SE, F, Info)) - return APValue(); - Result = APValue(F); - } else - return APValue(); - // For casts of a scalar to ExtVector, convert the scalar to the element type - // and splat it to all elements. - if (E->getType()->isExtVectorType()) { - if (EltTy->isIntegerType() && Result.isInt()) - Result = APValue(HandleIntToIntCast(EltTy, SETy, Result.getInt(), - Info.Ctx)); - else if (EltTy->isIntegerType()) - Result = APValue(HandleFloatToIntCast(EltTy, SETy, Result.getFloat(), - Info.Ctx)); - else if (EltTy->isRealFloatingType() && Result.isInt()) - Result = APValue(HandleIntToFloatCast(EltTy, SETy, Result.getInt(), - Info.Ctx)); - else if (EltTy->isRealFloatingType()) - Result = APValue(HandleFloatToFloatCast(EltTy, SETy, Result.getFloat(), - Info.Ctx)); - else + switch (E->getCastKind()) { + case CK_VectorSplat: { + APValue Result = APValue(); + if (SETy->isIntegerType()) { + APSInt IntResult; + if (!EvaluateInteger(SE, IntResult, Info)) + return APValue(); + Result = APValue(IntResult); + } else if (SETy->isRealFloatingType()) { + APFloat F(0.0); + if (!EvaluateFloat(SE, F, Info)) + return APValue(); + Result = APValue(F); + } else { return APValue(); + } // Splat and create vector APValue. llvm::SmallVector<APValue, 4> Elts(NElts, Result); return APValue(&Elts[0], Elts.size()); } + case CK_BitCast: { + if (SETy->isVectorType()) + return Visit(const_cast<Expr*>(SE)); - // For casts of a scalar to regular gcc-style vector type, bitcast the scalar - // to the vector. To construct the APValue vector initializer, bitcast the - // initializing value to an APInt, and shift out the bits pertaining to each - // element. - APSInt Init; - Init = Result.isInt() ? Result.getInt() : Result.getFloat().bitcastToAPInt(); - - llvm::SmallVector<APValue, 4> Elts; - for (unsigned i = 0; i != NElts; ++i) { - APSInt Tmp = Init.extOrTrunc(EltWidth); + if (!SETy->isIntegerType()) + return APValue(); - if (EltTy->isIntegerType()) - Elts.push_back(APValue(Tmp)); - else if (EltTy->isRealFloatingType()) - Elts.push_back(APValue(APFloat(Tmp))); - else + APSInt Init; + if (!EvaluateInteger(SE, Init, Info)) return APValue(); - Init >>= EltWidth; + assert((EltTy->isIntegerType() || EltTy->isRealFloatingType()) && + "Vectors must be composed of ints or floats"); + + llvm::SmallVector<APValue, 4> Elts; + for (unsigned i = 0; i != NElts; ++i) { + APSInt Tmp = Init.extOrTrunc(EltWidth); + + if (EltTy->isIntegerType()) + Elts.push_back(APValue(Tmp)); + else + Elts.push_back(APValue(APFloat(Tmp))); + + Init >>= EltWidth; + } + return APValue(&Elts[0], Elts.size()); + } + case CK_LValueToRValue: + case CK_NoOp: + return Visit(const_cast<Expr*>(SE)); + default: + return APValue(); } - return APValue(&Elts[0], Elts.size()); } APValue @@ -837,6 +843,12 @@ VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { // becomes every element of the vector, not just the first. // This is the behavior described in the IBM AltiVec documentation. if (NumInits == 1) { + + // Handle the case where the vector is initialized by a another + // vector (OpenCL 6.1.6). + if (E->getInit(0)->getType()->isVectorType()) + return this->Visit(const_cast<Expr*>(E->getInit(0))); + APValue InitValue; if (EltTy->isIntegerType()) { llvm::APSInt sInt(32); @@ -953,6 +965,11 @@ public: return true; } + bool Success(CharUnits Size, const Expr *E) { + return Success(Size.getQuantity(), E); + } + + bool Error(SourceLocation L, diag::kind D, const Expr *E) { // Take the first error. if (Info.EvalResult.Diag == 0) { @@ -977,6 +994,9 @@ public: } bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { + return Visit(E->getResultExpr()); + } bool VisitIntegerLiteral(const IntegerLiteral *E) { return Success(E->getValue(), E); @@ -1015,7 +1035,7 @@ public: bool VisitBinaryConditionalOperator(const BinaryConditionalOperator *E); bool VisitCastExpr(CastExpr* E); - bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); + bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return Success(E->getValue(), E); @@ -1041,6 +1061,14 @@ public: return Success(E->getValue(), E); } + bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) { + return Success(E->getValue(), E); + } + + bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E) { + return Success(E->getValue(), E); + } + bool VisitChooseExpr(const ChooseExpr *E) { return Visit(E->getChosenSubExpr(Info.Ctx)); } @@ -1213,7 +1241,7 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(CallExpr *E) { Size -= Offset; else Size = CharUnits::Zero(); - return Success(Size.getQuantity(), E); + return Success(Size, E); } bool IntExprEvaluator::VisitCallExpr(CallExpr *E) { @@ -1596,36 +1624,59 @@ CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) { } -/// VisitSizeAlignOfExpr - Evaluate a sizeof or alignof with a result as the -/// expression's type. -bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { - // Handle alignof separately. - if (!E->isSizeOf()) { +/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with +/// a result as the expression's type. +bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( + const UnaryExprOrTypeTraitExpr *E) { + switch(E->getKind()) { + case UETT_AlignOf: { if (E->isArgumentType()) - return Success(GetAlignOfType(E->getArgumentType()).getQuantity(), E); + return Success(GetAlignOfType(E->getArgumentType()), E); else - return Success(GetAlignOfExpr(E->getArgumentExpr()).getQuantity(), E); + return Success(GetAlignOfExpr(E->getArgumentExpr()), E); } - QualType SrcTy = E->getTypeOfArgument(); - // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, - // the result is the size of the referenced type." - // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the - // result shall be the alignment of the referenced type." - if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>()) - SrcTy = Ref->getPointeeType(); + case UETT_VecStep: { + QualType Ty = E->getTypeOfArgument(); - // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc - // extension. - if (SrcTy->isVoidType() || SrcTy->isFunctionType()) - return Success(1, E); + if (Ty->isVectorType()) { + unsigned n = Ty->getAs<VectorType>()->getNumElements(); - // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. - if (!SrcTy->isConstantSizeType()) - return false; + // The vec_step built-in functions that take a 3-component + // vector return 4. (OpenCL 1.1 spec 6.11.12) + if (n == 3) + n = 4; + + return Success(n, E); + } else + return Success(1, E); + } + + case UETT_SizeOf: { + QualType SrcTy = E->getTypeOfArgument(); + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>()) + SrcTy = Ref->getPointeeType(); + + // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc + // extension. + if (SrcTy->isVoidType() || SrcTy->isFunctionType()) + return Success(1, E); + + // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. + if (!SrcTy->isConstantSizeType()) + return false; + + // Get information about the size. + return Success(Info.Ctx.getTypeSizeInChars(SrcTy), E); + } + } - // Get information about the size. - return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E); + llvm_unreachable("unknown expr/type trait"); + return false; } bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { @@ -1694,7 +1745,7 @@ bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *E) { } } } - return Success(Result.getQuantity(), E); + return Success(Result, E); } bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { @@ -1742,15 +1793,60 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { QualType DestType = E->getType(); QualType SrcType = SubExpr->getType(); - if (DestType->isBooleanType()) { + switch (E->getCastKind()) { + case CK_BaseToDerived: + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_Dynamic: + case CK_ToUnion: + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + case CK_NullToPointer: + case CK_NullToMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_ConstructorConversion: + case CK_IntegralToPointer: + case CK_ToVoid: + case CK_VectorSplat: + case CK_IntegralToFloating: + case CK_FloatingCast: + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_ObjCObjectLValueCast: + case CK_FloatingRealToComplex: + case CK_FloatingComplexToReal: + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralRealToComplex: + case CK_IntegralComplexCast: + case CK_IntegralComplexToFloatingComplex: + llvm_unreachable("invalid cast kind for integral value"); + + case CK_BitCast: + case CK_Dependent: + case CK_GetObjCProperty: + case CK_LValueBitCast: + case CK_UserDefinedConversion: + return false; + + case CK_LValueToRValue: + case CK_NoOp: + return Visit(E->getSubExpr()); + + case CK_MemberPointerToBoolean: + case CK_PointerToBoolean: + case CK_IntegralToBoolean: + case CK_FloatingToBoolean: + case CK_FloatingComplexToBoolean: + case CK_IntegralComplexToBoolean: { bool BoolResult; if (!HandleConversionToBool(SubExpr, BoolResult, Info)) return false; return Success(BoolResult, E); } - // Handle simple integer->integer casts. - if (SrcType->isIntegralOrEnumerationType()) { + case CK_IntegralCast: { if (!Visit(SubExpr)) return false; @@ -1763,8 +1859,7 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { Result.getInt(), Info.Ctx), E); } - // FIXME: Clean this up! - if (SrcType->isPointerType()) { + case CK_PointerToIntegral: { LValue LV; if (!EvaluatePointer(SubExpr, LV, Info)) return false; @@ -1783,42 +1878,24 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E); } - if (SrcType->isArrayType() || SrcType->isFunctionType()) { - // This handles double-conversion cases, where there's both - // an l-value promotion and an implicit conversion to int. - LValue LV; - if (!EvaluateLValue(SubExpr, LV, Info)) - return false; - - if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(Info.Ctx.VoidPtrTy)) - return false; - - LV.moveInto(Result); - return true; - } - - if (SrcType->isAnyComplexType()) { + case CK_IntegralComplexToReal: { ComplexValue C; if (!EvaluateComplex(SubExpr, C, Info)) return false; - if (C.isComplexFloat()) - return Success(HandleFloatToIntCast(DestType, SrcType, - C.getComplexFloatReal(), Info.Ctx), - E); - else - return Success(HandleIntToIntCast(DestType, SrcType, - C.getComplexIntReal(), Info.Ctx), E); + return Success(C.getComplexIntReal(), E); } - // FIXME: Handle vectors - if (!SrcType->isRealFloatingType()) - return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E); + case CK_FloatingToIntegral: { + APFloat F(0.0); + if (!EvaluateFloat(SubExpr, F, Info)) + return false; - APFloat F(0.0); - if (!EvaluateFloat(SubExpr, F, Info)) - return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E); + return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E); + } + } - return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E); + llvm_unreachable("unknown cast resulting in integral value"); + return false; } bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { @@ -1871,6 +1948,9 @@ public: } bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { + return Visit(E->getResultExpr()); + } bool VisitCallExpr(const CallExpr *E); bool VisitUnaryOperator(const UnaryOperator *E); @@ -2119,7 +2199,15 @@ bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) { bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) { Expr* SubExpr = E->getSubExpr(); - if (SubExpr->getType()->isIntegralOrEnumerationType()) { + switch (E->getCastKind()) { + default: + return false; + + case CK_LValueToRValue: + case CK_NoOp: + return Visit(SubExpr); + + case CK_IntegralToFloating: { APSInt IntResult; if (!EvaluateInteger(SubExpr, IntResult, Info)) return false; @@ -2127,7 +2215,8 @@ bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) { IntResult, Info.Ctx); return true; } - if (SubExpr->getType()->isRealFloatingType()) { + + case CK_FloatingCast: { if (!Visit(SubExpr)) return false; Result = HandleFloatToFloatCast(E->getType(), SubExpr->getType(), @@ -2135,13 +2224,14 @@ bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) { return true; } - if (E->getCastKind() == CK_FloatingComplexToReal) { + case CK_FloatingComplexToReal: { ComplexValue V; if (!EvaluateComplex(SubExpr, V, Info)) return false; Result = V.getComplexFloatReal(); return true; } + } return false; } @@ -2194,6 +2284,9 @@ public: } bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitGenericSelectionExpr(GenericSelectionExpr *E) { + return Visit(E->getResultExpr()); + } bool VisitImaginaryLiteral(ImaginaryLiteral *E); @@ -2253,7 +2346,6 @@ bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) { switch (E->getCastKind()) { case CK_BitCast: - case CK_LValueBitCast: case CK_BaseToDerived: case CK_DerivedToBase: case CK_UncheckedDerivedToBase: @@ -2293,6 +2385,7 @@ bool ComplexExprEvaluator::VisitCastExpr(CastExpr *E) { case CK_Dependent: case CK_GetObjCProperty: + case CK_LValueBitCast: case CK_UserDefinedConversion: return false; @@ -2782,12 +2875,16 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::ParenExprClass: return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx); + case Expr::GenericSelectionExprClass: + return CheckICE(cast<GenericSelectionExpr>(E)->getResultExpr(), Ctx); case Expr::IntegerLiteralClass: case Expr::CharacterLiteralClass: case Expr::CXXBoolLiteralExprClass: case Expr::CXXScalarValueInitExprClass: case Expr::UnaryTypeTraitExprClass: case Expr::BinaryTypeTraitExprClass: + case Expr::ArrayTypeTraitExprClass: + case Expr::ExpressionTraitExprClass: case Expr::CXXNoexceptExprClass: return NoDiag(); case Expr::CallExprClass: @@ -2879,9 +2976,10 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { // are ICEs, the value of the offsetof must be an integer constant. return CheckEvalInICE(E, Ctx); } - case Expr::SizeOfAlignOfExprClass: { - const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E); - if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType()) + case Expr::UnaryExprOrTypeTraitExprClass: { + const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E); + if ((Exp->getKind() == UETT_SizeOf) && + Exp->getTypeOfArgument()->isVariableArrayType()) return ICEDiag(2, E->getLocStart()); return NoDiag(); } diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp new file mode 100644 index 000000000000..89bf56db1af7 --- /dev/null +++ b/lib/AST/ExternalASTSource.cpp @@ -0,0 +1,59 @@ +//===- ExternalASTSource.cpp - Abstract External AST Interface --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the default implementation of the ExternalASTSource +// interface, which enables construction of AST nodes from some external +// source. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/DeclarationName.h" + +using namespace clang; + +ExternalASTSource::~ExternalASTSource() { } + +void ExternalASTSource::PrintStats() { } + +Decl *ExternalASTSource::GetExternalDecl(uint32_t ID) { + return 0; +} + +Selector ExternalASTSource::GetExternalSelector(uint32_t ID) { + return Selector(); +} + +uint32_t ExternalASTSource::GetNumExternalSelectors() { + return 0; +} + +Stmt *ExternalASTSource::GetExternalDeclStmt(uint64_t Offset) { + return 0; +} + +CXXBaseSpecifier * +ExternalASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) { + return 0; +} + +DeclContextLookupResult +ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name) { + return DeclContext::lookup_result(); +} + +void ExternalASTSource::MaterializeVisibleDecls(const DeclContext *DC) { } + +bool +ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + llvm::SmallVectorImpl<Decl*> &Result) { + return true; +} diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp index 533a2329c583..c47a9dadbadd 100644 --- a/lib/AST/InheritViz.cpp +++ b/lib/AST/InheritViz.cpp @@ -17,7 +17,6 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/TypeOrdering.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/raw_ostream.h" #include <map> @@ -136,28 +135,34 @@ InheritanceHierarchyWriter::WriteNodeReference(QualType Type, /// class using GraphViz. void CXXRecordDecl::viewInheritance(ASTContext& Context) const { QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this)); - // Create temp directory - SmallString<128> Filename; - int FileFD = 0; - if (error_code ec = sys::fs::unique_file( - "clang-class-inheritance-hierarchy-%%-%%-%%-%%-" + - Self.getAsString() + ".dot", - FileFD, Filename)) { - errs() << "Error creating temporary output file: " << ec.message() << '\n'; + std::string ErrMsg; + sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg); + if (Filename.isEmpty()) { + llvm::errs() << "Error: " << ErrMsg << "\n"; + return; + } + Filename.appendComponent(Self.getAsString() + ".dot"); + if (Filename.makeUnique(true,&ErrMsg)) { + llvm::errs() << "Error: " << ErrMsg << "\n"; return; } - llvm::errs() << "Writing '" << Filename << "'... "; + llvm::errs() << "Writing '" << Filename.c_str() << "'... "; - llvm::raw_fd_ostream O(FileFD, true); - InheritanceHierarchyWriter Writer(Context, O); - Writer.WriteGraph(Self); + llvm::raw_fd_ostream O(Filename.c_str(), ErrMsg); - llvm::errs() << " done. \n"; - O.close(); + if (ErrMsg.empty()) { + InheritanceHierarchyWriter Writer(Context, O); + Writer.WriteGraph(Self); + llvm::errs() << " done. \n"; - // Display the graph - DisplayGraph(sys::Path(Filename)); + O.close(); + + // Display the graph + DisplayGraph(Filename); + } else { + llvm::errs() << "error opening file for writing!\n"; + } } } diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp index bed02b4c0010..30aece3ee73b 100644 --- a/lib/AST/ItaniumCXXABI.cpp +++ b/lib/AST/ItaniumCXXABI.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This provides C++ AST support targetting the Itanium C++ ABI, which is +// This provides C++ AST support targeting the Itanium C++ ABI, which is // documented at: // http://www.codesourcery.com/public/cxx-abi/abi.html // http://www.codesourcery.com/public/cxx-abi/abi-eh.html diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 939ca7a924aa..c460929c461d 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -21,6 +21,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" #include "clang/Basic/ABI.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -50,18 +51,16 @@ static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) { return 0; } -static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) { - assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) && - "Passed in decl is not a ctor or dtor!"); +static const FunctionDecl *getStructor(const FunctionDecl *fn) { + if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate()) + return ftd->getTemplatedDecl(); - if (const TemplateDecl *TD = MD->getPrimaryTemplate()) { - MD = cast<CXXMethodDecl>(TD->getTemplatedDecl()); - - assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) && - "Templated decl is not a ctor or dtor!"); - } + return fn; +} - return MD; +static const NamedDecl *getStructor(const NamedDecl *decl) { + const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl); + return (fn ? getStructor(fn) : decl); } static const unsigned UnknownArity = ~0U; @@ -138,27 +137,75 @@ class CXXNameMangler { ItaniumMangleContext &Context; llvm::raw_ostream &Out; - const CXXMethodDecl *Structor; + /// The "structor" is the top-level declaration being mangled, if + /// that's not a template specialization; otherwise it's the pattern + /// for that specialization. + const NamedDecl *Structor; unsigned StructorType; /// SeqID - The next subsitution sequence number. unsigned SeqID; + class FunctionTypeDepthState { + unsigned Bits; + + enum { InResultTypeMask = 1 }; + + public: + FunctionTypeDepthState() : Bits(0) {} + + /// The number of function types we're inside. + unsigned getDepth() const { + return Bits >> 1; + } + + /// True if we're in the return type of the innermost function type. + bool isInResultType() const { + return Bits & InResultTypeMask; + } + + FunctionTypeDepthState push() { + FunctionTypeDepthState tmp = *this; + Bits = (Bits & ~InResultTypeMask) + 2; + return tmp; + } + + void enterResultType() { + Bits |= InResultTypeMask; + } + + void leaveResultType() { + Bits &= ~InResultTypeMask; + } + + void pop(FunctionTypeDepthState saved) { + assert(getDepth() == saved.getDepth() + 1); + Bits = saved.Bits; + } + + } FunctionTypeDepth; + llvm::DenseMap<uintptr_t, unsigned> Substitutions; ASTContext &getASTContext() const { return Context.getASTContext(); } public: - CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_) - : Context(C), Out(Out_), Structor(0), StructorType(0), SeqID(0) { } + CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, + const NamedDecl *D = 0) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0), + SeqID(0) { + // These can't be mangled without a ctor type or dtor type. + assert(!D || (!isa<CXXDestructorDecl>(D) && + !isa<CXXConstructorDecl>(D))); + } CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, const CXXConstructorDecl *D, CXXCtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), - SeqID(0) { } + SeqID(0) { } CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), - SeqID(0) { } + SeqID(0) { } #if MANGLE_CHECKER ~CXXNameMangler() { @@ -200,11 +247,16 @@ private: void addSubstitution(TemplateName Template); void addSubstitution(uintptr_t Ptr); - void mangleUnresolvedScope(NestedNameSpecifier *Qualifier); - void mangleUnresolvedName(NestedNameSpecifier *Qualifier, - DeclarationName Name, + void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + bool recursive = false); + void mangleUnresolvedName(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName name, unsigned KnownArity = UnknownArity); + void mangleUnresolvedType(QualType type); + void mangleName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); @@ -223,6 +275,7 @@ private: void mangleNestedName(const TemplateDecl *TD, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); + void manglePrefix(NestedNameSpecifier *qualifier); void manglePrefix(const DeclContext *DC, bool NoFunction=false); void mangleTemplatePrefix(const TemplateDecl *ND); void mangleTemplatePrefix(TemplateName Template); @@ -245,10 +298,11 @@ private: void mangleNeonVectorType(const VectorType *T); void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); - void mangleMemberExpr(const Expr *Base, bool IsArrow, - NestedNameSpecifier *Qualifier, - DeclarationName Name, - unsigned KnownArity); + void mangleMemberExpr(const Expr *base, bool isArrow, + NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName name, + unsigned knownArity); void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); @@ -265,6 +319,8 @@ private: void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A); void mangleTemplateParameter(unsigned Index); + + void mangleFunctionParam(const ParmVarDecl *parm); }; } @@ -334,10 +390,11 @@ void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) { // another has a "\01foo". That is known to happen on ELF with the // tricks normally used for producing aliases (PR9177). Fortunately the // llvm mangler on ELF is a nop, so we can just avoid adding the \01 - // marker. + // marker. We also avoid adding the marker if this is an alias for an + // LLVM intrinsic. llvm::StringRef UserLabelPrefix = getASTContext().Target.getUserLabelPrefix(); - if (!UserLabelPrefix.empty()) + if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm.")) Out << '\01'; // LLVM IR Marker for __asm("foo") Out << ALA->getLabel(); @@ -552,11 +609,24 @@ void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) { addSubstitution(Template); } -void CXXNameMangler::mangleFloat(const llvm::APFloat &F) { - // TODO: avoid this copy with careful stream management. - llvm::SmallString<20> Buffer; - F.bitcastToAPInt().toString(Buffer, 16, false); - Out.write(Buffer.data(), Buffer.size()); +void CXXNameMangler::mangleFloat(const llvm::APFloat &f) { + // ABI: + // Floating-point literals are encoded using a fixed-length + // lowercase hexadecimal string corresponding to the internal + // representation (IEEE on Itanium), high-order bytes first, + // without leading zeroes. For example: "Lf bf800000 E" is -1.0f + // on Itanium. + // APInt::toString uses uppercase hexadecimal, and it's not really + // worth embellishing that interface for this use case, so we just + // do a second pass to lowercase things. + typedef llvm::SmallString<20> buffer_t; + buffer_t buffer; + f.bitcastToAPInt().toString(buffer, 16, false); + + for (buffer_t::iterator i = buffer.begin(), e = buffer.end(); i != e; ++i) + if (isupper(*i)) *i = tolower(*i); + + Out.write(buffer.data(), buffer.size()); } void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) { @@ -597,59 +667,162 @@ void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) { Out << '_'; } -void CXXNameMangler::mangleUnresolvedScope(NestedNameSpecifier *Qualifier) { - Qualifier = getASTContext().getCanonicalNestedNameSpecifier(Qualifier); - switch (Qualifier->getKind()) { +void CXXNameMangler::mangleUnresolvedType(QualType type) { + if (const TemplateSpecializationType *TST = + type->getAs<TemplateSpecializationType>()) { + if (!mangleSubstitution(QualType(TST, 0))) { + mangleTemplatePrefix(TST->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), + TST->getNumArgs()); + addSubstitution(QualType(TST, 0)); + } + } else if (const DependentTemplateSpecializationType *DTST + = type->getAs<DependentTemplateSpecializationType>()) { + TemplateName Template + = getASTContext().getDependentTemplateName(DTST->getQualifier(), + DTST->getIdentifier()); + mangleTemplatePrefix(Template); + + // 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()); + } else { + // We use the QualType mangle type variant here because it handles + // substitutions. + mangleType(type); + } +} + +/// Mangle everything prior to the base-unresolved-name in an unresolved-name. +/// +/// \param firstQualifierLookup - the entity found by unqualified lookup +/// for the first name in the qualifier, if this is for a member expression +/// \param recursive - true if this is being called recursively, +/// i.e. if there is more prefix "to the right". +void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + bool recursive) { + + // x, ::x + // <unresolved-name> ::= [gs] <base-unresolved-name> + + // T::x / decltype(p)::x + // <unresolved-name> ::= sr <unresolved-type> <base-unresolved-name> + + // T::N::x /decltype(p)::N::x + // <unresolved-name> ::= srN <unresolved-type> <unresolved-qualifier-level>+ E + // <base-unresolved-name> + + // A::x, N::y, A<T>::z; "gs" means leading "::" + // <unresolved-name> ::= [gs] sr <unresolved-qualifier-level>+ E + // <base-unresolved-name> + + switch (qualifier->getKind()) { case NestedNameSpecifier::Global: - // nothing - break; + Out << "gs"; + + // We want an 'sr' unless this is the entire NNS. + if (recursive) + Out << "sr"; + + // We never want an 'E' here. + return; + case NestedNameSpecifier::Namespace: - mangleName(Qualifier->getAsNamespace()); + if (qualifier->getPrefix()) + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + else + Out << "sr"; + mangleSourceName(qualifier->getAsNamespace()->getIdentifier()); break; case NestedNameSpecifier::NamespaceAlias: - mangleName(Qualifier->getAsNamespaceAlias()->getNamespace()); + if (qualifier->getPrefix()) + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + else + Out << "sr"; + mangleSourceName(qualifier->getAsNamespaceAlias()->getIdentifier()); break; + case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { - const Type *QTy = Qualifier->getAsType(); + // Both cases want this. + Out << "sr"; - if (const TemplateSpecializationType *TST = - dyn_cast<TemplateSpecializationType>(QTy)) { - if (!mangleSubstitution(QualType(TST, 0))) { - mangleTemplatePrefix(TST->getTemplateName()); - - // FIXME: GCC does not appear to mangle the template arguments when - // the template in question is a dependent template name. Should we - // emulate that badness? - mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), - TST->getNumArgs()); - addSubstitution(QualType(TST, 0)); - } - } else { - // We use the QualType mangle type variant here because it handles - // substitutions. - mangleType(QualType(QTy, 0)); - } + // We only get here recursively if we're followed by identifiers. + if (recursive) Out << 'N'; + + mangleUnresolvedType(QualType(qualifier->getAsType(), 0)); + + // We never want to print 'E' directly after an unresolved-type, + // so we return directly. + return; } - break; + case NestedNameSpecifier::Identifier: // Member expressions can have these without prefixes. - if (Qualifier->getPrefix()) - mangleUnresolvedScope(Qualifier->getPrefix()); - mangleSourceName(Qualifier->getAsIdentifier()); + if (qualifier->getPrefix()) { + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + } else if (firstQualifierLookup) { + + // Try to make a proper qualifier out of the lookup result, and + // then just recurse on that. + NestedNameSpecifier *newQualifier; + if (TypeDecl *typeDecl = dyn_cast<TypeDecl>(firstQualifierLookup)) { + QualType type = getASTContext().getTypeDeclType(typeDecl); + + // Pretend we had a different nested name specifier. + newQualifier = NestedNameSpecifier::Create(getASTContext(), + /*prefix*/ 0, + /*template*/ false, + type.getTypePtr()); + } else if (NamespaceDecl *nspace = + dyn_cast<NamespaceDecl>(firstQualifierLookup)) { + newQualifier = NestedNameSpecifier::Create(getASTContext(), + /*prefix*/ 0, + nspace); + } else if (NamespaceAliasDecl *alias = + dyn_cast<NamespaceAliasDecl>(firstQualifierLookup)) { + newQualifier = NestedNameSpecifier::Create(getASTContext(), + /*prefix*/ 0, + alias); + } else { + // No sensible mangling to do here. + newQualifier = 0; + } + + if (newQualifier) + return mangleUnresolvedPrefix(newQualifier, /*lookup*/ 0, recursive); + + } else { + Out << "sr"; + } + + mangleSourceName(qualifier->getAsIdentifier()); break; } -} -/// Mangles a name which was not resolved to a specific entity. -void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *Qualifier, - DeclarationName Name, - unsigned KnownArity) { - if (Qualifier) - mangleUnresolvedScope(Qualifier); - // FIXME: ambiguity of unqualified lookup with :: + // If this was the innermost part of the NNS, and we fell out to + // here, append an 'E'. + if (!recursive) + Out << 'E'; +} - mangleUnqualifiedName(0, Name, KnownArity); +/// Mangle an unresolved-name, which is generally used for names which +/// weren't resolved to specific entities. +void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName name, + unsigned knownArity) { + if (qualifier) mangleUnresolvedPrefix(qualifier, firstQualifierLookup); + mangleUnqualifiedName(0, name, knownArity); } static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) { @@ -684,10 +857,12 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, case DeclarationName::Identifier: { if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { // We must avoid conflicts between internally- and externally- - // linked variable declaration names in the same TU. - // This naming convention is the same as that followed by GCC, though it - // shouldn't actually matter. - if (ND && isa<VarDecl>(ND) && ND->getLinkage() == InternalLinkage && + // linked variable and function declaration names in the same TU: + // void test() { extern void foo(); } + // static void foo(); + // This naming convention is the same as that followed by GCC, + // though it shouldn't actually matter. + if (ND && ND->getLinkage() == InternalLinkage && ND->getDeclContext()->isFileContext()) Out << 'L'; @@ -734,7 +909,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // We must have an anonymous struct. const TagDecl *TD = cast<TagDecl>(ND); - if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) { + if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { assert(TD->getDeclContext() == D->getDeclContext() && "Typedef should not be in another decl context!"); assert(D->getDeclName().getAsIdentifierInfo() && @@ -906,6 +1081,38 @@ void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { mangleUnqualifiedName(ND); } +void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { + switch (qualifier->getKind()) { + case NestedNameSpecifier::Global: + // nothing + return; + + case NestedNameSpecifier::Namespace: + mangleName(qualifier->getAsNamespace()); + return; + + case NestedNameSpecifier::NamespaceAlias: + mangleName(qualifier->getAsNamespaceAlias()->getNamespace()); + return; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + mangleUnresolvedType(QualType(qualifier->getAsType(), 0)); + return; + + case NestedNameSpecifier::Identifier: + // Member expressions can have these without prefixes, but that + // should end up in mangleUnresolvedPrefix instead. + assert(qualifier->getPrefix()); + manglePrefix(qualifier->getPrefix()); + + mangleSourceName(qualifier->getAsIdentifier()); + return; + } + + llvm_unreachable("unexpected nested name specifier"); +} + void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { // <prefix> ::= <prefix> <unqualified-name> // ::= <template-prefix> <template-args> @@ -959,7 +1166,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { return mangleTemplatePrefix(TD); if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName()) - mangleUnresolvedScope(Qualified->getQualifier()); + manglePrefix(Qualified->getQualifier()); if (OverloadedTemplateStorage *Overloaded = Template.getAsOverloadedTemplate()) { @@ -970,7 +1177,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); assert(Dependent && "Unknown template name kind?"); - mangleUnresolvedScope(Dependent->getQualifier()); + manglePrefix(Dependent->getQualifier()); mangleUnscopedTemplateName(Template); } @@ -1033,7 +1240,7 @@ void CXXNameMangler::mangleType(TemplateName TN) { // <class-enum-type> ::= <name> // <name> ::= <nested-name> - mangleUnresolvedScope(Dependent->getQualifier()); + mangleUnresolvedPrefix(Dependent->getQualifier(), 0); mangleSourceName(Dependent->getIdentifier()); break; } @@ -1313,8 +1520,9 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Overload: case BuiltinType::Dependent: - assert(false && - "Overloaded and dependent types shouldn't get to name mangling"); + case BuiltinType::BoundMember: + case BuiltinType::UnknownAny: + llvm_unreachable("mangling a placeholder type"); break; case BuiltinType::ObjCId: Out << "11objc_object"; break; case BuiltinType::ObjCClass: Out << "10objc_class"; break; @@ -1339,13 +1547,22 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, // We should never be mangling something without a prototype. const FunctionProtoType *Proto = cast<FunctionProtoType>(T); + // Record that we're in a function type. See mangleFunctionParam + // for details on what we're trying to achieve here. + FunctionTypeDepthState saved = FunctionTypeDepth.push(); + // <bare-function-type> ::= <signature type>+ - if (MangleReturnType) + if (MangleReturnType) { + FunctionTypeDepth.enterResultType(); mangleType(Proto->getResultType()); + FunctionTypeDepth.leaveResultType(); + } if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { // <builtin-type> ::= v # void Out << 'v'; + + FunctionTypeDepth.pop(saved); return; } @@ -1354,6 +1571,8 @@ void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, Arg != ArgEnd; ++Arg) mangleType(*Arg); + FunctionTypeDepth.pop(saved); + // <builtin-type> ::= z # ellipsis if (Proto->isVariadic()) Out << 'z'; @@ -1590,13 +1809,13 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { void CXXNameMangler::mangleType(const DependentNameType *T) { // Typename types are always nested Out << 'N'; - mangleUnresolvedScope(T->getQualifier()); + manglePrefix(T->getQualifier()); mangleSourceName(T->getIdentifier()); Out << 'E'; } void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) { - // Dependently-scoped template types are always nested + // Dependently-scoped template types are nested if they have a prefix. Out << 'N'; // TODO: avoid making this TemplateName. @@ -1676,23 +1895,54 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T, /// Mangles a member expression. Implicit accesses are not handled, /// but that should be okay, because you shouldn't be able to /// make an implicit access in a function template declaration. -void CXXNameMangler::mangleMemberExpr(const Expr *Base, - bool IsArrow, - NestedNameSpecifier *Qualifier, - DeclarationName Member, - unsigned Arity) { - // gcc-4.4 uses 'dt' for dot expressions, which is reasonable. - // OTOH, gcc also mangles the name as an expression. - Out << (IsArrow ? "pt" : "dt"); - mangleExpression(Base); - mangleUnresolvedName(Qualifier, Member, Arity); +void CXXNameMangler::mangleMemberExpr(const Expr *base, + bool isArrow, + NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName member, + unsigned arity) { + // <expression> ::= dt <expression> <unresolved-name> + // ::= pt <expression> <unresolved-name> + Out << (isArrow ? "pt" : "dt"); + mangleExpression(base); + mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity); +} + +/// Look at the callee of the given call expression and determine if +/// it's a parenthesized id-expression which would have triggered ADL +/// otherwise. +static bool isParenthesizedADLCallee(const CallExpr *call) { + const Expr *callee = call->getCallee(); + const Expr *fn = callee->IgnoreParens(); + + // Must be parenthesized. IgnoreParens() skips __extension__ nodes, + // too, but for those to appear in the callee, it would have to be + // parenthesized. + if (callee == fn) return false; + + // Must be an unresolved lookup. + const UnresolvedLookupExpr *lookup = dyn_cast<UnresolvedLookupExpr>(fn); + if (!lookup) return false; + + assert(!lookup->requiresADL()); + + // Must be an unqualified lookup. + if (lookup->getQualifier()) return false; + + // Must not have found a class member. Note that if one is a class + // member, they're all class members. + if (lookup->getNumDecls() > 0 && + (*lookup->decls_begin())->isCXXClassMember()) + return false; + + // Otherwise, ADL would have been triggered. + return true; } void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { // <expression> ::= <unary operator-name> <expression> // ::= <binary operator-name> <expression> <expression> // ::= <trinary operator-name> <expression> <expression> <expression> - // ::= cl <expression>* E # call // ::= cv <type> expression # conversion with one argument // ::= cv <type> _ <expression>* E # conversion with a different number of arguments // ::= st <type> # sizeof (a type) @@ -1735,6 +1985,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::ChooseExprClass: case Expr::CompoundLiteralExprClass: case Expr::ExtVectorElementExprClass: + case Expr::GenericSelectionExprClass: case Expr::ObjCEncodeExprClass: case Expr::ObjCIsaExprClass: case Expr::ObjCIvarRefExprClass: @@ -1749,6 +2000,8 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::StmtExprClass: case Expr::UnaryTypeTraitExprClass: case Expr::BinaryTypeTraitExprClass: + case Expr::ArrayTypeTraitExprClass: + case Expr::ExpressionTraitExprClass: case Expr::VAArgExprClass: case Expr::CXXUuidofExprClass: case Expr::CXXNoexceptExprClass: @@ -1784,7 +2037,22 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::CXXMemberCallExprClass: // fallthrough case Expr::CallExprClass: { const CallExpr *CE = cast<CallExpr>(E); - Out << "cl"; + + // <expression> ::= cp <simple-id> <expression>* E + // We use this mangling only when the call would use ADL except + // for being parenthesized. Per discussion with David + // Vandervoorde, 2011.04.25. + if (isParenthesizedADLCallee(CE)) { + Out << "cp"; + // The callee here is a parenthesized UnresolvedLookupExpr with + // no qualifier and should always get mangled as a <simple-id> + // anyway. + + // <expression> ::= cl <expression>* E + } else { + Out << "cl"; + } + mangleExpression(CE->getCallee(), CE->getNumArgs()); for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I) mangleExpression(CE->getArg(I)); @@ -1815,7 +2083,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::MemberExprClass: { const MemberExpr *ME = cast<MemberExpr>(E); mangleMemberExpr(ME->getBase(), ME->isArrow(), - ME->getQualifier(), ME->getMemberDecl()->getDeclName(), + ME->getQualifier(), 0, ME->getMemberDecl()->getDeclName(), Arity); break; } @@ -1823,7 +2091,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::UnresolvedMemberExprClass: { const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E); mangleMemberExpr(ME->getBase(), ME->isArrow(), - ME->getQualifier(), ME->getMemberName(), + ME->getQualifier(), 0, ME->getMemberName(), Arity); if (ME->hasExplicitTemplateArgs()) mangleTemplateArgs(ME->getExplicitTemplateArgs()); @@ -1834,19 +2102,16 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { const CXXDependentScopeMemberExpr *ME = cast<CXXDependentScopeMemberExpr>(E); mangleMemberExpr(ME->getBase(), ME->isArrow(), - ME->getQualifier(), ME->getMember(), - Arity); + ME->getQualifier(), ME->getFirstQualifierFoundInScope(), + ME->getMember(), Arity); if (ME->hasExplicitTemplateArgs()) mangleTemplateArgs(ME->getExplicitTemplateArgs()); break; } case Expr::UnresolvedLookupExprClass: { - // The ABI doesn't cover how to mangle overload sets, so we mangle - // using something as close as possible to the original lookup - // expression. const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E); - mangleUnresolvedName(ULE->getQualifier(), ULE->getName(), Arity); + mangleUnresolvedName(ULE->getQualifier(), 0, ULE->getName(), Arity); if (ULE->hasExplicitTemplateArgs()) mangleTemplateArgs(ULE->getExplicitTemplateArgs()); break; @@ -1877,10 +2142,22 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { break; } - case Expr::SizeOfAlignOfExprClass: { - const SizeOfAlignOfExpr *SAE = cast<SizeOfAlignOfExpr>(E); - if (SAE->isSizeOf()) Out << 's'; - else Out << 'a'; + case Expr::UnaryExprOrTypeTraitExprClass: { + const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E); + switch(SAE->getKind()) { + case UETT_SizeOf: + Out << 's'; + break; + case UETT_AlignOf: + Out << 'a'; + break; + case UETT_VecStep: + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot yet mangle vec_step expression"); + Diags.Report(DiagID); + return; + } if (SAE->isArgumentType()) { Out << 't'; mangleType(SAE->getArgumentType()); @@ -1939,7 +2216,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::ArraySubscriptExprClass: { const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E); - // Array subscript is treated as a syntactically wierd form of + // Array subscript is treated as a syntactically weird form of // binary operator. Out << "ix"; mangleExpression(AE->getLHS()); @@ -2009,6 +2286,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { Out << 'E'; break; + case Decl::ParmVar: + mangleFunctionParam(cast<ParmVarDecl>(D)); + break; + case Decl::EnumConstant: { const EnumConstantDecl *ED = cast<EnumConstantDecl>(D); mangleIntegerLiteral(ED->getType(), ED->getInitVal()); @@ -2165,10 +2446,72 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { Diags.Report(DiagID); return; } + break; } } } +/// Mangle an expression which refers to a parameter variable. +/// +/// <expression> ::= <function-param> +/// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, I == 0 +/// <function-param> ::= fp <top-level CV-qualifiers> +/// <parameter-2 non-negative number> _ # L == 0, I > 0 +/// <function-param> ::= fL <L-1 non-negative number> +/// p <top-level CV-qualifiers> _ # L > 0, I == 0 +/// <function-param> ::= fL <L-1 non-negative number> +/// p <top-level CV-qualifiers> +/// <I-1 non-negative number> _ # L > 0, I > 0 +/// +/// L is the nesting depth of the parameter, defined as 1 if the +/// parameter comes from the innermost function prototype scope +/// enclosing the current context, 2 if from the next enclosing +/// function prototype scope, and so on, with one special case: if +/// we've processed the full parameter clause for the innermost +/// function type, then L is one less. This definition conveniently +/// makes it irrelevant whether a function's result type was written +/// trailing or leading, but is otherwise overly complicated; the +/// numbering was first designed without considering references to +/// parameter in locations other than return types, and then the +/// mangling had to be generalized without changing the existing +/// manglings. +/// +/// I is the zero-based index of the parameter within its parameter +/// declaration clause. Note that the original ABI document describes +/// this using 1-based ordinals. +void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) { + unsigned parmDepth = parm->getFunctionScopeDepth(); + unsigned parmIndex = parm->getFunctionScopeIndex(); + + // Compute 'L'. + // parmDepth does not include the declaring function prototype. + // FunctionTypeDepth does account for that. + assert(parmDepth < FunctionTypeDepth.getDepth()); + unsigned nestingDepth = FunctionTypeDepth.getDepth() - parmDepth; + if (FunctionTypeDepth.isInResultType()) + nestingDepth--; + + if (nestingDepth == 0) { + Out << "fp"; + } else { + Out << "fL" << (nestingDepth - 1) << 'p'; + } + + // Top-level qualifiers. We don't have to worry about arrays here, + // because parameters declared as arrays should already have been + // tranformed to have pointer type. FIXME: apparently these don't + // get mangled if used as an rvalue of a known non-class type? + assert(!parm->getType()->isArrayType() + && "parameter's type is still an array type?"); + mangleQualifiers(parm->getType().getQualifiers()); + + // Parameter index. + if (parmIndex != 0) { + Out << (parmIndex - 1); + } + Out << '_'; +} + void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { // <ctor-dtor-name> ::= C1 # complete object constructor // ::= C2 # base object constructor @@ -2287,8 +2630,7 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, // an expression. We compensate for it here to produce the correct mangling. NamedDecl *D = cast<NamedDecl>(A.getAsDecl()); const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P); - bool compensateMangling = D->isCXXClassMember() && - !Parameter->getType()->isReferenceType(); + bool compensateMangling = !Parameter->getType()->isReferenceType(); if (compensateMangling) { Out << 'X'; mangleOperatorName(OO_Amp, 1); @@ -2576,7 +2918,7 @@ void ItaniumMangleContext::mangleName(const NamedDecl *D, getASTContext().getSourceManager(), "Mangling declaration"); - CXXNameMangler Mangler(*this, Out); + CXXNameMangler Mangler(*this, Out, D); return Mangler.mangle(D); } diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index 4de93bb4beab..206f6dd0c9eb 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This provides C++ AST support targetting the Microsoft Visual C++ +// This provides C++ AST support targeting the Microsoft Visual C++ // ABI. // //===----------------------------------------------------------------------===// diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 4bf7f23a0a9d..5424bebc81b0 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This provides C++ name mangling targetting the Microsoft Visual C++ ABI. +// This provides C++ name mangling targeting the Microsoft Visual C++ ABI. // //===----------------------------------------------------------------------===// @@ -314,7 +314,7 @@ MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // We must have an anonymous struct. const TagDecl *TD = cast<TagDecl>(ND); - if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) { + if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { assert(TD->getDeclContext() == D->getDeclContext() && "Typedef should not be in another decl context!"); assert(D->getDeclName().getAsIdentifierInfo() && @@ -676,12 +676,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) { // ::= M # float // ::= N # double // ::= O # long double (__float80 is mangled differently) - // ::= _D # __int8 (yup, it's a distinct type in MSVC) - // ::= _E # unsigned __int8 - // ::= _F # __int16 - // ::= _G # unsigned __int16 - // ::= _H # __int32 - // ::= _I # unsigned __int32 // ::= _J # long long, __int64 // ::= _K # unsigned long long, __int64 // ::= _L # __int128 @@ -706,7 +700,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Double: Out << 'N'; break; // TODO: Determine size and mangle accordingly case BuiltinType::LongDouble: Out << 'O'; break; - // TODO: __int8 and friends case BuiltinType::LongLong: Out << "_J"; break; case BuiltinType::ULongLong: Out << "_K"; break; case BuiltinType::Int128: Out << "_L"; break; @@ -717,6 +710,8 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) { case BuiltinType::Overload: case BuiltinType::Dependent: + case BuiltinType::UnknownAny: + case BuiltinType::BoundMember: assert(false && "Overloaded and dependent types shouldn't get to name mangling"); break; @@ -873,6 +868,8 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, if (CC == CC_Default) CC = IsInstMethod ? getASTContext().getDefaultMethodCallConv() : CC_C; switch (CC) { + default: + assert(0 && "Unsupported CC for mangling"); case CC_Default: case CC_C: Out << 'A'; break; case CC_X86Pascal: Out << 'C'; break; diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index 6f1ec058d74e..2878dff3edc4 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -371,3 +371,249 @@ TypeLoc NestedNameSpecifierLoc::getTypeLoc() const { void *TypeData = LoadPointer(Data, Offset); return TypeLoc(Qualifier->getAsType(), TypeData); } + +namespace { + void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, + unsigned &BufferCapacity) { + if (BufferSize + (End - Start) > BufferCapacity) { + // Reallocate the buffer. + unsigned NewCapacity + = std::max((unsigned)(BufferCapacity? BufferCapacity * 2 + : sizeof(void*) * 2), + (unsigned)(BufferSize + (End - Start))); + char *NewBuffer = static_cast<char *>(malloc(NewCapacity)); + memcpy(NewBuffer, Buffer, BufferSize); + + if (BufferCapacity) + free(Buffer); + Buffer = NewBuffer; + BufferCapacity = NewCapacity; + } + + memcpy(Buffer + BufferSize, Start, End - Start); + BufferSize += End-Start; + } + + /// \brief Save a source location to the given buffer. + void SaveSourceLocation(SourceLocation Loc, char *&Buffer, + unsigned &BufferSize, unsigned &BufferCapacity) { + unsigned Raw = Loc.getRawEncoding(); + Append(reinterpret_cast<char *>(&Raw), + reinterpret_cast<char *>(&Raw) + sizeof(unsigned), + Buffer, BufferSize, BufferCapacity); + } + + /// \brief Save a pointer to the given buffer. + void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize, + unsigned &BufferCapacity) { + Append(reinterpret_cast<char *>(&Ptr), + reinterpret_cast<char *>(&Ptr) + sizeof(void *), + Buffer, BufferSize, BufferCapacity); + } +} + +NestedNameSpecifierLocBuilder::NestedNameSpecifierLocBuilder() + : Representation(0), Buffer(0), BufferSize(0), BufferCapacity(0) { } + +NestedNameSpecifierLocBuilder:: +NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other) + : Representation(Other.Representation), Buffer(0), + BufferSize(0), BufferCapacity(0) +{ + if (!Other.Buffer) + return; + + if (Other.BufferCapacity == 0) { + // Shallow copy is okay. + Buffer = Other.Buffer; + BufferSize = Other.BufferSize; + return; + } + + // Deep copy + BufferSize = Other.BufferSize; + BufferCapacity = Other.BufferSize; + Buffer = static_cast<char *>(malloc(BufferCapacity)); + memcpy(Buffer, Other.Buffer, BufferSize); +} + +NestedNameSpecifierLocBuilder & +NestedNameSpecifierLocBuilder:: +operator=(const NestedNameSpecifierLocBuilder &Other) { + Representation = Other.Representation; + + if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) { + // Re-use our storage. + BufferSize = Other.BufferSize; + memcpy(Buffer, Other.Buffer, BufferSize); + return *this; + } + + // Free our storage, if we have any. + if (BufferCapacity) { + free(Buffer); + BufferCapacity = 0; + } + + if (!Other.Buffer) { + // Empty. + Buffer = 0; + BufferSize = 0; + return *this; + } + + if (Other.BufferCapacity == 0) { + // Shallow copy is okay. + Buffer = Other.Buffer; + BufferSize = Other.BufferSize; + return *this; + } + + // Deep copy. + BufferSize = Other.BufferSize; + BufferCapacity = BufferSize; + Buffer = static_cast<char *>(malloc(BufferSize)); + memcpy(Buffer, Other.Buffer, BufferSize); + return *this; +} + +NestedNameSpecifierLocBuilder::~NestedNameSpecifierLocBuilder() { + if (BufferCapacity) + free(Buffer); +} + +void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, + SourceLocation TemplateKWLoc, + TypeLoc TL, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier::Create(Context, Representation, + TemplateKWLoc.isValid(), + TL.getTypePtr()); + + // Push source-location info into the buffer. + SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + +void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, + IdentifierInfo *Identifier, + SourceLocation IdentifierLoc, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier::Create(Context, Representation, + Identifier); + + // Push source-location info into the buffer. + SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + +void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, + NamespaceDecl *Namespace, + SourceLocation NamespaceLoc, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier::Create(Context, Representation, + Namespace); + + // Push source-location info into the buffer. + SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + +void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, + NamespaceAliasDecl *Alias, + SourceLocation AliasLoc, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier::Create(Context, Representation, Alias); + + // Push source-location info into the buffer. + SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + +void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context, + SourceLocation ColonColonLoc) { + assert(!Representation && "Already have a nested-name-specifier!?"); + Representation = NestedNameSpecifier::GlobalSpecifier(Context); + + // Push source-location info into the buffer. + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + +void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, + NestedNameSpecifier *Qualifier, + SourceRange R) { + Representation = Qualifier; + + // Construct bogus (but well-formed) source information for the + // nested-name-specifier. + BufferSize = 0; + llvm::SmallVector<NestedNameSpecifier *, 4> Stack; + for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix()) + Stack.push_back(NNS); + while (!Stack.empty()) { + NestedNameSpecifier *NNS = Stack.back(); + Stack.pop_back(); + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + TypeSourceInfo *TSInfo + = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0), + R.getBegin()); + SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, + BufferCapacity); + break; + } + + case NestedNameSpecifier::Global: + break; + } + + // Save the location of the '::'. + SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(), + Buffer, BufferSize, BufferCapacity); + } +} + +void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) { + if (BufferCapacity) + free(Buffer); + + if (!Other) { + Representation = 0; + BufferSize = 0; + return; + } + + // Rather than copying the data (which is wasteful), "adopt" the + // pointer (which points into the ASTContext) but set the capacity to zero to + // indicate that we don't own it. + Representation = Other.getNestedNameSpecifier(); + Buffer = static_cast<char *>(Other.getOpaqueData()); + BufferSize = Other.getDataLength(); + BufferCapacity = 0; +} + +NestedNameSpecifierLoc +NestedNameSpecifierLocBuilder::getWithLocInContext(ASTContext &Context) const { + if (!Representation) + return NestedNameSpecifierLoc(); + + // If we adopted our data pointer from elsewhere in the AST context, there's + // no need to copy the memory. + if (BufferCapacity == 0) + return NestedNameSpecifierLoc(Representation, Buffer); + + // FIXME: After copying the source-location information, should we free + // our (temporary) buffer and adopt the ASTContext-allocated memory? + // Doing so would optimize repeated calls to getWithLocInContext(). + void *Mem = Context.Allocate(BufferSize, llvm::alignOf<void *>()); + memcpy(Mem, Buffer, BufferSize); + return NestedNameSpecifierLoc(Representation, Mem); +} + diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 4ed031f97499..0770e1f15143 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -19,7 +19,7 @@ #include "llvm/Support/Format.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Support/MathExtras.h" -#include <map> +#include "llvm/Support/CrashRecoveryContext.h" using namespace clang; @@ -564,6 +564,8 @@ protected: unsigned IsUnion : 1; unsigned IsMac68kAlign : 1; + + unsigned IsMsStruct : 1; /// UnfilledBitsInLastByte - If the last field laid out was a bitfield, /// this contains the number of bits in the last byte that can be used for @@ -580,6 +582,8 @@ protected: CharUnits NonVirtualSize; CharUnits NonVirtualAlignment; + CharUnits ZeroLengthBitfieldAlignment; + /// PrimaryBase - the primary base class (if one exists) of the class /// we're laying out. const CXXRecordDecl *PrimaryBase; @@ -612,10 +616,12 @@ protected: *EmptySubobjects) : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), Alignment(CharUnits::One()), UnpackedAlignment(Alignment), - Packed(false), IsUnion(false), IsMac68kAlign(false), + Packed(false), IsUnion(false), + IsMac68kAlign(false), IsMsStruct(false), UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()), DataSize(0), NonVirtualSize(CharUnits::Zero()), - NonVirtualAlignment(CharUnits::One()), PrimaryBase(0), + NonVirtualAlignment(CharUnits::One()), + ZeroLengthBitfieldAlignment(CharUnits::Zero()), PrimaryBase(0), PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { } void Layout(const RecordDecl *D); @@ -657,7 +663,7 @@ protected: void SelectPrimaryVBase(const CXXRecordDecl *RD); - virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const; + virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const; /// LayoutNonVirtualBases - Determines the primary base class (if any) and /// lays it out. Will then proceed to lay out all non-virtual base clasess. @@ -757,9 +763,9 @@ RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { } } -uint64_t +CharUnits RecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { - return Context.Target.getPointerWidth(0); + return Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); } /// DeterminePrimaryBase - Determine the primary base of the given class. @@ -815,8 +821,8 @@ void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); // Update the size. - setSize(getSizeInBits() + GetVirtualPointersSize(RD)); - setDataSize(getSizeInBits()); + setSize(getSize() + GetVirtualPointersSize(RD)); + setDataSize(getSize()); CharUnits UnpackedBaseAlign = Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0)); @@ -1108,8 +1114,7 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { // If we have an empty base class, try to place it at offset 0. if (Base->Class->isEmpty() && EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) { - uint64_t RecordSizeInBits = Context.toBits(Layout.getSize()); - setSize(std::max(getSizeInBits(), RecordSizeInBits)); + setSize(std::max(getSize(), Layout.getSize())); return CharUnits::Zero(); } @@ -1124,27 +1129,24 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { } // Round up the current record size to the base's alignment boundary. - uint64_t Offset = - llvm::RoundUpToAlignment(getDataSizeInBits(), Context.toBits(BaseAlign)); + CharUnits Offset = getDataSize().RoundUpToAlignment(BaseAlign); // Try to place the base. - while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, - Context.toCharUnitsFromBits(Offset))) - Offset += Context.toBits(BaseAlign); + while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset)) + Offset += BaseAlign; if (!Base->Class->isEmpty()) { // Update the data size. - setDataSize(Offset + Context.toBits(Layout.getNonVirtualSize())); + setDataSize(Offset + Layout.getNonVirtualSize()); - setSize(std::max(getSizeInBits(), getDataSizeInBits())); + setSize(std::max(getSize(), getDataSize())); } else - setSize(std::max(getSizeInBits(), - Offset + Context.toBits(Layout.getSize()))); + setSize(std::max(getSize(), Offset + Layout.getSize())); // Remember max struct/class alignment. UpdateAlignment(BaseAlign, UnpackedBaseAlign); - return Context.toCharUnitsFromBits(Offset); + return Offset; } void RecordLayoutBuilder::InitializeLayout(const Decl *D) { @@ -1152,6 +1154,8 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) { IsUnion = RD->isUnion(); Packed = D->hasAttr<PackedAttr>(); + + IsMsStruct = D->hasAttr<MsStructAttr>(); // mac68k alignment supersedes maximum field alignment and attribute aligned, // and forces all structures to have 2-byte alignment. The IBM docs on it @@ -1187,8 +1191,9 @@ void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { LayoutFields(RD); - // FIXME: Size isn't always an exact multiple of the char width. Round up? - NonVirtualSize = Context.toCharUnitsFromBits(getSizeInBits()); + NonVirtualSize = Context.toCharUnitsFromBits( + llvm::RoundUpToAlignment(getSizeInBits(), + Context.Target.getCharAlign())); NonVirtualAlignment = Alignment; // Lay out the virtual bases and add the primary virtual base offsets. @@ -1233,7 +1238,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { // We start laying out ivars not at the end of the superclass // structure, but at the next byte following the last field. setSize(SL.getDataSize()); - setDataSize(getSizeInBits()); + setDataSize(getSize()); } InitializeLayout(D); @@ -1252,9 +1257,28 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { // Layout each field, for now, just sequentially, respecting alignment. In // the future, this will need to be tweakable by targets. + const FieldDecl *LastFD = 0; for (RecordDecl::field_iterator Field = D->field_begin(), - FieldEnd = D->field_end(); Field != FieldEnd; ++Field) + FieldEnd = D->field_end(); Field != FieldEnd; ++Field) { + if (IsMsStruct) { + const FieldDecl *FD = (*Field); + if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD)) { + // FIXME. Multiple zero bitfields may follow a bitfield. + // set ZeroLengthBitfieldAlignment to max. of its + // currrent and alignment of 'FD'. + std::pair<CharUnits, CharUnits> FieldInfo = + Context.getTypeInfoInChars(FD->getType()); + ZeroLengthBitfieldAlignment = FieldInfo.second; + continue; + } + // Zero-length bitfields following non-bitfield members are + // ignored: + if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD)) + continue; + LastFD = FD; + } LayoutField(*Field); + } } void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, @@ -1285,7 +1309,7 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, } assert(!Type.isNull() && "Did not find a type!"); - unsigned TypeAlign = Context.getTypeAlign(Type); + CharUnits TypeAlign = Context.getTypeAlignInChars(Type); // We're not going to use any of the unfilled bits in the last byte. UnfilledBitsInLastByte = 0; @@ -1299,11 +1323,13 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, } else { // The bitfield is allocated starting at the next offset aligned appropriately // for T', with length n bits. - FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(), TypeAlign); + FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(), + Context.toBits(TypeAlign)); uint64_t NewSizeInBits = FieldOffset + FieldSize; - setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, 8)); + setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, + Context.Target.getCharAlign())); UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; } @@ -1311,13 +1337,13 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, FieldOffsets.push_back(FieldOffset); CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, FieldOffset, - TypeAlign, FieldPacked, D); + Context.toBits(TypeAlign), FieldPacked, D); // Update the size. setSize(std::max(getSizeInBits(), getDataSizeInBits())); // Remember max struct/class alignment. - UpdateAlignment(Context.toCharUnitsFromBits(TypeAlign)); + UpdateAlignment(TypeAlign); } void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { @@ -1380,7 +1406,8 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { } else { uint64_t NewSizeInBits = FieldOffset + FieldSize; - setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, 8)); + setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, + Context.Target.getCharAlign())); UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; } @@ -1428,6 +1455,9 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { Context.getTypeInfoInChars(D->getType()); FieldSize = FieldInfo.first; FieldAlign = FieldInfo.second; + if (ZeroLengthBitfieldAlignment > FieldAlign) + FieldAlign = ZeroLengthBitfieldAlignment; + ZeroLengthBitfieldAlignment = CharUnits::Zero(); if (Context.getLangOptions().MSBitfields) { // If MS bitfield layout is required, figure out what type is being @@ -1487,7 +1517,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { if (IsUnion) setSize(std::max(getSizeInBits(), FieldSizeInBits)); else - setSize(Context.toBits(FieldOffset) + FieldSizeInBits); + setSize(FieldOffset + FieldSize); // Update the data size. setDataSize(getSizeInBits()); @@ -1504,17 +1534,18 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { // which is not empty but of size 0; such as having fields of // array of zero-length, remains of Size 0 if (RD->isEmpty()) - setSize(8); + setSize(CharUnits::One()); } else - setSize(8); + 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 UnpackedSize = + uint64_t UnpackedSizeInBits = llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(UnpackedAlignment)); + CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits); setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment))); unsigned CharBitNum = Context.Target.getCharWidth(); @@ -1536,7 +1567,7 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { // Warn if we packed it unnecessarily. If the alignment is 1 byte don't // bother since there won't be alignment issues. if (Packed && UnpackedAlignment > CharUnits::One() && - getSizeInBits() == UnpackedSize) + getSize() == UnpackedSize) Diag(D->getLocation(), diag::warn_unnecessary_packed) << Context.getTypeDeclType(RD); } @@ -1664,17 +1695,19 @@ namespace { EmptySubobjectMap *EmptySubobjects) : RecordLayoutBuilder(Ctx, EmptySubobjects) {} - virtual uint64_t GetVirtualPointersSize(const CXXRecordDecl *RD) const; + virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const; }; } -uint64_t +CharUnits MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { // We should reserve space for two pointers if the class has both // virtual functions and virtual bases. + CharUnits PointerWidth = + Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); if (RD->isPolymorphic() && RD->getNumVBases() > 0) - return 2 * Context.Target.getPointerWidth(0); - return Context.Target.getPointerWidth(0); + return 2 * PointerWidth; + return PointerWidth; } /// getASTRecordLayout - Get or compute information about the layout of the @@ -1705,6 +1738,10 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { case CXXABI_Microsoft: Builder.reset(new MSRecordLayoutBuilder(*this, &EmptySubobjects)); } + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder> + RecordBuilderCleanup(Builder.get()); + Builder->Layout(RD); // FIXME: This is not always correct. See the part about bitfields at @@ -1713,17 +1750,15 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD(); // FIXME: This should be done in FinalizeLayout. - uint64_t DataSize = - IsPODForThePurposeOfLayout ? Builder->Size : Builder->DataSize; - CharUnits NonVirtualSize = - IsPODForThePurposeOfLayout ? - toCharUnitsFromBits(DataSize) : Builder->NonVirtualSize; + CharUnits DataSize = + IsPODForThePurposeOfLayout ? Builder->getSize() : Builder->getDataSize(); + CharUnits NonVirtualSize = + IsPODForThePurposeOfLayout ? DataSize : Builder->NonVirtualSize; - CharUnits RecordSize = toCharUnitsFromBits(Builder->Size); NewEntry = - new (*this) ASTRecordLayout(*this, RecordSize, + new (*this) ASTRecordLayout(*this, Builder->getSize(), Builder->Alignment, - toCharUnitsFromBits(DataSize), + DataSize, Builder->FieldOffsets.data(), Builder->FieldOffsets.size(), NonVirtualSize, @@ -1736,12 +1771,10 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); Builder.Layout(D); - CharUnits RecordSize = toCharUnitsFromBits(Builder.Size); - NewEntry = - new (*this) ASTRecordLayout(*this, RecordSize, + new (*this) ASTRecordLayout(*this, Builder.getSize(), Builder.Alignment, - toCharUnitsFromBits(Builder.Size), + Builder.getSize(), Builder.FieldOffsets.data(), Builder.FieldOffsets.size()); } @@ -1797,12 +1830,10 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); Builder.Layout(D); - CharUnits RecordSize = toCharUnitsFromBits(Builder.Size); - const ASTRecordLayout *NewEntry = - new (*this) ASTRecordLayout(*this, RecordSize, + new (*this) ASTRecordLayout(*this, Builder.getSize(), Builder.Alignment, - toCharUnitsFromBits(Builder.DataSize), + Builder.getDataSize(), Builder.FieldOffsets.data(), Builder.FieldOffsets.size()); diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 8a80275aa165..380ad94ca224 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -540,6 +540,40 @@ CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, std::copy(handlers, handlers + NumHandlers, Stmts + 1); } +CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt, + Expr *Cond, Expr *Inc, DeclStmt *LoopVar, + Stmt *Body, SourceLocation FL, + SourceLocation CL, SourceLocation RPL) + : Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) { + SubExprs[RANGE] = Range; + SubExprs[BEGINEND] = BeginEndStmt; + SubExprs[COND] = reinterpret_cast<Stmt*>(Cond); + SubExprs[INC] = reinterpret_cast<Stmt*>(Inc); + SubExprs[LOOPVAR] = LoopVar; + SubExprs[BODY] = Body; +} + +Expr *CXXForRangeStmt::getRangeInit() { + DeclStmt *RangeStmt = getRangeStmt(); + VarDecl *RangeDecl = dyn_cast_or_null<VarDecl>(RangeStmt->getSingleDecl()); + assert(RangeDecl &&& "for-range should have a single var decl"); + return RangeDecl->getInit(); +} + +const Expr *CXXForRangeStmt::getRangeInit() const { + return const_cast<CXXForRangeStmt*>(this)->getRangeInit(); +} + +VarDecl *CXXForRangeStmt::getLoopVariable() { + Decl *LV = cast<DeclStmt>(getLoopVarStmt())->getSingleDecl(); + assert(LV && "No loop variable in CXXForRangeStmt"); + return cast<VarDecl>(LV); +} + +const VarDecl *CXXForRangeStmt::getLoopVariable() const { + return const_cast<CXXForRangeStmt*>(this)->getLoopVariable(); +} + IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, Stmt *then, SourceLocation EL, Stmt *elsev) : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) @@ -628,14 +662,14 @@ void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) { } Stmt *SwitchCase::getSubStmt() { - if (isa<CaseStmt>(this)) return cast<CaseStmt>(this)->getSubStmt(); + if (isa<CaseStmt>(this)) + return cast<CaseStmt>(this)->getSubStmt(); return cast<DefaultStmt>(this)->getSubStmt(); } WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, SourceLocation WL) -: Stmt(WhileStmtClass) -{ + : Stmt(WhileStmtClass) { setConditionVariable(C, Var); SubExprs[COND] = reinterpret_cast<Stmt*>(cond); SubExprs[BODY] = body; @@ -676,3 +710,61 @@ const Expr* ReturnStmt::getRetValue() const { Expr* ReturnStmt::getRetValue() { return cast_or_null<Expr>(RetExpr); } + +SEHTryStmt::SEHTryStmt(bool IsCXXTry, + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler) + : Stmt(SEHTryStmtClass), + IsCXXTry(IsCXXTry), + TryLoc(TryLoc) +{ + Children[TRY] = TryBlock; + Children[HANDLER] = Handler; +} + +SEHTryStmt* SEHTryStmt::Create(ASTContext &C, + bool IsCXXTry, + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler) { + return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler); +} + +SEHExceptStmt* SEHTryStmt::getExceptHandler() const { + return dyn_cast<SEHExceptStmt>(getHandler()); +} + +SEHFinallyStmt* SEHTryStmt::getFinallyHandler() const { + return dyn_cast<SEHFinallyStmt>(getHandler()); +} + +SEHExceptStmt::SEHExceptStmt(SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block) + : Stmt(SEHExceptStmtClass), + Loc(Loc) +{ + Children[FILTER_EXPR] = reinterpret_cast<Stmt*>(FilterExpr); + Children[BLOCK] = Block; +} + +SEHExceptStmt* SEHExceptStmt::Create(ASTContext &C, + SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block) { + return new(C) SEHExceptStmt(Loc,FilterExpr,Block); +} + +SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc, + Stmt *Block) + : Stmt(SEHFinallyStmtClass), + Loc(Loc), + Block(Block) +{} + +SEHFinallyStmt* SEHFinallyStmt::Create(ASTContext &C, + SourceLocation Loc, + Stmt *Block) { + return new(C)SEHFinallyStmt(Loc,Block); +} diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 5c7dbb3ed990..fb024f33ab30 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -141,7 +141,7 @@ namespace { void VisitFloatingLiteral(FloatingLiteral *Node); void VisitStringLiteral(StringLiteral *Str); void VisitUnaryOperator(UnaryOperator *Node); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node); void VisitMemberExpr(MemberExpr *Node); void VisitExtVectorElementExpr(ExtVectorElementExpr *Node); void VisitBinaryOperator(BinaryOperator *Node); @@ -236,6 +236,9 @@ void StmtDumper::DumpDeclarator(Decl *D) { if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) { OS << "\"typedef " << localType->getUnderlyingType().getAsString() << ' ' << localType << '"'; + } else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) { + OS << "\"using " << localType << " = " + << localType->getUnderlyingType().getAsString() << '"'; } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { OS << "\""; // Emit storage class for vardecls. @@ -284,6 +287,12 @@ void StmtDumper::DumpDeclarator(Decl *D) { OS << ";\""; } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) { OS << "label " << LD->getNameAsString(); + } else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) { + OS << "\"static_assert(\n"; + DumpSubTree(SAD->getAssertExpr()); + OS << ",\n"; + DumpSubTree(SAD->getMessage()); + OS << ");\""; } else { assert(0 && "Unexpected decl"); } @@ -360,6 +369,11 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { OS << " "; DumpDeclRef(Node->getDecl()); + if (Node->getDecl() != Node->getFoundDecl()) { + OS << " ("; + DumpDeclRef(Node->getFoundDecl()); + OS << ")"; + } } void StmtDumper::DumpDeclRef(Decl *d) { @@ -441,9 +455,19 @@ void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) { OS << " " << (Node->isPostfix() ? "postfix" : "prefix") << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; } -void StmtDumper::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { +void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) { DumpExpr(Node); - OS << " " << (Node->isSizeOf() ? "sizeof" : "alignof") << " "; + switch(Node->getKind()) { + case UETT_SizeOf: + OS << " sizeof "; + break; + case UETT_AlignOf: + OS << " __alignof "; + break; + case UETT_VecStep: + OS << " vec_step "; + break; + } if (Node->isArgumentType()) DumpType(Node->getArgumentType()); } diff --git a/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp index 9a7265a043f2..9bf4aeaae83e 100644 --- a/lib/AST/StmtIterator.cpp +++ b/lib/AST/StmtIterator.cpp @@ -98,7 +98,7 @@ bool StmtIteratorBase::HandleDecl(Decl* D) { if (VD->getInit()) return true; } - else if (TypedefDecl* TD = dyn_cast<TypedefDecl>(D)) { + else if (TypedefNameDecl* TD = dyn_cast<TypedefNameDecl>(D)) { if (const VariableArrayType* VAPtr = FindVA(TD->getUnderlyingType().getTypePtr())) { setVAPtr(VAPtr); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 1cdd22088141..0d13502e8d58 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -66,6 +66,8 @@ namespace { void PrintRawIfStmt(IfStmt *If); void PrintRawCXXCatchStmt(CXXCatchStmt *Catch); void PrintCallArgs(CallExpr *E); + void PrintRawSEHExceptHandler(SEHExceptStmt *S); + void PrintRawSEHFinallyStmt(SEHFinallyStmt *S); void PrintExpr(Expr *E) { if (E) @@ -291,6 +293,18 @@ void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) { } } +void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) { + Indent() << "for ("; + PrintingPolicy SubPolicy(Policy); + SubPolicy.SuppressInitializers = true; + Node->getLoopVariable()->print(OS, SubPolicy, IndentLevel); + OS << " : "; + PrintExpr(Node->getRangeInit()); + OS << ") {\n"; + PrintStmt(Node->getBody()); + Indent() << "}\n"; +} + void StmtPrinter::VisitGotoStmt(GotoStmt *Node) { Indent() << "goto " << Node->getLabel()->getName() << ";\n"; } @@ -461,6 +475,46 @@ void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) { OS << "\n"; } +void StmtPrinter::VisitSEHTryStmt(SEHTryStmt *Node) { + Indent() << (Node->getIsCXXTry() ? "try " : "__try "); + PrintRawCompoundStmt(Node->getTryBlock()); + SEHExceptStmt *E = Node->getExceptHandler(); + SEHFinallyStmt *F = Node->getFinallyHandler(); + if(E) + PrintRawSEHExceptHandler(E); + else { + assert(F && "Must have a finally block..."); + PrintRawSEHFinallyStmt(F); + } + OS << "\n"; +} + +void StmtPrinter::PrintRawSEHFinallyStmt(SEHFinallyStmt *Node) { + OS << "__finally "; + PrintRawCompoundStmt(Node->getBlock()); + OS << "\n"; +} + +void StmtPrinter::PrintRawSEHExceptHandler(SEHExceptStmt *Node) { + OS << "__except ("; + VisitExpr(Node->getFilterExpr()); + OS << ")\n"; + PrintRawCompoundStmt(Node->getBlock()); + OS << "\n"; +} + +void StmtPrinter::VisitSEHExceptStmt(SEHExceptStmt *Node) { + Indent(); + PrintRawSEHExceptHandler(Node); + OS << "\n"; +} + +void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) { + Indent(); + PrintRawSEHFinallyStmt(Node); + OS << "\n"; +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// @@ -706,8 +760,18 @@ void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) { OS << ")"; } -void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { - OS << (Node->isSizeOf() ? "sizeof" : "__alignof"); +void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){ + switch(Node->getKind()) { + case UETT_SizeOf: + OS << "sizeof"; + break; + case UETT_AlignOf: + OS << "__alignof"; + break; + case UETT_VecStep: + OS << "vec_step"; + break; + } if (Node->isArgumentType()) OS << "(" << Node->getArgumentType().getAsString(Policy) << ")"; else { @@ -715,6 +779,23 @@ void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { PrintExpr(Node->getArgumentExpr()); } } + +void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) { + OS << "_Generic("; + PrintExpr(Node->getControllingExpr()); + for (unsigned i = 0; i != Node->getNumAssocs(); ++i) { + OS << ", "; + QualType T = Node->getAssocType(i); + if (T.isNull()) + OS << "default"; + else + OS << T.getAsString(Policy); + OS << ": "; + PrintExpr(Node->getAssocExpr(i)); + } + OS << ")"; +} + void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) { PrintExpr(Node->getLHS()); OS << "["; @@ -1212,33 +1293,75 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { static const char *getTypeTraitName(UnaryTypeTrait UTT) { switch (UTT) { - default: llvm_unreachable("Unknown unary type trait"); case UTT_HasNothrowAssign: return "__has_nothrow_assign"; - case UTT_HasNothrowCopy: return "__has_nothrow_copy"; case UTT_HasNothrowConstructor: return "__has_nothrow_constructor"; + case UTT_HasNothrowCopy: return "__has_nothrow_copy"; case UTT_HasTrivialAssign: return "__has_trivial_assign"; - case UTT_HasTrivialCopy: return "__has_trivial_copy"; case UTT_HasTrivialConstructor: return "__has_trivial_constructor"; + case UTT_HasTrivialCopy: return "__has_trivial_copy"; case UTT_HasTrivialDestructor: return "__has_trivial_destructor"; case UTT_HasVirtualDestructor: return "__has_virtual_destructor"; case UTT_IsAbstract: return "__is_abstract"; + case UTT_IsArithmetic: return "__is_arithmetic"; + case UTT_IsArray: return "__is_array"; case UTT_IsClass: return "__is_class"; + case UTT_IsCompleteType: return "__is_complete_type"; + case UTT_IsCompound: return "__is_compound"; + case UTT_IsConst: return "__is_const"; case UTT_IsEmpty: return "__is_empty"; case UTT_IsEnum: return "__is_enum"; + case UTT_IsFloatingPoint: return "__is_floating_point"; + case UTT_IsFunction: return "__is_function"; + case UTT_IsFundamental: return "__is_fundamental"; + case UTT_IsIntegral: return "__is_integral"; + case UTT_IsLiteral: return "__is_literal"; + case UTT_IsLvalueReference: return "__is_lvalue_reference"; + case UTT_IsMemberFunctionPointer: return "__is_member_function_pointer"; + case UTT_IsMemberObjectPointer: return "__is_member_object_pointer"; + case UTT_IsMemberPointer: return "__is_member_pointer"; + case UTT_IsObject: return "__is_object"; case UTT_IsPOD: return "__is_pod"; + case UTT_IsPointer: return "__is_pointer"; case UTT_IsPolymorphic: return "__is_polymorphic"; + case UTT_IsReference: return "__is_reference"; + case UTT_IsRvalueReference: return "__is_rvalue_reference"; + case UTT_IsScalar: return "__is_scalar"; + case UTT_IsSigned: return "__is_signed"; + case UTT_IsStandardLayout: return "__is_standard_layout"; + case UTT_IsTrivial: return "__is_trivial"; case UTT_IsUnion: return "__is_union"; + case UTT_IsUnsigned: return "__is_unsigned"; + case UTT_IsVoid: return "__is_void"; + case UTT_IsVolatile: return "__is_volatile"; } - return ""; + llvm_unreachable("Type trait not covered by switch statement"); } static const char *getTypeTraitName(BinaryTypeTrait BTT) { switch (BTT) { case BTT_IsBaseOf: return "__is_base_of"; + case BTT_IsConvertible: return "__is_convertible"; + case BTT_IsSame: return "__is_same"; case BTT_TypeCompatible: return "__builtin_types_compatible_p"; case BTT_IsConvertibleTo: return "__is_convertible_to"; } - return ""; + llvm_unreachable("Binary type trait not covered by switch"); +} + +static const char *getTypeTraitName(ArrayTypeTrait ATT) { + switch (ATT) { + case ATT_ArrayRank: return "__array_rank"; + case ATT_ArrayExtent: return "__array_extent"; + } + llvm_unreachable("Array type trait not covered by switch"); +} + +static const char *getExpressionTraitName(ExpressionTrait ET) { + switch (ET) { + case ET_IsLValueExpr: return "__is_lvalue_expr"; + case ET_IsRValueExpr: return "__is_rvalue_expr"; + } + llvm_unreachable("Expression type trait not covered by switch"); } void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { @@ -1252,6 +1375,17 @@ void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { << E->getRhsType().getAsString(Policy) << ")"; } +void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { + OS << getTypeTraitName(E->getTrait()) << "(" + << E->getQueriedType().getAsString(Policy) << ")"; +} + +void StmtPrinter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { + OS << getExpressionTraitName(E->getTrait()) << "("; + PrintExpr(E->getQueriedExpression()); + OS << ")"; +} + void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { OS << "noexcept("; PrintExpr(E->getOperand()); diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index b54001167b42..44818e8c0847 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -177,6 +177,22 @@ void StmtProfiler::VisitCXXTryStmt(CXXTryStmt *S) { VisitStmt(S); } +void StmtProfiler::VisitCXXForRangeStmt(CXXForRangeStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitSEHTryStmt(SEHTryStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitSEHFinallyStmt(SEHFinallyStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitSEHExceptStmt(SEHExceptStmt *S) { + VisitStmt(S); +} + void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { VisitStmt(S); } @@ -290,9 +306,9 @@ void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) { VisitExpr(S); } -void StmtProfiler::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *S) { +void StmtProfiler::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *S) { VisitExpr(S); - ID.AddBoolean(S->isSizeOf()); + ID.AddInteger(S->getKind()); if (S->isArgumentType()) VisitType(S->getArgumentType()); } @@ -430,6 +446,18 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) { ID.AddBoolean(S->isConstQualAdded()); } +void StmtProfiler::VisitGenericSelectionExpr(GenericSelectionExpr *S) { + VisitExpr(S); + for (unsigned i = 0; i != S->getNumAssocs(); ++i) { + QualType T = S->getAssocType(i); + if (T.isNull()) + ID.AddPointer(0); + else + VisitType(T); + VisitExpr(S->getAssocExpr(i)); + } +} + static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S, UnaryOperatorKind &UnaryOp, BinaryOperatorKind &BinaryOp) { @@ -786,6 +814,18 @@ void StmtProfiler::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *S) { VisitType(S->getRhsType()); } +void StmtProfiler::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getTrait()); + VisitType(S->getQueriedType()); +} + +void StmtProfiler::VisitExpressionTraitExpr(ExpressionTraitExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getTrait()); + VisitExpr(S->getQueriedExpression()); +} + void StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) { VisitExpr(S); @@ -921,12 +961,16 @@ void StmtProfiler::VisitDecl(Decl *D) { } if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) { - // The Itanium C++ ABI uses the type of a parameter when mangling - // expressions that involve function parameters, so we will use the - // parameter's type for establishing function parameter identity. That - // way, our definition of "equivalent" (per C++ [temp.over.link]) - // matches the definition of "equivalent" used for name mangling. + // The Itanium C++ ABI uses the type, scope depth, and scope + // index of a parameter when mangling expressions that involve + // function parameters, so we will use the parameter's type for + // establishing function parameter identity. That way, our + // definition of "equivalent" (per C++ [temp.over.link]) is at + // least as strong as the definition of "equivalent" used for + // name mangling. VisitType(Parm->getType()); + ID.AddInteger(Parm->getFunctionScopeDepth()); + ID.AddInteger(Parm->getFunctionScopeIndex()); return; } diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index 1764f4ab1f03..6114a5a051be 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -338,7 +338,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy, //===----------------------------------------------------------------------===// TemplateArgumentLocInfo::TemplateArgumentLocInfo() { - memset(this, 0, sizeof(TemplateArgumentLocInfo)); + memset((void*)this, 0, sizeof(TemplateArgumentLocInfo)); } SourceRange TemplateArgumentLoc::getSourceRange() const { @@ -356,14 +356,14 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { return SourceRange(); case TemplateArgument::Template: - if (getTemplateQualifierRange().isValid()) - return SourceRange(getTemplateQualifierRange().getBegin(), + if (getTemplateQualifierLoc()) + return SourceRange(getTemplateQualifierLoc().getBeginLoc(), getTemplateNameLoc()); return SourceRange(getTemplateNameLoc()); case TemplateArgument::TemplateExpansion: - if (getTemplateQualifierRange().isValid()) - return SourceRange(getTemplateQualifierRange().getBegin(), + if (getTemplateQualifierLoc()) + return SourceRange(getTemplateQualifierLoc().getBeginLoc(), getTemplateEllipsisLoc()); return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc()); @@ -425,7 +425,7 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis, Ellipsis = getTemplateEllipsisLoc(); NumExpansions = Argument.getNumTemplateExpansions(); return TemplateArgumentLoc(Argument.getPackExpansionPattern(), - getTemplateQualifierRange(), + getTemplateQualifierLoc(), getTemplateNameLoc()); case TemplateArgument::Declaration: diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 6b378a001101..ebd07f486783 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -118,6 +118,10 @@ TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, } else if (SubstTemplateTemplateParmPackStorage *SubstPack = getAsSubstTemplateTemplateParmPack()) OS << SubstPack->getParameterPack()->getNameAsString(); + else { + OverloadedTemplateStorage *OTS = getAsOverloadedTemplate(); + (*OTS->begin())->printName(OS); + } } const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index b03314e11d13..9eb497bea629 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -21,11 +21,24 @@ #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Specifiers.h" +#include "llvm/ADT/APSInt.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> using namespace clang; +bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const { + return (*this != Other) && + // CVR qualifiers superset + (((Mask & CVRMask) | (Other.Mask & CVRMask)) == (Mask & CVRMask)) && + // ObjC GC qualifiers superset + ((getObjCGCAttr() == Other.getObjCGCAttr()) || + (hasObjCGCAttr() && !Other.hasObjCGCAttr())) && + // Address space superset. + ((getAddressSpace() == Other.getAddressSpace()) || + (hasAddressSpace()&& !Other.hasAddressSpace())); +} + bool QualType::isConstant(QualType T, ASTContext &Ctx) { if (T.isConstQualified()) return true; @@ -407,6 +420,16 @@ const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { return 0; } +const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const { + // There is no sugar for ObjCQualifiedClassType's, just return the canonical + // type pointer if it is the right class. + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { + if (OPT->isObjCQualifiedClassType()) + return OPT; + } + return 0; +} + const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { if (OPT->getInterfaceType()) @@ -858,37 +881,178 @@ bool Type::isPODType() const { } bool Type::isLiteralType() const { - if (isIncompleteType()) + if (isDependentType()) return false; // C++0x [basic.types]p10: // A type is a literal type if it is: - switch (CanonicalType->getTypeClass()) { - // We're whitelisting - default: return false; + // [...] + // -- an array of literal type + // Extension: variable arrays cannot be literal types, since they're + // runtime-sized. + if (isVariableArrayType()) + return false; + const Type *BaseTy = getBaseElementTypeUnsafe(); + assert(BaseTy && "NULL element type"); + + // Return false for incomplete types after skipping any incomplete array + // types; those are expressly allowed by the standard and thus our API. + if (BaseTy->isIncompleteType()) + return false; + + // C++0x [basic.types]p10: + // A type is a literal type if it is: + // -- a scalar type; or + // As an extension, Clang treats vector types as Scalar types. + if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + // -- a reference type; or + if (BaseTy->isReferenceType()) return true; + // -- a class type that has all of the following properties: + if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) { + // -- a trivial destructor, + if (!ClassDecl->hasTrivialDestructor()) return false; + // -- every constructor call and full-expression in the + // brace-or-equal-initializers for non-static data members (if any) + // is a constant expression, + // FIXME: C++0x: Clang doesn't yet support non-static data member + // declarations with initializers, or constexprs. + // -- it is an aggregate type or has at least one constexpr + // constructor or constructor template that is not a copy or move + // constructor, and + if (!ClassDecl->isAggregate() && + !ClassDecl->hasConstExprNonCopyMoveConstructor()) + return false; + // -- all non-static data members and base classes of literal types + if (ClassDecl->hasNonLiteralTypeFieldsOrBases()) return false; + } - // -- a scalar type - case Builtin: - case Complex: - case Pointer: - case MemberPointer: - case Vector: - case ExtVector: - case ObjCObjectPointer: - case Enum: return true; + } + return false; +} - // -- a class type with ... - case Record: - // FIXME: Do the tests +bool Type::isTrivialType() const { + if (isDependentType()) return false; - // -- an array of literal type - // Extension: variable arrays cannot be literal types, since they're - // runtime-sized. - case ConstantArray: - return cast<ArrayType>(CanonicalType)->getElementType()->isLiteralType(); + // C++0x [basic.types]p9: + // Scalar types, trivial class types, arrays of such types, and + // cv-qualified versions of these types are collectively called trivial + // types. + const Type *BaseTy = getBaseElementTypeUnsafe(); + assert(BaseTy && "NULL element type"); + + // Return false for incomplete types after skipping any incomplete array + // types which are expressly allowed by the standard and thus our API. + if (BaseTy->isIncompleteType()) + return false; + + // As an extension, Clang treats vector types as Scalar types. + if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) { + // C++0x [class]p5: + // A trivial class is a class that has a trivial default constructor + if (!ClassDecl->hasTrivialConstructor()) return false; + // and is trivially copyable. + if (!ClassDecl->isTriviallyCopyable()) return false; + } + + return true; + } + + // No other types can match. + return false; +} + +bool Type::isStandardLayoutType() const { + if (isDependentType()) + return false; + + // C++0x [basic.types]p9: + // Scalar types, standard-layout class types, arrays of such types, and + // cv-qualified versions of these types are collectively called + // standard-layout types. + const Type *BaseTy = getBaseElementTypeUnsafe(); + assert(BaseTy && "NULL element type"); + + // Return false for incomplete types after skipping any incomplete array + // types which are expressly allowed by the standard and thus our API. + if (BaseTy->isIncompleteType()) + return false; + + // As an extension, Clang treats vector types as Scalar types. + if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) + if (!ClassDecl->isStandardLayout()) + return false; + + // Default to 'true' for non-C++ class types. + // FIXME: This is a bit dubious, but plain C structs should trivially meet + // all the requirements of standard layout classes. + return true; + } + + // No other types can match. + return false; +} + +// This is effectively the intersection of isTrivialType and +// isStandardLayoutType. We implement it dircetly to avoid redundant +// conversions from a type to a CXXRecordDecl. +bool Type::isCXX11PODType() const { + if (isDependentType()) + return false; + + // C++11 [basic.types]p9: + // Scalar types, POD classes, arrays of such types, and cv-qualified + // versions of these types are collectively called trivial types. + const Type *BaseTy = getBaseElementTypeUnsafe(); + assert(BaseTy && "NULL element type"); + + // Return false for incomplete types after skipping any incomplete array + // types which are expressly allowed by the standard and thus our API. + if (BaseTy->isIncompleteType()) + return false; + + // As an extension, Clang treats vector types as Scalar types. + if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) { + // C++11 [class]p10: + // A POD struct is a non-union class that is both a trivial class [...] + // C++11 [class]p5: + // A trivial class is a class that has a trivial default constructor + if (!ClassDecl->hasTrivialConstructor()) return false; + // and is trivially copyable. + if (!ClassDecl->isTriviallyCopyable()) return false; + + // C++11 [class]p10: + // A POD struct is a non-union class that is both a trivial class and + // a standard-layout class [...] + if (!ClassDecl->isStandardLayout()) return false; + + // C++11 [class]p10: + // A POD struct is a non-union class that is both a trivial class and + // a standard-layout class, and has no non-static data members of type + // non-POD struct, non-POD union (or array of such types). [...] + // + // We don't directly query the recursive aspect as the requiremets for + // both standard-layout classes and trivial classes apply recursively + // already. + } + + return true; } + + // No other types can match. + return false; } bool Type::isPromotableIntegerType() const { @@ -1040,9 +1204,9 @@ DependentTemplateSpecializationType::DependentTemplateSpecializationType( QualType Canon) : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true, /*VariablyModified=*/false, - NNS->containsUnexpandedParameterPack()), + NNS && NNS->containsUnexpandedParameterPack()), NNS(NNS), Name(Name), NumArgs(NumArgs) { - assert(NNS && NNS->isDependent() && + assert((!NNS || NNS->isDependent()) && "DependentTemplateSpecializatonType requires dependent qualifier"); for (unsigned I = 0; I != NumArgs; ++I) { if (Args[I].containsUnexpandedParameterPack()) @@ -1120,7 +1284,9 @@ const char *BuiltinType::getName(const LangOptions &LO) const { case Char32: return "char32_t"; case NullPtr: return "nullptr_t"; case Overload: return "<overloaded function type>"; + case BoundMember: return "<bound member function type>"; case Dependent: return "<dependent type>"; + case UnknownAny: return "<unknown type>"; case ObjCId: return "id"; case ObjCClass: return "Class"; case ObjCSel: return "SEL"; @@ -1157,6 +1323,8 @@ llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_X86FastCall: return "fastcall"; case CC_X86ThisCall: return "thiscall"; case CC_X86Pascal: return "pascal"; + case CC_AAPCS: return "aapcs"; + case CC_AAPCS_VFP: return "aapcs-vfp"; } llvm_unreachable("Invalid calling convention."); @@ -1173,8 +1341,7 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, result->containsUnexpandedParameterPack(), epi.ExtInfo), NumArgs(numArgs), NumExceptions(epi.NumExceptions), - HasExceptionSpec(epi.HasExceptionSpec), - HasAnyExceptionSpec(epi.HasAnyExceptionSpec) + ExceptionSpecType(epi.ExceptionSpecType) { // Fill in the trailing argument array. QualType *argSlot = reinterpret_cast<QualType*>(this+1); @@ -1187,20 +1354,50 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, argSlot[i] = args[i]; } - - // Fill in the exception array. - QualType *exnSlot = argSlot + numArgs; - for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) { - if (epi.Exceptions[i]->isDependentType()) - setDependent(); - if (epi.Exceptions[i]->containsUnexpandedParameterPack()) - setContainsUnexpandedParameterPack(); + if (getExceptionSpecType() == EST_Dynamic) { + // Fill in the exception array. + QualType *exnSlot = argSlot + numArgs; + for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) { + if (epi.Exceptions[i]->isDependentType()) + setDependent(); - exnSlot[i] = epi.Exceptions[i]; + if (epi.Exceptions[i]->containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + + exnSlot[i] = epi.Exceptions[i]; + } + } else if (getExceptionSpecType() == EST_ComputedNoexcept) { + // Store the noexcept expression and context. + Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs); + *noexSlot = epi.NoexceptExpr; } } +FunctionProtoType::NoexceptResult +FunctionProtoType::getNoexceptSpec(ASTContext &ctx) const { + ExceptionSpecificationType est = getExceptionSpecType(); + if (est == EST_BasicNoexcept) + return NR_Nothrow; + + if (est != EST_ComputedNoexcept) + return NR_NoNoexcept; + + Expr *noexceptExpr = getNoexceptExpr(); + if (!noexceptExpr) + return NR_BadNoexcept; + if (noexceptExpr->isValueDependent()) + return NR_Dependent; + + llvm::APSInt value; + bool isICE = noexceptExpr->isIntegerConstantExpr(value, ctx, 0, + /*evaluated*/false); + (void)isICE; + assert(isICE && "AST should not contain bad noexcept expressions."); + + return value.getBoolValue() ? NR_Nothrow : NR_Throw; +} + bool FunctionProtoType::isTemplateVariadic() const { for (unsigned ArgIdx = getNumArgs(); ArgIdx; --ArgIdx) if (isa<PackExpansionType>(getArgType(ArgIdx - 1))) @@ -1211,23 +1408,28 @@ bool FunctionProtoType::isTemplateVariadic() const { void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, const QualType *ArgTys, unsigned NumArgs, - const ExtProtoInfo &epi) { + const ExtProtoInfo &epi, + const ASTContext &Context) { ID.AddPointer(Result.getAsOpaquePtr()); for (unsigned i = 0; i != NumArgs; ++i) ID.AddPointer(ArgTys[i].getAsOpaquePtr()); ID.AddBoolean(epi.Variadic); ID.AddInteger(epi.TypeQuals); ID.AddInteger(epi.RefQualifier); - if (epi.HasExceptionSpec) { - ID.AddBoolean(epi.HasAnyExceptionSpec); + ID.AddInteger(epi.ExceptionSpecType); + if (epi.ExceptionSpecType == EST_Dynamic) { for (unsigned i = 0; i != epi.NumExceptions; ++i) ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr()); + } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){ + epi.NoexceptExpr->Profile(ID, Context, true); } epi.ExtInfo.Profile(ID); } -void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo()); +void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Ctx) { + Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo(), + Ctx); } QualType TypedefType::desugar() const { @@ -1302,6 +1504,10 @@ bool EnumType::classof(const TagType *TT) { return isa<EnumDecl>(TT->getDecl()); } +IdentifierInfo *TemplateTypeParmType::getIdentifier() const { + return isCanonicalUnqualified() ? 0 : getDecl()->getIdentifier(); +} + SubstTemplateTypeParmPackType:: SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, QualType Canon, @@ -1357,10 +1563,11 @@ TemplateSpecializationType(TemplateName T, unsigned NumArgs, QualType Canon) : Type(TemplateSpecialization, Canon.isNull()? QualType(this, 0) : Canon, - T.isDependent(), false, - T.containsUnexpandedParameterPack()), + T.isDependent(), false, T.containsUnexpandedParameterPack()), Template(T), NumArgs(NumArgs) { + assert(!T.getAsDependentTemplateName() && + "Use DependentTemplateSpecializationType for dependent template-name"); assert((!Canon.isNull() || T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) && "No canonical type for non-dependent class template specialization"); @@ -1529,7 +1736,7 @@ static CachedProperties computeCachedProperties(const Type *T) { NamedDecl::LinkageInfo LV = Tag->getLinkageAndVisibility(); bool IsLocalOrUnnamed = Tag->getDeclContext()->isFunctionOrMethod() || - (!Tag->getIdentifier() && !Tag->getTypedefForAnonDecl()); + (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()); return CachedProperties(LV.linkage(), LV.visibility(), IsLocalOrUnnamed); } diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 14db7f83c2d0..34e7693e3075 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -102,6 +102,8 @@ SourceLocation TypeLoc::getBeginLoc() const { // FIXME: Currently QualifiedTypeLoc does not have a source range // case Qualified: case Elaborated: + case DependentName: + case DependentTemplateSpecialization: break; default: TypeLoc Next = Cur.getNextTypeLoc(); @@ -116,18 +118,37 @@ SourceLocation TypeLoc::getBeginLoc() const { SourceLocation TypeLoc::getEndLoc() const { TypeLoc Cur = *this; + TypeLoc Last; while (true) { switch (Cur.getTypeLocClass()) { default: + if (!Last) + Last = Cur; + return Last.getLocalSourceRange().getEnd(); + case Paren: + case ConstantArray: + case DependentSizedArray: + case IncompleteArray: + case VariableArray: + case FunctionProto: + case FunctionNoProto: + Last = Cur; + break; + case Pointer: + case BlockPointer: + case MemberPointer: + case LValueReference: + case RValueReference: + case PackExpansion: + if (!Last) + Last = Cur; break; case Qualified: case Elaborated: - Cur = Cur.getNextTypeLoc(); - continue; + break; } - break; + Cur = Cur.getNextTypeLoc(); } - return Cur.getLocalSourceRange().getEnd(); } @@ -213,6 +234,8 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::NullPtr: case BuiltinType::Overload: case BuiltinType::Dependent: + case BuiltinType::BoundMember: + case BuiltinType::UnknownAny: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: @@ -229,6 +252,43 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { return TL; } +void ElaboratedTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setKeywordLoc(Loc); + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); + setQualifierLoc(Builder.getWithLocInContext(Context)); +} + +void DependentNameTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setKeywordLoc(Loc); + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); + setQualifierLoc(Builder.getWithLocInContext(Context)); + setNameLoc(Loc); +} + +void +DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setKeywordLoc(Loc); + if (getTypePtr()->getQualifier()) { + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); + setQualifierLoc(Builder.getWithLocInContext(Context)); + } else { + setQualifierLoc(NestedNameSpecifierLoc()); + } + + setNameLoc(Loc); + setLAngleLoc(Loc); + setRAngleLoc(Loc); + TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), + getTypePtr()->getArgs(), + getArgInfos(), Loc); +} + void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, unsigned NumArgs, const TemplateArgument *Args, @@ -252,13 +312,22 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, break; case TemplateArgument::Template: - ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc, - SourceLocation()); - break; + case TemplateArgument::TemplateExpansion: { + NestedNameSpecifierLocBuilder Builder; + TemplateName Template = Args[i].getAsTemplate(); + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) + Builder.MakeTrivial(Context, DTN->getQualifier(), Loc); + else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + Builder.MakeTrivial(Context, QTN->getQualifier(), Loc); - case TemplateArgument::TemplateExpansion: - ArgInfos[i] = TemplateArgumentLocInfo(SourceRange(Loc), Loc, Loc); + ArgInfos[i] = TemplateArgumentLocInfo( + Builder.getWithLocInContext(Context), + Loc, + Args[i].getKind() == TemplateArgument::Template + ? SourceLocation() + : Loc); break; + } } } } diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 139073987a0e..0c5df7fae671 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -400,6 +400,12 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T, case CC_X86Pascal: S += " __attribute__((pascal))"; break; + case CC_AAPCS: + S += " __attribute__((pcs(\"aapcs\")))"; + break; + case CC_AAPCS_VFP: + S += " __attribute__((pcs(\"aapcs-vfp\")))"; + break; } if (Info.getNoReturn()) S += " __attribute__((noreturn))"; @@ -421,12 +427,12 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T, S += " &&"; break; } - - if (T->hasExceptionSpec()) { + + if (T->hasDynamicExceptionSpec()) { S += " throw("; - if (T->hasAnyExceptionSpec()) + if (T->getExceptionSpecType() == EST_MSAny) S += "..."; - else + else for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) { if (I) S += ", "; @@ -436,6 +442,16 @@ void TypePrinter::printFunctionProto(const FunctionProtoType *T, S += ExceptionType; } S += ")"; + } else if (isNoexceptExceptionSpec(T->getExceptionSpecType())) { + S += " noexcept"; + if (T->getExceptionSpecType() == EST_ComputedNoexcept) { + S += "("; + llvm::raw_string_ostream EOut(S); + T->getNoexceptExpr()->printPretty(EOut, 0, Policy); + EOut.flush(); + S += EOut.str(); + S += ")"; + } } print(T->getResultType(), S); @@ -530,7 +546,7 @@ void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) { Buffer += Spec->getIdentifier()->getName(); Buffer += TemplateArgsStr; } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { - if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl()) + if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl()) Buffer += Typedef->getIdentifier()->getName(); else if (Tag->getIdentifier()) Buffer += Tag->getIdentifier()->getName(); @@ -547,9 +563,13 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) { std::string Buffer; bool HasKindDecoration = false; + // bool SuppressTagKeyword + // = Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword; + // We don't print tags unless this is an elaborated type. // In C, we just assume every RecordType is an elaborated type. - if (!Policy.LangOpts.CPlusPlus && !D->getTypedefForAnonDecl()) { + if (!(Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword || + D->getTypedefNameForAnonDecl())) { HasKindDecoration = true; Buffer += D->getKindName(); Buffer += ' '; @@ -563,7 +583,7 @@ void TypePrinter::printTag(TagDecl *D, std::string &InnerString) { if (const IdentifierInfo *II = D->getIdentifier()) Buffer += II->getNameStart(); - else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) { + else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) { assert(Typedef->getIdentifier() && "Typedef without identifier?"); Buffer += Typedef->getIdentifier()->getNameStart(); } else { @@ -632,12 +652,12 @@ void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'. S = ' ' + S; - - if (!T->getName()) + + if (IdentifierInfo *Id = T->getIdentifier()) + S = Id->getName().str() + S; + else S = "type-parameter-" + llvm::utostr_32(T->getDepth()) + '-' + llvm::utostr_32(T->getIndex()) + S; - else - S = T->getName()->getName().str() + S; } void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T, @@ -691,6 +711,7 @@ void TypePrinter::printElaborated(const ElaboratedType *T, std::string &S) { std::string TypeStr; PrintingPolicy InnerPolicy(Policy); + InnerPolicy.SuppressTagKeyword = true; InnerPolicy.SuppressScope = true; TypePrinter(InnerPolicy).print(T->getNamedType(), TypeStr); @@ -737,7 +758,8 @@ void TypePrinter::printDependentTemplateSpecialization( if (T->getKeyword() != ETK_None) OS << " "; - T->getQualifier()->print(OS, Policy); + if (T->getQualifier()) + T->getQualifier()->print(OS, Policy); OS << T->getIdentifier()->getName(); OS << TemplateSpecializationType::PrintTemplateArgumentList( T->getArgs(), @@ -759,10 +781,14 @@ void TypePrinter::printPackExpansion(const PackExpansionType *T, void TypePrinter::printAttributed(const AttributedType *T, std::string &S) { + // Prefer the macro forms of the GC qualifiers. + if (T->getAttrKind() == AttributedType::attr_objc_gc) + return print(T->getEquivalentType(), S); + print(T->getModifiedType(), S); // TODO: not all attributes are GCC-style attributes. - S += "__attribute__(("; + S += " __attribute__(("; switch (T->getAttrKind()) { case AttributedType::attr_address_space: S += "address_space("; @@ -831,6 +857,16 @@ void TypePrinter::printAttributed(const AttributedType *T, case AttributedType::attr_stdcall: S += "stdcall"; break; case AttributedType::attr_thiscall: S += "thiscall"; break; case AttributedType::attr_pascal: S += "pascal"; break; + case AttributedType::attr_pcs: { + S += "pcs("; + QualType t = T->getEquivalentType(); + while (!t->isFunctionType()) + t = t->getPointeeType(); + S += (t->getAs<FunctionType>()->getCallConv() == CC_AAPCS ? + "\"aapcs\"" : "\"aapcs-vfp\""); + S += ")"; + break; + } } S += "))"; } @@ -1031,20 +1067,18 @@ std::string Qualifiers::getAsString() const { void Qualifiers::getAsStringInternal(std::string &S, const PrintingPolicy&) const { AppendTypeQualList(S, getCVRQualifiers()); - if (unsigned AddressSpace = getAddressSpace()) { + if (unsigned addrspace = getAddressSpace()) { if (!S.empty()) S += ' '; S += "__attribute__((address_space("; - S += llvm::utostr_32(AddressSpace); + S += llvm::utostr_32(addrspace); S += ")))"; } - if (Qualifiers::GC GCAttrType = getObjCGCAttr()) { + if (Qualifiers::GC gc = getObjCGCAttr()) { if (!S.empty()) S += ' '; - S += "__attribute__((objc_gc("; - if (GCAttrType == Qualifiers::Weak) - S += "weak"; + if (gc == Qualifiers::Weak) + S += "__weak"; else - S += "strong"; - S += ")))"; + S += "__strong"; } } diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp index 62097ef20dd9..ddc5e887031b 100644 --- a/lib/Analysis/AnalysisContext.cpp +++ b/lib/Analysis/AnalysisContext.cpp @@ -29,6 +29,24 @@ using namespace clang; +AnalysisContext::AnalysisContext(const Decl *d, + idx::TranslationUnit *tu, + bool useUnoptimizedCFG, + bool addehedges, + bool addImplicitDtors, + bool addInitializers) + : D(d), TU(tu), + forcedBlkExprs(0), + builtCFG(false), builtCompleteCFG(false), + useUnoptimizedCFG(useUnoptimizedCFG), + ReferencedBlockVars(0) +{ + cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; + cfgBuildOptions.AddEHEdges = addehedges; + cfgBuildOptions.AddImplicitDtors = addImplicitDtors; + cfgBuildOptions.AddInitializers = addInitializers; +} + void AnalysisContextManager::clear() { for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I) delete I->second; @@ -56,57 +74,71 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const { return NULL; } +void AnalysisContext::registerForcedBlockExpression(const Stmt *stmt) { + if (!forcedBlkExprs) + forcedBlkExprs = new CFG::BuildOptions::ForcedBlkExprs(); + // Default construct an entry for 'stmt'. + if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt)) + stmt = pe->IgnoreParens(); + (void) (*forcedBlkExprs)[stmt]; +} + +const CFGBlock * +AnalysisContext::getBlockForRegisteredExpression(const Stmt *stmt) { + assert(forcedBlkExprs); + if (const ParenExpr *pe = dyn_cast<ParenExpr>(stmt)) + stmt = pe->IgnoreParens(); + CFG::BuildOptions::ForcedBlkExprs::const_iterator itr = + forcedBlkExprs->find(stmt); + assert(itr != forcedBlkExprs->end()); + return itr->second; +} + CFG *AnalysisContext::getCFG() { - if (UseUnoptimizedCFG) + if (useUnoptimizedCFG) return getUnoptimizedCFG(); if (!builtCFG) { - CFG::BuildOptions B; - B.AddEHEdges = AddEHEdges; - B.AddImplicitDtors = AddImplicitDtors; - B.AddInitializers = AddInitializers; - cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), B); + cfg.reset(CFG::buildCFG(D, getBody(), + &D->getASTContext(), cfgBuildOptions)); // Even when the cfg is not successfully built, we don't // want to try building it again. builtCFG = true; } - return cfg; + return cfg.get(); } CFG *AnalysisContext::getUnoptimizedCFG() { if (!builtCompleteCFG) { - CFG::BuildOptions B; + CFG::BuildOptions B = cfgBuildOptions; B.PruneTriviallyFalseEdges = false; - B.AddEHEdges = AddEHEdges; - B.AddImplicitDtors = AddImplicitDtors; - B.AddInitializers = AddInitializers; - completeCFG = CFG::buildCFG(D, getBody(), &D->getASTContext(), B); + completeCFG.reset(CFG::buildCFG(D, getBody(), &D->getASTContext(), B)); // Even when the cfg is not successfully built, we don't // want to try building it again. builtCompleteCFG = true; } - return completeCFG; + return completeCFG.get(); } CFGStmtMap *AnalysisContext::getCFGStmtMap() { if (cfgStmtMap) - return cfgStmtMap; + return cfgStmtMap.get(); if (CFG *c = getCFG()) { - cfgStmtMap = CFGStmtMap::Build(c, &getParentMap()); - return cfgStmtMap; + cfgStmtMap.reset(CFGStmtMap::Build(c, &getParentMap())); + return cfgStmtMap.get(); } return 0; } -CFGReachabilityAnalysis *AnalysisContext::getCFGReachablityAnalysis() { +CFGReverseBlockReachabilityAnalysis *AnalysisContext::getCFGReachablityAnalysis() { if (CFA) - return CFA; + return CFA.get(); if (CFG *c = getCFG()) { - CFA = new CFGReachabilityAnalysis(*c); - return CFA; + CFA.reset(new CFGReverseBlockReachabilityAnalysis(*c)); + return CFA.get(); } return 0; @@ -118,42 +150,37 @@ void AnalysisContext::dumpCFG() { ParentMap &AnalysisContext::getParentMap() { if (!PM) - PM = new ParentMap(getBody()); + PM.reset(new ParentMap(getBody())); return *PM; } PseudoConstantAnalysis *AnalysisContext::getPseudoConstantAnalysis() { if (!PCA) - PCA = new PseudoConstantAnalysis(getBody()); - return PCA; + PCA.reset(new PseudoConstantAnalysis(getBody())); + return PCA.get(); } LiveVariables *AnalysisContext::getLiveVariables() { if (!liveness) { - CFG *c = getCFG(); - if (!c) - return 0; - - liveness = new LiveVariables(*this); - liveness->runOnCFG(*c); - liveness->runOnAllBlocks(*c, 0, true); + if (CFG *c = getCFG()) { + liveness.reset(new LiveVariables(*this)); + liveness->runOnCFG(*c); + liveness->runOnAllBlocks(*c, 0, true); + } } - return liveness; + return liveness.get(); } LiveVariables *AnalysisContext::getRelaxedLiveVariables() { - if (!relaxedLiveness) { - CFG *c = getCFG(); - if (!c) - return 0; - - relaxedLiveness = new LiveVariables(*this, false); - relaxedLiveness->runOnCFG(*c); - relaxedLiveness->runOnAllBlocks(*c, 0, true); - } + if (!relaxedLiveness) + if (CFG *c = getCFG()) { + relaxedLiveness.reset(new LiveVariables(*this, false)); + relaxedLiveness->runOnCFG(*c); + relaxedLiveness->runOnAllBlocks(*c, 0, true); + } - return relaxedLiveness; + return relaxedLiveness.get(); } AnalysisContext *AnalysisContextManager::getContext(const Decl *D, @@ -370,14 +397,7 @@ AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) { //===----------------------------------------------------------------------===// AnalysisContext::~AnalysisContext() { - delete cfg; - delete completeCFG; - delete cfgStmtMap; - delete liveness; - delete relaxedLiveness; - delete PM; - delete PCA; - delete CFA; + delete forcedBlkExprs; delete ReferencedBlockVars; } diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index cc6e9c592a1e..de16334ce137 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -36,6 +36,8 @@ static SourceLocation GetEndLoc(Decl* D) { return D->getLocation(); } +class CFGBuilder; + /// The CFG builder uses a recursive algorithm to build the CFG. When /// we process an expression, sometimes we know that we must add the /// subexpressions as block-level expressions. For example: @@ -55,13 +57,13 @@ public: AddStmtChoice(Kind a_kind = NotAlwaysAdd) : kind(a_kind) {} - bool alwaysAdd() const { return kind & AlwaysAdd; } + bool alwaysAdd(CFGBuilder &builder, + const Stmt *stmt) const; /// Return a copy of this object, except with the 'always-add' bit /// set as specified. AddStmtChoice withAlwaysAdd(bool alwaysAdd) const { - return AddStmtChoice(alwaysAdd ? Kind(kind | AlwaysAdd) : - Kind(kind & ~AlwaysAdd)); + return AddStmtChoice(alwaysAdd ? AlwaysAdd : NotAlwaysAdd); } private: @@ -210,6 +212,25 @@ struct BlockScopePosPair { LocalScope::const_iterator scopePosition; }; +/// TryResult - a class representing a variant over the values +/// 'true', 'false', or 'unknown'. This is returned by tryEvaluateBool, +/// and is used by the CFGBuilder to decide if a branch condition +/// can be decided up front during CFG construction. +class TryResult { + int X; +public: + TryResult(bool b) : X(b ? 1 : 0) {} + TryResult() : X(-1) {} + + bool isTrue() const { return X == 1; } + bool isFalse() const { return X == 0; } + bool isKnown() const { return X >= 0; } + void negate() { + assert(isKnown()); + X ^= 0x1; + } +}; + /// CFGBuilder - This class implements CFG construction from an AST. /// The builder is stateful: an instance of the builder should be used to only /// construct a single CFG. @@ -238,7 +259,7 @@ class CFGBuilder { CFGBlock* SwitchTerminatedBlock; CFGBlock* DefaultCaseBlock; CFGBlock* TryTerminatedBlock; - + // Current position in local scope. LocalScope::const_iterator ScopePos; @@ -256,18 +277,30 @@ class CFGBuilder { LabelSetTy AddressTakenLabels; bool badCFG; - CFG::BuildOptions BuildOpts; + const CFG::BuildOptions &BuildOpts; + + // State to track for building switch statements. + bool switchExclusivelyCovered; + Expr::EvalResult *switchCond; + + CFG::BuildOptions::ForcedBlkExprs::value_type *cachedEntry; + const Stmt *lastLookup; public: - explicit CFGBuilder() : cfg(new CFG()), // crew a new CFG - Block(NULL), Succ(NULL), - SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL), - TryTerminatedBlock(NULL), badCFG(false) {} + explicit CFGBuilder(ASTContext *astContext, + const CFG::BuildOptions &buildOpts) + : Context(astContext), cfg(new CFG()), // crew a new CFG + Block(NULL), Succ(NULL), + SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL), + TryTerminatedBlock(NULL), badCFG(false), BuildOpts(buildOpts), + switchExclusivelyCovered(false), switchCond(0), + cachedEntry(0), lastLookup(0) {} // buildCFG - Used by external clients to construct the CFG. - CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, - CFG::BuildOptions BO); + CFG* buildCFG(const Decl *D, Stmt *Statement); + bool alwaysAdd(const Stmt *stmt); + private: // Visitors to walk an AST and construct the CFG. CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc); @@ -279,6 +312,7 @@ private: AddStmtChoice asc); CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T); CFGBlock *VisitCXXTryStmt(CXXTryStmt *S); + CFGBlock *VisitCXXForRangeStmt(CXXForRangeStmt *S); CFGBlock *VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, AddStmtChoice asc); CFGBlock *VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc); @@ -311,7 +345,8 @@ private: CFGBlock *VisitObjCAtTryStmt(ObjCAtTryStmt *S); CFGBlock *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); CFGBlock *VisitReturnStmt(ReturnStmt* R); - CFGBlock *VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, AddStmtChoice asc); + CFGBlock *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, + AddStmtChoice asc); CFGBlock *VisitStmtExpr(StmtExpr *S, AddStmtChoice asc); CFGBlock *VisitSwitchStmt(SwitchStmt *S); CFGBlock *VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc); @@ -359,9 +394,11 @@ private: void addLocalScopeAndDtors(Stmt* S); // Interface to CFGBlock - adding CFGElements. - void appendStmt(CFGBlock *B, Stmt *S, - AddStmtChoice asc = AddStmtChoice::AlwaysAdd) { - B->appendStmt(S, cfg->getBumpVectorContext()); + void appendStmt(CFGBlock *B, const Stmt *S) { + if (alwaysAdd(S)) + cachedEntry->second = B; + + B->appendStmt(const_cast<Stmt*>(S), cfg->getBumpVectorContext()); } void appendInitializer(CFGBlock *B, CXXCtorInitializer *I) { B->appendInitializer(I, cfg->getBumpVectorContext()); @@ -387,47 +424,74 @@ private: B->addSuccessor(S, cfg->getBumpVectorContext()); } - /// TryResult - a class representing a variant over the values - /// 'true', 'false', or 'unknown'. This is returned by tryEvaluateBool, - /// and is used by the CFGBuilder to decide if a branch condition - /// can be decided up front during CFG construction. - class TryResult { - int X; - public: - TryResult(bool b) : X(b ? 1 : 0) {} - TryResult() : X(-1) {} - - bool isTrue() const { return X == 1; } - bool isFalse() const { return X == 0; } - bool isKnown() const { return X >= 0; } - void negate() { - assert(isKnown()); - X ^= 0x1; - } - }; + /// Try and evaluate an expression to an integer constant. + bool tryEvaluate(Expr *S, Expr::EvalResult &outResult) { + if (!BuildOpts.PruneTriviallyFalseEdges) + return false; + return !S->isTypeDependent() && + !S->isValueDependent() && + S->Evaluate(outResult, *Context); + } /// tryEvaluateBool - Try and evaluate the Stmt and return 0 or 1 /// if we can evaluate to a known value, otherwise return -1. TryResult tryEvaluateBool(Expr *S) { - if (!BuildOpts.PruneTriviallyFalseEdges) - return TryResult(); - Expr::EvalResult Result; - if (!S->isTypeDependent() && !S->isValueDependent() && - S->Evaluate(Result, *Context)) { - if (Result.Val.isInt()) - return Result.Val.getInt().getBoolValue(); - if (Result.Val.isLValue()) { - Expr *e = Result.Val.getLValueBase(); - const CharUnits &c = Result.Val.getLValueOffset(); - if (!e && c.isZero()) - return false; - } + if (!tryEvaluate(S, Result)) + return TryResult(); + + if (Result.Val.isInt()) + return Result.Val.getInt().getBoolValue(); + + if (Result.Val.isLValue()) { + Expr *e = Result.Val.getLValueBase(); + const CharUnits &c = Result.Val.getLValueOffset(); + if (!e && c.isZero()) + return false; } return TryResult(); } + }; +inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder, + const Stmt *stmt) const { + return builder.alwaysAdd(stmt) || kind == AlwaysAdd; +} + +bool CFGBuilder::alwaysAdd(const Stmt *stmt) { + if (!BuildOpts.forcedBlkExprs) + return false; + + if (lastLookup == stmt) { + if (cachedEntry) { + assert(cachedEntry->first == stmt); + return true; + } + return false; + } + + lastLookup = stmt; + + // Perform the lookup! + CFG::BuildOptions::ForcedBlkExprs *fb = *BuildOpts.forcedBlkExprs; + + if (!fb) { + // No need to update 'cachedEntry', since it will always be null. + assert(cachedEntry == 0); + return false; + } + + CFG::BuildOptions::ForcedBlkExprs::iterator itr = fb->find(stmt); + if (itr == fb->end()) { + cachedEntry = 0; + return false; + } + + cachedEntry = &*itr; + return true; +} + // FIXME: Add support for dependent-sized array types in C++? // Does it even make sense to build a CFG for an uninstantiated template? static const VariableArrayType *FindVA(const Type *t) { @@ -447,16 +511,11 @@ static const VariableArrayType *FindVA(const Type *t) { /// body (compound statement). The ownership of the returned CFG is /// transferred to the caller. If CFG construction fails, this method returns /// NULL. -CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C, - CFG::BuildOptions BO) { - - Context = C; +CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement) { assert(cfg.get()); if (!Statement) return NULL; - BuildOpts = BO; - // Create an empty block that will serve as the exit block for the CFG. Since // this is the first block added to the CFG, it will be implicitly registered // as the exit block. @@ -853,6 +912,9 @@ tryAgain: case Stmt::CXXTryStmtClass: return VisitCXXTryStmt(cast<CXXTryStmt>(S)); + case Stmt::CXXForRangeStmtClass: + return VisitCXXForRangeStmt(cast<CXXForRangeStmt>(S)); + case Stmt::DeclStmtClass: return VisitDeclStmt(cast<DeclStmt>(S)); @@ -908,8 +970,9 @@ tryAgain: case Stmt::ReturnStmtClass: return VisitReturnStmt(cast<ReturnStmt>(S)); - case Stmt::SizeOfAlignOfExprClass: - return VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), asc); + case Stmt::UnaryExprOrTypeTraitExprClass: + return VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S), + asc); case Stmt::StmtExprClass: return VisitStmtExpr(cast<StmtExpr>(S), asc); @@ -926,9 +989,9 @@ tryAgain: } CFGBlock *CFGBuilder::VisitStmt(Stmt *S, AddStmtChoice asc) { - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, S)) { autoCreateBlock(); - appendStmt(Block, S, asc); + appendStmt(Block, S); } return VisitChildren(S); @@ -949,9 +1012,9 @@ CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc) { AddressTakenLabels.insert(A->getLabel()); - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, A)) { autoCreateBlock(); - appendStmt(Block, A, asc); + appendStmt(Block, A); } return Block; @@ -959,9 +1022,9 @@ CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc) { - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, U)) { autoCreateBlock(); - appendStmt(Block, U, asc); + appendStmt(Block, U); } return Visit(U->getSubExpr(), AddStmtChoice()); @@ -971,7 +1034,7 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc) { if (B->isLogicalOp()) { // && or || CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); - appendStmt(ConfluenceBlock, B, asc); + appendStmt(ConfluenceBlock, B); if (badCFG) return 0; @@ -1016,23 +1079,23 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, if (B->getOpcode() == BO_Comma) { // , autoCreateBlock(); - appendStmt(Block, B, asc); + appendStmt(Block, B); addStmt(B->getRHS()); return addStmt(B->getLHS()); } if (B->isAssignmentOp()) { - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, B)) { autoCreateBlock(); - appendStmt(Block, B, asc); + appendStmt(Block, B); } Visit(B->getLHS()); return Visit(B->getRHS()); } - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, B)) { autoCreateBlock(); - appendStmt(Block, B, asc); + appendStmt(Block, B); } CFGBlock *RBlock = Visit(B->getRHS()); @@ -1044,9 +1107,9 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, } CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, AddStmtChoice asc) { - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, E)) { autoCreateBlock(); - appendStmt(Block, E, asc); + appendStmt(Block, E); } return Block; } @@ -1073,7 +1136,7 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { return Block; } -static bool CanThrow(Expr *E) { +static bool CanThrow(Expr *E, ASTContext &Ctx) { QualType Ty = E->getType(); if (Ty->isFunctionPointerType()) Ty = Ty->getAs<PointerType>()->getPointeeType(); @@ -1083,7 +1146,7 @@ static bool CanThrow(Expr *E) { const FunctionType *FT = Ty->getAs<FunctionType>(); if (FT) { if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT)) - if (Proto->hasEmptyExceptionSpec()) + if (Proto->isNothrow(Ctx)) return false; } return true; @@ -1099,7 +1162,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { bool AddEHEdge = false; // Languages without exceptions are assumed to not throw. - if (Context->getLangOptions().areExceptionsEnabled()) { + if (Context->getLangOptions().Exceptions) { if (BuildOpts.AddEHEdges) AddEHEdge = true; } @@ -1111,7 +1174,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { AddEHEdge = false; } - if (!CanThrow(C->getCallee())) + if (!CanThrow(C->getCallee(), *Context)) AddEHEdge = false; if (!NoReturn && !AddEHEdge) @@ -1124,7 +1187,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { } Block = createBlock(!NoReturn); - appendStmt(Block, C, asc); + appendStmt(Block, C); if (NoReturn) { // Wire this to the exit block directly. @@ -1144,7 +1207,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, AddStmtChoice asc) { CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); - appendStmt(ConfluenceBlock, C, asc); + appendStmt(ConfluenceBlock, C); if (badCFG) return 0; @@ -1197,7 +1260,7 @@ CFGBlock *CFGBuilder::VisitConditionalOperator(AbstractConditionalOperator *C, // Create the confluence block that will "merge" the results of the ternary // expression. CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); - appendStmt(ConfluenceBlock, C, asc); + appendStmt(ConfluenceBlock, C); if (badCFG) return 0; @@ -1353,7 +1416,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { addAutomaticObjDtors(ScopePos, BeginScopePos, I); } - // The block we were proccessing is now finished. Make it the successor + // The block we were processing is now finished. Make it the successor // block. if (Block) { Succ = Block; @@ -1436,7 +1499,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { if (VarDecl *VD = I->getConditionVariable()) { if (Expr *Init = VD->getInit()) { autoCreateBlock(); - appendStmt(Block, I, AddStmtChoice::AlwaysAdd); + appendStmt(Block, I->getConditionVariableDeclStmt()); addStmt(Init); } } @@ -1574,7 +1637,7 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { if (VarDecl *VD = F->getConditionVariable()) { if (Expr *Init = VD->getInit()) { autoCreateBlock(); - appendStmt(Block, F, AddStmtChoice::AlwaysAdd); + appendStmt(Block, F->getConditionVariableDeclStmt()); EntryConditionBlock = addStmt(Init); assert(Block == EntryConditionBlock); } @@ -1672,9 +1735,9 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { } CFGBlock *CFGBuilder::VisitMemberExpr(MemberExpr *M, AddStmtChoice asc) { - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, M)) { autoCreateBlock(); - appendStmt(Block, M, asc); + appendStmt(Block, M); } return Visit(M->getBase()); } @@ -1736,7 +1799,7 @@ CFGBlock* CFGBuilder::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { Block = ExitConditionBlock; // Walk the 'element' expression to see if there are any side-effects. We - // generate new blocks as necesary. We DON'T add the statement by default to + // generate new blocks as necessary. We DON'T add the statement by default to // the CFG unless it contains control-flow. EntryConditionBlock = Visit(S->getElement(), AddStmtChoice::NotAlwaysAdd); if (Block) { @@ -1799,7 +1862,7 @@ CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) { // Add the @synchronized to the CFG. autoCreateBlock(); - appendStmt(Block, S, AddStmtChoice::AlwaysAdd); + appendStmt(Block, S); // Inline the sync expression. return addStmt(S->getSynchExpr()); @@ -1858,7 +1921,7 @@ CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { if (VarDecl *VD = W->getConditionVariable()) { if (Expr *Init = VD->getInit()) { autoCreateBlock(); - appendStmt(Block, W, AddStmtChoice::AlwaysAdd); + appendStmt(Block, W->getConditionVariableDeclStmt()); EntryConditionBlock = addStmt(Init); assert(Block == EntryConditionBlock); } @@ -2105,28 +2168,30 @@ CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) { return Block; } -CFGBlock *CFGBuilder::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E, - AddStmtChoice asc) { +CFGBlock *CFGBuilder::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E, + AddStmtChoice asc) { - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, E)) { autoCreateBlock(); appendStmt(Block, E); } // VLA types have expressions that must be evaluated. + CFGBlock *lastBlock = Block; + if (E->isArgumentType()) { for (const VariableArrayType *VA =FindVA(E->getArgumentType().getTypePtr()); VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) - addStmt(VA->getSizeExpr()); + lastBlock = addStmt(VA->getSizeExpr()); } - return Block; + return lastBlock; } /// VisitStmtExpr - Utility method to handle (nested) statement /// expressions (a GCC extension). CFGBlock* CFGBuilder::VisitStmtExpr(StmtExpr *SE, AddStmtChoice asc) { - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, SE)) { autoCreateBlock(); appendStmt(Block, SE); } @@ -2180,6 +2245,18 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { assert(Terminator->getBody() && "switch must contain a non-NULL body"); Block = NULL; + // For pruning unreachable case statements, save the current state + // for tracking the condition value. + SaveAndRestore<bool> save_switchExclusivelyCovered(switchExclusivelyCovered, + false); + + // Determine if the switch condition can be explicitly evaluated. + assert(Terminator->getCond() && "switch condition must be non-NULL"); + Expr::EvalResult result; + bool b = tryEvaluate(Terminator->getCond(), result); + SaveAndRestore<Expr::EvalResult*> save_switchCond(switchCond, + b ? &result : 0); + // If body is not a compound statement create implicit scope // and add destructors. if (!isa<CompoundStmt>(Terminator->getBody())) @@ -2192,12 +2269,14 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { } // If we have no "default:" case, the default transition is to the code - // following the switch body. - addSuccessor(SwitchTerminatedBlock, DefaultCaseBlock); + // following the switch body. Moreover, take into account if all the + // cases of a switch are covered (e.g., switching on an enum value). + addSuccessor(SwitchTerminatedBlock, + switchExclusivelyCovered || Terminator->isAllEnumCasesCovered() + ? 0 : DefaultCaseBlock); // Add the terminator and condition in the switch block. SwitchTerminatedBlock->setTerminator(Terminator); - assert(Terminator->getCond() && "switch condition must be non-NULL"); Block = SwitchTerminatedBlock; Block = addStmt(Terminator->getCond()); @@ -2206,19 +2285,60 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { if (VarDecl *VD = Terminator->getConditionVariable()) { if (Expr *Init = VD->getInit()) { autoCreateBlock(); - appendStmt(Block, Terminator, AddStmtChoice::AlwaysAdd); + appendStmt(Block, Terminator->getConditionVariableDeclStmt()); addStmt(Init); } } return Block; } + +static bool shouldAddCase(bool &switchExclusivelyCovered, + const Expr::EvalResult *switchCond, + const CaseStmt *CS, + ASTContext &Ctx) { + if (!switchCond) + return true; + + bool addCase = false; + + if (!switchExclusivelyCovered) { + if (switchCond->Val.isInt()) { + // Evaluate the LHS of the case value. + Expr::EvalResult V1; + CS->getLHS()->Evaluate(V1, Ctx); + assert(V1.Val.isInt()); + const llvm::APSInt &condInt = switchCond->Val.getInt(); + const llvm::APSInt &lhsInt = V1.Val.getInt(); + + if (condInt == lhsInt) { + addCase = true; + switchExclusivelyCovered = true; + } + else if (condInt < lhsInt) { + if (const Expr *RHS = CS->getRHS()) { + // Evaluate the RHS of the case value. + Expr::EvalResult V2; + RHS->Evaluate(V2, Ctx); + assert(V2.Val.isInt()); + if (V2.Val.getInt() <= condInt) { + addCase = true; + switchExclusivelyCovered = true; + } + } + } + } + else + addCase = true; + } + return addCase; +} CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { // CaseStmts are essentially labels, so they are the first statement in a // block. CFGBlock *TopBlock = 0, *LastBlock = 0; - + if (Stmt *Sub = CS->getSubStmt()) { // For deeply nested chains of CaseStmts, instead of doing a recursion // (which can blow out the stack), manually unroll and create blocks @@ -2232,9 +2352,12 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { else TopBlock = currentBlock; - addSuccessor(SwitchTerminatedBlock, currentBlock); - LastBlock = currentBlock; + addSuccessor(SwitchTerminatedBlock, + shouldAddCase(switchExclusivelyCovered, switchCond, + CS, *Context) + ? currentBlock : 0); + LastBlock = currentBlock; CS = cast<CaseStmt>(Sub); Sub = CS->getSubStmt(); } @@ -2256,7 +2379,10 @@ CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* CS) { // Add this block to the list of successors for the block with the switch // statement. assert(SwitchTerminatedBlock); - addSuccessor(SwitchTerminatedBlock, CaseBlock); + addSuccessor(SwitchTerminatedBlock, + shouldAddCase(switchExclusivelyCovered, switchCond, + CS, *Context) + ? CaseBlock : 0); // We set Block to NULL to allow lazy creation of a new block (if necessary) Block = NULL; @@ -2391,6 +2517,122 @@ CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) { return CatchBlock; } +CFGBlock* CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt* S) { + // C++0x for-range statements are specified as [stmt.ranged]: + // + // { + // auto && __range = range-init; + // for ( auto __begin = begin-expr, + // __end = end-expr; + // __begin != __end; + // ++__begin ) { + // for-range-declaration = *__begin; + // statement + // } + // } + + // Save local scope position before the addition of the implicit variables. + SaveAndRestore<LocalScope::const_iterator> save_scope_pos(ScopePos); + + // Create local scopes and destructors for range, begin and end variables. + if (Stmt *Range = S->getRangeStmt()) + addLocalScopeForStmt(Range); + if (Stmt *BeginEnd = S->getBeginEndStmt()) + addLocalScopeForStmt(BeginEnd); + addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S); + + LocalScope::const_iterator ContinueScopePos = ScopePos; + + // "for" is a control-flow statement. Thus we stop processing the current + // block. + CFGBlock* LoopSuccessor = NULL; + if (Block) { + if (badCFG) + return 0; + LoopSuccessor = Block; + } else + LoopSuccessor = Succ; + + // Save the current value for the break targets. + // All breaks should go to the code following the loop. + SaveAndRestore<JumpTarget> save_break(BreakJumpTarget); + BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); + + // The block for the __begin != __end expression. + CFGBlock* ConditionBlock = createBlock(false); + ConditionBlock->setTerminator(S); + + // Now add the actual condition to the condition block. + if (Expr *C = S->getCond()) { + Block = ConditionBlock; + CFGBlock *BeginConditionBlock = addStmt(C); + if (badCFG) + return 0; + assert(BeginConditionBlock == ConditionBlock && + "condition block in for-range was unexpectedly complex"); + (void)BeginConditionBlock; + } + + // The condition block is the implicit successor for the loop body as well as + // any code above the loop. + Succ = ConditionBlock; + + // See if this is a known constant. + TryResult KnownVal(true); + + if (S->getCond()) + KnownVal = tryEvaluateBool(S->getCond()); + + // Now create the loop body. + { + assert(S->getBody()); + + // Save the current values for Block, Succ, and continue targets. + SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ); + SaveAndRestore<JumpTarget> save_continue(ContinueJumpTarget); + + // Generate increment code in its own basic block. This is the target of + // continue statements. + Block = 0; + Succ = addStmt(S->getInc()); + ContinueJumpTarget = JumpTarget(Succ, ContinueScopePos); + + // The starting block for the loop increment is the block that should + // represent the 'loop target' for looping back to the start of the loop. + ContinueJumpTarget.block->setLoopTarget(S); + + // Finish up the increment block and prepare to start the loop body. + assert(Block); + if (badCFG) + return 0; + Block = 0; + + + // Add implicit scope and dtors for loop variable. + addLocalScopeAndDtors(S->getLoopVarStmt()); + + // Populate a new block to contain the loop body and loop variable. + Block = addStmt(S->getBody()); + if (badCFG) + return 0; + Block = addStmt(S->getLoopVarStmt()); + if (badCFG) + return 0; + + // This new body block is a successor to our condition block. + addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : Block); + } + + // Link up the condition block with the code that follows the loop (the + // false branch). + addSuccessor(ConditionBlock, KnownVal.isTrue() ? 0 : LoopSuccessor); + + // Add the initialization statements. + Block = createBlock(); + addStmt(S->getBeginEndStmt()); + return addStmt(S->getRangeStmt()); +} + CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E, AddStmtChoice asc) { if (BuildOpts.AddImplicitDtors) { @@ -2407,9 +2649,9 @@ CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E, CFGBlock *CFGBuilder::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E, AddStmtChoice asc) { - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, E)) { autoCreateBlock(); - appendStmt(Block, E, asc); + appendStmt(Block, E); // We do not want to propagate the AlwaysAdd property. asc = asc.withAlwaysAdd(false); @@ -2421,16 +2663,16 @@ CFGBlock *CFGBuilder::VisitCXXConstructExpr(CXXConstructExpr *C, AddStmtChoice asc) { autoCreateBlock(); if (!C->isElidable()) - appendStmt(Block, C, asc.withAlwaysAdd(true)); + appendStmt(Block, C); return VisitChildren(C); } CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E, AddStmtChoice asc) { - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, E)) { autoCreateBlock(); - appendStmt(Block, E, asc); + appendStmt(Block, E); // We do not want to propagate the AlwaysAdd property. asc = asc.withAlwaysAdd(false); } @@ -2440,22 +2682,22 @@ CFGBlock *CFGBuilder::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E, CFGBlock *CFGBuilder::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *C, AddStmtChoice asc) { autoCreateBlock(); - appendStmt(Block, C, asc.withAlwaysAdd(true)); + appendStmt(Block, C); return VisitChildren(C); } CFGBlock *CFGBuilder::VisitCXXMemberCallExpr(CXXMemberCallExpr *C, AddStmtChoice asc) { autoCreateBlock(); - appendStmt(Block, C, asc.withAlwaysAdd(true)); + appendStmt(Block, C); return VisitChildren(C); } CFGBlock *CFGBuilder::VisitImplicitCastExpr(ImplicitCastExpr *E, AddStmtChoice asc) { - if (asc.alwaysAdd()) { + if (asc.alwaysAdd(*this, E)) { autoCreateBlock(); - appendStmt(Block, E, asc); + appendStmt(Block, E); } return Visit(E->getSubExpr(), AddStmtChoice()); } @@ -2699,9 +2941,53 @@ CFGBlock* CFG::createBlock() { /// buildCFG - Constructs a CFG from an AST. Ownership of the returned /// CFG is returned to the caller. CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C, - BuildOptions BO) { - CFGBuilder Builder; - return Builder.buildCFG(D, Statement, C, BO); + const BuildOptions &BO) { + CFGBuilder Builder(C, BO); + return Builder.buildCFG(D, Statement); +} + +const CXXDestructorDecl * +CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { + switch (getKind()) { + case CFGElement::Invalid: + case CFGElement::Statement: + case CFGElement::Initializer: + llvm_unreachable("getDestructorDecl should only be used with " + "ImplicitDtors"); + case CFGElement::AutomaticObjectDtor: { + const VarDecl *var = cast<CFGAutomaticObjDtor>(this)->getVarDecl(); + QualType ty = var->getType(); + ty = ty.getNonReferenceType(); + if (const ArrayType *arrayType = astContext.getAsArrayType(ty)) { + ty = arrayType->getElementType(); + } + const RecordType *recordType = ty->getAs<RecordType>(); + const CXXRecordDecl *classDecl = + cast<CXXRecordDecl>(recordType->getDecl()); + return classDecl->getDestructor(); + } + case CFGElement::TemporaryDtor: { + const CXXBindTemporaryExpr *bindExpr = + cast<CFGTemporaryDtor>(this)->getBindTemporaryExpr(); + const CXXTemporary *temp = bindExpr->getTemporary(); + return temp->getDestructor(); + } + case CFGElement::BaseDtor: + case CFGElement::MemberDtor: + + // Not yet supported. + return 0; + } + llvm_unreachable("getKind() returned bogus value"); + return 0; +} + +bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const { + if (const CXXDestructorDecl *cdecl = getDestructorDecl(astContext)) { + QualType ty = cdecl->getType(); + return cast<FunctionType>(ty)->getNoReturnAttr(); + } + return false; } //===----------------------------------------------------------------------===// @@ -2740,8 +3026,8 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) - if (CFGStmt S = BI->getAs<CFGStmt>()) - FindSubExprAssignments(S, SubExprAssignments); + if (const CFGStmt *S = BI->getAs<CFGStmt>()) + FindSubExprAssignments(S->getStmt(), SubExprAssignments); for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) { @@ -2749,10 +3035,10 @@ static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { // block-level that are block-level expressions. for (CFGBlock::iterator BI=(*I)->begin(), EI=(*I)->end(); BI != EI; ++BI) { - CFGStmt CS = BI->getAs<CFGStmt>(); - if (!CS.isValid()) + const CFGStmt *CS = BI->getAs<CFGStmt>(); + if (!CS) continue; - if (Expr* Exp = dyn_cast<Expr>(CS.getStmt())) { + if (Expr* Exp = dyn_cast<Expr>(CS->getStmt())) { if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) { // Assignment expressions that are not nested within another @@ -2814,15 +3100,15 @@ unsigned CFG::getNumBlkExprs() { bool CFGBlock::FilterEdge(const CFGBlock::FilterOptions &F, const CFGBlock *From, const CFGBlock *To) { - if (F.IgnoreDefaultsWithCoveredEnums) { + if (To && F.IgnoreDefaultsWithCoveredEnums) { // If the 'To' has no label or is labeled but the label isn't a // CaseStmt then filter this edge. if (const SwitchStmt *S = - dyn_cast_or_null<SwitchStmt>(From->getTerminator().getStmt())) { + dyn_cast_or_null<SwitchStmt>(From->getTerminator().getStmt())) { if (S->isAllEnumCasesCovered()) { - const Stmt *L = To->getLabel(); - if (!L || !isa<CaseStmt>(L)) - return true; + const Stmt *L = To->getLabel(); + if (!L || !isa<CaseStmt>(L)) + return true; } } } @@ -2845,8 +3131,8 @@ CFG::~CFG() { namespace { class StmtPrinterHelper : public PrinterHelper { - typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy; - typedef llvm::DenseMap<Decl*,std::pair<unsigned,unsigned> > DeclMapTy; + typedef llvm::DenseMap<const Stmt*,std::pair<unsigned,unsigned> > StmtMapTy; + typedef llvm::DenseMap<const Decl*,std::pair<unsigned,unsigned> > DeclMapTy; StmtMapTy StmtMap; DeclMapTy DeclMap; signed currentBlock; @@ -2855,42 +3141,62 @@ class StmtPrinterHelper : public PrinterHelper { public: StmtPrinterHelper(const CFG* cfg, const LangOptions &LO) - : currentBlock(0), currentStmt(0), LangOpts(LO) { + : currentBlock(0), currentStmt(0), LangOpts(LO) + { for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) { unsigned j = 1; for (CFGBlock::const_iterator BI = (*I)->begin(), BEnd = (*I)->end() ; BI != BEnd; ++BI, ++j ) { - if (CFGStmt SE = BI->getAs<CFGStmt>()) { + if (const CFGStmt *SE = BI->getAs<CFGStmt>()) { + const Stmt *stmt= SE->getStmt(); std::pair<unsigned, unsigned> P((*I)->getBlockID(), j); - StmtMap[SE] = P; - - if (DeclStmt* DS = dyn_cast<DeclStmt>(SE.getStmt())) { - DeclMap[DS->getSingleDecl()] = P; - - } else if (IfStmt* IS = dyn_cast<IfStmt>(SE.getStmt())) { - if (VarDecl* VD = IS->getConditionVariable()) - DeclMap[VD] = P; - - } else if (ForStmt* FS = dyn_cast<ForStmt>(SE.getStmt())) { - if (VarDecl* VD = FS->getConditionVariable()) - DeclMap[VD] = P; - - } else if (WhileStmt* WS = dyn_cast<WhileStmt>(SE.getStmt())) { - if (VarDecl* VD = WS->getConditionVariable()) - DeclMap[VD] = P; - - } else if (SwitchStmt* SS = dyn_cast<SwitchStmt>(SE.getStmt())) { - if (VarDecl* VD = SS->getConditionVariable()) - DeclMap[VD] = P; - - } else if (CXXCatchStmt* CS = dyn_cast<CXXCatchStmt>(SE.getStmt())) { - if (VarDecl* VD = CS->getExceptionDecl()) - DeclMap[VD] = P; + StmtMap[stmt] = P; + + switch (stmt->getStmtClass()) { + case Stmt::DeclStmtClass: + DeclMap[cast<DeclStmt>(stmt)->getSingleDecl()] = P; + break; + case Stmt::IfStmtClass: { + const VarDecl *var = cast<IfStmt>(stmt)->getConditionVariable(); + if (var) + DeclMap[var] = P; + break; + } + case Stmt::ForStmtClass: { + const VarDecl *var = cast<ForStmt>(stmt)->getConditionVariable(); + if (var) + DeclMap[var] = P; + break; + } + case Stmt::WhileStmtClass: { + const VarDecl *var = + cast<WhileStmt>(stmt)->getConditionVariable(); + if (var) + DeclMap[var] = P; + break; + } + case Stmt::SwitchStmtClass: { + const VarDecl *var = + cast<SwitchStmt>(stmt)->getConditionVariable(); + if (var) + DeclMap[var] = P; + break; + } + case Stmt::CXXCatchStmtClass: { + const VarDecl *var = + cast<CXXCatchStmt>(stmt)->getExceptionDecl(); + if (var) + DeclMap[var] = P; + break; + } + default: + break; } } } } } + virtual ~StmtPrinterHelper() {} @@ -2913,7 +3219,7 @@ public: return true; } - bool handleDecl(Decl* D, llvm::raw_ostream& OS) { + bool handleDecl(const Decl* D, llvm::raw_ostream& OS) { DeclMapTy::iterator I = DeclMap.find(D); if (I == DeclMap.end()) @@ -3031,8 +3337,8 @@ public: static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, const CFGElement &E) { - if (CFGStmt CS = E.getAs<CFGStmt>()) { - Stmt *S = CS; + if (const CFGStmt *CS = E.getAs<CFGStmt>()) { + Stmt *S = CS->getStmt(); if (Helper) { @@ -3069,8 +3375,8 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, if (isa<Expr>(S)) OS << '\n'; - } else if (CFGInitializer IE = E.getAs<CFGInitializer>()) { - CXXCtorInitializer* I = IE; + } else if (const CFGInitializer *IE = E.getAs<CFGInitializer>()) { + const CXXCtorInitializer *I = IE->getInitializer(); if (I->isBaseInitializer()) OS << I->getBaseClass()->getAsCXXRecordDecl()->getName(); else OS << I->getAnyMember()->getName(); @@ -3084,8 +3390,8 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, OS << " (Base initializer)\n"; else OS << " (Member initializer)\n"; - } else if (CFGAutomaticObjDtor DE = E.getAs<CFGAutomaticObjDtor>()){ - VarDecl* VD = DE.getVarDecl(); + } else if (const CFGAutomaticObjDtor *DE = E.getAs<CFGAutomaticObjDtor>()){ + const VarDecl* VD = DE->getVarDecl(); Helper->handleDecl(VD, OS); const Type* T = VD->getType().getTypePtr(); @@ -3097,13 +3403,13 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()"; OS << " (Implicit destructor)\n"; - } else if (CFGBaseDtor BE = E.getAs<CFGBaseDtor>()) { - const CXXBaseSpecifier *BS = BE.getBaseSpecifier(); + } else if (const CFGBaseDtor *BE = E.getAs<CFGBaseDtor>()) { + const CXXBaseSpecifier *BS = BE->getBaseSpecifier(); OS << "~" << BS->getType()->getAsCXXRecordDecl()->getName() << "()"; OS << " (Base object destructor)\n"; - } else if (CFGMemberDtor ME = E.getAs<CFGMemberDtor>()) { - FieldDecl *FD = ME.getFieldDecl(); + } else if (const CFGMemberDtor *ME = E.getAs<CFGMemberDtor>()) { + const FieldDecl *FD = ME->getFieldDecl(); const Type *T = FD->getType().getTypePtr(); if (const Type *ET = T->getArrayElementTypeNoTypeQual()) @@ -3113,8 +3419,8 @@ static void print_elem(llvm::raw_ostream &OS, StmtPrinterHelper* Helper, OS << ".~" << T->getAsCXXRecordDecl()->getName() << "()"; OS << " (Member object destructor)\n"; - } else if (CFGTemporaryDtor TE = E.getAs<CFGTemporaryDtor>()) { - CXXBindTemporaryExpr *BT = TE.getBindTemporaryExpr(); + } else if (const CFGTemporaryDtor *TE = E.getAs<CFGTemporaryDtor>()) { + const CXXBindTemporaryExpr *BT = TE->getBindTemporaryExpr(); OS << "~" << BT->getType()->getAsCXXRecordDecl()->getName() << "()"; OS << " (Temporary object destructor)\n"; } @@ -3344,32 +3650,6 @@ Stmt* CFGBlock::getTerminatorCondition() { return E ? E->IgnoreParens() : NULL; } -bool CFGBlock::hasBinaryBranchTerminator() const { - const Stmt *Terminator = this->Terminator; - if (!Terminator) - return false; - - Expr* E = NULL; - - switch (Terminator->getStmtClass()) { - default: - return false; - - case Stmt::ForStmtClass: - case Stmt::WhileStmtClass: - case Stmt::DoStmtClass: - case Stmt::IfStmtClass: - case Stmt::ChooseExprClass: - case Stmt::BinaryConditionalOperatorClass: - case Stmt::ConditionalOperatorClass: - case Stmt::BinaryOperatorClass: - return true; - } - - return E ? E->IgnoreParens() : NULL; -} - - //===----------------------------------------------------------------------===// // CFG Graphviz Visualization //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/CFGReachabilityAnalysis.cpp b/lib/Analysis/CFGReachabilityAnalysis.cpp index 77865849014a..65cd0898573c 100644 --- a/lib/Analysis/CFGReachabilityAnalysis.cpp +++ b/lib/Analysis/CFGReachabilityAnalysis.cpp @@ -19,10 +19,10 @@ using namespace clang; -CFGReachabilityAnalysis::CFGReachabilityAnalysis(const CFG &cfg) +CFGReverseBlockReachabilityAnalysis::CFGReverseBlockReachabilityAnalysis(const CFG &cfg) : analyzed(cfg.getNumBlockIDs(), false) {} -bool CFGReachabilityAnalysis::isReachable(const CFGBlock *Src, +bool CFGReverseBlockReachabilityAnalysis::isReachable(const CFGBlock *Src, const CFGBlock *Dst) { const unsigned DstBlockID = Dst->getBlockID(); @@ -39,7 +39,7 @@ bool CFGReachabilityAnalysis::isReachable(const CFGBlock *Src, // Maps reachability to a common node by walking the predecessors of the // destination node. -void CFGReachabilityAnalysis::mapReachability(const CFGBlock *Dst) { +void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) { llvm::SmallVector<const CFGBlock *, 11> worklist; llvm::BitVector visited(analyzed.size()); diff --git a/lib/Analysis/CFGStmtMap.cpp b/lib/Analysis/CFGStmtMap.cpp index 3a030f9bdd1e..1fd5eedfeb86 100644 --- a/lib/Analysis/CFGStmtMap.cpp +++ b/lib/Analysis/CFGStmtMap.cpp @@ -50,11 +50,11 @@ static void Accumulate(SMap &SM, CFGBlock *B) { // First walk the block-level expressions. for (CFGBlock::iterator I = B->begin(), E = B->end(); I != E; ++I) { const CFGElement &CE = *I; - CFGStmt CS = CE.getAs<CFGStmt>(); - if (!CS.isValid()) + const CFGStmt *CS = CE.getAs<CFGStmt>(); + if (!CS) continue; - CFGBlock *&Entry = SM[CS]; + CFGBlock *&Entry = SM[CS->getStmt()]; // If 'Entry' is already initialized (e.g., a terminator was already), // skip. if (Entry) diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 84b211f2cfca..967fc2930f42 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -13,7 +13,6 @@ add_clang_library(clangAnalysis ReachableCode.cpp ScanfFormatString.cpp UninitializedValues.cpp - UninitializedValuesV2.cpp ) add_dependencies(clangAnalysis ClangAttrClasses ClangAttrList diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp index 22b6c1aaf021..4c62f36e6c92 100644 --- a/lib/Analysis/CocoaConventions.cpp +++ b/lib/Analysis/CocoaConventions.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace ento; @@ -35,84 +36,27 @@ using llvm::StringRef; // not release it." // -static bool isWordEnd(char ch, char prev, char next) { - return ch == '\0' - || (islower(prev) && isupper(ch)) // xxxC - || (isupper(prev) && isupper(ch) && islower(next)) // XXCreate - || !isalpha(ch); -} - -static const char* parseWord(const char* s) { - char ch = *s, prev = '\0'; - assert(ch != '\0'); - char next = *(s+1); - while (!isWordEnd(ch, prev, next)) { - prev = ch; - ch = next; - next = *((++s)+1); - } - return s; -} - -cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S, - bool ignorePrefix) { - IdentifierInfo *II = S.getIdentifierInfoForSlot(0); - - if (!II) - return NoConvention; - - const char *s = II->getNameStart(); - - const char *orig = s; - // A method/function name may contain a prefix. We don't know it is there, - // however, until we encounter the first '_'. - while (*s != '\0') { - // Skip '_', numbers, ':', etc. - if (*s == '_' || !isalpha(*s)) { - ++s; - continue; - } - break; - } - - if (!ignorePrefix && s != orig) +cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) { + switch (S.getMethodFamily()) { + case OMF_None: + case OMF_autorelease: + case OMF_dealloc: + case OMF_release: + case OMF_retain: + case OMF_retainCount: return NoConvention; - // Parse the first word, and look for specific keywords. - const char *wordEnd = parseWord(s); - assert(wordEnd > s); - unsigned len = wordEnd - s; + case OMF_init: + return InitRule; - switch (len) { - default: - return NoConvention; - case 3: - // Methods starting with 'new' follow the create rule. - return (memcmp(s, "new", 3) == 0) ? CreateRule : NoConvention; - case 4: - // Methods starting with 'copy' follow the create rule. - if (memcmp(s, "copy", 4) == 0) - return CreateRule; - // Methods starting with 'init' follow the init rule. - if (memcmp(s, "init", 4) == 0) - return InitRule; - return NoConvention; - case 5: - return (memcmp(s, "alloc", 5) == 0) ? CreateRule : NoConvention; - case 7: - // Methods starting with 'mutableCopy' follow the create rule. - if (memcmp(s, "mutable", 7) == 0) { - // Look at the next word to see if it is "Copy". - s = wordEnd; - if (*s != '\0') { - wordEnd = parseWord(s); - len = wordEnd - s; - if (len == 4 && memcmp(s, "Copy", 4) == 0) - return CreateRule; - } - } - return NoConvention; + case OMF_alloc: + case OMF_copy: + case OMF_mutableCopy: + case OMF_new: + return CreateRule; } + llvm_unreachable("unexpected naming convention"); + return NoConvention; } bool cocoa::isRefType(QualType RetTy, llvm::StringRef Prefix, diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index db9f7f2c834e..00b0b279e4a0 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -381,8 +381,32 @@ bool PrintfSpecifier::fixType(QualType QT) { // Set length modifier switch (BT->getKind()) { - default: - // The rest of the conversions are either optional or for non-builtin types + case BuiltinType::Bool: + case BuiltinType::WChar_U: + case BuiltinType::WChar_S: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::UInt128: + case BuiltinType::Int128: + // Integral types which are non-trivial to correct. + return false; + + case BuiltinType::Void: + case BuiltinType::NullPtr: + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + case BuiltinType::Dependent: + case BuiltinType::Overload: + case BuiltinType::BoundMember: + case BuiltinType::UnknownAny: + // Misc other stuff which doesn't make sense here. + return false; + + case BuiltinType::UInt: + case BuiltinType::Int: + case BuiltinType::Float: + case BuiltinType::Double: LM.setKind(LengthModifier::None); break; @@ -398,8 +422,6 @@ bool PrintfSpecifier::fixType(QualType QT) { LM.setKind(LengthModifier::AsShort); break; - case BuiltinType::WChar_S: - case BuiltinType::WChar_U: case BuiltinType::Long: case BuiltinType::ULong: LM.setKind(LengthModifier::AsLong); @@ -429,24 +451,19 @@ bool PrintfSpecifier::fixType(QualType QT) { else if (QT->isRealFloatingType()) { CS.setKind(ConversionSpecifier::fArg); } - else if (QT->isPointerType()) { - CS.setKind(ConversionSpecifier::pArg); - Precision.setHowSpecified(OptionalAmount::NotSpecified); - HasAlternativeForm = 0; - HasLeadingZeroes = 0; - HasPlusPrefix = 0; - } else if (QT->isSignedIntegerType()) { CS.setKind(ConversionSpecifier::dArg); HasAlternativeForm = 0; } else if (QT->isUnsignedIntegerType()) { - CS.setKind(ConversionSpecifier::uArg); + // Preserve the original formatting, e.g. 'X', 'o'. + if (!cast<PrintfConversionSpecifier>(CS).isUIntArg()) + CS.setKind(ConversionSpecifier::uArg); HasAlternativeForm = 0; HasPlusPrefix = 0; } else { - return false; + assert(0 && "Unexpected type"); } return true; diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp index 7afa586479b3..9ac456f53a67 100644 --- a/lib/Analysis/ReachableCode.cpp +++ b/lib/Analysis/ReachableCode.cpp @@ -31,11 +31,11 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1, R1 = R2 = SourceRange(); if (sn < b.size()) { - CFGStmt CS = b[sn].getAs<CFGStmt>(); + const CFGStmt *CS = b[sn].getAs<CFGStmt>(); if (!CS) return SourceLocation(); - S = CS.getStmt(); + S = CS->getStmt(); } else if (b.getTerminator()) S = b.getTerminator(); else @@ -49,7 +49,7 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1, const BinaryOperator *BO = cast<BinaryOperator>(S); if (BO->getOpcode() == BO_Comma) { if (sn+1 < b.size()) - return b[sn+1].getAs<CFGStmt>().getStmt()->getLocStart(); + return b[sn+1].getAs<CFGStmt>()->getStmt()->getLocStart(); const CFGBlock *n = &b; while (1) { if (n->getTerminator()) @@ -60,7 +60,7 @@ static SourceLocation GetUnreachableLoc(const CFGBlock &b, SourceRange &R1, if (n->pred_size() != 1) return SourceLocation(); if (!n->empty()) - return n[0][0].getAs<CFGStmt>().getStmt()->getLocStart(); + return n[0][0].getAs<CFGStmt>()->getStmt()->getLocStart(); } } R1 = BO->getLHS()->getSourceRange(); @@ -193,7 +193,7 @@ unsigned ScanReachableFromBlock(const CFGBlock &Start, unsigned count = 0; llvm::SmallVector<const CFGBlock*, 32> WL; - // Prep work queue + // Prep work queue Reachable.set(Start.getBlockID()); ++count; WL.push_back(&Start); diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index c08cbedf4b94..88a2db751a43 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -7,311 +7,723 @@ // //===----------------------------------------------------------------------===// // -// This file implements Uninitialized Values analysis for source-level CFGs. +// This file implements uninitialized values analysis for source-level CFGs. // //===----------------------------------------------------------------------===// -#include "clang/Analysis/Analyses/UninitializedValues.h" +#include <utility> +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" +#include "clang/AST/Decl.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" -#include "clang/Analysis/AnalysisDiagnostic.h" -#include "clang/AST/ASTContext.h" -#include "clang/Analysis/FlowSensitive/DataflowSolver.h" - -#include "llvm/ADT/SmallPtrSet.h" +#include "clang/Analysis/Analyses/UninitializedValues.h" +#include "clang/Analysis/Support/SaveAndRestore.h" using namespace clang; -//===----------------------------------------------------------------------===// -// Dataflow initialization logic. -//===----------------------------------------------------------------------===// - -namespace { +static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) { + if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() && + !vd->isExceptionVariable() && + vd->getDeclContext() == dc) { + QualType ty = vd->getType(); + return ty->isScalarType() || ty->isVectorType(); + } + return false; +} -class RegisterDecls - : public CFGRecStmtDeclVisitor<RegisterDecls> { +//------------------------------------------------------------------------====// +// DeclToIndex: a mapping from Decls we track to value indices. +//====------------------------------------------------------------------------// - UninitializedValues::AnalysisDataTy& AD; +namespace { +class DeclToIndex { + llvm::DenseMap<const VarDecl *, unsigned> map; public: - RegisterDecls(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {} - - void VisitVarDecl(VarDecl* VD) { AD.Register(VD); } - CFG& getCFG() { return AD.getCFG(); } + DeclToIndex() {} + + /// Compute the actual mapping from declarations to bits. + void computeMap(const DeclContext &dc); + + /// Return the number of declarations in the map. + unsigned size() const { return map.size(); } + + /// Returns the bit vector index for a given declaration. + llvm::Optional<unsigned> getValueIndex(const VarDecl *d) const; }; +} -} // end anonymous namespace +void DeclToIndex::computeMap(const DeclContext &dc) { + unsigned count = 0; + DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()), + E(dc.decls_end()); + for ( ; I != E; ++I) { + const VarDecl *vd = *I; + if (isTrackedVar(vd, &dc)) + map[vd] = count++; + } +} -void UninitializedValues::InitializeValues(const CFG& cfg) { - RegisterDecls R(getAnalysisData()); - cfg.VisitBlockStmts(R); +llvm::Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) const { + llvm::DenseMap<const VarDecl *, unsigned>::const_iterator I = map.find(d); + if (I == map.end()) + return llvm::Optional<unsigned>(); + return I->second; } -//===----------------------------------------------------------------------===// -// Transfer functions. -//===----------------------------------------------------------------------===// +//------------------------------------------------------------------------====// +// CFGBlockValues: dataflow values for CFG blocks. +//====------------------------------------------------------------------------// -namespace { -class TransferFuncs - : public CFGStmtVisitor<TransferFuncs,bool> { +// These values are defined in such a way that a merge can be done using +// a bitwise OR. +enum Value { Unknown = 0x0, /* 00 */ + Initialized = 0x1, /* 01 */ + Uninitialized = 0x2, /* 10 */ + MayUninitialized = 0x3 /* 11 */ }; - UninitializedValues::ValTy V; - UninitializedValues::AnalysisDataTy& AD; +static bool isUninitialized(const Value v) { + return v >= Uninitialized; +} +static bool isAlwaysUninit(const Value v) { + return v == Uninitialized; +} + +namespace { +class ValueVector { + llvm::BitVector vec; public: - TransferFuncs(UninitializedValues::AnalysisDataTy& ad) : AD(ad) {} + ValueVector() {} + ValueVector(unsigned size) : vec(size << 1) {} + void resize(unsigned n) { vec.resize(n << 1); } + void merge(const ValueVector &rhs) { vec |= rhs.vec; } + bool operator!=(const ValueVector &rhs) const { return vec != rhs.vec; } + void reset() { vec.reset(); } + + class reference { + ValueVector &vv; + const unsigned idx; + + reference(); // Undefined + public: + reference(ValueVector &vv, unsigned idx) : vv(vv), idx(idx) {} + ~reference() {} + + reference &operator=(Value v) { + vv.vec[idx << 1] = (((unsigned) v) & 0x1) ? true : false; + vv.vec[(idx << 1) | 1] = (((unsigned) v) & 0x2) ? true : false; + return *this; + } + operator Value() { + unsigned x = (vv.vec[idx << 1] ? 1 : 0) | (vv.vec[(idx << 1) | 1] ? 2 :0); + return (Value) x; + } + }; + + reference operator[](unsigned idx) { return reference(*this, idx); } +}; - UninitializedValues::ValTy& getVal() { return V; } - CFG& getCFG() { return AD.getCFG(); } +typedef std::pair<ValueVector *, ValueVector *> BVPair; - void SetTopValue(UninitializedValues::ValTy& X) { - X.setDeclValues(AD); - X.resetBlkExprValues(AD); +class CFGBlockValues { + const CFG &cfg; + BVPair *vals; + ValueVector scratch; + DeclToIndex declToIndex; + + ValueVector &lazyCreate(ValueVector *&bv); +public: + CFGBlockValues(const CFG &cfg); + ~CFGBlockValues(); + + unsigned getNumEntries() const { return declToIndex.size(); } + + void computeSetOfDeclarations(const DeclContext &dc); + ValueVector &getValueVector(const CFGBlock *block, + const CFGBlock *dstBlock); + + BVPair &getValueVectors(const CFGBlock *block, bool shouldLazyCreate); + + void mergeIntoScratch(ValueVector const &source, bool isFirst); + bool updateValueVectorWithScratch(const CFGBlock *block); + bool updateValueVectors(const CFGBlock *block, const BVPair &newVals); + + bool hasNoDeclarations() const { + return declToIndex.size() == 0; } + + bool hasEntry(const VarDecl *vd) const { + return declToIndex.getValueIndex(vd).hasValue(); + } + + bool hasValues(const CFGBlock *block); + + void resetScratch(); + ValueVector &getScratch() { return scratch; } + + ValueVector::reference operator[](const VarDecl *vd); +}; +} // end anonymous namespace - bool VisitDeclRefExpr(DeclRefExpr* DR); - bool VisitBinaryOperator(BinaryOperator* B); - bool VisitUnaryOperator(UnaryOperator* U); - bool VisitStmt(Stmt* S); - bool VisitCallExpr(CallExpr* C); - bool VisitDeclStmt(DeclStmt* D); - bool VisitAbstractConditionalOperator(AbstractConditionalOperator* C); - bool BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S); - - bool Visit(Stmt *S); - bool BlockStmt_VisitExpr(Expr* E); +CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) { + unsigned n = cfg.getNumBlockIDs(); + if (!n) + return; + vals = new std::pair<ValueVector*, ValueVector*>[n]; + memset((void*)vals, 0, sizeof(*vals) * n); +} - void VisitTerminator(CFGBlock* B) { } - - void setCurrentBlock(const CFGBlock *block) {} -}; +CFGBlockValues::~CFGBlockValues() { + unsigned n = cfg.getNumBlockIDs(); + if (n == 0) + return; + for (unsigned i = 0; i < n; ++i) { + delete vals[i].first; + delete vals[i].second; + } + delete [] vals; +} -static const bool Initialized = false; -static const bool Uninitialized = true; +void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) { + declToIndex.computeMap(dc); + scratch.resize(declToIndex.size()); +} -bool TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) { +ValueVector &CFGBlockValues::lazyCreate(ValueVector *&bv) { + if (!bv) + bv = new ValueVector(declToIndex.size()); + return *bv; +} - if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) - if (VD->isLocalVarDecl()) { +/// This function pattern matches for a '&&' or '||' that appears at +/// the beginning of a CFGBlock that also (1) has a terminator and +/// (2) has no other elements. If such an expression is found, it is returned. +static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) { + if (block->empty()) + return 0; + + const CFGStmt *cstmt = block->front().getAs<CFGStmt>(); + if (!cstmt) + return 0; + + BinaryOperator *b = llvm::dyn_cast_or_null<BinaryOperator>(cstmt->getStmt()); + + if (!b || !b->isLogicalOp()) + return 0; + + if (block->pred_size() == 2 && + ((block->succ_size() == 2 && block->getTerminatorCondition() == b) || + block->size() == 1)) + return b; + + return 0; +} - if (AD.Observer) - AD.Observer->ObserveDeclRefExpr(V, AD, DR, VD); +ValueVector &CFGBlockValues::getValueVector(const CFGBlock *block, + const CFGBlock *dstBlock) { + unsigned idx = block->getBlockID(); + if (dstBlock && getLogicalOperatorInChain(block)) { + if (*block->succ_begin() == dstBlock) + return lazyCreate(vals[idx].first); + assert(*(block->succ_begin()+1) == dstBlock); + return lazyCreate(vals[idx].second); + } - // Pseudo-hack to prevent cascade of warnings. If an accessed variable - // is uninitialized, then we are already going to flag a warning for - // this variable, which a "source" of uninitialized values. - // We can otherwise do a full "taint" of uninitialized values. The - // client has both options by toggling AD.FullUninitTaint. + assert(vals[idx].second == 0); + return lazyCreate(vals[idx].first); +} - if (AD.FullUninitTaint) - return V(VD,AD); - } +bool CFGBlockValues::hasValues(const CFGBlock *block) { + unsigned idx = block->getBlockID(); + return vals[idx].second != 0; +} - return Initialized; +BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block, + bool shouldLazyCreate) { + unsigned idx = block->getBlockID(); + lazyCreate(vals[idx].first); + if (shouldLazyCreate) + lazyCreate(vals[idx].second); + return vals[idx]; } -static VarDecl* FindBlockVarDecl(Expr* E) { +void CFGBlockValues::mergeIntoScratch(ValueVector const &source, + bool isFirst) { + if (isFirst) + scratch = source; + else + scratch.merge(source); +} +#if 0 +static void printVector(const CFGBlock *block, ValueVector &bv, + unsigned num) { + + llvm::errs() << block->getBlockID() << " :"; + for (unsigned i = 0; i < bv.size(); ++i) { + llvm::errs() << ' ' << bv[i]; + } + llvm::errs() << " : " << num << '\n'; +} +#endif + +bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) { + ValueVector &dst = getValueVector(block, 0); + bool changed = (dst != scratch); + if (changed) + dst = scratch; +#if 0 + printVector(block, scratch, 0); +#endif + return changed; +} - // Blast through casts and parentheses to find any DeclRefExprs that - // refer to a block VarDecl. +bool CFGBlockValues::updateValueVectors(const CFGBlock *block, + const BVPair &newVals) { + BVPair &vals = getValueVectors(block, true); + bool changed = *newVals.first != *vals.first || + *newVals.second != *vals.second; + *vals.first = *newVals.first; + *vals.second = *newVals.second; +#if 0 + printVector(block, *vals.first, 1); + printVector(block, *vals.second, 2); +#endif + return changed; +} - if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts())) - if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) - if (VD->isLocalVarDecl()) return VD; +void CFGBlockValues::resetScratch() { + scratch.reset(); +} - return NULL; +ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) { + const llvm::Optional<unsigned> &idx = declToIndex.getValueIndex(vd); + assert(idx.hasValue()); + return scratch[idx.getValue()]; } -bool TransferFuncs::VisitBinaryOperator(BinaryOperator* B) { +//------------------------------------------------------------------------====// +// Worklist: worklist for dataflow analysis. +//====------------------------------------------------------------------------// - if (VarDecl* VD = FindBlockVarDecl(B->getLHS())) - if (B->isAssignmentOp()) { - if (B->getOpcode() == BO_Assign) - return V(VD,AD) = Visit(B->getRHS()); - else // Handle +=, -=, *=, etc. We do want '&', not '&&'. - return V(VD,AD) = Visit(B->getLHS()) & Visit(B->getRHS()); - } +namespace { +class DataflowWorklist { + llvm::SmallVector<const CFGBlock *, 20> worklist; + llvm::BitVector enqueuedBlocks; +public: + DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {} + + void enqueue(const CFGBlock *block); + void enqueueSuccessors(const CFGBlock *block); + const CFGBlock *dequeue(); + +}; +} - return VisitStmt(B); +void DataflowWorklist::enqueue(const CFGBlock *block) { + if (!block) + return; + unsigned idx = block->getBlockID(); + if (enqueuedBlocks[idx]) + return; + worklist.push_back(block); + enqueuedBlocks[idx] = true; } -bool TransferFuncs::VisitDeclStmt(DeclStmt* S) { - for (DeclStmt::decl_iterator I=S->decl_begin(), E=S->decl_end(); I!=E; ++I) { - VarDecl *VD = dyn_cast<VarDecl>(*I); - if (VD && VD->isLocalVarDecl()) { - if (Stmt* I = VD->getInit()) { - // Visit the subexpression to check for uses of uninitialized values, - // even if we don't propagate that value. - bool isSubExprUninit = Visit(I); - V(VD,AD) = AD.FullUninitTaint ? isSubExprUninit : Initialized; - } - else { - // Special case for declarations of array types. For things like: - // - // char x[10]; - // - // we should treat "x" as being initialized, because the variable - // "x" really refers to the memory block. Clearly x[1] is - // uninitialized, but expressions like "(char *) x" really do refer to - // an initialized value. This simple dataflow analysis does not reason - // about the contents of arrays, although it could be potentially - // extended to do so if the array were of constant size. - if (VD->getType()->isArrayType()) - V(VD,AD) = Initialized; - else - V(VD,AD) = Uninitialized; - } - } +void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) { + for (CFGBlock::const_succ_iterator I = block->succ_begin(), + E = block->succ_end(); I != E; ++I) { + enqueue(*I); } - return Uninitialized; // Value is never consumed. } -bool TransferFuncs::VisitCallExpr(CallExpr* C) { - VisitChildren(C); - return Initialized; +const CFGBlock *DataflowWorklist::dequeue() { + if (worklist.empty()) + return 0; + const CFGBlock *b = worklist.back(); + worklist.pop_back(); + enqueuedBlocks[b->getBlockID()] = false; + return b; } -bool TransferFuncs::VisitUnaryOperator(UnaryOperator* U) { - switch (U->getOpcode()) { - case UO_AddrOf: { - VarDecl* VD = FindBlockVarDecl(U->getSubExpr()); - if (VD && VD->isLocalVarDecl()) - return V(VD,AD) = Initialized; - break; - } +//------------------------------------------------------------------------====// +// Transfer function for uninitialized values analysis. +//====------------------------------------------------------------------------// - default: - break; +namespace { +class FindVarResult { + const VarDecl *vd; + const DeclRefExpr *dr; +public: + FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {} + + const DeclRefExpr *getDeclRefExpr() const { return dr; } + const VarDecl *getDecl() const { return vd; } +}; + +class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> { + CFGBlockValues &vals; + const CFG &cfg; + AnalysisContext ∾ + UninitVariablesHandler *handler; + const DeclRefExpr *currentDR; + const Expr *currentVoidCast; + const bool flagBlockUses; +public: + TransferFunctions(CFGBlockValues &vals, const CFG &cfg, + AnalysisContext &ac, + UninitVariablesHandler *handler, + bool flagBlockUses) + : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0), + currentVoidCast(0), flagBlockUses(flagBlockUses) {} + + const CFG &getCFG() { return cfg; } + void reportUninit(const DeclRefExpr *ex, const VarDecl *vd, + bool isAlwaysUninit); + + void VisitBlockExpr(BlockExpr *be); + void VisitDeclStmt(DeclStmt *ds); + void VisitDeclRefExpr(DeclRefExpr *dr); + void VisitUnaryOperator(UnaryOperator *uo); + void VisitBinaryOperator(BinaryOperator *bo); + void VisitCastExpr(CastExpr *ce); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *se); + void VisitCXXTypeidExpr(CXXTypeidExpr *E); + void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs); + + bool isTrackedVar(const VarDecl *vd) { + return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl())); } - - return Visit(U->getSubExpr()); + + FindVarResult findBlockVarDecl(Expr *ex); +}; } -bool -TransferFuncs::BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { - // This represents a use of the 'collection' - bool x = Visit(S->getCollection()); +void TransferFunctions::reportUninit(const DeclRefExpr *ex, + const VarDecl *vd, bool isAlwaysUnit) { + if (handler) handler->handleUseOfUninitVariable(ex, vd, isAlwaysUnit); +} - if (x == Uninitialized) - return Uninitialized; +FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) { + if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts())) + if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl())) + if (isTrackedVar(vd)) + return FindVarResult(vd, dr); + return FindVarResult(0, 0); +} +void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt( + ObjCForCollectionStmt *fs) { + + Visit(fs->getCollection()); + // This represents an initialization of the 'element' value. - Stmt* Element = S->getElement(); - VarDecl* VD = 0; - - if (DeclStmt* DS = dyn_cast<DeclStmt>(Element)) - VD = cast<VarDecl>(DS->getSingleDecl()); + Stmt *element = fs->getElement(); + const VarDecl* vd = 0; + + if (DeclStmt* ds = dyn_cast<DeclStmt>(element)) { + vd = cast<VarDecl>(ds->getSingleDecl()); + if (!isTrackedVar(vd)) + vd = 0; + } else { - Expr* ElemExpr = cast<Expr>(Element)->IgnoreParens(); - // Initialize the value of the reference variable. - if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(ElemExpr)) - VD = cast<VarDecl>(DR->getDecl()); - else - return Visit(ElemExpr); + const FindVarResult &res = findBlockVarDecl(cast<Expr>(element)); + vd = res.getDecl(); + if (!vd) { + Visit(element); + return; + } } - - V(VD,AD) = Initialized; - return Initialized; + + if (vd) + vals[vd] = Initialized; } - -bool TransferFuncs:: -VisitAbstractConditionalOperator(AbstractConditionalOperator* C) { - Visit(C->getCond()); - - bool rhsResult = Visit(C->getFalseExpr()); - // Handle the GNU extension for missing LHS. - if (isa<ConditionalOperator>(C)) - return Visit(C->getTrueExpr()) & rhsResult; // Yes: we want &, not &&. - else - return rhsResult; +void TransferFunctions::VisitBlockExpr(BlockExpr *be) { + if (!flagBlockUses || !handler) + return; + const BlockDecl *bd = be->getBlockDecl(); + for (BlockDecl::capture_const_iterator i = bd->capture_begin(), + e = bd->capture_end() ; i != e; ++i) { + const VarDecl *vd = i->getVariable(); + if (!vd->hasLocalStorage()) + continue; + if (!isTrackedVar(vd)) + continue; + if (i->isByRef()) { + vals[vd] = Initialized; + continue; + } + Value v = vals[vd]; + if (isUninitialized(v)) + handler->handleUseOfUninitVariable(be, vd, isAlwaysUninit(v)); + } } -bool TransferFuncs::VisitStmt(Stmt* S) { - bool x = Initialized; - - // We don't stop at the first subexpression that is Uninitialized because - // evaluating some subexpressions may result in propogating "Uninitialized" - // or "Initialized" to variables referenced in the other subexpressions. - for (Stmt::child_range I = S->children(); I; ++I) - if (*I && Visit(*I) == Uninitialized) x = Uninitialized; - - return x; +void TransferFunctions::VisitDeclStmt(DeclStmt *ds) { + for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end(); + DI != DE; ++DI) { + if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) { + if (isTrackedVar(vd)) { + if (Expr *init = vd->getInit()) { + Visit(init); + + // If the initializer consists solely of a reference to itself, we + // explicitly mark the variable as uninitialized. This allows code + // like the following: + // + // int x = x; + // + // to deliberately leave a variable uninitialized. Different analysis + // clients can detect this pattern and adjust their reporting + // appropriately, but we need to continue to analyze subsequent uses + // of the variable. + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(init->IgnoreParenImpCasts()); + vals[vd] = (DRE && DRE->getDecl() == vd) ? Uninitialized + : Initialized; + } + } else if (Stmt *init = vd->getInit()) { + Visit(init); + } + } + } } -bool TransferFuncs::Visit(Stmt *S) { - if (AD.isTracked(static_cast<Expr*>(S))) return V(static_cast<Expr*>(S),AD); - else return static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(S); +void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { + // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast + // cannot be block-level expressions. Therefore, we determine if + // a DeclRefExpr is involved in a "load" by comparing it to the current + // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. + // If a DeclRefExpr is not involved in a load, we are essentially computing + // its address, either for assignment to a reference or via the '&' operator. + // In such cases, treat the variable as being initialized, since this + // analysis isn't powerful enough to do alias tracking. + if (dr != currentDR) + if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl())) + if (isTrackedVar(vd)) + vals[vd] = Initialized; } -bool TransferFuncs::BlockStmt_VisitExpr(Expr* E) { - bool x = static_cast<CFGStmtVisitor<TransferFuncs,bool>*>(this)->Visit(E); - if (AD.isTracked(E)) V(E,AD) = x; - return x; +void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) { + if (bo->isAssignmentOp()) { + const FindVarResult &res = findBlockVarDecl(bo->getLHS()); + if (const VarDecl* vd = res.getDecl()) { + // We assume that DeclRefExprs wrapped in a BinaryOperator "assignment" + // cannot be block-level expressions. Therefore, we determine if + // a DeclRefExpr is involved in a "load" by comparing it to the current + // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. + SaveAndRestore<const DeclRefExpr*> lastDR(currentDR, + res.getDeclRefExpr()); + Visit(bo->getRHS()); + Visit(bo->getLHS()); + + ValueVector::reference val = vals[vd]; + if (isUninitialized(val)) { + if (bo->getOpcode() != BO_Assign) + reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); + val = Initialized; + } + return; + } + } + Visit(bo->getRHS()); + Visit(bo->getLHS()); } -} // end anonymous namespace - -//===----------------------------------------------------------------------===// -// Merge operator. -// -// In our transfer functions we take the approach that any -// combination of uninitialized values, e.g. -// Uninitialized + ___ = Uninitialized. -// -// Merges take the same approach, preferring soundness. At a confluence point, -// if any predecessor has a variable marked uninitialized, the value is -// uninitialized at the confluence point. -//===----------------------------------------------------------------------===// - -namespace { - typedef StmtDeclBitVector_Types::Union Merge; - typedef DataflowSolver<UninitializedValues,TransferFuncs,Merge> Solver; +void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) { + switch (uo->getOpcode()) { + case clang::UO_PostDec: + case clang::UO_PostInc: + case clang::UO_PreDec: + case clang::UO_PreInc: { + const FindVarResult &res = findBlockVarDecl(uo->getSubExpr()); + if (const VarDecl *vd = res.getDecl()) { + // We assume that DeclRefExprs wrapped in a unary operator ++/-- + // cannot be block-level expressions. Therefore, we determine if + // a DeclRefExpr is involved in a "load" by comparing it to the current + // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. + SaveAndRestore<const DeclRefExpr*> lastDR(currentDR, + res.getDeclRefExpr()); + Visit(uo->getSubExpr()); + + ValueVector::reference val = vals[vd]; + if (isUninitialized(val)) { + reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); + // Don't cascade warnings. + val = Initialized; + } + return; + } + break; + } + default: + break; + } + Visit(uo->getSubExpr()); } -//===----------------------------------------------------------------------===// -// Uninitialized values checker. Scan an AST and flag variable uses -//===----------------------------------------------------------------------===// - -UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {} - -namespace { -class UninitializedValuesChecker - : public UninitializedValues::ObserverTy { +void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) { + if (ce->getCastKind() == CK_LValueToRValue) { + const FindVarResult &res = findBlockVarDecl(ce->getSubExpr()); + if (const VarDecl *vd = res.getDecl()) { + // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast + // cannot be block-level expressions. Therefore, we determine if + // a DeclRefExpr is involved in a "load" by comparing it to the current + // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. + // Here we update 'currentDR' to be the one associated with this + // lvalue-to-rvalue cast. Then, when we analyze the DeclRefExpr, we + // will know that we are not computing its lvalue for other purposes + // than to perform a load. + SaveAndRestore<const DeclRefExpr*> lastDR(currentDR, + res.getDeclRefExpr()); + Visit(ce->getSubExpr()); + if (currentVoidCast != ce) { + Value val = vals[vd]; + if (isUninitialized(val)) { + reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); + // Don't cascade warnings. + vals[vd] = Initialized; + } + } + return; + } + } + else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) { + if (cse->getType()->isVoidType()) { + // e.g. (void) x; + SaveAndRestore<const Expr *> + lastVoidCast(currentVoidCast, cse->getSubExpr()->IgnoreParens()); + Visit(cse->getSubExpr()); + return; + } + } + Visit(ce->getSubExpr()); +} - ASTContext &Ctx; - Diagnostic &Diags; - llvm::SmallPtrSet<VarDecl*,10> AlreadyWarned; +void TransferFunctions::VisitUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *se) { + if (se->getKind() == UETT_SizeOf) { + if (se->getType()->isConstantSizeType()) + return; + // Handle VLAs. + Visit(se->getArgumentExpr()); + } +} -public: - UninitializedValuesChecker(ASTContext &ctx, Diagnostic &diags) - : Ctx(ctx), Diags(diags) {} +void TransferFunctions::VisitCXXTypeidExpr(CXXTypeidExpr *E) { + // typeid(expression) is potentially evaluated when the argument is + // a glvalue of polymorphic type. (C++ 5.2.8p2-3) + if (!E->isTypeOperand() && E->Classify(ac.getASTContext()).isGLValue()) { + QualType SubExprTy = E->getExprOperand()->getType(); + if (const RecordType *Record = SubExprTy->getAs<RecordType>()) + if (cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic()) + Visit(E->getExprOperand()); + } +} - virtual void ObserveDeclRefExpr(UninitializedValues::ValTy& V, - UninitializedValues::AnalysisDataTy& AD, - DeclRefExpr* DR, VarDecl* VD) { +//------------------------------------------------------------------------====// +// High-level "driver" logic for uninitialized values analysis. +//====------------------------------------------------------------------------// + +static bool runOnBlock(const CFGBlock *block, const CFG &cfg, + AnalysisContext &ac, CFGBlockValues &vals, + llvm::BitVector &wasAnalyzed, + UninitVariablesHandler *handler = 0, + bool flagBlockUses = false) { + + wasAnalyzed[block->getBlockID()] = true; + + if (const BinaryOperator *b = getLogicalOperatorInChain(block)) { + CFGBlock::const_pred_iterator itr = block->pred_begin(); + BVPair vA = vals.getValueVectors(*itr, false); + ++itr; + BVPair vB = vals.getValueVectors(*itr, false); + + BVPair valsAB; + + if (b->getOpcode() == BO_LAnd) { + // Merge the 'F' bits from the first and second. + vals.mergeIntoScratch(*(vA.second ? vA.second : vA.first), true); + vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false); + valsAB.first = vA.first; + valsAB.second = &vals.getScratch(); + } + else { + // Merge the 'T' bits from the first and second. + assert(b->getOpcode() == BO_LOr); + vals.mergeIntoScratch(*vA.first, true); + vals.mergeIntoScratch(*vB.first, false); + valsAB.first = &vals.getScratch(); + valsAB.second = vA.second ? vA.second : vA.first; + } + return vals.updateValueVectors(block, valsAB); + } - assert ( AD.isTracked(VD) && "Unknown VarDecl."); + // Default behavior: merge in values of predecessor blocks. + vals.resetScratch(); + bool isFirst = true; + for (CFGBlock::const_pred_iterator I = block->pred_begin(), + E = block->pred_end(); I != E; ++I) { + vals.mergeIntoScratch(vals.getValueVector(*I, block), isFirst); + isFirst = false; + } + // Apply the transfer function. + TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses); + for (CFGBlock::const_iterator I = block->begin(), E = block->end(); + I != E; ++I) { + if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) { + tf.BlockStmt_Visit(cs->getStmt()); + } + } + return vals.updateValueVectorWithScratch(block); +} - if (V(VD,AD) == Uninitialized) - if (AlreadyWarned.insert(VD)) - Diags.Report(Ctx.getFullLoc(DR->getSourceRange().getBegin()), - diag::warn_uninit_val); +void clang::runUninitializedVariablesAnalysis(const DeclContext &dc, + const CFG &cfg, + AnalysisContext &ac, + UninitVariablesHandler &handler) { + CFGBlockValues vals(cfg); + vals.computeSetOfDeclarations(dc); + if (vals.hasNoDeclarations()) + return; + + // Mark all variables uninitialized at the entry. + const CFGBlock &entry = cfg.getEntry(); + for (CFGBlock::const_succ_iterator i = entry.succ_begin(), + e = entry.succ_end(); i != e; ++i) { + if (const CFGBlock *succ = *i) { + ValueVector &vec = vals.getValueVector(&entry, succ); + const unsigned n = vals.getNumEntries(); + for (unsigned j = 0; j < n ; ++j) { + vec[j] = Uninitialized; + } + } } -}; -} // end anonymous namespace -namespace clang { -void CheckUninitializedValues(CFG& cfg, ASTContext &Ctx, Diagnostic &Diags, - bool FullUninitTaint) { + // Proceed with the workist. + DataflowWorklist worklist(cfg); + llvm::BitVector previouslyVisited(cfg.getNumBlockIDs()); + worklist.enqueueSuccessors(&cfg.getEntry()); + llvm::BitVector wasAnalyzed(cfg.getNumBlockIDs(), false); + + while (const CFGBlock *block = worklist.dequeue()) { + // Did the block change? + bool changed = runOnBlock(block, cfg, ac, vals, wasAnalyzed); + if (changed || !previouslyVisited[block->getBlockID()]) + worklist.enqueueSuccessors(block); + previouslyVisited[block->getBlockID()] = true; + } + + // Run through the blocks one more time, and report uninitialized variabes. + for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) { + if (wasAnalyzed[(*BI)->getBlockID()]) + runOnBlock(*BI, cfg, ac, vals, wasAnalyzed, &handler, + /* flagBlockUses */ true); + } +} - // Compute the uninitialized values information. - UninitializedValues U(cfg); - U.getAnalysisData().FullUninitTaint = FullUninitTaint; - Solver S(U); - S.runOnCFG(cfg); +UninitVariablesHandler::~UninitVariablesHandler() {} - // Scan for DeclRefExprs that use uninitialized values. - UninitializedValuesChecker Observer(Ctx,Diags); - U.getAnalysisData().Observer = &Observer; - S.runOnAllBlocks(cfg); -} -} // end namespace clang diff --git a/lib/Analysis/UninitializedValuesV2.cpp b/lib/Analysis/UninitializedValuesV2.cpp deleted file mode 100644 index 75eccbf7a3c8..000000000000 --- a/lib/Analysis/UninitializedValuesV2.cpp +++ /dev/null @@ -1,610 +0,0 @@ -//==- UninitializedValuesV2.cpp - Find Uninitialized Values -----*- C++ --*-==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements uninitialized values analysis for source-level CFGs. -// -//===----------------------------------------------------------------------===// - -#include <utility> -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/DenseMap.h" -#include "clang/AST/Decl.h" -#include "clang/Analysis/CFG.h" -#include "clang/Analysis/AnalysisContext.h" -#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" -#include "clang/Analysis/Analyses/UninitializedValuesV2.h" -#include "clang/Analysis/Support/SaveAndRestore.h" - -using namespace clang; - -static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) { - return vd->isLocalVarDecl() && !vd->hasGlobalStorage() && - vd->getType()->isScalarType() && - vd->getDeclContext() == dc; -} - -//------------------------------------------------------------------------====// -// DeclToBit: a mapping from Decls we track to bitvector indices. -//====------------------------------------------------------------------------// - -namespace { -class DeclToBit { - llvm::DenseMap<const VarDecl *, unsigned> map; -public: - DeclToBit() {} - - /// Compute the actual mapping from declarations to bits. - void computeMap(const DeclContext &dc); - - /// Return the number of declarations in the map. - unsigned size() const { return map.size(); } - - /// Returns the bit vector index for a given declaration. - llvm::Optional<unsigned> getBitVectorIndex(const VarDecl *d); -}; -} - -void DeclToBit::computeMap(const DeclContext &dc) { - unsigned count = 0; - DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()), - E(dc.decls_end()); - for ( ; I != E; ++I) { - const VarDecl *vd = *I; - if (isTrackedVar(vd, &dc)) - map[vd] = count++; - } -} - -llvm::Optional<unsigned> DeclToBit::getBitVectorIndex(const VarDecl *d) { - llvm::DenseMap<const VarDecl *, unsigned>::iterator I = map.find(d); - if (I == map.end()) - return llvm::Optional<unsigned>(); - return I->second; -} - -//------------------------------------------------------------------------====// -// CFGBlockValues: dataflow values for CFG blocks. -//====------------------------------------------------------------------------// - -typedef std::pair<llvm::BitVector *, llvm::BitVector *> BVPair; - -namespace { -class CFGBlockValues { - const CFG &cfg; - BVPair *vals; - llvm::BitVector scratch; - DeclToBit declToBit; - - llvm::BitVector &lazyCreate(llvm::BitVector *&bv); -public: - CFGBlockValues(const CFG &cfg); - ~CFGBlockValues(); - - void computeSetOfDeclarations(const DeclContext &dc); - llvm::BitVector &getBitVector(const CFGBlock *block, - const CFGBlock *dstBlock); - - BVPair &getBitVectors(const CFGBlock *block, bool shouldLazyCreate); - - void mergeIntoScratch(llvm::BitVector const &source, bool isFirst); - bool updateBitVectorWithScratch(const CFGBlock *block); - bool updateBitVectors(const CFGBlock *block, const BVPair &newVals); - - bool hasNoDeclarations() const { - return declToBit.size() == 0; - } - - void resetScratch(); - llvm::BitVector &getScratch() { return scratch; } - - llvm::BitVector::reference operator[](const VarDecl *vd); -}; -} - -CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) { - unsigned n = cfg.getNumBlockIDs(); - if (!n) - return; - vals = new std::pair<llvm::BitVector*, llvm::BitVector*>[n]; - memset(vals, 0, sizeof(*vals) * n); -} - -CFGBlockValues::~CFGBlockValues() { - unsigned n = cfg.getNumBlockIDs(); - if (n == 0) - return; - for (unsigned i = 0; i < n; ++i) { - delete vals[i].first; - delete vals[i].second; - } - delete [] vals; -} - -void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) { - declToBit.computeMap(dc); - scratch.resize(declToBit.size()); -} - -llvm::BitVector &CFGBlockValues::lazyCreate(llvm::BitVector *&bv) { - if (!bv) - bv = new llvm::BitVector(declToBit.size()); - return *bv; -} - -/// This function pattern matches for a '&&' or '||' that appears at -/// the beginning of a CFGBlock that also (1) has a terminator and -/// (2) has no other elements. If such an expression is found, it is returned. -static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) { - if (block->empty()) - return 0; - - CFGStmt cstmt = block->front().getAs<CFGStmt>(); - BinaryOperator *b = llvm::dyn_cast_or_null<BinaryOperator>(cstmt.getStmt()); - - if (!b || !b->isLogicalOp()) - return 0; - - if (block->pred_size() == 2 && - ((block->succ_size() == 2 && block->getTerminatorCondition() == b) || - block->size() == 1)) - return b; - - return 0; -} - -llvm::BitVector &CFGBlockValues::getBitVector(const CFGBlock *block, - const CFGBlock *dstBlock) { - unsigned idx = block->getBlockID(); - if (dstBlock && getLogicalOperatorInChain(block)) { - if (*block->succ_begin() == dstBlock) - return lazyCreate(vals[idx].first); - assert(*(block->succ_begin()+1) == dstBlock); - return lazyCreate(vals[idx].second); - } - - assert(vals[idx].second == 0); - return lazyCreate(vals[idx].first); -} - -BVPair &CFGBlockValues::getBitVectors(const clang::CFGBlock *block, - bool shouldLazyCreate) { - unsigned idx = block->getBlockID(); - lazyCreate(vals[idx].first); - if (shouldLazyCreate) - lazyCreate(vals[idx].second); - return vals[idx]; -} - -void CFGBlockValues::mergeIntoScratch(llvm::BitVector const &source, - bool isFirst) { - if (isFirst) - scratch = source; - else - scratch |= source; -} -#if 0 -static void printVector(const CFGBlock *block, llvm::BitVector &bv, - unsigned num) { - - llvm::errs() << block->getBlockID() << " :"; - for (unsigned i = 0; i < bv.size(); ++i) { - llvm::errs() << ' ' << bv[i]; - } - llvm::errs() << " : " << num << '\n'; -} -#endif - -bool CFGBlockValues::updateBitVectorWithScratch(const CFGBlock *block) { - llvm::BitVector &dst = getBitVector(block, 0); - bool changed = (dst != scratch); - if (changed) - dst = scratch; -#if 0 - printVector(block, scratch, 0); -#endif - return changed; -} - -bool CFGBlockValues::updateBitVectors(const CFGBlock *block, - const BVPair &newVals) { - BVPair &vals = getBitVectors(block, true); - bool changed = *newVals.first != *vals.first || - *newVals.second != *vals.second; - *vals.first = *newVals.first; - *vals.second = *newVals.second; -#if 0 - printVector(block, *vals.first, 1); - printVector(block, *vals.second, 2); -#endif - return changed; -} - -void CFGBlockValues::resetScratch() { - scratch.reset(); -} - -llvm::BitVector::reference CFGBlockValues::operator[](const VarDecl *vd) { - const llvm::Optional<unsigned> &idx = declToBit.getBitVectorIndex(vd); - assert(idx.hasValue()); - return scratch[idx.getValue()]; -} - -//------------------------------------------------------------------------====// -// Worklist: worklist for dataflow analysis. -//====------------------------------------------------------------------------// - -namespace { -class DataflowWorklist { - llvm::SmallVector<const CFGBlock *, 20> worklist; - llvm::BitVector enqueuedBlocks; -public: - DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {} - - void enqueue(const CFGBlock *block); - void enqueueSuccessors(const CFGBlock *block); - const CFGBlock *dequeue(); - -}; -} - -void DataflowWorklist::enqueue(const CFGBlock *block) { - if (!block) - return; - unsigned idx = block->getBlockID(); - if (enqueuedBlocks[idx]) - return; - worklist.push_back(block); - enqueuedBlocks[idx] = true; -} - -void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) { - for (CFGBlock::const_succ_iterator I = block->succ_begin(), - E = block->succ_end(); I != E; ++I) { - enqueue(*I); - } -} - -const CFGBlock *DataflowWorklist::dequeue() { - if (worklist.empty()) - return 0; - const CFGBlock *b = worklist.back(); - worklist.pop_back(); - enqueuedBlocks[b->getBlockID()] = false; - return b; -} - -//------------------------------------------------------------------------====// -// Transfer function for uninitialized values analysis. -//====------------------------------------------------------------------------// - -static const bool Initialized = false; -static const bool Uninitialized = true; - -namespace { -class FindVarResult { - const VarDecl *vd; - const DeclRefExpr *dr; -public: - FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {} - - const DeclRefExpr *getDeclRefExpr() const { return dr; } - const VarDecl *getDecl() const { return vd; } -}; - -class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> { - CFGBlockValues &vals; - const CFG &cfg; - AnalysisContext ∾ - UninitVariablesHandler *handler; - const DeclRefExpr *currentDR; - const Expr *currentVoidCast; - const bool flagBlockUses; -public: - TransferFunctions(CFGBlockValues &vals, const CFG &cfg, - AnalysisContext &ac, - UninitVariablesHandler *handler, - bool flagBlockUses) - : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0), - currentVoidCast(0), flagBlockUses(flagBlockUses) {} - - const CFG &getCFG() { return cfg; } - void reportUninit(const DeclRefExpr *ex, const VarDecl *vd); - - void VisitBlockExpr(BlockExpr *be); - void VisitDeclStmt(DeclStmt *ds); - void VisitDeclRefExpr(DeclRefExpr *dr); - void VisitUnaryOperator(UnaryOperator *uo); - void VisitBinaryOperator(BinaryOperator *bo); - void VisitCastExpr(CastExpr *ce); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *se); - void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs); - - bool isTrackedVar(const VarDecl *vd) { - return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl())); - } - - FindVarResult findBlockVarDecl(Expr *ex); -}; -} - -void TransferFunctions::reportUninit(const DeclRefExpr *ex, - const VarDecl *vd) { - if (handler) handler->handleUseOfUninitVariable(ex, vd); -} - -FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) { - if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts())) - if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl())) - if (isTrackedVar(vd)) - return FindVarResult(vd, dr); - return FindVarResult(0, 0); -} - -void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt( - ObjCForCollectionStmt *fs) { - - Visit(fs->getCollection()); - - // This represents an initialization of the 'element' value. - Stmt *element = fs->getElement(); - const VarDecl* vd = 0; - - if (DeclStmt* ds = dyn_cast<DeclStmt>(element)) { - vd = cast<VarDecl>(ds->getSingleDecl()); - if (!isTrackedVar(vd)) - vd = 0; - } - else { - // Initialize the value of the reference variable. - const FindVarResult &res = findBlockVarDecl(cast<Expr>(element)); - vd = res.getDecl(); - if (!vd) { - Visit(element); - return; - } - } - - if (vd) - vals[vd] = Initialized; -} - -void TransferFunctions::VisitBlockExpr(BlockExpr *be) { - if (!flagBlockUses || !handler) - return; - AnalysisContext::referenced_decls_iterator i, e; - llvm::tie(i, e) = ac.getReferencedBlockVars(be->getBlockDecl()); - for ( ; i != e; ++i) { - const VarDecl *vd = *i; - if (vd->getAttr<BlocksAttr>() || !vd->hasLocalStorage() || - !isTrackedVar(vd)) - continue; - if (vals[vd] == Uninitialized) - handler->handleUseOfUninitVariable(be, vd); - } -} - -void TransferFunctions::VisitDeclStmt(DeclStmt *ds) { - for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end(); - DI != DE; ++DI) { - if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) { - if (isTrackedVar(vd)) { - vals[vd] = Uninitialized; - if (Stmt *init = vd->getInit()) { - Visit(init); - vals[vd] = Initialized; - } - } - else if (Stmt *init = vd->getInit()) { - Visit(init); - } - } - } -} - -void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { - // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast - // cannot be block-level expressions. Therefore, we determine if - // a DeclRefExpr is involved in a "load" by comparing it to the current - // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. - // If a DeclRefExpr is not involved in a load, we are essentially computing - // its address, either for assignment to a reference or via the '&' operator. - // In such cases, treat the variable as being initialized, since this - // analysis isn't powerful enough to do alias tracking. - if (dr != currentDR) - if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl())) - if (isTrackedVar(vd)) - vals[vd] = Initialized; -} - -void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) { - if (bo->isAssignmentOp()) { - const FindVarResult &res = findBlockVarDecl(bo->getLHS()); - if (const VarDecl* vd = res.getDecl()) { - // We assume that DeclRefExprs wrapped in a BinaryOperator "assignment" - // cannot be block-level expressions. Therefore, we determine if - // a DeclRefExpr is involved in a "load" by comparing it to the current - // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. - SaveAndRestore<const DeclRefExpr*> lastDR(currentDR, - res.getDeclRefExpr()); - Visit(bo->getRHS()); - Visit(bo->getLHS()); - - llvm::BitVector::reference bit = vals[vd]; - if (bit == Uninitialized) { - if (bo->getOpcode() != BO_Assign) - reportUninit(res.getDeclRefExpr(), vd); - bit = Initialized; - } - return; - } - } - Visit(bo->getRHS()); - Visit(bo->getLHS()); -} - -void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) { - switch (uo->getOpcode()) { - case clang::UO_PostDec: - case clang::UO_PostInc: - case clang::UO_PreDec: - case clang::UO_PreInc: { - const FindVarResult &res = findBlockVarDecl(uo->getSubExpr()); - if (const VarDecl *vd = res.getDecl()) { - // We assume that DeclRefExprs wrapped in a unary operator ++/-- - // cannot be block-level expressions. Therefore, we determine if - // a DeclRefExpr is involved in a "load" by comparing it to the current - // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. - SaveAndRestore<const DeclRefExpr*> lastDR(currentDR, - res.getDeclRefExpr()); - Visit(uo->getSubExpr()); - - llvm::BitVector::reference bit = vals[vd]; - if (bit == Uninitialized) { - reportUninit(res.getDeclRefExpr(), vd); - bit = Initialized; - } - return; - } - break; - } - default: - break; - } - Visit(uo->getSubExpr()); -} - -void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) { - if (ce->getCastKind() == CK_LValueToRValue) { - const FindVarResult &res = findBlockVarDecl(ce->getSubExpr()); - if (const VarDecl *vd = res.getDecl()) { - // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast - // cannot be block-level expressions. Therefore, we determine if - // a DeclRefExpr is involved in a "load" by comparing it to the current - // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr. - // Here we update 'currentDR' to be the one associated with this - // lvalue-to-rvalue cast. Then, when we analyze the DeclRefExpr, we - // will know that we are not computing its lvalue for other purposes - // than to perform a load. - SaveAndRestore<const DeclRefExpr*> lastDR(currentDR, - res.getDeclRefExpr()); - Visit(ce->getSubExpr()); - if (currentVoidCast != ce && vals[vd] == Uninitialized) { - reportUninit(res.getDeclRefExpr(), vd); - // Don't cascade warnings. - vals[vd] = Initialized; - } - return; - } - } - else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) { - if (cse->getType()->isVoidType()) { - // e.g. (void) x; - SaveAndRestore<const Expr *> - lastVoidCast(currentVoidCast, cse->getSubExpr()->IgnoreParens()); - Visit(cse->getSubExpr()); - return; - } - } - Visit(ce->getSubExpr()); -} - -void TransferFunctions::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *se) { - if (se->isSizeOf()) { - if (se->getType()->isConstantSizeType()) - return; - // Handle VLAs. - Visit(se->getArgumentExpr()); - } -} - -//------------------------------------------------------------------------====// -// High-level "driver" logic for uninitialized values analysis. -//====------------------------------------------------------------------------// - -static bool runOnBlock(const CFGBlock *block, const CFG &cfg, - AnalysisContext &ac, CFGBlockValues &vals, - UninitVariablesHandler *handler = 0, - bool flagBlockUses = false) { - - if (const BinaryOperator *b = getLogicalOperatorInChain(block)) { - CFGBlock::const_pred_iterator itr = block->pred_begin(); - BVPair vA = vals.getBitVectors(*itr, false); - ++itr; - BVPair vB = vals.getBitVectors(*itr, false); - - BVPair valsAB; - - if (b->getOpcode() == BO_LAnd) { - // Merge the 'F' bits from the first and second. - vals.mergeIntoScratch(*(vA.second ? vA.second : vA.first), true); - vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false); - valsAB.first = vA.first; - valsAB.second = &vals.getScratch(); - } - else { - // Merge the 'T' bits from the first and second. - assert(b->getOpcode() == BO_LOr); - vals.mergeIntoScratch(*vA.first, true); - vals.mergeIntoScratch(*vB.first, false); - valsAB.first = &vals.getScratch(); - valsAB.second = vA.second ? vA.second : vA.first; - } - return vals.updateBitVectors(block, valsAB); - } - - // Default behavior: merge in values of predecessor blocks. - vals.resetScratch(); - bool isFirst = true; - for (CFGBlock::const_pred_iterator I = block->pred_begin(), - E = block->pred_end(); I != E; ++I) { - vals.mergeIntoScratch(vals.getBitVector(*I, block), isFirst); - isFirst = false; - } - // Apply the transfer function. - TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses); - for (CFGBlock::const_iterator I = block->begin(), E = block->end(); - I != E; ++I) { - if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) { - tf.BlockStmt_Visit(cs->getStmt()); - } - } - return vals.updateBitVectorWithScratch(block); -} - -void clang::runUninitializedVariablesAnalysis(const DeclContext &dc, - const CFG &cfg, - AnalysisContext &ac, - UninitVariablesHandler &handler) { - CFGBlockValues vals(cfg); - vals.computeSetOfDeclarations(dc); - if (vals.hasNoDeclarations()) - return; - DataflowWorklist worklist(cfg); - llvm::BitVector previouslyVisited(cfg.getNumBlockIDs()); - - worklist.enqueueSuccessors(&cfg.getEntry()); - - while (const CFGBlock *block = worklist.dequeue()) { - // Did the block change? - bool changed = runOnBlock(block, cfg, ac, vals); - if (changed || !previouslyVisited[block->getBlockID()]) - worklist.enqueueSuccessors(block); - previouslyVisited[block->getBlockID()] = true; - } - - // Run through the blocks one more time, and report uninitialized variabes. - for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) { - runOnBlock(*BI, cfg, ac, vals, &handler, /* flagBlockUses */ true); - } -} - -UninitVariablesHandler::~UninitVariablesHandler() {} - diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt index 91e7deb078ad..c1e7cf6bf971 100644 --- a/lib/Basic/CMakeLists.txt +++ b/lib/Basic/CMakeLists.txt @@ -14,6 +14,7 @@ add_clang_library(clangBasic Targets.cpp TokenKinds.cpp Version.cpp + VersionTuple.cpp ) # Determine Subversion revision. @@ -39,5 +40,6 @@ add_dependencies(clangBasic ClangDiagnosticGroups ClangDiagnosticLex ClangDiagnosticParse - ClangDiagnosticSema) + ClangDiagnosticSema + ClangDiagnosticIndexName) diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 31e33315cce2..e8cd21885d22 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -16,6 +16,8 @@ #include "clang/Basic/PartialDiagnostic.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/CrashRecoveryContext.h" + using namespace clang; static void DummyArgToStringFn(Diagnostic::ArgumentKind AK, intptr_t QT, @@ -49,11 +51,6 @@ Diagnostic::Diagnostic(const llvm::IntrusiveRefCntPtr<DiagnosticIDs> &diags, ErrorLimit = 0; TemplateBacktraceLimit = 0; - // Create a DiagState and DiagStatePoint representing diagnostic changes - // through command-line. - DiagStates.push_back(DiagState()); - PushDiagStatePoint(&DiagStates.back(), SourceLocation()); - Reset(); } @@ -100,6 +97,16 @@ void Diagnostic::Reset() { // displayed. LastDiagLevel = (DiagnosticIDs::Level)-1; DelayedDiagID = 0; + + // Clear state related to #pragma diagnostic. + DiagStates.clear(); + DiagStatePoints.clear(); + DiagStateOnPushStack.clear(); + + // Create a DiagState and DiagStatePoint representing diagnostic changes + // through command-line. + DiagStates.push_back(DiagState()); + PushDiagStatePoint(&DiagStates.back(), SourceLocation()); } void Diagnostic::SetDelayedDiagnostic(unsigned DiagID, llvm::StringRef Arg1, @@ -168,7 +175,7 @@ void Diagnostic::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, // after the previous one. if ((Loc.isValid() && LastStateChangePos.isInvalid()) || LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) { - // A diagnostic pragma occured, create a new DiagState initialized with + // A diagnostic pragma occurred, create a new DiagState initialized with // the current one and a new DiagStatePoint to record at which location // the new state became active. DiagStates.push_back(*GetCurDiagState()); @@ -683,5 +690,7 @@ PartialDiagnostic::StorageAllocator::StorageAllocator() { } PartialDiagnostic::StorageAllocator::~StorageAllocator() { - assert(NumFreeListEntries == NumCached && "A partial is on the lamb"); + // Don't assert if we are in a CrashRecovery context, as this + // invariant may be invalidated during a crash. + assert((NumFreeListEntries == NumCached || llvm::CrashRecoveryContext::isRecoveringFromCrash()) && "A partial is on the lamb"); } diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp index 553e4c929454..b4dd575a9684 100644 --- a/lib/Basic/DiagnosticIDs.cpp +++ b/lib/Basic/DiagnosticIDs.cpp @@ -46,19 +46,41 @@ struct StaticDiagInfoRec { unsigned AccessControl : 1; unsigned Category : 5; + const char *Name; + const char *Description; const char *OptionGroup; + const char *BriefExplanation; + const char *FullExplanation; + bool operator<(const StaticDiagInfoRec &RHS) const { return DiagID < RHS.DiagID; } }; +struct StaticDiagNameIndexRec { + const char *Name; + unsigned short DiagID; + + bool operator<(const StaticDiagNameIndexRec &RHS) const { + assert(Name && RHS.Name && "Null Diagnostic Name"); + return strcmp(Name, RHS.Name) == -1; + } + + bool operator==(const StaticDiagNameIndexRec &RHS) const { + assert(Name && RHS.Name && "Null Diagnostic Name"); + return strcmp(Name, RHS.Name) == 0; + } +}; + } static const StaticDiagInfoRec StaticDiagInfo[] = { -#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,SFINAE,ACCESS,CATEGORY) \ - { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS, CATEGORY, DESC, GROUP }, +#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP, \ + SFINAE,ACCESS,CATEGORY,BRIEF,FULL) \ + { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, \ + ACCESS, CATEGORY, #ENUM, DESC, GROUP, BRIEF, FULL }, #include "clang/Basic/DiagnosticCommonKinds.inc" #include "clang/Basic/DiagnosticDriverKinds.inc" #include "clang/Basic/DiagnosticFrontendKinds.inc" @@ -67,20 +89,32 @@ static const StaticDiagInfoRec StaticDiagInfo[] = { #include "clang/Basic/DiagnosticASTKinds.inc" #include "clang/Basic/DiagnosticSemaKinds.inc" #include "clang/Basic/DiagnosticAnalysisKinds.inc" - { 0, 0, 0, 0, 0, 0, 0, 0} -}; #undef DIAG + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +}; + +static const unsigned StaticDiagInfoSize = + sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1; + +/// To be sorted before first use (since it's splitted among multiple files) +static StaticDiagNameIndexRec StaticDiagNameIndex[] = { +#define DIAG_NAME_INDEX(ENUM) { #ENUM, diag::ENUM }, +#include "clang/Basic/DiagnosticIndexName.inc" +#undef DIAG_NAME_INDEX + { 0, 0 } +}; + +static const unsigned StaticDiagNameIndexSize = + sizeof(StaticDiagNameIndex)/sizeof(StaticDiagNameIndex[0])-1; /// GetDiagInfo - Return the StaticDiagInfoRec entry for the specified DiagID, /// or null if the ID is invalid. static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { - unsigned NumDiagEntries = sizeof(StaticDiagInfo)/sizeof(StaticDiagInfo[0])-1; - // If assertions are enabled, verify that the StaticDiagInfo array is sorted. #ifndef NDEBUG static bool IsFirst = true; if (IsFirst) { - for (unsigned i = 1; i != NumDiagEntries; ++i) { + for (unsigned i = 1; i != StaticDiagInfoSize; ++i) { assert(StaticDiagInfo[i-1].DiagID != StaticDiagInfo[i].DiagID && "Diag ID conflict, the enums at the start of clang::diag (in " "DiagnosticIDs.h) probably need to be increased"); @@ -93,11 +127,11 @@ static const StaticDiagInfoRec *GetDiagInfo(unsigned DiagID) { #endif // Search the diagnostic table with a binary search. - StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0 }; + StaticDiagInfoRec Find = { DiagID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const StaticDiagInfoRec *Found = - std::lower_bound(StaticDiagInfo, StaticDiagInfo + NumDiagEntries, Find); - if (Found == StaticDiagInfo + NumDiagEntries || + std::lower_bound(StaticDiagInfo, StaticDiagInfo + StaticDiagInfoSize, Find); + if (Found == StaticDiagInfo + StaticDiagInfoSize || Found->DiagID != DiagID) return 0; @@ -119,7 +153,7 @@ const char *DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) { return 0; } -/// getWarningOptionForDiag - Return the category number that a specified +/// getCategoryNumberForDiag - Return the category number that a specified /// DiagID belongs to, or 0 if no category. unsigned DiagnosticIDs::getCategoryNumberForDiag(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) @@ -167,7 +201,48 @@ DiagnosticIDs::getDiagnosticSFINAEResponse(unsigned DiagID) { return SFINAE_Report; } -/// getDiagClass - Return the class field of the diagnostic. +/// getName - Given a diagnostic ID, return its name +const char *DiagnosticIDs::getName(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->Name; + return 0; +} + +/// getIdFromName - Given a diagnostic name, return its ID, or 0 +unsigned DiagnosticIDs::getIdFromName(char const *Name) { + StaticDiagNameIndexRec *StaticDiagNameIndexEnd = + StaticDiagNameIndex + StaticDiagNameIndexSize; + + if (Name == 0) { return diag::DIAG_UPPER_LIMIT; } + + StaticDiagNameIndexRec Find = { Name, 0 }; + + const StaticDiagNameIndexRec *Found = + std::lower_bound( StaticDiagNameIndex, StaticDiagNameIndexEnd, Find); + if (Found == StaticDiagNameIndexEnd || + strcmp(Found->Name, Name) != 0) + return diag::DIAG_UPPER_LIMIT; + + return Found->DiagID; +} + +/// getBriefExplanation - Given a diagnostic ID, return a brief explanation +/// of the issue +const char *DiagnosticIDs::getBriefExplanation(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->BriefExplanation; + return 0; +} + +/// getFullExplanation - Given a diagnostic ID, return a full explanation +/// of the issue +const char *DiagnosticIDs::getFullExplanation(unsigned DiagID) { + if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) + return Info->FullExplanation; + return 0; +} + +/// getBuiltinDiagClass - Return the class field of the diagnostic. /// static unsigned getBuiltinDiagClass(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) @@ -329,6 +404,8 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass, if (mapping) *mapping = (diag::Mapping) (MappingInfo & 7); + bool ShouldEmitInSystemHeader = false; + switch (MappingInfo & 7) { default: assert(0 && "Unknown mapping!"); case diag::MAP_IGNORE: @@ -351,6 +428,9 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass, case diag::MAP_FATAL: Result = DiagnosticIDs::Fatal; break; + case diag::MAP_WARNING_SHOW_IN_SYSTEM_HEADER: + ShouldEmitInSystemHeader = true; + // continue as MAP_WARNING. case diag::MAP_WARNING: // If warnings are globally mapped to ignore or error, do it. if (Diag.IgnoreAllWarnings) @@ -395,6 +475,20 @@ DiagnosticIDs::getDiagnosticLevel(unsigned DiagID, unsigned DiagClass, if (Diag.AllExtensionsSilenced && isBuiltinExtensionDiag(DiagID)) return DiagnosticIDs::Ignored; + // If we are in a system header, we ignore it. + // We also want to ignore extensions and warnings in -Werror and + // -pedantic-errors modes, which *map* warnings/extensions to errors. + if (Result >= DiagnosticIDs::Warning && + DiagClass != CLASS_ERROR && + // Custom diagnostics always are emitted in system headers. + DiagID < diag::DIAG_UPPER_LIMIT && + !ShouldEmitInSystemHeader && + Diag.SuppressSystemWarnings && + Loc.isValid() && + Diag.getSourceManager().isInSystemHeader( + Diag.getSourceManager().getInstantiationLoc(Loc))) + return DiagnosticIDs::Ignored; + return Result; } @@ -480,16 +574,9 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { DiagnosticIDs::Level DiagLevel; unsigned DiagID = Info.getID(); - // ShouldEmitInSystemHeader - True if this diagnostic should be produced even - // in a system header. - bool ShouldEmitInSystemHeader; - if (DiagID >= diag::DIAG_UPPER_LIMIT) { // Handle custom diagnostics, which cannot be mapped. DiagLevel = CustomDiagInfo->getLevel(DiagID); - - // Custom diagnostics always are emitted in system headers. - ShouldEmitInSystemHeader = true; } else { // Get the class of the diagnostic. If this is a NOTE, map it onto whatever // the diagnostic level was for the previous diagnostic so that it is @@ -497,14 +584,7 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { unsigned DiagClass = getBuiltinDiagClass(DiagID); if (DiagClass == CLASS_NOTE) { DiagLevel = DiagnosticIDs::Note; - ShouldEmitInSystemHeader = false; // extra consideration is needed } else { - // If this is not an error and we are in a system header, we ignore it. - // Check the original Diag ID here, because we also want to ignore - // extensions and warnings in -Werror and -pedantic-errors modes, which - // *map* warnings/extensions to errors. - ShouldEmitInSystemHeader = DiagClass == CLASS_ERROR; - DiagLevel = getDiagnosticLevel(DiagID, DiagClass, Info.getLocation(), Diag); } @@ -540,18 +620,6 @@ bool DiagnosticIDs::ProcessDiag(Diagnostic &Diag) const { Diag.LastDiagLevel == DiagnosticIDs::Ignored)) return false; - // If this diagnostic is in a system header and is not a clang error, suppress - // it. - if (Diag.SuppressSystemWarnings && !ShouldEmitInSystemHeader && - Info.getLocation().isValid() && - Diag.getSourceManager().isInSystemHeader( - Diag.getSourceManager().getInstantiationLoc(Info.getLocation())) && - (DiagLevel != DiagnosticIDs::Note || - Diag.LastDiagLevel == DiagnosticIDs::Ignored)) { - Diag.LastDiagLevel = DiagnosticIDs::Ignored; - return false; - } - if (DiagLevel >= DiagnosticIDs::Error) { if (Diag.Client->IncludeInDiagnosticCounts()) { Diag.ErrorOccurred = true; diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index 342413d7da52..4e5a129082f4 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -313,7 +313,7 @@ const DirectoryEntry *FileManager::getDirectory(llvm::StringRef DirName) { /// getFile - Lookup, cache, and verify the specified file (real or /// virtual). This returns NULL if the file doesn't exist. /// -const FileEntry *FileManager::getFile(llvm::StringRef Filename) { +const FileEntry *FileManager::getFile(llvm::StringRef Filename, bool openFile) { ++NumFileLookups; // See if there is already an entry in the map. @@ -354,6 +354,11 @@ const FileEntry *FileManager::getFile(llvm::StringRef Filename) { return 0; } + if (FileDescriptor != -1 && !openFile) { + close(FileDescriptor); + FileDescriptor = -1; + } + // It exists. See if we have already opened a file with the same inode. // This occurs when one dir is symlinked to another, for example. FileEntry &UFE = UniqueRealFiles.getFile(InterndFileName, StatBuf); @@ -450,13 +455,15 @@ FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size, return UFE; } -void FileManager::FixupRelativePath(llvm::sys::Path &path, - const FileSystemOptions &FSOpts) { - if (FSOpts.WorkingDir.empty() || llvm::sys::path::is_absolute(path.str())) +void FileManager::FixupRelativePath(llvm::SmallVectorImpl<char> &path) const { + llvm::StringRef pathRef(path.data(), path.size()); + + if (FileSystemOpts.WorkingDir.empty() + || llvm::sys::path::is_absolute(pathRef)) return; - llvm::SmallString<128> NewPath(FSOpts.WorkingDir); - llvm::sys::path::append(NewPath, path.str()); + llvm::SmallString<128> NewPath(FileSystemOpts.WorkingDir); + llvm::sys::path::append(NewPath, pathRef); path = NewPath; } @@ -464,30 +471,32 @@ llvm::MemoryBuffer *FileManager:: getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) { llvm::OwningPtr<llvm::MemoryBuffer> Result; llvm::error_code ec; - if (FileSystemOpts.WorkingDir.empty()) { - const char *Filename = Entry->getName(); - // If the file is already open, use the open file descriptor. - if (Entry->FD != -1) { - ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result, - Entry->getSize()); - if (ErrorStr) - *ErrorStr = ec.message(); - - close(Entry->FD); - Entry->FD = -1; - return Result.take(); - } - // Otherwise, open the file. + const char *Filename = Entry->getName(); + // If the file is already open, use the open file descriptor. + if (Entry->FD != -1) { + ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result, + Entry->getSize()); + if (ErrorStr) + *ErrorStr = ec.message(); + + close(Entry->FD); + Entry->FD = -1; + return Result.take(); + } + + // Otherwise, open the file. + + if (FileSystemOpts.WorkingDir.empty()) { ec = llvm::MemoryBuffer::getFile(Filename, Result, Entry->getSize()); if (ec && ErrorStr) *ErrorStr = ec.message(); return Result.take(); } - - llvm::sys::Path FilePath(Entry->getName()); - FixupRelativePath(FilePath, FileSystemOpts); - ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result, Entry->getSize()); + + llvm::SmallString<128> FilePath(Entry->getName()); + FixupRelativePath(FilePath); + ec = llvm::MemoryBuffer::getFile(FilePath.str(), Result, Entry->getSize()); if (ec && ErrorStr) *ErrorStr = ec.message(); return Result.take(); @@ -504,8 +513,8 @@ getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) { return Result.take(); } - llvm::sys::Path FilePath(Filename); - FixupRelativePath(FilePath, FileSystemOpts); + llvm::SmallString<128> FilePath(Filename); + FixupRelativePath(FilePath); ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result); if (ec && ErrorStr) *ErrorStr = ec.message(); @@ -525,13 +534,21 @@ bool FileManager::getStatValue(const char *Path, struct stat &StatBuf, return FileSystemStatCache::get(Path, StatBuf, FileDescriptor, StatCache.get()); - llvm::sys::Path FilePath(Path); - FixupRelativePath(FilePath, FileSystemOpts); + llvm::SmallString<128> FilePath(Path); + FixupRelativePath(FilePath); return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor, StatCache.get()); } +bool FileManager::getNoncachedStatValue(llvm::StringRef Path, + struct stat &StatBuf) { + llvm::SmallString<128> FilePath(Path); + FixupRelativePath(FilePath); + + return ::stat(FilePath.c_str(), &StatBuf) != 0; +} + void FileManager::GetUniqueIDMapping( llvm::SmallVectorImpl<const FileEntry *> &UIDToFiles) const { UIDToFiles.clear(); diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index ef11d658ed9e..cb1f55b75773 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -81,17 +81,18 @@ IdentifierTable::IdentifierTable(const LangOptions &LangOpts, // Constants for TokenKinds.def namespace { enum { - KEYALL = 1, - KEYC99 = 2, - KEYCXX = 4, - KEYCXX0X = 8, - KEYGNU = 16, - KEYMS = 32, - BOOLSUPPORT = 64, - KEYALTIVEC = 128, - KEYNOCXX = 256, - KEYBORLAND = 512, - KEYOPENCL = 1024 + KEYC99 = 0x1, + KEYCXX = 0x2, + KEYCXX0X = 0x4, + KEYGNU = 0x8, + KEYMS = 0x10, + BOOLSUPPORT = 0x20, + KEYALTIVEC = 0x40, + KEYNOCXX = 0x80, + KEYBORLAND = 0x100, + KEYOPENCL = 0x200, + KEYC1X = 0x400, + KEYALL = 0x7ff }; } @@ -107,7 +108,7 @@ static void AddKeyword(llvm::StringRef Keyword, tok::TokenKind TokenCode, unsigned Flags, const LangOptions &LangOpts, IdentifierTable &Table) { unsigned AddResult = 0; - if (Flags & KEYALL) AddResult = 2; + if (Flags == KEYALL) AddResult = 2; else if (LangOpts.CPlusPlus && (Flags & KEYCXX)) AddResult = 2; else if (LangOpts.CPlusPlus0x && (Flags & KEYCXX0X)) AddResult = 2; else if (LangOpts.C99 && (Flags & KEYC99)) AddResult = 2; @@ -118,6 +119,7 @@ static void AddKeyword(llvm::StringRef Keyword, else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2; else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2; else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2; + else if (LangOpts.C1X && (Flags & KEYC1X)) AddResult = 2; // Don't add this keyword if disabled in this language. if (AddResult == 0) return; @@ -162,7 +164,12 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { #define OBJC2_AT_KEYWORD(NAME) \ if (LangOpts.ObjC2) \ AddObjCKeyword(llvm::StringRef(#NAME), tok::objc_##NAME, *this); +#define TESTING_KEYWORD(NAME, FLAGS) #include "clang/Basic/TokenKinds.def" + + if (LangOpts.ParseUnknownAnytype) + AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL, + LangOpts, *this); } tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { @@ -364,6 +371,56 @@ std::string Selector::getAsString() const { return reinterpret_cast<MultiKeywordSelector *>(InfoPtr)->getName(); } +/// Interpreting the given string using the normal CamelCase +/// conventions, determine whether the given string starts with the +/// given "word", which is assumed to end in a lowercase letter. +static bool startsWithWord(llvm::StringRef name, llvm::StringRef word) { + if (name.size() < word.size()) return false; + return ((name.size() == word.size() || + !islower(name[word.size()])) + && name.startswith(word)); +} + +ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { + IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); + if (!first) return OMF_None; + + llvm::StringRef name = first->getName(); + if (sel.isUnarySelector()) { + if (name == "autorelease") return OMF_autorelease; + if (name == "dealloc") return OMF_dealloc; + if (name == "release") return OMF_release; + if (name == "retain") return OMF_retain; + if (name == "retainCount") return OMF_retainCount; + } + + // The other method families may begin with a prefix of underscores. + while (!name.empty() && name.front() == '_') + name = name.substr(1); + + if (name.empty()) return OMF_None; + switch (name.front()) { + case 'a': + if (startsWithWord(name, "alloc")) return OMF_alloc; + break; + case 'c': + if (startsWithWord(name, "copy")) return OMF_copy; + break; + case 'i': + if (startsWithWord(name, "init")) return OMF_init; + break; + case 'm': + if (startsWithWord(name, "mutableCopy")) return OMF_mutableCopy; + break; + case 'n': + if (startsWithWord(name, "new")) return OMF_new; + break; + default: + break; + } + + return OMF_None; +} namespace { struct SelectorTableImpl { @@ -376,6 +433,10 @@ static SelectorTableImpl &getSelectorTableImpl(void *P) { return *static_cast<SelectorTableImpl*>(P); } +size_t SelectorTable::getTotalMemory() const { + SelectorTableImpl &SelTabImpl = getSelectorTableImpl(Impl); + return SelTabImpl.Allocator.getTotalMemory(); +} Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { if (nKeys < 2) diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index e2783ba6fda2..c3e03933e5e5 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -46,13 +46,26 @@ unsigned ContentCache::getSizeBytesMapped() const { return Buffer.getPointer() ? Buffer.getPointer()->getBufferSize() : 0; } +/// Returns the kind of memory used to back the memory buffer for +/// this content cache. This is used for performance analysis. +llvm::MemoryBuffer::BufferKind ContentCache::getMemoryBufferKind() const { + assert(Buffer.getPointer()); + + // Should be unreachable, but keep for sanity. + if (!Buffer.getPointer()) + return llvm::MemoryBuffer::MemoryBuffer_Malloc; + + const llvm::MemoryBuffer *buf = Buffer.getPointer(); + return buf->getBufferKind(); +} + /// getSize - Returns the size of the content encapsulated by this ContentCache. /// This can be the size of the source file or the size of an arbitrary /// scratch buffer. If the ContentCache encapsulates a source file, that /// file is not lazily brought in from disk to satisfy this query. unsigned ContentCache::getSize() const { return Buffer.getPointer() ? (unsigned) Buffer.getPointer()->getBufferSize() - : (unsigned) Entry->getSize(); + : (unsigned) ContentsEntry->getSize(); } void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B, @@ -70,8 +83,8 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, SourceLocation Loc, bool *Invalid) const { // Lazily create the Buffer for ContentCaches that wrap files. If we already - // computed it, jsut return what we have. - if (Buffer.getPointer() || Entry == 0) { + // computed it, just return what we have. + if (Buffer.getPointer() || ContentsEntry == 0) { if (Invalid) *Invalid = isBufferInvalid(); @@ -79,7 +92,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, } std::string ErrorStr; - Buffer.setPointer(SM.getFileManager().getBufferForFile(Entry, &ErrorStr)); + Buffer.setPointer(SM.getFileManager().getBufferForFile(ContentsEntry, &ErrorStr)); // If we were unable to open the file, then we are in an inconsistent // situation where the content cache referenced a file which no longer @@ -93,18 +106,18 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, // possible. if (!Buffer.getPointer()) { const llvm::StringRef FillStr("<<<MISSING SOURCE FILE>>>\n"); - Buffer.setPointer(MemoryBuffer::getNewMemBuffer(Entry->getSize(), + Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(), "<invalid>")); char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart()); - for (unsigned i = 0, e = Entry->getSize(); i != e; ++i) + for (unsigned i = 0, e = ContentsEntry->getSize(); i != e; ++i) Ptr[i] = FillStr[i % FillStr.size()]; if (Diag.isDiagnosticInFlight()) Diag.SetDelayedDiagnostic(diag::err_cannot_open_file, - Entry->getName(), ErrorStr); + ContentsEntry->getName(), ErrorStr); else Diag.Report(Loc, diag::err_cannot_open_file) - << Entry->getName() << ErrorStr; + << ContentsEntry->getName() << ErrorStr; Buffer.setInt(Buffer.getInt() | InvalidFlag); @@ -114,25 +127,24 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, // Check that the file's size is the same as in the file entry (which may // have come from a stat cache). - if (getRawBuffer()->getBufferSize() != (size_t)Entry->getSize()) { + if (getRawBuffer()->getBufferSize() != (size_t)ContentsEntry->getSize()) { if (Diag.isDiagnosticInFlight()) Diag.SetDelayedDiagnostic(diag::err_file_modified, - Entry->getName()); + ContentsEntry->getName()); else Diag.Report(Loc, diag::err_file_modified) - << Entry->getName(); + << ContentsEntry->getName(); Buffer.setInt(Buffer.getInt() | InvalidFlag); if (Invalid) *Invalid = true; return Buffer.getPointer(); } - + // If the buffer is valid, check to see if it has a UTF Byte Order Mark - // (BOM). We only support UTF-8 without a BOM right now. See + // (BOM). We only support UTF-8 with and without a BOM right now. See // http://en.wikipedia.org/wiki/Byte_order_mark for more information. llvm::StringRef BufStr = Buffer.getPointer()->getBuffer(); - const char *BOM = llvm::StringSwitch<const char *>(BufStr) - .StartsWith("\xEF\xBB\xBF", "UTF-8") + const char *InvalidBOM = llvm::StringSwitch<const char *>(BufStr) .StartsWith("\xFE\xFF", "UTF-16 (BE)") .StartsWith("\xFF\xFE", "UTF-16 (LE)") .StartsWith("\x00\x00\xFE\xFF", "UTF-32 (BE)") @@ -145,9 +157,9 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(Diagnostic &Diag, .StartsWith("\x84\x31\x95\x33", "GB-18030") .Default(0); - if (BOM) { + if (InvalidBOM) { Diag.Report(Loc, diag::err_unsupported_bom) - << BOM << Entry->getName(); + << InvalidBOM << ContentsEntry->getName(); Buffer.setInt(Buffer.getInt() | InvalidFlag); } @@ -279,7 +291,12 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID) { std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); - const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile(); + bool Invalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); + if (!Entry.isFile() || Invalid) + return; + + const SrcMgr::FileInfo &FileInfo = Entry.getFile(); // Remember that this file has #line directives now if it doesn't already. const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives(); @@ -303,7 +320,13 @@ void SourceManager::AddLineNote(SourceLocation Loc, unsigned LineNo, } std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); - const SrcMgr::FileInfo &FileInfo = getSLocEntry(LocInfo.first).getFile(); + + bool Invalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); + if (!Entry.isFile() || Invalid) + return; + + const SrcMgr::FileInfo &FileInfo = Entry.getFile(); // Remember that this file has #line directives now if it doesn't already. const_cast<SrcMgr::FileInfo&>(FileInfo).setHasLineDirectives(); @@ -340,9 +363,9 @@ LineTableInfo &SourceManager::getLineTable() { //===----------------------------------------------------------------------===// SourceManager::SourceManager(Diagnostic &Diag, FileManager &FileMgr) - : Diag(Diag), FileMgr(FileMgr), + : Diag(Diag), FileMgr(FileMgr), OverridenFilesKeepOriginalName(true), ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), - NumBinaryProbes(0) { + NumBinaryProbes(0), FakeBufferForRecovery(0) { clearIDTables(); Diag.setSourceManager(this); } @@ -362,6 +385,8 @@ SourceManager::~SourceManager() { I->second->~ContentCache(); ContentCacheAlloc.Deallocate(I->second); } + + delete FakeBufferForRecovery; } void SourceManager::clearIDTables() { @@ -395,7 +420,18 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) { unsigned EntryAlign = llvm::AlignOf<ContentCache>::Alignment; EntryAlign = std::max(8U, EntryAlign); Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign); - new (Entry) ContentCache(FileEnt); + + // If the file contents are overridden with contents from another file, + // pass that file to ContentCache. + llvm::DenseMap<const FileEntry *, const FileEntry *>::iterator + overI = OverriddenFiles.find(FileEnt); + if (overI == OverriddenFiles.end()) + new (Entry) ContentCache(FileEnt); + else + new (Entry) ContentCache(OverridenFilesKeepOriginalName ? FileEnt + : overI->second, + overI->second); + return Entry; } @@ -445,6 +481,15 @@ void SourceManager::ClearPreallocatedSLocEntries() { ExternalSLocEntries = 0; } +/// \brief As part of recovering from missing or changed content, produce a +/// fake, non-empty buffer. +const llvm::MemoryBuffer *SourceManager::getFakeBufferForRecovery() const { + if (!FakeBufferForRecovery) + FakeBufferForRecovery + = llvm::MemoryBuffer::getMemBuffer("<<<INVALID BUFFER>>"); + + return FakeBufferForRecovery; +} //===----------------------------------------------------------------------===// // Methods to create new FileID's and instantiations. @@ -531,10 +576,21 @@ void SourceManager::overrideFileContents(const FileEntry *SourceFile, const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer, DoNotFree); } +void SourceManager::overrideFileContents(const FileEntry *SourceFile, + const FileEntry *NewFile) { + assert(SourceFile->getSize() == NewFile->getSize() && + "Different sizes, use the FileManager to create a virtual file with " + "the correct size"); + assert(FileInfos.count(SourceFile) == 0 && + "This function should be called at the initialization stage, before " + "any parsing occurs."); + OverriddenFiles[SourceFile] = NewFile; +} + llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { bool MyInvalid = false; - const SLocEntry &SLoc = getSLocEntry(FID.ID); - if (!SLoc.isFile()) { + const SLocEntry &SLoc = getSLocEntry(FID.ID, &MyInvalid); + if (!SLoc.isFile() || MyInvalid) { if (Invalid) *Invalid = true; return "<<<<<INVALID SOURCE LOCATION>>>>>"; @@ -562,7 +618,8 @@ llvm::StringRef SourceManager::getBufferData(FileID FID, bool *Invalid) const { /// SLocEntryTable which contains the specified location. /// FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { - assert(SLocOffset && "Invalid FileID"); + if (!SLocOffset) + return FileID::get(0); // After the first and second level caches, I see two common sorts of // behavior: 1) a lot of searched FileID's are "near" the cached file location @@ -590,8 +647,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { unsigned NumProbes = 0; while (1) { --I; - if (ExternalSLocEntries) - getSLocEntry(FileID::get(I - SLocEntryTable.begin())); + if (ExternalSLocEntries) { + bool Invalid = false; + getSLocEntry(FileID::get(I - SLocEntryTable.begin()), &Invalid); + if (Invalid) + return FileID::get(0); + } + if (I->getOffset() <= SLocOffset) { #if 0 printf("lin %d -> %d [%s] %d %d\n", SLocOffset, @@ -621,9 +683,13 @@ FileID SourceManager::getFileIDSlow(unsigned SLocOffset) const { unsigned LessIndex = 0; NumProbes = 0; while (1) { + bool Invalid = false; unsigned MiddleIndex = (GreaterIndex-LessIndex)/2+LessIndex; - unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex)).getOffset(); - + unsigned MidOffset = getSLocEntry(FileID::get(MiddleIndex), &Invalid) + .getOffset(); + if (Invalid) + return FileID::get(0); + ++NumProbes; // If the offset of the midpoint is too large, chop the high side of the @@ -773,9 +839,16 @@ const char *SourceManager::getCharacterData(SourceLocation SL, // Note that calling 'getBuffer()' may lazily page in a source file. bool CharDataInvalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &CharDataInvalid); + if (CharDataInvalid || !Entry.isFile()) { + if (Invalid) + *Invalid = true; + + return "<<<<INVALID BUFFER>>>>"; + } const llvm::MemoryBuffer *Buffer - = getSLocEntry(LocInfo.first).getFile().getContentCache() - ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid); + = Entry.getFile().getContentCache() + ->getBuffer(Diag, *this, SourceLocation(), &CharDataInvalid); if (Invalid) *Invalid = CharDataInvalid; return Buffer->getBufferStart() + (CharDataInvalid? 0 : LocInfo.second); @@ -891,10 +964,18 @@ unsigned SourceManager::getLineNumber(FileID FID, unsigned FilePos, ContentCache *Content; if (LastLineNoFileIDQuery == FID) Content = LastLineNoContentCache; - else - Content = const_cast<ContentCache*>(getSLocEntry(FID) - .getFile().getContentCache()); - + else { + bool MyInvalid = false; + const SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); + if (MyInvalid || !Entry.isFile()) { + if (Invalid) + *Invalid = true; + return 1; + } + + Content = const_cast<ContentCache*>(Entry.getFile().getContentCache()); + } + // If this is the first use of line information for this buffer, compute the /// SourceLineCache for it on demand. if (Content->SourceLineCache == 0) { @@ -1021,7 +1102,12 @@ SrcMgr::CharacteristicKind SourceManager::getFileCharacteristic(SourceLocation Loc) const { assert(!Loc.isInvalid() && "Can't get file characteristic of invalid loc!"); std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); - const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile(); + bool Invalid = false; + const SLocEntry &SEntry = getSLocEntry(LocInfo.first, &Invalid); + if (Invalid || !SEntry.isFile()) + return C_User; + + const SrcMgr::FileInfo &FI = SEntry.getFile(); // If there are no #line directives in this file, just return the whole-file // state. @@ -1064,18 +1150,23 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const { // Presumed locations are always for instantiation points. std::pair<FileID, unsigned> LocInfo = getDecomposedInstantiationLoc(Loc); - const SrcMgr::FileInfo &FI = getSLocEntry(LocInfo.first).getFile(); + bool Invalid = false; + const SLocEntry &Entry = getSLocEntry(LocInfo.first, &Invalid); + if (Invalid || !Entry.isFile()) + return PresumedLoc(); + + const SrcMgr::FileInfo &FI = Entry.getFile(); const SrcMgr::ContentCache *C = FI.getContentCache(); // To get the source name, first consult the FileEntry (if one exists) // before the MemBuffer as this will avoid unnecessarily paging in the // MemBuffer. const char *Filename; - if (C->Entry) - Filename = C->Entry->getName(); + if (C->OrigEntry) + Filename = C->OrigEntry->getName(); else Filename = C->getBuffer(Diag, *this)->getBufferIdentifier(); - bool Invalid = false; + unsigned LineNo = getLineNumber(LocInfo.first, LocInfo.second, &Invalid); if (Invalid) return PresumedLoc(); @@ -1152,18 +1243,22 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, llvm::Optional<ino_t> SourceFileInode; llvm::Optional<llvm::StringRef> SourceFileName; if (!MainFileID.isInvalid()) { - const SLocEntry &MainSLoc = getSLocEntry(MainFileID); + bool Invalid = false; + const SLocEntry &MainSLoc = getSLocEntry(MainFileID, &Invalid); + if (Invalid) + return SourceLocation(); + if (MainSLoc.isFile()) { const ContentCache *MainContentCache = MainSLoc.getFile().getContentCache(); if (!MainContentCache) { // Can't do anything - } else if (MainContentCache->Entry == SourceFile) { + } else if (MainContentCache->OrigEntry == SourceFile) { FirstFID = MainFileID; } else { // Fall back: check whether we have the same base name and inode // as the main file. - const FileEntry *MainFile = MainContentCache->Entry; + const FileEntry *MainFile = MainContentCache->OrigEntry; SourceFileName = llvm::sys::path::filename(SourceFile->getName()); if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) { SourceFileInode = getActualFileInode(SourceFile); @@ -1185,10 +1280,14 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, // The location we're looking for isn't in the main file; look // through all of the source locations. for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) { - const SLocEntry &SLoc = getSLocEntry(I); + bool Invalid = false; + const SLocEntry &SLoc = getSLocEntry(I, &Invalid); + if (Invalid) + return SourceLocation(); + if (SLoc.isFile() && SLoc.getFile().getContentCache() && - SLoc.getFile().getContentCache()->Entry == SourceFile) { + SLoc.getFile().getContentCache()->OrigEntry == SourceFile) { FirstFID = FileID::get(I); break; } @@ -1203,12 +1302,16 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, (SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) && (SourceFileInode || (SourceFileInode = getActualFileInode(SourceFile)))) { + bool Invalid = false; for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) { - const SLocEntry &SLoc = getSLocEntry(I); + const SLocEntry &SLoc = getSLocEntry(I, &Invalid); + if (Invalid) + return SourceLocation(); + if (SLoc.isFile()) { const ContentCache *FileContentCache = SLoc.getFile().getContentCache(); - const FileEntry *Entry =FileContentCache? FileContentCache->Entry : 0; + const FileEntry *Entry =FileContentCache? FileContentCache->OrigEntry : 0; if (Entry && *SourceFileName == llvm::sys::path::filename(Entry->getName())) { if (llvm::Optional<ino_t> EntryInode = getActualFileInode(Entry)) { @@ -1367,7 +1470,7 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, while (!MoveUpIncludeHierarchy(LOffs, *this)) /*empty*/; while (!MoveUpIncludeHierarchy(ROffs, *this)) /*empty*/; - // If exactly one location is a memory buffer, assume it preceeds the other. + // If exactly one location is a memory buffer, assume it precedes the other. // Strip off macro instantation locations, going up to the top-level File // SLocEntry. @@ -1403,3 +1506,24 @@ void SourceManager::PrintStats() const { } ExternalSLocEntrySource::~ExternalSLocEntrySource() { } + +/// Return the amount of memory used by memory buffers, breaking down +/// by heap-backed versus mmap'ed memory. +SourceManager::MemoryBufferSizes SourceManager::getMemoryBufferSizes() const { + size_t malloc_bytes = 0; + size_t mmap_bytes = 0; + + for (unsigned i = 0, e = MemBufferInfos.size(); i != e; ++i) + if (size_t sized_mapped = MemBufferInfos[i]->getSizeBytesMapped()) + switch (MemBufferInfos[i]->getMemoryBufferKind()) { + case llvm::MemoryBuffer::MemoryBuffer_MMap: + mmap_bytes += sized_mapped; + break; + case llvm::MemoryBuffer::MemoryBuffer_Malloc: + malloc_bytes += sized_mapped; + break; + } + + return MemoryBufferSizes(malloc_bytes, mmap_bytes); +} + diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index a9eeb8b4cc4e..dcf0cb4237a9 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/AddressSpaces.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/LangOptions.h" #include "llvm/ADT/APFloat.h" @@ -19,6 +20,8 @@ #include <cstdlib> using namespace clang; +static const LangAS::Map DefaultAddrSpaceMap = { 0 }; + // TargetInfo Constructor. TargetInfo::TargetInfo(const std::string &T) : Triple(T) { // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or @@ -64,6 +67,13 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { // Default to using the Itanium ABI. CXXABI = CXXABI_Itanium; + + // Default to an empty address space map. + AddrSpaceMap = &DefaultAddrSpaceMap; + + // Default to an unknown platform name. + PlatformName = "unknown"; + PlatformMinVersion = VersionTuple(); } // Out of line virtual dtor for TargetInfo. @@ -422,7 +432,7 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, case ',': // multiple alternative constraint. Ignore comma. break; case '?': // Disparage slightly code. - case '!': // Disparage severly. + case '!': // Disparage severely. break; // Pass them. } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 55321f2498ef..97109caf1237 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -76,7 +76,9 @@ public: static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, - const llvm::Triple &Triple) { + const llvm::Triple &Triple, + llvm::StringRef &PlatformName, + VersionTuple &PlatformMinVersion) { Builder.defineMacro("__APPLE_CC__", "5621"); Builder.defineMacro("__APPLE__"); Builder.defineMacro("__MACH__"); @@ -99,19 +101,40 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); - // Get the OS version number from the triple. + // Get the platform type and version number from the triple. unsigned Maj, Min, Rev; // If no version was given, default to to 10.4.0, for simplifying tests. - if (Triple.getOSName() == "darwin") { + if (Triple.getOSName() == "darwin" || Triple.getOSName() == "osx") { + PlatformName = "macosx"; Min = Rev = 0; Maj = 8; - } else - Triple.getDarwinNumber(Maj, Min, Rev); + } else { + // Otherwise, honor all three triple forms ("-darwinNNN[-iphoneos]", + // "-osxNNN", and "-iosNNN"). + + if (Triple.getOS() == llvm::Triple::Darwin) { + // For historical reasons that make little sense, the version passed here + // is the "darwin" version, which drops the 10 and offsets by 4. + Triple.getOSVersion(Maj, Min, Rev); + + if (Triple.getEnvironmentName() == "iphoneos") { + PlatformName = "ios"; + } else { + PlatformName = "macosx"; + Rev = Min; + Min = Maj - 4; + Maj = 10; + } + } else { + Triple.getOSVersion(Maj, Min, Rev); + PlatformName = llvm::Triple::getOSTypeName(Triple.getOS()); + } + } // Set the appropriate OS version define. - if (Triple.getEnvironmentName() == "iphoneos") { - assert(Maj < 10 && Min < 99 && Rev < 99 && "Invalid version!"); + if (PlatformName == "ios") { + assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!"); char Str[6]; Str[0] = '0' + Maj; Str[1] = '0' + (Min / 10); @@ -121,22 +144,22 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, Str[5] = '\0'; Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str); } else { - // For historical reasons that make little sense, the version passed here is - // the "darwin" version, which drops the 10 and offsets by 4. - Rev = Min; - Min = Maj - 4; - Maj = 10; - + // Note that the Driver allows versions which aren't representable in the + // define (because we only get a single digit for the minor and micro + // revision numbers). So, we limit them to the maximum representable + // version. assert(Triple.getEnvironmentName().empty() && "Invalid environment!"); - assert(Maj < 99 && Min < 10 && Rev < 10 && "Invalid version!"); + assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!"); char Str[5]; Str[0] = '0' + (Maj / 10); Str[1] = '0' + (Maj % 10); - Str[2] = '0' + Min; - Str[3] = '0' + Rev; + Str[2] = '0' + std::min(Min, 9U); + Str[3] = '0' + std::min(Rev, 9U); Str[4] = '\0'; Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str); } + + PlatformMinVersion = VersionTuple(Maj, Min, Rev); } namespace { @@ -145,7 +168,8 @@ class DarwinTargetInfo : public OSTargetInfo<Target> { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const { - getDarwinDefines(Builder, Opts, Triple); + getDarwinDefines(Builder, Opts, Triple, this->PlatformName, + this->PlatformMinVersion); } public: @@ -159,8 +183,9 @@ public: // Let MCSectionMachO validate this. llvm::StringRef Segment, Section; unsigned TAA, StubSize; + bool HasTAA; return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section, - TAA, StubSize); + TAA, HasTAA, StubSize); } virtual const char *getStaticInitSectionSpecifier() const { @@ -823,6 +848,87 @@ public: } // end anonymous namespace. namespace { + class PTXTargetInfo : public TargetInfo { + static const char * const GCCRegNames[]; + static const Builtin::Info BuiltinInfo[]; + public: + PTXTargetInfo(const std::string& triple) : TargetInfo(triple) { + TLSSupported = false; + LongWidth = LongAlign = 64; + } + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__PTX__"); + } + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + Records = BuiltinInfo; + NumRecords = clang::PTX::LastTSBuiltin-Builtin::FirstTSBuiltin; + } + + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + // No aliases. + Aliases = 0; + NumAliases = 0; + } + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const { + // FIXME: implement + return true; + } + virtual const char *getClobbers() const { + // FIXME: Is this really right? + return ""; + } + virtual const char *getVAListDeclaration() const { + // FIXME: implement + return "typedef char* __builtin_va_list;"; + } + }; + + const Builtin::Info PTXTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES, false }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER,\ + ALL_LANGUAGES, false }, +#include "clang/Basic/BuiltinsPTX.def" + }; + + const char * const PTXTargetInfo::GCCRegNames[] = { + "r0" + }; + + void PTXTargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); + } + + + class PTX32TargetInfo : public PTXTargetInfo { + public: + PTX32TargetInfo(const std::string& triple) : PTXTargetInfo(triple) { + PointerWidth = PointerAlign = 32; + SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedInt; + DescriptionString + = "e-p:32:32-i64:64:64-f64:64:64-n1:8:16:32:64"; + } + }; + + class PTX64TargetInfo : public PTXTargetInfo { + public: + PTX64TargetInfo(const std::string& triple) : PTXTargetInfo(triple) { + PointerWidth = PointerAlign = 64; + SizeType = PtrDiffType = IntPtrType = TargetInfo::UnsignedLongLong; + DescriptionString + = "e-p:64:64-i64:64:64-f64:64:64-n1:8:16:32:64"; + } + }; +} + +namespace { // MBlaze abstract base class class MBlazeTargetInfo : public TargetInfo { static const char * const GCCRegNames[]; @@ -1074,8 +1180,11 @@ void X86TargetInfo::getDefaultFeatures(const std::string &CPU, else if (CPU == "corei7") { setFeatureEnabled(Features, "sse4", true); setFeatureEnabled(Features, "aes", true); - } - else if (CPU == "k6" || CPU == "winchip-c6") + } else if (CPU == "sandybridge") { + setFeatureEnabled(Features, "sse4", true); + setFeatureEnabled(Features, "aes", true); +// setFeatureEnabled(Features, "avx", true); + } else if (CPU == "k6" || CPU == "winchip-c6") setFeatureEnabled(Features, "mmx", true); else if (CPU == "k6-2" || CPU == "k6-3" || CPU == "athlon" || CPU == "athlon-tbird" || CPU == "winchip2" || CPU == "c3") { @@ -1133,7 +1242,8 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, Features["avx"] = true; } else { if (Name == "mmx") - Features["mmx"] = Features["sse"] = Features["sse2"] = Features["sse3"] = + Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = + Features["sse"] = Features["sse2"] = Features["sse3"] = Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; else if (Name == "sse") Features["sse"] = Features["sse2"] = Features["sse3"] = @@ -1146,12 +1256,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, Features["sse42"] = false; else if (Name == "ssse3") Features["ssse3"] = Features["sse41"] = Features["sse42"] = false; - else if (Name == "sse4") + else if (Name == "sse4" || Name == "sse4.1") Features["sse41"] = Features["sse42"] = false; else if (Name == "sse4.2") Features["sse42"] = false; - else if (Name == "sse4.1") - Features["sse41"] = Features["sse42"] = false; else if (Name == "3dnow") Features["3dnow"] = Features["3dnowa"] = false; else if (Name == "3dnowa") @@ -1451,7 +1559,7 @@ class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo { public: VisualStudioWindowsX86_32TargetInfo(const std::string& triple) : WindowsX86_32TargetInfo(triple) { - LongDoubleWidth = 64; + LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } virtual void getTargetDefines(const LangOptions &Opts, @@ -1481,7 +1589,15 @@ public: Builder.defineMacro("_X86_"); Builder.defineMacro("__MSVCRT__"); Builder.defineMacro("__MINGW32__"); - Builder.defineMacro("__declspec", "__declspec"); + + // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)). + // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions. + if (Opts.Microsoft) + // Provide "as-is" __declspec. + Builder.defineMacro("__declspec", "__declspec"); + else + // Provide alias of __attribute__ like mingw32-gcc. + Builder.defineMacro("__declspec(a)", "__attribute__((a))"); } }; } // end anonymous namespace @@ -1606,6 +1722,8 @@ class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo { public: VisualStudioWindowsX86_64TargetInfo(const std::string& triple) : WindowsX86_64TargetInfo(triple) { + LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -1629,8 +1747,17 @@ public: WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); DefineStd(Builder, "WIN64", Opts); Builder.defineMacro("__MSVCRT__"); + Builder.defineMacro("__MINGW32__"); Builder.defineMacro("__MINGW64__"); - Builder.defineMacro("__declspec", "__declspec"); + + // mingw32-gcc provides __declspec(a) as alias of __attribute__((a)). + // In contrast, clang-cc1 provides __declspec(a) with -fms-extensions. + if (Opts.Microsoft) + // Provide "as-is" __declspec. + Builder.defineMacro("__declspec", "__declspec"); + else + // Provide alias of __attribute__ like mingw32-gcc. + Builder.defineMacro("__declspec(a)", "__attribute__((a))"); } }; } // end anonymous namespace @@ -1700,13 +1827,15 @@ public: // FIXME: Should we just treat this as a feature? IsThumb = getTriple().getArchName().startswith("thumb"); if (IsThumb) { + // Thumb1 add sp, #imm requires the immediate value be multiple of 4, + // so set preferred for small types to 32. DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-" - "v64:64:64-v128:128:128-a0:0:32-n32"); + "v64:64:64-v128:64:128-a0:0:32-n32"); } else { DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" "i64:64:64-f32:32:32-f64:64:64-" - "v64:64:64-v128:128:128-a0:0:64-n32"); + "v64:64:64-v128:64:128-a0:0:64-n32"); } // ARM targets default to using the ARM C++ ABI. @@ -1729,13 +1858,15 @@ public: UseBitFieldTypeAlignment = false; if (IsThumb) { + // Thumb1 add sp, #imm requires the immediate value be multiple of 4, + // so set preferred for small types to 32. DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-" "i64:32:32-f32:32:32-f64:32:32-" - "v64:64:64-v128:128:128-a0:0:32-n32"); + "v64:32:64-v128:32:128-a0:0:32-n32"); } else { DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:32:32-f32:32:32-f64:32:32-" - "v64:64:64-v128:128:128-a0:0:64-n32"); + "i64:32:64-f32:32:32-f64:32:64-" + "v64:32:64-v128:32:128-a0:0:32-n32"); } // FIXME: Override "preferred align" for double and long long. @@ -1822,6 +1953,7 @@ public: .Cases("arm1156t2-s", "arm1156t2f-s", "6T2") .Cases("cortex-a8", "cortex-a9", "7A") .Case("cortex-m3", "7M") + .Case("cortex-m0", "6M") .Default(0); } virtual bool setCPU(const std::string &Name) { @@ -1984,7 +2116,7 @@ class DarwinARMTargetInfo : protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const { - getDarwinDefines(Builder, Opts, Triple); + getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); } public: @@ -2563,11 +2695,12 @@ static TargetInfo *AllocateTarget(const std::string &T) { case llvm::Triple::arm: case llvm::Triple::thumb: + if (Triple.isOSDarwin()) + return new DarwinARMTargetInfo(T); + switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo<ARMTargetInfo>(T); - case llvm::Triple::Darwin: - return new DarwinARMTargetInfo(T); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo<ARMTargetInfo>(T); default: @@ -2595,14 +2728,14 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new MipselTargetInfo(T); case llvm::Triple::ppc: - if (os == llvm::Triple::Darwin) + if (Triple.isOSDarwin()) return new DarwinPPC32TargetInfo(T); else if (os == llvm::Triple::FreeBSD) return new FreeBSDTargetInfo<PPC32TargetInfo>(T); return new PPC32TargetInfo(T); case llvm::Triple::ppc64: - if (os == llvm::Triple::Darwin) + if (Triple.isOSDarwin()) return new DarwinPPC64TargetInfo(T); else if (os == llvm::Triple::Lv2) return new PS3PPUTargetInfo<PPC64TargetInfo>(T); @@ -2610,6 +2743,11 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new FreeBSDTargetInfo<PPC64TargetInfo>(T); return new PPC64TargetInfo(T); + case llvm::Triple::ptx32: + return new PTX32TargetInfo(T); + case llvm::Triple::ptx64: + return new PTX64TargetInfo(T); + case llvm::Triple::mblaze: return new MBlazeTargetInfo(T); @@ -2631,11 +2769,12 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new TCETargetInfo(T); case llvm::Triple::x86: + if (Triple.isOSDarwin()) + return new DarwinI386TargetInfo(T); + switch (os) { case llvm::Triple::AuroraUX: return new AuroraUXTargetInfo<X86_32TargetInfo>(T); - case llvm::Triple::Darwin: - return new DarwinI386TargetInfo(T); case llvm::Triple::Linux: return new LinuxTargetInfo<X86_32TargetInfo>(T); case llvm::Triple::DragonFly: @@ -2663,11 +2802,12 @@ static TargetInfo *AllocateTarget(const std::string &T) { } case llvm::Triple::x86_64: + if (Triple.isOSDarwin() || Triple.getEnvironment() == llvm::Triple::MachO) + return new DarwinX86_64TargetInfo(T); + switch (os) { case llvm::Triple::AuroraUX: return new AuroraUXTargetInfo<X86_64TargetInfo>(T); - case llvm::Triple::Darwin: - return new DarwinX86_64TargetInfo(T); case llvm::Triple::Linux: return new LinuxTargetInfo<X86_64TargetInfo>(T); case llvm::Triple::DragonFly: @@ -2683,10 +2823,7 @@ static TargetInfo *AllocateTarget(const std::string &T) { case llvm::Triple::MinGW32: return new MinGWX86_64TargetInfo(T); case llvm::Triple::Win32: // This is what Triple.h supports now. - if (Triple.getEnvironment() == llvm::Triple::MachO) - return new DarwinX86_64TargetInfo(T); - else - return new VisualStudioWindowsX86_64TargetInfo(T); + return new VisualStudioWindowsX86_64TargetInfo(T); default: return new X86_64TargetInfo(T); } diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index 6573eb96e3f3..8f713524629c 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -17,11 +17,12 @@ #include <cstring> #include <cstdlib> -using namespace std; - namespace clang { std::string getClangRepositoryPath() { +#if defined(CLANG_REPOSITORY_STRING) + return CLANG_REPOSITORY_STRING; +#else #ifdef SVN_REPOSITORY llvm::StringRef URL(SVN_REPOSITORY); #else @@ -45,6 +46,7 @@ std::string getClangRepositoryPath() { URL = URL.substr(Start + 4); return URL; +#endif } std::string getClangRevision() { @@ -87,4 +89,17 @@ std::string getClangFullVersion() { return OS.str(); } +std::string getClangFullCPPVersion() { + // The version string we report in __VERSION__ is just a compacted version of + // the one we report on the command line. + std::string buf; + llvm::raw_string_ostream OS(buf); +#ifdef CLANG_VENDOR + OS << CLANG_VENDOR; +#endif + OS << "Clang " CLANG_VERSION_STRING " (" + << getClangFullRepositoryVersion() << ')'; + return OS.str(); +} + } // end namespace clang diff --git a/lib/Basic/VersionTuple.cpp b/lib/Basic/VersionTuple.cpp new file mode 100644 index 000000000000..d5cf126ff487 --- /dev/null +++ b/lib/Basic/VersionTuple.cpp @@ -0,0 +1,36 @@ +//===- VersionTuple.cpp - Version Number Handling ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the VersionTuple class, which represents a version in +// the form major[.minor[.subminor]]. +// +//===----------------------------------------------------------------------===// +#include "clang/Basic/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +std::string VersionTuple::getAsString() const { + std::string Result; + { + llvm::raw_string_ostream Out(Result); + Out << *this; + } + return Result; +} + +llvm::raw_ostream& clang::operator<<(llvm::raw_ostream &Out, + const VersionTuple &V) { + Out << V.getMajor(); + if (llvm::Optional<unsigned> Minor = V.getMinor()) + Out << '.' << *Minor; + if (llvm::Optional<unsigned> Subminor = V.getSubminor()) + Out << '.' << *Subminor; + return Out; +} diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index b4574344bc5f..0943e2b1c785 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -13,3 +13,4 @@ add_subdirectory(Frontend) add_subdirectory(FrontendTool) add_subdirectory(Index) add_subdirectory(StaticAnalyzer) +add_subdirectory(Tooling) diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 9897b1b1a028..1264473dabce 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -30,6 +30,7 @@ #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegistry.h" +#include "llvm/Transforms/Instrumentation.h" using namespace clang; using namespace llvm; @@ -108,9 +109,9 @@ void EmitAssemblyHelper::CreatePasses() { OptLevel = 0; Inlining = CodeGenOpts.NoInlining; } - + FunctionPassManager *FPM = getPerFunctionPasses(); - + TargetLibraryInfo *TLI = new TargetLibraryInfo(Triple(TheModule->getTargetTriple())); if (!CodeGenOpts.SimplifyLibCalls) @@ -133,8 +134,10 @@ void EmitAssemblyHelper::CreatePasses() { // // FIXME: Derive these constants in a principled fashion. unsigned Threshold = 225; - if (CodeGenOpts.OptimizeSize) + if (CodeGenOpts.OptimizeSize == 1) //-Os Threshold = 75; + else if (CodeGenOpts.OptimizeSize == 2) //-Oz + Threshold = 25; else if (OptLevel > 2) Threshold = 275; InliningPass = createFunctionInliningPass(Threshold); @@ -146,12 +149,19 @@ void EmitAssemblyHelper::CreatePasses() { } PassManager *MPM = getPerModulePasses(); - + TLI = new TargetLibraryInfo(Triple(TheModule->getTargetTriple())); if (!CodeGenOpts.SimplifyLibCalls) TLI->disableAllFunctions(); MPM->add(TLI); + if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) { + MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes, + CodeGenOpts.EmitGcovArcs)); + if (!CodeGenOpts.DebugInfo) + MPM->add(createStripSymbolsPass(true)); + } + // For now we always create per module passes. llvm::createStandardModulePasses(MPM, OptLevel, CodeGenOpts.OptimizeSize, @@ -190,7 +200,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, } // Set float ABI type. - if (CodeGenOpts.FloatABI == "soft") + if (CodeGenOpts.FloatABI == "soft" || CodeGenOpts.FloatABI == "softfp") llvm::FloatABIType = llvm::FloatABI::Soft; else if (CodeGenOpts.FloatABI == "hard") llvm::FloatABIType = llvm::FloatABI::Hard; @@ -248,6 +258,8 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, } if (llvm::TimePassesIsEnabled) BackendArgs.push_back("-time-passes"); + for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i) + BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str()); BackendArgs.push_back(0); llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, const_cast<char **>(&BackendArgs[0])); @@ -266,6 +278,10 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, if (CodeGenOpts.RelaxAll) TM->setMCRelaxAll(true); + if (CodeGenOpts.SaveTempLabels) + TM->setMCSaveTempLabels(true); + if (CodeGenOpts.NoDwarf2CFIAsm) + TM->setMCUseCFI(false); // Create the code generator passes. PassManager *PM = getCodeGenPasses(); @@ -319,6 +335,9 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) { return; } + // Before executing passes, print the final values of the LLVM options. + cl::PrintOptionValues(); + // Run passes. For now we do all passes at once, but eventually we // would like to have the option of streaming code generation. diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 9587de223aa7..99a69a4f4a93 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -27,13 +27,16 @@ using namespace CodeGen; CGBlockInfo::CGBlockInfo(const BlockExpr *blockExpr, const char *N) : Name(N), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false), - HasCXXObject(false), StructureType(0), Block(blockExpr) { + HasCXXObject(false), UsesStret(false), StructureType(0), Block(blockExpr) { // Skip asm prefix, if any. if (Name && Name[0] == '\01') ++Name; } +// Anchor the vtable to this translation unit. +CodeGenModule::ByrefHelpers::~ByrefHelpers() {} + /// Build the given block as a global block. static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, const CGBlockInfo &blockInfo, @@ -104,23 +107,6 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType()); } -static BlockFlags computeBlockFlag(CodeGenModule &CGM, - const BlockExpr *BE, - BlockFlags flags) { - const FunctionType *ftype = BE->getFunctionType(); - - // This is a bit overboard. - CallArgList args; - const CGFunctionInfo &fnInfo = - CGM.getTypes().getFunctionInfo(ftype->getResultType(), args, - ftype->getExtInfo()); - - if (CGM.ReturnTypeUsesSRet(fnInfo)) - flags |= BLOCK_USE_STRET; - - return flags; -} - /* Purely notional variadic template describing the layout of a block. @@ -536,7 +522,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { BlockFlags flags = BLOCK_HAS_SIGNATURE; if (blockInfo.NeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ; - flags = computeBlockFlag(CGM, blockInfo.getBlockExpr(), flags); + if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; // Initialize the block literal. Builder.CreateStore(isa, Builder.CreateStructGEP(blockAddr, 0, "block.isa")); @@ -630,7 +616,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) { ImplicitCastExpr l2r(ImplicitCastExpr::OnStack, type, CK_LValueToRValue, declRef, VK_RValue); - EmitAnyExprToMem(&l2r, blockField, /*volatile*/ false, /*init*/ true); + EmitExprAsInit(&l2r, variable, blockField, + getContext().getDeclAlign(variable), + /*captured by init*/ false); } // Push a destructor if necessary. The semantics for when this @@ -734,7 +722,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, // Add the block literal. QualType VoidPtrTy = getContext().getPointerType(getContext().VoidTy); CallArgList Args; - Args.push_back(std::make_pair(RValue::get(BlockLiteral), VoidPtrTy)); + Args.add(RValue::get(BlockLiteral), VoidPtrTy); QualType FnType = BPT->getPointeeType(); @@ -745,7 +733,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E, // Load the function. llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp"); - const FunctionType *FuncTy = FnType->getAs<FunctionType>(); + const FunctionType *FuncTy = FnType->castAs<FunctionType>(); QualType ResultType = FuncTy->getResultType(); const CGFunctionInfo &FnInfo = @@ -834,8 +822,9 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, fields[0] = CGM.getNSConcreteGlobalBlock(); // __flags - BlockFlags flags = computeBlockFlag(CGM, blockInfo.getBlockExpr(), - BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE); + BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE; + if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; + fields[1] = llvm::ConstantInt::get(CGM.IntTy, flags.getBitMask()); // Reserved @@ -873,7 +862,10 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const DeclMapTy &ldm) { const BlockDecl *blockDecl = blockInfo.getBlockDecl(); - DebugInfo = CGM.getDebugInfo(); + // Check if we should generate debug info for this block function. + if (CGM.getModuleDebugInfo()) + DebugInfo = CGM.getModuleDebugInfo(); + BlockInfo = &blockInfo; // Arrange for local static and local extern declarations to appear @@ -897,12 +889,12 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, ImplicitParamDecl selfDecl(const_cast<BlockDecl*>(blockDecl), SourceLocation(), II, selfTy); - args.push_back(std::make_pair(&selfDecl, selfTy)); + args.push_back(&selfDecl); // Now add the rest of the parameters. for (BlockDecl::param_const_iterator i = blockDecl->param_begin(), e = blockDecl->param_end(); i != e; ++i) - args.push_back(std::make_pair(*i, (*i)->getType())); + args.push_back(*i); // Create the function declaration. const FunctionProtoType *fnType = @@ -910,6 +902,9 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const CGFunctionInfo &fnInfo = CGM.getTypes().getFunctionInfo(fnType->getResultType(), args, fnType->getExtInfo()); + if (CGM.ReturnTypeUsesSRet(fnInfo)) + blockInfo.UsesStret = true; + const llvm::FunctionType *fnLLVMType = CGM.getTypes().GetFunctionType(fnInfo, fnType->isVariadic()); @@ -921,8 +916,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, CGM.SetInternalFunctionAttributes(blockDecl, fn, fnInfo); // Begin generating the function. - StartFunction(blockDecl, fnType->getResultType(), fn, args, - blockInfo.getBlockExpr()->getBody()->getLocEnd()); + StartFunction(blockDecl, fnType->getResultType(), fn, fnInfo, args, + blockInfo.getBlockExpr()->getBody()->getLocStart()); CurFuncDecl = outerFnDecl; // StartFunction sets this to blockDecl // Okay. Undo some of what StartFunction did. @@ -1049,13 +1044,10 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { ASTContext &C = getContext(); FunctionArgList args; - // FIXME: This leaks - ImplicitParamDecl *dstDecl = - ImplicitParamDecl::Create(C, 0, SourceLocation(), 0, C.VoidPtrTy); - args.push_back(std::make_pair(dstDecl, dstDecl->getType())); - ImplicitParamDecl *srcDecl = - ImplicitParamDecl::Create(C, 0, SourceLocation(), 0, C.VoidPtrTy); - args.push_back(std::make_pair(srcDecl, srcDecl->getType())); + ImplicitParamDecl dstDecl(0, SourceLocation(), 0, C.VoidPtrTy); + args.push_back(&dstDecl); + ImplicitParamDecl srcDecl(0, SourceLocation(), 0, C.VoidPtrTy); + args.push_back(&srcDecl); const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo()); @@ -1073,20 +1065,21 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { FunctionDecl *FD = FunctionDecl::Create(C, C.getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), II, C.VoidTy, 0, SC_Static, SC_None, false, true); - StartFunction(FD, C.VoidTy, Fn, args, SourceLocation()); + StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation()); const llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); - llvm::Value *src = GetAddrOfLocalVar(srcDecl); + llvm::Value *src = GetAddrOfLocalVar(&srcDecl); src = Builder.CreateLoad(src); src = Builder.CreateBitCast(src, structPtrTy, "block.source"); - llvm::Value *dst = GetAddrOfLocalVar(dstDecl); + llvm::Value *dst = GetAddrOfLocalVar(&dstDecl); dst = Builder.CreateLoad(dst); dst = Builder.CreateBitCast(dst, structPtrTy, "block.dest"); @@ -1143,10 +1136,8 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { ASTContext &C = getContext(); FunctionArgList args; - // FIXME: This leaks - ImplicitParamDecl *srcDecl = - ImplicitParamDecl::Create(C, 0, SourceLocation(), 0, C.VoidPtrTy); - args.push_back(std::make_pair(srcDecl, srcDecl->getType())); + ImplicitParamDecl srcDecl(0, SourceLocation(), 0, C.VoidPtrTy); + args.push_back(&srcDecl); const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(C.VoidTy, args, FunctionType::ExtInfo()); @@ -1163,15 +1154,16 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { = &CGM.getContext().Idents.get("__destroy_helper_block_"); FunctionDecl *FD = FunctionDecl::Create(C, C.getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), II, C.VoidTy, 0, SC_Static, SC_None, false, true); - StartFunction(FD, C.VoidTy, Fn, args, SourceLocation()); + StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation()); const llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); - llvm::Value *src = GetAddrOfLocalVar(srcDecl); + llvm::Value *src = GetAddrOfLocalVar(&srcDecl); src = Builder.CreateLoad(src); src = Builder.CreateBitCast(src, structPtrTy, "block"); @@ -1229,99 +1221,158 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { return llvm::ConstantExpr::getBitCast(Fn, VoidPtrTy); } -llvm::Constant *CodeGenFunction:: -GeneratebyrefCopyHelperFunction(const llvm::Type *T, BlockFieldFlags flags, - const VarDecl *variable) { - QualType R = getContext().VoidTy; - - FunctionArgList Args; - // FIXME: This leaks - ImplicitParamDecl *Dst = - ImplicitParamDecl::Create(getContext(), 0, - SourceLocation(), 0, - getContext().getPointerType(getContext().VoidTy)); - Args.push_back(std::make_pair(Dst, Dst->getType())); - - // FIXME: This leaks - ImplicitParamDecl *Src = - ImplicitParamDecl::Create(getContext(), 0, - SourceLocation(), 0, - getContext().getPointerType(getContext().VoidTy)); - Args.push_back(std::make_pair(Src, Src->getType())); +namespace { + +/// Emits the copy/dispose helper functions for a __block object of id type. +class ObjectByrefHelpers : public CodeGenModule::ByrefHelpers { + BlockFieldFlags Flags; + +public: + ObjectByrefHelpers(CharUnits alignment, BlockFieldFlags flags) + : ByrefHelpers(alignment), Flags(flags) {} + + void emitCopy(CodeGenFunction &CGF, llvm::Value *destField, + llvm::Value *srcField) { + destField = CGF.Builder.CreateBitCast(destField, CGF.VoidPtrTy); + + srcField = CGF.Builder.CreateBitCast(srcField, CGF.VoidPtrPtrTy); + llvm::Value *srcValue = CGF.Builder.CreateLoad(srcField); + + unsigned flags = (Flags | BLOCK_BYREF_CALLER).getBitMask(); + + llvm::Value *flagsVal = llvm::ConstantInt::get(CGF.Int32Ty, flags); + llvm::Value *fn = CGF.CGM.getBlockObjectAssign(); + CGF.Builder.CreateCall3(fn, destField, srcValue, flagsVal); + } + + void emitDispose(CodeGenFunction &CGF, llvm::Value *field) { + field = CGF.Builder.CreateBitCast(field, CGF.Int8PtrTy->getPointerTo(0)); + llvm::Value *value = CGF.Builder.CreateLoad(field); + + CGF.BuildBlockRelease(value, Flags | BLOCK_BYREF_CALLER); + } + + void profileImpl(llvm::FoldingSetNodeID &id) const { + id.AddInteger(Flags.getBitMask()); + } +}; + +/// Emits the copy/dispose helpers for a __block variable with a +/// nontrivial copy constructor or destructor. +class CXXByrefHelpers : public CodeGenModule::ByrefHelpers { + QualType VarType; + const Expr *CopyExpr; + +public: + CXXByrefHelpers(CharUnits alignment, QualType type, + const Expr *copyExpr) + : ByrefHelpers(alignment), VarType(type), CopyExpr(copyExpr) {} + + bool needsCopy() const { return CopyExpr != 0; } + void emitCopy(CodeGenFunction &CGF, llvm::Value *destField, + llvm::Value *srcField) { + if (!CopyExpr) return; + CGF.EmitSynthesizedCXXCopyCtor(destField, srcField, CopyExpr); + } + + void emitDispose(CodeGenFunction &CGF, llvm::Value *field) { + EHScopeStack::stable_iterator cleanupDepth = CGF.EHStack.stable_begin(); + CGF.PushDestructorCleanup(VarType, field); + CGF.PopCleanupBlocks(cleanupDepth); + } + + void profileImpl(llvm::FoldingSetNodeID &id) const { + id.AddPointer(VarType.getCanonicalType().getAsOpaquePtr()); + } +}; +} // end anonymous namespace + +static llvm::Constant * +generateByrefCopyHelper(CodeGenFunction &CGF, + const llvm::StructType &byrefType, + CodeGenModule::ByrefHelpers &byrefInfo) { + ASTContext &Context = CGF.getContext(); + + QualType R = Context.VoidTy; + + FunctionArgList args; + ImplicitParamDecl dst(0, SourceLocation(), 0, Context.VoidPtrTy); + args.push_back(&dst); + + ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy); + args.push_back(&src); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo()); + CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo()); - CodeGenTypes &Types = CGM.getTypes(); + CodeGenTypes &Types = CGF.CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); // FIXME: We'd like to put these into a mergable by content, with // internal linkage. llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, - "__Block_byref_object_copy_", &CGM.getModule()); + "__Block_byref_object_copy_", &CGF.CGM.getModule()); IdentifierInfo *II - = &CGM.getContext().Idents.get("__Block_byref_object_copy_"); + = &Context.Idents.get("__Block_byref_object_copy_"); - FunctionDecl *FD = FunctionDecl::Create(getContext(), - getContext().getTranslationUnitDecl(), + FunctionDecl *FD = FunctionDecl::Create(Context, + Context.getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), II, R, 0, SC_Static, SC_None, false, true); - StartFunction(FD, R, Fn, Args, SourceLocation()); - - // dst->x - llvm::Value *V = GetAddrOfLocalVar(Dst); - V = Builder.CreateBitCast(V, llvm::PointerType::get(T, 0)); - V = Builder.CreateLoad(V); - V = Builder.CreateStructGEP(V, 6, "x"); - llvm::Value *DstObj = V; - - // src->x - V = GetAddrOfLocalVar(Src); - V = Builder.CreateLoad(V); - V = Builder.CreateBitCast(V, T); - V = Builder.CreateStructGEP(V, 6, "x"); - - if (Expr *copyExpr = getContext().getBlockVarCopyInits(variable)) { - llvm::Value *SrcObj = V; - EmitSynthesizedCXXCopyCtor(DstObj, SrcObj, copyExpr); - } else { - DstObj = Builder.CreateBitCast(DstObj, VoidPtrTy); - V = Builder.CreateBitCast(V, VoidPtrPtrTy); - llvm::Value *SrcObj = Builder.CreateLoad(V); - flags |= BLOCK_BYREF_CALLER; - llvm::Value *N = llvm::ConstantInt::get(Int32Ty, flags.getBitMask()); - llvm::Value *F = CGM.getBlockObjectAssign(); - Builder.CreateCall3(F, DstObj, SrcObj, N); - } - - FinishFunction(); + CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation()); - return llvm::ConstantExpr::getBitCast(Fn, Int8PtrTy); + if (byrefInfo.needsCopy()) { + const llvm::Type *byrefPtrType = byrefType.getPointerTo(0); + + // dst->x + llvm::Value *destField = CGF.GetAddrOfLocalVar(&dst); + destField = CGF.Builder.CreateLoad(destField); + destField = CGF.Builder.CreateBitCast(destField, byrefPtrType); + destField = CGF.Builder.CreateStructGEP(destField, 6, "x"); + + // src->x + llvm::Value *srcField = CGF.GetAddrOfLocalVar(&src); + srcField = CGF.Builder.CreateLoad(srcField); + srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType); + srcField = CGF.Builder.CreateStructGEP(srcField, 6, "x"); + + byrefInfo.emitCopy(CGF, destField, srcField); + } + + CGF.FinishFunction(); + + return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy); } -llvm::Constant * -CodeGenFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, - BlockFieldFlags flags, - const VarDecl *variable) { - QualType R = getContext().VoidTy; +/// Build the copy helper for a __block variable. +static llvm::Constant *buildByrefCopyHelper(CodeGenModule &CGM, + const llvm::StructType &byrefType, + CodeGenModule::ByrefHelpers &info) { + CodeGenFunction CGF(CGM); + return generateByrefCopyHelper(CGF, byrefType, info); +} - FunctionArgList Args; - // FIXME: This leaks - ImplicitParamDecl *Src = - ImplicitParamDecl::Create(getContext(), 0, - SourceLocation(), 0, - getContext().getPointerType(getContext().VoidTy)); +/// Generate code for a __block variable's dispose helper. +static llvm::Constant * +generateByrefDisposeHelper(CodeGenFunction &CGF, + const llvm::StructType &byrefType, + CodeGenModule::ByrefHelpers &byrefInfo) { + ASTContext &Context = CGF.getContext(); + QualType R = Context.VoidTy; - Args.push_back(std::make_pair(Src, Src->getType())); + FunctionArgList args; + ImplicitParamDecl src(0, SourceLocation(), 0, Context.VoidPtrTy); + args.push_back(&src); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(R, Args, FunctionType::ExtInfo()); + CGF.CGM.getTypes().getFunctionInfo(R, args, FunctionType::ExtInfo()); - CodeGenTypes &Types = CGM.getTypes(); + CodeGenTypes &Types = CGF.CGM.getTypes(); const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false); // FIXME: We'd like to put these into a mergable by content, with @@ -1329,81 +1380,255 @@ CodeGenFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T, llvm::Function *Fn = llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, "__Block_byref_object_dispose_", - &CGM.getModule()); + &CGF.CGM.getModule()); IdentifierInfo *II - = &CGM.getContext().Idents.get("__Block_byref_object_dispose_"); + = &Context.Idents.get("__Block_byref_object_dispose_"); - FunctionDecl *FD = FunctionDecl::Create(getContext(), - getContext().getTranslationUnitDecl(), + FunctionDecl *FD = FunctionDecl::Create(Context, + Context.getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), II, R, 0, SC_Static, SC_None, false, true); - StartFunction(FD, R, Fn, Args, SourceLocation()); + CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation()); + + if (byrefInfo.needsDispose()) { + llvm::Value *V = CGF.GetAddrOfLocalVar(&src); + V = CGF.Builder.CreateLoad(V); + V = CGF.Builder.CreateBitCast(V, byrefType.getPointerTo(0)); + V = CGF.Builder.CreateStructGEP(V, 6, "x"); - llvm::Value *V = GetAddrOfLocalVar(Src); - V = Builder.CreateBitCast(V, llvm::PointerType::get(T, 0)); - V = Builder.CreateLoad(V); - V = Builder.CreateStructGEP(V, 6, "x"); + byrefInfo.emitDispose(CGF, V); + } - // If it's not any kind of special object, it must have a destructor - // or something. - if (!flags.isSpecialPointer()) { - EHScopeStack::stable_iterator CleanupDepth = EHStack.stable_begin(); - PushDestructorCleanup(variable->getType(), V); - PopCleanupBlocks(CleanupDepth); + CGF.FinishFunction(); - // Otherwise, call _Block_object_dispose. - } else { - V = Builder.CreateBitCast(V, llvm::PointerType::get(Int8PtrTy, 0)); - V = Builder.CreateLoad(V); + return llvm::ConstantExpr::getBitCast(Fn, CGF.Int8PtrTy); +} - flags |= BLOCK_BYREF_CALLER; - BuildBlockRelease(V, flags); +/// Build the dispose helper for a __block variable. +static llvm::Constant *buildByrefDisposeHelper(CodeGenModule &CGM, + const llvm::StructType &byrefType, + CodeGenModule::ByrefHelpers &info) { + CodeGenFunction CGF(CGM); + return generateByrefDisposeHelper(CGF, byrefType, info); +} + +/// +template <class T> static T *buildByrefHelpers(CodeGenModule &CGM, + const llvm::StructType &byrefTy, + T &byrefInfo) { + // Increase the field's alignment to be at least pointer alignment, + // since the layout of the byref struct will guarantee at least that. + byrefInfo.Alignment = std::max(byrefInfo.Alignment, + CharUnits::fromQuantity(CGM.PointerAlignInBytes)); + + llvm::FoldingSetNodeID id; + byrefInfo.Profile(id); + + void *insertPos; + CodeGenModule::ByrefHelpers *node + = CGM.ByrefHelpersCache.FindNodeOrInsertPos(id, insertPos); + if (node) return static_cast<T*>(node); + + byrefInfo.CopyHelper = buildByrefCopyHelper(CGM, byrefTy, byrefInfo); + byrefInfo.DisposeHelper = buildByrefDisposeHelper(CGM, byrefTy, byrefInfo); + + T *copy = new (CGM.getContext()) T(byrefInfo); + CGM.ByrefHelpersCache.InsertNode(copy, insertPos); + return copy; +} + +CodeGenModule::ByrefHelpers * +CodeGenFunction::buildByrefHelpers(const llvm::StructType &byrefType, + const AutoVarEmission &emission) { + const VarDecl &var = *emission.Variable; + QualType type = var.getType(); + + if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) { + const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(&var); + if (!copyExpr && record->hasTrivialDestructor()) return 0; + + CXXByrefHelpers byrefInfo(emission.Alignment, type, copyExpr); + return ::buildByrefHelpers(CGM, byrefType, byrefInfo); } - FinishFunction(); + BlockFieldFlags flags; + if (type->isBlockPointerType()) { + flags |= BLOCK_FIELD_IS_BLOCK; + } else if (CGM.getContext().isObjCNSObjectType(type) || + type->isObjCObjectPointerType()) { + flags |= BLOCK_FIELD_IS_OBJECT; + } else { + return 0; + } - return llvm::ConstantExpr::getBitCast(Fn, Int8PtrTy); + if (type.isObjCGCWeak()) + flags |= BLOCK_FIELD_IS_WEAK; + + ObjectByrefHelpers byrefInfo(emission.Alignment, flags); + return ::buildByrefHelpers(CGM, byrefType, byrefInfo); } -llvm::Constant *CodeGenModule::BuildbyrefCopyHelper(const llvm::Type *T, - BlockFieldFlags flags, - unsigned align, - const VarDecl *var) { - // All alignments below pointer alignment are bumped up, as we - // always have at least that much alignment to begin with. - if (align < PointerAlignInBytes) align = PointerAlignInBytes; +unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const { + assert(ByRefVal |