diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib')
294 files changed, 29816 insertions, 15103 deletions
diff --git a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp index 9c24550..8316ea6 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp index 5bf8a38..897b4a4 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp index 21f10fb..dc881ba 100644 --- a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp b/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp index ca9ec18..9ffe1f8 100644 --- a/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/Decl.cpp b/contrib/llvm/tools/clang/lib/AST/Decl.cpp index 73fe117..b21ba9a 100644 --- a/contrib/llvm/tools/clang/lib/AST/Decl.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp index 81df00d..6d517c5 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp index 46768c1..9099cd5 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp index 45f5188..24d281e 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp index c6ae128..2fd88d7 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp index a73deea..6272340 100644 --- a/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp b/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp index 9d828fc..7d593bc 100644 --- a/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/Expr.cpp b/contrib/llvm/tools/clang/lib/AST/Expr.cpp index 1c1061b..6499f32 100644 --- a/contrib/llvm/tools/clang/lib/AST/Expr.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp b/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp index 4f4a6b4..1a1a0a3 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp index 890898a..888a93c 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp index 3a5eb66..c2caf8d4 100644 --- a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp b/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp new file mode 100644 index 0000000..89bf56d --- /dev/null +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/InheritViz.cpp b/contrib/llvm/tools/clang/lib/AST/InheritViz.cpp index 533a232..c47a9da 100644 --- a/contrib/llvm/tools/clang/lib/AST/InheritViz.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp b/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp index bed02b4..30aece3 100644 --- a/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp index 939ca7a..c460929 100644 --- a/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp b/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp index 4de93bb..206f6dd 100644 --- a/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp index 4bf7f23..5424beb 100644 --- a/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp b/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp index 6f1ec05..2878dff 100644 --- a/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp index 4ed031f..0770e1f 100644 --- a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/Stmt.cpp b/contrib/llvm/tools/clang/lib/AST/Stmt.cpp index 8a80275..380ad94 100644 --- a/contrib/llvm/tools/clang/lib/AST/Stmt.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp b/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp index 5c7dbb3..fb024f3 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/StmtIterator.cpp b/contrib/llvm/tools/clang/lib/AST/StmtIterator.cpp index 9a7265a..9bf4aea 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtIterator.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp index 1cdd220..0d13502 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp index b540011..44818e8 100644 --- a/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp index 1764f4a..6114a5a 100644 --- a/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp index 6b378a0..ebd07f4 100644 --- a/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/Type.cpp b/contrib/llvm/tools/clang/lib/AST/Type.cpp index b03314e..9eb497b 100644 --- a/contrib/llvm/tools/clang/lib/AST/Type.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp b/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp index 14db7f8..34e7693 100644 --- a/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp index 1390739..0c5df7f 100644 --- a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp b/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp index 62097ef..ddc5e88 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/AnalysisContext.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp index cc6e9c5..de16334 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CFG.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/CFGReachabilityAnalysis.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFGReachabilityAnalysis.cpp index 7786584..65cd089 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CFGReachabilityAnalysis.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/CFGStmtMap.cpp b/contrib/llvm/tools/clang/lib/Analysis/CFGStmtMap.cpp index 3a030f9..1fd5eed 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CFGStmtMap.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp b/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp index 22b6c1a..4c62f36 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/CocoaConventions.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp b/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp index ef5c0fb..ce2690f 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp +++ b/contrib/llvm/tools/clang/lib/Analysis/PrintfFormatString.cpp @@ -397,8 +397,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; @@ -414,8 +438,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); @@ -445,24 +467,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/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp b/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp index 7afa586..9ac456f 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/ReachableCode.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp index c08cbed..88a2db7 100644 --- a/contrib/llvm/tools/clang/lib/Analysis/UninitializedValues.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Analysis/UninitializedValuesV2.cpp b/contrib/llvm/tools/clang/lib/Analysis/UninitializedValuesV2.cpp deleted file mode 100644 index 75eccbf..0000000 --- a/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp b/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp index 31e3331..e8cd218 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Diagnostic.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp b/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp index 553e4c9..b4dd575 100644 --- a/contrib/llvm/tools/clang/lib/Basic/DiagnosticIDs.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp b/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp index 342413d..4e5a129 100644 --- a/contrib/llvm/tools/clang/lib/Basic/FileManager.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp b/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp index ef11d65..cb1f55b 100644 --- a/contrib/llvm/tools/clang/lib/Basic/IdentifierTable.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp b/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp index e2783ba..c3e0393 100644 --- a/contrib/llvm/tools/clang/lib/Basic/SourceManager.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp index a9eeb8b..dcf0cb4 100644 --- a/contrib/llvm/tools/clang/lib/Basic/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/Basic/Targets.cpp b/contrib/llvm/tools/clang/lib/Basic/Targets.cpp index 08a9208..97109ca 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Targets.cpp +++ b/contrib/llvm/tools/clang/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") { @@ -1450,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, @@ -1480,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 @@ -1605,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 { @@ -1628,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 @@ -1699,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. @@ -1728,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. @@ -1821,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) { @@ -1983,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: @@ -2562,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: @@ -2594,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); @@ -2609,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); @@ -2630,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: @@ -2662,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: @@ -2682,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/contrib/llvm/tools/clang/lib/Basic/Version.cpp b/contrib/llvm/tools/clang/lib/Basic/Version.cpp index 3a82e5d..89076ca 100644 --- a/contrib/llvm/tools/clang/lib/Basic/Version.cpp +++ b/contrib/llvm/tools/clang/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() { @@ -89,4 +91,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/contrib/llvm/tools/clang/lib/Basic/VersionTuple.cpp b/contrib/llvm/tools/clang/lib/Basic/VersionTuple.cpp new file mode 100644 index 0000000..d5cf126 --- /dev/null +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp b/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp index 9897b1b..1264473 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/BackendUtil.cpp +++ b/contrib/llvm/tools/clang/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/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp index 9587de2..99a69a4 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.cpp +++ b/contrib/llvm/tools/clang/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(ByRefValueInfo.count(VD) && "Did not find value!"); - // As an optimization, we only generate a single function of each kind we - // might need. We need a different one for each alignment and for each - // setting of flags. We mix Align and flag to get the kind. - uint64_t Kind = (uint64_t)align*BLOCK_BYREF_CURRENT_MAX + flags.getBitMask(); - llvm::Constant *&Entry = AssignCache[Kind]; - if (!Entry) - Entry = CodeGenFunction(*this). - GeneratebyrefCopyHelperFunction(T, flags, var); - return Entry; + return ByRefValueInfo.find(VD)->second.second; +} + +llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr, + const VarDecl *V) { + llvm::Value *Loc = Builder.CreateStructGEP(BaseAddr, 1, "forwarding"); + Loc = Builder.CreateLoad(Loc); + Loc = Builder.CreateStructGEP(Loc, getByRefValueLLVMField(V), + V->getNameAsString()); + return Loc; } -llvm::Constant *CodeGenModule::BuildbyrefDestroyHelper(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; +/// BuildByRefType - This routine changes a __block variable declared as T x +/// into: +/// +/// struct { +/// void *__isa; +/// void *__forwarding; +/// int32_t __flags; +/// int32_t __size; +/// void *__copy_helper; // only if needed +/// void *__destroy_helper; // only if needed +/// char padding[X]; // only if needed +/// T x; +/// } x +/// +const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { + std::pair<const llvm::Type *, unsigned> &Info = ByRefValueInfo[D]; + if (Info.first) + return Info.first; + + QualType Ty = D->getType(); + + std::vector<const llvm::Type *> Types; + + llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(getLLVMContext()); + + // void *__isa; + Types.push_back(Int8PtrTy); + + // void *__forwarding; + Types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder)); + + // int32_t __flags; + Types.push_back(Int32Ty); + + // int32_t __size; + Types.push_back(Int32Ty); + + bool HasCopyAndDispose = getContext().BlockRequiresCopying(Ty); + if (HasCopyAndDispose) { + /// void *__copy_helper; + Types.push_back(Int8PtrTy); + + /// void *__destroy_helper; + Types.push_back(Int8PtrTy); + } + + bool Packed = false; + CharUnits Align = getContext().getDeclAlign(D); + if (Align > getContext().toCharUnitsFromBits(Target.getPointerAlign(0))) { + // We have to insert padding. + + // The struct above has 2 32-bit integers. + unsigned CurrentOffsetInBytes = 4 * 2; + + // And either 2 or 4 pointers. + CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) * + CGM.getTargetData().getTypeAllocSize(Int8PtrTy); + + // Align the offset. + unsigned AlignedOffsetInBytes = + llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align.getQuantity()); + + unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes; + if (NumPaddingBytes > 0) { + const llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext()); + // FIXME: We need a sema error for alignment larger than the minimum of + // the maximal stack alignmint and the alignment of malloc on the system. + if (NumPaddingBytes > 1) + Ty = llvm::ArrayType::get(Ty, NumPaddingBytes); + + Types.push_back(Ty); + + // We want a packed struct. + Packed = true; + } + } + + // T x; + Types.push_back(ConvertTypeForMem(Ty)); + + const llvm::Type *T = llvm::StructType::get(getLLVMContext(), Types, Packed); + + cast<llvm::OpaqueType>(ByRefTypeHolder.get())->refineAbstractTypeTo(T); + CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(), + ByRefTypeHolder.get()); - // As an optimization, we only generate a single function of each kind we - // might need. We need a different one for each alignment and for each - // setting of flags. We mix Align and flag to get the kind. - uint64_t Kind = (uint64_t)align*BLOCK_BYREF_CURRENT_MAX + flags.getBitMask(); - llvm::Constant *&Entry = DestroyCache[Kind]; - if (!Entry) - Entry = CodeGenFunction(*this). - GeneratebyrefDestroyHelperFunction(T, flags, var); - return Entry; + Info.first = ByRefTypeHolder.get(); + + Info.second = Types.size() - 1; + + return Info.first; +} + +/// Initialize the structural components of a __block variable, i.e. +/// everything but the actual object. +void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) { + // Find the address of the local. + llvm::Value *addr = emission.Address; + + // That's an alloca of the byref structure type. + const llvm::StructType *byrefType = cast<llvm::StructType>( + cast<llvm::PointerType>(addr->getType())->getElementType()); + + // Build the byref helpers if necessary. This is null if we don't need any. + CodeGenModule::ByrefHelpers *helpers = + buildByrefHelpers(*byrefType, emission); + + const VarDecl &D = *emission.Variable; + QualType type = D.getType(); + + llvm::Value *V; + + // Initialize the 'isa', which is just 0 or 1. + int isa = 0; + if (type.isObjCGCWeak()) + isa = 1; + V = Builder.CreateIntToPtr(Builder.getInt32(isa), Int8PtrTy, "isa"); + Builder.CreateStore(V, Builder.CreateStructGEP(addr, 0, "byref.isa")); + + // Store the address of the variable into its own forwarding pointer. + Builder.CreateStore(addr, + Builder.CreateStructGEP(addr, 1, "byref.forwarding")); + + // Blocks ABI: + // c) the flags field is set to either 0 if no helper functions are + // needed or BLOCK_HAS_COPY_DISPOSE if they are, + BlockFlags flags; + if (helpers) flags |= BLOCK_HAS_COPY_DISPOSE; + Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()), + Builder.CreateStructGEP(addr, 2, "byref.flags")); + + CharUnits byrefSize = CGM.GetTargetTypeStoreSize(byrefType); + V = llvm::ConstantInt::get(IntTy, byrefSize.getQuantity()); + Builder.CreateStore(V, Builder.CreateStructGEP(addr, 3, "byref.size")); + + if (helpers) { + llvm::Value *copy_helper = Builder.CreateStructGEP(addr, 4); + Builder.CreateStore(helpers->CopyHelper, copy_helper); + + llvm::Value *destroy_helper = Builder.CreateStructGEP(addr, 5); + Builder.CreateStore(helpers->DisposeHelper, destroy_helper); + } } void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) { @@ -1413,3 +1638,26 @@ void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) { N = llvm::ConstantInt::get(Int32Ty, flags.getBitMask()); Builder.CreateCall2(F, V, N); } + +namespace { + struct CallBlockRelease : EHScopeStack::Cleanup { + llvm::Value *Addr; + CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF); + } + }; +} + +/// Enter a cleanup to destroy a __block variable. Note that this +/// cleanup should be a no-op if the variable hasn't left the stack +/// yet; if a cleanup is required for the variable itself, that needs +/// to be done externally. +void CodeGenFunction::enterByrefCleanup(const AutoVarEmission &emission) { + // We don't enter this cleanup if we're in pure-GC mode. + if (CGM.getLangOptions().getGCMode() == LangOptions::GCOnly) + return; + + EHStack.pushCleanup<CallBlockRelease>(NormalAndEHCleanup, emission.Address); +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h index 0bc8bca..9bd18e5 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBlocks.h @@ -173,6 +173,10 @@ public: /// need to be run even in GC mode. bool HasCXXObject : 1; + /// UsesStret : True if the block uses an stret return. Mutable + /// because it gets set later in the block-creation process. + mutable bool UsesStret : 1; + const llvm::StructType *StructureType; const BlockExpr *Block; CharUnits BlockSize; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp index 5eeb605..7a0c8da 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGBuiltin.cpp @@ -176,7 +176,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E) { // See if we can constant fold this builtin. If so, don't emit it at all. Expr::EvalResult Result; - if (E->Evaluate(Result, CGM.getContext())) { + if (E->Evaluate(Result, CGM.getContext()) && + !Result.hasSideEffects()) { if (Result.Val.isInt()) return RValue::get(llvm::ConstantInt::get(getLLVMContext(), Result.Val.getInt())); @@ -312,9 +313,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BI__builtin_expect: { // FIXME: pass expect through to LLVM + Value *ArgValue = EmitScalarExpr(E->getArg(0)); if (E->getArg(1)->HasSideEffects(getContext())) (void)EmitScalarExpr(E->getArg(1)); - return RValue::get(EmitScalarExpr(E->getArg(0))); + return RValue::get(ArgValue); } case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: { @@ -473,7 +475,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, BasicBlock *End = createBasicBlock("fpclassify_end", this->CurFn); Builder.SetInsertPoint(End); PHINode *Result = - Builder.CreatePHI(ConvertType(E->getArg(0)->getType()), + Builder.CreatePHI(ConvertType(E->getArg(0)->getType()), 4, "fpclassify_result"); // if (V==0) return FP_ZERO @@ -543,6 +545,22 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Address); } + case Builtin::BI__builtin___memcpy_chk: { + // fold __builtin_memcpy_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. + if (!E->getArg(2)->isEvaluatable(CGM.getContext()) || + !E->getArg(3)->isEvaluatable(CGM.getContext())) + break; + llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext()); + llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext()); + if (Size.ugt(DstSize)) + break; + Value *Dest = EmitScalarExpr(E->getArg(0)); + Value *Src = EmitScalarExpr(E->getArg(1)); + Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); + Builder.CreateMemCpy(Dest, Src, SizeVal, 1, false); + return RValue::get(Dest); + } + case Builtin::BI__builtin_objc_memmove_collectable: { Value *Address = EmitScalarExpr(E->getArg(0)); Value *SrcAddr = EmitScalarExpr(E->getArg(1)); @@ -551,7 +569,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Address, SrcAddr, SizeVal); return RValue::get(Address); } - + + case Builtin::BI__builtin___memmove_chk: { + // fold __builtin_memmove_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. + if (!E->getArg(2)->isEvaluatable(CGM.getContext()) || + !E->getArg(3)->isEvaluatable(CGM.getContext())) + break; + llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext()); + llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext()); + if (Size.ugt(DstSize)) + break; + Value *Dest = EmitScalarExpr(E->getArg(0)); + Value *Src = EmitScalarExpr(E->getArg(1)); + Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); + Builder.CreateMemMove(Dest, Src, SizeVal, 1, false); + return RValue::get(Dest); + } + case Builtin::BImemmove: case Builtin::BI__builtin_memmove: { Value *Address = EmitScalarExpr(E->getArg(0)); @@ -569,6 +603,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Builder.CreateMemSet(Address, ByteVal, SizeVal, 1, false); return RValue::get(Address); } + case Builtin::BI__builtin___memset_chk: { + // fold __builtin_memset_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. + if (!E->getArg(2)->isEvaluatable(CGM.getContext()) || + !E->getArg(3)->isEvaluatable(CGM.getContext())) + break; + llvm::APSInt Size = E->getArg(2)->EvaluateAsInt(CGM.getContext()); + llvm::APSInt DstSize = E->getArg(3)->EvaluateAsInt(CGM.getContext()); + if (Size.ugt(DstSize)) + break; + Value *Address = EmitScalarExpr(E->getArg(0)); + Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)), + Builder.getInt8Ty()); + Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); + Builder.CreateMemSet(Address, ByteVal, SizeVal, 1, false); + + return RValue::get(Address); + } case Builtin::BI__builtin_dwarf_cfa: { // The offset in bytes from the first argument to the CFA. // @@ -721,6 +772,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_bool_compare_and_swap: case Builtin::BI__sync_lock_test_and_set: case Builtin::BI__sync_lock_release: + case Builtin::BI__sync_swap: assert(0 && "Shouldn't make it through sema"); case Builtin::BI__sync_fetch_and_add_1: case Builtin::BI__sync_fetch_and_add_2: @@ -860,6 +912,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Result); } + case Builtin::BI__sync_swap_1: + case Builtin::BI__sync_swap_2: + case Builtin::BI__sync_swap_4: + case Builtin::BI__sync_swap_8: + case Builtin::BI__sync_swap_16: + return EmitBinaryAtomic(*this, Intrinsic::atomic_swap, E); + case Builtin::BI__sync_lock_test_and_set_1: case Builtin::BI__sync_lock_test_and_set_2: case Builtin::BI__sync_lock_test_and_set_4: @@ -948,8 +1007,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return EmitCall(E->getCallee()->getType(), CGM.getBuiltinLibFunction(FD, BuiltinID), - ReturnValueSlot(), - E->arg_begin(), E->arg_end()); + ReturnValueSlot(), E->arg_begin(), E->arg_end(), FD); // See if we have a target specific intrinsic. const char *Name = getContext().BuiltinInfo.GetName(BuiltinID); @@ -1116,13 +1174,16 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { if (BuiltinID == ARM::BI__clear_cache) { const FunctionDecl *FD = E->getDirectCallee(); - Value *a = EmitScalarExpr(E->getArg(0)); - Value *b = EmitScalarExpr(E->getArg(1)); + // Oddly people write this call without args on occasion and gcc accepts + // it - it's also marked as varargs in the description file. + llvm::SmallVector<Value*, 2> Ops; + for (unsigned i = 0; i < E->getNumArgs(); i++) + Ops.push_back(EmitScalarExpr(E->getArg(i))); const llvm::Type *Ty = CGM.getTypes().ConvertType(FD->getType()); const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty); llvm::StringRef Name = FD->getName(); - return Builder.CreateCall2(CGM.CreateRuntimeFunction(FTy, Name), - a, b); + return Builder.CreateCall(CGM.CreateRuntimeFunction(FTy, Name), + Ops.begin(), Ops.end()); } llvm::SmallVector<Value*, 4> Ops; @@ -1462,9 +1523,9 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vmulp, &Ty, 1), Ops, "vmul"); case ARM::BI__builtin_neon_vmull_v: - assert(poly && "vmull builtin only supported for polynomial types"); - return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vmullp, &Ty, 1), - Ops, "vmull"); + Int = usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls; + Int = poly ? (unsigned)Intrinsic::arm_neon_vmullp : Int; + return EmitNeonCall(CGM.getIntrinsic(Int, &Ty, 1), Ops, "vmull"); case ARM::BI__builtin_neon_vpadal_v: case ARM::BI__builtin_neon_vpadalq_v: { Int = usgn ? Intrinsic::arm_neon_vpadalu : Intrinsic::arm_neon_vpadals; @@ -2082,6 +2143,149 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, // If palignr is shifting the pair of vectors more than 32 bytes, emit zero. return llvm::Constant::getNullValue(ConvertType(E->getType())); } + case X86::BI__builtin_ia32_loaddqu: { + const llvm::Type *VecTy = ConvertType(E->getType()); + const llvm::Type *IntTy = llvm::IntegerType::get(getLLVMContext(), 128); + + Value *BC = Builder.CreateBitCast(Ops[0], + llvm::PointerType::getUnqual(IntTy), + "cast"); + LoadInst *LI = Builder.CreateLoad(BC); + LI->setAlignment(1); // Unaligned load. + return Builder.CreateBitCast(LI, VecTy, "loadu.cast"); + } + // 3DNow! + case X86::BI__builtin_ia32_pavgusb: + case X86::BI__builtin_ia32_pf2id: + case X86::BI__builtin_ia32_pfacc: + case X86::BI__builtin_ia32_pfadd: + case X86::BI__builtin_ia32_pfcmpeq: + case X86::BI__builtin_ia32_pfcmpge: + case X86::BI__builtin_ia32_pfcmpgt: + case X86::BI__builtin_ia32_pfmax: + case X86::BI__builtin_ia32_pfmin: + case X86::BI__builtin_ia32_pfmul: + case X86::BI__builtin_ia32_pfrcp: + case X86::BI__builtin_ia32_pfrcpit1: + case X86::BI__builtin_ia32_pfrcpit2: + case X86::BI__builtin_ia32_pfrsqrt: + case X86::BI__builtin_ia32_pfrsqit1: + case X86::BI__builtin_ia32_pfrsqrtit1: + case X86::BI__builtin_ia32_pfsub: + case X86::BI__builtin_ia32_pfsubr: + case X86::BI__builtin_ia32_pi2fd: + case X86::BI__builtin_ia32_pmulhrw: + case X86::BI__builtin_ia32_pf2iw: + case X86::BI__builtin_ia32_pfnacc: + case X86::BI__builtin_ia32_pfpnacc: + case X86::BI__builtin_ia32_pi2fw: + case X86::BI__builtin_ia32_pswapdsf: + case X86::BI__builtin_ia32_pswapdsi: { + const char *name = 0; + Intrinsic::ID ID = Intrinsic::not_intrinsic; + switch(BuiltinID) { + case X86::BI__builtin_ia32_pavgusb: + name = "pavgusb"; + ID = Intrinsic::x86_3dnow_pavgusb; + break; + case X86::BI__builtin_ia32_pf2id: + name = "pf2id"; + ID = Intrinsic::x86_3dnow_pf2id; + break; + case X86::BI__builtin_ia32_pfacc: + name = "pfacc"; + ID = Intrinsic::x86_3dnow_pfacc; + break; + case X86::BI__builtin_ia32_pfadd: + name = "pfadd"; + ID = Intrinsic::x86_3dnow_pfadd; + break; + case X86::BI__builtin_ia32_pfcmpeq: + name = "pfcmpeq"; + ID = Intrinsic::x86_3dnow_pfcmpeq; + break; + case X86::BI__builtin_ia32_pfcmpge: + name = "pfcmpge"; + ID = Intrinsic::x86_3dnow_pfcmpge; + break; + case X86::BI__builtin_ia32_pfcmpgt: + name = "pfcmpgt"; + ID = Intrinsic::x86_3dnow_pfcmpgt; + break; + case X86::BI__builtin_ia32_pfmax: + name = "pfmax"; + ID = Intrinsic::x86_3dnow_pfmax; + break; + case X86::BI__builtin_ia32_pfmin: + name = "pfmin"; + ID = Intrinsic::x86_3dnow_pfmin; + break; + case X86::BI__builtin_ia32_pfmul: + name = "pfmul"; + ID = Intrinsic::x86_3dnow_pfmul; + break; + case X86::BI__builtin_ia32_pfrcp: + name = "pfrcp"; + ID = Intrinsic::x86_3dnow_pfrcp; + break; + case X86::BI__builtin_ia32_pfrcpit1: + name = "pfrcpit1"; + ID = Intrinsic::x86_3dnow_pfrcpit1; + break; + case X86::BI__builtin_ia32_pfrcpit2: + name = "pfrcpit2"; + ID = Intrinsic::x86_3dnow_pfrcpit2; + break; + case X86::BI__builtin_ia32_pfrsqrt: + name = "pfrsqrt"; + ID = Intrinsic::x86_3dnow_pfrsqrt; + break; + case X86::BI__builtin_ia32_pfrsqit1: + case X86::BI__builtin_ia32_pfrsqrtit1: + name = "pfrsqit1"; + ID = Intrinsic::x86_3dnow_pfrsqit1; + break; + case X86::BI__builtin_ia32_pfsub: + name = "pfsub"; + ID = Intrinsic::x86_3dnow_pfsub; + break; + case X86::BI__builtin_ia32_pfsubr: + name = "pfsubr"; + ID = Intrinsic::x86_3dnow_pfsubr; + break; + case X86::BI__builtin_ia32_pi2fd: + name = "pi2fd"; + ID = Intrinsic::x86_3dnow_pi2fd; + break; + case X86::BI__builtin_ia32_pmulhrw: + name = "pmulhrw"; + ID = Intrinsic::x86_3dnow_pmulhrw; + break; + case X86::BI__builtin_ia32_pf2iw: + name = "pf2iw"; + ID = Intrinsic::x86_3dnowa_pf2iw; + break; + case X86::BI__builtin_ia32_pfnacc: + name = "pfnacc"; + ID = Intrinsic::x86_3dnowa_pfnacc; + break; + case X86::BI__builtin_ia32_pfpnacc: + name = "pfpnacc"; + ID = Intrinsic::x86_3dnowa_pfpnacc; + break; + case X86::BI__builtin_ia32_pi2fw: + name = "pi2fw"; + ID = Intrinsic::x86_3dnowa_pi2fw; + break; + case X86::BI__builtin_ia32_pswapdsf: + case X86::BI__builtin_ia32_pswapdsi: + name = "pswapd"; + ID = Intrinsic::x86_3dnowa_pswapd; + break; + } + llvm::Function *F = CGM.getIntrinsic(ID); + return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size(), name); + } } } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp index 7ffc6e7..184147c 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXX.cpp @@ -194,39 +194,44 @@ void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) { EmitGlobal(GlobalDecl(D, Ctor_Base)); } -void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D, - CXXCtorType Type) { +void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor, + CXXCtorType ctorType) { // The complete constructor is equivalent to the base constructor // for classes with no virtual bases. Try to emit it as an alias. - if (Type == Ctor_Complete && - !D->getParent()->getNumVBases() && - !TryEmitDefinitionAsAlias(GlobalDecl(D, Ctor_Complete), - GlobalDecl(D, Ctor_Base))) + if (ctorType == Ctor_Complete && + !ctor->getParent()->getNumVBases() && + !TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete), + GlobalDecl(ctor, Ctor_Base))) return; - llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXConstructor(D, Type)); - setFunctionLinkage(D, Fn); + const CGFunctionInfo &fnInfo = getTypes().getFunctionInfo(ctor, ctorType); - CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); + llvm::Function *fn = + cast<llvm::Function>(GetAddrOfCXXConstructor(ctor, ctorType, &fnInfo)); + setFunctionLinkage(ctor, fn); - SetFunctionDefinitionAttributes(D, Fn); - SetLLVMFunctionAttributesForDefinition(D, Fn); + CodeGenFunction(*this).GenerateCode(GlobalDecl(ctor, ctorType), fn, fnInfo); + + SetFunctionDefinitionAttributes(ctor, fn); + SetLLVMFunctionAttributesForDefinition(ctor, fn); } llvm::GlobalValue * -CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D, - CXXCtorType Type) { - GlobalDecl GD(D, Type); +CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor, + CXXCtorType ctorType, + const CGFunctionInfo *fnInfo) { + GlobalDecl GD(ctor, ctorType); - llvm::StringRef Name = getMangledName(GD); - if (llvm::GlobalValue *V = GetGlobalValue(Name)) - return V; - - const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>(); - const llvm::FunctionType *FTy = - getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), - FPT->isVariadic()); - return cast<llvm::Function>(GetOrCreateLLVMFunction(Name, FTy, GD, + llvm::StringRef name = getMangledName(GD); + if (llvm::GlobalValue *existing = GetGlobalValue(name)) + return existing; + + if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(ctor, ctorType); + + const FunctionProtoType *proto = ctor->getType()->castAs<FunctionProtoType>(); + const llvm::FunctionType *fnType = + getTypes().GetFunctionType(*fnInfo, proto->isVariadic()); + return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD, /*ForVTable=*/false)); } @@ -246,45 +251,51 @@ void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) { EmitGlobal(GlobalDecl(D, Dtor_Base)); } -void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D, - CXXDtorType Type) { +void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor, + CXXDtorType dtorType) { // The complete destructor is equivalent to the base destructor for // classes with no virtual bases, so try to emit it as an alias. - if (Type == Dtor_Complete && - !D->getParent()->getNumVBases() && - !TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Complete), - GlobalDecl(D, Dtor_Base))) + if (dtorType == Dtor_Complete && + !dtor->getParent()->getNumVBases() && + !TryEmitDefinitionAsAlias(GlobalDecl(dtor, Dtor_Complete), + GlobalDecl(dtor, Dtor_Base))) return; // The base destructor is equivalent to the base destructor of its // base class if there is exactly one non-virtual base class with a // non-trivial destructor, there are no fields with a non-trivial // destructor, and the body of the destructor is trivial. - if (Type == Dtor_Base && !TryEmitBaseDestructorAsAlias(D)) + if (dtorType == Dtor_Base && !TryEmitBaseDestructorAsAlias(dtor)) return; - llvm::Function *Fn = cast<llvm::Function>(GetAddrOfCXXDestructor(D, Type)); - setFunctionLinkage(D, Fn); + const CGFunctionInfo &fnInfo = getTypes().getFunctionInfo(dtor, dtorType); - CodeGenFunction(*this).GenerateCode(GlobalDecl(D, Type), Fn); + llvm::Function *fn = + cast<llvm::Function>(GetAddrOfCXXDestructor(dtor, dtorType, &fnInfo)); + setFunctionLinkage(dtor, fn); - SetFunctionDefinitionAttributes(D, Fn); - SetLLVMFunctionAttributesForDefinition(D, Fn); + CodeGenFunction(*this).GenerateCode(GlobalDecl(dtor, dtorType), fn, fnInfo); + + SetFunctionDefinitionAttributes(dtor, fn); + SetLLVMFunctionAttributesForDefinition(dtor, fn); } llvm::GlobalValue * -CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D, - CXXDtorType Type) { - GlobalDecl GD(D, Type); +CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor, + CXXDtorType dtorType, + const CGFunctionInfo *fnInfo) { + GlobalDecl GD(dtor, dtorType); + + llvm::StringRef name = getMangledName(GD); + if (llvm::GlobalValue *existing = GetGlobalValue(name)) + return existing; - llvm::StringRef Name = getMangledName(GD); - if (llvm::GlobalValue *V = GetGlobalValue(Name)) - return V; + if (!fnInfo) fnInfo = &getTypes().getFunctionInfo(dtor, dtorType); - const llvm::FunctionType *FTy = - getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), false); + const llvm::FunctionType *fnType = + getTypes().GetFunctionType(*fnInfo, false); - return cast<llvm::Function>(GetOrCreateLLVMFunction(Name, FTy, GD, + return cast<llvm::Function>(GetOrCreateLLVMFunction(name, fnType, GD, /*ForVTable=*/false)); } @@ -334,7 +345,7 @@ CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD, MD = MD->getCanonicalDecl(); uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(MD); uint64_t AddressPoint = - CGM.getVTables().getAddressPoint(BaseSubobject(RD, 0), RD); + CGM.getVTables().getAddressPoint(BaseSubobject(RD, CharUnits::Zero()), RD); VTableIndex += AddressPoint; llvm::Value *VFuncPtr = Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt"); @@ -369,7 +380,7 @@ CodeGenFunction::BuildAppleKextVirtualDestructorCall( uint64_t VTableIndex = CGM.getVTables().getMethodVTableIndex(GlobalDecl(DD, Type)); uint64_t AddressPoint = - CGM.getVTables().getAddressPoint(BaseSubobject(RD, 0), RD); + CGM.getVTables().getAddressPoint(BaseSubobject(RD, CharUnits::Zero()), RD); VTableIndex += AddressPoint; llvm::Value *VFuncPtr = Builder.CreateConstInBoundsGEP1_64(VTable, VTableIndex, "vfnkxt"); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp index 8373b66..92f1c63 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCXXABI.cpp @@ -115,7 +115,7 @@ bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) { return true; } -void CGCXXABI::BuildThisParam(CodeGenFunction &CGF, FunctionArgList &Params) { +void CGCXXABI::BuildThisParam(CodeGenFunction &CGF, FunctionArgList ¶ms) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl()); // FIXME: I'm not entirely sure I like using a fake decl just for code @@ -124,7 +124,7 @@ void CGCXXABI::BuildThisParam(CodeGenFunction &CGF, FunctionArgList &Params) { = ImplicitParamDecl::Create(CGM.getContext(), 0, MD->getLocation(), &CGM.getContext().Idents.get("this"), MD->getThisType(CGM.getContext())); - Params.push_back(std::make_pair(ThisDecl, ThisDecl->getType())); + params.push_back(ThisDecl); getThisDecl(CGF) = ThisDecl; } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp index ae84b61..a765f0f 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.cpp @@ -36,6 +36,8 @@ static unsigned ClangCallConvToLLVMCallConv(CallingConv CC) { case CC_X86StdCall: return llvm::CallingConv::X86_StdCall; case CC_X86FastCall: return llvm::CallingConv::X86_FastCall; case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall; + case CC_AAPCS: return llvm::CallingConv::ARM_AAPCS; + case CC_AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP; // TODO: add support for CC_X86Pascal to llvm } } @@ -104,6 +106,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) { if (D->hasAttr<PascalAttr>()) return CC_X86Pascal; + if (PcsAttr *PCS = D->getAttr<PcsAttr>()) + return (PCS->getPCS() == PcsAttr::AAPCS ? CC_AAPCS : CC_AAPCS_VFP); + return CC_C; } @@ -188,6 +193,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const ObjCMethodDecl *MD) { ArgTys, FunctionType::ExtInfo( /*NoReturn*/ false, + /*HasRegParm*/ false, /*RegParm*/ 0, getCallingConventionForDecl(MD))); } @@ -212,7 +218,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, llvm::SmallVector<CanQualType, 16> ArgTys; for (CallArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) - ArgTys.push_back(Context.getCanonicalParamType(i->second)); + ArgTys.push_back(Context.getCanonicalParamType(i->Ty)); return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info); } @@ -223,10 +229,15 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(QualType ResTy, llvm::SmallVector<CanQualType, 16> ArgTys; for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) - ArgTys.push_back(Context.getCanonicalParamType(i->second)); + ArgTys.push_back(Context.getCanonicalParamType((*i)->getType())); return getFunctionInfo(GetReturnType(ResTy), ArgTys, Info); } +const CGFunctionInfo &CodeGenTypes::getNullaryFunctionInfo() { + llvm::SmallVector<CanQualType, 1> args; + return getFunctionInfo(getContext().VoidTy, args, FunctionType::ExtInfo()); +} + const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, const llvm::SmallVectorImpl<CanQualType> &ArgTys, const FunctionType::ExtInfo &Info, @@ -250,7 +261,7 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, return *FI; // Construct the function info. - FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getRegParm(), ResTy, + FI = new CGFunctionInfo(CC, Info.getNoReturn(), Info.getHasRegParm(), Info.getRegParm(), ResTy, ArgTys.data(), ArgTys.size()); FunctionInfos.InsertNode(FI, InsertPos); @@ -279,13 +290,13 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(CanQualType ResTy, } CGFunctionInfo::CGFunctionInfo(unsigned _CallingConvention, - bool _NoReturn, unsigned _RegParm, + bool _NoReturn, bool _HasRegParm, unsigned _RegParm, CanQualType ResTy, const CanQualType *ArgTys, unsigned NumArgTys) : CallingConvention(_CallingConvention), EffectiveCallingConvention(_CallingConvention), - NoReturn(_NoReturn), RegParm(_RegParm) + NoReturn(_NoReturn), HasRegParm(_HasRegParm), RegParm(_RegParm) { NumArgs = NumArgTys; @@ -622,7 +633,8 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic, assert(!RetAI.getIndirectAlign() && "Align unused on indirect return."); ResultType = llvm::Type::getVoidTy(getLLVMContext()); const llvm::Type *STy = ConvertType(RetTy, IsRecursive); - ArgTys.push_back(llvm::PointerType::get(STy, RetTy.getAddressSpace())); + unsigned AS = Context.getTargetAddressSpace(RetTy); + ArgTys.push_back(llvm::PointerType::get(STy, AS)); break; } @@ -704,7 +716,7 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, FuncAttrs |= llvm::Attribute::NoUnwind; else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) { const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>(); - if (FPT && FPT->hasEmptyExceptionSpec()) + if (FPT && FPT->isNothrow(getContext())) FuncAttrs |= llvm::Attribute::NoUnwind; } @@ -756,8 +768,10 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs)); // FIXME: RegParm should be reduced in case of global register variable. - signed RegParm = FI.getRegParm(); - if (!RegParm) + signed RegParm; + if (FI.getHasRegParm()) + RegParm = FI.getRegParm(); + else RegParm = CodeGenOpts.NumRegisterParameters; unsigned PointerWidth = getContext().Target.getPointerWidth(0); @@ -826,6 +840,26 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, PAL.push_back(llvm::AttributeWithIndex::get(~0, FuncAttrs)); } +/// An argument came in as a promoted argument; demote it back to its +/// declared type. +static llvm::Value *emitArgumentDemotion(CodeGenFunction &CGF, + const VarDecl *var, + llvm::Value *value) { + const llvm::Type *varType = CGF.ConvertType(var->getType()); + + // This can happen with promotions that actually don't change the + // underlying type, like the enum promotions. + if (value->getType() == varType) return value; + + assert((varType->isIntegerTy() || varType->isFloatingPointTy()) + && "unexpected promotion type"); + + if (isa<llvm::IntegerType>(varType)) + return CGF.Builder.CreateTrunc(value, varType, "arg.unpromote"); + + return CGF.Builder.CreateFPCast(value, varType, "arg.unpromote"); +} + void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, llvm::Function *Fn, const FunctionArgList &Args) { @@ -856,13 +890,17 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, assert(FI.arg_size() == Args.size() && "Mismatch between function signature & arguments."); + unsigned ArgNo = 1; CGFunctionInfo::const_arg_iterator info_it = FI.arg_begin(); - for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); - i != e; ++i, ++info_it) { - const VarDecl *Arg = i->first; + for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); + i != e; ++i, ++info_it, ++ArgNo) { + const VarDecl *Arg = *i; QualType Ty = info_it->type; const ABIArgInfo &ArgI = info_it->info; + bool isPromoted = + isa<ParmVarDecl>(Arg) && cast<ParmVarDecl>(Arg)->isKNRPromoted(); + switch (ArgI.getKind()) { case ABIArgInfo::Indirect: { llvm::Value *V = AI; @@ -880,8 +918,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // copy. const llvm::Type *I8PtrTy = Builder.getInt8PtrTy(); CharUnits Size = getContext().getTypeSizeInChars(Ty); - Builder.CreateMemCpy(Builder.CreateBitCast(AlignedTemp, I8PtrTy), - Builder.CreateBitCast(V, I8PtrTy), + llvm::Value *Dst = Builder.CreateBitCast(AlignedTemp, I8PtrTy); + llvm::Value *Src = Builder.CreateBitCast(V, I8PtrTy); + Builder.CreateMemCpy(Dst, + Src, llvm::ConstantInt::get(IntPtrTy, Size.getQuantity()), ArgI.getIndirectAlign(), @@ -892,13 +932,11 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // Load scalar value from indirect argument. CharUnits Alignment = getContext().getTypeAlignInChars(Ty); V = EmitLoadOfScalar(V, false, Alignment.getQuantity(), Ty); - if (!getContext().typesAreCompatible(Ty, Arg->getType())) { - // This must be a promotion, for something like - // "void a(x) short x; {..." - V = EmitScalarConversion(V, Ty, Arg->getType()); - } + + if (isPromoted) + V = emitArgumentDemotion(*this, Arg, V); } - EmitParmDecl(*Arg, V); + EmitParmDecl(*Arg, V, ArgNo); break; } @@ -914,12 +952,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, if (Arg->getType().isRestrictQualified()) AI->addAttr(llvm::Attribute::NoAlias); - if (!getContext().typesAreCompatible(Ty, Arg->getType())) { - // This must be a promotion, for something like - // "void a(x) short x; {..." - V = EmitScalarConversion(V, Ty, Arg->getType()); - } - EmitParmDecl(*Arg, V); + if (isPromoted) + V = emitArgumentDemotion(*this, Arg, V); + + EmitParmDecl(*Arg, V, ArgNo); break; } @@ -968,13 +1004,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // Match to what EmitParmDecl is expecting for this type. if (!CodeGenFunction::hasAggregateLLVMType(Ty)) { V = EmitLoadOfScalar(V, false, AlignmentToUse, Ty); - if (!getContext().typesAreCompatible(Ty, Arg->getType())) { - // This must be a promotion, for something like - // "void a(x) short x; {..." - V = EmitScalarConversion(V, Ty, Arg->getType()); - } + if (isPromoted) + V = emitArgumentDemotion(*this, Arg, V); } - EmitParmDecl(*Arg, V); + EmitParmDecl(*Arg, V, ArgNo); continue; // Skip ++AI increment, already done. } @@ -985,7 +1018,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, llvm::Value *Temp = CreateMemTemp(Ty, Arg->getName() + ".addr"); llvm::Function::arg_iterator End = ExpandTypeFromArgs(Ty, MakeAddrLValue(Temp, Ty), AI); - EmitParmDecl(*Arg, Temp); + EmitParmDecl(*Arg, Temp, ArgNo); // Name the arguments used in expansion and increment AI. unsigned Index = 0; @@ -997,9 +1030,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, case ABIArgInfo::Ignore: // Initialize the local variable appropriately. if (hasAggregateLLVMType(Ty)) - EmitParmDecl(*Arg, CreateMemTemp(Ty)); + EmitParmDecl(*Arg, CreateMemTemp(Ty), ArgNo); else - EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType()))); + EmitParmDecl(*Arg, llvm::UndefValue::get(ConvertType(Arg->getType())), + ArgNo); // Skip increment, no matching LLVM parameter. continue; @@ -1091,42 +1125,48 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) { Ret->setDebugLoc(RetDbgLoc); } -RValue CodeGenFunction::EmitDelegateCallArg(const VarDecl *Param) { +void CodeGenFunction::EmitDelegateCallArg(CallArgList &args, + const VarDecl *param) { // StartFunction converted the ABI-lowered parameter(s) into a // local alloca. We need to turn that into an r-value suitable // for EmitCall. - llvm::Value *Local = GetAddrOfLocalVar(Param); + llvm::Value *local = GetAddrOfLocalVar(param); - QualType ArgType = Param->getType(); + QualType type = param->getType(); // For the most part, we just need to load the alloca, except: // 1) aggregate r-values are actually pointers to temporaries, and // 2) references to aggregates are pointers directly to the aggregate. // I don't know why references to non-aggregates are different here. - if (const ReferenceType *RefType = ArgType->getAs<ReferenceType>()) { - if (hasAggregateLLVMType(RefType->getPointeeType())) - return RValue::getAggregate(Local); + if (const ReferenceType *ref = type->getAs<ReferenceType>()) { + if (hasAggregateLLVMType(ref->getPointeeType())) + return args.add(RValue::getAggregate(local), type); // Locals which are references to scalars are represented // with allocas holding the pointer. - return RValue::get(Builder.CreateLoad(Local)); + return args.add(RValue::get(Builder.CreateLoad(local)), type); } - if (ArgType->isAnyComplexType()) - return RValue::getComplex(LoadComplexFromAddr(Local, /*volatile*/ false)); + if (type->isAnyComplexType()) { + ComplexPairTy complex = LoadComplexFromAddr(local, /*volatile*/ false); + return args.add(RValue::getComplex(complex), type); + } - if (hasAggregateLLVMType(ArgType)) - return RValue::getAggregate(Local); + if (hasAggregateLLVMType(type)) + return args.add(RValue::getAggregate(local), type); - unsigned Alignment = getContext().getDeclAlign(Param).getQuantity(); - return RValue::get(EmitLoadOfScalar(Local, false, Alignment, ArgType)); + unsigned alignment = getContext().getDeclAlign(param).getQuantity(); + llvm::Value *value = EmitLoadOfScalar(local, false, alignment, type); + return args.add(RValue::get(value), type); } -RValue CodeGenFunction::EmitCallArg(const Expr *E, QualType ArgType) { - if (ArgType->isReferenceType()) - return EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0); +void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, + QualType type) { + if (type->isReferenceType()) + return args.add(EmitReferenceBindingToExpr(E, /*InitializedDecl=*/0), + type); - return EmitAnyExprToTemp(E); + args.add(EmitAnyExprToTemp(E), type); } /// Emits a call or invoke instruction to the given function, depending @@ -1177,18 +1217,18 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, for (CallArgList::const_iterator I = CallArgs.begin(), E = CallArgs.end(); I != E; ++I, ++info_it) { const ABIArgInfo &ArgInfo = info_it->info; - RValue RV = I->first; + RValue RV = I->RV; unsigned Alignment = - getContext().getTypeAlignInChars(I->second).getQuantity(); + getContext().getTypeAlignInChars(I->Ty).getQuantity(); switch (ArgInfo.getKind()) { case ABIArgInfo::Indirect: { if (RV.isScalar() || RV.isComplex()) { // Make a temporary alloca to pass the argument. - Args.push_back(CreateMemTemp(I->second)); + Args.push_back(CreateMemTemp(I->Ty)); if (RV.isScalar()) EmitStoreOfScalar(RV.getScalarVal(), Args.back(), false, - Alignment, I->second); + Alignment, I->Ty); else StoreComplexToAddr(RV.getComplexVal(), Args.back(), false); } else { @@ -1215,11 +1255,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // FIXME: Avoid the conversion through memory if possible. llvm::Value *SrcPtr; if (RV.isScalar()) { - SrcPtr = CreateMemTemp(I->second, "coerce"); - EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, Alignment, - I->second); + SrcPtr = CreateMemTemp(I->Ty, "coerce"); + EmitStoreOfScalar(RV.getScalarVal(), SrcPtr, false, Alignment, I->Ty); } else if (RV.isComplex()) { - SrcPtr = CreateMemTemp(I->second, "coerce"); + SrcPtr = CreateMemTemp(I->Ty, "coerce"); StoreComplexToAddr(RV.getComplexVal(), SrcPtr, false); } else SrcPtr = RV.getAggregateAddr(); @@ -1257,7 +1296,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } case ABIArgInfo::Expand: - ExpandTypeToArgs(I->second, RV, Args); + ExpandTypeToArgs(I->Ty, RV, Args); break; } } @@ -1275,7 +1314,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (CE->getOpcode() == llvm::Instruction::BitCast && ActualFT->getReturnType() == CurFT->getReturnType() && ActualFT->getNumParams() == CurFT->getNumParams() && - ActualFT->getNumParams() == Args.size()) { + ActualFT->getNumParams() == Args.size() && + (CurFT->isVarArg() || !ActualFT->isVarArg())) { bool ArgsMatch = true; for (unsigned i = 0, e = ActualFT->getNumParams(); i != e; ++i) if (ActualFT->getParamType(i) != CurFT->getParamType(i)) { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h index 41e707a..3f600c0 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCall.h @@ -44,15 +44,29 @@ namespace clang { namespace CodeGen { typedef llvm::SmallVector<llvm::AttributeWithIndex, 8> AttributeListType; + struct CallArg { + RValue RV; + QualType Ty; + CallArg(RValue rv, QualType ty) + : RV(rv), Ty(ty) + { } + }; + /// CallArgList - Type for representing both the value and type of /// arguments in a call. - typedef llvm::SmallVector<std::pair<RValue, QualType>, 16> CallArgList; + class CallArgList : + public llvm::SmallVector<CallArg, 16> { + public: + void add(RValue rvalue, QualType type) { + push_back(CallArg(rvalue, type)); + } + }; /// FunctionArgList - Type for representing both the decl and type /// of parameters to a function. The decl must be either a /// ParmVarDecl or ImplicitParamDecl. - typedef llvm::SmallVector<std::pair<const VarDecl*, QualType>, - 16> FunctionArgList; + class FunctionArgList : public llvm::SmallVector<const VarDecl*, 16> { + }; /// CGFunctionInfo - Class to encapsulate the information about a /// function definition. @@ -77,6 +91,7 @@ namespace CodeGen { ArgInfo *Args; /// How many arguments to pass inreg. + bool HasRegParm; unsigned RegParm; public: @@ -84,7 +99,7 @@ namespace CodeGen { typedef ArgInfo *arg_iterator; CGFunctionInfo(unsigned CallingConvention, bool NoReturn, - unsigned RegParm, CanQualType ResTy, + bool HasRegParm, unsigned RegParm, CanQualType ResTy, const CanQualType *ArgTys, unsigned NumArgTys); ~CGFunctionInfo() { delete[] Args; } @@ -110,6 +125,7 @@ namespace CodeGen { EffectiveCallingConvention = Value; } + bool getHasRegParm() const { return HasRegParm; } unsigned getRegParm() const { return RegParm; } CanQualType getReturnType() const { return Args[0].type; } @@ -120,6 +136,7 @@ namespace CodeGen { void Profile(llvm::FoldingSetNodeID &ID) { ID.AddInteger(getCallingConvention()); ID.AddBoolean(NoReturn); + ID.AddBoolean(HasRegParm); ID.AddInteger(RegParm); getReturnType().Profile(ID); for (arg_iterator it = arg_begin(), ie = arg_end(); it != ie; ++it) @@ -133,6 +150,7 @@ namespace CodeGen { Iterator end) { ID.AddInteger(Info.getCC()); ID.AddBoolean(Info.getNoReturn()); + ID.AddBoolean(Info.getHasRegParm()); ID.AddInteger(Info.getRegParm()); ResTy.Profile(ID); for (; begin != end; ++begin) { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp index cd28bbe..ca8b657 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGClass.cpp @@ -22,12 +22,12 @@ using namespace clang; using namespace CodeGen; -static uint64_t +static CharUnits ComputeNonVirtualBaseClassOffset(ASTContext &Context, const CXXRecordDecl *DerivedClass, CastExpr::path_const_iterator Start, CastExpr::path_const_iterator End) { - uint64_t Offset = 0; + CharUnits Offset = CharUnits::Zero(); const CXXRecordDecl *RD = DerivedClass; @@ -42,13 +42,12 @@ ComputeNonVirtualBaseClassOffset(ASTContext &Context, cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); // Add the offset. - Offset += Layout.getBaseClassOffsetInBits(BaseDecl); + Offset += Layout.getBaseClassOffset(BaseDecl); RD = BaseDecl; } - // FIXME: We should not use / 8 here. - return Offset / 8; + return Offset; } llvm::Constant * @@ -57,16 +56,16 @@ CodeGenModule::GetNonVirtualBaseClassOffset(const CXXRecordDecl *ClassDecl, CastExpr::path_const_iterator PathEnd) { assert(PathBegin != PathEnd && "Base path should not be empty!"); - uint64_t Offset = + CharUnits Offset = ComputeNonVirtualBaseClassOffset(getContext(), ClassDecl, PathBegin, PathEnd); - if (!Offset) + if (Offset.isZero()) return 0; const llvm::Type *PtrDiffTy = Types.ConvertType(getContext().getPointerDiffType()); - return llvm::ConstantInt::get(PtrDiffTy, Offset); + return llvm::ConstantInt::get(PtrDiffTy, Offset.getQuantity()); } /// Gets the address of a direct base class within a complete object. @@ -85,20 +84,20 @@ CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This, == ConvertType(Derived)); // Compute the offset of the virtual base. - uint64_t Offset; + CharUnits Offset; const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived); if (BaseIsVirtual) - Offset = Layout.getVBaseClassOffsetInBits(Base); + Offset = Layout.getVBaseClassOffset(Base); else - Offset = Layout.getBaseClassOffsetInBits(Base); + Offset = Layout.getBaseClassOffset(Base); // Shift and cast down to the base type. // TODO: for complete types, this should be possible with a GEP. llvm::Value *V = This; - if (Offset) { + if (Offset.isPositive()) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); V = Builder.CreateBitCast(V, Int8PtrTy); - V = Builder.CreateConstInBoundsGEP1_64(V, Offset / 8); + V = Builder.CreateConstInBoundsGEP1_64(V, Offset.getQuantity()); } V = Builder.CreateBitCast(V, ConvertType(Base)->getPointerTo()); @@ -107,13 +106,14 @@ CodeGenFunction::GetAddressOfDirectBaseInCompleteClass(llvm::Value *This, static llvm::Value * ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, llvm::Value *ThisPtr, - uint64_t NonVirtual, llvm::Value *Virtual) { + CharUnits NonVirtual, llvm::Value *Virtual) { const llvm::Type *PtrDiffTy = CGF.ConvertType(CGF.getContext().getPointerDiffType()); llvm::Value *NonVirtualOffset = 0; - if (NonVirtual) - NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, NonVirtual); + if (!NonVirtual.isZero()) + NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, + NonVirtual.getQuantity()); llvm::Value *BaseOffset; if (Virtual) { @@ -150,7 +150,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, ++Start; } - uint64_t NonVirtualOffset = + CharUnits NonVirtualOffset = ComputeNonVirtualBaseClassOffset(getContext(), VBase ? VBase : Derived, Start, PathEnd); @@ -158,7 +158,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, const llvm::Type *BasePtrTy = ConvertType((PathEnd[-1])->getType())->getPointerTo(); - if (!NonVirtualOffset && !VBase) { + if (NonVirtualOffset.isZero() && !VBase) { // Just cast back. return Builder.CreateBitCast(Value, BasePtrTy); } @@ -172,9 +172,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, CastNotNull = createBasicBlock("cast.notnull"); CastEnd = createBasicBlock("cast.end"); - llvm::Value *IsNull = - Builder.CreateICmpEQ(Value, - llvm::Constant::getNullValue(Value->getType())); + llvm::Value *IsNull = Builder.CreateIsNull(Value); Builder.CreateCondBr(IsNull, CastNull, CastNotNull); EmitBlock(CastNotNull); } @@ -187,14 +185,15 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Derived); - uint64_t VBaseOffset = Layout.getVBaseClassOffsetInBits(VBase); - NonVirtualOffset += VBaseOffset / 8; + CharUnits VBaseOffset = Layout.getVBaseClassOffset(VBase); + NonVirtualOffset += VBaseOffset; } else VirtualOffset = GetVirtualBaseClassOffset(Value, Derived, VBase); } // Apply the offsets. - Value = ApplyNonVirtualAndVirtualOffset(*this, Value, NonVirtualOffset, + Value = ApplyNonVirtualAndVirtualOffset(*this, Value, + NonVirtualOffset, VirtualOffset); // Cast back. @@ -206,8 +205,7 @@ CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value, Builder.CreateBr(CastEnd); EmitBlock(CastEnd); - llvm::PHINode *PHI = Builder.CreatePHI(Value->getType()); - PHI->reserveOperandSpace(2); + llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2); PHI->addIncoming(Value, CastNotNull); PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), CastNull); @@ -246,9 +244,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, CastNotNull = createBasicBlock("cast.notnull"); CastEnd = createBasicBlock("cast.end"); - llvm::Value *IsNull = - Builder.CreateICmpEQ(Value, - llvm::Constant::getNullValue(Value->getType())); + llvm::Value *IsNull = Builder.CreateIsNull(Value); Builder.CreateCondBr(IsNull, CastNull, CastNotNull); EmitBlock(CastNotNull); } @@ -267,8 +263,7 @@ CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value, Builder.CreateBr(CastEnd); EmitBlock(CastEnd); - llvm::PHINode *PHI = Builder.CreatePHI(Value->getType()); - PHI->reserveOperandSpace(2); + llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2); PHI->addIncoming(Value, CastNotNull); PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), CastNull); @@ -304,9 +299,9 @@ static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD, } else { const ASTRecordLayout &Layout = CGF.getContext().getASTRecordLayout(RD); - uint64_t BaseOffset = ForVirtualBase ? - Layout.getVBaseClassOffsetInBits(Base) : - Layout.getBaseClassOffsetInBits(Base); + CharUnits BaseOffset = ForVirtualBase ? + Layout.getVBaseClassOffset(Base) : + Layout.getBaseClassOffset(Base); SubVTTIndex = CGF.CGM.getVTables().getSubVTTIndex(RD, BaseSubobject(Base, BaseOffset)); @@ -407,7 +402,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF, CGF.EmitAggExpr(BaseInit->getInit(), AggSlot); - if (CGF.CGM.getLangOptions().areExceptionsEnabled() && + if (CGF.CGM.getLangOptions().Exceptions && !BaseClassDecl->hasTrivialDestructor()) CGF.EHStack.pushCleanup<CallBaseDtor>(EHCleanup, BaseClassDecl, isBaseVirtual); @@ -589,8 +584,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, // we know we're in a copy constructor. unsigned SrcArgIndex = Args.size() - 1; llvm::Value *SrcPtr - = CGF.Builder.CreateLoad( - CGF.GetAddrOfLocalVar(Args[SrcArgIndex].first)); + = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex])); LValue Src = CGF.EmitLValueForFieldInitialization(SrcPtr, Field, 0); // Copy the aggregate. @@ -606,7 +600,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, EmitAggMemberInitializer(CGF, LHS, ArrayIndexVar, MemberInit, FieldType, 0); - if (!CGF.CGM.getLangOptions().areExceptionsEnabled()) + if (!CGF.CGM.getLangOptions().Exceptions) return; // FIXME: If we have an array of classes w/ non-trivial destructors, @@ -664,6 +658,10 @@ static bool IsConstructorDelegationValid(const CXXConstructorDecl *Ctor) { if (Ctor->getType()->getAs<FunctionProtoType>()->isVariadic()) return false; + // FIXME: Decide if we can do a delegation of a delegating constructor. + if (Ctor->isDelegatingConstructor()) + return false; + return true; } @@ -716,6 +714,9 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) { void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType CtorType, FunctionArgList &Args) { + if (CD->isDelegatingConstructor()) + return EmitDelegatingCXXConstructorCall(CD, Args); + const CXXRecordDecl *ClassDecl = CD->getParent(); llvm::SmallVector<CXXCtorInitializer *, 8> MemberInitializers; @@ -727,8 +728,10 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, if (Member->isBaseInitializer()) EmitBaseInitializer(*this, ClassDecl, Member, CtorType); - else + else if (Member->isAnyMemberInitializer()) MemberInitializers.push_back(Member); + else + llvm_unreachable("Delegating initializer on non-delegating constructor"); } InitializeVTablePointers(ClassDecl); @@ -1196,15 +1199,14 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, CallArgList Args; // Push the this ptr. - Args.push_back(std::make_pair(RValue::get(This), - D->getThisType(getContext()))); + Args.add(RValue::get(This), D->getThisType(getContext())); // Push the src ptr. QualType QT = *(FPT->arg_type_begin()); const llvm::Type *t = CGM.getTypes().ConvertType(QT); Src = Builder.CreateBitCast(Src, t); - Args.push_back(std::make_pair(RValue::get(Src), QT)); + Args.add(RValue::get(Src), QT); // Skip over first argument (Src). ++ArgBeg; @@ -1212,9 +1214,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin()+1, E = FPT->arg_type_end(); I != E; ++I, ++Arg) { assert(Arg != ArgEnd && "Running over edge of argument list!"); - QualType ArgType = *I; - Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType), - ArgType)); + EmitCallArg(Args, *Arg, *I); } // Either we've emitted all the call args, or we have a call to a // variadic function. @@ -1223,8 +1223,7 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, // If we still have any arguments, emit them using the type of the argument. for (; Arg != ArgEnd; ++Arg) { QualType ArgType = Arg->getType(); - Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType), - ArgType)); + EmitCallArg(Args, *Arg, ArgType); } QualType ResultType = FPT->getResultType(); @@ -1243,30 +1242,26 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, assert(I != E && "no parameters to constructor"); // this - DelegateArgs.push_back(std::make_pair(RValue::get(LoadCXXThis()), - I->second)); + DelegateArgs.add(RValue::get(LoadCXXThis()), (*I)->getType()); ++I; // vtt if (llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(Ctor, CtorType), /*ForVirtualBase=*/false)) { QualType VoidPP = getContext().getPointerType(getContext().VoidPtrTy); - DelegateArgs.push_back(std::make_pair(RValue::get(VTT), VoidPP)); + DelegateArgs.add(RValue::get(VTT), VoidPP); if (CodeGenVTables::needsVTTParameter(CurGD)) { assert(I != E && "cannot skip vtt parameter, already done with args"); - assert(I->second == VoidPP && "skipping parameter not of vtt type"); + assert((*I)->getType() == VoidPP && "skipping parameter not of vtt type"); ++I; } } // Explicit arguments. for (; I != E; ++I) { - const VarDecl *Param = I->first; - QualType ArgType = Param->getType(); // because we're passing it to itself - RValue Arg = EmitDelegateCallArg(Param); - - DelegateArgs.push_back(std::make_pair(Arg, ArgType)); + const VarDecl *param = *I; + EmitDelegateCallArg(DelegateArgs, param); } EmitCall(CGM.getTypes().getFunctionInfo(Ctor, CtorType), @@ -1274,6 +1269,19 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, ReturnValueSlot(), DelegateArgs, Ctor); } +void +CodeGenFunction::EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor, + const FunctionArgList &Args) { + assert(Ctor->isDelegatingConstructor()); + + llvm::Value *ThisPtr = LoadCXXThis(); + + AggValueSlot AggSlot = AggValueSlot::forAddr(ThisPtr, false, /*Lifetime*/ true); + + EmitAggExpr(Ctor->init_begin()[0]->getInit(), AggSlot); +} + + void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, bool ForVirtualBase, @@ -1317,6 +1325,7 @@ void CodeGenFunction::PushDestructorCleanup(QualType T, llvm::Value *Addr) { if (ClassDecl->hasTrivialDestructor()) return; const CXXDestructorDecl *D = ClassDecl->getDestructor(); + assert(D && D->isUsed() && "destructor not marked as used!"); PushDestructorCleanup(D, Addr); } @@ -1325,11 +1334,12 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This, const CXXRecordDecl *ClassDecl, const CXXRecordDecl *BaseClassDecl) { llvm::Value *VTablePtr = GetVTablePtr(This, Int8PtrTy); - int64_t VBaseOffsetOffset = + CharUnits VBaseOffsetOffset = CGM.getVTables().getVirtualBaseOffsetOffset(ClassDecl, BaseClassDecl); llvm::Value *VBaseOffsetPtr = - Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset, "vbase.offset.ptr"); + Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetOffset.getQuantity(), + "vbase.offset.ptr"); const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); @@ -1344,7 +1354,7 @@ CodeGenFunction::GetVirtualBaseClassOffset(llvm::Value *This, void CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, const CXXRecordDecl *NearestVBase, - uint64_t OffsetFromNearestVBase, + CharUnits OffsetFromNearestVBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass) { const CXXRecordDecl *RD = Base.getBase(); @@ -1374,23 +1384,23 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, // Compute where to store the address point. llvm::Value *VirtualOffset = 0; - uint64_t NonVirtualOffset = 0; + CharUnits NonVirtualOffset = CharUnits::Zero(); if (CodeGenVTables::needsVTTParameter(CurGD) && NearestVBase) { // We need to use the virtual base offset offset because the virtual base // might have a different offset in the most derived class. VirtualOffset = GetVirtualBaseClassOffset(LoadCXXThis(), VTableClass, NearestVBase); - NonVirtualOffset = OffsetFromNearestVBase / 8; + NonVirtualOffset = OffsetFromNearestVBase; } else { // We can just use the base offset in the complete class. - NonVirtualOffset = Base.getBaseOffset() / 8; + NonVirtualOffset = Base.getBaseOffset(); } // Apply the offsets. llvm::Value *VTableField = LoadCXXThis(); - if (NonVirtualOffset || VirtualOffset) + if (!NonVirtualOffset.isZero() || VirtualOffset) VTableField = ApplyNonVirtualAndVirtualOffset(*this, VTableField, NonVirtualOffset, VirtualOffset); @@ -1405,7 +1415,7 @@ CodeGenFunction::InitializeVTablePointer(BaseSubobject Base, void CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, const CXXRecordDecl *NearestVBase, - uint64_t OffsetFromNearestVBase, + CharUnits OffsetFromNearestVBase, bool BaseIsNonVirtualPrimaryBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass, @@ -1430,8 +1440,8 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, if (!BaseDecl->isDynamicClass()) continue; - uint64_t BaseOffset; - uint64_t BaseOffsetFromNearestVBase; + CharUnits BaseOffset; + CharUnits BaseOffsetFromNearestVBase; bool BaseDeclIsNonVirtualPrimaryBase; if (I->isVirtual()) { @@ -1442,16 +1452,15 @@ CodeGenFunction::InitializeVTablePointers(BaseSubobject Base, const ASTRecordLayout &Layout = getContext().getASTRecordLayout(VTableClass); - BaseOffset = Layout.getVBaseClassOffsetInBits(BaseDecl); - BaseOffsetFromNearestVBase = 0; + BaseOffset = Layout.getVBaseClassOffset(BaseDecl); + BaseOffsetFromNearestVBase = CharUnits::Zero(); BaseDeclIsNonVirtualPrimaryBase = false; } else { const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); - BaseOffset = - Base.getBaseOffset() + Layout.getBaseClassOffsetInBits(BaseDecl); + BaseOffset = Base.getBaseOffset() + Layout.getBaseClassOffset(BaseDecl); BaseOffsetFromNearestVBase = - OffsetFromNearestVBase + Layout.getBaseClassOffsetInBits(BaseDecl); + OffsetFromNearestVBase + Layout.getBaseClassOffset(BaseDecl); BaseDeclIsNonVirtualPrimaryBase = Layout.getPrimaryBase() == BaseDecl; } @@ -1473,8 +1482,9 @@ void CodeGenFunction::InitializeVTablePointers(const CXXRecordDecl *RD) { // Initialize the vtable pointers for this class and all of its bases. VisitedVirtualBasesSetTy VBases; - InitializeVTablePointers(BaseSubobject(RD, 0), /*NearestVBase=*/0, - /*OffsetFromNearestVBase=*/0, + InitializeVTablePointers(BaseSubobject(RD, CharUnits::Zero()), + /*NearestVBase=*/0, + /*OffsetFromNearestVBase=*/CharUnits::Zero(), /*BaseIsNonVirtualPrimaryBase=*/false, VTable, RD, VBases); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp index 1d7901a..41ecd81 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGCleanup.cpp @@ -870,6 +870,29 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { } } +/// isObviouslyBranchWithoutCleanups - Return true if a branch to the +/// specified destination obviously has no cleanups to run. 'false' is always +/// a conservatively correct answer for this method. +bool CodeGenFunction::isObviouslyBranchWithoutCleanups(JumpDest Dest) const { + assert(Dest.getScopeDepth().encloses(EHStack.stable_begin()) + && "stale jump destination"); + + // Calculate the innermost active normal cleanup. + EHScopeStack::stable_iterator TopCleanup = + EHStack.getInnermostActiveNormalCleanup(); + + // If we're not in an active normal cleanup scope, or if the + // destination scope is within the innermost active normal cleanup + // scope, we don't need to worry about fixups. + if (TopCleanup == EHStack.stable_end() || + TopCleanup.encloses(Dest.getScopeDepth())) // works for invalid + return true; + + // Otherwise, we might need some cleanups. + return false; +} + + /// Terminate the current block by emitting a branch which might leave /// the current cleanup-protected scope. The target scope may not yet /// be known, in which case this will require a fixup. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp index dfd9f56..f2e1c02 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.cpp @@ -119,6 +119,17 @@ llvm::StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { return llvm::StringRef(StrPtr, OS.tell()); } +/// getSelectorName - Return selector name. This is used for debugging +/// info. +llvm::StringRef CGDebugInfo::getSelectorName(Selector S) { + llvm::SmallString<256> SName; + llvm::raw_svector_ostream OS(SName); + OS << S.getAsString(); + char *StrPtr = DebugInfoNames.Allocate<char>(OS.tell()); + memcpy(StrPtr, SName.begin(), OS.tell()); + return llvm::StringRef(StrPtr, OS.tell()); +} + /// getClassName - Get class name including template argument list. llvm::StringRef CGDebugInfo::getClassName(RecordDecl *RD) { @@ -306,8 +317,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) { DBuilder.createMemberType("isa", getOrCreateMainFile(), 0,Size, 0, 0, 0, ISATy); EltTys.push_back(FieldTy); - llvm::DIArray Elements = - DBuilder.getOrCreateArray(EltTys.data(), EltTys.size()); + llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); return DBuilder.createStructType(TheCU, "objc_object", getOrCreateMainFile(), @@ -462,8 +472,8 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag, // Bit size, align and offset of the type. // Size is always the size of a pointer. We can't use getTypeSize here // because that does not return the correct value for references. - uint64_t Size = - CGM.getContext().Target.getPointerWidth(PointeeTy.getAddressSpace()); + unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy); + uint64_t Size = CGM.getContext().Target.getPointerWidth(AS); uint64_t Align = CGM.getContext().getTypeAlign(Ty); return @@ -488,7 +498,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(CreateMemberType(Unit, FType, "reserved", &FieldOffset)); EltTys.push_back(CreateMemberType(Unit, FType, "Size", &FieldOffset)); - Elements = DBuilder.getOrCreateArray(EltTys.data(), EltTys.size()); + Elements = DBuilder.getOrCreateArray(EltTys); EltTys.clear(); unsigned Flags = llvm::DIDescriptor::FlagAppleBlock; @@ -522,7 +532,7 @@ llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - Elements = DBuilder.getOrCreateArray(EltTys.data(), EltTys.size()); + Elements = DBuilder.getOrCreateArray(EltTys); EltTy = DBuilder.createStructType(Unit, "__block_literal_generic", Unit, LineNo, FieldOffset, 0, @@ -564,8 +574,7 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty, EltTys.push_back(getOrCreateType(FTP->getArgType(i), Unit)); } - llvm::DIArray EltTypeArray = - DBuilder.getOrCreateArray(EltTys.data(), EltTys.size()); + llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(EltTys); llvm::DIType DbgTy = DBuilder.createSubroutineType(Unit, EltTypeArray); return DbgTy; @@ -609,18 +618,32 @@ void CGDebugInfo:: CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit, llvm::SmallVectorImpl<llvm::Value *> &elements) { unsigned fieldNo = 0; + const FieldDecl *LastFD = 0; + bool IsMsStruct = record->hasAttr<MsStructAttr>(); + const ASTRecordLayout &layout = CGM.getContext().getASTRecordLayout(record); for (RecordDecl::field_iterator I = record->field_begin(), E = record->field_end(); I != E; ++I, ++fieldNo) { FieldDecl *field = *I; + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are ignored + if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((field), LastFD) || + CGM.getContext().ZeroBitfieldFollowsBitfield((field), LastFD)) { + --fieldNo; + continue; + } + LastFD = field; + } llvm::StringRef name = field->getName(); QualType type = field->getType(); // Ignore unnamed fields unless they're anonymous structs/unions. - if (name.empty() && !type->isRecordType()) + if (name.empty() && !type->isRecordType()) { + LastFD = field; continue; + } llvm::DIType fieldType = createFieldType(name, type, field->getBitWidth(), @@ -655,9 +678,7 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, if (!Method->isStatic()) { // "this" pointer is always first argument. - ASTContext &Context = CGM.getContext(); - QualType ThisPtr = - Context.getPointerType(Context.getTagDeclType(Method->getParent())); + QualType ThisPtr = Method->getThisType(CGM.getContext()); llvm::DIType ThisPtrType = DBuilder.createArtificialType(getOrCreateType(ThisPtr, Unit)); @@ -669,8 +690,7 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, for (unsigned i = 1, e = Args.getNumElements(); i != e; ++i) Elts.push_back(Args.getElement(i)); - llvm::DIArray EltTypeArray = - DBuilder.getOrCreateArray(Elts.data(), Elts.size()); + llvm::DIArray EltTypeArray = DBuilder.getOrCreateArray(Elts); return DBuilder.createSubroutineType(Unit, EltTypeArray); } @@ -753,10 +773,7 @@ CGDebugInfo::CreateCXXMemberFunction(const CXXMethodDecl *Method, Virtuality, VIndex, ContainingType, Flags, CGM.getLangOptions().Optimize); - // Don't cache ctors or dtors since we have to emit multiple functions for - // a single ctor or dtor. - if (!IsCtorOrDtor && Method->isThisDeclarationADefinition()) - SPCache[Method] = llvm::WeakVH(SP); + SPCache[Method] = llvm::WeakVH(SP); return SP; } @@ -816,10 +833,13 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit, if (BI->isVirtual()) { // virtual base offset offset is -ve. The code generator emits dwarf // expression where it expects +ve number. - BaseOffset = 0 - CGM.getVTables().getVirtualBaseOffsetOffset(RD, Base); + BaseOffset = + 0 - CGM.getVTables().getVirtualBaseOffsetOffset(RD, Base).getQuantity(); BFlags = llvm::DIDescriptor::FlagVirtual; } else BaseOffset = RL.getBaseClassOffsetInBits(Base); + // FIXME: Inconsistent units for BaseOffset. It is in bytes when + // BI->isVirtual() and bits when not. AccessSpecifier Access = BI->getAccessSpecifier(); if (Access == clang::AS_private) @@ -835,6 +855,60 @@ CollectCXXBases(const CXXRecordDecl *RD, llvm::DIFile Unit, } } +/// CollectTemplateParams - A helper function to collect template parameters. +llvm::DIArray CGDebugInfo:: +CollectTemplateParams(const TemplateParameterList *TPList, + const TemplateArgumentList &TAList, + llvm::DIFile Unit) { + llvm::SmallVector<llvm::Value *, 16> TemplateParams; + for (unsigned i = 0, e = TAList.size(); i != e; ++i) { + const TemplateArgument &TA = TAList[i]; + const NamedDecl *ND = TPList->getParam(i); + if (TA.getKind() == TemplateArgument::Type) { + llvm::DIType TTy = getOrCreateType(TA.getAsType(), Unit); + llvm::DITemplateTypeParameter TTP = + DBuilder.createTemplateTypeParameter(TheCU, ND->getName(), TTy); + TemplateParams.push_back(TTP); + } else if (TA.getKind() == TemplateArgument::Integral) { + llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit); + llvm::DITemplateValueParameter TVP = + DBuilder.createTemplateValueParameter(TheCU, ND->getName(), TTy, + TA.getAsIntegral()->getZExtValue()); + TemplateParams.push_back(TVP); + } + } + return DBuilder.getOrCreateArray(TemplateParams); +} + +/// CollectFunctionTemplateParams - A helper function to collect debug +/// info for function template parameters. +llvm::DIArray CGDebugInfo:: +CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit) { + if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization){ + const TemplateParameterList *TList = + FD->getTemplateSpecializationInfo()->getTemplate()->getTemplateParameters(); + return + CollectTemplateParams(TList, *FD->getTemplateSpecializationArgs(), Unit); + } + return llvm::DIArray(); +} + +/// CollectCXXTemplateParams - A helper function to collect debug info for +/// template parameters. +llvm::DIArray CGDebugInfo:: +CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TSpecial, + llvm::DIFile Unit) { + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + PU = TSpecial->getSpecializedTemplateOrPartial(); + + TemplateParameterList *TPList = PU.is<ClassTemplateDecl *>() ? + PU.get<ClassTemplateDecl *>()->getTemplateParameters() : + PU.get<ClassTemplatePartialSpecializationDecl *>()->getTemplateParameters(); + const TemplateArgumentList &TAList = TSpecial->getTemplateInstantiationArgs(); + return CollectTemplateParams(TPList, TAList, Unit); +} + /// getOrCreateVTablePtrType - Return debug info descriptor for vtable. llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) { if (VTablePtrType.isValid()) @@ -844,7 +918,7 @@ llvm::DIType CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile Unit) { /* Function type */ llvm::Value *STy = getOrCreateType(Context.IntTy, Unit); - llvm::DIArray SElements = DBuilder.getOrCreateArray(&STy, 1); + llvm::DIArray SElements = DBuilder.getOrCreateArray(STy); llvm::DIType SubTy = DBuilder.createSubroutineType(Unit, SElements); unsigned Size = Context.getTypeSize(Context.VoidPtrTy); llvm::DIType vtbl_ptr_type = DBuilder.createPointerType(SubTy, Size, 0, @@ -971,30 +1045,13 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { } CollectRecordFields(RD, Unit, EltTys); - llvm::SmallVector<llvm::Value *, 16> TemplateParams; + llvm::DIArray TParamsArray; if (CXXDecl) { CollectCXXMemberFunctions(CXXDecl, Unit, EltTys, FwdDecl); CollectCXXFriends(CXXDecl, Unit, EltTys, FwdDecl); - if (ClassTemplateSpecializationDecl *TSpecial - = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { - const TemplateArgumentList &TAL = TSpecial->getTemplateArgs(); - for (unsigned i = 0, e = TAL.size(); i != e; ++i) { - const TemplateArgument &TA = TAL[i]; - if (TA.getKind() == TemplateArgument::Type) { - llvm::DIType TTy = getOrCreateType(TA.getAsType(), Unit); - llvm::DITemplateTypeParameter TTP = - DBuilder.createTemplateTypeParameter(TheCU, TTy.getName(), TTy); - TemplateParams.push_back(TTP); - } else if (TA.getKind() == TemplateArgument::Integral) { - llvm::DIType TTy = getOrCreateType(TA.getIntegralType(), Unit); - // FIXME: Get parameter name, instead of parameter type name. - llvm::DITemplateValueParameter TVP = - DBuilder.createTemplateValueParameter(TheCU, TTy.getName(), TTy, - TA.getAsIntegral()->getZExtValue()); - TemplateParams.push_back(TVP); - } - } - } + if (const ClassTemplateSpecializationDecl *TSpecial + = dyn_cast<ClassTemplateSpecializationDecl>(RD)) + TParamsArray = CollectCXXTemplateParams(TSpecial, Unit); } RegionStack.pop_back(); @@ -1008,18 +1065,13 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { llvm::StringRef RDName = RD->getName(); uint64_t Size = CGM.getContext().getTypeSize(Ty); uint64_t Align = CGM.getContext().getTypeAlign(Ty); - llvm::DIArray Elements = - DBuilder.getOrCreateArray(EltTys.data(), EltTys.size()); + llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); llvm::MDNode *RealDecl = NULL; - if (RD->isStruct()) - RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line, - Size, Align, 0, Elements); - else if (RD->isUnion()) + if (RD->isUnion()) RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line, - Size, Align, 0, Elements); - else { - assert(RD->isClass() && "Unknown RecordType!"); + Size, Align, 0, Elements); + else if (CXXDecl) { RDName = getClassName(RD); // A class's primary base or the class itself contains the vtable. llvm::MDNode *ContainingType = NULL; @@ -1039,13 +1091,14 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { } else if (CXXDecl->isDynamicClass()) ContainingType = FwdDecl; - llvm::DIArray TParamsArray = - DBuilder.getOrCreateArray(TemplateParams.data(), TemplateParams.size()); + RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line, Size, Align, 0, 0, llvm::DIType(), Elements, ContainingType, TParamsArray); - } + } else + RealDecl = DBuilder.createStructType(RDContext, RDName, DefUnit, Line, + Size, Align, 0, Elements); // Now that we have a real decl for the struct, replace anything using the // old decl with the new one. This will recursively update the debug info. @@ -1156,14 +1209,26 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, else if (Field->getAccessControl() == ObjCIvarDecl::Private) Flags = llvm::DIDescriptor::FlagPrivate; - FieldTy = DBuilder.createMemberType(FieldName, FieldDefUnit, - FieldLine, FieldSize, FieldAlign, - FieldOffset, Flags, FieldTy); + llvm::StringRef PropertyName; + llvm::StringRef PropertyGetter; + llvm::StringRef PropertySetter; + unsigned PropertyAttributes = 0; + if (ObjCPropertyDecl *PD = + ID->FindPropertyVisibleInPrimaryClass(Field->getIdentifier())) { + PropertyName = PD->getName(); + PropertyGetter = getSelectorName(PD->getGetterName()); + PropertySetter = getSelectorName(PD->getSetterName()); + PropertyAttributes = PD->getPropertyAttributes(); + } + FieldTy = DBuilder.createObjCIVar(FieldName, FieldDefUnit, + FieldLine, FieldSize, FieldAlign, + FieldOffset, Flags, FieldTy, + PropertyName, PropertyGetter, + PropertySetter, PropertyAttributes); EltTys.push_back(FieldTy); } - llvm::DIArray Elements = - DBuilder.getOrCreateArray(EltTys.data(), EltTys.size()); + llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); RegionStack.pop_back(); llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator RI = @@ -1200,12 +1265,17 @@ llvm::DIType CGDebugInfo::CreateType(const TagType *Ty) { llvm::DIType CGDebugInfo::CreateType(const VectorType *Ty, llvm::DIFile Unit) { llvm::DIType ElementTy = getOrCreateType(Ty->getElementType(), Unit); - uint64_t NumElems = Ty->getNumElements(); - if (NumElems > 0) + int64_t NumElems = Ty->getNumElements(); + int64_t LowerBound = 0; + if (NumElems == 0) + // If number of elements are not known then this is an unbounded array. + // Use Low = 1, Hi = 0 to express such arrays. + LowerBound = 1; + else --NumElems; - llvm::Value *Subscript = DBuilder.getOrCreateSubrange(0, NumElems); - llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(&Subscript, 1); + llvm::Value *Subscript = DBuilder.getOrCreateSubrange(LowerBound, NumElems); + llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscript); uint64_t Size = CGM.getContext().getTypeSize(Ty); uint64_t Align = CGM.getContext().getTypeAlign(Ty); @@ -1228,6 +1298,9 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, } else if (Ty->isIncompleteArrayType()) { Size = 0; Align = CGM.getContext().getTypeAlign(Ty->getElementType()); + } else if (Ty->isDependentSizedArrayType() || Ty->isIncompleteType()) { + Size = 0; + Align = 0; } else { // Size and align of the whole array, not the element type. Size = CGM.getContext().getTypeSize(Ty); @@ -1243,18 +1316,23 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty, EltTy = Ty->getElementType(); else { while ((Ty = dyn_cast<ArrayType>(EltTy))) { - uint64_t Upper = 0; - if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) + int64_t UpperBound = 0; + int64_t LowerBound = 0; + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) { if (CAT->getSize().getZExtValue()) - Upper = CAT->getSize().getZExtValue() - 1; + UpperBound = CAT->getSize().getZExtValue() - 1; + } else + // This is an unbounded array. Use Low = 1, Hi = 0 to express such + // arrays. + LowerBound = 1; + // FIXME: Verify this is right for VLAs. - Subscripts.push_back(DBuilder.getOrCreateSubrange(0, Upper)); + Subscripts.push_back(DBuilder.getOrCreateSubrange(LowerBound, UpperBound)); EltTy = Ty->getElementType(); } } - llvm::DIArray SubscriptArray = - DBuilder.getOrCreateArray(Subscripts.data(), Subscripts.size()); + llvm::DIArray SubscriptArray = DBuilder.getOrCreateArray(Subscripts); llvm::DIType DbgTy = DBuilder.createArrayType(Size, Align, getOrCreateType(EltTy, Unit), @@ -1303,9 +1381,7 @@ llvm::DIType CGDebugInfo::CreateType(const MemberPointerType *Ty, Info.first, Info.second, FieldOffset, 0, PointerDiffDITy); - llvm::DIArray Elements = - DBuilder.getOrCreateArray(&ElementTypes[0], - llvm::array_lengthof(ElementTypes)); + llvm::DIArray Elements = DBuilder.getOrCreateArray(ElementTypes); return DBuilder.createStructType(U, llvm::StringRef("test"), U, 0, FieldOffset, @@ -1327,8 +1403,7 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) { } // Return a CompositeType for the enum itself. - llvm::DIArray EltArray = - DBuilder.getOrCreateArray(Enumerators.data(), Enumerators.size()); + llvm::DIArray EltArray = DBuilder.getOrCreateArray(Enumerators); llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation()); unsigned Line = getLineNumber(ED->getLocation()); @@ -1366,6 +1441,7 @@ static QualType UnwrapTypeForDebugInfo(QualType T) { break; case Type::Attributed: T = cast<AttributedType>(T)->getEquivalentType(); + break; case Type::Elaborated: T = cast<ElaboratedType>(T)->getNamedType(); break; @@ -1375,6 +1451,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T) { case Type::SubstTemplateTypeParm: T = cast<SubstTemplateTypeParmType>(T)->getReplacementType(); break; + case Type::Auto: + T = cast<AutoType>(T)->getDeducedType(); + break; } assert(T != LastT && "Type unwrapping failed to unwrap!"); @@ -1394,7 +1473,7 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty, // Unwrap the type as needed for debug information. Ty = UnwrapTypeForDebugInfo(Ty); - + // Check for existing entry. llvm::DenseMap<void *, llvm::WeakVH>::iterator it = TypeCache.find(Ty.getAsOpaquePtr()); @@ -1502,6 +1581,37 @@ llvm::DIType CGDebugInfo::CreateMemberType(llvm::DIFile Unit, QualType FType, return Ty; } +/// getFunctionDeclaration - Return debug info descriptor to describe method +/// declaration for the given method definition. +llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) { + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (!FD) return llvm::DISubprogram(); + + // Setup context. + getContextDescriptor(cast<Decl>(D->getDeclContext())); + + llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator + MI = SPCache.find(FD); + if (MI != SPCache.end()) { + llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(&*MI->second)); + if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition()) + return SP; + } + + for (FunctionDecl::redecl_iterator I = FD->redecls_begin(), + E = FD->redecls_end(); I != E; ++I) { + const FunctionDecl *NextFD = *I; + llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator + MI = SPCache.find(NextFD); + if (MI != SPCache.end()) { + llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(&*MI->second)); + if (SP.isSubprogram() && !llvm::DISubprogram(SP).isDefinition()) + return SP; + } + } + return llvm::DISubprogram(); +} + /// EmitFunctionStart - Constructs the debug code for entering a function - /// "llvm.dbg.func.start.". void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, @@ -1514,9 +1624,11 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, FnBeginRegionCount.push_back(RegionStack.size()); const Decl *D = GD.getDecl(); + unsigned Flags = 0; llvm::DIFile Unit = getOrCreateFile(CurLoc); llvm::DIDescriptor FDContext(Unit); + llvm::DIArray TParamsArray; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // If there is a DISubprogram for this function available then use it. llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator @@ -1540,6 +1652,9 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, if (const NamespaceDecl *NSDecl = dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext())) FDContext = getOrCreateNameSpace(NSDecl); + + // Collect template parameters. + TParamsArray = CollectFunctionTemplateParams(FD, Unit); } else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) { Name = getObjCMethodName(OMD); Flags |= llvm::DIDescriptor::FlagPrototyped; @@ -1557,11 +1672,14 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, unsigned LineNo = getLineNumber(CurLoc); if (D->isImplicit()) Flags |= llvm::DIDescriptor::FlagArtificial; + llvm::DIType SPTy = getOrCreateType(FnType, Unit); + llvm::DISubprogram SPDecl = getFunctionDeclaration(D); llvm::DISubprogram SP = DBuilder.createFunction(FDContext, Name, LinkageName, Unit, - LineNo, getOrCreateType(FnType, Unit), + LineNo, SPTy, Fn->hasInternalLinkage(), true/*definition*/, - Flags, CGM.getLangOptions().Optimize, Fn); + Flags, CGM.getLangOptions().Optimize, Fn, + TParamsArray, SPDecl); // Push function on region stack. llvm::MDNode *SPN = SP; @@ -1714,15 +1832,17 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, } CharUnits Align = CGM.getContext().getDeclAlign(VD); - if (Align > CharUnits::fromQuantity( - CGM.getContext().Target.getPointerAlign(0) / 8)) { - unsigned AlignedOffsetInBytes - = llvm::RoundUpToAlignment(FieldOffset/8, Align.getQuantity()); - unsigned NumPaddingBytes - = AlignedOffsetInBytes - FieldOffset/8; + if (Align > CGM.getContext().toCharUnitsFromBits( + CGM.getContext().Target.getPointerAlign(0))) { + CharUnits FieldOffsetInBytes + = CGM.getContext().toCharUnitsFromBits(FieldOffset); + CharUnits AlignedOffsetInBytes + = FieldOffsetInBytes.RoundUpToAlignment(Align); + CharUnits NumPaddingBytes + = AlignedOffsetInBytes - FieldOffsetInBytes; - if (NumPaddingBytes > 0) { - llvm::APInt pad(32, NumPaddingBytes); + if (NumPaddingBytes.isPositive()) { + llvm::APInt pad(32, NumPaddingBytes.getQuantity()); FType = CGM.getContext().getConstantArrayType(CGM.getContext().CharTy, pad, ArrayType::Normal, 0); EltTys.push_back(CreateMemberType(Unit, FType, "", &FieldOffset)); @@ -1732,7 +1852,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, FType = Type; llvm::DIType FieldTy = CGDebugInfo::getOrCreateType(FType, Unit); FieldSize = CGM.getContext().getTypeSize(FType); - FieldAlign = Align.getQuantity()*8; + FieldAlign = CGM.getContext().toBits(Align); *XOffset = FieldOffset; FieldTy = DBuilder.createMemberType(VD->getName(), Unit, @@ -1741,8 +1861,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, EltTys.push_back(FieldTy); FieldOffset += FieldSize; - llvm::DIArray Elements = - DBuilder.getOrCreateArray(EltTys.data(), EltTys.size()); + llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); unsigned Flags = llvm::DIDescriptor::FlagBlockByrefStruct; @@ -1752,7 +1871,8 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, /// EmitDeclare - Emit local variable declaration debug info. void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, - llvm::Value *Storage, CGBuilderTy &Builder) { + llvm::Value *Storage, + unsigned ArgNo, CGBuilderTy &Builder) { assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); @@ -1798,13 +1918,13 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(CGM.getLLVMContext()); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); // offset of __forwarding field - offset = - CharUnits::fromQuantity(CGM.getContext().Target.getPointerWidth(0)/8); + offset = CGM.getContext().toCharUnitsFromBits( + CGM.getContext().Target.getPointerWidth(0)); addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); // offset of x field - offset = CharUnits::fromQuantity(XOffset/8); + offset = CGM.getContext().toCharUnitsFromBits(XOffset); addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); // Create the descriptor for the variable. @@ -1812,7 +1932,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, DBuilder.createComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()), VD->getName(), Unit, Line, Ty, - addr.data(), addr.size()); + addr, ArgNo); // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = @@ -1825,7 +1945,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, llvm::DIVariable D = DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope), Name, Unit, Line, Ty, - CGM.getLangOptions().Optimize, Flags); + CGM.getLangOptions().Optimize, Flags, ArgNo); // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = @@ -1855,7 +1975,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, llvm::DIVariable D = DBuilder.createLocalVariable(Tag, llvm::DIDescriptor(Scope), FieldName, Unit, Line, FieldTy, - CGM.getLangOptions().Optimize, Flags); + CGM.getLangOptions().Optimize, Flags, + ArgNo); // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = @@ -1867,17 +1988,22 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, } } -/// EmitDeclare - Emit local variable declaration debug info. -void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, - llvm::Value *Storage, CGBuilderTy &Builder, - const CGBlockInfo &blockInfo) { - assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); +void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, + llvm::Value *Storage, + CGBuilderTy &Builder) { + EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder); +} +void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( + const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder, + const CGBlockInfo &blockInfo) { + assert(!RegionStack.empty() && "Region stack mismatch, stack empty!"); + if (Builder.GetInsertBlock() == 0) return; - + bool isByRef = VD->hasAttr<BlocksAttr>(); - + uint64_t XOffset = 0; llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); llvm::DIType Ty; @@ -1904,46 +2030,34 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); // offset of __forwarding field - offset = CharUnits::fromQuantity(target.getPointerSize()/8); + offset = CGM.getContext().toCharUnitsFromBits(target.getPointerSizeInBits()); addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); // offset of x field - offset = CharUnits::fromQuantity(XOffset/8); + offset = CGM.getContext().toCharUnitsFromBits(XOffset); addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); } // Create the descriptor for the variable. llvm::DIVariable D = - DBuilder.createComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()), - VD->getName(), Unit, Line, Ty, - addr.data(), addr.size()); + DBuilder.createComplexVariable(llvm::dwarf::DW_TAG_auto_variable, + llvm::DIDescriptor(RegionStack.back()), + VD->getName(), Unit, Line, Ty, addr); // Insert an llvm.dbg.declare into the current block. llvm::Instruction *Call = - DBuilder.insertDeclare(Storage, D, Builder.GetInsertBlock()); + DBuilder.insertDeclare(Storage, D, Builder.GetInsertPoint()); llvm::MDNode *Scope = RegionStack.back(); Call->setDebugLoc(llvm::DebugLoc::get(Line, Column, Scope)); } -void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, - llvm::Value *Storage, - CGBuilderTy &Builder) { - EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder); -} - -void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( - const VarDecl *variable, llvm::Value *Storage, CGBuilderTy &Builder, - const CGBlockInfo &blockInfo) { - EmitDeclare(variable, llvm::dwarf::DW_TAG_auto_variable, Storage, Builder, - blockInfo); -} - /// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument /// variable declaration. void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, + unsigned ArgNo, CGBuilderTy &Builder) { - EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, Builder); + EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, ArgNo, Builder); } namespace { @@ -1969,8 +2083,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, unsigned column = getColumnNumber(loc); // Build the debug-info type for the block literal. - llvm::DIDescriptor enclosingContext = - getContextDescriptor(cast<Decl>(blockDecl->getDeclContext())); + getContextDescriptor(cast<Decl>(blockDecl->getDeclContext())); const llvm::StructLayout *blockLayout = CGM.getTargetData().getStructLayout(block.StructureType); @@ -2048,18 +2161,31 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, } const VarDecl *variable = capture->getVariable(); - QualType type = (capture->isByRef() ? C.VoidPtrTy : variable->getType()); llvm::StringRef name = variable->getName(); - fields.push_back(createFieldType(name, type, 0, loc, AS_public, - offsetInBits, tunit)); + + llvm::DIType fieldType; + if (capture->isByRef()) { + std::pair<uint64_t,unsigned> ptrInfo = C.getTypeInfo(C.VoidPtrTy); + + // FIXME: this creates a second copy of this type! + uint64_t xoffset; + fieldType = EmitTypeForVarWithBlocksAttr(variable, &xoffset); + fieldType = DBuilder.createPointerType(fieldType, ptrInfo.first); + fieldType = DBuilder.createMemberType(name, tunit, line, + ptrInfo.first, ptrInfo.second, + offsetInBits, 0, fieldType); + } else { + fieldType = createFieldType(name, variable->getType(), 0, + loc, AS_public, offsetInBits, tunit); + } + fields.push_back(fieldType); } llvm::SmallString<36> typeName; llvm::raw_svector_ostream(typeName) << "__block_literal_" << CGM.getUniqueBlockCount(); - llvm::DIArray fieldsArray = - DBuilder.getOrCreateArray(fields.data(), fields.size()); + llvm::DIArray fieldsArray = DBuilder.getOrCreateArray(fields); llvm::DIType type = DBuilder.createStructType(tunit, typeName.str(), tunit, line, @@ -2078,7 +2204,8 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, DBuilder.createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, llvm::DIDescriptor(scope), name, tunit, line, type, - CGM.getLangOptions().Optimize, flags); + CGM.getLangOptions().Optimize, flags, + cast<llvm::Argument>(addr)->getArgNo() + 1); // Insert an llvm.dbg.value into the current block. llvm::Instruction *declare = @@ -2185,3 +2312,17 @@ CGDebugInfo::getOrCreateNameSpace(const NamespaceDecl *NSDecl) { NameSpaceCache[NSDecl] = llvm::WeakVH(NS); return NS; } + +/// UpdateCompletedType - Update type cache because the type is now +/// translated. +void CGDebugInfo::UpdateCompletedType(const TagDecl *TD) { + QualType Ty = CGM.getContext().getTagDeclType(TD); + + // If the type exist in type cache then remove it from the cache. + // There is no need to prepare debug info for the completed type + // right now. It will be generated on demand lazily. + llvm::DenseMap<void *, llvm::WeakVH>::iterator it = + TypeCache.find(Ty.getAsOpaquePtr()); + if (it != TypeCache.end()) + TypeCache.erase(it); +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h index a390788..27d991b 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDebugInfo.h @@ -32,6 +32,7 @@ namespace llvm { namespace clang { class VarDecl; class ObjCInterfaceDecl; + class ClassTemplateSpecializationDecl; namespace CodeGen { class CodeGenModule; @@ -122,6 +123,16 @@ class CGDebugInfo { llvm::DIFile F, llvm::SmallVectorImpl<llvm::Value *> &EltTys, llvm::DIType RecordTy); + + llvm::DIArray + CollectTemplateParams(const TemplateParameterList *TPList, + const TemplateArgumentList &TAList, + llvm::DIFile Unit); + llvm::DIArray + CollectFunctionTemplateParams(const FunctionDecl *FD, llvm::DIFile Unit); + llvm::DIArray + CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS, + llvm::DIFile F); llvm::DIType createFieldType(llvm::StringRef name, QualType type, Expr *bitWidth, SourceLocation loc, @@ -158,6 +169,10 @@ public: /// has introduced scope change. void UpdateLineDirectiveRegion(CGBuilderTy &Builder); + /// UpdateCompletedType - Update type cache because the type is now + /// translated. + void UpdateCompletedType(const TagDecl *TD); + /// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start /// of a new block. void EmitRegionStart(CGBuilderTy &Builder); @@ -181,7 +196,7 @@ public: /// EmitDeclareOfArgVariable - Emit call to llvm.dbg.declare for an argument /// variable declaration. void EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI, - CGBuilderTy &Builder); + unsigned ArgNo, CGBuilderTy &Builder); /// EmitDeclareOfBlockLiteralArgVariable - Emit call to /// llvm.dbg.declare for the block-literal argument to a block @@ -204,12 +219,7 @@ public: private: /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration. void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI, - CGBuilderTy &Builder); - - /// EmitDeclare - Emit call to llvm.dbg.declare for a variable - /// declaration from an enclosing block. - void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI, - CGBuilderTy &Builder, const CGBlockInfo &blockInfo); + unsigned ArgNo, CGBuilderTy &Builder); // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. // See BuildByRefType. @@ -243,6 +253,10 @@ private: llvm::DIType CreateMemberType(llvm::DIFile Unit, QualType FType, llvm::StringRef Name, uint64_t *Offset); + /// getFunctionDeclaration - Return debug info descriptor to describe method + /// declaration for the given method definition. + llvm::DISubprogram getFunctionDeclaration(const Decl *D); + /// getFunctionName - Get function name for the given FunctionDecl. If the /// name is constructred on demand (e.g. C++ destructor) then the name /// is stored on the side. @@ -252,6 +266,10 @@ private: /// This is the display name for the debugging info. llvm::StringRef getObjCMethodName(const ObjCMethodDecl *FD); + /// getSelectorName - Return selector name. This is used for debugging + /// info. + llvm::StringRef getSelectorName(Selector S); + /// getClassName - Get class name including template argument list. llvm::StringRef getClassName(RecordDecl *RD); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp index f4db01d..c027375 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDecl.cpp @@ -14,7 +14,6 @@ #include "CGDebugInfo.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" -#include "CGBlocks.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" @@ -70,7 +69,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Friend: case Decl::FriendTemplate: case Decl::Block: - assert(0 && "Declaration not should not be in declstmts!"); + assert(0 && "Declaration should not be in declstmts!"); case Decl::Function: // void X(); case Decl::Record: // struct/union/class X; case Decl::Enum: // enum X; @@ -92,8 +91,9 @@ void CodeGenFunction::EmitDecl(const Decl &D) { return EmitVarDecl(VD); } - case Decl::Typedef: { // typedef int X; - const TypedefDecl &TD = cast<TypedefDecl>(D); + case Decl::Typedef: // typedef int X; + case Decl::TypeAlias: { // using X = int; [C++0x] + const TypedefNameDecl &TD = cast<TypedefNameDecl>(D); QualType Ty = TD.getUnderlyingType(); if (Ty->isVariablyModifiedType()) @@ -179,7 +179,8 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, new llvm::GlobalVariable(CGM.getModule(), LTy, Ty.isConstant(getContext()), Linkage, CGM.EmitNullConstant(D.getType()), Name, 0, - D.isThreadSpecified(), Ty.getAddressSpace()); + D.isThreadSpecified(), + CGM.getContext().getTargetAddressSpace(Ty)); GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); if (Linkage != llvm::GlobalValue::InternalLinkage) GV->setVisibility(CurFn->getVisibility()); @@ -222,7 +223,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, OldGV->getLinkage(), Init, "", /*InsertBefore*/ OldGV, D.isThreadSpecified(), - D.getType().getAddressSpace()); + CGM.getContext().getTargetAddressSpace(D.getType())); GV->setVisibility(OldGV->getVisibility()); // Steal the name of the old global @@ -289,7 +290,8 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, // FIXME: It is really dangerous to store this in the map; if anyone // RAUW's the GV uses of this constant will be invalid. const llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType()); - const llvm::Type *LPtrTy = LTy->getPointerTo(D.getType().getAddressSpace()); + const llvm::Type *LPtrTy = + LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(D.getType())); DMEntry = llvm::ConstantExpr::getBitCast(GV, LPtrTy); // Emit global variable debug descriptor for static vars. @@ -300,114 +302,6 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, } } -unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const { - assert(ByRefValueInfo.count(VD) && "Did not find value!"); - - return ByRefValueInfo.find(VD)->second.second; -} - -llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr, - const VarDecl *V) { - llvm::Value *Loc = Builder.CreateStructGEP(BaseAddr, 1, "forwarding"); - Loc = Builder.CreateLoad(Loc); - Loc = Builder.CreateStructGEP(Loc, getByRefValueLLVMField(V), - V->getNameAsString()); - return Loc; -} - -/// BuildByRefType - This routine changes a __block variable declared as T x -/// into: -/// -/// struct { -/// void *__isa; -/// void *__forwarding; -/// int32_t __flags; -/// int32_t __size; -/// void *__copy_helper; // only if needed -/// void *__destroy_helper; // only if needed -/// char padding[X]; // only if needed -/// T x; -/// } x -/// -const llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { - std::pair<const llvm::Type *, unsigned> &Info = ByRefValueInfo[D]; - if (Info.first) - return Info.first; - - QualType Ty = D->getType(); - - std::vector<const llvm::Type *> Types; - - llvm::PATypeHolder ByRefTypeHolder = llvm::OpaqueType::get(getLLVMContext()); - - // void *__isa; - Types.push_back(Int8PtrTy); - - // void *__forwarding; - Types.push_back(llvm::PointerType::getUnqual(ByRefTypeHolder)); - - // int32_t __flags; - Types.push_back(Int32Ty); - - // int32_t __size; - Types.push_back(Int32Ty); - - bool HasCopyAndDispose = getContext().BlockRequiresCopying(Ty); - if (HasCopyAndDispose) { - /// void *__copy_helper; - Types.push_back(Int8PtrTy); - - /// void *__destroy_helper; - Types.push_back(Int8PtrTy); - } - - bool Packed = false; - CharUnits Align = getContext().getDeclAlign(D); - if (Align > getContext().toCharUnitsFromBits(Target.getPointerAlign(0))) { - // We have to insert padding. - - // The struct above has 2 32-bit integers. - unsigned CurrentOffsetInBytes = 4 * 2; - - // And either 2 or 4 pointers. - CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) * - CGM.getTargetData().getTypeAllocSize(Int8PtrTy); - - // Align the offset. - unsigned AlignedOffsetInBytes = - llvm::RoundUpToAlignment(CurrentOffsetInBytes, Align.getQuantity()); - - unsigned NumPaddingBytes = AlignedOffsetInBytes - CurrentOffsetInBytes; - if (NumPaddingBytes > 0) { - const llvm::Type *Ty = llvm::Type::getInt8Ty(getLLVMContext()); - // FIXME: We need a sema error for alignment larger than the minimum of - // the maximal stack alignmint and the alignment of malloc on the system. - if (NumPaddingBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumPaddingBytes); - - Types.push_back(Ty); - - // We want a packed struct. - Packed = true; - } - } - - // T x; - Types.push_back(ConvertTypeForMem(Ty)); - - const llvm::Type *T = llvm::StructType::get(getLLVMContext(), Types, Packed); - - cast<llvm::OpaqueType>(ByRefTypeHolder.get())->refineAbstractTypeTo(T); - CGM.getModule().addTypeName("struct.__block_byref_" + D->getNameAsString(), - ByRefTypeHolder.get()); - - Info.first = ByRefTypeHolder.get(); - - Info.second = Types.size() - 1; - - return Info.first; -} - namespace { struct CallArrayDtor : EHScopeStack::Cleanup { CallArrayDtor(const CXXDestructorDecl *Dtor, @@ -498,20 +392,11 @@ namespace { CGF.Builder.CreateBitCast(Addr, CGF.ConvertType(ArgTy)); CallArgList Args; - Args.push_back(std::make_pair(RValue::get(Arg), - CGF.getContext().getPointerType(Var.getType()))); + Args.add(RValue::get(Arg), + CGF.getContext().getPointerType(Var.getType())); CGF.EmitCall(FnInfo, CleanupFn, ReturnValueSlot(), Args); } }; - - struct CallBlockRelease : EHScopeStack::Cleanup { - llvm::Value *Addr; - CallBlockRelease(llvm::Value *Addr) : Addr(Addr) {} - - void Emit(CodeGenFunction &CGF, bool IsForEH) { - CGF.BuildBlockRelease(Addr, BLOCK_FIELD_IS_BYREF); - } - }; } @@ -642,7 +527,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // candidate nor a __block variable, emit it as a global instead. if (CGM.getCodeGenOpts().MergeAllConstants && Ty.isConstQualified() && !NRVO && !isByRef) { - EmitStaticVarDecl(D, llvm::GlobalValue::PrivateLinkage); + EmitStaticVarDecl(D, llvm::GlobalValue::InternalLinkage); emission.Address = 0; // signal this condition to later callbacks assert(emission.wasEmittedAsGlobal()); @@ -724,7 +609,8 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // Get the element type. const llvm::Type *LElemTy = ConvertTypeForMem(Ty); - const llvm::Type *LElemPtrTy = LElemTy->getPointerTo(Ty.getAddressSpace()); + const llvm::Type *LElemPtrTy = + LElemTy->getPointerTo(CGM.getContext().getTargetAddressSpace(Ty)); llvm::Value *VLASize = EmitVLASize(Ty); @@ -800,75 +686,14 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { EnsureInsertPoint(); } - CharUnits alignment = emission.Alignment; - - if (emission.IsByRef) { - llvm::Value *V; - - BlockFieldFlags fieldFlags; - bool fieldNeedsCopyDispose = false; - - if (type->isBlockPointerType()) { - fieldFlags |= BLOCK_FIELD_IS_BLOCK; - fieldNeedsCopyDispose = true; - } else if (getContext().isObjCNSObjectType(type) || - type->isObjCObjectPointerType()) { - fieldFlags |= BLOCK_FIELD_IS_OBJECT; - fieldNeedsCopyDispose = true; - } else if (getLangOptions().CPlusPlus) { - if (getContext().getBlockVarCopyInits(&D)) - fieldNeedsCopyDispose = true; - else if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) - fieldNeedsCopyDispose = !record->hasTrivialDestructor(); - } - - llvm::Value *addr = emission.Address; - - // FIXME: Someone double check this. - if (type.isObjCGCWeak()) - fieldFlags |= BLOCK_FIELD_IS_WEAK; - - // Initialize the 'isa', which is just 0 or 1. - int isa = 0; - if (fieldFlags & BLOCK_FIELD_IS_WEAK) - isa = 1; - V = Builder.CreateIntToPtr(Builder.getInt32(isa), Int8PtrTy, "isa"); - Builder.CreateStore(V, Builder.CreateStructGEP(addr, 0, "byref.isa")); - - // Store the address of the variable into its own forwarding pointer. - Builder.CreateStore(addr, - Builder.CreateStructGEP(addr, 1, "byref.forwarding")); - - // Blocks ABI: - // c) the flags field is set to either 0 if no helper functions are - // needed or BLOCK_HAS_COPY_DISPOSE if they are, - BlockFlags flags; - if (fieldNeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; - Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()), - Builder.CreateStructGEP(addr, 2, "byref.flags")); - - const llvm::Type *V1; - V1 = cast<llvm::PointerType>(addr->getType())->getElementType(); - V = llvm::ConstantInt::get(IntTy, CGM.GetTargetTypeStoreSize(V1).getQuantity()); - Builder.CreateStore(V, Builder.CreateStructGEP(addr, 3, "byref.size")); - - if (fieldNeedsCopyDispose) { - llvm::Value *copy_helper = Builder.CreateStructGEP(addr, 4); - Builder.CreateStore(CGM.BuildbyrefCopyHelper(addr->getType(), fieldFlags, - alignment.getQuantity(), &D), - copy_helper); - - llvm::Value *destroy_helper = Builder.CreateStructGEP(addr, 5); - Builder.CreateStore(CGM.BuildbyrefDestroyHelper(addr->getType(), - fieldFlags, - alignment.getQuantity(), - &D), - destroy_helper); - } - } + // Initialize the structure of a __block variable. + if (emission.IsByRef) + emitByrefStructureInit(emission); if (!Init) return; + CharUnits alignment = emission.Alignment; + // Check whether this is a byref variable that's potentially // captured and moved by its own initializer. If so, we'll need to // emit the initializer first, then copy into the variable. @@ -877,67 +702,91 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { llvm::Value *Loc = capturedByInit ? emission.Address : emission.getObjectAddress(*this); - bool isVolatile = type.isVolatileQualified(); - + if (!emission.IsConstantAggregate) + return EmitExprAsInit(Init, &D, Loc, alignment, capturedByInit); + // If this is a simple aggregate initialization, we can optimize it // in various ways. - if (emission.IsConstantAggregate) { - assert(!capturedByInit && "constant init contains a capturing block?"); - - llvm::Constant *Init = CGM.EmitConstantExpr(D.getInit(), type, this); - assert(Init != 0 && "Wasn't a simple constant init?"); - - llvm::Value *SizeVal = - llvm::ConstantInt::get(IntPtrTy, - getContext().getTypeSizeInChars(type).getQuantity()); - - const llvm::Type *BP = Int8PtrTy; - if (Loc->getType() != BP) - Loc = Builder.CreateBitCast(Loc, BP, "tmp"); - - // If the initializer is all or mostly zeros, codegen with memset then do - // a few stores afterward. - if (shouldUseMemSetPlusStoresToInitialize(Init, - CGM.getTargetData().getTypeAllocSize(Init->getType()))) { - Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal, - alignment.getQuantity(), isVolatile); - if (!Init->isNullValue()) { - Loc = Builder.CreateBitCast(Loc, Init->getType()->getPointerTo()); - emitStoresForInitAfterMemset(Init, Loc, isVolatile, Builder); - } - } else { - // Otherwise, create a temporary global with the initializer then - // memcpy from the global to the alloca. - std::string Name = GetStaticDeclName(*this, D, "."); - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(CGM.getModule(), Init->getType(), true, - llvm::GlobalValue::InternalLinkage, - Init, Name, 0, false, 0); - GV->setAlignment(alignment.getQuantity()); - - llvm::Value *SrcPtr = GV; - if (SrcPtr->getType() != BP) - SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp"); + assert(!capturedByInit && "constant init contains a capturing block?"); + + bool isVolatile = type.isVolatileQualified(); - Builder.CreateMemCpy(Loc, SrcPtr, SizeVal, alignment.getQuantity(), - isVolatile); + llvm::Constant *constant = CGM.EmitConstantExpr(D.getInit(), type, this); + assert(constant != 0 && "Wasn't a simple constant init?"); + + llvm::Value *SizeVal = + llvm::ConstantInt::get(IntPtrTy, + getContext().getTypeSizeInChars(type).getQuantity()); + + const llvm::Type *BP = Int8PtrTy; + if (Loc->getType() != BP) + Loc = Builder.CreateBitCast(Loc, BP, "tmp"); + + // If the initializer is all or mostly zeros, codegen with memset then do + // a few stores afterward. + if (shouldUseMemSetPlusStoresToInitialize(constant, + CGM.getTargetData().getTypeAllocSize(constant->getType()))) { + Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal, + alignment.getQuantity(), isVolatile); + if (!constant->isNullValue()) { + Loc = Builder.CreateBitCast(Loc, constant->getType()->getPointerTo()); + emitStoresForInitAfterMemset(constant, Loc, isVolatile, Builder); } - } else if (type->isReferenceType()) { - RValue RV = EmitReferenceBindingToExpr(Init, &D); - if (capturedByInit) Loc = BuildBlockByrefAddress(Loc, &D); - EmitStoreOfScalar(RV.getScalarVal(), Loc, false, alignment.getQuantity(), - type); + } else { + // Otherwise, create a temporary global with the initializer then + // memcpy from the global to the alloca. + std::string Name = GetStaticDeclName(*this, D, "."); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), constant->getType(), true, + llvm::GlobalValue::InternalLinkage, + constant, Name, 0, false, 0); + GV->setAlignment(alignment.getQuantity()); + + llvm::Value *SrcPtr = GV; + if (SrcPtr->getType() != BP) + SrcPtr = Builder.CreateBitCast(SrcPtr, BP, "tmp"); + + Builder.CreateMemCpy(Loc, SrcPtr, SizeVal, alignment.getQuantity(), + isVolatile); + } +} + +/// Emit an expression as an initializer for a variable at the given +/// location. The expression is not necessarily the normal +/// initializer for the variable, and the address is not necessarily +/// its normal location. +/// +/// \param init the initializing expression +/// \param var the variable to act as if we're initializing +/// \param loc the address to initialize; its type is a pointer +/// to the LLVM mapping of the variable's type +/// \param alignment the alignment of the address +/// \param capturedByInit true if the variable is a __block variable +/// whose address is potentially changed by the initializer +void CodeGenFunction::EmitExprAsInit(const Expr *init, + const VarDecl *var, + llvm::Value *loc, + CharUnits alignment, + bool capturedByInit) { + QualType type = var->getType(); + bool isVolatile = type.isVolatileQualified(); + + if (type->isReferenceType()) { + RValue RV = EmitReferenceBindingToExpr(init, var); + if (capturedByInit) loc = BuildBlockByrefAddress(loc, var); + EmitStoreOfScalar(RV.getScalarVal(), loc, false, + alignment.getQuantity(), type); } else if (!hasAggregateLLVMType(type)) { - llvm::Value *V = EmitScalarExpr(Init); - if (capturedByInit) Loc = BuildBlockByrefAddress(Loc, &D); - EmitStoreOfScalar(V, Loc, isVolatile, alignment.getQuantity(), type); + llvm::Value *V = EmitScalarExpr(init); + if (capturedByInit) loc = BuildBlockByrefAddress(loc, var); + EmitStoreOfScalar(V, loc, isVolatile, alignment.getQuantity(), type); } else if (type->isAnyComplexType()) { - ComplexPairTy complex = EmitComplexExpr(Init); - if (capturedByInit) Loc = BuildBlockByrefAddress(Loc, &D); - StoreComplexToAddr(complex, Loc, isVolatile); + ComplexPairTy complex = EmitComplexExpr(init); + if (capturedByInit) loc = BuildBlockByrefAddress(loc, var); + StoreComplexToAddr(complex, loc, isVolatile); } else { // TODO: how can we delay here if D is captured by its initializer? - EmitAggExpr(Init, AggValueSlot::forAddr(Loc, isVolatile, true, false)); + EmitAggExpr(init, AggValueSlot::forAddr(loc, isVolatile, true, false)); } } @@ -993,14 +842,14 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) { // If this is a block variable, call _Block_object_destroy // (on the unforwarded address). - if (emission.IsByRef && - CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) - EHStack.pushCleanup<CallBlockRelease>(NormalAndEHCleanup, emission.Address); + if (emission.IsByRef) + enterByrefCleanup(emission); } /// Emit an alloca (or GlobalValue depending on target) /// for the specified parameter and set up LocalDeclMap. -void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { +void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg, + unsigned ArgNo) { // FIXME: Why isn't ImplicitParamDecl a ParmVarDecl? assert((isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) && "Invalid argument to EmitParmDecl"); @@ -1046,6 +895,6 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg) { // Emit debug info for param declaration. if (CGDebugInfo *DI = getDebugInfo()) { DI->setLocation(D.getLocation()); - DI->EmitDeclareOfArgVariable(&D, DeclPtr, Builder); + DI->EmitDeclareOfArgVariable(&D, DeclPtr, ArgNo, Builder); } } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp index e295267..45b0b96 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGDeclCXX.cpp @@ -138,6 +138,8 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, "__cxa_atexit"); + if (llvm::Function *Fn = dyn_cast<llvm::Function>(AtExitFn)) + Fn->setDoesNotThrow(); llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, "__dso_handle"); @@ -149,6 +151,14 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, void CodeGenFunction::EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr) { + // If we've been asked to forbid guard variables, emit an error now. + // This diagnostic is hard-coded for Darwin's use case; we can find + // better phrasing if someone else needs it. + if (CGM.getCodeGenOpts().ForbidGuardVariables) + CGM.Error(D.getLocation(), + "this initialization requires a guard variable, which " + "the kernel does not support"); + CGM.getCXXABI().EmitGuardedInit(*this, D, DeclPtr); } @@ -166,7 +176,7 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, Fn->setSection(Section); } - if (!CGM.getLangOptions().areExceptionsEnabled()) + if (!CGM.getLangOptions().Exceptions) Fn->setDoesNotThrow(); return Fn; @@ -260,12 +270,16 @@ void CodeGenModule::EmitCXXGlobalDtorFunc() { void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D, llvm::GlobalVariable *Addr) { - StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), - SourceLocation()); + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, + getTypes().getNullaryFunctionInfo(), + FunctionArgList(), SourceLocation()); // Use guarded initialization if the global variable is weak due to - // being a class template's static data member. - if (Addr->hasWeakLinkage() && D->getInstantiatedFromStaticDataMember()) { + // being a class template's static data member. These will always + // have weak_odr linkage. + if (Addr->getLinkage() == llvm::GlobalValue::WeakODRLinkage && + D->isStaticDataMember() && + D->getInstantiatedFromStaticDataMember()) { EmitCXXGuardedInit(*D, Addr); } else { EmitCXXGlobalVarDeclInit(*D, Addr); @@ -277,8 +291,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, llvm::Constant **Decls, unsigned NumDecls) { - StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), - SourceLocation()); + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, + getTypes().getNullaryFunctionInfo(), + FunctionArgList(), SourceLocation()); for (unsigned i = 0; i != NumDecls; ++i) if (Decls[i]) @@ -290,8 +305,9 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn, const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> > &DtorsAndObjects) { - StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), - SourceLocation()); + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, + getTypes().getNullaryFunctionInfo(), + FunctionArgList(), SourceLocation()); // Emit the dtors, in reverse order from construction. for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) { @@ -313,21 +329,19 @@ llvm::Function * CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D, const ArrayType *Array, llvm::Value *This) { - FunctionArgList Args; - ImplicitParamDecl *Dst = - ImplicitParamDecl::Create(getContext(), 0, - SourceLocation(), 0, - getContext().getPointerType(getContext().VoidTy)); - Args.push_back(std::make_pair(Dst, Dst->getType())); + FunctionArgList args; + ImplicitParamDecl dst(0, SourceLocation(), 0, getContext().VoidPtrTy); + args.push_back(&dst); const CGFunctionInfo &FI = - CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args, + CGM.getTypes().getFunctionInfo(getContext().VoidTy, args, FunctionType::ExtInfo()); const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false); llvm::Function *Fn = CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor"); - StartFunction(GlobalDecl(), getContext().VoidTy, Fn, Args, SourceLocation()); + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FI, args, + SourceLocation()); QualType BaseElementTy = getContext().getBaseElementType(Array); const llvm::Type *BasePtr = ConvertType(BaseElementTy)->getPointerTo(); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp index 4bce081..6cb9599 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGException.cpp @@ -28,24 +28,22 @@ using namespace CodeGen; static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) { // void *__cxa_allocate_exception(size_t thrown_size); - const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); - std::vector<const llvm::Type*> Args(1, SizeTy); + const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()), - Args, false); + llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()), + SizeTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception"); } static llvm::Constant *getFreeExceptionFn(CodeGenFunction &CGF) { // void __cxa_free_exception(void *thrown_exception); - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - std::vector<const llvm::Type*> Args(1, Int8PtrTy); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), - Args, false); + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Int8PtrTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception"); } @@ -55,11 +53,10 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { // void (*dest) (void *)); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - std::vector<const llvm::Type*> Args(3, Int8PtrTy); - + const llvm::Type *Args[3] = { Int8PtrTy, Int8PtrTy, Int8PtrTy }; const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), - Args, false); + Args, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); } @@ -68,18 +65,18 @@ static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { // void __cxa_rethrow(); const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); } static llvm::Constant *getGetExceptionPtrFn(CodeGenFunction &CGF) { // void *__cxa_get_exception_ptr(void*); - const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - std::vector<const llvm::Type*> Args(1, Int8PtrTy); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); const llvm::FunctionType *FTy = - llvm::FunctionType::get(Int8PtrTy, Args, false); + llvm::FunctionType::get(Int8PtrTy, Int8PtrTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_get_exception_ptr"); } @@ -88,10 +85,8 @@ static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { // void *__cxa_begin_catch(void*); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - std::vector<const llvm::Type*> Args(1, Int8PtrTy); - const llvm::FunctionType *FTy = - llvm::FunctionType::get(Int8PtrTy, Args, false); + llvm::FunctionType::get(Int8PtrTy, Int8PtrTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); } @@ -100,7 +95,8 @@ static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { // void __cxa_end_catch(); const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); } @@ -109,22 +105,18 @@ static llvm::Constant *getUnexpectedFn(CodeGenFunction &CGF) { // void __cxa_call_unexepcted(void *thrown_exception); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - std::vector<const llvm::Type*> Args(1, Int8PtrTy); - const llvm::FunctionType *FTy = llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), - Args, false); + Int8PtrTy, /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_call_unexpected"); } llvm::Constant *CodeGenFunction::getUnwindResumeOrRethrowFn() { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - std::vector<const llvm::Type*> Args(1, Int8PtrTy); - const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Args, - false); + llvm::FunctionType::get(llvm::Type::getVoidTy(getLLVMContext()), Int8PtrTy, + /*IsVarArgs=*/false); if (CGM.getLangOptions().SjLjExceptions) return CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume_or_Rethrow"); @@ -135,7 +127,8 @@ static llvm::Constant *getTerminateFn(CodeGenFunction &CGF) { // void __terminate(); const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, CGF.CGM.getLangOptions().CPlusPlus ? "_ZSt9terminatev" : "abort"); @@ -145,10 +138,9 @@ static llvm::Constant *getCatchallRethrowFn(CodeGenFunction &CGF, llvm::StringRef Name) { const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - std::vector<const llvm::Type*> Args(1, Int8PtrTy); - const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext()); - const llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, Args, false); + const llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, Int8PtrTy, + /*IsVarArgs=*/false); return CGF.CGM.CreateRuntimeFunction(FTy, Name); } @@ -160,6 +152,7 @@ const EHPersonality EHPersonality::GNU_CPlusPlus("__gxx_personality_v0"); const EHPersonality EHPersonality::GNU_CPlusPlus_SJLJ("__gxx_personality_sj0"); const EHPersonality EHPersonality::GNU_ObjC("__gnu_objc_personality_v0", "objc_exception_throw"); +const EHPersonality EHPersonality::GNU_ObjCXX("__gnustep_objcxx_personality_v0"); static const EHPersonality &getCPersonality(const LangOptions &L) { if (L.SjLjExceptions) @@ -201,7 +194,7 @@ static const EHPersonality &getObjCXXPersonality(const LangOptions &L) { // The GNU runtime's personality function inherently doesn't support // mixed EH. Use the C++ personality just to avoid returning null. - return getCXXPersonality(L); + return EHPersonality::GNU_ObjCXX; } const EHPersonality &EHPersonality::get(const LangOptions &L) { @@ -273,7 +266,7 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) { /// when it really needs it. void CodeGenModule::SimplifyPersonality() { // For now, this is really a Darwin-specific operation. - if (Context.Target.getTriple().getOS() != llvm::Triple::Darwin) + if (!Context.Target.getTriple().isOSDarwin()) return; // If we're not in ObjC++ -fexceptions, there's nothing to do. @@ -439,7 +432,7 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { } void CodeGenFunction::EmitStartEHSpec(const Decl *D) { - if (!CGM.getLangOptions().areExceptionsEnabled()) + if (!CGM.getLangOptions().CXXExceptions) return; const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); @@ -449,25 +442,28 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { if (Proto == 0) return; - assert(!Proto->hasAnyExceptionSpec() && "function with parameter pack"); - - if (!Proto->hasExceptionSpec()) - return; - - unsigned NumExceptions = Proto->getNumExceptions(); - EHFilterScope *Filter = EHStack.pushFilter(NumExceptions); - - for (unsigned I = 0; I != NumExceptions; ++I) { - QualType Ty = Proto->getExceptionType(I); - QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType(); - llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, - /*ForEH=*/true); - Filter->setFilter(I, EHType); + ExceptionSpecificationType EST = Proto->getExceptionSpecType(); + if (isNoexceptExceptionSpec(EST)) { + if (Proto->getNoexceptSpec(getContext()) == FunctionProtoType::NR_Nothrow) { + // noexcept functions are simple terminate scopes. + EHStack.pushTerminate(); + } + } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { + unsigned NumExceptions = Proto->getNumExceptions(); + EHFilterScope *Filter = EHStack.pushFilter(NumExceptions); + + for (unsigned I = 0; I != NumExceptions; ++I) { + QualType Ty = Proto->getExceptionType(I); + QualType ExceptType = Ty.getNonReferenceType().getUnqualifiedType(); + llvm::Value *EHType = CGM.GetAddrOfRTTIDescriptor(ExceptType, + /*ForEH=*/true); + Filter->setFilter(I, EHType); + } } } void CodeGenFunction::EmitEndEHSpec(const Decl *D) { - if (!CGM.getLangOptions().areExceptionsEnabled()) + if (!CGM.getLangOptions().CXXExceptions) return; const FunctionDecl* FD = dyn_cast_or_null<FunctionDecl>(D); @@ -477,10 +473,14 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { if (Proto == 0) return; - if (!Proto->hasExceptionSpec()) - return; - - EHStack.popFilter(); + ExceptionSpecificationType EST = Proto->getExceptionSpecType(); + if (isNoexceptExceptionSpec(EST)) { + if (Proto->getNoexceptSpec(getContext()) == FunctionProtoType::NR_Nothrow) { + EHStack.popTerminate(); + } + } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { + EHStack.popFilter(); + } } void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { @@ -541,7 +541,7 @@ llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() { assert(EHStack.requiresLandingPad()); assert(!EHStack.empty()); - if (!CGM.getLangOptions().areExceptionsEnabled()) + if (!CGM.getLangOptions().Exceptions) return 0; // Check the innermost scope for a cached landing pad. If this is @@ -664,7 +664,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() { assert(I.next() == EHStack.end() && "EH filter is not end of EH stack"); assert(!CatchAll.isValid() && "EH filter reached after catch-all"); - // Filter scopes get added to the selector in wierd ways. + // Filter scopes get added to the selector in weird ways. EHFilterScope &Filter = cast<EHFilterScope>(*I); HasEHFilter = true; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGException.h b/contrib/llvm/tools/clang/lib/CodeGen/CGException.h index 1f9b896..5a743b5 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGException.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGException.h @@ -41,6 +41,7 @@ public: static const EHPersonality GNU_C; static const EHPersonality GNU_C_SJLJ; static const EHPersonality GNU_ObjC; + static const EHPersonality GNU_ObjCXX; static const EHPersonality NeXT_ObjC; static const EHPersonality GNU_CPlusPlus; static const EHPersonality GNU_CPlusPlus_SJLJ; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp index 2abaadf..bc2cd35 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExpr.cpp @@ -15,6 +15,7 @@ #include "CodeGenModule.h" #include "CGCall.h" #include "CGCXXABI.h" +#include "CGDebugInfo.h" #include "CGRecordLayout.h" #include "CGObjCRuntime.h" #include "clang/AST/ASTContext.h" @@ -215,24 +216,28 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, InitializedDecl); } + if (const ObjCPropertyRefExpr *PRE = + dyn_cast<ObjCPropertyRefExpr>(E->IgnoreParenImpCasts())) + if (PRE->getGetterResultType()->isReferenceType()) + E = PRE; + RValue RV; if (E->isGLValue()) { // Emit the expression as an lvalue. LValue LV = CGF.EmitLValue(E); + if (LV.isPropertyRef()) { + RV = CGF.EmitLoadOfPropertyRefLValue(LV); + return RV.getScalarVal(); + } if (LV.isSimple()) return LV.getAddress(); // We have to load the lvalue. RV = CGF.EmitLoadOfLValue(LV, E->getType()); } else { - QualType ResultTy = E->getType(); - llvm::SmallVector<SubobjectAdjustment, 2> Adjustments; while (true) { - if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) { - E = PE->getSubExpr(); - continue; - } + E = E->IgnoreParens(); if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { if ((CE->getCastKind() == CK_DerivedToBase || @@ -327,9 +332,8 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, } } - - const llvm::Type *ResultPtrTy = CGF.ConvertType(ResultTy)->getPointerTo(); - return CGF.Builder.CreateBitCast(Object, ResultPtrTy, "temp"); + + return Object; } } @@ -536,6 +540,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { case Expr::DeclRefExprClass: return EmitDeclRefLValue(cast<DeclRefExpr>(E)); case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr()); + case Expr::GenericSelectionExprClass: + return EmitLValue(cast<GenericSelectionExpr>(E)->getResultExpr()); case Expr::PredefinedExprClass: return EmitPredefinedLValue(cast<PredefinedExpr>(E)); case Expr::StringLiteralClass: @@ -718,21 +724,22 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV, Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field"); // Offset by the byte offset, if used. - if (AI.FieldByteOffset) { + if (!AI.FieldByteOffset.isZero()) { Ptr = EmitCastToVoidPtr(Ptr); - Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs"); + Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset.getQuantity(), + "bf.field.offs"); } // Cast to the access type. const llvm::Type *PTy = llvm::Type::getIntNPtrTy(getLLVMContext(), AI.AccessWidth, - ExprType.getAddressSpace()); + CGM.getContext().getTargetAddressSpace(ExprType)); Ptr = Builder.CreateBitCast(Ptr, PTy); // Perform the load. llvm::LoadInst *Load = Builder.CreateLoad(Ptr, LV.isVolatileQualified()); - if (AI.AccessAlignment) - Load->setAlignment(AI.AccessAlignment); + if (!AI.AccessAlignment.isZero()) + Load->setAlignment(AI.AccessAlignment.getQuantity()); // Shift out unused low bits and mask out unused high bits. llvm::Value *Val = Load; @@ -921,9 +928,10 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, Ptr = Builder.CreateStructGEP(Ptr, AI.FieldIndex, "bf.field"); // Offset by the byte offset, if used. - if (AI.FieldByteOffset) { + if (!AI.FieldByteOffset.isZero()) { Ptr = EmitCastToVoidPtr(Ptr); - Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset,"bf.field.offs"); + Ptr = Builder.CreateConstGEP1_32(Ptr, AI.FieldByteOffset.getQuantity(), + "bf.field.offs"); } // Cast to the access type. @@ -954,8 +962,8 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // If necessary, load and OR in bits that are outside of the bit-field. if (AI.TargetBitWidth != AI.AccessWidth) { llvm::LoadInst *Load = Builder.CreateLoad(Ptr, Dst.isVolatileQualified()); - if (AI.AccessAlignment) - Load->setAlignment(AI.AccessAlignment); + if (!AI.AccessAlignment.isZero()) + Load->setAlignment(AI.AccessAlignment.getQuantity()); // Compute the mask for zeroing the bits that are part of the bit-field. llvm::APInt InvMask = @@ -969,8 +977,8 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // Write the value. llvm::StoreInst *Store = Builder.CreateStore(Val, Ptr, Dst.isVolatileQualified()); - if (AI.AccessAlignment) - Store->setAlignment(AI.AccessAlignment); + if (!AI.AccessAlignment.isZero()) + Store->setAlignment(AI.AccessAlignment.getQuantity()); } } @@ -1090,6 +1098,12 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E, } return; } + + if (const GenericSelectionExpr *Exp = dyn_cast<GenericSelectionExpr>(E)) { + setObjCGCLValueClass(Ctx, Exp->getResultExpr(), LV); + return; + } + if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E)) { setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV); return; @@ -1415,6 +1429,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { // We know that the pointer points to a type of the correct size, unless the // size is a VLA or Objective-C interface. llvm::Value *Address = 0; + unsigned ArrayAlignment = 0; if (const VariableArrayType *VAT = getContext().getAsVariableArrayType(E->getType())) { llvm::Value *VLASize = GetVLASize(VAT); @@ -1425,7 +1440,10 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { llvm::Value *Base = EmitScalarExpr(E->getBase()); Address = EmitCastToVoidPtr(Base); - Address = Builder.CreateInBoundsGEP(Address, Idx, "arrayidx"); + if (getContext().getLangOptions().isSignedOverflowDefined()) + Address = Builder.CreateGEP(Address, Idx, "arrayidx"); + else + Address = Builder.CreateInBoundsGEP(Address, Idx, "arrayidx"); Address = Builder.CreateBitCast(Address, Base->getType()); } else if (const ObjCObjectType *OIT = E->getType()->getAs<ObjCObjectType>()){ // Indexing over an interface, as in "NSString *P; P[4];" @@ -1447,22 +1465,38 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { // "gep x, i" here. Emit one "gep A, 0, i". assert(Array->getType()->isArrayType() && "Array to pointer decay must have array source type!"); - llvm::Value *ArrayPtr = EmitLValue(Array).getAddress(); + LValue ArrayLV = EmitLValue(Array); + llvm::Value *ArrayPtr = ArrayLV.getAddress(); llvm::Value *Zero = llvm::ConstantInt::get(Int32Ty, 0); llvm::Value *Args[] = { Zero, Idx }; - Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, Args+2, "arrayidx"); + // Propagate the alignment from the array itself to the result. + ArrayAlignment = ArrayLV.getAlignment(); + + if (getContext().getLangOptions().isSignedOverflowDefined()) + Address = Builder.CreateGEP(ArrayPtr, Args, Args+2, "arrayidx"); + else + Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, Args+2, "arrayidx"); } else { // The base must be a pointer, which is not an aggregate. Emit it. llvm::Value *Base = EmitScalarExpr(E->getBase()); - Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx"); + if (getContext().getLangOptions().isSignedOverflowDefined()) + Address = Builder.CreateGEP(Base, Idx, "arrayidx"); + else + Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx"); } QualType T = E->getBase()->getType()->getPointeeType(); assert(!T.isNull() && "CodeGenFunction::EmitArraySubscriptExpr(): Illegal base type"); - LValue LV = MakeAddrLValue(Address, T); + // Limit the alignment to that of the result type. + if (ArrayAlignment) { + unsigned Align = getContext().getTypeAlignInChars(T).getQuantity(); + ArrayAlignment = std::min(Align, ArrayAlignment); + } + + LValue LV = MakeAddrLValue(Address, T, ArrayAlignment); LV.getQuals().setAddressSpace(E->getBase()->getType().getAddressSpace()); if (getContext().getLangOptions().ObjC1 && @@ -1715,10 +1749,10 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) { } const Expr *condExpr = expr->getCond(); - - if (int condValue = ConstantFoldsToSimpleInteger(condExpr)) { + bool CondExprBool; + if (ConstantFoldsToSimpleInteger(condExpr, CondExprBool)) { const Expr *live = expr->getTrueExpr(), *dead = expr->getFalseExpr(); - if (condValue == -1) std::swap(live, dead); + if (!CondExprBool) std::swap(live, dead); if (!ContainsLabel(dead)) return EmitLValue(live); @@ -1756,9 +1790,8 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) { EmitBlock(contBlock); - llvm::PHINode *phi = Builder.CreatePHI(lhs.getAddress()->getType(), + llvm::PHINode *phi = Builder.CreatePHI(lhs.getAddress()->getType(), 2, "cond-lvalue"); - phi->reserveOperandSpace(2); phi->addIncoming(lhs.getAddress(), lhsBlock); phi->addIncoming(rhs.getAddress(), rhsBlock); return MakeAddrLValue(phi, expr->getType()); @@ -1927,6 +1960,12 @@ LValue CodeGenFunction::EmitOpaqueValueLValue(const OpaqueValueExpr *e) { RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue) { + if (CGDebugInfo *DI = getDebugInfo()) { + DI->setLocation(E->getLocStart()); + DI->UpdateLineDirectiveRegion(Builder); + DI->EmitStopPoint(Builder); + } + // Builtins never have block type. if (E->getCallee()->getType()->isBlockPointerType()) return EmitBlockCallExpr(E, ReturnValue); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp index f992dc7..29c7688 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprAgg.cpp @@ -81,6 +81,9 @@ public: CGF.ErrorUnsupported(S, "aggregate expression"); } void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); } + void VisitGenericSelectionExpr(GenericSelectionExpr *GE) { + Visit(GE->getResultExpr()); + } void VisitUnaryExtension(UnaryOperator *E) { Visit(E->getSubExpr()); } // l-values. @@ -179,11 +182,9 @@ bool AggExprEmitter::TypeRequiresGCollection(QualType T) { /// move will be performed. void AggExprEmitter::EmitGCMove(const Expr *E, RValue Src) { if (Dest.requiresGCollection()) { - std::pair<uint64_t, unsigned> TypeInfo = - CGF.getContext().getTypeInfo(E->getType()); - unsigned long size = TypeInfo.first/8; + CharUnits size = CGF.getContext().getTypeSizeInChars(E->getType()); const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); - llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size); + llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity()); CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, Dest.getAddr(), Src.getAggregateAddr(), SizeVal); @@ -212,11 +213,9 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, RValue Src, bool Ignore) { } if (Dest.requiresGCollection()) { - std::pair<uint64_t, unsigned> TypeInfo = - CGF.getContext().getTypeInfo(E->getType()); - unsigned long size = TypeInfo.first/8; + CharUnits size = CGF.getContext().getTypeSizeInChars(E->getType()); const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType()); - llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size); + llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity()); CGF.CGM.getObjCRuntime().EmitGCMemmoveCollectable(CGF, Dest.getAddr(), Src.getAggregateAddr(), @@ -249,11 +248,6 @@ void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) { } void AggExprEmitter::VisitCastExpr(CastExpr *E) { - if (Dest.isIgnored() && E->getCastKind() != CK_Dynamic) { - Visit(E->getSubExpr()); - return; - } - switch (E->getCastKind()) { case CK_Dynamic: { assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?"); @@ -270,6 +264,8 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { } case CK_ToUnion: { + if (Dest.isIgnored()) break; + // GCC union extension QualType Ty = E->getSubExpr()->getType(); QualType PtrTy = CGF.getContext().getPointerType(Ty); @@ -309,7 +305,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_LValueBitCast: llvm_unreachable("should not be emitting lvalue bitcast as rvalue"); break; - + case CK_Dependent: case CK_BitCast: case CK_ArrayToPointerDecay: @@ -397,15 +393,38 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { E->getRHS()->getType()) && "Invalid assignment"); - // FIXME: __block variables need the RHS evaluated first! + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->getLHS())) + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) + if (VD->hasAttr<BlocksAttr>() && + E->getRHS()->HasSideEffects(CGF.getContext())) { + // When __block variable on LHS, the RHS must be evaluated first + // as it may change the 'forwarding' field via call to Block_copy. + LValue RHS = CGF.EmitLValue(E->getRHS()); + LValue LHS = CGF.EmitLValue(E->getLHS()); + bool GCollection = false; + if (CGF.getContext().getLangOptions().getGCMode()) + GCollection = TypeRequiresGCollection(E->getLHS()->getType()); + Dest = AggValueSlot::forLValue(LHS, true, GCollection); + EmitFinalDestCopy(E, RHS, true); + return; + } + LValue LHS = CGF.EmitLValue(E->getLHS()); // We have to special case property setters, otherwise we must have // a simple lvalue (no aggregates inside vectors, bitfields). if (LHS.isPropertyRef()) { - AggValueSlot Slot = EnsureSlot(E->getRHS()->getType()); - CGF.EmitAggExpr(E->getRHS(), Slot); - CGF.EmitStoreThroughPropertyRefLValue(Slot.asRValue(), LHS); + const ObjCPropertyRefExpr *RE = LHS.getPropertyRefExpr(); + QualType ArgType = RE->getSetterArgType(); + RValue Src; + if (ArgType->isReferenceType()) + Src = CGF.EmitReferenceBindingToExpr(E->getRHS(), 0); + else { + AggValueSlot Slot = EnsureSlot(E->getRHS()->getType()); + CGF.EmitAggExpr(E->getRHS(), Slot); + Src = Slot.asRValue(); + } + CGF.EmitStoreThroughPropertyRefLValue(Src, LHS); } else { bool GCollection = false; if (CGF.getContext().getLangOptions().getGCMode()) @@ -513,9 +532,8 @@ void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { /// zero to memory, return true. This can return false if uncertain, so it just /// handles simple cases. static bool isSimpleZero(const Expr *E, CodeGenFunction &CGF) { - // (0) - if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) - return isSimpleZero(PE->getSubExpr(), CGF); + E = E->IgnoreParens(); + // 0 if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E)) return IL->getValue() == 0; @@ -619,6 +637,14 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { QualType ElementType = CGF.getContext().getCanonicalType(E->getType()); ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType(); + bool hasNonTrivialCXXConstructor = false; + if (CGF.getContext().getLangOptions().CPlusPlus) + if (const RecordType *RT = CGF.getContext() + .getBaseElementType(ElementType)->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + hasNonTrivialCXXConstructor = !RD->hasTrivialConstructor(); + } + // FIXME: were we intentionally ignoring address spaces and GC attributes? for (uint64_t i = 0; i != NumArrayElements; ++i) { @@ -626,7 +652,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // then we're done. if (i == NumInitElements && Dest.isZeroed() && - CGF.getTypes().isZeroInitializable(ElementType)) + CGF.getTypes().isZeroInitializable(ElementType) && + !hasNonTrivialCXXConstructor) break; llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array"); @@ -634,6 +661,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { if (i < NumInitElements) EmitInitializationToLValue(E->getInit(i), LV, ElementType); + else if (Expr *filler = E->getArrayFiller()) + EmitInitializationToLValue(filler, LV, ElementType); else EmitNullInitializationToLValue(LV, ElementType); @@ -737,18 +766,17 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { /// GetNumNonZeroBytesInInit - Get an approximate count of the number of /// non-zero bytes that will be stored when outputting the initializer for the /// specified initializer expression. -static uint64_t GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) { - if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) - return GetNumNonZeroBytesInInit(PE->getSubExpr(), CGF); +static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) { + E = E->IgnoreParens(); // 0 and 0.0 won't require any non-zero stores! - if (isSimpleZero(E, CGF)) return 0; + if (isSimpleZero(E, CGF)) return CharUnits::Zero(); // If this is an initlist expr, sum up the size of sizes of the (present) // elements. If this is something weird, assume the whole thing is non-zero. const InitListExpr *ILE = dyn_cast<InitListExpr>(E); if (ILE == 0 || !CGF.getTypes().isZeroInitializable(ILE->getType())) - return CGF.getContext().getTypeSize(E->getType())/8; + return CGF.getContext().getTypeSizeInChars(E->getType()); // InitListExprs for structs have to be handled carefully. If there are // reference members, we need to consider the size of the reference, not the @@ -756,7 +784,7 @@ static uint64_t GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) { if (const RecordType *RT = E->getType()->getAs<RecordType>()) { if (!RT->isUnionType()) { RecordDecl *SD = E->getType()->getAs<RecordType>()->getDecl(); - uint64_t NumNonZeroBytes = 0; + CharUnits NumNonZeroBytes = CharUnits::Zero(); unsigned ILEElement = 0; for (RecordDecl::field_iterator Field = SD->field_begin(), @@ -773,7 +801,8 @@ static uint64_t GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) { // Reference values are always non-null and have the width of a pointer. if (Field->getType()->isReferenceType()) - NumNonZeroBytes += CGF.getContext().Target.getPointerWidth(0); + NumNonZeroBytes += CGF.getContext().toCharUnitsFromBits( + CGF.getContext().Target.getPointerWidth(0)); else NumNonZeroBytes += GetNumNonZeroBytesInInit(E, CGF); } @@ -783,7 +812,7 @@ static uint64_t GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) { } - uint64_t NumNonZeroBytes = 0; + CharUnits NumNonZeroBytes = CharUnits::Zero(); for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) NumNonZeroBytes += GetNumNonZeroBytesInInit(ILE->getInit(i), CGF); return NumNonZeroBytes; @@ -797,28 +826,38 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E, // If the slot is already known to be zeroed, nothing to do. Don't mess with // volatile stores. if (Slot.isZeroed() || Slot.isVolatile() || Slot.getAddr() == 0) return; - + + // C++ objects with a user-declared constructor don't need zero'ing. + if (CGF.getContext().getLangOptions().CPlusPlus) + if (const RecordType *RT = CGF.getContext() + .getBaseElementType(E->getType())->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->hasUserDeclaredConstructor()) + return; + } + // If the type is 16-bytes or smaller, prefer individual stores over memset. - std::pair<uint64_t, unsigned> TypeInfo = - CGF.getContext().getTypeInfo(E->getType()); - if (TypeInfo.first/8 <= 16) + std::pair<CharUnits, CharUnits> TypeInfo = + CGF.getContext().getTypeInfoInChars(E->getType()); + if (TypeInfo.first <= CharUnits::fromQuantity(16)) return; // Check to see if over 3/4 of the initializer are known to be zero. If so, // we prefer to emit memset + individual stores for the rest. - uint64_t NumNonZeroBytes = GetNumNonZeroBytesInInit(E, CGF); - if (NumNonZeroBytes*4 > TypeInfo.first/8) + CharUnits NumNonZeroBytes = GetNumNonZeroBytesInInit(E, CGF); + if (NumNonZeroBytes*4 > TypeInfo.first) return; // Okay, it seems like a good idea to use an initial memset, emit the call. - llvm::Constant *SizeVal = CGF.Builder.getInt64(TypeInfo.first/8); - unsigned Align = TypeInfo.second/8; + llvm::Constant *SizeVal = CGF.Builder.getInt64(TypeInfo.first.getQuantity()); + CharUnits Align = TypeInfo.second; llvm::Value *Loc = Slot.getAddr(); const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); Loc = CGF.Builder.CreateBitCast(Loc, BP); - CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal, Align, false); + CGF.Builder.CreateMemSet(Loc, CGF.Builder.getInt8(0), SizeVal, + Align.getQuantity(), false); // Tell the AggExprEmitter that the slot is known zero. Slot.setZeroed(); @@ -887,7 +926,8 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, // safely handle this, we can add a target hook. // Get size and alignment info for this aggregate. - std::pair<uint64_t, unsigned> TypeInfo = getContext().getTypeInfo(Ty); + std::pair<CharUnits, CharUnits> TypeInfo = + getContext().getTypeInfoInChars(Ty); // FIXME: Handle variable sized types. @@ -917,9 +957,9 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, if (const RecordType *RecordTy = Ty->getAs<RecordType>()) { RecordDecl *Record = RecordTy->getDecl(); if (Record->hasObjectMember()) { - unsigned long size = TypeInfo.first/8; + CharUnits size = TypeInfo.first; const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); - llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size); + llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size.getQuantity()); CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, SizeVal); return; @@ -928,9 +968,10 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, QualType BaseType = getContext().getBaseElementType(Ty); if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) { if (RecordTy->getDecl()->hasObjectMember()) { - unsigned long size = TypeInfo.first/8; + CharUnits size = TypeInfo.first; const llvm::Type *SizeTy = ConvertType(getContext().getSizeType()); - llvm::Value *SizeVal = llvm::ConstantInt::get(SizeTy, size); + llvm::Value *SizeVal = + llvm::ConstantInt::get(SizeTy, size.getQuantity()); CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestPtr, SrcPtr, SizeVal); return; @@ -939,6 +980,7 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, } Builder.CreateMemCpy(DestPtr, SrcPtr, - llvm::ConstantInt::get(IntPtrTy, TypeInfo.first/8), - TypeInfo.second/8, isVolatile); + llvm::ConstantInt::get(IntPtrTy, + TypeInfo.first.getQuantity()), + TypeInfo.second.getQuantity(), isVolatile); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp index bba7864..bdaa873 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprCXX.cpp @@ -17,6 +17,8 @@ #include "CGObjCRuntime.h" #include "CGDebugInfo.h" #include "llvm/Intrinsics.h" +#include "llvm/Support/CallSite.h" + using namespace clang; using namespace CodeGen; @@ -35,13 +37,12 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, CallArgList Args; // Push the this ptr. - Args.push_back(std::make_pair(RValue::get(This), - MD->getThisType(getContext()))); + Args.add(RValue::get(This), MD->getThisType(getContext())); // If there is a VTT parameter, emit it. if (VTT) { QualType T = getContext().getPointerType(getContext().VoidPtrTy); - Args.push_back(std::make_pair(RValue::get(VTT), T)); + Args.add(RValue::get(VTT), T); } // And the rest of the call args @@ -77,6 +78,31 @@ static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) { return cast<CXXRecordDecl>(DerivedType->castAs<RecordType>()->getDecl()); } +// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do +// quite what we want. +static const Expr *skipNoOpCastsAndParens(const Expr *E) { + while (true) { + if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) { + E = PE->getSubExpr(); + continue; + } + + if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { + if (CE->getCastKind() == CK_NoOp) { + E = CE->getSubExpr(); + continue; + } + } + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + if (UO->getOpcode() == UO_Extension) { + E = UO->getSubExpr(); + continue; + } + } + return E; + } +} + /// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given /// expr can be devirtualized. static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context, @@ -112,6 +138,7 @@ static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context, if (MD->getParent()->hasAttr<FinalAttr>()) return true; + Base = skipNoOpCastsAndParens(Base); if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { // This is a record decl. We know the type and can devirtualize it. @@ -141,10 +168,12 @@ static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context, // extensions allowing explicit constructor function call. RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, ReturnValueSlot ReturnValue) { - if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens())) + const Expr *callee = CE->getCallee()->IgnoreParens(); + + if (isa<BinaryOperator>(callee)) return EmitCXXMemberPointerCallExpr(CE, ReturnValue); - - const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens()); + + const MemberExpr *ME = cast<MemberExpr>(callee); const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); CGDebugInfo *DI = getDebugInfo(); @@ -259,10 +288,10 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, const Expr *MemFnExpr = BO->getRHS(); const MemberPointerType *MPT = - MemFnExpr->getType()->getAs<MemberPointerType>(); + MemFnExpr->getType()->castAs<MemberPointerType>(); const FunctionProtoType *FPT = - MPT->getPointeeType()->getAs<FunctionProtoType>(); + MPT->getPointeeType()->castAs<FunctionProtoType>(); const CXXRecordDecl *RD = cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl()); @@ -287,12 +316,11 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, getContext().getPointerType(getContext().getTagDeclType(RD)); // Push the this ptr. - Args.push_back(std::make_pair(RValue::get(This), ThisType)); + Args.add(RValue::get(This), ThisType); // And the rest of the call args EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end()); - const FunctionType *BO_FPT = BO->getType()->getAs<FunctionProtoType>(); - return EmitCall(CGM.getTypes().getFunctionInfo(Args, BO_FPT), Callee, + return EmitCall(CGM.getTypes().getFunctionInfo(Args, FPT), Callee, ReturnValue, Args); } @@ -341,8 +369,9 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E, // If we require zero initialization before (or instead of) calling the // constructor, as can be the case with a non-user-provided default - // constructor, emit the zero initialization now. - if (E->requiresZeroInitialization()) + // constructor, emit the zero initialization now, unless destination is + // already zeroed. + if (E->requiresZeroInitialization() && !Dest.isZeroed()) EmitNullInitialization(Dest.getAddr(), E->getType()); // If this is a call to a trivial default constructor, do nothing. @@ -374,9 +403,16 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E, E->arg_begin(), E->arg_end()); } else { - CXXCtorType Type = - (E->getConstructionKind() == CXXConstructExpr::CK_Complete) - ? Ctor_Complete : Ctor_Base; + CXXCtorType Type; + CXXConstructExpr::ConstructionKind K = E->getConstructionKind(); + if (K == CXXConstructExpr::CK_Delegating) { + // We should be emitting a constructor; GlobalDecl will assert this + Type = CurGD.getCtorType(); + } else { + Type = (E->getConstructionKind() == CXXConstructExpr::CK_Complete) + ? Ctor_Complete : Ctor_Base; + } + bool ForVirtualBase = E->getConstructionKind() == CXXConstructExpr::CK_VirtualBase; @@ -595,7 +631,7 @@ static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context, Size = CGF.Builder.CreateExtractValue(AddRes, 0); llvm::Value *AddDidOverflow = CGF.Builder.CreateExtractValue(AddRes, 1); - DidOverflow = CGF.Builder.CreateAnd(DidOverflow, AddDidOverflow); + DidOverflow = CGF.Builder.CreateOr(DidOverflow, AddDidOverflow); } Size = CGF.Builder.CreateSelect(DidOverflow, @@ -800,15 +836,15 @@ namespace { // The first argument is always a void*. FunctionProtoType::arg_type_iterator AI = FPT->arg_type_begin(); - DeleteArgs.push_back(std::make_pair(RValue::get(Ptr), *AI++)); + DeleteArgs.add(RValue::get(Ptr), *AI++); // A member 'operator delete' can take an extra 'size_t' argument. if (FPT->getNumArgs() == NumPlacementArgs + 2) - DeleteArgs.push_back(std::make_pair(RValue::get(AllocSize), *AI++)); + DeleteArgs.add(RValue::get(AllocSize), *AI++); // Pass the rest of the arguments, which must match exactly. for (unsigned I = 0; I != NumPlacementArgs; ++I) - DeleteArgs.push_back(std::make_pair(getPlacementArgs()[I], *AI++)); + DeleteArgs.add(getPlacementArgs()[I], *AI++); // Call 'operator delete'. CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(DeleteArgs, FPT), @@ -857,18 +893,18 @@ namespace { // The first argument is always a void*. FunctionProtoType::arg_type_iterator AI = FPT->arg_type_begin(); - DeleteArgs.push_back(std::make_pair(Ptr.restore(CGF), *AI++)); + DeleteArgs.add(Ptr.restore(CGF), *AI++); // A member 'operator delete' can take an extra 'size_t' argument. if (FPT->getNumArgs() == NumPlacementArgs + 2) { RValue RV = AllocSize.restore(CGF); - DeleteArgs.push_back(std::make_pair(RV, *AI++)); + DeleteArgs.add(RV, *AI++); } // Pass the rest of the arguments, which must match exactly. for (unsigned I = 0; I != NumPlacementArgs; ++I) { RValue RV = getPlacementArgs()[I].restore(CGF); - DeleteArgs.push_back(std::make_pair(RV, *AI++)); + DeleteArgs.add(RV, *AI++); } // Call 'operator delete'. @@ -895,7 +931,7 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF, E->getOperatorDelete(), NewPtr, AllocSize); for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) - Cleanup->setPlacementArg(I, NewArgs[I+1].first); + Cleanup->setPlacementArg(I, NewArgs[I+1].RV); return; } @@ -914,148 +950,154 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF, SavedAllocSize); for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) Cleanup->setPlacementArg(I, - DominatingValue<RValue>::save(CGF, NewArgs[I+1].first)); + DominatingValue<RValue>::save(CGF, NewArgs[I+1].RV)); CGF.ActivateCleanupBlock(CGF.EHStack.stable_begin()); } llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { - QualType AllocType = E->getAllocatedType(); - if (AllocType->isArrayType()) - while (const ArrayType *AType = getContext().getAsArrayType(AllocType)) - AllocType = AType->getElementType(); + // The element type being allocated. + QualType allocType = getContext().getBaseElementType(E->getAllocatedType()); - FunctionDecl *NewFD = E->getOperatorNew(); - const FunctionProtoType *NewFTy = NewFD->getType()->getAs<FunctionProtoType>(); + // 1. Build a call to the allocation function. + FunctionDecl *allocator = E->getOperatorNew(); + const FunctionProtoType *allocatorType = + allocator->getType()->castAs<FunctionProtoType>(); - CallArgList NewArgs; + CallArgList allocatorArgs; // The allocation size is the first argument. - QualType SizeTy = getContext().getSizeType(); + QualType sizeType = getContext().getSizeType(); - llvm::Value *NumElements = 0; - llvm::Value *AllocSizeWithoutCookie = 0; - llvm::Value *AllocSize = EmitCXXNewAllocSize(getContext(), - *this, E, NumElements, - AllocSizeWithoutCookie); + llvm::Value *numElements = 0; + llvm::Value *allocSizeWithoutCookie = 0; + llvm::Value *allocSize = + EmitCXXNewAllocSize(getContext(), *this, E, numElements, + allocSizeWithoutCookie); - NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy)); + allocatorArgs.add(RValue::get(allocSize), sizeType); // Emit the rest of the arguments. // FIXME: Ideally, this should just use EmitCallArgs. - CXXNewExpr::const_arg_iterator NewArg = E->placement_arg_begin(); + CXXNewExpr::const_arg_iterator placementArg = E->placement_arg_begin(); // First, use the types from the function type. // We start at 1 here because the first argument (the allocation size) // has already been emitted. - for (unsigned i = 1, e = NewFTy->getNumArgs(); i != e; ++i, ++NewArg) { - QualType ArgType = NewFTy->getArgType(i); + for (unsigned i = 1, e = allocatorType->getNumArgs(); i != e; + ++i, ++placementArg) { + QualType argType = allocatorType->getArgType(i); - assert(getContext().getCanonicalType(ArgType.getNonReferenceType()). - getTypePtr() == - getContext().getCanonicalType(NewArg->getType()).getTypePtr() && + assert(getContext().hasSameUnqualifiedType(argType.getNonReferenceType(), + placementArg->getType()) && "type mismatch in call argument!"); - NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), - ArgType)); - + EmitCallArg(allocatorArgs, *placementArg, argType); } // Either we've emitted all the call args, or we have a call to a // variadic function. - assert((NewArg == E->placement_arg_end() || NewFTy->isVariadic()) && - "Extra arguments in non-variadic function!"); + assert((placementArg == E->placement_arg_end() || + allocatorType->isVariadic()) && + "Extra arguments to non-variadic function!"); // If we still have any arguments, emit them using the type of the argument. - for (CXXNewExpr::const_arg_iterator NewArgEnd = E->placement_arg_end(); - NewArg != NewArgEnd; ++NewArg) { - QualType ArgType = NewArg->getType(); - NewArgs.push_back(std::make_pair(EmitCallArg(*NewArg, ArgType), - ArgType)); + for (CXXNewExpr::const_arg_iterator placementArgsEnd = E->placement_arg_end(); + placementArg != placementArgsEnd; ++placementArg) { + EmitCallArg(allocatorArgs, *placementArg, placementArg->getType()); } - // Emit the call to new. + // Emit the allocation call. RValue RV = - EmitCall(CGM.getTypes().getFunctionInfo(NewArgs, NewFTy), - CGM.GetAddrOfFunction(NewFD), ReturnValueSlot(), NewArgs, NewFD); - - // If an allocation function is declared with an empty exception specification - // it returns null to indicate failure to allocate storage. [expr.new]p13. - // (We don't need to check for null when there's no new initializer and - // we're allocating a POD type). - bool NullCheckResult = NewFTy->hasEmptyExceptionSpec() && - !(AllocType->isPODType() && !E->hasInitializer()); - - llvm::BasicBlock *NullCheckSource = 0; - llvm::BasicBlock *NewNotNull = 0; - llvm::BasicBlock *NewEnd = 0; - - llvm::Value *NewPtr = RV.getScalarVal(); - unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace(); - - if (NullCheckResult) { - NullCheckSource = Builder.GetInsertBlock(); - NewNotNull = createBasicBlock("new.notnull"); - NewEnd = createBasicBlock("new.end"); - - llvm::Value *IsNull = Builder.CreateIsNull(NewPtr, "new.isnull"); - Builder.CreateCondBr(IsNull, NewEnd, NewNotNull); - EmitBlock(NewNotNull); + EmitCall(CGM.getTypes().getFunctionInfo(allocatorArgs, allocatorType), + CGM.GetAddrOfFunction(allocator), ReturnValueSlot(), + allocatorArgs, allocator); + + // Emit a null check on the allocation result if the allocation + // function is allowed to return null (because it has a non-throwing + // exception spec; for this part, we inline + // CXXNewExpr::shouldNullCheckAllocation()) and we have an + // interesting initializer. + bool nullCheck = allocatorType->isNothrow(getContext()) && + !(allocType->isPODType() && !E->hasInitializer()); + + llvm::BasicBlock *nullCheckBB = 0; + llvm::BasicBlock *contBB = 0; + + llvm::Value *allocation = RV.getScalarVal(); + unsigned AS = + cast<llvm::PointerType>(allocation->getType())->getAddressSpace(); + + // The null-check means that the initializer is conditionally + // evaluated. + ConditionalEvaluation conditional(*this); + + if (nullCheck) { + conditional.begin(*this); + + nullCheckBB = Builder.GetInsertBlock(); + llvm::BasicBlock *notNullBB = createBasicBlock("new.notnull"); + contBB = createBasicBlock("new.cont"); + + llvm::Value *isNull = Builder.CreateIsNull(allocation, "new.isnull"); + Builder.CreateCondBr(isNull, contBB, notNullBB); + EmitBlock(notNullBB); } - assert((AllocSize == AllocSizeWithoutCookie) == + assert((allocSize == allocSizeWithoutCookie) == CalculateCookiePadding(*this, E).isZero()); - if (AllocSize != AllocSizeWithoutCookie) { + if (allocSize != allocSizeWithoutCookie) { assert(E->isArray()); - NewPtr = CGM.getCXXABI().InitializeArrayCookie(*this, NewPtr, NumElements, - E, AllocType); + allocation = CGM.getCXXABI().InitializeArrayCookie(*this, allocation, + numElements, + E, allocType); } // If there's an operator delete, enter a cleanup to call it if an // exception is thrown. - EHScopeStack::stable_iterator CallOperatorDelete; + EHScopeStack::stable_iterator operatorDeleteCleanup; if (E->getOperatorDelete()) { - EnterNewDeleteCleanup(*this, E, NewPtr, AllocSize, NewArgs); - CallOperatorDelete = EHStack.stable_begin(); + EnterNewDeleteCleanup(*this, E, allocation, allocSize, allocatorArgs); + operatorDeleteCleanup = EHStack.stable_begin(); } - const llvm::Type *ElementPtrTy - = ConvertTypeForMem(AllocType)->getPointerTo(AS); - NewPtr = Builder.CreateBitCast(NewPtr, ElementPtrTy); + const llvm::Type *elementPtrTy + = ConvertTypeForMem(allocType)->getPointerTo(AS); + llvm::Value *result = Builder.CreateBitCast(allocation, elementPtrTy); if (E->isArray()) { - EmitNewInitializer(*this, E, NewPtr, NumElements, AllocSizeWithoutCookie); + EmitNewInitializer(*this, E, result, numElements, allocSizeWithoutCookie); // NewPtr is a pointer to the base element type. If we're // allocating an array of arrays, we'll need to cast back to the // array pointer type. - const llvm::Type *ResultTy = ConvertTypeForMem(E->getType()); - if (NewPtr->getType() != ResultTy) - NewPtr = Builder.CreateBitCast(NewPtr, ResultTy); + const llvm::Type *resultType = ConvertTypeForMem(E->getType()); + if (result->getType() != resultType) + result = Builder.CreateBitCast(result, resultType); } else { - EmitNewInitializer(*this, E, NewPtr, NumElements, AllocSizeWithoutCookie); + EmitNewInitializer(*this, E, result, numElements, allocSizeWithoutCookie); } // Deactivate the 'operator delete' cleanup if we finished // initialization. - if (CallOperatorDelete.isValid()) - DeactivateCleanupBlock(CallOperatorDelete); + if (operatorDeleteCleanup.isValid()) + DeactivateCleanupBlock(operatorDeleteCleanup); - if (NullCheckResult) { - Builder.CreateBr(NewEnd); - llvm::BasicBlock *NotNullSource = Builder.GetInsertBlock(); - EmitBlock(NewEnd); - - llvm::PHINode *PHI = Builder.CreatePHI(NewPtr->getType()); - PHI->reserveOperandSpace(2); - PHI->addIncoming(NewPtr, NotNullSource); - PHI->addIncoming(llvm::Constant::getNullValue(NewPtr->getType()), - NullCheckSource); - - NewPtr = PHI; + if (nullCheck) { + conditional.end(*this); + + llvm::BasicBlock *notNullBB = Builder.GetInsertBlock(); + EmitBlock(contBB); + + llvm::PHINode *PHI = Builder.CreatePHI(result->getType(), 2); + PHI->addIncoming(result, notNullBB); + PHI->addIncoming(llvm::Constant::getNullValue(result->getType()), + nullCheckBB); + + result = PHI; } - return NewPtr; + return result; } void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, @@ -1080,10 +1122,10 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, QualType ArgTy = DeleteFTy->getArgType(0); llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy)); - DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy)); + DeleteArgs.add(RValue::get(DeletePtr), ArgTy); if (Size) - DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy)); + DeleteArgs.add(RValue::get(Size), SizeTy); // Emit the call to delete. EmitCall(CGM.getTypes().getFunctionInfo(DeleteArgs, DeleteFTy), @@ -1180,7 +1222,7 @@ namespace { QualType VoidPtrTy = DeleteFTy->getArgType(0); llvm::Value *DeletePtr = CGF.Builder.CreateBitCast(Ptr, CGF.ConvertType(VoidPtrTy)); - Args.push_back(std::make_pair(RValue::get(DeletePtr), VoidPtrTy)); + Args.add(RValue::get(DeletePtr), VoidPtrTy); // Pass the original requested size as the second argument. if (DeleteFTy->getNumArgs() == 2) { @@ -1203,7 +1245,7 @@ namespace { Size = CGF.Builder.CreateAdd(Size, CookieSizeV); } - Args.push_back(std::make_pair(RValue::get(Size), size_t)); + Args.add(RValue::get(Size), size_t); } // Emit the call to delete. @@ -1264,9 +1306,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull"); llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end"); - llvm::Value *IsNull = - Builder.CreateICmpEQ(Ptr, llvm::Constant::getNullValue(Ptr->getType()), - "isnull"); + llvm::Value *IsNull = Builder.CreateIsNull(Ptr, "isnull"); Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); EmitBlock(DeleteNotNull); @@ -1306,173 +1346,253 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { EmitBlock(DeleteEnd); } +static llvm::Constant *getBadTypeidFn(CodeGenFunction &CGF) { + // void __cxa_bad_typeid(); + + const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext()); + const llvm::FunctionType *FTy = + llvm::FunctionType::get(VoidTy, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid"); +} + +static void EmitBadTypeidCall(CodeGenFunction &CGF) { + llvm::Value *Fn = getBadTypeidFn(CGF); + CGF.EmitCallOrInvoke(Fn, 0, 0).setDoesNotReturn(); + CGF.Builder.CreateUnreachable(); +} + +static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, + const Expr *E, + const llvm::Type *StdTypeInfoPtrTy) { + // Get the vtable pointer. + llvm::Value *ThisPtr = CGF.EmitLValue(E).getAddress(); + + // C++ [expr.typeid]p2: + // If the glvalue expression is obtained by applying the unary * operator to + // a pointer and the pointer is a null pointer value, the typeid expression + // throws the std::bad_typeid exception. + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) { + if (UO->getOpcode() == UO_Deref) { + llvm::BasicBlock *BadTypeidBlock = + CGF.createBasicBlock("typeid.bad_typeid"); + llvm::BasicBlock *EndBlock = + CGF.createBasicBlock("typeid.end"); + + llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr); + CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock); + + CGF.EmitBlock(BadTypeidBlock); + EmitBadTypeidCall(CGF); + CGF.EmitBlock(EndBlock); + } + } + + llvm::Value *Value = CGF.GetVTablePtr(ThisPtr, + StdTypeInfoPtrTy->getPointerTo()); + + // Load the type info. + Value = CGF.Builder.CreateConstInBoundsGEP1_64(Value, -1ULL); + return CGF.Builder.CreateLoad(Value); +} + llvm::Value *CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) { - QualType Ty = E->getType(); - const llvm::Type *LTy = ConvertType(Ty)->getPointerTo(); + const llvm::Type *StdTypeInfoPtrTy = + ConvertType(E->getType())->getPointerTo(); if (E->isTypeOperand()) { llvm::Constant *TypeInfo = CGM.GetAddrOfRTTIDescriptor(E->getTypeOperand()); - return Builder.CreateBitCast(TypeInfo, LTy); + return Builder.CreateBitCast(TypeInfo, StdTypeInfoPtrTy); } - - Expr *subE = E->getExprOperand(); - Ty = subE->getType(); - CanQualType CanTy = CGM.getContext().getCanonicalType(Ty); - Ty = CanTy.getUnqualifiedType().getNonReferenceType(); - if (const RecordType *RT = Ty->getAs<RecordType>()) { - const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - if (RD->isPolymorphic()) { - // FIXME: if subE is an lvalue do - LValue Obj = EmitLValue(subE); - llvm::Value *This = Obj.getAddress(); - // We need to do a zero check for *p, unless it has NonNullAttr. - // FIXME: PointerType->hasAttr<NonNullAttr>() - bool CanBeZero = false; - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(subE->IgnoreParens())) - if (UO->getOpcode() == UO_Deref) - CanBeZero = true; - if (CanBeZero) { - llvm::BasicBlock *NonZeroBlock = createBasicBlock(); - llvm::BasicBlock *ZeroBlock = createBasicBlock(); - - llvm::Value *Zero = llvm::Constant::getNullValue(This->getType()); - Builder.CreateCondBr(Builder.CreateICmpNE(This, Zero), - NonZeroBlock, ZeroBlock); - EmitBlock(ZeroBlock); - /// Call __cxa_bad_typeid - const llvm::Type *ResultType = llvm::Type::getVoidTy(getLLVMContext()); - const llvm::FunctionType *FTy; - FTy = llvm::FunctionType::get(ResultType, false); - llvm::Value *F = CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid"); - Builder.CreateCall(F)->setDoesNotReturn(); - Builder.CreateUnreachable(); - EmitBlock(NonZeroBlock); - } - llvm::Value *V = GetVTablePtr(This, LTy->getPointerTo()); - V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL); - V = Builder.CreateLoad(V); - return V; + + // C++ [expr.typeid]p2: + // When typeid is applied to a glvalue expression whose type is a + // polymorphic class type, the result refers to a std::type_info object + // representing the type of the most derived object (that is, the dynamic + // type) to which the glvalue refers. + if (E->getExprOperand()->isGLValue()) { + if (const RecordType *RT = + E->getExprOperand()->getType()->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + if (RD->isPolymorphic()) + return EmitTypeidFromVTable(*this, E->getExprOperand(), + StdTypeInfoPtrTy); } } - return Builder.CreateBitCast(CGM.GetAddrOfRTTIDescriptor(Ty), LTy); + + QualType OperandTy = E->getExprOperand()->getType(); + return Builder.CreateBitCast(CGM.GetAddrOfRTTIDescriptor(OperandTy), + StdTypeInfoPtrTy); } -llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V, - const CXXDynamicCastExpr *DCE) { - QualType SrcTy = DCE->getSubExpr()->getType(); - QualType DestTy = DCE->getTypeAsWritten(); - QualType InnerType = DestTy->getPointeeType(); +static llvm::Constant *getDynamicCastFn(CodeGenFunction &CGF) { + // void *__dynamic_cast(const void *sub, + // const abi::__class_type_info *src, + // const abi::__class_type_info *dst, + // std::ptrdiff_t src2dst_offset); - const llvm::Type *LTy = ConvertType(DCE->getType()); - - bool CanBeZero = false; - bool ToVoid = false; - bool ThrowOnBad = false; - if (DestTy->isPointerType()) { - // FIXME: if PointerType->hasAttr<NonNullAttr>(), we don't set this - CanBeZero = true; - if (InnerType->isVoidType()) - ToVoid = true; - } else { - LTy = LTy->getPointerTo(); - - // FIXME: What if exceptions are disabled? - ThrowOnBad = true; + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + const llvm::Type *PtrDiffTy = + CGF.ConvertType(CGF.getContext().getPointerDiffType()); + + const llvm::Type *Args[4] = { Int8PtrTy, Int8PtrTy, Int8PtrTy, PtrDiffTy }; + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(Int8PtrTy, Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"); +} + +static llvm::Constant *getBadCastFn(CodeGenFunction &CGF) { + // void __cxa_bad_cast(); + + const llvm::Type *VoidTy = llvm::Type::getVoidTy(CGF.getLLVMContext()); + const llvm::FunctionType *FTy = + llvm::FunctionType::get(VoidTy, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_bad_cast"); +} + +static void EmitBadCastCall(CodeGenFunction &CGF) { + llvm::Value *Fn = getBadCastFn(CGF); + CGF.EmitCallOrInvoke(Fn, 0, 0).setDoesNotReturn(); + CGF.Builder.CreateUnreachable(); +} + +static llvm::Value * +EmitDynamicCastCall(CodeGenFunction &CGF, llvm::Value *Value, + QualType SrcTy, QualType DestTy, + llvm::BasicBlock *CastEnd) { + const llvm::Type *PtrDiffLTy = + CGF.ConvertType(CGF.getContext().getPointerDiffType()); + const llvm::Type *DestLTy = CGF.ConvertType(DestTy); + + if (const PointerType *PTy = DestTy->getAs<PointerType>()) { + if (PTy->getPointeeType()->isVoidType()) { + // C++ [expr.dynamic.cast]p7: + // If T is "pointer to cv void," then the result is a pointer to the + // most derived object pointed to by v. + + // Get the vtable pointer. + llvm::Value *VTable = CGF.GetVTablePtr(Value, PtrDiffLTy->getPointerTo()); + + // Get the offset-to-top from the vtable. + llvm::Value *OffsetToTop = + CGF.Builder.CreateConstInBoundsGEP1_64(VTable, -2ULL); + OffsetToTop = CGF.Builder.CreateLoad(OffsetToTop, "offset.to.top"); + + // Finally, add the offset to the pointer. + Value = CGF.EmitCastToVoidPtr(Value); + Value = CGF.Builder.CreateInBoundsGEP(Value, OffsetToTop); + + return CGF.Builder.CreateBitCast(Value, DestLTy); + } } - if (SrcTy->isPointerType() || SrcTy->isReferenceType()) - SrcTy = SrcTy->getPointeeType(); - SrcTy = SrcTy.getUnqualifiedType(); - - if (DestTy->isPointerType() || DestTy->isReferenceType()) - DestTy = DestTy->getPointeeType(); - DestTy = DestTy.getUnqualifiedType(); - - llvm::BasicBlock *ContBlock = createBasicBlock(); - llvm::BasicBlock *NullBlock = 0; - llvm::BasicBlock *NonZeroBlock = 0; - if (CanBeZero) { - NonZeroBlock = createBasicBlock(); - NullBlock = createBasicBlock(); - Builder.CreateCondBr(Builder.CreateIsNotNull(V), NonZeroBlock, NullBlock); - EmitBlock(NonZeroBlock); + QualType SrcRecordTy; + QualType DestRecordTy; + + if (const PointerType *DestPTy = DestTy->getAs<PointerType>()) { + SrcRecordTy = SrcTy->castAs<PointerType>()->getPointeeType(); + DestRecordTy = DestPTy->getPointeeType(); + } else { + SrcRecordTy = SrcTy; + DestRecordTy = DestTy->castAs<ReferenceType>()->getPointeeType(); } - llvm::BasicBlock *BadCastBlock = 0; + assert(SrcRecordTy->isRecordType() && "source type must be a record type!"); + assert(DestRecordTy->isRecordType() && "dest type must be a record type!"); - const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType()); + llvm::Value *SrcRTTI = + CGF.CGM.GetAddrOfRTTIDescriptor(SrcRecordTy.getUnqualifiedType()); + llvm::Value *DestRTTI = + CGF.CGM.GetAddrOfRTTIDescriptor(DestRecordTy.getUnqualifiedType()); - // See if this is a dynamic_cast(void*) - if (ToVoid) { - llvm::Value *This = V; - V = GetVTablePtr(This, PtrDiffTy->getPointerTo()); - V = Builder.CreateConstInBoundsGEP1_64(V, -2ULL); - V = Builder.CreateLoad(V, "offset to top"); - This = EmitCastToVoidPtr(This); - V = Builder.CreateInBoundsGEP(This, V); - V = Builder.CreateBitCast(V, LTy); - } else { - /// Call __dynamic_cast - const llvm::Type *ResultType = Int8PtrTy; - const llvm::FunctionType *FTy; - std::vector<const llvm::Type*> ArgTys; - ArgTys.push_back(Int8PtrTy); - ArgTys.push_back(Int8PtrTy); - ArgTys.push_back(Int8PtrTy); - ArgTys.push_back(PtrDiffTy); - FTy = llvm::FunctionType::get(ResultType, ArgTys, false); - - // FIXME: Calculate better hint. - llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL); - - assert(SrcTy->isRecordType() && "Src type must be record type!"); - assert(DestTy->isRecordType() && "Dest type must be record type!"); - - llvm::Value *SrcArg - = CGM.GetAddrOfRTTIDescriptor(SrcTy.getUnqualifiedType()); - llvm::Value *DestArg - = CGM.GetAddrOfRTTIDescriptor(DestTy.getUnqualifiedType()); - - V = Builder.CreateBitCast(V, Int8PtrTy); - V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"), - V, SrcArg, DestArg, hint); - V = Builder.CreateBitCast(V, LTy); - - if (ThrowOnBad) { - BadCastBlock = createBasicBlock(); - Builder.CreateCondBr(Builder.CreateIsNotNull(V), ContBlock, BadCastBlock); - EmitBlock(BadCastBlock); - /// Invoke __cxa_bad_cast - ResultType = llvm::Type::getVoidTy(getLLVMContext()); - const llvm::FunctionType *FBadTy; - FBadTy = llvm::FunctionType::get(ResultType, false); - llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast"); - if (llvm::BasicBlock *InvokeDest = getInvokeDest()) { - llvm::BasicBlock *Cont = createBasicBlock("invoke.cont"); - Builder.CreateInvoke(F, Cont, InvokeDest)->setDoesNotReturn(); - EmitBlock(Cont); - } else { - // FIXME: Does this ever make sense? - Builder.CreateCall(F)->setDoesNotReturn(); - } - Builder.CreateUnreachable(); - } + // FIXME: Actually compute a hint here. + llvm::Value *OffsetHint = llvm::ConstantInt::get(PtrDiffLTy, -1ULL); + + // Emit the call to __dynamic_cast. + Value = CGF.EmitCastToVoidPtr(Value); + Value = CGF.Builder.CreateCall4(getDynamicCastFn(CGF), Value, + SrcRTTI, DestRTTI, OffsetHint); + Value = CGF.Builder.CreateBitCast(Value, DestLTy); + + /// C++ [expr.dynamic.cast]p9: + /// A failed cast to reference type throws std::bad_cast + if (DestTy->isReferenceType()) { + llvm::BasicBlock *BadCastBlock = + CGF.createBasicBlock("dynamic_cast.bad_cast"); + + llvm::Value *IsNull = CGF.Builder.CreateIsNull(Value); + CGF.Builder.CreateCondBr(IsNull, BadCastBlock, CastEnd); + + CGF.EmitBlock(BadCastBlock); + EmitBadCastCall(CGF); } + + return Value; +} + +static llvm::Value *EmitDynamicCastToNull(CodeGenFunction &CGF, + QualType DestTy) { + const llvm::Type *DestLTy = CGF.ConvertType(DestTy); + if (DestTy->isPointerType()) + return llvm::Constant::getNullValue(DestLTy); + + /// C++ [expr.dynamic.cast]p9: + /// A failed cast to reference type throws std::bad_cast + EmitBadCastCall(CGF); + + CGF.EmitBlock(CGF.createBasicBlock("dynamic_cast.end")); + return llvm::UndefValue::get(DestLTy); +} + +llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value, + const CXXDynamicCastExpr *DCE) { + QualType DestTy = DCE->getTypeAsWritten(); + + if (DCE->isAlwaysNull()) + return EmitDynamicCastToNull(*this, DestTy); + + QualType SrcTy = DCE->getSubExpr()->getType(); + + // C++ [expr.dynamic.cast]p4: + // If the value of v is a null pointer value in the pointer case, the result + // is the null pointer value of type T. + bool ShouldNullCheckSrcValue = SrcTy->isPointerType(); - if (CanBeZero) { - Builder.CreateBr(ContBlock); - EmitBlock(NullBlock); - Builder.CreateBr(ContBlock); + llvm::BasicBlock *CastNull = 0; + llvm::BasicBlock *CastNotNull = 0; + llvm::BasicBlock *CastEnd = createBasicBlock("dynamic_cast.end"); + + if (ShouldNullCheckSrcValue) { + CastNull = createBasicBlock("dynamic_cast.null"); + CastNotNull = createBasicBlock("dynamic_cast.notnull"); + + llvm::Value *IsNull = Builder.CreateIsNull(Value); + Builder.CreateCondBr(IsNull, CastNull, CastNotNull); + EmitBlock(CastNotNull); + } + + Value = EmitDynamicCastCall(*this, Value, SrcTy, DestTy, CastEnd); + + if (ShouldNullCheckSrcValue) { + EmitBranch(CastEnd); + + EmitBlock(CastNull); + EmitBranch(CastEnd); } - EmitBlock(ContBlock); - if (CanBeZero) { - llvm::PHINode *PHI = Builder.CreatePHI(LTy); - PHI->reserveOperandSpace(2); - PHI->addIncoming(V, NonZeroBlock); - PHI->addIncoming(llvm::Constant::getNullValue(LTy), NullBlock); - V = PHI; + + EmitBlock(CastEnd); + + if (ShouldNullCheckSrcValue) { + llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2); + PHI->addIncoming(Value, CastNotNull); + PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), CastNull); + + Value = PHI; } - return V; + return Value; } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp index 7b0292b..bd19586 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprComplex.cpp @@ -108,6 +108,9 @@ public: } ComplexPairTy VisitExpr(Expr *S); ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());} + ComplexPairTy VisitGenericSelectionExpr(GenericSelectionExpr *GE) { + return Visit(GE->getResultExpr()); + } ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL); // l-values. @@ -668,14 +671,12 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { eval.end(CGF); // Create a PHI node for the real part. - llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), "cond.r"); - RealPN->reserveOperandSpace(2); + llvm::PHINode *RealPN = Builder.CreatePHI(LHS.first->getType(), 2, "cond.r"); RealPN->addIncoming(LHS.first, LHSBlock); RealPN->addIncoming(RHS.first, RHSBlock); // Create a PHI node for the imaginary part. - llvm::PHINode *ImagPN = Builder.CreatePHI(LHS.first->getType(), "cond.i"); - ImagPN->reserveOperandSpace(2); + llvm::PHINode *ImagPN = Builder.CreatePHI(LHS.first->getType(), 2, "cond.i"); ImagPN->addIncoming(LHS.second, LHSBlock); ImagPN->addIncoming(RHS.second, RHSBlock); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp index 40d7b6c..463b913 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprConstant.cpp @@ -38,8 +38,8 @@ class ConstStructBuilder { CodeGenFunction *CGF; bool Packed; - unsigned NextFieldOffsetInBytes; - unsigned LLVMStructAlignment; + CharUnits NextFieldOffsetInChars; + CharUnits LLVMStructAlignment; std::vector<llvm::Constant *> Elements; public: static llvm::Constant *BuildStruct(CodeGenModule &CGM, CodeGenFunction *CGF, @@ -47,8 +47,9 @@ public: private: ConstStructBuilder(CodeGenModule &CGM, CodeGenFunction *CGF) - : CGM(CGM), CGF(CGF), Packed(false), NextFieldOffsetInBytes(0), - LLVMStructAlignment(1) { } + : CGM(CGM), CGF(CGF), Packed(false), + NextFieldOffsetInChars(CharUnits::Zero()), + LLVMStructAlignment(CharUnits::One()) { } bool AppendField(const FieldDecl *Field, uint64_t FieldOffset, llvm::Constant *InitExpr); @@ -56,64 +57,71 @@ private: void AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, llvm::ConstantInt *InitExpr); - void AppendPadding(uint64_t NumBytes); + void AppendPadding(CharUnits PadSize); - void AppendTailPadding(uint64_t RecordSize); + void AppendTailPadding(CharUnits RecordSize); void ConvertStructToPacked(); bool Build(InitListExpr *ILE); - unsigned getAlignment(const llvm::Constant *C) const { - if (Packed) return 1; - return CGM.getTargetData().getABITypeAlignment(C->getType()); + CharUnits getAlignment(const llvm::Constant *C) const { + if (Packed) return CharUnits::One(); + return CharUnits::fromQuantity( + CGM.getTargetData().getABITypeAlignment(C->getType())); } - uint64_t getSizeInBytes(const llvm::Constant *C) const { - return CGM.getTargetData().getTypeAllocSize(C->getType()); + CharUnits getSizeInChars(const llvm::Constant *C) const { + return CharUnits::fromQuantity( + CGM.getTargetData().getTypeAllocSize(C->getType())); } }; bool ConstStructBuilder:: AppendField(const FieldDecl *Field, uint64_t FieldOffset, llvm::Constant *InitCst) { - uint64_t FieldOffsetInBytes = FieldOffset / 8; - assert(NextFieldOffsetInBytes <= FieldOffsetInBytes + const ASTContext &Context = CGM.getContext(); + + CharUnits FieldOffsetInChars = Context.toCharUnitsFromBits(FieldOffset); + + assert(NextFieldOffsetInChars <= FieldOffsetInChars && "Field offset mismatch!"); - unsigned FieldAlignment = getAlignment(InitCst); + CharUnits FieldAlignment = getAlignment(InitCst); // Round up the field offset to the alignment of the field type. - uint64_t AlignedNextFieldOffsetInBytes = - llvm::RoundUpToAlignment(NextFieldOffsetInBytes, FieldAlignment); + CharUnits AlignedNextFieldOffsetInChars = + NextFieldOffsetInChars.RoundUpToAlignment(FieldAlignment); - if (AlignedNextFieldOffsetInBytes > FieldOffsetInBytes) { + if (AlignedNextFieldOffsetInChars > FieldOffsetInChars) { assert(!Packed && "Alignment is wrong even with a packed struct!"); // Convert the struct to a packed struct. ConvertStructToPacked(); - AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + AlignedNextFieldOffsetInChars = NextFieldOffsetInChars; } - if (AlignedNextFieldOffsetInBytes < FieldOffsetInBytes) { + if (AlignedNextFieldOffsetInChars < FieldOffsetInChars) { // We need to append padding. - AppendPadding(FieldOffsetInBytes - NextFieldOffsetInBytes); + AppendPadding( + FieldOffsetInChars - NextFieldOffsetInChars); - assert(NextFieldOffsetInBytes == FieldOffsetInBytes && + assert(NextFieldOffsetInChars == FieldOffsetInChars && "Did not add enough padding!"); - AlignedNextFieldOffsetInBytes = NextFieldOffsetInBytes; + AlignedNextFieldOffsetInChars = NextFieldOffsetInChars; } // Add the field. Elements.push_back(InitCst); - NextFieldOffsetInBytes = AlignedNextFieldOffsetInBytes + - getSizeInBytes(InitCst); + NextFieldOffsetInChars = AlignedNextFieldOffsetInChars + + getSizeInChars(InitCst); if (Packed) - assert(LLVMStructAlignment == 1 && "Packed struct not byte-aligned!"); + assert(LLVMStructAlignment == CharUnits::One() && + "Packed struct not byte-aligned!"); else LLVMStructAlignment = std::max(LLVMStructAlignment, FieldAlignment); @@ -123,17 +131,20 @@ AppendField(const FieldDecl *Field, uint64_t FieldOffset, void ConstStructBuilder::AppendBitField(const FieldDecl *Field, uint64_t FieldOffset, llvm::ConstantInt *CI) { - if (FieldOffset > NextFieldOffsetInBytes * 8) { + const ASTContext &Context = CGM.getContext(); + const uint64_t CharWidth = Context.getCharWidth(); + uint64_t NextFieldOffsetInBits = Context.toBits(NextFieldOffsetInChars); + if (FieldOffset > NextFieldOffsetInBits) { // We need to add padding. - uint64_t NumBytes = - llvm::RoundUpToAlignment(FieldOffset - - NextFieldOffsetInBytes * 8, 8) / 8; + CharUnits PadSize = Context.toCharUnitsFromBits( + llvm::RoundUpToAlignment(FieldOffset - NextFieldOffsetInBits, + Context.Target.getCharAlign())); - AppendPadding(NumBytes); + AppendPadding(PadSize); } uint64_t FieldSize = - Field->getBitWidth()->EvaluateAsInt(CGM.getContext()).getZExtValue(); + Field->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); llvm::APInt FieldValue = CI->getValue(); @@ -148,13 +159,13 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, if (FieldSize < FieldValue.getBitWidth()) FieldValue = FieldValue.trunc(FieldSize); - if (FieldOffset < NextFieldOffsetInBytes * 8) { + NextFieldOffsetInBits = Context.toBits(NextFieldOffsetInChars); + if (FieldOffset < NextFieldOffsetInBits) { // Either part of the field or the entire field can go into the previous // byte. assert(!Elements.empty() && "Elements can't be empty!"); - unsigned BitsInPreviousByte = - NextFieldOffsetInBytes * 8 - FieldOffset; + unsigned BitsInPreviousByte = NextFieldOffsetInBits - FieldOffset; bool FitsCompletelyInPreviousByte = BitsInPreviousByte >= FieldValue.getBitWidth(); @@ -179,12 +190,12 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, } } - Tmp = Tmp.zext(8); + Tmp = Tmp.zext(CharWidth); if (CGM.getTargetData().isBigEndian()) { if (FitsCompletelyInPreviousByte) Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth()); } else { - Tmp = Tmp.shl(8 - BitsInPreviousByte); + Tmp = Tmp.shl(CharWidth - BitsInPreviousByte); } // 'or' in the bits that go into the previous byte. @@ -203,19 +214,19 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, assert(isa<llvm::ArrayType>(LastElt->getType()) && "Expected array padding of undefs"); const llvm::ArrayType *AT = cast<llvm::ArrayType>(LastElt->getType()); - assert(AT->getElementType()->isIntegerTy(8) && + assert(AT->getElementType()->isIntegerTy(CharWidth) && AT->getNumElements() != 0 && "Expected non-empty array padding of undefs"); // Remove the padding array. - NextFieldOffsetInBytes -= AT->getNumElements(); + NextFieldOffsetInChars -= CharUnits::fromQuantity(AT->getNumElements()); Elements.pop_back(); // Add the padding back in two chunks. - AppendPadding(AT->getNumElements()-1); - AppendPadding(1); + AppendPadding(CharUnits::fromQuantity(AT->getNumElements()-1)); + AppendPadding(CharUnits::One()); assert(isa<llvm::UndefValue>(Elements.back()) && - Elements.back()->getType()->isIntegerTy(8) && + Elements.back()->getType()->isIntegerTy(CharWidth) && "Padding addition didn't work right"); } } @@ -226,105 +237,104 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, return; } - while (FieldValue.getBitWidth() > 8) { + while (FieldValue.getBitWidth() > CharWidth) { llvm::APInt Tmp; if (CGM.getTargetData().isBigEndian()) { // We want the high bits. - Tmp = FieldValue.lshr(FieldValue.getBitWidth() - 8).trunc(8); + Tmp = + FieldValue.lshr(FieldValue.getBitWidth() - CharWidth).trunc(CharWidth); } else { // We want the low bits. - Tmp = FieldValue.trunc(8); + Tmp = FieldValue.trunc(CharWidth); - FieldValue = FieldValue.lshr(8); + FieldValue = FieldValue.lshr(CharWidth); } Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), Tmp)); - NextFieldOffsetInBytes++; + ++NextFieldOffsetInChars; - FieldValue = FieldValue.trunc(FieldValue.getBitWidth() - 8); + FieldValue = FieldValue.trunc(FieldValue.getBitWidth() - CharWidth); } assert(FieldValue.getBitWidth() > 0 && "Should have at least one bit left!"); - assert(FieldValue.getBitWidth() <= 8 && + assert(FieldValue.getBitWidth() <= CharWidth && "Should not have more than a byte left!"); - if (FieldValue.getBitWidth() < 8) { + if (FieldValue.getBitWidth() < CharWidth) { if (CGM.getTargetData().isBigEndian()) { unsigned BitWidth = FieldValue.getBitWidth(); - FieldValue = FieldValue.zext(8) << (8 - BitWidth); + FieldValue = FieldValue.zext(CharWidth) << (CharWidth - BitWidth); } else - FieldValue = FieldValue.zext(8); + FieldValue = FieldValue.zext(CharWidth); } // Append the last element. Elements.push_back(llvm::ConstantInt::get(CGM.getLLVMContext(), FieldValue)); - NextFieldOffsetInBytes++; + ++NextFieldOffsetInChars; } -void ConstStructBuilder::AppendPadding(uint64_t NumBytes) { - if (!NumBytes) +void ConstStructBuilder::AppendPadding(CharUnits PadSize) { + if (PadSize.isZero()) return; const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); - if (NumBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumBytes); + if (PadSize > CharUnits::One()) + Ty = llvm::ArrayType::get(Ty, PadSize.getQuantity()); llvm::Constant *C = llvm::UndefValue::get(Ty); Elements.push_back(C); - assert(getAlignment(C) == 1 && "Padding must have 1 byte alignment!"); + assert(getAlignment(C) == CharUnits::One() && + "Padding must have 1 byte alignment!"); - NextFieldOffsetInBytes += getSizeInBytes(C); + NextFieldOffsetInChars += getSizeInChars(C); } -void ConstStructBuilder::AppendTailPadding(uint64_t RecordSize) { - assert(RecordSize % 8 == 0 && "Invalid record size!"); +void ConstStructBuilder::AppendTailPadding(CharUnits RecordSize) { + assert(NextFieldOffsetInChars <= RecordSize && + "Size mismatch!"); - uint64_t RecordSizeInBytes = RecordSize / 8; - assert(NextFieldOffsetInBytes <= RecordSizeInBytes && "Size mismatch!"); - - unsigned NumPadBytes = RecordSizeInBytes - NextFieldOffsetInBytes; - AppendPadding(NumPadBytes); + AppendPadding(RecordSize - NextFieldOffsetInChars); } void ConstStructBuilder::ConvertStructToPacked() { std::vector<llvm::Constant *> PackedElements; - uint64_t ElementOffsetInBytes = 0; + CharUnits ElementOffsetInChars = CharUnits::Zero(); for (unsigned i = 0, e = Elements.size(); i != e; ++i) { llvm::Constant *C = Elements[i]; - unsigned ElementAlign = - CGM.getTargetData().getABITypeAlignment(C->getType()); - uint64_t AlignedElementOffsetInBytes = - llvm::RoundUpToAlignment(ElementOffsetInBytes, ElementAlign); + CharUnits ElementAlign = CharUnits::fromQuantity( + CGM.getTargetData().getABITypeAlignment(C->getType())); + CharUnits AlignedElementOffsetInChars = + ElementOffsetInChars.RoundUpToAlignment(ElementAlign); - if (AlignedElementOffsetInBytes > ElementOffsetInBytes) { + if (AlignedElementOffsetInChars > ElementOffsetInChars) { // We need some padding. - uint64_t NumBytes = - AlignedElementOffsetInBytes - ElementOffsetInBytes; + CharUnits NumChars = + AlignedElementOffsetInChars - ElementOffsetInChars; const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext()); - if (NumBytes > 1) - Ty = llvm::ArrayType::get(Ty, NumBytes); + if (NumChars > CharUnits::One()) + Ty = llvm::ArrayType::get(Ty, NumChars.getQuantity()); llvm::Constant *Padding = llvm::UndefValue::get(Ty); PackedElements.push_back(Padding); - ElementOffsetInBytes += getSizeInBytes(Padding); + ElementOffsetInChars += getSizeInChars(Padding); } PackedElements.push_back(C); - ElementOffsetInBytes += getSizeInBytes(C); + ElementOffsetInChars += getSizeInChars(C); } - assert(ElementOffsetInBytes == NextFieldOffsetInBytes && + assert(ElementOffsetInChars == NextFieldOffsetInChars && "Packing the struct changed its size!"); Elements = PackedElements; - LLVMStructAlignment = 1; + LLVMStructAlignment = CharUnits::One(); Packed = true; } @@ -334,16 +344,31 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { unsigned FieldNo = 0; unsigned ElementNo = 0; + const FieldDecl *LastFD = 0; + bool IsMsStruct = RD->hasAttr<MsStructAttr>(); + for (RecordDecl::field_iterator Field = RD->field_begin(), FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are + // ignored: + if (CGM.getContext().ZeroBitfieldFollowsNonBitfield((*Field), LastFD) || + CGM.getContext().ZeroBitfieldFollowsBitfield((*Field), LastFD)) { + --FieldNo; + continue; + } + LastFD = (*Field); + } // If this is a union, skip all the fields that aren't being initialized. if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) continue; // Don't emit anonymous bitfields, they just affect layout. - if (Field->isBitField() && !Field->getIdentifier()) + if (Field->isBitField() && !Field->getIdentifier()) { + LastFD = (*Field); continue; + } // Get the initializer. A struct can include fields without initializers, // we just use explicit null values for them. @@ -368,9 +393,9 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { } } - uint64_t LayoutSizeInBytes = Layout.getSize().getQuantity(); + CharUnits LayoutSizeInChars = Layout.getSize(); - if (NextFieldOffsetInBytes > LayoutSizeInBytes) { + if (NextFieldOffsetInChars > LayoutSizeInChars) { // If the struct is bigger than the size of the record type, // we must have a flexible array member at the end. assert(RD->hasFlexibleArrayMember() && @@ -380,23 +405,23 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { return true; } - uint64_t LLVMSizeInBytes = llvm::RoundUpToAlignment(NextFieldOffsetInBytes, - LLVMStructAlignment); + CharUnits LLVMSizeInChars = + NextFieldOffsetInChars.RoundUpToAlignment(LLVMStructAlignment); // Check if we need to convert the struct to a packed struct. - if (NextFieldOffsetInBytes <= LayoutSizeInBytes && - LLVMSizeInBytes > LayoutSizeInBytes) { + if (NextFieldOffsetInChars <= LayoutSizeInChars && + LLVMSizeInChars > LayoutSizeInChars) { assert(!Packed && "Size mismatch!"); ConvertStructToPacked(); - assert(NextFieldOffsetInBytes <= LayoutSizeInBytes && + assert(NextFieldOffsetInChars <= LayoutSizeInChars && "Converting to packed did not help!"); } // Append tail padding if necessary. - AppendTailPadding(CGM.getContext().toBits(Layout.getSize())); + AppendTailPadding(LayoutSizeInChars); - assert(Layout.getSize().getQuantity() == NextFieldOffsetInBytes && + assert(LayoutSizeInChars == NextFieldOffsetInChars && "Tail padding mismatch!"); return true; @@ -413,9 +438,9 @@ llvm::Constant *ConstStructBuilder:: llvm::ConstantStruct::get(CGM.getLLVMContext(), Builder.Elements, Builder.Packed); - assert(llvm::RoundUpToAlignment(Builder.NextFieldOffsetInBytes, - Builder.getAlignment(Result)) == - Builder.getSizeInBytes(Result) && "Size mismatch!"); + assert(Builder.NextFieldOffsetInChars.RoundUpToAlignment( + Builder.getAlignment(Result)) == + Builder.getSizeInChars(Result) && "Size mismatch!"); return Result; } @@ -447,6 +472,10 @@ public: return Visit(PE->getSubExpr()); } + llvm::Constant *VisitGenericSelectionExpr(GenericSelectionExpr *GE) { + return Visit(GE->getResultExpr()); + } + llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return Visit(E->getInitializer()); } @@ -480,18 +509,17 @@ public: } llvm::Constant *VisitCastExpr(CastExpr* E) { + Expr *subExpr = E->getSubExpr(); + llvm::Constant *C = CGM.EmitConstantExpr(subExpr, subExpr->getType(), CGF); + if (!C) return 0; + + const llvm::Type *destType = ConvertType(E->getType()); + switch (E->getCastKind()) { case CK_ToUnion: { // GCC cast to union extension assert(E->getType()->isUnionType() && "Destination type is not union type!"); - const llvm::Type *Ty = ConvertType(E->getType()); - Expr *SubExpr = E->getSubExpr(); - - llvm::Constant *C = - CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF); - if (!C) - return 0; // Build a struct with the union sub-element as the first member, // and padded to the appropriate size @@ -500,7 +528,7 @@ public: Elts.push_back(C); Types.push_back(C->getType()); unsigned CurSize = CGM.getTargetData().getTypeAllocSize(C->getType()); - unsigned TotalSize = CGM.getTargetData().getTypeAllocSize(Ty); + unsigned TotalSize = CGM.getTargetData().getTypeAllocSize(destType); assert(CurSize <= TotalSize && "Union size mismatch!"); if (unsigned NumPadBytes = TotalSize - CurSize) { @@ -520,40 +548,103 @@ public: const MemberPointerType *MPT = E->getType()->getAs<MemberPointerType>(); return CGM.getCXXABI().EmitNullMemberPointer(MPT); } - - case CK_BaseToDerivedMemberPointer: { - Expr *SubExpr = E->getSubExpr(); - llvm::Constant *C = - CGM.EmitConstantExpr(SubExpr, SubExpr->getType(), CGF); - if (!C) return 0; + case CK_DerivedToBaseMemberPointer: + case CK_BaseToDerivedMemberPointer: return CGM.getCXXABI().EmitMemberPointerConversion(C, E); - } - case CK_BitCast: - // This must be a member function pointer cast. - return Visit(E->getSubExpr()); - - default: { - // FIXME: This should be handled by the CK_NoOp cast kind. - // Explicit and implicit no-op casts - QualType Ty = E->getType(), SubTy = E->getSubExpr()->getType(); - if (CGM.getContext().hasSameUnqualifiedType(Ty, SubTy)) - return Visit(E->getSubExpr()); - - // Handle integer->integer casts for address-of-label differences. - if (Ty->isIntegerType() && SubTy->isIntegerType() && - CGF) { - llvm::Value *Src = Visit(E->getSubExpr()); - if (Src == 0) return 0; - - // Use EmitScalarConversion to perform the conversion. - return cast<llvm::Constant>(CGF->EmitScalarConversion(Src, SubTy, Ty)); - } - + case CK_LValueToRValue: + case CK_NoOp: + return C; + + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_LValueBitCast: + case CK_BitCast: + if (C->getType() == destType) return C; + return llvm::ConstantExpr::getBitCast(C, destType); + + case CK_Dependent: llvm_unreachable("saw dependent cast!"); + + // These will never be supported. + case CK_ObjCObjectLValueCast: + case CK_GetObjCProperty: + case CK_ToVoid: + case CK_Dynamic: return 0; + + // These might need to be supported for constexpr. + case CK_UserDefinedConversion: + case CK_ConstructorConversion: + return 0; + + // These should eventually be supported. + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + case CK_BaseToDerived: + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_MemberPointerToBoolean: + case CK_VectorSplat: + case CK_FloatingRealToComplex: + case CK_FloatingComplexToReal: + case CK_FloatingComplexToBoolean: + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralRealToComplex: + case CK_IntegralComplexToReal: + case CK_IntegralComplexToBoolean: + case CK_IntegralComplexCast: + case CK_IntegralComplexToFloatingComplex: + return 0; + + case CK_PointerToIntegral: + if (!E->getType()->isBooleanType()) + return llvm::ConstantExpr::getPtrToInt(C, destType); + // fallthrough + + case CK_PointerToBoolean: + return llvm::ConstantExpr::getICmp(llvm::CmpInst::ICMP_EQ, C, + llvm::ConstantPointerNull::get(cast<llvm::PointerType>(C->getType()))); + + case CK_NullToPointer: + return llvm::ConstantPointerNull::get(cast<llvm::PointerType>(destType)); + + case CK_IntegralCast: { + bool isSigned = subExpr->getType()->isSignedIntegerType(); + return llvm::ConstantExpr::getIntegerCast(C, destType, isSigned); + } + + case CK_IntegralToPointer: { + bool isSigned = subExpr->getType()->isSignedIntegerType(); + C = llvm::ConstantExpr::getIntegerCast(C, CGM.IntPtrTy, isSigned); + return llvm::ConstantExpr::getIntToPtr(C, destType); } + + case CK_IntegralToBoolean: + return llvm::ConstantExpr::getICmp(llvm::CmpInst::ICMP_EQ, C, + llvm::Constant::getNullValue(C->getType())); + + case CK_IntegralToFloating: + if (subExpr->getType()->isSignedIntegerType()) + return llvm::ConstantExpr::getSIToFP(C, destType); + else + return llvm::ConstantExpr::getUIToFP(C, destType); + + case CK_FloatingToIntegral: + if (E->getType()->isSignedIntegerType()) + return llvm::ConstantExpr::getFPToSI(C, destType); + else + return llvm::ConstantExpr::getFPToUI(C, destType); + + case CK_FloatingToBoolean: + return llvm::ConstantExpr::getFCmp(llvm::CmpInst::FCMP_UNE, C, + llvm::Constant::getNullValue(C->getType())); + + case CK_FloatingCast: + return llvm::ConstantExpr::getFPCast(C, destType); } + llvm_unreachable("Invalid CastKind"); } llvm::Constant *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { @@ -562,7 +653,7 @@ public: llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) { unsigned NumInitElements = ILE->getNumInits(); - if (NumInitElements == 1 && + if (NumInitElements == 1 && ILE->getType() == ILE->getInit(0)->getType() && (isa<StringLiteral>(ILE->getInit(0)) || isa<ObjCEncodeExpr>(ILE->getInit(0)))) return Visit(ILE->getInit(0)); @@ -591,8 +682,16 @@ public: // Initialize remaining array elements. // FIXME: This doesn't handle member pointers correctly! + llvm::Constant *fillC; + if (Expr *filler = ILE->getArrayFiller()) + fillC = CGM.EmitConstantExpr(filler, filler->getType(), CGF); + else + fillC = llvm::Constant::getNullValue(ElemTy); + if (!fillC) + return 0; + RewriteType |= (fillC->getType() != ElemTy); for (; i < NumElements; ++i) - Elts.push_back(llvm::Constant::getNullValue(ElemTy)); + Elts.push_back(fillC); if (RewriteType) { // FIXME: Try to avoid packing the array @@ -730,7 +829,7 @@ public: E->getType().isConstant(CGM.getContext()), llvm::GlobalValue::InternalLinkage, C, ".compoundliteral", 0, false, - E->getType().getAddressSpace()); + CGM.getContext().getTargetAddressSpace(E->getType())); return C; } case Expr::DeclRefExprClass: { @@ -907,12 +1006,29 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E, llvm::SmallVector<llvm::Constant *, 4> Inits; unsigned NumElts = Result.Val.getVectorLength(); - for (unsigned i = 0; i != NumElts; ++i) { - APValue &Elt = Result.Val.getVectorElt(i); - if (Elt.isInt()) - Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt())); - else - Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat())); + if (Context.getLangOptions().AltiVec && + isa<CastExpr>(E) && + cast<CastExpr>(E)->getCastKind() == CK_VectorSplat) { + // AltiVec vector initialization with a single literal + APValue &Elt = Result.Val.getVectorElt(0); + + llvm::Constant* InitValue = Elt.isInt() + ? cast<llvm::Constant> + (llvm::ConstantInt::get(VMContext, Elt.getInt())) + : cast<llvm::Constant> + (llvm::ConstantFP::get(VMContext, Elt.getFloat())); + + for (unsigned i = 0; i != NumElts; ++i) + Inits.push_back(InitValue); + + } else { + for (unsigned i = 0; i != NumElts; ++i) { + APValue &Elt = Result.Val.getVectorElt(i); + if (Elt.isInt()) + Inits.push_back(llvm::ConstantInt::get(VMContext, Elt.getInt())); + else + Inits.push_back(llvm::ConstantFP::get(VMContext, Elt.getFloat())); + } } return llvm::ConstantVector::get(Inits); } @@ -963,7 +1079,8 @@ static void FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T, std::vector<llvm::Constant *> &Elements, uint64_t StartOffset) { - assert(StartOffset % 8 == 0 && "StartOffset not byte aligned!"); + assert(StartOffset % CGM.getContext().getCharWidth() == 0 && + "StartOffset not byte aligned!"); if (CGM.getTypes().isZeroInitializable(T)) return; @@ -1022,8 +1139,8 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T, assert(!T->getAs<MemberPointerType>()->getPointeeType()->isFunctionType() && "Should only see pointers to data members here!"); - uint64_t StartIndex = StartOffset / 8; - uint64_t EndIndex = StartIndex + CGM.getContext().getTypeSize(T) / 8; + CharUnits StartIndex = CGM.getContext().toCharUnitsFromBits(StartOffset); + CharUnits EndIndex = StartIndex + CGM.getContext().getTypeSizeInChars(T); // FIXME: hardcodes Itanium member pointer representation! llvm::Constant *NegativeOne = @@ -1031,8 +1148,8 @@ FillInNullDataMemberPointers(CodeGenModule &CGM, QualType T, -1ULL, /*isSigned*/true); // Fill in the null data member pointer. - for (uint64_t I = StartIndex; I != EndIndex; ++I) - Elements[I] = NegativeOne; + for (CharUnits I = StartIndex; I != EndIndex; ++I) + Elements[I.getQuantity()] = NegativeOne; } } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp index 3e1debd..6bcc425 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGExprScalar.cpp @@ -140,9 +140,7 @@ public: } } - const llvm::IntegerType *Ty = cast<llvm::IntegerType>(V->getType()); - Value *Zero = llvm::ConstantInt::get(Ty, 0); - return Builder.CreateICmpNE(V, Zero, "tobool"); + return Builder.CreateIsNotNull(V, "tobool"); } //===--------------------------------------------------------------------===// @@ -163,10 +161,13 @@ public: Value *VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr()); } + Value *VisitGenericSelectionExpr(GenericSelectionExpr *GE) { + return Visit(GE->getResultExpr()); + } // Leaves. Value *VisitIntegerLiteral(const IntegerLiteral *E) { - return llvm::ConstantInt::get(VMContext, E->getValue()); + return Builder.getInt(E->getValue()); } Value *VisitFloatingLiteral(const FloatingLiteral *E) { return llvm::ConstantFP::get(VMContext, E->getValue()); @@ -184,15 +185,14 @@ public: return EmitNullValue(E->getType()); } Value *VisitOffsetOfExpr(OffsetOfExpr *E); - Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); + Value *VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); Value *VisitAddrLabelExpr(const AddrLabelExpr *E) { llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel()); return Builder.CreateBitCast(V, ConvertType(E->getType())); } Value *VisitSizeOfPackExpr(SizeOfPackExpr *E) { - return llvm::ConstantInt::get(ConvertType(E->getType()), - E->getPackLength()); + return llvm::ConstantInt::get(ConvertType(E->getType()),E->getPackLength()); } Value *VisitOpaqueValueExpr(OpaqueValueExpr *E) { @@ -212,13 +212,12 @@ public: assert(!Result.HasSideEffects && "Constant declref with side-effect?!"); llvm::Constant *C; - if (Result.Val.isInt()) { - C = llvm::ConstantInt::get(VMContext, Result.Val.getInt()); - } else if (Result.Val.isFloat()) { + if (Result.Val.isInt()) + C = Builder.getInt(Result.Val.getInt()); + else if (Result.Val.isFloat()) C = llvm::ConstantFP::get(VMContext, Result.Val.getFloat()); - } else { + else return EmitLoadOfLValue(E); - } // Make sure we emit a debug reference to the global variable. if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) { @@ -245,6 +244,9 @@ public: return EmitLoadOfLValue(E); } Value *VisitObjCMessageExpr(ObjCMessageExpr *E) { + if (E->getMethodDecl() && + E->getMethodDecl()->getResultType()->isReferenceType()) + return EmitLoadOfLValue(E); return CGF.EmitObjCMessageExpr(E).getScalarVal(); } @@ -358,13 +360,21 @@ public: return 0; } Value *VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { - return llvm::ConstantInt::get(Builder.getInt1Ty(), E->getValue()); + return Builder.getInt1(E->getValue()); } Value *VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *E) { return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue()); } + Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) { + return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue()); + } + + Value *VisitExpressionTraitExpr(const ExpressionTraitExpr *E) { + return llvm::ConstantInt::get(Builder.getInt1Ty(), E->getValue()); + } + Value *VisitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *E) { // C++ [expr.pseudo]p1: // The result shall only be used as the operand for the function call @@ -385,7 +395,7 @@ public: } Value *VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { - return llvm::ConstantInt::get(Builder.getInt1Ty(), E->getValue()); + return Builder.getInt1(E->getValue()); } // Binary Operators. @@ -579,14 +589,14 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, // Insert the element in element zero of an undef vector llvm::Value *UnV = llvm::UndefValue::get(DstTy); - llvm::Value *Idx = llvm::ConstantInt::get(CGF.Int32Ty, 0); + llvm::Value *Idx = Builder.getInt32(0); UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp"); // Splat the element across to all elements llvm::SmallVector<llvm::Constant*, 16> Args; unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements(); for (unsigned i = 0; i != NumElements; ++i) - Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 0)); + Args.push_back(Builder.getInt32(0)); llvm::Constant *Mask = llvm::ConstantVector::get(Args); llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat"); @@ -683,8 +693,8 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { // Shuffle LHS & RHS into one input vector. llvm::SmallVector<llvm::Constant*, 32> concat; for (unsigned i = 0; i != LHSElts; ++i) { - concat.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 2*i)); - concat.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 2*i+1)); + concat.push_back(Builder.getInt32(2*i)); + concat.push_back(Builder.getInt32(2*i+1)); } Value* CV = llvm::ConstantVector::get(concat); @@ -726,18 +736,16 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { MTy->getNumElements()); Value* NewV = llvm::UndefValue::get(RTy); for (unsigned i = 0, e = MTy->getNumElements(); i != e; ++i) { - Value *Indx = llvm::ConstantInt::get(CGF.Int32Ty, i); + Value *Indx = Builder.getInt32(i); Indx = Builder.CreateExtractElement(Mask, Indx, "shuf_idx"); Indx = Builder.CreateZExt(Indx, CGF.Int32Ty, "idx_zext"); // Handle vec3 special since the index will be off by one for the RHS. if ((LHSElts == 6) && (E->getNumSubExprs() == 3)) { Value *cmpIndx, *newIndx; - cmpIndx = Builder.CreateICmpUGT(Indx, - llvm::ConstantInt::get(CGF.Int32Ty, 3), + cmpIndx = Builder.CreateICmpUGT(Indx, Builder.getInt32(3), "cmp_shuf_idx"); - newIndx = Builder.CreateSub(Indx, llvm::ConstantInt::get(CGF.Int32Ty,1), - "shuf_idx_adj"); + newIndx = Builder.CreateSub(Indx, Builder.getInt32(1), "shuf_idx_adj"); Indx = Builder.CreateSelect(cmpIndx, newIndx, Indx, "sel_shuf_idx"); } Value *VExt = Builder.CreateExtractElement(LHS, Indx, "shuf_elt"); @@ -775,7 +783,7 @@ Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) { CGF.EmitScalarExpr(E->getBase()); else EmitLValue(E->getBase()); - return llvm::ConstantInt::get(VMContext, Result.Val.getInt()); + return Builder.getInt(Result.Val.getInt()); } // Emit debug info for aggregate now, if it was delayed to reduce @@ -875,8 +883,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { llvm::ShuffleVectorInst *SVV = cast<llvm::ShuffleVectorInst>(V); for (unsigned j = 0; j != CurIdx; ++j) Args.push_back(getMaskElt(SVV, j, 0, CGF.Int32Ty)); - Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty, - ResElts + C->getZExtValue())); + Args.push_back(Builder.getInt32(ResElts + C->getZExtValue())); for (unsigned j = CurIdx + 1; j != ResElts; ++j) Args.push_back(llvm::UndefValue::get(CGF.Int32Ty)); @@ -892,8 +899,8 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { } } } - Value *Idx = llvm::ConstantInt::get(CGF.Int32Ty, CurIdx); - V = Builder.CreateInsertElement(V, Init, Idx, "vecinit"); + V = Builder.CreateInsertElement(V, Init, Builder.getInt32(CurIdx), + "vecinit"); VIsUndefShuffle = false; ++CurIdx; continue; @@ -918,7 +925,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { Args.push_back(getMaskElt(cast<llvm::ShuffleVectorInst>(V), j, 0, CGF.Int32Ty)); } else { - Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty, j)); + Args.push_back(Builder.getInt32(j)); } } for (unsigned j = 0, je = InitElts; j != je; ++j) @@ -937,7 +944,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { // to the vector initializer into V. if (Args.empty()) { for (unsigned j = 0; j != InitElts; ++j) - Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty, j)); + Args.push_back(Builder.getInt32(j)); for (unsigned j = InitElts; j != ResElts; ++j) Args.push_back(llvm::UndefValue::get(CGF.Int32Ty)); llvm::Constant *Mask = llvm::ConstantVector::get(Args); @@ -946,9 +953,9 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { Args.clear(); for (unsigned j = 0; j != CurIdx; ++j) - Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty, j)); + Args.push_back(Builder.getInt32(j)); for (unsigned j = 0; j != InitElts; ++j) - Args.push_back(llvm::ConstantInt::get(CGF.Int32Ty, j+Offset)); + Args.push_back(Builder.getInt32(j+Offset)); for (unsigned j = CurIdx + InitElts; j != ResElts; ++j) Args.push_back(llvm::UndefValue::get(CGF.Int32Ty)); } @@ -969,7 +976,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) { // Emit remaining default initializers for (/* Do not initialize i*/; CurIdx < ResElts; ++CurIdx) { - Value *Idx = llvm::ConstantInt::get(CGF.Int32Ty, CurIdx); + Value *Idx = Builder.getInt32(CurIdx); llvm::Value *Init = llvm::Constant::getNullValue(EltTy); V = Builder.CreateInsertElement(V, Init, Idx, "vecinit"); } @@ -1123,7 +1130,7 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { RValue RV = CGF.EmitLoadOfLValue(CGF.EmitLValue(E), E->getType()); return RV.getScalarVal(); } - + case CK_LValueToRValue: assert(CGF.getContext().hasSameUnqualifiedType(E->getType(), DestTy)); assert(E->isGLValue() && "lvalue-to-rvalue applied to r-value!"); @@ -1160,13 +1167,13 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) { // Insert the element in element zero of an undef vector llvm::Value *UnV = llvm::UndefValue::get(DstTy); - llvm::Value *Idx = llvm::ConstantInt::get(CGF.Int32Ty, 0); + llvm::Value *Idx = Builder.getInt32(0); UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp"); // Splat the element across to all elements llvm::SmallVector<llvm::Constant*, 16> Args; unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements(); - llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Int32Ty, 0); + llvm::Constant *Zero = Builder.getInt32(0); for (unsigned i = 0; i < NumElements; i++) Args.push_back(Zero); @@ -1218,10 +1225,8 @@ Value *ScalarExprEmitter::VisitStmtExpr(const StmtExpr *E) { } Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) { - llvm::Value *V = CGF.GetAddrOfBlockDecl(E); - if (E->getType().isObjCGCWeak()) - return CGF.CGM.getObjCRuntime().EmitObjCWeakRead(CGF, V); - return CGF.EmitLoadOfScalar(V, false, 0, E->getType()); + LValue LV = CGF.EmitBlockDeclRefLValue(E); + return CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal(); } //===----------------------------------------------------------------------===// @@ -1278,10 +1283,12 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount); - if (type->isSignedIntegerType()) + // Note that signed integer inc/dec with width less than int can't + // overflow because of promotion rules; we're just eliding a few steps here. + if (type->isSignedIntegerType() && + value->getType()->getPrimitiveSizeInBits() >= + CGF.CGM.IntTy->getBitWidth()) value = EmitAddConsiderOverflowBehavior(E, value, amt, isInc); - - // Unsigned integer inc is always two's complement. else value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); @@ -1295,21 +1302,30 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, CGF.GetVLASize(CGF.getContext().getAsVariableArrayType(type)); value = CGF.EmitCastToVoidPtr(value); if (!isInc) vlaSize = Builder.CreateNSWNeg(vlaSize, "vla.negsize"); - value = Builder.CreateInBoundsGEP(value, vlaSize, "vla.inc"); + if (CGF.getContext().getLangOptions().isSignedOverflowDefined()) + value = Builder.CreateGEP(value, vlaSize, "vla.inc"); + else + value = Builder.CreateInBoundsGEP(value, vlaSize, "vla.inc"); value = Builder.CreateBitCast(value, input->getType()); // Arithmetic on function pointers (!) is just +-1. } else if (type->isFunctionType()) { - llvm::Value *amt = llvm::ConstantInt::get(CGF.Int32Ty, amount); + llvm::Value *amt = Builder.getInt32(amount); value = CGF.EmitCastToVoidPtr(value); - value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr"); + if (CGF.getContext().getLangOptions().isSignedOverflowDefined()) + value = Builder.CreateGEP(value, amt, "incdec.funcptr"); + else + value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr"); value = Builder.CreateBitCast(value, input->getType()); // For everything else, we can just do a simple increment. } else { - llvm::Value *amt = llvm::ConstantInt::get(CGF.Int32Ty, amount); - value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr"); + llvm::Value *amt = Builder.getInt32(amount); + if (CGF.getContext().getLangOptions().isSignedOverflowDefined()) + value = Builder.CreateGEP(value, amt, "incdec.ptr"); + else + value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr"); } // Vector increment/decrement. @@ -1357,7 +1373,10 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, llvm::Value *sizeValue = llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity()); - value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr"); + if (CGF.getContext().getLangOptions().isSignedOverflowDefined()) + value = Builder.CreateGEP(value, sizeValue, "incdec.objptr"); + else + value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr"); value = Builder.CreateBitCast(value, input->getType()); } @@ -1413,7 +1432,7 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { // Try folding the offsetof to a constant. Expr::EvalResult EvalResult; if (E->Evaluate(EvalResult, CGF.getContext())) - return llvm::ConstantInt::get(VMContext, EvalResult.Val.getInt()); + return Builder.getInt(EvalResult.Val.getInt()); // Loop over the components of the offsetof to compute the value. unsigned n = E->getNumComponents(); @@ -1499,12 +1518,13 @@ Value *ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *E) { return Result; } -/// VisitSizeOfAlignOfExpr - Return the size or alignment of the type of +/// VisitUnaryExprOrTypeTraitExpr - Return the size or alignment of the type of /// argument of the sizeof expression as an integer. Value * -ScalarExprEmitter::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { +ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr( + const UnaryExprOrTypeTraitExpr *E) { QualType TypeToSize = E->getTypeOfArgument(); - if (E->isSizeOf()) { + if (E->getKind() == UETT_SizeOf) { if (const VariableArrayType *VAT = CGF.getContext().getAsVariableArrayType(TypeToSize)) { if (E->isArgumentType()) { @@ -1524,7 +1544,7 @@ ScalarExprEmitter::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { // folding logic so we don't have to duplicate it here. Expr::EvalResult Result; E->Evaluate(Result, CGF.getContext()); - return llvm::ConstantInt::get(VMContext, Result.Val.getInt()); + return Builder.getInt(Result.Val.getInt()); } Value *ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *E) { @@ -1664,8 +1684,7 @@ void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( if (Ops.Ty->hasSignedIntegerRepresentation()) { llvm::Value *IntMin = - llvm::ConstantInt::get(VMContext, - llvm::APInt::getSignedMinValue(Ty->getBitWidth())); + Builder.getInt(llvm::APInt::getSignedMinValue(Ty->getBitWidth())); llvm::Value *NegOne = llvm::ConstantInt::get(Ty, -1ULL); llvm::Value *Cond1 = Builder.CreateICmpEQ(Ops.RHS, Zero); @@ -1715,7 +1734,7 @@ Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, false); } - if (Ops.Ty->isUnsignedIntegerType()) + if (Ops.Ty->hasUnsignedIntegerRepresentation()) return Builder.CreateURem(Ops.LHS, Ops.RHS, "rem"); else return Builder.CreateSRem(Ops.LHS, Ops.RHS, "rem"); @@ -1801,8 +1820,7 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { Builder.CreateBr(continueBB); Builder.SetInsertPoint(continueBB); - llvm::PHINode *phi = Builder.CreatePHI(opTy); - phi->reserveOperandSpace(2); + llvm::PHINode *phi = Builder.CreatePHI(opTy, 2); phi->addIncoming(result, initialBB); phi->addIncoming(handlerResult, overflowBB); @@ -1889,6 +1907,8 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) { return Builder.CreateBitCast(Res, Ptr->getType()); } + if (CGF.getContext().getLangOptions().isSignedOverflowDefined()) + return Builder.CreateGEP(Ptr, Idx, "add.ptr"); return Builder.CreateInBoundsGEP(Ptr, Idx, "add.ptr"); } @@ -1964,38 +1984,39 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) { return Builder.CreateBitCast(Res, Ops.LHS->getType()); } + if (CGF.getContext().getLangOptions().isSignedOverflowDefined()) + return Builder.CreateGEP(Ops.LHS, Idx, "sub.ptr"); return Builder.CreateInBoundsGEP(Ops.LHS, Idx, "sub.ptr"); - } else { - // pointer - pointer - Value *LHS = Ops.LHS; - Value *RHS = Ops.RHS; - - CharUnits ElementSize; - - // Handle GCC extension for pointer arithmetic on void* and function pointer - // types. - if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) { - ElementSize = CharUnits::One(); - } else { - ElementSize = CGF.getContext().getTypeSizeInChars(LHSElementType); - } - - const llvm::Type *ResultType = ConvertType(Ops.Ty); - LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast"); - RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast"); - Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub"); + } + + // pointer - pointer + Value *LHS = Ops.LHS; + Value *RHS = Ops.RHS; - // Optimize out the shift for element size of 1. - if (ElementSize.isOne()) - return BytesBetween; + CharUnits ElementSize; - // Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since - // pointer difference in C is only defined in the case where both operands - // are pointing to elements of an array. - Value *BytesPerElt = - llvm::ConstantInt::get(ResultType, ElementSize.getQuantity()); - return Builder.CreateExactSDiv(BytesBetween, BytesPerElt, "sub.ptr.div"); - } + // Handle GCC extension for pointer arithmetic on void* and function pointer + // types. + if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) + ElementSize = CharUnits::One(); + else + ElementSize = CGF.getContext().getTypeSizeInChars(LHSElementType); + + const llvm::Type *ResultType = ConvertType(Ops.Ty); + LHS = Builder.CreatePtrToInt(LHS, ResultType, "sub.ptr.lhs.cast"); + RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast"); + Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub"); + + // Optimize out the shift for element size of 1. + if (ElementSize.isOne()) + return BytesBetween; + + // Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since + // pointer difference in C is only defined in the case where both operands + // are pointing to elements of an array. + Value *BytesPerElt = + llvm::ConstantInt::get(ResultType, ElementSize.getQuantity()); + return Builder.CreateExactSDiv(BytesBetween, BytesPerElt, "sub.ptr.div"); } Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { @@ -2100,7 +2121,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, // If AltiVec, the comparison results in a numeric type, so we use // intrinsics comparing vectors and giving 0 or 1 as a result - if (LHSTy->isVectorType() && CGF.getContext().getLangOptions().AltiVec) { + if (LHSTy->isVectorType() && !E->getType()->isVectorType()) { // constants for mapping CR6 register bits to predicate result enum { CR6_EQ=0, CR6_EQ_REV, CR6_LT, CR6_LT_REV } CR6; @@ -2157,7 +2178,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, break; } - Value *CR6Param = llvm::ConstantInt::get(CGF.Int32Ty, CR6); + Value *CR6Param = Builder.getInt32(CR6); llvm::Function *F = CGF.CGM.getIntrinsic(ID); Result = Builder.CreateCall3(F, CR6Param, FirstVecArg, SecondVecArg, ""); return EmitScalarConversion(Result, CGF.getContext().BoolTy, E->getType()); @@ -2257,8 +2278,9 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { // If we have 0 && RHS, see if we can elide RHS, if so, just return 0. // If we have 1 && X, just emit X without inserting the control flow. - if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getLHS())) { - if (Cond == 1) { // If we have 1 && X, just emit X. + bool LHSCondVal; + if (CGF.ConstantFoldsToSimpleInteger(E->getLHS(), LHSCondVal)) { + if (LHSCondVal) { // If we have 1 && X, just emit X. Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); // ZExt result to int or bool. return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "land.ext"); @@ -2280,9 +2302,8 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { // Any edges into the ContBlock are now from an (indeterminate number of) // edges from this first condition. All of these values will be false. Start // setting up the PHI node in the Cont Block for this. - llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), + llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), 2, "", ContBlock); - PN->reserveOperandSpace(2); // Normal case, two inputs. for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock); PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI); @@ -2297,6 +2318,9 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) { // Emit an unconditional branch from this block to ContBlock. Insert an entry // into the phi node for the edge with the value of RHSCond. + if (CGF.getDebugInfo()) + // There is no need to emit line number for unconditional branch. + Builder.SetCurrentDebugLocation(llvm::DebugLoc()); CGF.EmitBlock(ContBlock); PN->addIncoming(RHSCond, RHSBlock); @@ -2309,8 +2333,9 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { // If we have 1 || RHS, see if we can elide RHS, if so, just return 1. // If we have 0 || X, just emit X without inserting the control flow. - if (int Cond = CGF.ConstantFoldsToSimpleInteger(E->getLHS())) { - if (Cond == -1) { // If we have 0 || X, just emit X. + bool LHSCondVal; + if (CGF.ConstantFoldsToSimpleInteger(E->getLHS(), LHSCondVal)) { + if (!LHSCondVal) { // If we have 0 || X, just emit X. Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS()); // ZExt result to int or bool. return Builder.CreateZExtOrBitCast(RHSCond, ResTy, "lor.ext"); @@ -2332,9 +2357,8 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) { // Any edges into the ContBlock are now from an (indeterminate number of) // edges from this first condition. All of these values will be true. Start // setting up the PHI node in the Cont Block for this. - llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), + llvm::PHINode *PN = llvm::PHINode::Create(llvm::Type::getInt1Ty(VMContext), 2, "", ContBlock); - PN->reserveOperandSpace(2); // Normal case, two inputs. for (llvm::pred_iterator PI = pred_begin(ContBlock), PE = pred_end(ContBlock); PI != PE; ++PI) PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI); @@ -2375,12 +2399,10 @@ Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) { /// flow into selects in some cases. static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E, CodeGenFunction &CGF) { - if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) - return isCheapEnoughToEvaluateUnconditionally(PE->getSubExpr(), CGF); + E = E->IgnoreParens(); - // TODO: Allow anything we can constant fold to an integer or fp constant. - if (isa<IntegerLiteral>(E) || isa<CharacterLiteral>(E) || - isa<FloatingLiteral>(E)) + // Anything that is an integer or floating point constant is fine. + if (E->isConstantInitializer(CGF.getContext(), false)) return true; // Non-volatile automatic variables too, to get "cond ? X : Y" where @@ -2409,9 +2431,10 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { // If the condition constant folds and can be elided, try to avoid emitting // the condition and the dead arm. - if (int Cond = CGF.ConstantFoldsToSimpleInteger(condExpr)){ + bool CondExprBool; + if (CGF.ConstantFoldsToSimpleInteger(condExpr, CondExprBool)) { Expr *live = lhsExpr, *dead = rhsExpr; - if (Cond == -1) std::swap(live, dead); + if (!CondExprBool) std::swap(live, dead); // If the dead side doesn't have labels we need, and if the Live side isn't // the gnu missing ?: extension (which we could handle, but don't bother @@ -2436,7 +2459,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { std::vector<llvm::Constant*> Zvals; for (unsigned i = 0; i < numElem; ++i) - Zvals.push_back(llvm::ConstantInt::get(elemType,0)); + Zvals.push_back(llvm::ConstantInt::get(elemType, 0)); llvm::Value *zeroVec = llvm::ConstantVector::get(Zvals); llvm::Value *TestMSB = Builder.CreateICmpSLT(CondV, zeroVec); @@ -2507,8 +2530,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { return LHS; // Create a PHI node for the real part. - llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), "cond"); - PN->reserveOperandSpace(2); + llvm::PHINode *PN = Builder.CreatePHI(LHS->getType(), 2, "cond"); PN->addIncoming(LHS, LHSBlock); PN->addIncoming(RHS, RHSBlock); return PN; @@ -2544,8 +2566,13 @@ Value *CodeGenFunction::EmitScalarExpr(const Expr *E, bool IgnoreResultAssign) { assert(E && !hasAggregateLLVMType(E->getType()) && "Invalid scalar expression to emit"); - return ScalarExprEmitter(*this, IgnoreResultAssign) + if (isa<CXXDefaultArgExpr>(E)) + disableDebugInfo(); + Value *V = ScalarExprEmitter(*this, IgnoreResultAssign) .Visit(const_cast<Expr*>(E)); + if (isa<CXXDefaultArgExpr>(E)) + enableDebugInfo(); + return V; } /// EmitScalarConversion - Emit a conversion from the specified type to the diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp index 5d34907..5b0d41e 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjC.cpp @@ -119,28 +119,26 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, /// CodeGenFunction. void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) { - FunctionArgList Args; + FunctionArgList args; // Check if we should generate debug info for this method. - if (CGM.getDebugInfo() && !OMD->hasAttr<NoDebugAttr>()) - DebugInfo = CGM.getDebugInfo(); + if (CGM.getModuleDebugInfo() && !OMD->hasAttr<NoDebugAttr>()) + DebugInfo = CGM.getModuleDebugInfo(); llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD); const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(OMD); CGM.SetInternalFunctionAttributes(OMD, Fn, FI); - Args.push_back(std::make_pair(OMD->getSelfDecl(), - OMD->getSelfDecl()->getType())); - Args.push_back(std::make_pair(OMD->getCmdDecl(), - OMD->getCmdDecl()->getType())); + args.push_back(OMD->getSelfDecl()); + args.push_back(OMD->getCmdDecl()); for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), E = OMD->param_end(); PI != E; ++PI) - Args.push_back(std::make_pair(*PI, (*PI)->getType())); + args.push_back(*PI); CurGD = OMD; - StartFunction(OMD, OMD->getResultType(), Fn, Args, OMD->getLocStart()); + StartFunction(OMD, OMD->getResultType(), Fn, FI, args, OMD->getLocStart()); } void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar, @@ -155,27 +153,24 @@ void CodeGenFunction::GenerateObjCGetterBody(ObjCIvarDecl *Ivar, CallArgList Args; RValue RV = RValue::get(Builder.CreateBitCast(ReturnValue, Types.ConvertType(getContext().VoidPtrTy))); - Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + Args.add(RV, getContext().VoidPtrTy); RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), Types.ConvertType(getContext().VoidPtrTy))); - Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + Args.add(RV, getContext().VoidPtrTy); // sizeof (Type of Ivar) CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType()); llvm::Value *SizeVal = llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size.getQuantity()); - Args.push_back(std::make_pair(RValue::get(SizeVal), - getContext().LongTy)); + Args.add(RValue::get(SizeVal), getContext().LongTy); llvm::Value *isAtomic = llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), IsAtomic ? 1 : 0); - Args.push_back(std::make_pair(RValue::get(isAtomic), - getContext().BoolTy)); + Args.add(RValue::get(isAtomic), getContext().BoolTy); llvm::Value *hasStrong = llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), IsStrong ? 1 : 0); - Args.push_back(std::make_pair(RValue::get(hasStrong), - getContext().BoolTy)); + Args.add(RValue::get(hasStrong), getContext().BoolTy); EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, FunctionType::ExtInfo()), GetCopyStructFn, ReturnValueSlot(), Args); @@ -236,10 +231,10 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, llvm::Value *True = llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1); CallArgList Args; - Args.push_back(std::make_pair(RValue::get(SelfAsId), IdTy)); - Args.push_back(std::make_pair(RValue::get(CmdVal), Cmd->getType())); - Args.push_back(std::make_pair(RValue::get(Offset), getContext().LongTy)); - Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy)); + Args.add(RValue::get(SelfAsId), IdTy); + Args.add(RValue::get(CmdVal), Cmd->getType()); + Args.add(RValue::get(Offset), getContext().getPointerDiffType()); + Args.add(RValue::get(True), getContext().BoolTy); // FIXME: We shouldn't need to get the function info here, the // runtime already should have computed it to build the function. RValue RV = EmitCall(Types.getFunctionInfo(PD->getType(), Args, @@ -263,6 +258,22 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, CGM.getObjCRuntime().GetGetStructFunction()) { GenerateObjCGetterBody(Ivar, true, false); } + else if (IsAtomic && + (IVART->isScalarType() && !IVART->isRealFloatingType()) && + Triple.getArch() == llvm::Triple::x86 && + (getContext().getTypeSizeInChars(IVART) + > CharUnits::fromQuantity(4)) && + CGM.getObjCRuntime().GetGetStructFunction()) { + GenerateObjCGetterBody(Ivar, true, false); + } + else if (IsAtomic && + (IVART->isScalarType() && !IVART->isRealFloatingType()) && + Triple.getArch() == llvm::Triple::x86_64 && + (getContext().getTypeSizeInChars(IVART) + > CharUnits::fromQuantity(8)) && + CGM.getObjCRuntime().GetGetStructFunction()) { + GenerateObjCGetterBody(Ivar, true, false); + } else if (IVART->isAnyComplexType()) { LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); @@ -272,18 +283,36 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, } else if (hasAggregateLLVMType(IVART)) { bool IsStrong = false; - if ((IsAtomic || (IsStrong = IvarTypeWithAggrGCObjects(IVART))) + if ((IsStrong = IvarTypeWithAggrGCObjects(IVART)) && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect && CGM.getObjCRuntime().GetGetStructFunction()) { GenerateObjCGetterBody(Ivar, IsAtomic, IsStrong); } else { - if (PID->getGetterCXXConstructor()) { + const CXXRecordDecl *classDecl = IVART->getAsCXXRecordDecl(); + + if (PID->getGetterCXXConstructor() && + classDecl && !classDecl->hasTrivialConstructor()) { ReturnStmt *Stmt = new (getContext()) ReturnStmt(SourceLocation(), PID->getGetterCXXConstructor(), 0); EmitReturnStmt(*Stmt); + } else if (IsAtomic && + !IVART->isAnyComplexType() && + Triple.getArch() == llvm::Triple::x86 && + (getContext().getTypeSizeInChars(IVART) + > CharUnits::fromQuantity(4)) && + CGM.getObjCRuntime().GetGetStructFunction()) { + GenerateObjCGetterBody(Ivar, true, false); + } + else if (IsAtomic && + !IVART->isAnyComplexType() && + Triple.getArch() == llvm::Triple::x86_64 && + (getContext().getTypeSizeInChars(IVART) + > CharUnits::fromQuantity(8)) && + CGM.getObjCRuntime().GetGetStructFunction()) { + GenerateObjCGetterBody(Ivar, true, false); } else { LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), @@ -295,11 +324,17 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, else { LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); - CodeGenTypes &Types = CGM.getTypes(); - RValue RV = EmitLoadOfLValue(LV, IVART); - RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(), + if (PD->getType()->isReferenceType()) { + RValue RV = RValue::get(LV.getAddress()); + EmitReturnOfRValue(RV, PD->getType()); + } + else { + CodeGenTypes &Types = CGM.getTypes(); + RValue RV = EmitLoadOfLValue(LV, IVART); + RV = RValue::get(Builder.CreateBitCast(RV.getScalarVal(), Types.ConvertType(PD->getType()))); - EmitReturnOfRValue(RV, PD->getType()); + EmitReturnOfRValue(RV, PD->getType()); + } } } @@ -318,31 +353,42 @@ void CodeGenFunction::GenerateObjCAtomicSetterBody(ObjCMethodDecl *OMD, RValue RV = RValue::get(Builder.CreateBitCast(LV.getAddress(), Types.ConvertType(getContext().VoidPtrTy))); - Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + Args.add(RV, getContext().VoidPtrTy); llvm::Value *Arg = LocalDeclMap[*OMD->param_begin()]; llvm::Value *ArgAsPtrTy = Builder.CreateBitCast(Arg, Types.ConvertType(getContext().VoidPtrTy)); RV = RValue::get(ArgAsPtrTy); - Args.push_back(std::make_pair(RV, getContext().VoidPtrTy)); + Args.add(RV, getContext().VoidPtrTy); // sizeof (Type of Ivar) CharUnits Size = getContext().getTypeSizeInChars(Ivar->getType()); llvm::Value *SizeVal = llvm::ConstantInt::get(Types.ConvertType(getContext().LongTy), Size.getQuantity()); - Args.push_back(std::make_pair(RValue::get(SizeVal), - getContext().LongTy)); + Args.add(RValue::get(SizeVal), getContext().LongTy); llvm::Value *True = llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 1); - Args.push_back(std::make_pair(RValue::get(True), getContext().BoolTy)); + Args.add(RValue::get(True), getContext().BoolTy); llvm::Value *False = llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0); - Args.push_back(std::make_pair(RValue::get(False), getContext().BoolTy)); + Args.add(RValue::get(False), getContext().BoolTy); EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, FunctionType::ExtInfo()), GetCopyStructFn, ReturnValueSlot(), Args); } +static bool +IvarAssignHasTrvialAssignment(const ObjCPropertyImplDecl *PID, + QualType IvarT) { + bool HasTrvialAssignment = true; + if (PID->getSetterCXXAssignment()) { + const CXXRecordDecl *classDecl = IvarT->getAsCXXRecordDecl(); + HasTrvialAssignment = + (!classDecl || classDecl->hasTrivialCopyAssignment()); + } + return HasTrvialAssignment; +} + /// GenerateObjCSetter - Generate an Objective-C property setter /// function. The given Decl must be an ObjCImplementationDecl. @synthesize /// is illegal within a category. @@ -353,7 +399,8 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, ObjCMethodDecl *OMD = PD->getSetterMethodDecl(); assert(OMD && "Invalid call to generate setter (empty method)"); StartObjCMethod(OMD, IMP->getClassInterface()); - + const llvm::Triple &Triple = getContext().Target.getTriple(); + QualType IVART = Ivar->getType(); bool IsCopy = PD->getSetterKind() == ObjCPropertyDecl::Copy; bool IsAtomic = !(PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic); @@ -394,32 +441,34 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, llvm::Value *False = llvm::ConstantInt::get(Types.ConvertType(getContext().BoolTy), 0); CallArgList Args; - Args.push_back(std::make_pair(RValue::get(SelfAsId), IdTy)); - Args.push_back(std::make_pair(RValue::get(CmdVal), Cmd->getType())); - Args.push_back(std::make_pair(RValue::get(Offset), getContext().LongTy)); - Args.push_back(std::make_pair(RValue::get(ArgAsId), IdTy)); - Args.push_back(std::make_pair(RValue::get(IsAtomic ? True : False), - getContext().BoolTy)); - Args.push_back(std::make_pair(RValue::get(IsCopy ? True : False), - getContext().BoolTy)); + Args.add(RValue::get(SelfAsId), IdTy); + Args.add(RValue::get(CmdVal), Cmd->getType()); + Args.add(RValue::get(Offset), getContext().getPointerDiffType()); + Args.add(RValue::get(ArgAsId), IdTy); + Args.add(RValue::get(IsAtomic ? True : False), getContext().BoolTy); + Args.add(RValue::get(IsCopy ? True : False), getContext().BoolTy); // FIXME: We shouldn't need to get the function info here, the runtime // already should have computed it to build the function. EmitCall(Types.getFunctionInfo(getContext().VoidTy, Args, FunctionType::ExtInfo()), SetPropertyFn, ReturnValueSlot(), Args); - } else if (IsAtomic && hasAggregateLLVMType(Ivar->getType()) && - !Ivar->getType()->isAnyComplexType() && - IndirectObjCSetterArg(*CurFnInfo) + } else if (IsAtomic && hasAggregateLLVMType(IVART) && + !IVART->isAnyComplexType() && + IvarAssignHasTrvialAssignment(PID, IVART) && + ((Triple.getArch() == llvm::Triple::x86 && + (getContext().getTypeSizeInChars(IVART) + > CharUnits::fromQuantity(4))) || + (Triple.getArch() == llvm::Triple::x86_64 && + (getContext().getTypeSizeInChars(IVART) + > CharUnits::fromQuantity(8)))) && CGM.getObjCRuntime().GetSetStructFunction()) { - // objc_copyStruct (&structIvar, &Arg, - // sizeof (struct something), true, false); + // objc_copyStruct (&structIvar, &Arg, + // sizeof (struct something), true, false); GenerateObjCAtomicSetterBody(OMD, Ivar); } else if (PID->getSetterCXXAssignment()) { EmitIgnoredExpr(PID->getSetterCXXAssignment()); } else { - const llvm::Triple &Triple = getContext().Target.getTriple(); - QualType IVART = Ivar->getType(); if (IsAtomic && IVART->isScalarType() && (Triple.getArch() == llvm::Triple::arm || @@ -429,6 +478,22 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, CGM.getObjCRuntime().GetGetStructFunction()) { GenerateObjCAtomicSetterBody(OMD, Ivar); } + else if (IsAtomic && + (IVART->isScalarType() && !IVART->isRealFloatingType()) && + Triple.getArch() == llvm::Triple::x86 && + (getContext().getTypeSizeInChars(IVART) + > CharUnits::fromQuantity(4)) && + CGM.getObjCRuntime().GetGetStructFunction()) { + GenerateObjCAtomicSetterBody(OMD, Ivar); + } + else if (IsAtomic && + (IVART->isScalarType() && !IVART->isRealFloatingType()) && + Triple.getArch() == llvm::Triple::x86_64 && + (getContext().getTypeSizeInChars(IVART) + > CharUnits::fromQuantity(8)) && + CGM.getObjCRuntime().GetGetStructFunction()) { + GenerateObjCAtomicSetterBody(OMD, Ivar); + } else { // FIXME: Find a clean way to avoid AST node creation. SourceLocation Loc = PD->getLocation(); @@ -436,7 +501,10 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, ObjCIvarDecl *Ivar = PID->getPropertyIvarDecl(); DeclRefExpr Base(Self, Self->getType(), VK_RValue, Loc); ParmVarDecl *ArgDecl = *OMD->param_begin(); - DeclRefExpr Arg(ArgDecl, ArgDecl->getType(), VK_LValue, Loc); + QualType T = ArgDecl->getType(); + if (T->isReferenceType()) + T = cast<ReferenceType>(T)->getPointeeType(); + DeclRefExpr Arg(ArgDecl, T, VK_LValue, Loc); ObjCIvarRefExpr IvarRef(Ivar, Ivar->getType(), Loc, &Base, true, true); // The property type can differ from the ivar type in some situations with @@ -460,20 +528,104 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, FinishFunction(); } +// FIXME: these are stolen from CGClass.cpp, which is lame. +namespace { + struct CallArrayIvarDtor : EHScopeStack::Cleanup { + const ObjCIvarDecl *ivar; + llvm::Value *self; + CallArrayIvarDtor(const ObjCIvarDecl *ivar, llvm::Value *self) + : ivar(ivar), self(self) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + LValue lvalue = + CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), self, ivar, 0); + + QualType type = ivar->getType(); + const ConstantArrayType *arrayType + = CGF.getContext().getAsConstantArrayType(type); + QualType baseType = CGF.getContext().getBaseElementType(arrayType); + const CXXRecordDecl *classDecl = baseType->getAsCXXRecordDecl(); + + llvm::Value *base + = CGF.Builder.CreateBitCast(lvalue.getAddress(), + CGF.ConvertType(baseType)->getPointerTo()); + CGF.EmitCXXAggrDestructorCall(classDecl->getDestructor(), + arrayType, base); + } + }; + + struct CallIvarDtor : EHScopeStack::Cleanup { + const ObjCIvarDecl *ivar; + llvm::Value *self; + CallIvarDtor(const ObjCIvarDecl *ivar, llvm::Value *self) + : ivar(ivar), self(self) {} + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + LValue lvalue = + CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), self, ivar, 0); + + QualType type = ivar->getType(); + const CXXRecordDecl *classDecl = type->getAsCXXRecordDecl(); + + CGF.EmitCXXDestructorCall(classDecl->getDestructor(), + Dtor_Complete, /*ForVirtualBase=*/false, + lvalue.getAddress()); + } + }; +} + +static void emitCXXDestructMethod(CodeGenFunction &CGF, + ObjCImplementationDecl *impl) { + CodeGenFunction::RunCleanupsScope scope(CGF); + + llvm::Value *self = CGF.LoadObjCSelf(); + + ObjCInterfaceDecl *iface + = const_cast<ObjCInterfaceDecl*>(impl->getClassInterface()); + for (ObjCIvarDecl *ivar = iface->all_declared_ivar_begin(); + ivar; ivar = ivar->getNextIvar()) { + QualType type = ivar->getType(); + + // Drill down to the base element type. + QualType baseType = type; + const ConstantArrayType *arrayType = + CGF.getContext().getAsConstantArrayType(baseType); + if (arrayType) baseType = CGF.getContext().getBaseElementType(arrayType); + + // Check whether the ivar is a destructible type. + QualType::DestructionKind destructKind = baseType.isDestructedType(); + assert(destructKind == type.isDestructedType()); + + switch (destructKind) { + case QualType::DK_none: + continue; + + case QualType::DK_cxx_destructor: + if (arrayType) + CGF.EHStack.pushCleanup<CallArrayIvarDtor>(NormalAndEHCleanup, + ivar, self); + else + CGF.EHStack.pushCleanup<CallIvarDtor>(NormalAndEHCleanup, + ivar, self); + break; + } + } + + assert(scope.requiresCleanups() && "nothing to do in .cxx_destruct?"); +} + void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, ObjCMethodDecl *MD, bool ctor) { - llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers; MD->createImplicitParams(CGM.getContext(), IMP->getClassInterface()); StartObjCMethod(MD, IMP->getClassInterface()); - for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(), - E = IMP->init_end(); B != E; ++B) { - CXXCtorInitializer *Member = (*B); - IvarInitializers.push_back(Member); - } + + // Emit .cxx_construct. if (ctor) { - for (unsigned I = 0, E = IvarInitializers.size(); I != E; ++I) { - CXXCtorInitializer *IvarInit = IvarInitializers[I]; + llvm::SmallVector<CXXCtorInitializer *, 8> IvarInitializers; + for (ObjCImplementationDecl::init_const_iterator B = IMP->init_begin(), + E = IMP->init_end(); B != E; ++B) { + CXXCtorInitializer *IvarInit = (*B); FieldDecl *Field = IvarInit->getAnyMember(); ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field); LValue LV = EmitLValueForIvar(TypeOfSelfObject(), @@ -486,37 +638,10 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, llvm::Value *SelfAsId = Builder.CreateBitCast(LoadObjCSelf(), Types.ConvertType(IdTy)); EmitReturnOfRValue(RValue::get(SelfAsId), IdTy); + + // Emit .cxx_destruct. } else { - // dtor - for (size_t i = IvarInitializers.size(); i > 0; --i) { - FieldDecl *Field = IvarInitializers[i - 1]->getAnyMember(); - QualType FieldType = Field->getType(); - const ConstantArrayType *Array = - getContext().getAsConstantArrayType(FieldType); - if (Array) - FieldType = getContext().getBaseElementType(FieldType); - - ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(Field); - LValue LV = EmitLValueForIvar(TypeOfSelfObject(), - LoadObjCSelf(), Ivar, 0); - const RecordType *RT = FieldType->getAs<RecordType>(); - CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); - CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(); - if (!Dtor->isTrivial()) { - if (Array) { - const llvm::Type *BasePtr = ConvertType(FieldType); - BasePtr = llvm::PointerType::getUnqual(BasePtr); - llvm::Value *BaseAddrPtr = - Builder.CreateBitCast(LV.getAddress(), BasePtr); - EmitCXXAggrDestructorCall(Dtor, - Array, BaseAddrPtr); - } else { - EmitCXXDestructorCall(Dtor, - Dtor_Complete, /*ForVirtualBase=*/false, - LV.getAddress()); - } - } - } + emitCXXDestructMethod(*this, IMP); } FinishFunction(); } @@ -585,16 +710,14 @@ static RValue GenerateMessageSendSuper(CodeGenFunction &CGF, RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV, ReturnValueSlot Return) { const ObjCPropertyRefExpr *E = LV.getPropertyRefExpr(); - QualType ResultType; + QualType ResultType = E->getGetterResultType(); Selector S; if (E->isExplicitProperty()) { const ObjCPropertyDecl *Property = E->getExplicitProperty(); S = Property->getGetterName(); - ResultType = E->getType(); } else { const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter(); S = Getter->getSelector(); - ResultType = Getter->getResultType(); // with reference! } llvm::Value *Receiver = LV.getPropertyRefBaseAddr(); @@ -615,14 +738,8 @@ void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src, LValue Dst) { const ObjCPropertyRefExpr *E = Dst.getPropertyRefExpr(); Selector S = E->getSetterSelector(); - QualType ArgType; - if (E->isImplicitProperty()) { - const ObjCMethodDecl *Setter = E->getImplicitPropertySetter(); - ObjCMethodDecl::param_iterator P = Setter->param_begin(); - ArgType = (*P)->getType(); - } else { - ArgType = E->getType(); - } + QualType ArgType = E->getSetterArgType(); + // FIXME. Other than scalars, AST is not adequate for setter and // getter type mismatches which require conversion. if (Src.isScalar()) { @@ -635,7 +752,7 @@ void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src, } CallArgList Args; - Args.push_back(std::make_pair(Src, ArgType)); + Args.add(Src, ArgType); llvm::Value *Receiver = Dst.getPropertyRefBaseAddr(); QualType ResultType = getContext().VoidTy; @@ -707,22 +824,19 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ CallArgList Args; // The first argument is a temporary of the enumeration-state type. - Args.push_back(std::make_pair(RValue::get(StatePtr), - getContext().getPointerType(StateTy))); + Args.add(RValue::get(StatePtr), getContext().getPointerType(StateTy)); // The second argument is a temporary array with space for NumItems // pointers. We'll actually be loading elements from the array // pointer written into the control state; this buffer is so that // collections that *aren't* backed by arrays can still queue up // batches of elements. - Args.push_back(std::make_pair(RValue::get(ItemsPtr), - getContext().getPointerType(ItemsTy))); + Args.add(RValue::get(ItemsPtr), getContext().getPointerType(ItemsTy)); // The third argument is the capacity of that temporary array. const llvm::Type *UnsignedLongLTy = ConvertType(getContext().UnsignedLongTy); llvm::Constant *Count = llvm::ConstantInt::get(UnsignedLongLTy, NumItems); - Args.push_back(std::make_pair(RValue::get(Count), - getContext().UnsignedLongTy)); + Args.add(RValue::get(Count), getContext().UnsignedLongTy); // Start the enumeration. RValue CountRV = @@ -764,11 +878,11 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ EmitBlock(LoopBodyBB); // The current index into the buffer. - llvm::PHINode *index = Builder.CreatePHI(UnsignedLongLTy, "forcoll.index"); + llvm::PHINode *index = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.index"); index->addIncoming(zero, LoopInitBB); // The current buffer size. - llvm::PHINode *count = Builder.CreatePHI(UnsignedLongLTy, "forcoll.count"); + llvm::PHINode *count = Builder.CreatePHI(UnsignedLongLTy, 3, "forcoll.count"); count->addIncoming(initialBufferLimit, LoopInitBB); // Check whether the mutations value has changed from where it was @@ -779,7 +893,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ = Builder.CreateLoad(StateMutationsPtr, "statemutations"); llvm::BasicBlock *WasMutatedBB = createBasicBlock("forcoll.mutated"); - llvm::BasicBlock *WasNotMutatedBB = createBasicBlock("forcool.notmutated"); + llvm::BasicBlock *WasNotMutatedBB = createBasicBlock("forcoll.notmutated"); Builder.CreateCondBr(Builder.CreateICmpEQ(currentMutations, initialMutations), WasNotMutatedBB, WasMutatedBB); @@ -791,8 +905,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ ConvertType(getContext().getObjCIdType()), "tmp"); CallArgList Args2; - Args2.push_back(std::make_pair(RValue::get(V), - getContext().getObjCIdType())); + Args2.add(RValue::get(V), getContext().getObjCIdType()); // FIXME: We shouldn't need to get the function info here, the runtime already // should have computed it to build the function. EmitCall(CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args2, diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp index 5f19dc6..c4dc4c4 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCGNU.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This provides Objective-C code generation targetting the GNU runtime. The +// This provides Objective-C code generation targeting the GNU runtime. The // class in this file generates structures used by the GNU Objective-C runtime // library. These structures are defined in objc/objc.h and objc/objc-api.h in // the GNU runtime distribution. @@ -24,90 +24,342 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtObjC.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" #include "llvm/Intrinsics.h" #include "llvm/Module.h" #include "llvm/LLVMContext.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/Support/CallSite.h" #include "llvm/Support/Compiler.h" #include "llvm/Target/TargetData.h" -#include <map> +#include <stdarg.h> using namespace clang; using namespace CodeGen; using llvm::dyn_cast; -// The version of the runtime that this class targets. Must match the version -// in the runtime. -static const int RuntimeVersion = 8; -static const int NonFragileRuntimeVersion = 9; -static const int ProtocolVersion = 2; -static const int NonFragileProtocolVersion = 3; namespace { -class CGObjCGNU : public CodeGen::CGObjCRuntime { -private: - CodeGen::CodeGenModule &CGM; +/// Class that lazily initialises the runtime function. Avoids inserting the +/// types and the function declaration into a module if they're not used, and +/// avoids constructing the type more than once if it's used more than once. +class LazyRuntimeFunction { + CodeGenModule *CGM; + std::vector<const llvm::Type*> ArgTys; + const char *FunctionName; + llvm::Function *Function; + public: + /// Constructor leaves this class uninitialized, because it is intended to + /// be used as a field in another class and not all of the types that are + /// used as arguments will necessarily be available at construction time. + LazyRuntimeFunction() : CGM(0), FunctionName(0), Function(0) {} + + /// Initialises the lazy function with the name, return type, and the types + /// of the arguments. + END_WITH_NULL + void init(CodeGenModule *Mod, const char *name, + const llvm::Type *RetTy, ...) { + CGM =Mod; + FunctionName = name; + Function = 0; + ArgTys.clear(); + va_list Args; + va_start(Args, RetTy); + while (const llvm::Type *ArgTy = va_arg(Args, const llvm::Type*)) + ArgTys.push_back(ArgTy); + va_end(Args); + // Push the return type on at the end so we can pop it off easily + ArgTys.push_back(RetTy); + } + /// Overloaded cast operator, allows the class to be implicitly cast to an + /// LLVM constant. + operator llvm::Function*() { + if (!Function) { + if (0 == FunctionName) return 0; + // We put the return type on the end of the vector, so pop it back off + const llvm::Type *RetTy = ArgTys.back(); + ArgTys.pop_back(); + llvm::FunctionType *FTy = llvm::FunctionType::get(RetTy, ArgTys, false); + Function = + cast<llvm::Function>(CGM->CreateRuntimeFunction(FTy, FunctionName)); + // We won't need to use the types again, so we may as well clean up the + // vector now + ArgTys.resize(0); + } + return Function; + } +}; + + +/// GNU Objective-C runtime code generation. This class implements the parts of +/// Objective-C support that are specific to the GNU family of runtimes (GCC and +/// GNUstep). +class CGObjCGNU : public CGObjCRuntime { +protected: + /// The module that is using this class + CodeGenModule &CGM; + /// The LLVM module into which output is inserted llvm::Module &TheModule; + /// strut objc_super. Used for sending messages to super. This structure + /// contains the receiver (object) and the expected class. + const llvm::StructType *ObjCSuperTy; + /// struct objc_super*. The type of the argument to the superclass message + /// lookup functions. + const llvm::PointerType *PtrToObjCSuperTy; + /// LLVM type for selectors. Opaque pointer (i8*) unless a header declaring + /// SEL is included in a header somewhere, in which case it will be whatever + /// type is declared in that header, most likely {i8*, i8*}. const llvm::PointerType *SelectorTy; + /// LLVM i8 type. Cached here to avoid repeatedly getting it in all of the + /// places where it's used const llvm::IntegerType *Int8Ty; + /// Pointer to i8 - LLVM type of char*, for all of the places where the + /// runtime needs to deal with C strings. const llvm::PointerType *PtrToInt8Ty; - const llvm::FunctionType *IMPTy; + /// Instance Method Pointer type. This is a pointer to a function that takes, + /// at a minimum, an object and a selector, and is the generic type for + /// Objective-C methods. Due to differences between variadic / non-variadic + /// calling conventions, it must always be cast to the correct type before + /// actually being used. + const llvm::PointerType *IMPTy; + /// Type of an untyped Objective-C object. Clang treats id as a built-in type + /// when compiling Objective-C code, so this may be an opaque pointer (i8*), + /// but if the runtime header declaring it is included then it may be a + /// pointer to a structure. const llvm::PointerType *IdTy; + /// Pointer to a pointer to an Objective-C object. Used in the new ABI + /// message lookup function and some GC-related functions. const llvm::PointerType *PtrToIdTy; + /// The clang type of id. Used when using the clang CGCall infrastructure to + /// call Objective-C methods. CanQualType ASTIdTy; + /// LLVM type for C int type. const llvm::IntegerType *IntTy; + /// LLVM type for an opaque pointer. This is identical to PtrToInt8Ty, but is + /// used in the code to document the difference between i8* meaning a pointer + /// to a C string and i8* meaning a pointer to some opaque type. const llvm::PointerType *PtrTy; + /// LLVM type for C long type. The runtime uses this in a lot of places where + /// it should be using intptr_t, but we can't fix this without breaking + /// compatibility with GCC... const llvm::IntegerType *LongTy; + /// LLVM type for C size_t. Used in various runtime data structures. const llvm::IntegerType *SizeTy; + /// LLVM type for C ptrdiff_t. Mainly used in property accessor functions. const llvm::IntegerType *PtrDiffTy; + /// LLVM type for C int*. Used for GCC-ABI-compatible non-fragile instance + /// variables. const llvm::PointerType *PtrToIntTy; + /// LLVM type for Objective-C BOOL type. const llvm::Type *BoolTy; + /// Metadata kind used to tie method lookups to message sends. The GNUstep + /// runtime provides some LLVM passes that can use this to do things like + /// automatic IMP caching and speculative inlining. + unsigned msgSendMDKind; + /// Helper function that generates a constant string and returns a pointer to + /// the start of the string. The result of this function can be used anywhere + /// where the C code specifies const char*. + llvm::Constant *MakeConstantString(const std::string &Str, + const std::string &Name="") { + llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str()); + return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2); + } + /// Emits a linkonce_odr string, whose name is the prefix followed by the + /// string value. This allows the linker to combine the strings between + /// different modules. Used for EH typeinfo names, selector strings, and a + /// few other things. + llvm::Constant *ExportUniqueString(const std::string &Str, + const std::string prefix) { + std::string name = prefix + Str; + llvm::Constant *ConstStr = TheModule.getGlobalVariable(name); + if (!ConstStr) { + llvm::Constant *value = llvm::ConstantArray::get(VMContext, Str, true); + ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true, + llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str); + } + return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2); + } + /// Generates a global structure, initialized by the elements in the vector. + /// The element types must match the types of the structure elements in the + /// first argument. + llvm::GlobalVariable *MakeGlobal(const llvm::StructType *Ty, + std::vector<llvm::Constant*> &V, + llvm::StringRef Name="", + llvm::GlobalValue::LinkageTypes linkage + =llvm::GlobalValue::InternalLinkage) { + llvm::Constant *C = llvm::ConstantStruct::get(Ty, V); + return new llvm::GlobalVariable(TheModule, Ty, false, + linkage, C, Name); + } + /// Generates a global array. The vector must contain the same number of + /// elements that the array type declares, of the type specified as the array + /// element type. + llvm::GlobalVariable *MakeGlobal(const llvm::ArrayType *Ty, + std::vector<llvm::Constant*> &V, + llvm::StringRef Name="", + llvm::GlobalValue::LinkageTypes linkage + =llvm::GlobalValue::InternalLinkage) { + llvm::Constant *C = llvm::ConstantArray::get(Ty, V); + return new llvm::GlobalVariable(TheModule, Ty, false, + linkage, C, Name); + } + /// Generates a global array, inferring the array type from the specified + /// element type and the size of the initialiser. + llvm::GlobalVariable *MakeGlobalArray(const llvm::Type *Ty, + std::vector<llvm::Constant*> &V, + llvm::StringRef Name="", + llvm::GlobalValue::LinkageTypes linkage + =llvm::GlobalValue::InternalLinkage) { + llvm::ArrayType *ArrayTy = llvm::ArrayType::get(Ty, V.size()); + return MakeGlobal(ArrayTy, V, Name, linkage); + } + /// Ensures that the value has the required type, by inserting a bitcast if + /// required. This function lets us avoid inserting bitcasts that are + /// redundant. + llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, const llvm::Type *Ty){ + if (V->getType() == Ty) return V; + return B.CreateBitCast(V, Ty); + } + // Some zeros used for GEPs in lots of places. + llvm::Constant *Zeros[2]; + /// Null pointer value. Mainly used as a terminator in various arrays. + llvm::Constant *NULLPtr; + /// LLVM context. + llvm::LLVMContext &VMContext; +private: + /// Placeholder for the class. Lots of things refer to the class before we've + /// actually emitted it. We use this alias as a placeholder, and then replace + /// it with a pointer to the class structure before finally emitting the + /// module. llvm::GlobalAlias *ClassPtrAlias; + /// Placeholder for the metaclass. Lots of things refer to the class before + /// we've / actually emitted it. We use this alias as a placeholder, and then + /// replace / it with a pointer to the metaclass structure before finally + /// emitting the / module. llvm::GlobalAlias *MetaClassPtrAlias; + /// All of the classes that have been generated for this compilation units. std::vector<llvm::Constant*> Classes; + /// All of the categories that have been generated for this compilation units. std::vector<llvm::Constant*> Categories; + /// All of the Objective-C constant strings that have been generated for this + /// compilation units. std::vector<llvm::Constant*> ConstantStrings; + /// Map from string values to Objective-C constant strings in the output. + /// Used to prevent emitting Objective-C strings more than once. This should + /// not be required at all - CodeGenModule should manage this list. llvm::StringMap<llvm::Constant*> ObjCStrings; - llvm::Function *LoadFunction; + /// All of the protocols that have been declared. llvm::StringMap<llvm::Constant*> ExistingProtocols; - typedef std::pair<std::string, std::string> TypedSelector; - std::map<TypedSelector, llvm::GlobalAlias*> TypedSelectors; - llvm::StringMap<llvm::GlobalAlias*> UntypedSelectors; - // Selectors that we don't emit in GC mode + /// For each variant of a selector, we store the type encoding and a + /// placeholder value. For an untyped selector, the type will be the empty + /// string. Selector references are all done via the module's selector table, + /// so we create an alias as a placeholder and then replace it with the real + /// value later. + typedef std::pair<std::string, llvm::GlobalAlias*> TypedSelector; + /// Type of the selector map. This is roughly equivalent to the structure + /// used in the GNUstep runtime, which maintains a list of all of the valid + /// types for a selector in a table. + typedef llvm::DenseMap<Selector, llvm::SmallVector<TypedSelector, 2> > + SelectorMap; + /// A map from selectors to selector types. This allows us to emit all + /// selectors of the same name and type together. + SelectorMap SelectorTable; + + /// Selectors related to memory management. When compiling in GC mode, we + /// omit these. Selector RetainSel, ReleaseSel, AutoreleaseSel; - // Functions used for GC. - llvm::Constant *IvarAssignFn, *StrongCastAssignFn, *MemMoveFn, *WeakReadFn, - *WeakAssignFn, *GlobalAssignFn; - // Some zeros used for GEPs in lots of places. - llvm::Constant *Zeros[2]; - llvm::Constant *NULLPtr; - llvm::LLVMContext &VMContext; - /// Metadata kind used to tie method lookups to message sends. - unsigned msgSendMDKind; + /// Runtime functions used for memory management in GC mode. Note that clang + /// supports code generation for calling these functions, but neither GNU + /// runtime actually supports this API properly yet. + LazyRuntimeFunction IvarAssignFn, StrongCastAssignFn, MemMoveFn, WeakReadFn, + WeakAssignFn, GlobalAssignFn; + +protected: + /// Function used for throwing Objective-C exceptions. + LazyRuntimeFunction ExceptionThrowFn; + /// Function used for rethrowing exceptions, used at the end of @finally or + /// @synchronize blocks. + LazyRuntimeFunction ExceptionReThrowFn; + /// Function called when entering a catch function. This is required for + /// differentiating Objective-C exceptions and foreign exceptions. + LazyRuntimeFunction EnterCatchFn; + /// Function called when exiting from a catch block. Used to do exception + /// cleanup. + LazyRuntimeFunction ExitCatchFn; + /// Function called when entering an @synchronize block. Acquires the lock. + LazyRuntimeFunction SyncEnterFn; + /// Function called when exiting an @synchronize block. Releases the lock. + LazyRuntimeFunction SyncExitFn; + +private: + + /// Function called if fast enumeration detects that the collection is + /// modified during the update. + LazyRuntimeFunction EnumerationMutationFn; + /// Function for implementing synthesized property getters that return an + /// object. + LazyRuntimeFunction GetPropertyFn; + /// Function for implementing synthesized property setters that return an + /// object. + LazyRuntimeFunction SetPropertyFn; + /// Function used for non-object declared property getters. + LazyRuntimeFunction GetStructPropertyFn; + /// Function used for non-object declared property setters. + LazyRuntimeFunction SetStructPropertyFn; + + /// The version of the runtime that this class targets. Must match the + /// version in the runtime. + const int RuntimeVersion; + /// The version of the protocol class. Used to differentiate between ObjC1 + /// and ObjC2 protocols. Objective-C 1 protocols can not contain optional + /// components and can not contain declared properties. We always emit + /// Objective-C 2 property structures, but we have to pretend that they're + /// Objective-C 1 property structures when targeting the GCC runtime or it + /// will abort. + const int ProtocolVersion; private: + /// Generates an instance variable list structure. This is a structure + /// containing a size and an array of structures containing instance variable + /// metadata. This is used purely for introspection in the fragile ABI. In + /// the non-fragile ABI, it's used for instance variable fixup. llvm::Constant *GenerateIvarList( const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames, const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes, const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets); - llvm::Constant *GenerateMethodList(const std::string &ClassName, - const std::string &CategoryName, + /// Generates a method list structure. This is a structure containing a size + /// and an array of structures containing method metadata. + /// + /// This structure is used by both classes and categories, and contains a next + /// pointer allowing them to be chained together in a linked list. + llvm::Constant *GenerateMethodList(const llvm::StringRef &ClassName, + const llvm::StringRef &CategoryName, const llvm::SmallVectorImpl<Selector> &MethodSels, const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes, bool isClassMethodList); + /// Emits an empty protocol. This is used for @protocol() where no protocol + /// is found. The runtime will (hopefully) fix up the pointer to refer to the + /// real protocol. llvm::Constant *GenerateEmptyProtocol(const std::string &ProtocolName); + /// Generates a list of property metadata structures. This follows the same + /// pattern as method and instance variable metadata lists. llvm::Constant *GeneratePropertyList(const ObjCImplementationDecl *OID, llvm::SmallVectorImpl<Selector> &InstanceMethodSels, llvm::SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes); + /// Generates a list of referenced protocols. Classes, categories, and + /// protocols all use this structure. llvm::Constant *GenerateProtocolList( const llvm::SmallVectorImpl<std::string> &Protocols); - // To ensure that all protocols are seen by the runtime, we add a category on - // a class defined in the runtime, declaring no methods, but adopting the - // protocols. + /// To ensure that all protocols are seen by the runtime, we add a category on + /// a class defined in the runtime, declaring no methods, but adopting the + /// protocols. This is a horribly ugly hack, but it allows us to collect all + /// of the protocols without changing the ABI. void GenerateProtocolHolderCategory(void); + /// Generates a class structure. llvm::Constant *GenerateClassStructure( llvm::Constant *MetaClass, llvm::Constant *SuperClass, @@ -121,31 +373,43 @@ private: llvm::Constant *IvarOffsets, llvm::Constant *Properties, bool isMeta=false); + /// Generates a method list. This is used by protocols to define the required + /// and optional methods. llvm::Constant *GenerateProtocolMethodList( const llvm::SmallVectorImpl<llvm::Constant *> &MethodNames, const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes); - llvm::Constant *MakeConstantString(const std::string &Str, const std::string - &Name=""); - llvm::Constant *ExportUniqueString(const std::string &Str, const std::string - prefix); - llvm::Constant *MakeGlobal(const llvm::StructType *Ty, - std::vector<llvm::Constant*> &V, llvm::StringRef Name="", - llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage); - llvm::Constant *MakeGlobal(const llvm::ArrayType *Ty, - std::vector<llvm::Constant*> &V, llvm::StringRef Name="", - llvm::GlobalValue::LinkageTypes linkage=llvm::GlobalValue::InternalLinkage); + /// Returns a selector with the specified type encoding. An empty string is + /// used to return an untyped selector (with the types field set to NULL). + llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel, + const std::string &TypeEncoding, bool lval); + /// Returns the variable used to store the offset of an instance variable. llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID, const ObjCIvarDecl *Ivar); + /// Emits a reference to a class. This allows the linker to object if there + /// is no class of the matching name. void EmitClassRef(const std::string &className); - llvm::Value* EnforceType(CGBuilderTy B, llvm::Value *V, const llvm::Type *Ty){ - if (V->getType() == Ty) return V; - return B.CreateBitCast(V, Ty); - } +protected: + /// Looks up the method for sending a message to the specified object. This + /// mechanism differs between the GCC and GNU runtimes, so this method must be + /// overridden in subclasses. + virtual llvm::Value *LookupIMP(CodeGenFunction &CGF, + llvm::Value *&Receiver, + llvm::Value *cmd, + llvm::MDNode *node) = 0; + /// Looks up the method for sending a message to a superclass. This mechanism + /// differs between the GCC and GNU runtimes, so this method must be + /// overridden in subclasses. + virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, + llvm::Value *ObjCSuper, + llvm::Value *cmd) = 0; public: - CGObjCGNU(CodeGen::CodeGenModule &cgm); + CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, + unsigned protocolClassVersion); + virtual llvm::Constant *GenerateConstantString(const StringLiteral *); - virtual CodeGen::RValue - GenerateMessageSend(CodeGen::CodeGenFunction &CGF, + + virtual RValue + GenerateMessageSend(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, @@ -153,8 +417,8 @@ public: const CallArgList &CallArgs, const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method); - virtual CodeGen::RValue - GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, + virtual RValue + GenerateMessageSendSuper(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, @@ -186,41 +450,174 @@ public: virtual llvm::Function *GetGetStructFunction(); virtual llvm::Constant *EnumerationMutationFunction(); - virtual void EmitTryStmt(CodeGen::CodeGenFunction &CGF, + virtual void EmitTryStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S); - virtual void EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, + virtual void EmitSynchronizedStmt(CodeGenFunction &CGF, const ObjCAtSynchronizedStmt &S); - virtual void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, + virtual void EmitThrowStmt(CodeGenFunction &CGF, const ObjCAtThrowStmt &S); - virtual llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, + virtual llvm::Value * EmitObjCWeakRead(CodeGenFunction &CGF, llvm::Value *AddrWeakObj); - virtual void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, + virtual void EmitObjCWeakAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst); - virtual void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, + virtual void EmitObjCGlobalAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest, bool threadlocal=false); - virtual void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, + virtual void EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest, llvm::Value *ivarOffset); - virtual void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, + virtual void EmitObjCStrongCastAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dest); - virtual void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, + virtual void EmitGCMemmoveCollectable(CodeGenFunction &CGF, llvm::Value *DestPtr, llvm::Value *SrcPtr, llvm::Value *Size); - virtual LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, + virtual LValue EmitObjCValueForIvar(CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers); - virtual llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF, + virtual llvm::Value *EmitIvarOffset(CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); - virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM, + virtual llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { return NULLPtr; } }; +/// Class representing the legacy GCC Objective-C ABI. This is the default when +/// -fobjc-nonfragile-abi is not specified. +/// +/// The GCC ABI target actually generates code that is approximately compatible +/// with the new GNUstep runtime ABI, but refrains from using any features that +/// would not work with the GCC runtime. For example, clang always generates +/// the extended form of the class structure, and the extra fields are simply +/// ignored by GCC libobjc. +class CGObjCGCC : public CGObjCGNU { + /// The GCC ABI message lookup function. Returns an IMP pointing to the + /// method implementation for this message. + LazyRuntimeFunction MsgLookupFn; + /// The GCC ABI superclass message lookup function. Takes a pointer to a + /// structure describing the receiver and the class, and a selector as + /// arguments. Returns the IMP for the corresponding method. + LazyRuntimeFunction MsgLookupSuperFn; +protected: + virtual llvm::Value *LookupIMP(CodeGenFunction &CGF, + llvm::Value *&Receiver, + llvm::Value *cmd, + llvm::MDNode *node) { + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *imp = Builder.CreateCall2(MsgLookupFn, + EnforceType(Builder, Receiver, IdTy), + EnforceType(Builder, cmd, SelectorTy)); + cast<llvm::CallInst>(imp)->setMetadata(msgSendMDKind, node); + return imp; + } + virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, + llvm::Value *ObjCSuper, + llvm::Value *cmd) { + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper, + PtrToObjCSuperTy), cmd}; + return Builder.CreateCall(MsgLookupSuperFn, lookupArgs, lookupArgs+2); + } + public: + CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) { + // IMP objc_msg_lookup(id, SEL); + MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, NULL); + // IMP objc_msg_lookup_super(struct objc_super*, SEL); + MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy, + PtrToObjCSuperTy, SelectorTy, NULL); + } +}; +/// Class used when targeting the new GNUstep runtime ABI. +class CGObjCGNUstep : public CGObjCGNU { + /// The slot lookup function. Returns a pointer to a cacheable structure + /// that contains (among other things) the IMP. + LazyRuntimeFunction SlotLookupFn; + /// The GNUstep ABI superclass message lookup function. Takes a pointer to + /// a structure describing the receiver and the class, and a selector as + /// arguments. Returns the slot for the corresponding method. Superclass + /// message lookup rarely changes, so this is a good caching opportunity. + LazyRuntimeFunction SlotLookupSuperFn; + /// Type of an slot structure pointer. This is returned by the various + /// lookup functions. + llvm::Type *SlotTy; + protected: + virtual llvm::Value *LookupIMP(CodeGenFunction &CGF, + llvm::Value *&Receiver, + llvm::Value *cmd, + llvm::MDNode *node) { + CGBuilderTy &Builder = CGF.Builder; + llvm::Function *LookupFn = SlotLookupFn; + + // Store the receiver on the stack so that we can reload it later + llvm::Value *ReceiverPtr = CGF.CreateTempAlloca(Receiver->getType()); + Builder.CreateStore(Receiver, ReceiverPtr); + + llvm::Value *self; + + if (isa<ObjCMethodDecl>(CGF.CurCodeDecl)) { + self = CGF.LoadObjCSelf(); + } else { + self = llvm::ConstantPointerNull::get(IdTy); + } + + // The lookup function is guaranteed not to capture the receiver pointer. + LookupFn->setDoesNotCapture(1); + + llvm::CallInst *slot = + Builder.CreateCall3(LookupFn, + EnforceType(Builder, ReceiverPtr, PtrToIdTy), + EnforceType(Builder, cmd, SelectorTy), + EnforceType(Builder, self, IdTy)); + slot->setOnlyReadsMemory(); + slot->setMetadata(msgSendMDKind, node); + + // Load the imp from the slot + llvm::Value *imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); + + // The lookup function may have changed the receiver, so make sure we use + // the new one. + Receiver = Builder.CreateLoad(ReceiverPtr, true); + return imp; + } + virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, + llvm::Value *ObjCSuper, + llvm::Value *cmd) { + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *lookupArgs[] = {ObjCSuper, cmd}; + + llvm::CallInst *slot = Builder.CreateCall(SlotLookupSuperFn, lookupArgs, + lookupArgs+2); + slot->setOnlyReadsMemory(); + + return Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); + } + public: + CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNU(Mod, 9, 3) { + llvm::StructType *SlotStructTy = llvm::StructType::get(VMContext, PtrTy, + PtrTy, PtrTy, IntTy, IMPTy, NULL); + SlotTy = llvm::PointerType::getUnqual(SlotStructTy); + // Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender); + SlotLookupFn.init(&CGM, "objc_msg_lookup_sender", SlotTy, PtrToIdTy, + SelectorTy, IdTy, NULL); + // Slot_t objc_msg_lookup_super(struct objc_super*, SEL); + SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy, + PtrToObjCSuperTy, SelectorTy, NULL); + // If we're in ObjC++ mode, then we want to make + if (CGM.getLangOptions().CPlusPlus) { + const llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); + // void *__cxa_begin_catch(void *e) + EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy, NULL); + // void __cxa_end_catch(void) + EnterCatchFn.init(&CGM, "__cxa_end_catch", VoidTy, NULL); + // void _Unwind_Resume_or_Rethrow(void*) + ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy, PtrTy, NULL); + } + } +}; + } // end anonymous namespace @@ -242,45 +639,34 @@ void CGObjCGNU::EmitClassRef(const std::string &className) { llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef); } -static std::string SymbolNameForMethod(const std::string &ClassName, const - std::string &CategoryName, const std::string &MethodName, bool isClassMethod) -{ - std::string MethodNameColonStripped = MethodName; +static std::string SymbolNameForMethod(const llvm::StringRef &ClassName, + const llvm::StringRef &CategoryName, const Selector MethodName, + bool isClassMethod) { + std::string MethodNameColonStripped = MethodName.getAsString(); std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(), ':', '_'); - return std::string(isClassMethod ? "_c_" : "_i_") + ClassName + "_" + - CategoryName + "_" + MethodNameColonStripped; -} -static std::string MangleSelectorTypes(const std::string &TypeString) { - std::string Mangled = TypeString; - // Simple mangling to avoid breaking when we mix JIT / static code. - // Not part of the ABI, subject to change without notice. - std::replace(Mangled.begin(), Mangled.end(), '@', '_'); - std::replace(Mangled.begin(), Mangled.end(), ':', 'J'); - std::replace(Mangled.begin(), Mangled.end(), '*', 'e'); - std::replace(Mangled.begin(), Mangled.end(), '#', 'E'); - std::replace(Mangled.begin(), Mangled.end(), ':', 'j'); - std::replace(Mangled.begin(), Mangled.end(), '(', 'g'); - std::replace(Mangled.begin(), Mangled.end(), ')', 'G'); - std::replace(Mangled.begin(), Mangled.end(), '[', 'h'); - std::replace(Mangled.begin(), Mangled.end(), ']', 'H'); - return Mangled; + return (llvm::Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" + + CategoryName + "_" + MethodNameColonStripped).str(); } -CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) - : CGM(cgm), TheModule(CGM.getModule()), ClassPtrAlias(0), - MetaClassPtrAlias(0), VMContext(cgm.getLLVMContext()) { +CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, + unsigned protocolClassVersion) + : CGM(cgm), TheModule(CGM.getModule()), VMContext(cgm.getLLVMContext()), + ClassPtrAlias(0), MetaClassPtrAlias(0), RuntimeVersion(runtimeABIVersion), + ProtocolVersion(protocolClassVersion) { + msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend"); + CodeGenTypes &Types = CGM.getTypes(); IntTy = cast<llvm::IntegerType>( - CGM.getTypes().ConvertType(CGM.getContext().IntTy)); + Types.ConvertType(CGM.getContext().IntTy)); LongTy = cast<llvm::IntegerType>( - CGM.getTypes().ConvertType(CGM.getContext().LongTy)); + Types.ConvertType(CGM.getContext().LongTy)); SizeTy = cast<llvm::IntegerType>( - CGM.getTypes().ConvertType(CGM.getContext().getSizeType())); + Types.ConvertType(CGM.getContext().getSizeType())); PtrDiffTy = cast<llvm::IntegerType>( - CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType())); + Types.ConvertType(CGM.getContext().getPointerDiffType())); BoolTy = CGM.getTypes().ConvertType(CGM.getContext().BoolTy); Int8Ty = llvm::Type::getInt8Ty(VMContext); @@ -302,20 +688,54 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) PtrTy = PtrToInt8Ty; // Object type - ASTIdTy = CGM.getContext().getCanonicalType(CGM.getContext().getObjCIdType()); - if (QualType() == ASTIdTy) { - IdTy = PtrToInt8Ty; - } else { + QualType UnqualIdTy = CGM.getContext().getObjCIdType(); + ASTIdTy = CanQualType(); + if (UnqualIdTy != QualType()) { + ASTIdTy = CGM.getContext().getCanonicalType(UnqualIdTy); IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy)); + } else { + IdTy = PtrToInt8Ty; } PtrToIdTy = llvm::PointerType::getUnqual(IdTy); + ObjCSuperTy = llvm::StructType::get(VMContext, IdTy, IdTy, NULL); + PtrToObjCSuperTy = llvm::PointerType::getUnqual(ObjCSuperTy); + + const llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); + + // void objc_exception_throw(id); + ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, NULL); + ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy, NULL); + // int objc_sync_enter(id); + SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy, NULL); + // int objc_sync_exit(id); + SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy, NULL); + + // void objc_enumerationMutation (id) + EnumerationMutationFn.init(&CGM, "objc_enumerationMutation", VoidTy, + IdTy, NULL); + + // id objc_getProperty(id, SEL, ptrdiff_t, BOOL) + GetPropertyFn.init(&CGM, "objc_getProperty", IdTy, IdTy, SelectorTy, + PtrDiffTy, BoolTy, NULL); + // void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, BOOL) + SetPropertyFn.init(&CGM, "objc_setProperty", VoidTy, IdTy, SelectorTy, + PtrDiffTy, IdTy, BoolTy, BoolTy, NULL); + // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL) + GetStructPropertyFn.init(&CGM, "objc_getPropertyStruct", VoidTy, PtrTy, PtrTy, + PtrDiffTy, BoolTy, BoolTy, NULL); + // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL) + SetStructPropertyFn.init(&CGM, "objc_setPropertyStruct", VoidTy, PtrTy, PtrTy, + PtrDiffTy, BoolTy, BoolTy, NULL); + // IMP type std::vector<const llvm::Type*> IMPArgs; IMPArgs.push_back(IdTy); IMPArgs.push_back(SelectorTy); - IMPTy = llvm::FunctionType::get(IdTy, IMPArgs, true); + IMPTy = llvm::PointerType::getUnqual(llvm::FunctionType::get(IdTy, IMPArgs, + true)); + // Don't bother initialising the GC stuff unless we're compiling in GC mode if (CGM.getLangOptions().getGCMode() != LangOptions::NonGC) { // Get selectors needed in GC mode RetainSel = GetNullarySelector("retain", CGM.getContext()); @@ -325,34 +745,21 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm) // Get functions needed in GC mode // id objc_assign_ivar(id, id, ptrdiff_t); - std::vector<const llvm::Type*> Args(1, IdTy); - Args.push_back(PtrToIdTy); - Args.push_back(PtrDiffTy); - llvm::FunctionType *FTy = llvm::FunctionType::get(IdTy, Args, false); - IvarAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_ivar"); + IvarAssignFn.init(&CGM, "objc_assign_ivar", IdTy, IdTy, IdTy, PtrDiffTy, + NULL); // id objc_assign_strongCast (id, id*) - Args.pop_back(); - FTy = llvm::FunctionType::get(IdTy, Args, false); - StrongCastAssignFn = - CGM.CreateRuntimeFunction(FTy, "objc_assign_strongCast"); + StrongCastAssignFn.init(&CGM, "objc_assign_strongCast", IdTy, IdTy, + PtrToIdTy, NULL); // id objc_assign_global(id, id*); - FTy = llvm::FunctionType::get(IdTy, Args, false); - GlobalAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_global"); + GlobalAssignFn.init(&CGM, "objc_assign_global", IdTy, IdTy, PtrToIdTy, + NULL); // id objc_assign_weak(id, id*); - FTy = llvm::FunctionType::get(IdTy, Args, false); - WeakAssignFn = CGM.CreateRuntimeFunction(FTy, "objc_assign_weak"); + WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy, NULL); // id objc_read_weak(id*); - Args.clear(); - Args.push_back(PtrToIdTy); - FTy = llvm::FunctionType::get(IdTy, Args, false); - WeakReadFn = CGM.CreateRuntimeFunction(FTy, "objc_read_weak"); + WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy, NULL); // void *objc_memmove_collectable(void*, void *, size_t); - Args.clear(); - Args.push_back(PtrToInt8Ty); - Args.push_back(PtrToInt8Ty); - Args.push_back(SizeTy); - FTy = llvm::FunctionType::get(IdTy, Args, false); - MemMoveFn = CGM.CreateRuntimeFunction(FTy, "objc_memmove_collectable"); + MemMoveFn.init(&CGM, "objc_memmove_collectable", PtrTy, PtrTy, PtrTy, + SizeTy, NULL); } } @@ -378,79 +785,127 @@ llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder, } llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel, + const std::string &TypeEncoding, bool lval) { + + llvm::SmallVector<TypedSelector, 2> &Types = SelectorTable[Sel]; + llvm::GlobalAlias *SelValue = 0; + + + for (llvm::SmallVectorImpl<TypedSelector>::iterator i = Types.begin(), + e = Types.end() ; i!=e ; i++) { + if (i->first == TypeEncoding) { + SelValue = i->second; + break; + } + } + if (0 == SelValue) { + SelValue = new llvm::GlobalAlias(SelectorTy, + llvm::GlobalValue::PrivateLinkage, + ".objc_selector_"+Sel.getAsString(), NULL, + &TheModule); + Types.push_back(TypedSelector(TypeEncoding, SelValue)); + } + + if (lval) { + llvm::Value *tmp = Builder.CreateAlloca(SelValue->getType()); + Builder.CreateStore(SelValue, tmp); + return tmp; + } + return SelValue; +} + +llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel, bool lval) { - llvm::GlobalAlias *&US = UntypedSelectors[Sel.getAsString()]; - if (US == 0) - US = new llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy), - llvm::GlobalValue::PrivateLinkage, - ".objc_untyped_selector_alias"+Sel.getAsString(), - NULL, &TheModule); - if (lval) - return US; - return Builder.CreateLoad(US); + return GetSelector(Builder, Sel, std::string(), lval); } llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl *Method) { - - std::string SelName = Method->getSelector().getAsString(); std::string SelTypes; CGM.getContext().getObjCEncodingForMethodDecl(Method, SelTypes); - // Typed selectors - TypedSelector Selector = TypedSelector(SelName, - SelTypes); - - // If it's already cached, return it. - if (TypedSelectors[Selector]) { - return Builder.CreateLoad(TypedSelectors[Selector]); - } - - // If it isn't, cache it. - llvm::GlobalAlias *Sel = new llvm::GlobalAlias( - llvm::PointerType::getUnqual(SelectorTy), - llvm::GlobalValue::PrivateLinkage, ".objc_selector_alias" + SelName, - NULL, &TheModule); - TypedSelectors[Selector] = Sel; - - return Builder.CreateLoad(Sel); + return GetSelector(Builder, Method->getSelector(), SelTypes, false); } llvm::Constant *CGObjCGNU::GetEHType(QualType T) { - llvm_unreachable("asking for catch type for ObjC type in GNU runtime"); - return 0; -} + if (!CGM.getLangOptions().CPlusPlus) { + if (T->isObjCIdType() + || T->isObjCQualifiedIdType()) { + // With the old ABI, there was only one kind of catchall, which broke + // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as + // a pointer indicating object catchalls, and NULL to indicate real + // catchalls + if (CGM.getLangOptions().ObjCNonFragileABI) { + return MakeConstantString("@id"); + } else { + return 0; + } + } -llvm::Constant *CGObjCGNU::MakeConstantString(const std::string &Str, - const std::string &Name) { - llvm::Constant *ConstStr = CGM.GetAddrOfConstantCString(Str, Name.c_str()); - return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2); -} -llvm::Constant *CGObjCGNU::ExportUniqueString(const std::string &Str, - const std::string prefix) { - std::string name = prefix + Str; - llvm::Constant *ConstStr = TheModule.getGlobalVariable(name); - if (!ConstStr) { - llvm::Constant *value = llvm::ConstantArray::get(VMContext, Str, true); - ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true, - llvm::GlobalValue::LinkOnceODRLinkage, value, prefix + Str); + // All other types should be Objective-C interface pointer types. + const ObjCObjectPointerType *OPT = + T->getAs<ObjCObjectPointerType>(); + assert(OPT && "Invalid @catch type."); + const ObjCInterfaceDecl *IDecl = + OPT->getObjectType()->getInterface(); + assert(IDecl && "Invalid @catch type."); + return MakeConstantString(IDecl->getIdentifier()->getName()); + } + // For Objective-C++, we want to provide the ability to catch both C++ and + // Objective-C objects in the same function. + + // There's a particular fixed type info for 'id'. + if (T->isObjCIdType() || + T->isObjCQualifiedIdType()) { + llvm::Constant *IDEHType = + CGM.getModule().getGlobalVariable("__objc_id_type_info"); + if (!IDEHType) + IDEHType = + new llvm::GlobalVariable(CGM.getModule(), PtrToInt8Ty, + false, + llvm::GlobalValue::ExternalLinkage, + 0, "__objc_id_type_info"); + return llvm::ConstantExpr::getBitCast(IDEHType, PtrToInt8Ty); } - return llvm::ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2); -} - -llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::StructType *Ty, - std::vector<llvm::Constant*> &V, llvm::StringRef Name, - llvm::GlobalValue::LinkageTypes linkage) { - llvm::Constant *C = llvm::ConstantStruct::get(Ty, V); - return new llvm::GlobalVariable(TheModule, Ty, false, - linkage, C, Name); -} -llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty, - std::vector<llvm::Constant*> &V, llvm::StringRef Name, - llvm::GlobalValue::LinkageTypes linkage) { - llvm::Constant *C = llvm::ConstantArray::get(Ty, V); - return new llvm::GlobalVariable(TheModule, Ty, false, - linkage, C, Name); + const ObjCObjectPointerType *PT = + T->getAs<ObjCObjectPointerType>(); + assert(PT && "Invalid @catch type."); + const ObjCInterfaceType *IT = PT->getInterfaceType(); + assert(IT && "Invalid @catch type."); + std::string className = IT->getDecl()->getIdentifier()->getName(); + + std::string typeinfoName = "__objc_eh_typeinfo_" + className; + + // Return the existing typeinfo if it exists + llvm::Constant *typeinfo = TheModule.getGlobalVariable(typeinfoName); + if (typeinfo) return typeinfo; + + // Otherwise create it. + + // vtable for gnustep::libobjc::__objc_class_type_info + // It's quite ugly hard-coding this. Ideally we'd generate it using the host + // platform's name mangling. + const char *vtableName = "_ZTVN7gnustep7libobjc22__objc_class_type_infoE"; + llvm::Constant *Vtable = TheModule.getGlobalVariable(vtableName); + if (!Vtable) { + Vtable = new llvm::GlobalVariable(TheModule, PtrToInt8Ty, true, + llvm::GlobalValue::ExternalLinkage, 0, vtableName); + } + llvm::Constant *Two = llvm::ConstantInt::get(IntTy, 2); + Vtable = llvm::ConstantExpr::getGetElementPtr(Vtable, &Two, 1); + Vtable = llvm::ConstantExpr::getBitCast(Vtable, PtrToInt8Ty); + + llvm::Constant *typeName = + ExportUniqueString(className, "__objc_eh_typename_"); + + std::vector<llvm::Constant*> fields; + fields.push_back(Vtable); + fields.push_back(typeName); + llvm::Constant *TI = + MakeGlobal(llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, + NULL), fields, "__objc_eh_typeinfo_" + className, + llvm::GlobalValue::LinkOnceODRLinkage); + return llvm::ConstantExpr::getBitCast(TI, PtrToInt8Ty); } /// Generate an NSConstantString object. @@ -479,8 +934,8 @@ llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) { ///Generates a message send where the super is the receiver. This is a message ///send to self with special delivery semantics indicating which class's method ///should be called. -CodeGen::RValue -CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, +RValue +CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, @@ -505,18 +960,13 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, CallArgList ActualArgs; - ActualArgs.push_back( - std::make_pair(RValue::get(Builder.CreateBitCast(Receiver, IdTy)), - ASTIdTy)); - ActualArgs.push_back(std::make_pair(RValue::get(cmd), - CGF.getContext().getObjCSelType())); + ActualArgs.add(RValue::get(EnforceType(Builder, Receiver, IdTy)), ASTIdTy); + ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType()); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); CodeGenTypes &Types = CGM.getTypes(); const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, ActualArgs, FunctionType::ExtInfo()); - const llvm::FunctionType *impType = - Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); llvm::Value *ReceiverClass = 0; if (isCategoryImpl) { @@ -570,43 +1020,20 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0)); Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1)); - // Get the IMP - std::vector<const llvm::Type*> Params; - Params.push_back(llvm::PointerType::getUnqual(ObjCSuperTy)); - Params.push_back(SelectorTy); - - llvm::Value *lookupArgs[] = {ObjCSuper, cmd}; - llvm::Value *imp; - - if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { - // The lookup function returns a slot, which can be safely cached. - llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy, - IntTy, llvm::PointerType::getUnqual(impType), NULL); - - llvm::Constant *lookupFunction = - CGM.CreateRuntimeFunction(llvm::FunctionType::get( - llvm::PointerType::getUnqual(SlotTy), Params, true), - "objc_slot_lookup_super"); - - llvm::CallInst *slot = Builder.CreateCall(lookupFunction, lookupArgs, - lookupArgs+2); - slot->setOnlyReadsMemory(); + ObjCSuper = EnforceType(Builder, ObjCSuper, PtrToObjCSuperTy); + const llvm::FunctionType *impType = + Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); - imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); - } else { - llvm::Constant *lookupFunction = - CGM.CreateRuntimeFunction(llvm::FunctionType::get( - llvm::PointerType::getUnqual(impType), Params, true), - "objc_msg_lookup_super"); - imp = Builder.CreateCall(lookupFunction, lookupArgs, lookupArgs+2); - } + // Get the IMP + llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd); + imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType)); llvm::Value *impMD[] = { llvm::MDString::get(VMContext, Sel.getAsString()), llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()), llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), IsClassMessage) }; - llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3); + llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD); llvm::Instruction *call; RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs, @@ -616,8 +1043,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, } /// Generate code for a message send expression. -CodeGen::RValue -CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, +RValue +CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, Selector Sel, @@ -646,11 +1073,10 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, // paragraph and insist on sending messages to nil that have structure // returns. With GCC, this generates a random return value (whatever happens // to be on the stack / in those registers at the time) on most platforms, - // and generates a SegV on SPARC. With LLVM it corrupts the stack. - bool isPointerSizedReturn = false; - if (ResultType->isAnyPointerType() || - ResultType->isIntegralOrEnumerationType() || ResultType->isVoidType()) - isPointerSizedReturn = true; + // and generates an illegal instruction trap on SPARC. With LLVM it corrupts + // the stack. + bool isPointerSizedReturn = (ResultType->isAnyPointerType() || + ResultType->isIntegralOrEnumerationType() || ResultType->isVoidType()); llvm::BasicBlock *startBB = 0; llvm::BasicBlock *messageBB = 0; @@ -673,13 +1099,22 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, cmd = GetSelector(Builder, Method); else cmd = GetSelector(Builder, Sel); - CallArgList ActualArgs; + cmd = EnforceType(Builder, cmd, SelectorTy); + Receiver = EnforceType(Builder, Receiver, IdTy); - Receiver = Builder.CreateBitCast(Receiver, IdTy); - ActualArgs.push_back( - std::make_pair(RValue::get(Receiver), ASTIdTy)); - ActualArgs.push_back(std::make_pair(RValue::get(cmd), - CGF.getContext().getObjCSelType())); + llvm::Value *impMD[] = { + llvm::MDString::get(VMContext, Sel.getAsString()), + llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""), + llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), Class!=0) + }; + llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD); + + // Get the IMP to call + llvm::Value *imp = LookupIMP(CGF, Receiver, cmd, node); + + CallArgList ActualArgs; + ActualArgs.add(RValue::get(Receiver), ASTIdTy); + ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType()); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); CodeGenTypes &Types = CGM.getTypes(); @@ -687,72 +1122,12 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, FunctionType::ExtInfo()); const llvm::FunctionType *impType = Types.GetFunctionType(FnInfo, Method ? Method->isVariadic() : false); - - llvm::Value *impMD[] = { - llvm::MDString::get(VMContext, Sel.getAsString()), - llvm::MDString::get(VMContext, Class ? Class->getNameAsString() :""), - llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext), Class!=0) - }; - llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD, 3); + imp = EnforceType(Builder, imp, llvm::PointerType::getUnqual(impType)); - llvm::Value *imp; // For sender-aware dispatch, we pass the sender as the third argument to a // lookup function. When sending messages from C code, the sender is nil. // objc_msg_lookup_sender(id *receiver, SEL selector, id sender); - if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { - - std::vector<const llvm::Type*> Params; - llvm::Value *ReceiverPtr = CGF.CreateTempAlloca(Receiver->getType()); - Builder.CreateStore(Receiver, ReceiverPtr); - Params.push_back(ReceiverPtr->getType()); - Params.push_back(SelectorTy); - llvm::Value *self; - - if (isa<ObjCMethodDecl>(CGF.CurCodeDecl)) { - self = CGF.LoadObjCSelf(); - } else { - self = llvm::ConstantPointerNull::get(IdTy); - } - - Params.push_back(self->getType()); - - // The lookup function returns a slot, which can be safely cached. - llvm::Type *SlotTy = llvm::StructType::get(VMContext, PtrTy, PtrTy, PtrTy, - IntTy, llvm::PointerType::getUnqual(impType), NULL); - llvm::Constant *lookupFunction = - CGM.CreateRuntimeFunction(llvm::FunctionType::get( - llvm::PointerType::getUnqual(SlotTy), Params, true), - "objc_msg_lookup_sender"); - - // The lookup function is guaranteed not to capture the receiver pointer. - if (llvm::Function *LookupFn = dyn_cast<llvm::Function>(lookupFunction)) { - LookupFn->setDoesNotCapture(1); - } - - llvm::CallInst *slot = - Builder.CreateCall3(lookupFunction, ReceiverPtr, cmd, self); - slot->setOnlyReadsMemory(); - slot->setMetadata(msgSendMDKind, node); - - imp = Builder.CreateLoad(Builder.CreateStructGEP(slot, 4)); - - // The lookup function may have changed the receiver, so make sure we use - // the new one. - ActualArgs[0] = std::make_pair(RValue::get( - Builder.CreateLoad(ReceiverPtr, true)), ASTIdTy); - } else { - std::vector<const llvm::Type*> Params; - Params.push_back(Receiver->getType()); - Params.push_back(SelectorTy); - llvm::Constant *lookupFunction = - CGM.CreateRuntimeFunction(llvm::FunctionType::get( - llvm::PointerType::getUnqual(impType), Params, true), - "objc_msg_lookup"); - - imp = Builder.CreateCall2(lookupFunction, Receiver, cmd); - cast<llvm::CallInst>(imp)->setMetadata(msgSendMDKind, node); - } llvm::Instruction *call; RValue msgRet = CGF.EmitCall(FnInfo, imp, Return, ActualArgs, 0, &call); @@ -765,13 +1140,13 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, CGF.EmitBlock(continueBB); if (msgRet.isScalar()) { llvm::Value *v = msgRet.getScalarVal(); - llvm::PHINode *phi = Builder.CreatePHI(v->getType()); + llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2); phi->addIncoming(v, messageBB); phi->addIncoming(llvm::Constant::getNullValue(v->getType()), startBB); msgRet = RValue::get(phi); } else if (msgRet.isAggregate()) { llvm::Value *v = msgRet.getAggregateAddr(); - llvm::PHINode *phi = Builder.CreatePHI(v->getType()); + llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2); const llvm::PointerType *RetTy = cast<llvm::PointerType>(v->getType()); llvm::AllocaInst *NullVal = CGF.CreateTempAlloca(RetTy->getElementType(), "null"); @@ -782,11 +1157,11 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, msgRet = RValue::getAggregate(phi); } else /* isComplex() */ { std::pair<llvm::Value*,llvm::Value*> v = msgRet.getComplexVal(); - llvm::PHINode *phi = Builder.CreatePHI(v.first->getType()); + llvm::PHINode *phi = Builder.CreatePHI(v.first->getType(), 2); phi->addIncoming(v.first, messageBB); phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()), startBB); - llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType()); + llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType(), 2); phi2->addIncoming(v.second, messageBB); phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()), startBB); @@ -798,8 +1173,8 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, /// Generates a MethodList. Used in construction of a objc_class and /// objc_category structures. -llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName, - const std::string &CategoryName, +llvm::Constant *CGObjCGNU::GenerateMethodList(const llvm::StringRef &ClassName, + const llvm::StringRef &CategoryName, const llvm::SmallVectorImpl<Selector> &MethodSels, const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes, bool isClassMethodList) { @@ -809,24 +1184,24 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName, llvm::StructType *ObjCMethodTy = llvm::StructType::get(VMContext, PtrToInt8Ty, // Really a selector, but the runtime creates it us. PtrToInt8Ty, // Method types - llvm::PointerType::getUnqual(IMPTy), //Method pointer + IMPTy, //Method pointer NULL); std::vector<llvm::Constant*> Methods; std::vector<llvm::Constant*> Elements; for (unsigned int i = 0, e = MethodTypes.size(); i < e; ++i) { Elements.clear(); - if (llvm::Constant *Method = + llvm::Constant *Method = TheModule.getFunction(SymbolNameForMethod(ClassName, CategoryName, - MethodSels[i].getAsString(), - isClassMethodList))) { - llvm::Constant *C = MakeConstantString(MethodSels[i].getAsString()); - Elements.push_back(C); - Elements.push_back(MethodTypes[i]); - Method = llvm::ConstantExpr::getBitCast(Method, - llvm::PointerType::getUnqual(IMPTy)); - Elements.push_back(Method); - Methods.push_back(llvm::ConstantStruct::get(ObjCMethodTy, Elements)); - } + MethodSels[i], + isClassMethodList)); + assert(Method && "Can't generate metadata for method that doesn't exist"); + llvm::Constant *C = MakeConstantString(MethodSels[i].getAsString()); + Elements.push_back(C); + Elements.push_back(MethodTypes[i]); + Method = llvm::ConstantExpr::getBitCast(Method, + IMPTy); + Elements.push_back(Method); + Methods.push_back(llvm::ConstantStruct::get(ObjCMethodTy, Elements)); } // Array of method structures @@ -951,8 +1326,10 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( Elements.push_back(llvm::ConstantInt::get(LongTy, info)); if (isMeta) { llvm::TargetData td(&TheModule); - Elements.push_back(llvm::ConstantInt::get(LongTy, - td.getTypeSizeInBits(ClassTy)/8)); + Elements.push_back( + llvm::ConstantInt::get(LongTy, + td.getTypeSizeInBits(ClassTy) / + CGM.getContext().getCharWidth())); } else Elements.push_back(InstanceSize); Elements.push_back(IVars); @@ -1063,10 +1440,9 @@ llvm::Constant *CGObjCGNU::GenerateEmptyProtocol( std::vector<llvm::Constant*> Elements; // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. - int Version = CGM.getContext().getLangOptions().ObjCNonFragileABI ? - NonFragileProtocolVersion : ProtocolVersion; Elements.push_back(llvm::ConstantExpr::getIntToPtr( - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Version), IdTy)); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + ProtocolVersion), IdTy)); Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name")); Elements.push_back(ProtocolList); Elements.push_back(MethodList); @@ -1225,10 +1601,9 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { std::vector<llvm::Constant*> Elements; // The isa pointer must be set to a magic number so the runtime knows it's // the correct layout. - int Version = CGM.getContext().getLangOptions().ObjCNonFragileABI ? - NonFragileProtocolVersion : ProtocolVersion; Elements.push_back(llvm::ConstantExpr::getIntToPtr( - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), Version), IdTy)); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + ProtocolVersion), IdTy)); Elements.push_back(MakeConstantString(ProtocolName, ".objc_protocol_name")); Elements.push_back(ProtocolList); Elements.push_back(InstanceMethodList); @@ -1486,13 +1861,9 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { "__objc_ivar_offset_value_" + ClassName +"." + IVD->getNameAsString())); } - llvm::Constant *IvarOffsetArrayInit = - llvm::ConstantArray::get(llvm::ArrayType::get(PtrToIntTy, - IvarOffsetValues.size()), IvarOffsetValues); - llvm::GlobalVariable *IvarOffsetArray = new llvm::GlobalVariable(TheModule, - IvarOffsetArrayInit->getType(), false, - llvm::GlobalValue::InternalLinkage, IvarOffsetArrayInit, - ".ivar.offsets"); + llvm::GlobalVariable *IvarOffsetArray = + MakeGlobalArray(PtrToIntTy, IvarOffsetValues, ".ivar.offsets"); + // Collect information about instance methods llvm::SmallVector<Selector, 16> InstanceMethodSels; @@ -1620,8 +1991,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { llvm::Function *CGObjCGNU::ModuleInitFunction() { // Only emit an ObjC load function if no Objective-C stuff has been called if (Classes.empty() && Categories.empty() && ConstantStrings.empty() && - ExistingProtocols.empty() && TypedSelectors.empty() && - UntypedSelectors.empty()) + ExistingProtocols.empty() && SelectorTable.empty()) return NULL; // Add all referenced protocols to a category. @@ -1630,12 +2000,10 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { const llvm::StructType *SelStructTy = dyn_cast<llvm::StructType>( SelectorTy->getElementType()); const llvm::Type *SelStructPtrTy = SelectorTy; - bool isSelOpaque = false; if (SelStructTy == 0) { SelStructTy = llvm::StructType::get(VMContext, PtrToInt8Ty, PtrToInt8Ty, NULL); SelStructPtrTy = llvm::PointerType::getUnqual(SelStructTy); - isSelOpaque = true; } // Name the ObjC types to make the IR a bit easier to read @@ -1652,7 +2020,9 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { ConstantStrings.push_back(NULLPtr); llvm::StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass; + if (StringClass.empty()) StringClass = "NXConstantString"; + Elements.push_back(MakeConstantString(StringClass, ".objc_static_class_name")); Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy, @@ -1682,75 +2052,62 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { Elements.clear(); // Pointer to an array of selectors used in this module. std::vector<llvm::Constant*> Selectors; - for (std::map<TypedSelector, llvm::GlobalAlias*>::iterator - iter = TypedSelectors.begin(), iterEnd = TypedSelectors.end(); - iter != iterEnd ; ++iter) { - Elements.push_back(ExportUniqueString(iter->first.first, ".objc_sel_name")); - Elements.push_back(MakeConstantString(iter->first.second, - ".objc_sel_types")); - Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements)); - Elements.clear(); - } - for (llvm::StringMap<llvm::GlobalAlias*>::iterator - iter = UntypedSelectors.begin(), iterEnd = UntypedSelectors.end(); - iter != iterEnd; ++iter) { - Elements.push_back( - ExportUniqueString(iter->getKeyData(), ".objc_sel_name")); - Elements.push_back(NULLPtr); - Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements)); - Elements.clear(); + std::vector<llvm::GlobalAlias*> SelectorAliases; + for (SelectorMap::iterator iter = SelectorTable.begin(), + iterEnd = SelectorTable.end(); iter != iterEnd ; ++iter) { + + std::string SelNameStr = iter->first.getAsString(); + llvm::Constant *SelName = ExportUniqueString(SelNameStr, ".objc_sel_name"); + + llvm::SmallVectorImpl<TypedSelector> &Types = iter->second; + for (llvm::SmallVectorImpl<TypedSelector>::iterator i = Types.begin(), + e = Types.end() ; i!=e ; i++) { + + llvm::Constant *SelectorTypeEncoding = NULLPtr; + if (!i->first.empty()) + SelectorTypeEncoding = MakeConstantString(i->first, ".objc_sel_types"); + + Elements.push_back(SelName); + Elements.push_back(SelectorTypeEncoding); + Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements)); + Elements.clear(); + + // Store the selector alias for later replacement + SelectorAliases.push_back(i->second); + } } + unsigned SelectorCount = Selectors.size(); + // NULL-terminate the selector list. This should not actually be required, + // because the selector list has a length field. Unfortunately, the GCC + // runtime decides to ignore the length field and expects a NULL terminator, + // and GCC cooperates with this by always setting the length to 0. Elements.push_back(NULLPtr); Elements.push_back(NULLPtr); Selectors.push_back(llvm::ConstantStruct::get(SelStructTy, Elements)); Elements.clear(); + // Number of static selectors - Elements.push_back(llvm::ConstantInt::get(LongTy, Selectors.size() )); - llvm::Constant *SelectorList = MakeGlobal( - llvm::ArrayType::get(SelStructTy, Selectors.size()), Selectors, + Elements.push_back(llvm::ConstantInt::get(LongTy, SelectorCount)); + llvm::Constant *SelectorList = MakeGlobalArray(SelStructTy, Selectors, ".objc_selector_list"); Elements.push_back(llvm::ConstantExpr::getBitCast(SelectorList, SelStructPtrTy)); // Now that all of the static selectors exist, create pointers to them. - int index = 0; - for (std::map<TypedSelector, llvm::GlobalAlias*>::iterator - iter=TypedSelectors.begin(), iterEnd =TypedSelectors.end(); - iter != iterEnd; ++iter) { + for (unsigned int i=0 ; i<SelectorCount ; i++) { + llvm::Constant *Idxs[] = {Zeros[0], - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]}; - llvm::Constant *SelPtr = new llvm::GlobalVariable(TheModule, SelStructPtrTy, - true, llvm::GlobalValue::LinkOnceODRLinkage, - llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2), - MangleSelectorTypes(".objc_sel_ptr"+iter->first.first+"."+ - iter->first.second)); + llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), i), Zeros[0]}; + // FIXME: We're generating redundant loads and stores here! + llvm::Constant *SelPtr = llvm::ConstantExpr::getGetElementPtr(SelectorList, + Idxs, 2); // If selectors are defined as an opaque type, cast the pointer to this // type. - if (isSelOpaque) { - SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, - llvm::PointerType::getUnqual(SelectorTy)); - } - (*iter).second->replaceAllUsesWith(SelPtr); - (*iter).second->eraseFromParent(); - } - for (llvm::StringMap<llvm::GlobalAlias*>::iterator - iter=UntypedSelectors.begin(), iterEnd = UntypedSelectors.end(); - iter != iterEnd; iter++) { - llvm::Constant *Idxs[] = {Zeros[0], - llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]}; - llvm::Constant *SelPtr = new llvm::GlobalVariable(TheModule, SelStructPtrTy, - true, llvm::GlobalValue::LinkOnceODRLinkage, - llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2), - MangleSelectorTypes(std::string(".objc_sel_ptr")+iter->getKey().str())); - // If selectors are defined as an opaque type, cast the pointer to this - // type. - if (isSelOpaque) { - SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, - llvm::PointerType::getUnqual(SelectorTy)); - } - (*iter).second->replaceAllUsesWith(SelPtr); - (*iter).second->eraseFromParent(); + SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, SelectorTy); + SelectorAliases[i]->replaceAllUsesWith(SelPtr); + SelectorAliases[i]->eraseFromParent(); } + // Number of classes defined. Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext), Classes.size())); @@ -1772,19 +2129,22 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { llvm::StructType * ModuleTy = llvm::StructType::get(VMContext, LongTy, LongTy, PtrToInt8Ty, llvm::PointerType::getUnqual(SymTabTy), NULL); Elements.clear(); - // Runtime version used for compatibility checking. - if (CGM.getContext().getLangOptions().ObjCNonFragileABI) { - Elements.push_back(llvm::ConstantInt::get(LongTy, - NonFragileRuntimeVersion)); - } else { - Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion)); - } + // Runtime version, used for ABI compatibility checking. + Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion)); // sizeof(ModuleTy) llvm::TargetData td(&TheModule); - Elements.push_back(llvm::ConstantInt::get(LongTy, - td.getTypeSizeInBits(ModuleTy)/8)); - //FIXME: Should be the path to the file where this module was declared - Elements.push_back(NULLPtr); + Elements.push_back( + llvm::ConstantInt::get(LongTy, + td.getTypeSizeInBits(ModuleTy) / + CGM.getContext().getCharWidth())); + + // The path to the source file where this module was declared + SourceManager &SM = CGM.getContext().getSourceManager(); + const FileEntry *mainFile = SM.getFileEntryForID(SM.getMainFileID()); + std::string path = + std::string(mainFile->getDir()->getName()) + '/' + mainFile->getName(); + Elements.push_back(MakeConstantString(path, ".objc_source_file_name")); + Elements.push_back(SymTab); llvm::Value *Module = MakeGlobal(ModuleTy, Elements); @@ -1813,9 +2173,9 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) { const ObjCCategoryImplDecl *OCD = dyn_cast<ObjCCategoryImplDecl>(OMD->getDeclContext()); - std::string CategoryName = OCD ? OCD->getNameAsString() : ""; - std::string ClassName = CD->getName(); - std::string MethodName = OMD->getSelector().getAsString(); + llvm::StringRef CategoryName = OCD ? OCD->getName() : ""; + llvm::StringRef ClassName = CD->getName(); + Selector MethodName = OMD->getSelector(); bool isClassMethod = !OMD->isInstanceMethod(); CodeGenTypes &Types = CGM.getTypes(); @@ -1833,121 +2193,31 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, } llvm::Function *CGObjCGNU::GetPropertyGetFunction() { - std::vector<const llvm::Type*> Params; - Params.push_back(IdTy); - Params.push_back(SelectorTy); - Params.push_back(SizeTy); - Params.push_back(BoolTy); - // void objc_getProperty (id, SEL, ptrdiff_t, bool) - const llvm::FunctionType *FTy = - llvm::FunctionType::get(IdTy, Params, false); - return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy, - "objc_getProperty")); + return GetPropertyFn; } llvm::Function *CGObjCGNU::GetPropertySetFunction() { - std::vector<const llvm::Type*> Params; - Params.push_back(IdTy); - Params.push_back(SelectorTy); - Params.push_back(SizeTy); - Params.push_back(IdTy); - Params.push_back(BoolTy); - Params.push_back(BoolTy); - // void objc_setProperty (id, SEL, ptrdiff_t, id, bool, bool) - const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); - return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy, - "objc_setProperty")); + return SetPropertyFn; } llvm::Function *CGObjCGNU::GetGetStructFunction() { - std::vector<const llvm::Type*> Params; - Params.push_back(PtrTy); - Params.push_back(PtrTy); - Params.push_back(PtrDiffTy); - Params.push_back(BoolTy); - Params.push_back(BoolTy); - // objc_setPropertyStruct (void*, void*, ptrdiff_t, BOOL, BOOL) - const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); - return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy, - "objc_getPropertyStruct")); + return GetStructPropertyFn; } llvm::Function *CGObjCGNU::GetSetStructFunction() { - std::vector<const llvm::Type*> Params; - Params.push_back(PtrTy); - Params.push_back(PtrTy); - Params.push_back(PtrDiffTy); - Params.push_back(BoolTy); - Params.push_back(BoolTy); - // objc_setPropertyStruct (void*, void*, ptrdiff_t, BOOL, BOOL) - const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); - return cast<llvm::Function>(CGM.CreateRuntimeFunction(FTy, - "objc_setPropertyStruct")); + return SetStructPropertyFn; } llvm::Constant *CGObjCGNU::EnumerationMutationFunction() { - CodeGen::CodeGenTypes &Types = CGM.getTypes(); - ASTContext &Ctx = CGM.getContext(); - // void objc_enumerationMutation (id) - llvm::SmallVector<CanQualType,1> Params; - Params.push_back(ASTIdTy); - const llvm::FunctionType *FTy = - Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params, - FunctionType::ExtInfo()), false); - return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation"); + return EnumerationMutationFn; } -namespace { - struct CallSyncExit : EHScopeStack::Cleanup { - llvm::Value *SyncExitFn; - llvm::Value *SyncArg; - CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg) - : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {} - - void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { - CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow(); - } - }; -} - -void CGObjCGNU::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, +void CGObjCGNU::EmitSynchronizedStmt(CodeGenFunction &CGF, const ObjCAtSynchronizedStmt &S) { - std::vector<const llvm::Type*> Args(1, IdTy); - llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); - - // Evaluate the lock operand. This should dominate the cleanup. - llvm::Value *SyncArg = - CGF.EmitScalarExpr(S.getSynchExpr()); - - // Acquire the lock. - llvm::Value *SyncEnter = CGM.CreateRuntimeFunction(FTy, "objc_sync_enter"); - SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy); - CGF.Builder.CreateCall(SyncEnter, SyncArg); - - // Register an all-paths cleanup to release the lock. - llvm::Value *SyncExit = CGM.CreateRuntimeFunction(FTy, "objc_sync_exit"); - CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, SyncExit, SyncArg); - - // Emit the body of the statement. - CGF.EmitStmt(S.getSynchBody()); - - // Pop the lock-release cleanup. - CGF.PopCleanupBlock(); + EmitAtSynchronizedStmt(CGF, S, SyncEnterFn, SyncExitFn); } -namespace { - struct CatchHandler { - const VarDecl *Variable; - const Stmt *Body; - llvm::BasicBlock *Block; - llvm::Value *TypeInfo; - }; -} -void CGObjCGNU::EmitTryStmt(CodeGen::CodeGenFunction &CGF, +void CGObjCGNU::EmitTryStmt(CodeGenFunction &CGF, const ObjCAtTryStmt &S) { // Unlike the Apple non-fragile runtimes, which also uses // unwind-based zero cost exceptions, the GNU Objective C runtime's @@ -1957,127 +2227,17 @@ void CGObjCGNU::EmitTryStmt(CodeGen::CodeGenFunction &CGF, // catch handlers with calls to __blah_begin_catch/__blah_end_catch // (or even _Unwind_DeleteException), but probably doesn't // interoperate very well with foreign exceptions. - - // Jump destination for falling out of catch bodies. - CodeGenFunction::JumpDest Cont; - if (S.getNumCatchStmts()) - Cont = CGF.getJumpDestInCurrentScope("eh.cont"); - - // We handle @finally statements by pushing them as a cleanup - // before entering the catch. - CodeGenFunction::FinallyInfo FinallyInfo; - if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) { - std::vector<const llvm::Type*> Args(1, IdTy); - llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); - llvm::Constant *Rethrow = - CGM.CreateRuntimeFunction(FTy, "objc_exception_throw"); - - FinallyInfo = CGF.EnterFinallyBlock(Finally->getFinallyBody(), 0, 0, - Rethrow); - } - - llvm::SmallVector<CatchHandler, 8> Handlers; - - // Enter the catch, if there is one. - if (S.getNumCatchStmts()) { - for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) { - const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I); - const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); - - Handlers.push_back(CatchHandler()); - CatchHandler &Handler = Handlers.back(); - Handler.Variable = CatchDecl; - Handler.Body = CatchStmt->getCatchBody(); - Handler.Block = CGF.createBasicBlock("catch"); - - // @catch() and @catch(id) both catch any ObjC exception. - // Treat them as catch-alls. - // FIXME: this is what this code was doing before, but should 'id' - // really be catching foreign exceptions? - if (!CatchDecl - || CatchDecl->getType()->isObjCIdType() - || CatchDecl->getType()->isObjCQualifiedIdType()) { - - Handler.TypeInfo = 0; // catch-all - - // Don't consider any other catches. - break; - } - - // All other types should be Objective-C interface pointer types. - const ObjCObjectPointerType *OPT = - CatchDecl->getType()->getAs<ObjCObjectPointerType>(); - assert(OPT && "Invalid @catch type."); - const ObjCInterfaceDecl *IDecl = - OPT->getObjectType()->getInterface(); - assert(IDecl && "Invalid @catch type."); - Handler.TypeInfo = MakeConstantString(IDecl->getNameAsString()); - } - - EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size()); - for (unsigned I = 0, E = Handlers.size(); I != E; ++I) - Catch->setHandler(I, Handlers[I].TypeInfo, Handlers[I].Block); - } - - // Emit the try body. - CGF.EmitStmt(S.getTryBody()); - - // Leave the try. - if (S.getNumCatchStmts()) - CGF.EHStack.popCatch(); - - // Remember where we were. - CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); - - // Emit the handlers. - for (unsigned I = 0, E = Handlers.size(); I != E; ++I) { - CatchHandler &Handler = Handlers[I]; - CGF.EmitBlock(Handler.Block); - - llvm::Value *Exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot()); - - // Bind the catch parameter if it exists. - if (const VarDecl *CatchParam = Handler.Variable) { - const llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType()); - Exn = CGF.Builder.CreateBitCast(Exn, CatchType); - - CGF.EmitAutoVarDecl(*CatchParam); - CGF.Builder.CreateStore(Exn, CGF.GetAddrOfLocalVar(CatchParam)); - } - - CGF.ObjCEHValueStack.push_back(Exn); - CGF.EmitStmt(Handler.Body); - CGF.ObjCEHValueStack.pop_back(); - - CGF.EmitBranchThroughCleanup(Cont); - } - - // Go back to the try-statement fallthrough. - CGF.Builder.restoreIP(SavedIP); - - // Pop out of the finally. - if (S.getFinallyStmt()) - CGF.ExitFinallyBlock(FinallyInfo); - - if (Cont.isValid()) { - if (Cont.getBlock()->use_empty()) - delete Cont.getBlock(); - else - CGF.EmitBlock(Cont.getBlock()); - } + // + // In Objective-C++ mode, we actually emit something equivalent to the C++ + // exception handler. + EmitTryCatchStmt(CGF, S, EnterCatchFn, ExitCatchFn, ExceptionReThrowFn); + return ; } -void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, +void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF, const ObjCAtThrowStmt &S) { llvm::Value *ExceptionAsObject; - std::vector<const llvm::Type*> Args(1, IdTy); - llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Args, false); - llvm::Value *ThrowFn = - CGM.CreateRuntimeFunction(FTy, "objc_exception_throw"); - if (const Expr *ThrowExpr = S.getThrowExpr()) { llvm::Value *Exception = CGF.EmitScalarExpr(ThrowExpr); ExceptionAsObject = Exception; @@ -2100,24 +2260,24 @@ void CGObjCGNU::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, // as a result of stupidity. llvm::BasicBlock *UnwindBB = CGF.getInvokeDest(); if (!UnwindBB) { - CGF.Builder.CreateCall(ThrowFn, ExceptionAsObject); + CGF.Builder.CreateCall(ExceptionThrowFn, ExceptionAsObject); CGF.Builder.CreateUnreachable(); } else { - CGF.Builder.CreateInvoke(ThrowFn, UnwindBB, UnwindBB, &ExceptionAsObject, + CGF.Builder.CreateInvoke(ExceptionThrowFn, UnwindBB, UnwindBB, &ExceptionAsObject, &ExceptionAsObject+1); } // Clear the insertion point to indicate we are in unreachable code. CGF.Builder.ClearInsertionPoint(); } -llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, +llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF, llvm::Value *AddrWeakObj) { CGBuilderTy B = CGF.Builder; AddrWeakObj = EnforceType(B, AddrWeakObj, IdTy); return B.CreateCall(WeakReadFn, AddrWeakObj); } -void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, +void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { CGBuilderTy B = CGF.Builder; src = EnforceType(B, src, IdTy); @@ -2125,7 +2285,7 @@ void CGObjCGNU::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, B.CreateCall2(WeakAssignFn, src, dst); } -void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, +void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst, bool threadlocal) { CGBuilderTy B = CGF.Builder; @@ -2138,7 +2298,7 @@ void CGObjCGNU::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, assert(false && "EmitObjCGlobalAssign - Threal Local API NYI"); } -void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, +void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst, llvm::Value *ivarOffset) { CGBuilderTy B = CGF.Builder; @@ -2147,7 +2307,7 @@ void CGObjCGNU::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, B.CreateCall3(IvarAssignFn, src, dst, ivarOffset); } -void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, +void CGObjCGNU::EmitObjCStrongCastAssign(CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { CGBuilderTy B = CGF.Builder; src = EnforceType(B, src, IdTy); @@ -2155,7 +2315,7 @@ void CGObjCGNU::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, B.CreateCall2(StrongCastAssignFn, src, dst); } -void CGObjCGNU::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, +void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF, llvm::Value *DestPtr, llvm::Value *SrcPtr, llvm::Value *Size) { @@ -2212,7 +2372,7 @@ llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( return IvarOffsetPointer; } -LValue CGObjCGNU::EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, +LValue CGObjCGNU::EmitObjCValueForIvar(CodeGenFunction &CGF, QualType ObjectTy, llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, @@ -2240,19 +2400,23 @@ static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, return 0; } -llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGen::CodeGenFunction &CGF, +llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) { if (CGM.getLangOptions().ObjCNonFragileABI) { Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar); - return CGF.Builder.CreateLoad(CGF.Builder.CreateLoad( - ObjCIvarOffsetVariable(Interface, Ivar), false, "ivar")); + return CGF.Builder.CreateZExtOrBitCast( + CGF.Builder.CreateLoad(CGF.Builder.CreateLoad( + ObjCIvarOffsetVariable(Interface, Ivar), false, "ivar")), + PtrDiffTy); } uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar); - return llvm::ConstantInt::get(LongTy, Offset, "ivar"); + return llvm::ConstantInt::get(PtrDiffTy, Offset, "ivar"); } -CodeGen::CGObjCRuntime * -CodeGen::CreateGNUObjCRuntime(CodeGen::CodeGenModule &CGM) { - return new CGObjCGNU(CGM); +CGObjCRuntime * +clang::CodeGen::CreateGNUObjCRuntime(CodeGenModule &CGM) { + if (CGM.getLangOptions().ObjCNonFragileABI) + return new CGObjCGNUstep(CGM); + return new CGObjCGCC(CGM); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp index 8dbd85f..2b1cfe3 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This provides Objective-C code generation targetting the Apple runtime. +// This provides Objective-C code generation targeting the Apple runtime. // //===----------------------------------------------------------------------===// @@ -42,9 +42,6 @@ using namespace clang; using namespace CodeGen; -// Common CGObjCRuntime functions, these don't belong here, but they -// don't belong in CGObjCRuntime either so we will live with it for -// now. static void EmitNullReturnInitialization(CodeGenFunction &CGF, ReturnValueSlot &returnSlot, @@ -55,112 +52,6 @@ static void EmitNullReturnInitialization(CodeGenFunction &CGF, CGF.EmitNullInitialization(returnSlot.getValue(), resultType); } -static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM, - const ObjCInterfaceDecl *OID, - const ObjCImplementationDecl *ID, - const ObjCIvarDecl *Ivar) { - const ObjCInterfaceDecl *Container = Ivar->getContainingInterface(); - - // FIXME: We should eliminate the need to have ObjCImplementationDecl passed - // in here; it should never be necessary because that should be the lexical - // decl context for the ivar. - - // If we know have an implementation (and the ivar is in it) then - // look up in the implementation layout. - const ASTRecordLayout *RL; - if (ID && ID->getClassInterface() == Container) - RL = &CGM.getContext().getASTObjCImplementationLayout(ID); - else - RL = &CGM.getContext().getASTObjCInterfaceLayout(Container); - - // Compute field index. - // - // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is - // implemented. This should be fixed to get the information from the layout - // directly. - unsigned Index = 0; - llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; - CGM.getContext().ShallowCollectObjCIvars(Container, Ivars); - for (unsigned k = 0, e = Ivars.size(); k != e; ++k) { - if (Ivar == Ivars[k]) - break; - ++Index; - } - assert(Index != Ivars.size() && "Ivar is not inside container!"); - assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!"); - - return RL->getFieldOffset(Index); -} - -uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, - const ObjCInterfaceDecl *OID, - const ObjCIvarDecl *Ivar) { - return LookupFieldBitOffset(CGM, OID, 0, Ivar) / 8; -} - -uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, - const ObjCImplementationDecl *OID, - const ObjCIvarDecl *Ivar) { - return LookupFieldBitOffset(CGM, OID->getClassInterface(), OID, Ivar) / 8; -} - -LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, - const ObjCInterfaceDecl *OID, - llvm::Value *BaseValue, - const ObjCIvarDecl *Ivar, - unsigned CVRQualifiers, - llvm::Value *Offset) { - // Compute (type*) ( (char *) BaseValue + Offset) - const llvm::Type *I8Ptr = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); - QualType IvarTy = Ivar->getType(); - const llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy); - llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr); - V = CGF.Builder.CreateGEP(V, Offset, "add.ptr"); - V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy)); - - if (!Ivar->isBitField()) { - LValue LV = CGF.MakeAddrLValue(V, IvarTy); - LV.getQuals().addCVRQualifiers(CVRQualifiers); - return LV; - } - - // We need to compute an access strategy for this bit-field. We are given the - // offset to the first byte in the bit-field, the sub-byte offset is taken - // from the original layout. We reuse the normal bit-field access strategy by - // treating this as an access to a struct where the bit-field is in byte 0, - // and adjust the containing type size as appropriate. - // - // FIXME: Note that currently we make a very conservative estimate of the - // alignment of the bit-field, because (a) it is not clear what guarantees the - // runtime makes us, and (b) we don't have a way to specify that the struct is - // at an alignment plus offset. - // - // Note, there is a subtle invariant here: we can only call this routine on - // non-synthesized ivars but we may be called for synthesized ivars. However, - // a synthesized ivar can never be a bit-field, so this is safe. - const ASTRecordLayout &RL = - CGF.CGM.getContext().getASTObjCInterfaceLayout(OID); - uint64_t TypeSizeInBits = CGF.CGM.getContext().toBits(RL.getSize()); - uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar); - uint64_t BitOffset = FieldBitOffset % 8; - uint64_t ContainingTypeAlign = 8; - uint64_t ContainingTypeSize = TypeSizeInBits - (FieldBitOffset - BitOffset); - uint64_t BitFieldSize = - Ivar->getBitWidth()->EvaluateAsInt(CGF.getContext()).getZExtValue(); - - // Allocate a new CGBitFieldInfo object to describe this access. - // - // FIXME: This is incredibly wasteful, these should be uniqued or part of some - // layout object. However, this is blocked on other cleanups to the - // Objective-C code, so for now we just live with allocating a bunch of these - // objects. - CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo( - CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize, - ContainingTypeSize, ContainingTypeAlign)); - - return LValue::MakeBitfield(V, *Info, - IvarTy.getCVRQualifiers() | CVRQualifiers); -} /// @@ -328,7 +219,7 @@ public: CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType()); Params.push_back(IdType); Params.push_back(SelType); - Params.push_back(Ctx.LongTy); + Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified()); Params.push_back(Ctx.BoolTy); const llvm::FunctionType *FTy = Types.GetFunctionType(Types.getFunctionInfo(IdType, Params, @@ -346,7 +237,7 @@ public: CanQualType SelType = Ctx.getCanonicalParamType(Ctx.getObjCSelType()); Params.push_back(IdType); Params.push_back(SelType); - Params.push_back(Ctx.LongTy); + Params.push_back(Ctx.getPointerDiffType()->getCanonicalTypeUnqualified()); Params.push_back(IdType); Params.push_back(Ctx.BoolTy); Params.push_back(Ctx.BoolTy); @@ -1294,7 +1185,8 @@ private: llvm::Value *Receiver, QualType Arg0Ty, bool IsSuper, - const CallArgList &CallArgs); + const CallArgList &CallArgs, + const ObjCMethodDecl *Method); /// GetClassGlobal - Return the global variable for the Objective-C /// class of the given name. @@ -1555,7 +1447,7 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, // Create and init a super structure; this is a (receiver, class) // pair we will pass to objc_msgSendSuper. llvm::Value *ObjCSuper = - CGF.Builder.CreateAlloca(ObjCTypes.SuperTy, 0, "objc_super"); + CGF.CreateTempAlloca(ObjCTypes.SuperTy, "objc_super"); llvm::Value *ReceiverAsObject = CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy); CGF.Builder.CreateStore(ReceiverAsObject, @@ -1630,9 +1522,8 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF, CallArgList ActualArgs; if (!IsSuper) Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy, "tmp"); - ActualArgs.push_back(std::make_pair(RValue::get(Arg0), Arg0Ty)); - ActualArgs.push_back(std::make_pair(RValue::get(Sel), - CGF.getContext().getObjCSelType())); + ActualArgs.add(RValue::get(Arg0), Arg0Ty); + ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType()); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); CodeGenTypes &Types = CGM.getTypes(); @@ -2177,6 +2068,8 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { 4, true); DefinedCategories.push_back(GV); DefinedCategoryNames.insert(ExtName.str()); + // method definition entries must be clear for next implementation. + MethodDefinitions.clear(); } // FIXME: Get from somewhere? @@ -2304,6 +2197,8 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { else GV = CreateMetadataVar(Name, Init, Section, 4, true); DefinedClasses.push_back(GV); + // method definition entries must be clear for next implementation. + MethodDefinitions.clear(); } llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID, @@ -3596,7 +3491,9 @@ llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) { Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_", llvm::ConstantArray::get(VMContext, Ident->getNameStart()), - "__TEXT,__cstring,cstring_literals", + ((ObjCABI == 2) ? + "__TEXT,__objc_classname,cstring_literals" : + "__TEXT,__cstring,cstring_literals"), 1, true); return getConstantGEP(VMContext, Entry, 0, 0); @@ -3668,7 +3565,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, // Note that 'i' here is actually the field index inside RD of Field, // although this dependency is hidden. const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); - FieldOffset = RL.getFieldOffset(i) / 8; + FieldOffset = RL.getFieldOffset(i) / ByteSizeInBits; } else FieldOffset = ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field)); @@ -3920,7 +3817,9 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string& BitMap) { llvm::GlobalVariable * Entry = CreateMetadataVar("\01L_OBJC_CLASS_NAME_", llvm::ConstantArray::get(VMContext, BitMap.c_str()), - "__TEXT,__cstring,cstring_literals", + ((ObjCABI == 2) ? + "__TEXT,__objc_classname,cstring_literals" : + "__TEXT,__cstring,cstring_literals"), 1, true); return getConstantGEP(VMContext, Entry, 0, 0); } @@ -3999,7 +3898,9 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) { if (!Entry) Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_NAME_", llvm::ConstantArray::get(VMContext, Sel.getAsString()), - "__TEXT,__cstring,cstring_literals", + ((ObjCABI == 2) ? + "__TEXT,__objc_methname,cstring_literals" : + "__TEXT,__cstring,cstring_literals"), 1, true); return getConstantGEP(VMContext, Entry, 0, 0); @@ -4019,7 +3920,9 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) { if (!Entry) Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_", llvm::ConstantArray::get(VMContext, TypeStr), - "__TEXT,__cstring,cstring_literals", + ((ObjCABI == 2) ? + "__TEXT,__objc_methtype,cstring_literals" : + "__TEXT,__cstring,cstring_literals"), 1, true); return getConstantGEP(VMContext, Entry, 0, 0); @@ -4035,7 +3938,9 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D) { if (!Entry) Entry = CreateMetadataVar("\01L_OBJC_METH_VAR_TYPE_", llvm::ConstantArray::get(VMContext, TypeStr), - "__TEXT,__cstring,cstring_literals", + ((ObjCABI == 2) ? + "__TEXT,__objc_methtype,cstring_literals" : + "__TEXT,__cstring,cstring_literals"), 1, true); return getConstantGEP(VMContext, Entry, 0, 0); @@ -4173,11 +4078,11 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) // } RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct, Ctx.getTranslationUnitDecl(), - SourceLocation(), + SourceLocation(), SourceLocation(), &Ctx.Idents.get("_objc_super")); - RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, + RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, Ctx.getObjCIdType(), 0, 0, false)); - RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, + RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, Ctx.getObjCClassType(), 0, 0, false)); RD->completeDefinition(); @@ -4636,11 +4541,11 @@ ObjCNonFragileABITypesHelper::ObjCNonFragileABITypesHelper(CodeGen::CodeGenModul // First the clang type for struct _message_ref_t RecordDecl *RD = RecordDecl::Create(Ctx, TTK_Struct, Ctx.getTranslationUnitDecl(), - SourceLocation(), + SourceLocation(), SourceLocation(), &Ctx.Idents.get("_message_ref_t")); - RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, + RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, Ctx.VoidPtrTy, 0, 0, false)); - RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), 0, + RD->addDecl(FieldDecl::Create(Ctx, RD, SourceLocation(), SourceLocation(), 0, Ctx.getObjCSelType(), 0, 0, false)); RD->completeDefinition(); @@ -4966,7 +4871,7 @@ void CGObjCNonFragileABIMac::GetClassSizeInfo(const ObjCImplementationDecl *OID, if (!RL.getFieldCount()) InstanceStart = InstanceSize; else - InstanceStart = RL.getFieldOffset(0) / 8; + InstanceStart = RL.getFieldOffset(0) / CGM.getContext().getCharWidth(); } void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { @@ -5017,14 +4922,14 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { while (const ObjCInterfaceDecl *Super = Root->getSuperClass()) Root = Super; IsAGV = GetClassGlobal(ObjCMetaClassName + Root->getNameAsString()); - if (Root->hasAttr<WeakImportAttr>()) + if (Root->isWeakImported()) IsAGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); // work on super class metadata symbol. std::string SuperClassName = ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString(); SuperClassGV = GetClassGlobal(SuperClassName); - if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>()) + if (ID->getClassInterface()->getSuperClass()->isWeakImported()) SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); } llvm::GlobalVariable *CLASS_RO_GV = BuildClassRoTInitializer(flags, @@ -5054,7 +4959,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { std::string RootClassName = ID->getClassInterface()->getSuperClass()->getNameAsString(); SuperClassGV = GetClassGlobal(ObjCClassName + RootClassName); - if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>()) + if (ID->getClassInterface()->getSuperClass()->isWeakImported()) SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); } GetClassSizeInfo(ID, InstanceStart, InstanceSize); @@ -5076,6 +4981,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { // Force the definition of the EHType if necessary. if (flags & CLS_EXCEPTION) GetInterfaceEHType(ID->getClassInterface(), true); + // Make sure method definition entries are all clear for next implementation. + MethodDefinitions.clear(); } /// GenerateProtocolRef - This routine is called to generate code for @@ -5136,7 +5043,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Values[0] = GetClassName(OCD->getIdentifier()); // meta-class entry symbol llvm::GlobalVariable *ClassGV = GetClassGlobal(ExtClassName); - if (Interface->hasAttr<WeakImportAttr>()) + if (Interface->isWeakImported()) ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); Values[1] = ClassGV; @@ -5204,6 +5111,8 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { // Determine if this category is also "non-lazy". if (ImplementationIsNonLazy(OCD)) DefinedNonLazyCategories.push_back(GCATV); + // method definition entries must be clear for next implementation. + MethodDefinitions.clear(); } /// GetMethodConstant - Return a struct objc_method constant for the @@ -5622,7 +5531,8 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( llvm::Value *Receiver, QualType Arg0Ty, bool IsSuper, - const CallArgList &CallArgs) { + const CallArgList &CallArgs, + const ObjCMethodDecl *Method) { // FIXME. Even though IsSuper is passes. This function doese not handle calls // to 'super' receivers. CodeGenTypes &Types = CGM.getTypes(); @@ -5685,15 +5595,15 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend( llvm::Value *Arg1 = CGF.Builder.CreateBitCast(GV, ObjCTypes.MessageRefPtrTy); CallArgList ActualArgs; - ActualArgs.push_back(std::make_pair(RValue::get(Arg0), Arg0Ty)); - ActualArgs.push_back(std::make_pair(RValue::get(Arg1), - ObjCTypes.MessageRefCPtrTy)); + ActualArgs.add(RValue::get(Arg0), Arg0Ty); + ActualArgs.add(RValue::get(Arg1), ObjCTypes.MessageRefCPtrTy); ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end()); const CGFunctionInfo &FnInfo1 = Types.getFunctionInfo(ResultType, ActualArgs, FunctionType::ExtInfo()); llvm::Value *Callee = CGF.Builder.CreateStructGEP(Arg1, 0); Callee = CGF.Builder.CreateLoad(Callee); - const llvm::FunctionType *FTy = Types.GetFunctionType(FnInfo1, true); + const llvm::FunctionType *FTy = + Types.GetFunctionType(FnInfo1, Method ? Method->isVariadic() : false); Callee = CGF.Builder.CreateBitCast(Callee, llvm::PointerType::getUnqual(FTy)); return CGF.EmitCall(FnInfo1, Callee, Return, ActualArgs); @@ -5716,7 +5626,7 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, false, CallArgs, Method, ObjCTypes) : EmitMessageSend(CGF, Return, ResultType, Sel, Receiver, CGF.getContext().getObjCIdType(), - false, CallArgs); + false, CallArgs, Method); } llvm::GlobalVariable * @@ -5807,7 +5717,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, /// decl. llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder, const ObjCInterfaceDecl *ID) { - if (ID->hasAttr<WeakImportAttr>()) { + if (ID->isWeakImported()) { std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString()); llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName); ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); @@ -5834,7 +5744,7 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, // Create and init a super structure; this is a (receiver, class) // pair we will pass to objc_msgSendSuper. llvm::Value *ObjCSuper = - CGF.Builder.CreateAlloca(ObjCTypes.SuperTy, 0, "objc_super"); + CGF.CreateTempAlloca(ObjCTypes.SuperTy, "objc_super"); llvm::Value *ReceiverAsObject = CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy); @@ -5870,7 +5780,7 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, true, CallArgs, Method, ObjCTypes) : EmitMessageSend(CGF, Return, ResultType, Sel, ObjCSuper, ObjCTypes.SuperPtrCTy, - true, CallArgs); + true, CallArgs, Method); } llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder, @@ -6008,65 +5918,12 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, return; } -namespace { - struct CallSyncExit : EHScopeStack::Cleanup { - llvm::Value *SyncExitFn; - llvm::Value *SyncArg; - CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg) - : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {} - - void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { - CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow(); - } - }; -} - void CGObjCNonFragileABIMac::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtSynchronizedStmt &S) { - // Evaluate the lock operand. This should dominate the cleanup. - llvm::Value *SyncArg = CGF.EmitScalarExpr(S.getSynchExpr()); - - // Acquire the lock. - SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy); - CGF.Builder.CreateCall(ObjCTypes.getSyncEnterFn(), SyncArg) - ->setDoesNotThrow(); - - // Register an all-paths cleanup to release the lock. - CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, - ObjCTypes.getSyncExitFn(), - SyncArg); - - // Emit the body of the statement. - CGF.EmitStmt(S.getSynchBody()); - - // Pop the lock-release cleanup. - CGF.PopCleanupBlock(); -} - -namespace { - struct CatchHandler { - const VarDecl *Variable; - const Stmt *Body; - llvm::BasicBlock *Block; - llvm::Value *TypeInfo; - }; - - struct CallObjCEndCatch : EHScopeStack::Cleanup { - CallObjCEndCatch(bool MightThrow, llvm::Value *Fn) : - MightThrow(MightThrow), Fn(Fn) {} - bool MightThrow; - llvm::Value *Fn; - - void Emit(CodeGenFunction &CGF, bool IsForEH) { - if (!MightThrow) { - CGF.Builder.CreateCall(Fn)->setDoesNotThrow(); - return; - } - - CGF.EmitCallOrInvoke(Fn, 0, 0); - } - }; + EmitAtSynchronizedStmt(CGF, S, + cast<llvm::Function>(ObjCTypes.getSyncEnterFn()), + cast<llvm::Function>(ObjCTypes.getSyncExitFn())); } llvm::Constant * @@ -6096,104 +5953,10 @@ CGObjCNonFragileABIMac::GetEHType(QualType T) { void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtTryStmt &S) { - // Jump destination for falling out of catch bodies. - CodeGenFunction::JumpDest Cont; - if (S.getNumCatchStmts()) - Cont = CGF.getJumpDestInCurrentScope("eh.cont"); - - CodeGenFunction::FinallyInfo FinallyInfo; - if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) - FinallyInfo = CGF.EnterFinallyBlock(Finally->getFinallyBody(), - ObjCTypes.getObjCBeginCatchFn(), - ObjCTypes.getObjCEndCatchFn(), - ObjCTypes.getExceptionRethrowFn()); - - llvm::SmallVector<CatchHandler, 8> Handlers; - - // Enter the catch, if there is one. - if (S.getNumCatchStmts()) { - for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) { - const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I); - const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); - - Handlers.push_back(CatchHandler()); - CatchHandler &Handler = Handlers.back(); - Handler.Variable = CatchDecl; - Handler.Body = CatchStmt->getCatchBody(); - Handler.Block = CGF.createBasicBlock("catch"); - - // @catch(...) always matches. - if (!CatchDecl) { - Handler.TypeInfo = 0; // catch-all - // Don't consider any other catches. - break; - } - - Handler.TypeInfo = GetEHType(CatchDecl->getType()); - } - - EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size()); - for (unsigned I = 0, E = Handlers.size(); I != E; ++I) - Catch->setHandler(I, Handlers[I].TypeInfo, Handlers[I].Block); - } - - // Emit the try body. - CGF.EmitStmt(S.getTryBody()); - - // Leave the try. - if (S.getNumCatchStmts()) - CGF.EHStack.popCatch(); - - // Remember where we were. - CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); - - // Emit the handlers. - for (unsigned I = 0, E = Handlers.size(); I != E; ++I) { - CatchHandler &Handler = Handlers[I]; - - CGF.EmitBlock(Handler.Block); - llvm::Value *RawExn = CGF.Builder.CreateLoad(CGF.getExceptionSlot()); - - // Enter the catch. - llvm::CallInst *Exn = - CGF.Builder.CreateCall(ObjCTypes.getObjCBeginCatchFn(), RawExn, - "exn.adjusted"); - Exn->setDoesNotThrow(); - - // Add a cleanup to leave the catch. - bool EndCatchMightThrow = (Handler.Variable == 0); - CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup, - EndCatchMightThrow, - ObjCTypes.getObjCEndCatchFn()); - - // Bind the catch parameter if it exists. - if (const VarDecl *CatchParam = Handler.Variable) { - const llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType()); - llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType); - - CGF.EmitAutoVarDecl(*CatchParam); - CGF.Builder.CreateStore(CastExn, CGF.GetAddrOfLocalVar(CatchParam)); - } - - CGF.ObjCEHValueStack.push_back(Exn); - CGF.EmitStmt(Handler.Body); - CGF.ObjCEHValueStack.pop_back(); - - // Leave the earlier cleanup. - CGF.PopCleanupBlock(); - - CGF.EmitBranchThroughCleanup(Cont); - } - - // Go back to the try-statement fallthrough. - CGF.Builder.restoreIP(SavedIP); - - // Pop out of the normal cleanup on the finally. - if (S.getFinallyStmt()) - CGF.ExitFinallyBlock(FinallyInfo); - - if (Cont.isValid()) - CGF.EmitBlock(Cont.getBlock()); + EmitTryCatchStmt(CGF, S, + cast<llvm::Function>(ObjCTypes.getObjCBeginCatchFn()), + cast<llvm::Function>(ObjCTypes.getObjCEndCatchFn()), + cast<llvm::Function>(ObjCTypes.getExceptionRethrowFn())); } /// EmitThrowStmt - Generate code for a throw statement. @@ -6290,10 +6053,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, CodeGen::CGObjCRuntime * CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM) { + if (CGM.getLangOptions().ObjCNonFragileABI) + return new CGObjCNonFragileABIMac(CGM); return new CGObjCMac(CGM); } - -CodeGen::CGObjCRuntime * -CodeGen::CreateMacNonFragileABIObjCRuntime(CodeGen::CodeGenModule &CGM) { - return new CGObjCNonFragileABIMac(CGM); -} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp new file mode 100644 index 0000000..3d854d4 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -0,0 +1,310 @@ +//==- CGObjCRuntime.cpp - Interface to Shared Objective-C Runtime Features ==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This abstract class defines the interface for Objective-C runtime-specific +// code generation. It provides some concrete helper methods for functionality +// shared between all (or most) of the Objective-C runtimes supported by clang. +// +//===----------------------------------------------------------------------===// + +#include "CGObjCRuntime.h" + +#include "CGRecordLayout.h" +#include "CodeGenModule.h" +#include "CodeGenFunction.h" +#include "CGCleanup.h" + +#include "clang/AST/RecordLayout.h" +#include "clang/AST/StmtObjC.h" + +#include "llvm/Support/CallSite.h" + +using namespace clang; +using namespace CodeGen; + +static uint64_t LookupFieldBitOffset(CodeGen::CodeGenModule &CGM, + const ObjCInterfaceDecl *OID, + const ObjCImplementationDecl *ID, + const ObjCIvarDecl *Ivar) { + const ObjCInterfaceDecl *Container = Ivar->getContainingInterface(); + + // FIXME: We should eliminate the need to have ObjCImplementationDecl passed + // in here; it should never be necessary because that should be the lexical + // decl context for the ivar. + + // If we know have an implementation (and the ivar is in it) then + // look up in the implementation layout. + const ASTRecordLayout *RL; + if (ID && ID->getClassInterface() == Container) + RL = &CGM.getContext().getASTObjCImplementationLayout(ID); + else + RL = &CGM.getContext().getASTObjCInterfaceLayout(Container); + + // Compute field index. + // + // FIXME: The index here is closely tied to how ASTContext::getObjCLayout is + // implemented. This should be fixed to get the information from the layout + // directly. + unsigned Index = 0; + llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; + CGM.getContext().ShallowCollectObjCIvars(Container, Ivars); + for (unsigned k = 0, e = Ivars.size(); k != e; ++k) { + if (Ivar == Ivars[k]) + break; + ++Index; + } + assert(Index != Ivars.size() && "Ivar is not inside container!"); + assert(Index < RL->getFieldCount() && "Ivar is not inside record layout!"); + + return RL->getFieldOffset(Index); +} + +uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, + const ObjCInterfaceDecl *OID, + const ObjCIvarDecl *Ivar) { + return LookupFieldBitOffset(CGM, OID, 0, Ivar) / + CGM.getContext().getCharWidth(); +} + +uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, + const ObjCImplementationDecl *OID, + const ObjCIvarDecl *Ivar) { + return LookupFieldBitOffset(CGM, OID->getClassInterface(), OID, Ivar) / + CGM.getContext().getCharWidth(); +} + +LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, + const ObjCInterfaceDecl *OID, + llvm::Value *BaseValue, + const ObjCIvarDecl *Ivar, + unsigned CVRQualifiers, + llvm::Value *Offset) { + // Compute (type*) ( (char *) BaseValue + Offset) + const llvm::Type *I8Ptr = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + QualType IvarTy = Ivar->getType(); + const llvm::Type *LTy = CGF.CGM.getTypes().ConvertTypeForMem(IvarTy); + llvm::Value *V = CGF.Builder.CreateBitCast(BaseValue, I8Ptr); + V = CGF.Builder.CreateInBoundsGEP(V, Offset, "add.ptr"); + V = CGF.Builder.CreateBitCast(V, llvm::PointerType::getUnqual(LTy)); + + if (!Ivar->isBitField()) { + LValue LV = CGF.MakeAddrLValue(V, IvarTy); + LV.getQuals().addCVRQualifiers(CVRQualifiers); + return LV; + } + + // We need to compute an access strategy for this bit-field. We are given the + // offset to the first byte in the bit-field, the sub-byte offset is taken + // from the original layout. We reuse the normal bit-field access strategy by + // treating this as an access to a struct where the bit-field is in byte 0, + // and adjust the containing type size as appropriate. + // + // FIXME: Note that currently we make a very conservative estimate of the + // alignment of the bit-field, because (a) it is not clear what guarantees the + // runtime makes us, and (b) we don't have a way to specify that the struct is + // at an alignment plus offset. + // + // Note, there is a subtle invariant here: we can only call this routine on + // non-synthesized ivars but we may be called for synthesized ivars. However, + // a synthesized ivar can never be a bit-field, so this is safe. + const ASTRecordLayout &RL = + CGF.CGM.getContext().getASTObjCInterfaceLayout(OID); + uint64_t TypeSizeInBits = CGF.CGM.getContext().toBits(RL.getSize()); + uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar); + uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth(); + uint64_t ContainingTypeAlign = CGF.CGM.getContext().Target.getCharAlign(); + uint64_t ContainingTypeSize = TypeSizeInBits - (FieldBitOffset - BitOffset); + uint64_t BitFieldSize = + Ivar->getBitWidth()->EvaluateAsInt(CGF.getContext()).getZExtValue(); + + // Allocate a new CGBitFieldInfo object to describe this access. + // + // FIXME: This is incredibly wasteful, these should be uniqued or part of some + // layout object. However, this is blocked on other cleanups to the + // Objective-C code, so for now we just live with allocating a bunch of these + // objects. + CGBitFieldInfo *Info = new (CGF.CGM.getContext()) CGBitFieldInfo( + CGBitFieldInfo::MakeInfo(CGF.CGM.getTypes(), Ivar, BitOffset, BitFieldSize, + ContainingTypeSize, ContainingTypeAlign)); + + return LValue::MakeBitfield(V, *Info, + IvarTy.getCVRQualifiers() | CVRQualifiers); +} + +namespace { + struct CatchHandler { + const VarDecl *Variable; + const Stmt *Body; + llvm::BasicBlock *Block; + llvm::Value *TypeInfo; + }; + + struct CallObjCEndCatch : EHScopeStack::Cleanup { + CallObjCEndCatch(bool MightThrow, llvm::Value *Fn) : + MightThrow(MightThrow), Fn(Fn) {} + bool MightThrow; + llvm::Value *Fn; + + void Emit(CodeGenFunction &CGF, bool IsForEH) { + if (!MightThrow) { + CGF.Builder.CreateCall(Fn)->setDoesNotThrow(); + return; + } + + CGF.EmitCallOrInvoke(Fn, 0, 0); + } + }; +} + + +void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, + const ObjCAtTryStmt &S, + llvm::Function *beginCatchFn, + llvm::Function *endCatchFn, + llvm::Function *exceptionRethrowFn) { + // Jump destination for falling out of catch bodies. + CodeGenFunction::JumpDest Cont; + if (S.getNumCatchStmts()) + Cont = CGF.getJumpDestInCurrentScope("eh.cont"); + + CodeGenFunction::FinallyInfo FinallyInfo; + if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) + FinallyInfo = CGF.EnterFinallyBlock(Finally->getFinallyBody(), + beginCatchFn, + endCatchFn, + exceptionRethrowFn); + + llvm::SmallVector<CatchHandler, 8> Handlers; + + // Enter the catch, if there is one. + if (S.getNumCatchStmts()) { + for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) { + const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I); + const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); + + Handlers.push_back(CatchHandler()); + CatchHandler &Handler = Handlers.back(); + Handler.Variable = CatchDecl; + Handler.Body = CatchStmt->getCatchBody(); + Handler.Block = CGF.createBasicBlock("catch"); + + // @catch(...) always matches. + if (!CatchDecl) { + Handler.TypeInfo = 0; // catch-all + // Don't consider any other catches. + break; + } + + Handler.TypeInfo = GetEHType(CatchDecl->getType()); + } + + EHCatchScope *Catch = CGF.EHStack.pushCatch(Handlers.size()); + for (unsigned I = 0, E = Handlers.size(); I != E; ++I) + Catch->setHandler(I, Handlers[I].TypeInfo, Handlers[I].Block); + } + + // Emit the try body. + CGF.EmitStmt(S.getTryBody()); + + // Leave the try. + if (S.getNumCatchStmts()) + CGF.EHStack.popCatch(); + + // Remember where we were. + CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP(); + + // Emit the handlers. + for (unsigned I = 0, E = Handlers.size(); I != E; ++I) { + CatchHandler &Handler = Handlers[I]; + + CGF.EmitBlock(Handler.Block); + llvm::Value *RawExn = CGF.Builder.CreateLoad(CGF.getExceptionSlot()); + + // Enter the catch. + llvm::Value *Exn = RawExn; + if (beginCatchFn) { + Exn = CGF.Builder.CreateCall(beginCatchFn, RawExn, "exn.adjusted"); + cast<llvm::CallInst>(Exn)->setDoesNotThrow(); + } + + if (endCatchFn) { + // Add a cleanup to leave the catch. + bool EndCatchMightThrow = (Handler.Variable == 0); + + CGF.EHStack.pushCleanup<CallObjCEndCatch>(NormalAndEHCleanup, + EndCatchMightThrow, + endCatchFn); + } + + // Bind the catch parameter if it exists. + if (const VarDecl *CatchParam = Handler.Variable) { + const llvm::Type *CatchType = CGF.ConvertType(CatchParam->getType()); + llvm::Value *CastExn = CGF.Builder.CreateBitCast(Exn, CatchType); + + CGF.EmitAutoVarDecl(*CatchParam); + CGF.Builder.CreateStore(CastExn, CGF.GetAddrOfLocalVar(CatchParam)); + } + + CGF.ObjCEHValueStack.push_back(Exn); + CGF.EmitStmt(Handler.Body); + CGF.ObjCEHValueStack.pop_back(); + + // Leave the earlier cleanup. + if (endCatchFn) + CGF.PopCleanupBlock(); + + CGF.EmitBranchThroughCleanup(Cont); + } + + // Go back to the try-statement fallthrough. + CGF.Builder.restoreIP(SavedIP); + + // Pop out of the normal cleanup on the finally. + if (S.getFinallyStmt()) + CGF.ExitFinallyBlock(FinallyInfo); + + if (Cont.isValid()) + CGF.EmitBlock(Cont.getBlock()); +} + +namespace { + struct CallSyncExit : EHScopeStack::Cleanup { + llvm::Value *SyncExitFn; + llvm::Value *SyncArg; + CallSyncExit(llvm::Value *SyncExitFn, llvm::Value *SyncArg) + : SyncExitFn(SyncExitFn), SyncArg(SyncArg) {} + + void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) { + CGF.Builder.CreateCall(SyncExitFn, SyncArg)->setDoesNotThrow(); + } + }; +} + +void CGObjCRuntime::EmitAtSynchronizedStmt(CodeGenFunction &CGF, + const ObjCAtSynchronizedStmt &S, + llvm::Function *syncEnterFn, + llvm::Function *syncExitFn) { + // Evaluate the lock operand. This should dominate the cleanup. + llvm::Value *SyncArg = + CGF.EmitScalarExpr(S.getSynchExpr()); + + // Acquire the lock. + SyncArg = CGF.Builder.CreateBitCast(SyncArg, syncEnterFn->getFunctionType()->getParamType(0)); + CGF.Builder.CreateCall(syncEnterFn, SyncArg); + + // Register an all-paths cleanup to release the lock. + CGF.EHStack.pushCleanup<CallSyncExit>(NormalAndEHCleanup, syncExitFn, + SyncArg); + + // Emit the body of the statement. + CGF.EmitStmt(S.getSynchBody()); + + // Pop the lock-release cleanup. + CGF.PopCleanupBlock(); +} diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h index 5ad3a50..0cc2d82 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCRuntime.h @@ -17,7 +17,6 @@ #define CLANG_CODEGEN_OBCJRUNTIME_H #include "clang/Basic/IdentifierTable.h" // Selector #include "clang/AST/DeclObjC.h" -#include <string> #include "CGBuilder.h" #include "CGCall.h" @@ -87,6 +86,26 @@ protected: const ObjCIvarDecl *Ivar, unsigned CVRQualifiers, llvm::Value *Offset); + /// Emits a try / catch statement. This function is intended to be called by + /// subclasses, and provides a generic mechanism for generating these, which + /// should be usable by all runtimes. The caller must provide the functions to + /// call when entering and exiting a @catch() block, and the function used to + /// rethrow exceptions. If the begin and end catch functions are NULL, then + /// the function assumes that the EH personality function provides the + /// thrown object directly. + void EmitTryCatchStmt(CodeGenFunction &CGF, + const ObjCAtTryStmt &S, + llvm::Function *beginCatchFn, + llvm::Function *endCatchFn, + llvm::Function *exceptionRethrowFn); + /// Emits an @synchronize() statement, using the syncEnterFn and syncExitFn + /// arguments as the functions called to lock and unlock the object. This + /// function can be called by subclasses that use zero-cost exception + /// handling. + void EmitAtSynchronizedStmt(CodeGenFunction &CGF, + const ObjCAtSynchronizedStmt &S, + llvm::Function *syncEnterFn, + llvm::Function *syncExitFn); public: virtual ~CGObjCRuntime(); @@ -118,7 +137,7 @@ public: /// accompanying metadata) and a list of protocols. virtual void GenerateCategory(const ObjCCategoryImplDecl *OCD) = 0; - /// Generate a class stucture for this class. + /// Generate a class structure for this class. virtual void GenerateClass(const ObjCImplementationDecl *OID) = 0; /// Generate an Objective-C message send operation. @@ -230,7 +249,6 @@ public: //TODO: This should include some way of selecting which runtime to target. CGObjCRuntime *CreateGNUObjCRuntime(CodeGenModule &CGM); CGObjCRuntime *CreateMacObjCRuntime(CodeGenModule &CGM); -CGObjCRuntime *CreateMacNonFragileABIObjCRuntime(CodeGenModule &CGM); } } #endif diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp index 7ec0ee4..c73b199 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGRTTI.cpp @@ -16,6 +16,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Frontend/CodeGenOptions.h" +#include "CGObjCRuntime.h" using namespace clang; using namespace CodeGen; @@ -195,7 +196,9 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { case BuiltinType::Overload: case BuiltinType::Dependent: - assert(false && "Should not see this type here!"); + case BuiltinType::BoundMember: + case BuiltinType::UnknownAny: + llvm_unreachable("asking for RRTI for a placeholder type!"); case BuiltinType::ObjCId: case BuiltinType::ObjCClass: @@ -875,14 +878,16 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { // For a non-virtual base, this is the offset in the object of the base // subobject. For a virtual base, this is the offset in the virtual table of // the virtual base offset for the virtual base referenced (negative). + CharUnits Offset; if (Base->isVirtual()) - OffsetFlags = CGM.getVTables().getVirtualBaseOffsetOffset(RD, BaseDecl); + Offset = + CGM.getVTables().getVirtualBaseOffsetOffset(RD, BaseDecl); else { const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - OffsetFlags = Layout.getBaseClassOffsetInBits(BaseDecl) / 8; + Offset = Layout.getBaseClassOffset(BaseDecl); }; - OffsetFlags <<= 8; + OffsetFlags = Offset.getQuantity() << 8; // The low-order byte of __offset_flags contains flags, as given by the // masks from the enumeration __offset_flags_masks. @@ -977,6 +982,10 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext); return llvm::Constant::getNullValue(Int8PtrTy); } + + if (ForEH && Ty->isObjCObjectPointerType() && !Features.NeXTRuntime) { + return Runtime->GetEHType(Ty); + } return RTTIBuilder(*this).BuildTypeInfo(Ty); } diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h index 30da05f..6d9fc05 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayout.h @@ -12,6 +12,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/DerivedTypes.h" +#include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" namespace llvm { class raw_ostream; @@ -53,7 +54,7 @@ public: /// unused as the cleanest IR comes from having a well-constructed LLVM type /// with proper GEP instructions, but sometimes its use is required, for /// example if an access is intended to straddle an LLVM field boundary. - unsigned FieldByteOffset; + CharUnits FieldByteOffset; /// Bit offset in the accessed value to use. The width is implied by \see /// TargetBitWidth. @@ -68,7 +69,7 @@ public: // FIXME: Remove use of 0 to encode default, instead have IRgen do the right // thing when it generates the code, if avoiding align directives is // desired. - unsigned AccessAlignment; + CharUnits AccessAlignment; /// Offset for the target value. unsigned TargetBitOffset; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index ceae66f..a4ac390 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -34,7 +34,7 @@ class CGRecordLayoutBuilder { public: /// FieldTypes - Holds the LLVM types that the struct is created from. /// - std::vector<const llvm::Type *> FieldTypes; + llvm::SmallVector<const llvm::Type *, 16> FieldTypes; /// BaseSubobjectType - Holds the LLVM type for the non-virtual part /// of the struct. For example, consider: @@ -77,13 +77,26 @@ public: /// Packed - Whether the resulting LLVM struct will be packed or not. bool Packed; + + /// IsMsStruct - Whether ms_struct is in effect or not + bool IsMsStruct; private: CodeGenTypes &Types; + /// LastLaidOutBaseInfo - Contains the offset and non-virtual size of the + /// last base laid out. Used so that we can replace the last laid out base + /// type with an i8 array if needed. + struct LastLaidOutBaseInfo { + CharUnits Offset; + CharUnits NonVirtualSize; + + bool isValid() const { return !NonVirtualSize.isZero(); } + void invalidate() { NonVirtualSize = CharUnits::Zero(); } + + } LastLaidOutBase; + /// Alignment - Contains the alignment of the RecordDecl. - // - // FIXME: This is not needed and should be removed. CharUnits Alignment; /// BitsAvailableInLastField - If a bit field spans only part of a LLVM field, @@ -143,6 +156,12 @@ private: /// struct size is a multiple of the field alignment. void AppendPadding(CharUnits fieldOffset, CharUnits fieldAlignment); + /// ResizeLastBaseFieldIfNecessary - Fields and bases can be laid out in the + /// tail padding of a previous base. If this happens, the type of the previous + /// base needs to be changed to an array of i8. Returns true if the last + /// laid out base was resized. + bool ResizeLastBaseFieldIfNecessary(CharUnits offset); + /// getByteArrayType - Returns a byte array type with the given number of /// elements. const llvm::Type *getByteArrayType(CharUnits NumBytes); @@ -152,7 +171,7 @@ private: /// AppendTailPadding - Append enough tail padding so that the type will have /// the passed size. - void AppendTailPadding(uint64_t RecordSize); + void AppendTailPadding(CharUnits RecordSize); CharUnits getTypeAlignment(const llvm::Type *Ty) const; @@ -168,7 +187,8 @@ public: CGRecordLayoutBuilder(CodeGenTypes &Types) : BaseSubobjectType(0), IsZeroInitializable(true), IsZeroInitializableAsBase(true), - Packed(false), Types(Types), BitsAvailableInLastField(0) { } + Packed(false), IsMsStruct(false), + Types(Types), BitsAvailableInLastField(0) { } /// Layout - Will layout a RecordDecl. void Layout(const RecordDecl *D); @@ -179,6 +199,8 @@ public: void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { Alignment = Types.getContext().getASTRecordLayout(D).getAlignment(); Packed = D->hasAttr<PackedAttr>(); + + IsMsStruct = D->hasAttr<MsStructAttr>(); if (D->isUnion()) { LayoutUnion(D); @@ -190,6 +212,7 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { // We weren't able to layout the struct. Try again with a packed struct Packed = true; + LastLaidOutBase.invalidate(); NextFieldOffset = CharUnits::Zero(); FieldTypes.clear(); Fields.clear(); @@ -242,7 +265,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, assert(llvm::isPowerOf2_32(TypeSizeInBits) && "Unexpected type size!"); CGBitFieldInfo::AccessInfo Components[3]; unsigned NumComponents = 0; - unsigned AccessedTargetBits = 0; // The tumber of target bits accessed. + unsigned AccessedTargetBits = 0; // The number of target bits accessed. unsigned AccessWidth = TypeSizeInBits; // The current access width to attempt. // Round down from the field offset to find the first access position that is @@ -292,13 +315,15 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, // in higher bits. But this also reverts the bytes, so fix this here by reverting // the byte offset on big-endian machines. if (Types.getTargetData().isBigEndian()) { - AI.FieldByteOffset = (ContainingTypeSizeInBits - AccessStart - AccessWidth )/8; + AI.FieldByteOffset = Types.getContext().toCharUnitsFromBits( + ContainingTypeSizeInBits - AccessStart - AccessWidth); } else { - AI.FieldByteOffset = AccessStart / 8; + AI.FieldByteOffset = Types.getContext().toCharUnitsFromBits(AccessStart); } AI.FieldBitStart = AccessBitsInFieldStart - AccessStart; AI.AccessWidth = AccessWidth; - AI.AccessAlignment = llvm::MinAlign(ContainingTypeAlign, AccessStart) / 8; + AI.AccessAlignment = Types.getContext().toCharUnitsFromBits( + llvm::MinAlign(ContainingTypeAlign, AccessStart)); AI.TargetBitOffset = AccessedTargetBits; AI.TargetBitWidth = AccessBitsInFieldSize; @@ -332,34 +357,51 @@ void CGRecordLayoutBuilder::LayoutBitField(const FieldDecl *D, return; uint64_t nextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset); - unsigned numBytesToAppend; + CharUnits numBytesToAppend; + unsigned charAlign = Types.getContext().Target.getCharAlign(); + + if (fieldOffset < nextFieldOffsetInBits && !BitsAvailableInLastField) { + assert(fieldOffset % charAlign == 0 && + "Field offset not aligned correctly"); + + CharUnits fieldOffsetInCharUnits = + Types.getContext().toCharUnitsFromBits(fieldOffset); + + // Try to resize the last base field. + if (ResizeLastBaseFieldIfNecessary(fieldOffsetInCharUnits)) + nextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset); + } if (fieldOffset < nextFieldOffsetInBits) { assert(BitsAvailableInLastField && "Bitfield size mismatch!"); assert(!NextFieldOffset.isZero() && "Must have laid out at least one byte"); // The bitfield begins in the previous bit-field. - numBytesToAppend = - llvm::RoundUpToAlignment(fieldSize - BitsAvailableInLastField, 8) / 8; + numBytesToAppend = Types.getContext().toCharUnitsFromBits( + llvm::RoundUpToAlignment(fieldSize - BitsAvailableInLastField, + charAlign)); } else { - assert(fieldOffset % 8 == 0 && "Field offset not aligned correctly"); + assert(fieldOffset % charAlign == 0 && + "Field offset not aligned correctly"); // Append padding if necessary. - AppendPadding(CharUnits::fromQuantity(fieldOffset / 8), CharUnits::One()); + AppendPadding(Types.getContext().toCharUnitsFromBits(fieldOffset), + CharUnits::One()); - numBytesToAppend = llvm::RoundUpToAlignment(fieldSize, 8) / 8; + numBytesToAppend = Types.getContext().toCharUnitsFromBits( + llvm::RoundUpToAlignment(fieldSize, charAlign)); - assert(numBytesToAppend && "No bytes to append!"); + assert(!numBytesToAppend.isZero() && "No bytes to append!"); } // Add the bit field info. BitFields.insert(std::make_pair(D, CGBitFieldInfo::MakeInfo(Types, D, fieldOffset, fieldSize))); - AppendBytes(CharUnits::fromQuantity(numBytesToAppend)); + AppendBytes(numBytesToAppend); BitsAvailableInLastField = - NextFieldOffset.getQuantity() * 8 - (fieldOffset + fieldSize); + Types.getContext().toBits(NextFieldOffset) - (fieldOffset + fieldSize); } bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, @@ -411,6 +453,14 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, NextFieldOffset.RoundUpToAlignment(typeAlignment); if (fieldOffsetInBytes < alignedNextFieldOffsetInBytes) { + // Try to resize the last base field. + if (ResizeLastBaseFieldIfNecessary(fieldOffsetInBytes)) { + alignedNextFieldOffsetInBytes = + NextFieldOffset.RoundUpToAlignment(typeAlignment); + } + } + + if (fieldOffsetInBytes < alignedNextFieldOffsetInBytes) { assert(!Packed && "Could not place field even with packed struct!"); return false; } @@ -421,6 +471,7 @@ bool CGRecordLayoutBuilder::LayoutField(const FieldDecl *D, Fields[D] = FieldTypes.size(); AppendField(fieldOffsetInBytes, Ty); + LastLaidOutBase.invalidate(); return true; } @@ -436,11 +487,12 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field, return 0; const llvm::Type *FieldTy = llvm::Type::getInt8Ty(Types.getLLVMContext()); - unsigned NumBytesToAppend = - llvm::RoundUpToAlignment(FieldSize, 8) / 8; + CharUnits NumBytesToAppend = Types.getContext().toCharUnitsFromBits( + llvm::RoundUpToAlignment(FieldSize, + Types.getContext().Target.getCharAlign())); - if (NumBytesToAppend > 1) - FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend); + if (NumBytesToAppend > CharUnits::One()) + FieldTy = llvm::ArrayType::get(FieldTy, NumBytesToAppend.getQuantity()); // Add the bit field info. BitFields.insert(std::make_pair(Field, @@ -516,11 +568,16 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base, const CGRecordLayout &baseLayout, CharUnits baseOffset) { + ResizeLastBaseFieldIfNecessary(baseOffset); + AppendPadding(baseOffset, CharUnits::One()); const ASTRecordLayout &baseASTLayout = Types.getContext().getASTRecordLayout(base); + LastLaidOutBase.Offset = NextFieldOffset; + LastLaidOutBase.NonVirtualSize = baseASTLayout.getNonVirtualSize(); + // Fields and bases can be laid out in the tail padding of previous // bases. If this happens, we need to allocate the base as an i8 // array; otherwise, we can use the subobject type. However, @@ -529,20 +586,10 @@ void CGRecordLayoutBuilder::LayoutBase(const CXXRecordDecl *base, // approximation, which is to use the base subobject type if it // has the same LLVM storage size as the nvsize. - // The nvsize, i.e. the unpadded size of the base class. - CharUnits nvsize = baseASTLayout.getNonVirtualSize(); - -#if 0 const llvm::StructType *subobjectType = baseLayout.getBaseSubobjectLLVMType(); - const llvm::StructLayout *baseLLVMLayout = - Types.getTargetData().getStructLayout(subobjectType); - CharUnits stsize = CharUnits::fromQuantity(baseLLVMLayout->getSizeInBytes()); + AppendField(baseOffset, subobjectType); - if (nvsize == stsize) - AppendField(baseOffset, subobjectType); - else -#endif - AppendBytes(nvsize); + Types.addBaseSubobjectTypeName(base, baseLayout); } void CGRecordLayoutBuilder::LayoutNonVirtualBase(const CXXRecordDecl *base, @@ -698,9 +745,22 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { LayoutNonVirtualBases(RD, Layout); unsigned FieldNo = 0; - + const FieldDecl *LastFD = 0; + for (RecordDecl::field_iterator Field = D->field_begin(), FieldEnd = D->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are + // ignored: + const FieldDecl *FD = (*Field); + if (Types.getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD) || + Types.getContext().ZeroBitfieldFollowsBitfield(FD, LastFD)) { + --FieldNo; + continue; + } + LastFD = FD; + } + if (!LayoutField(*Field, Layout.getFieldOffset(FieldNo))) { assert(!Packed && "Could not layout fields even with a packed LLVM struct!"); @@ -724,27 +784,25 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { } // Append tail padding if necessary. - AppendTailPadding(Types.getContext().toBits(Layout.getSize())); + AppendTailPadding(Layout.getSize()); return true; } -void CGRecordLayoutBuilder::AppendTailPadding(uint64_t RecordSize) { - assert(RecordSize % 8 == 0 && "Invalid record size!"); +void CGRecordLayoutBuilder::AppendTailPadding(CharUnits RecordSize) { + ResizeLastBaseFieldIfNecessary(RecordSize); - CharUnits RecordSizeInBytes = - Types.getContext().toCharUnitsFromBits(RecordSize); - assert(NextFieldOffset <= RecordSizeInBytes && "Size mismatch!"); + assert(NextFieldOffset <= RecordSize && "Size mismatch!"); CharUnits AlignedNextFieldOffset = NextFieldOffset.RoundUpToAlignment(getAlignmentAsLLVMStruct()); - if (AlignedNextFieldOffset == RecordSizeInBytes) { + if (AlignedNextFieldOffset == RecordSize) { // We don't need any padding. return; } - CharUnits NumPadBytes = RecordSizeInBytes - NextFieldOffset; + CharUnits NumPadBytes = RecordSize - NextFieldOffset; AppendBytes(NumPadBytes); } @@ -777,6 +835,24 @@ void CGRecordLayoutBuilder::AppendPadding(CharUnits fieldOffset, } } +bool CGRecordLayoutBuilder::ResizeLastBaseFieldIfNecessary(CharUnits offset) { + // Check if we have a base to resize. + if (!LastLaidOutBase.isValid()) + return false; + + // This offset does not overlap with the tail padding. + if (offset >= NextFieldOffset) + return false; + + // Restore the field offset and append an i8 array instead. + FieldTypes.pop_back(); + NextFieldOffset = LastLaidOutBase.Offset; + AppendBytes(LastLaidOutBase.NonVirtualSize); + LastLaidOutBase.invalidate(); + + return true; +} + const llvm::Type *CGRecordLayoutBuilder::getByteArrayType(CharUnits numBytes) { assert(!numBytes.isZero() && "Empty byte arrays aren't allowed."); @@ -903,6 +979,8 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D); RecordDecl::field_iterator it = D->field_begin(); + const FieldDecl *LastFD = 0; + bool IsMsStruct = D->hasAttr<MsStructAttr>(); for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) { const FieldDecl *FD = *it; @@ -912,13 +990,27 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { unsigned FieldNo = RL->getLLVMFieldNo(FD); assert(AST_RL.getFieldOffset(i) == SL->getElementOffsetInBits(FieldNo) && "Invalid field offset!"); + LastFD = FD; continue; } + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are + // ignored: + if (getContext().ZeroBitfieldFollowsNonBitfield(FD, LastFD) || + getContext().ZeroBitfieldFollowsBitfield(FD, LastFD)) { + --i; + continue; + } + LastFD = FD; + } + // Ignore unnamed bit-fields. - if (!FD->getDeclName()) + if (!FD->getDeclName()) { + LastFD = FD; continue; - + } + const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD); for (unsigned i = 0, e = Info.getNumComponents(); i != e; ++i) { const CGBitFieldInfo::AccessInfo &AI = Info.getComponent(i); @@ -926,7 +1018,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D) { // Verify that every component access is within the structure. uint64_t FieldOffset = SL->getElementOffsetInBits(AI.FieldIndex); uint64_t AccessBitOffset = FieldOffset + - getContext().toBits(CharUnits::fromQuantity(AI.FieldByteOffset)); + getContext().toBits(AI.FieldByteOffset); assert(AccessBitOffset + AI.AccessWidth <= TypeSizeInBits && "Invalid bit-field access (out of range)!"); } @@ -985,11 +1077,11 @@ void CGBitFieldInfo::print(llvm::raw_ostream &OS) const { OS.indent(8); OS << "<AccessInfo" << " FieldIndex:" << AI.FieldIndex - << " FieldByteOffset:" << AI.FieldByteOffset + << " FieldByteOffset:" << AI.FieldByteOffset.getQuantity() << " FieldBitStart:" << AI.FieldBitStart << " AccessWidth:" << AI.AccessWidth << "\n"; OS.indent(8 + strlen("<AccessInfo")); - OS << " AccessAlignment:" << AI.AccessAlignment + OS << " AccessAlignment:" << AI.AccessAlignment.getQuantity() << " TargetBitOffset:" << AI.TargetBitOffset << " TargetBitWidth:" << AI.TargetBitWidth << ">\n"; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp index cd23811..99bc3f4 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGStmt.cpp @@ -72,6 +72,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { switch (S->getStmtClass()) { case Stmt::NoStmtClass: case Stmt::CXXCatchStmtClass: + case Stmt::SEHExceptStmtClass: + case Stmt::SEHFinallyStmtClass: llvm_unreachable("invalid statement class to emit generically"); case Stmt::NullStmtClass: case Stmt::CompoundStmtClass: @@ -153,6 +155,11 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::CXXTryStmtClass: EmitCXXTryStmt(cast<CXXTryStmt>(*S)); break; + case Stmt::CXXForRangeStmtClass: + EmitCXXForRangeStmt(cast<CXXForRangeStmt>(*S)); + case Stmt::SEHTryStmtClass: + // FIXME Not yet implemented + break; } } @@ -359,10 +366,12 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { // If the condition constant folds and can be elided, try to avoid emitting // the condition and the dead arm of the if/else. - if (int Cond = ConstantFoldsToSimpleInteger(S.getCond())) { + bool CondConstant; + if (ConstantFoldsToSimpleInteger(S.getCond(), CondConstant)) { // Figure out which block (then or else) is executed. - const Stmt *Executed = S.getThen(), *Skipped = S.getElse(); - if (Cond == -1) // Condition false? + const Stmt *Executed = S.getThen(); + const Stmt *Skipped = S.getElse(); + if (!CondConstant) // Condition false? std::swap(Executed, Skipped); // If the skipped block has no labels in it, just emit the executed block. @@ -395,11 +404,17 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) { // Emit the 'else' code if present. if (const Stmt *Else = S.getElse()) { + // There is no need to emit line number for unconditional branch. + if (getDebugInfo()) + Builder.SetCurrentDebugLocation(llvm::DebugLoc()); EmitBlock(ElseBlock); { RunCleanupsScope ElseScope(*this); EmitStmt(Else); } + // There is no need to emit line number for unconditional branch. + if (getDebugInfo()) + Builder.SetCurrentDebugLocation(llvm::DebugLoc()); EmitBranch(ContBlock); } @@ -628,6 +643,80 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) { EmitBlock(LoopExit.getBlock(), true); } +void CodeGenFunction::EmitCXXForRangeStmt(const CXXForRangeStmt &S) { + JumpDest LoopExit = getJumpDestInCurrentScope("for.end"); + + RunCleanupsScope ForScope(*this); + + CGDebugInfo *DI = getDebugInfo(); + if (DI) { + DI->setLocation(S.getSourceRange().getBegin()); + DI->EmitRegionStart(Builder); + } + + // Evaluate the first pieces before the loop. + EmitStmt(S.getRangeStmt()); + EmitStmt(S.getBeginEndStmt()); + + // Start the loop with a block that tests the condition. + // If there's an increment, the continue scope will be overwritten + // later. + llvm::BasicBlock *CondBlock = createBasicBlock("for.cond"); + EmitBlock(CondBlock); + + // If there are any cleanups between here and the loop-exit scope, + // create a block to stage a loop exit along. + llvm::BasicBlock *ExitBlock = LoopExit.getBlock(); + if (ForScope.requiresCleanups()) + ExitBlock = createBasicBlock("for.cond.cleanup"); + + // The loop body, consisting of the specified body and the loop variable. + llvm::BasicBlock *ForBody = createBasicBlock("for.body"); + + // The body is executed if the expression, contextually converted + // to bool, is true. + llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond()); + Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock); + + if (ExitBlock != LoopExit.getBlock()) { + EmitBlock(ExitBlock); + EmitBranchThroughCleanup(LoopExit); + } + + EmitBlock(ForBody); + + // Create a block for the increment. In case of a 'continue', we jump there. + JumpDest Continue = getJumpDestInCurrentScope("for.inc"); + + // Store the blocks to use for break and continue. + BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); + + { + // Create a separate cleanup scope for the loop variable and body. + RunCleanupsScope BodyScope(*this); + EmitStmt(S.getLoopVarStmt()); + EmitStmt(S.getBody()); + } + + // If there is an increment, emit it next. + EmitBlock(Continue.getBlock()); + EmitStmt(S.getInc()); + + BreakContinueStack.pop_back(); + + EmitBranch(CondBlock); + + ForScope.ForceCleanup(); + + if (DI) { + DI->setLocation(S.getSourceRange().getEnd()); + DI->EmitRegionEnd(Builder); + } + + // Emit the fall-through block. + EmitBlock(LoopExit.getBlock(), true); +} + void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) { if (RV.isScalar()) { Builder.CreateStore(RV.getScalarVal(), ReturnValue); @@ -745,8 +834,7 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) { if (Range.ult(llvm::APInt(Range.getBitWidth(), 64))) { // Range is small enough to add multiple switch instruction cases. for (unsigned i = 0, e = Range.getZExtValue() + 1; i != e; ++i) { - SwitchInsn->addCase(llvm::ConstantInt::get(getLLVMContext(), LHS), - CaseDest); + SwitchInsn->addCase(Builder.getInt(LHS), CaseDest); LHS++; } return; @@ -767,11 +855,9 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) { // Emit range check. llvm::Value *Diff = - Builder.CreateSub(SwitchInsn->getCondition(), - llvm::ConstantInt::get(getLLVMContext(), LHS), "tmp"); + Builder.CreateSub(SwitchInsn->getCondition(), Builder.getInt(LHS), "tmp"); llvm::Value *Cond = - Builder.CreateICmpULE(Diff, llvm::ConstantInt::get(getLLVMContext(), Range), - "inbounds"); + Builder.CreateICmpULE(Diff, Builder.getInt(Range), "inbounds"); Builder.CreateCondBr(Cond, CaseDest, FalseDest); // Restore the appropriate insertion point. @@ -782,16 +868,37 @@ void CodeGenFunction::EmitCaseStmtRange(const CaseStmt &S) { } void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) { + // Handle case ranges. if (S.getRHS()) { EmitCaseStmtRange(S); return; } + llvm::ConstantInt *CaseVal = + Builder.getInt(S.getLHS()->EvaluateAsInt(getContext())); + + // If the body of the case is just a 'break', and if there was no fallthrough, + // try to not emit an empty block. + if (isa<BreakStmt>(S.getSubStmt())) { + JumpDest Block = BreakContinueStack.back().BreakBlock; + + // Only do this optimization if there are no cleanups that need emitting. + if (isObviouslyBranchWithoutCleanups(Block)) { + SwitchInsn->addCase(CaseVal, Block.getBlock()); + + // If there was a fallthrough into this case, make sure to redirect it to + // the end of the switch as well. + if (Builder.GetInsertBlock()) { + Builder.CreateBr(Block.getBlock()); + Builder.ClearInsertionPoint(); + } + return; + } + } + EmitBlock(createBasicBlock("sw.bb")); llvm::BasicBlock *CaseDest = Builder.GetInsertBlock(); - llvm::APSInt CaseVal = S.getLHS()->EvaluateAsInt(getContext()); - SwitchInsn->addCase(llvm::ConstantInt::get(getLLVMContext(), CaseVal), - CaseDest); + SwitchInsn->addCase(CaseVal, CaseDest); // Recursively emitting the statement is acceptable, but is not wonderful for // code where we have many case statements nested together, i.e.: @@ -805,13 +912,12 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) { const CaseStmt *CurCase = &S; const CaseStmt *NextCase = dyn_cast<CaseStmt>(S.getSubStmt()); - // Otherwise, iteratively add consequtive cases to this switch stmt. + // Otherwise, iteratively add consecutive cases to this switch stmt. while (NextCase && NextCase->getRHS() == 0) { CurCase = NextCase; - CaseVal = CurCase->getLHS()->EvaluateAsInt(getContext()); - SwitchInsn->addCase(llvm::ConstantInt::get(getLLVMContext(), CaseVal), - CaseDest); - + llvm::ConstantInt *CaseVal = + Builder.getInt(CurCase->getLHS()->EvaluateAsInt(getContext())); + SwitchInsn->addCase(CaseVal, CaseDest); NextCase = dyn_cast<CaseStmt>(CurCase->getSubStmt()); } @@ -827,6 +933,207 @@ void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) { EmitStmt(S.getSubStmt()); } +/// CollectStatementsForCase - Given the body of a 'switch' statement and a +/// constant value that is being switched on, see if we can dead code eliminate +/// the body of the switch to a simple series of statements to emit. Basically, +/// on a switch (5) we want to find these statements: +/// case 5: +/// printf(...); <-- +/// ++i; <-- +/// break; +/// +/// and add them to the ResultStmts vector. If it is unsafe to do this +/// transformation (for example, one of the elided statements contains a label +/// that might be jumped to), return CSFC_Failure. If we handled it and 'S' +/// should include statements after it (e.g. the printf() line is a substmt of +/// the case) then return CSFC_FallThrough. If we handled it and found a break +/// statement, then return CSFC_Success. +/// +/// If Case is non-null, then we are looking for the specified case, checking +/// that nothing we jump over contains labels. If Case is null, then we found +/// the case and are looking for the break. +/// +/// If the recursive walk actually finds our Case, then we set FoundCase to +/// true. +/// +enum CSFC_Result { CSFC_Failure, CSFC_FallThrough, CSFC_Success }; +static CSFC_Result CollectStatementsForCase(const Stmt *S, + const SwitchCase *Case, + bool &FoundCase, + llvm::SmallVectorImpl<const Stmt*> &ResultStmts) { + // If this is a null statement, just succeed. + if (S == 0) + return Case ? CSFC_Success : CSFC_FallThrough; + + // If this is the switchcase (case 4: or default) that we're looking for, then + // we're in business. Just add the substatement. + if (const SwitchCase *SC = dyn_cast<SwitchCase>(S)) { + if (S == Case) { + FoundCase = true; + return CollectStatementsForCase(SC->getSubStmt(), 0, FoundCase, + ResultStmts); + } + + // Otherwise, this is some other case or default statement, just ignore it. + return CollectStatementsForCase(SC->getSubStmt(), Case, FoundCase, + ResultStmts); + } + + // If we are in the live part of the code and we found our break statement, + // return a success! + if (Case == 0 && isa<BreakStmt>(S)) + return CSFC_Success; + + // If this is a switch statement, then it might contain the SwitchCase, the + // break, or neither. + if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(S)) { + // Handle this as two cases: we might be looking for the SwitchCase (if so + // the skipped statements must be skippable) or we might already have it. + CompoundStmt::const_body_iterator I = CS->body_begin(), E = CS->body_end(); + if (Case) { + // Keep track of whether we see a skipped declaration. The code could be + // using the declaration even if it is skipped, so we can't optimize out + // the decl if the kept statements might refer to it. + bool HadSkippedDecl = false; + + // If we're looking for the case, just see if we can skip each of the + // substatements. + for (; Case && I != E; ++I) { + HadSkippedDecl |= isa<DeclStmt>(I); + + switch (CollectStatementsForCase(*I, Case, FoundCase, ResultStmts)) { + case CSFC_Failure: return CSFC_Failure; + case CSFC_Success: + // A successful result means that either 1) that the statement doesn't + // have the case and is skippable, or 2) does contain the case value + // and also contains the break to exit the switch. In the later case, + // we just verify the rest of the statements are elidable. + if (FoundCase) { + // If we found the case and skipped declarations, we can't do the + // optimization. + if (HadSkippedDecl) + return CSFC_Failure; + + for (++I; I != E; ++I) + if (CodeGenFunction::ContainsLabel(*I, true)) + return CSFC_Failure; + return CSFC_Success; + } + break; + case CSFC_FallThrough: + // If we have a fallthrough condition, then we must have found the + // case started to include statements. Consider the rest of the + // statements in the compound statement as candidates for inclusion. + assert(FoundCase && "Didn't find case but returned fallthrough?"); + // We recursively found Case, so we're not looking for it anymore. + Case = 0; + + // If we found the case and skipped declarations, we can't do the + // optimization. + if (HadSkippedDecl) + return CSFC_Failure; + break; + } + } + } + + // If we have statements in our range, then we know that the statements are + // live and need to be added to the set of statements we're tracking. + for (; I != E; ++I) { + switch (CollectStatementsForCase(*I, 0, FoundCase, ResultStmts)) { + case CSFC_Failure: return CSFC_Failure; + case CSFC_FallThrough: + // A fallthrough result means that the statement was simple and just + // included in ResultStmt, keep adding them afterwards. + break; + case CSFC_Success: + // A successful result means that we found the break statement and + // stopped statement inclusion. We just ensure that any leftover stmts + // are skippable and return success ourselves. + for (++I; I != E; ++I) + if (CodeGenFunction::ContainsLabel(*I, true)) + return CSFC_Failure; + return CSFC_Success; + } + } + + return Case ? CSFC_Success : CSFC_FallThrough; + } + + // Okay, this is some other statement that we don't handle explicitly, like a + // for statement or increment etc. If we are skipping over this statement, + // just verify it doesn't have labels, which would make it invalid to elide. + if (Case) { + if (CodeGenFunction::ContainsLabel(S, true)) + return CSFC_Failure; + return CSFC_Success; + } + + // Otherwise, we want to include this statement. Everything is cool with that + // so long as it doesn't contain a break out of the switch we're in. + if (CodeGenFunction::containsBreak(S)) return CSFC_Failure; + + // Otherwise, everything is great. Include the statement and tell the caller + // that we fall through and include the next statement as well. + ResultStmts.push_back(S); + return CSFC_FallThrough; +} + +/// FindCaseStatementsForValue - Find the case statement being jumped to and +/// then invoke CollectStatementsForCase to find the list of statements to emit +/// for a switch on constant. See the comment above CollectStatementsForCase +/// for more details. +static bool FindCaseStatementsForValue(const SwitchStmt &S, + const llvm::APInt &ConstantCondValue, + llvm::SmallVectorImpl<const Stmt*> &ResultStmts, + ASTContext &C) { + // First step, find the switch case that is being branched to. We can do this + // efficiently by scanning the SwitchCase list. + const SwitchCase *Case = S.getSwitchCaseList(); + const DefaultStmt *DefaultCase = 0; + + for (; Case; Case = Case->getNextSwitchCase()) { + // It's either a default or case. Just remember the default statement in + // case we're not jumping to any numbered cases. + if (const DefaultStmt *DS = dyn_cast<DefaultStmt>(Case)) { + DefaultCase = DS; + continue; + } + + // Check to see if this case is the one we're looking for. + const CaseStmt *CS = cast<CaseStmt>(Case); + // Don't handle case ranges yet. + if (CS->getRHS()) return false; + + // If we found our case, remember it as 'case'. + if (CS->getLHS()->EvaluateAsInt(C) == ConstantCondValue) + break; + } + + // If we didn't find a matching case, we use a default if it exists, or we + // elide the whole switch body! + if (Case == 0) { + // It is safe to elide the body of the switch if it doesn't contain labels + // etc. If it is safe, return successfully with an empty ResultStmts list. + if (DefaultCase == 0) + return !CodeGenFunction::ContainsLabel(&S); + Case = DefaultCase; + } + + // Ok, we know which case is being jumped to, try to collect all the + // statements that follow it. This can fail for a variety of reasons. Also, + // check to see that the recursive walk actually found our case statement. + // Insane cases like this can fail to find it in the recursive walk since we + // don't handle every stmt kind: + // switch (4) { + // while (1) { + // case 4: ... + bool FoundCase = false; + return CollectStatementsForCase(S.getBody(), Case, FoundCase, + ResultStmts) != CSFC_Failure && + FoundCase; +} + void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { JumpDest SwitchExit = getJumpDestInCurrentScope("sw.epilog"); @@ -835,6 +1142,23 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) { if (S.getConditionVariable()) EmitAutoVarDecl(*S.getConditionVariable()); + // See if we can constant fold the condition of the switch and therefore only + // emit the live case statement (if any) of the switch. + llvm::APInt ConstantCondValue; + if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue)) { + llvm::SmallVector<const Stmt*, 4> CaseStmts; + if (FindCaseStatementsForValue(S, ConstantCondValue, CaseStmts, + getContext())) { + RunCleanupsScope ExecutedScope(*this); + + // Okay, we can dead code eliminate everything except this case. Emit the + // specified series of statements and we're good. + for (unsigned i = 0, e = CaseStmts.size(); i != e; ++i) + EmitStmt(CaseStmts[i]); + return; + } + } + llvm::Value *CondV = EmitScalarExpr(S.getCond()); // Handle nested switch statements. @@ -1031,7 +1355,7 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str, } } - return llvm::MDNode::get(CGF.getLLVMContext(), Locs.data(), Locs.size()); + return llvm::MDNode::get(CGF.getLLVMContext(), Locs); } void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp index 78b2dbe..a6849f8 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTT.cpp @@ -53,6 +53,10 @@ class VTTBuilder { /// GenerateDefinition - Whether the VTT builder should generate LLVM IR for /// the VTT. bool GenerateDefinition; + + /// The linkage to use for any construction vtables required by this VTT. + /// Only required if we're building a definition. + llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables; /// GetAddrOfVTable - Returns the address of the vtable for the base class in /// the given vtable class. @@ -109,7 +113,9 @@ class VTTBuilder { public: VTTBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerivedClass, - bool GenerateDefinition); + bool GenerateDefinition, + llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables + = (llvm::GlobalVariable::LinkageTypes) -1); // getVTTComponents - Returns a reference to the VTT components. const VTTComponentsVectorTy &getVTTComponents() const { @@ -132,13 +138,19 @@ public: VTTBuilder::VTTBuilder(CodeGenModule &CGM, const CXXRecordDecl *MostDerivedClass, - bool GenerateDefinition) + bool GenerateDefinition, + llvm::GlobalVariable::LinkageTypes LinkageForConstructionVTables) : CGM(CGM), MostDerivedClass(MostDerivedClass), MostDerivedClassLayout(CGM.getContext().getASTRecordLayout(MostDerivedClass)), - GenerateDefinition(GenerateDefinition) { + GenerateDefinition(GenerateDefinition), + LinkageForConstructionVTables(LinkageForConstructionVTables) { + assert(!GenerateDefinition || + LinkageForConstructionVTables + != (llvm::GlobalVariable::LinkageTypes) -1); // Lay out this VTT. - LayoutVTT(BaseSubobject(MostDerivedClass, 0), /*BaseIsVirtual=*/false); + LayoutVTT(BaseSubobject(MostDerivedClass, CharUnits::Zero()), + /*BaseIsVirtual=*/false); } llvm::Constant * @@ -148,7 +160,7 @@ VTTBuilder::GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual, return 0; if (Base.getBase() == MostDerivedClass) { - assert(Base.getBaseOffset() == 0 && + assert(Base.getBaseOffset().isZero() && "Most derived class vtable must have a zero offset!"); // This is a regular vtable. return CGM.getVTables().GetAddrOfVTable(MostDerivedClass); @@ -156,6 +168,7 @@ VTTBuilder::GetAddrOfVTable(BaseSubobject Base, bool BaseIsVirtual, return CGM.getVTables().GenerateConstructionVTable(MostDerivedClass, Base, BaseIsVirtual, + LinkageForConstructionVTables, AddressPoints); } @@ -217,8 +230,8 @@ void VTTBuilder::LayoutSecondaryVTTs(BaseSubobject Base) { cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - uint64_t BaseOffset = Base.getBaseOffset() + - Layout.getBaseClassOffsetInBits(BaseDecl); + CharUnits BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); // Layout the VTT for this base. LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/false); @@ -256,19 +269,19 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, bool BaseDeclIsMorallyVirtual = BaseIsMorallyVirtual; bool BaseDeclIsNonVirtualPrimaryBase = false; - uint64_t BaseOffset; + CharUnits BaseOffset; if (I->isVirtual()) { // Ignore virtual bases that we've already visited. if (!VBases.insert(BaseDecl)) continue; - BaseOffset = MostDerivedClassLayout.getVBaseClassOffsetInBits(BaseDecl); + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); BaseDeclIsMorallyVirtual = true; } else { const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD); - BaseOffset = - Base.getBaseOffset() + Layout.getBaseClassOffsetInBits(BaseDecl); + BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); if (!Layout.isPrimaryBaseVirtual() && Layout.getPrimaryBase() == BaseDecl) @@ -283,8 +296,8 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, if (!BaseDeclIsNonVirtualPrimaryBase && (BaseDecl->getNumVBases() || BaseDeclIsMorallyVirtual)) { // Add the vtable pointer. - AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTable, VTableClass, - AddressPoints); + AddVTablePointer(BaseSubobject(BaseDecl, BaseOffset), VTable, + VTableClass, AddressPoints); } // And lay out the secondary virtual pointers for the base class. @@ -316,8 +329,8 @@ void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, if (!VBases.insert(BaseDecl)) continue; - uint64_t BaseOffset = - MostDerivedClassLayout.getVBaseClassOffsetInBits(BaseDecl); + CharUnits BaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); LayoutVTT(BaseSubobject(BaseDecl, BaseOffset), /*BaseIsVirtual=*/true); } @@ -370,7 +383,7 @@ void CodeGenVTables::EmitVTTDefinition(llvm::GlobalVariable *VTT, llvm::GlobalVariable::LinkageTypes Linkage, const CXXRecordDecl *RD) { - VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/true); + VTTBuilder Builder(CGM, RD, /*GenerateDefinition=*/true, Linkage); const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); const llvm::ArrayType *ArrayType = diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp index 891697f..581467c 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.cpp @@ -43,15 +43,16 @@ struct BaseOffset { /// (Or the offset from the virtual base class to the base class, if the /// path from the derived class to the base class involves a virtual base /// class. - int64_t NonVirtualOffset; + CharUnits NonVirtualOffset; - BaseOffset() : DerivedClass(0), VirtualBase(0), NonVirtualOffset(0) { } + BaseOffset() : DerivedClass(0), VirtualBase(0), + NonVirtualOffset(CharUnits::Zero()) { } BaseOffset(const CXXRecordDecl *DerivedClass, - const CXXRecordDecl *VirtualBase, int64_t NonVirtualOffset) + const CXXRecordDecl *VirtualBase, CharUnits NonVirtualOffset) : DerivedClass(DerivedClass), VirtualBase(VirtualBase), NonVirtualOffset(NonVirtualOffset) { } - bool isEmpty() const { return !NonVirtualOffset && !VirtualBase; } + bool isEmpty() const { return NonVirtualOffset.isZero() && !VirtualBase; } }; /// FinalOverriders - Contains the final overrider member functions for all @@ -64,9 +65,9 @@ public: const CXXMethodDecl *Method; /// Offset - the base offset of the overrider in the layout class. - uint64_t Offset; + CharUnits Offset; - OverriderInfo() : Method(0), Offset(0) { } + OverriderInfo() : Method(0), Offset(CharUnits::Zero()) { } }; private: @@ -77,7 +78,7 @@ private: /// MostDerivedClassOffset - If we're building final overriders for a /// construction vtable, this holds the offset from the layout class to the /// most derived class. - const uint64_t MostDerivedClassOffset; + const CharUnits MostDerivedClassOffset; /// LayoutClass - The class we're using for layout information. Will be /// different than the most derived class if the final overriders are for a @@ -91,7 +92,7 @@ private: /// MethodBaseOffsetPairTy - Uniquely identifies a member function /// in a base subobject. - typedef std::pair<const CXXMethodDecl *, uint64_t> MethodBaseOffsetPairTy; + typedef std::pair<const CXXMethodDecl *, CharUnits> MethodBaseOffsetPairTy; typedef llvm::DenseMap<MethodBaseOffsetPairTy, OverriderInfo> OverridersMapTy; @@ -104,14 +105,14 @@ private: /// as a record decl and a subobject number) and its offsets in the most /// derived class as well as the layout class. typedef llvm::DenseMap<std::pair<const CXXRecordDecl *, unsigned>, - uint64_t> SubobjectOffsetMapTy; + CharUnits> SubobjectOffsetMapTy; typedef llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCountMapTy; /// ComputeBaseOffsets - Compute the offsets for all base subobjects of the /// given base. void ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, - uint64_t OffsetInLayoutClass, + CharUnits OffsetInLayoutClass, SubobjectOffsetMapTy &SubobjectOffsets, SubobjectOffsetMapTy &SubobjectLayoutClassOffsets, SubobjectCountMapTy &SubobjectCounts); @@ -125,13 +126,13 @@ private: public: FinalOverriders(const CXXRecordDecl *MostDerivedClass, - uint64_t MostDerivedClassOffset, + CharUnits MostDerivedClassOffset, const CXXRecordDecl *LayoutClass); /// getOverrider - Get the final overrider for the given method declaration in /// the subobject with the given base offset. OverriderInfo getOverrider(const CXXMethodDecl *MD, - uint64_t BaseOffset) const { + CharUnits BaseOffset) const { assert(OverridersMap.count(std::make_pair(MD, BaseOffset)) && "Did not find overrider!"); @@ -141,7 +142,8 @@ public: /// dump - dump the final overriders. void dump() { VisitedVirtualBasesSetTy VisitedVirtualBases; - dump(llvm::errs(), BaseSubobject(MostDerivedClass, 0), VisitedVirtualBases); + dump(llvm::errs(), BaseSubobject(MostDerivedClass, CharUnits::Zero()), + VisitedVirtualBases); } }; @@ -149,7 +151,7 @@ public: #define DUMP_OVERRIDERS 0 FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, - uint64_t MostDerivedClassOffset, + CharUnits MostDerivedClassOffset, const CXXRecordDecl *LayoutClass) : MostDerivedClass(MostDerivedClass), MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass), @@ -160,9 +162,11 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, SubobjectOffsetMapTy SubobjectOffsets; SubobjectOffsetMapTy SubobjectLayoutClassOffsets; SubobjectCountMapTy SubobjectCounts; - ComputeBaseOffsets(BaseSubobject(MostDerivedClass, 0), /*IsVirtual=*/false, - MostDerivedClassOffset, SubobjectOffsets, - SubobjectLayoutClassOffsets, SubobjectCounts); + ComputeBaseOffsets(BaseSubobject(MostDerivedClass, CharUnits::Zero()), + /*IsVirtual=*/false, + MostDerivedClassOffset, + SubobjectOffsets, SubobjectLayoutClassOffsets, + SubobjectCounts); // Get the the final overriders. CXXFinalOverriderMap FinalOverriders; @@ -180,7 +184,7 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, SubobjectNumber)) && "Did not find subobject offset!"); - uint64_t BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(), + CharUnits BaseOffset = SubobjectOffsets[std::make_pair(MD->getParent(), SubobjectNumber)]; assert(I->second.size() == 1 && "Final overrider is not unique!"); @@ -190,7 +194,7 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, assert(SubobjectLayoutClassOffsets.count( std::make_pair(OverriderRD, Method.Subobject)) && "Did not find subobject offset!"); - uint64_t OverriderOffset = + CharUnits OverriderOffset = SubobjectLayoutClassOffsets[std::make_pair(OverriderRD, Method.Subobject)]; @@ -211,7 +215,7 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, static BaseOffset ComputeBaseOffset(ASTContext &Context, const CXXRecordDecl *DerivedRD, const CXXBasePath &Path) { - int64_t NonVirtualOffset = 0; + CharUnits NonVirtualOffset = CharUnits::Zero(); unsigned NonVirtualStart = 0; const CXXRecordDecl *VirtualBase = 0; @@ -240,13 +244,13 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context, const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>(); const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl()); - NonVirtualOffset += Layout.getBaseClassOffsetInBits(Base); + NonVirtualOffset += Layout.getBaseClassOffset(Base); } // FIXME: This should probably use CharUnits or something. Maybe we should // even change the base offsets in ASTRecordLayout to be specified in // CharUnits. - return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset / 8); + return BaseOffset(DerivedRD, VirtualBase, NonVirtualOffset); } @@ -321,7 +325,7 @@ ComputeReturnAdjustmentBaseOffset(ASTContext &Context, void FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, - uint64_t OffsetInLayoutClass, + CharUnits OffsetInLayoutClass, SubobjectOffsetMapTy &SubobjectOffsets, SubobjectOffsetMapTy &SubobjectLayoutClassOffsets, SubobjectCountMapTy &SubobjectCounts) { @@ -337,8 +341,7 @@ FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, assert(!SubobjectLayoutClassOffsets.count(std::make_pair(RD, SubobjectNumber)) && "Subobject offset already exists!"); - SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = - Base.getBaseOffset(); + SubobjectOffsets[std::make_pair(RD, SubobjectNumber)] = Base.getBaseOffset(); SubobjectLayoutClassOffsets[std::make_pair(RD, SubobjectNumber)] = OffsetInLayoutClass; @@ -348,8 +351,8 @@ FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - uint64_t BaseOffset; - uint64_t BaseOffsetInLayoutClass; + CharUnits BaseOffset; + CharUnits BaseOffsetInLayoutClass; if (I->isVirtual()) { // Check if we've visited this virtual base before. if (SubobjectOffsets.count(std::make_pair(BaseDecl, 0))) @@ -358,20 +361,21 @@ FinalOverriders::ComputeBaseOffsets(BaseSubobject Base, bool IsVirtual, const ASTRecordLayout &LayoutClassLayout = Context.getASTRecordLayout(LayoutClass); - BaseOffset = MostDerivedClassLayout.getVBaseClassOffsetInBits(BaseDecl); + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); BaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffsetInBits(BaseDecl); + LayoutClassLayout.getVBaseClassOffset(BaseDecl); } else { const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - uint64_t Offset = Layout.getBaseClassOffsetInBits(BaseDecl); + CharUnits Offset = Layout.getBaseClassOffset(BaseDecl); BaseOffset = Base.getBaseOffset() + Offset; BaseOffsetInLayoutClass = OffsetInLayoutClass + Offset; } - ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset), I->isVirtual(), - BaseOffsetInLayoutClass, SubobjectOffsets, - SubobjectLayoutClassOffsets, SubobjectCounts); + ComputeBaseOffsets(BaseSubobject(BaseDecl, BaseOffset), + I->isVirtual(), BaseOffsetInLayoutClass, + SubobjectOffsets, SubobjectLayoutClassOffsets, + SubobjectCounts); } } @@ -389,24 +393,23 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base, if (!BaseDecl->isPolymorphic()) continue; - uint64_t BaseOffset; + CharUnits BaseOffset; if (I->isVirtual()) { if (!VisitedVirtualBases.insert(BaseDecl)) { // We've visited this base before. continue; } - BaseOffset = MostDerivedClassLayout.getVBaseClassOffsetInBits(BaseDecl); + BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); } else { - BaseOffset = Layout.getBaseClassOffsetInBits(BaseDecl) + - Base.getBaseOffset(); + BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset(); } dump(Out, BaseSubobject(BaseDecl, BaseOffset), VisitedVirtualBases); } Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", "; - Out << Base.getBaseOffset() / 8 << ")\n"; + Out << Base.getBaseOffset().getQuantity() << ")\n"; // Now dump the overriders for this base subobject. for (CXXRecordDecl::method_iterator I = RD->method_begin(), @@ -420,7 +423,7 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base, Out << " " << MD->getQualifiedNameAsString() << " - ("; Out << Overrider.Method->getQualifiedNameAsString(); - Out << ", " << ", " << Overrider.Offset / 8 << ')'; + Out << ", " << ", " << Overrider.Offset.getQuantity() << ')'; BaseOffset Offset; if (!Overrider.Method->isPure()) @@ -431,7 +434,7 @@ void FinalOverriders::dump(llvm::raw_ostream &Out, BaseSubobject Base, if (Offset.VirtualBase) Out << Offset.VirtualBase->getQualifiedNameAsString() << " vbase, "; - Out << Offset.NonVirtualOffset << " nv]"; + Out << Offset.NonVirtualOffset.getQuantity() << " nv]"; } Out << "\n"; @@ -460,15 +463,15 @@ public: CK_UnusedFunctionPointer }; - static VTableComponent MakeVCallOffset(int64_t Offset) { + static VTableComponent MakeVCallOffset(CharUnits Offset) { return VTableComponent(CK_VCallOffset, Offset); } - static VTableComponent MakeVBaseOffset(int64_t Offset) { + static VTableComponent MakeVBaseOffset(CharUnits Offset) { return VTableComponent(CK_VBaseOffset, Offset); } - static VTableComponent MakeOffsetToTop(int64_t Offset) { + static VTableComponent MakeOffsetToTop(CharUnits Offset) { return VTableComponent(CK_OffsetToTop, Offset); } @@ -510,19 +513,19 @@ public: return (Kind)(Value & 0x7); } - int64_t getVCallOffset() const { + CharUnits getVCallOffset() const { assert(getKind() == CK_VCallOffset && "Invalid component kind!"); return getOffset(); } - int64_t getVBaseOffset() const { + CharUnits getVBaseOffset() const { assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); return getOffset(); } - int64_t getOffsetToTop() const { + CharUnits getOffsetToTop() const { assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); return getOffset(); @@ -554,13 +557,13 @@ public: } private: - VTableComponent(Kind ComponentKind, int64_t Offset) { + VTableComponent(Kind ComponentKind, CharUnits Offset) { assert((ComponentKind == CK_VCallOffset || ComponentKind == CK_VBaseOffset || ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); - assert(Offset <= ((1LL << 56) - 1) && "Offset is too big!"); + assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!"); - Value = ((Offset << 3) | ComponentKind); + Value = ((Offset.getQuantity() << 3) | ComponentKind); } VTableComponent(Kind ComponentKind, uintptr_t Ptr) { @@ -576,11 +579,11 @@ private: Value = Ptr | ComponentKind; } - int64_t getOffset() const { + CharUnits getOffset() const { assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || getKind() == CK_OffsetToTop) && "Invalid component kind!"); - return Value >> 3; + return CharUnits::fromQuantity(Value >> 3); } uintptr_t getPointer() const { @@ -608,7 +611,7 @@ private: /// VCallOffsetMap - Keeps track of vcall offsets when building a vtable. struct VCallOffsetMap { - typedef std::pair<const CXXMethodDecl *, int64_t> MethodAndOffsetPairTy; + typedef std::pair<const CXXMethodDecl *, CharUnits> MethodAndOffsetPairTy; /// Offsets - Keeps track of methods and their offsets. // FIXME: This should be a real map and not a vector. @@ -623,11 +626,11 @@ public: /// AddVCallOffset - Adds a vcall offset to the map. Returns true if the /// add was successful, or false if there was already a member function with /// the same signature in the map. - bool AddVCallOffset(const CXXMethodDecl *MD, int64_t OffsetOffset); + bool AddVCallOffset(const CXXMethodDecl *MD, CharUnits OffsetOffset); /// getVCallOffsetOffset - Returns the vcall offset offset (relative to the /// vtable address point) for the given virtual member function. - int64_t getVCallOffsetOffset(const CXXMethodDecl *MD); + CharUnits getVCallOffsetOffset(const CXXMethodDecl *MD); // empty - Return whether the offset map is empty or not. bool empty() const { return Offsets.empty(); } @@ -677,7 +680,7 @@ bool VCallOffsetMap::MethodsCanShareVCallOffset(const CXXMethodDecl *LHS, } bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, - int64_t OffsetOffset) { + CharUnits OffsetOffset) { // Check if we can reuse an offset. for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) @@ -689,7 +692,7 @@ bool VCallOffsetMap::AddVCallOffset(const CXXMethodDecl *MD, return true; } -int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { +CharUnits VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { // Look for an offset. for (unsigned I = 0, E = Offsets.size(); I != E; ++I) { if (MethodsCanShareVCallOffset(Offsets[I].first, MD)) @@ -697,13 +700,13 @@ int64_t VCallOffsetMap::getVCallOffsetOffset(const CXXMethodDecl *MD) { } assert(false && "Should always find a vcall offset offset!"); - return 0; + return CharUnits::Zero(); } /// VCallAndVBaseOffsetBuilder - Class for building vcall and vbase offsets. class VCallAndVBaseOffsetBuilder { public: - typedef llvm::DenseMap<const CXXRecordDecl *, int64_t> + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> VBaseOffsetOffsetsMapTy; private: @@ -741,24 +744,25 @@ private: /// AddVCallAndVBaseOffsets - Add vcall offsets and vbase offsets for the /// given base subobject. void AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, - uint64_t RealBaseOffset); + CharUnits RealBaseOffset); /// AddVCallOffsets - Add vcall offsets for the given base subobject. - void AddVCallOffsets(BaseSubobject Base, uint64_t VBaseOffset); + void AddVCallOffsets(BaseSubobject Base, CharUnits VBaseOffset); /// AddVBaseOffsets - Add vbase offsets for the given class. - void AddVBaseOffsets(const CXXRecordDecl *Base, uint64_t OffsetInLayoutClass); + void AddVBaseOffsets(const CXXRecordDecl *Base, + CharUnits OffsetInLayoutClass); /// getCurrentOffsetOffset - Get the current vcall or vbase offset offset in - /// bytes, relative to the vtable address point. - int64_t getCurrentOffsetOffset() const; + /// chars, relative to the vtable address point. + CharUnits getCurrentOffsetOffset() const; public: VCallAndVBaseOffsetBuilder(const CXXRecordDecl *MostDerivedClass, const CXXRecordDecl *LayoutClass, const FinalOverriders *Overriders, BaseSubobject Base, bool BaseIsVirtual, - uint64_t OffsetInLayoutClass) + CharUnits OffsetInLayoutClass) : MostDerivedClass(MostDerivedClass), LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), Overriders(Overriders) { @@ -780,7 +784,7 @@ public: void VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, bool BaseIsVirtual, - uint64_t RealBaseOffset) { + CharUnits RealBaseOffset) { const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base.getBase()); // Itanium C++ ABI 2.5.2: @@ -795,7 +799,7 @@ VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { bool PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual(); - uint64_t PrimaryBaseOffset; + CharUnits PrimaryBaseOffset; // Get the base offset of the primary base. if (PrimaryBaseIsVirtual) { @@ -806,7 +810,7 @@ VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, Context.getASTRecordLayout(MostDerivedClass); PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffsetInBits(PrimaryBase); + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); } else { assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 && "Primary base should have a zero offset!"); @@ -814,8 +818,9 @@ VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, PrimaryBaseOffset = Base.getBaseOffset(); } - AddVCallAndVBaseOffsets(BaseSubobject(PrimaryBase, PrimaryBaseOffset), - PrimaryBaseIsVirtual, RealBaseOffset); + AddVCallAndVBaseOffsets( + BaseSubobject(PrimaryBase,PrimaryBaseOffset), + PrimaryBaseIsVirtual, RealBaseOffset); } AddVBaseOffsets(Base.getBase(), RealBaseOffset); @@ -825,22 +830,21 @@ VCallAndVBaseOffsetBuilder::AddVCallAndVBaseOffsets(BaseSubobject Base, AddVCallOffsets(Base, RealBaseOffset); } -int64_t VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const { +CharUnits VCallAndVBaseOffsetBuilder::getCurrentOffsetOffset() const { // OffsetIndex is the index of this vcall or vbase offset, relative to the // vtable address point. (We subtract 3 to account for the information just // above the address point, the RTTI info, the offset to top, and the // vcall offset itself). int64_t OffsetIndex = -(int64_t)(3 + Components.size()); - // FIXME: We shouldn't use / 8 here. - int64_t OffsetOffset = OffsetIndex * - (int64_t)Context.Target.getPointerWidth(0) / 8; - + CharUnits PointerWidth = + Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + CharUnits OffsetOffset = PointerWidth * OffsetIndex; return OffsetOffset; } void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, - uint64_t VBaseOffset) { + CharUnits VBaseOffset) { const CXXRecordDecl *RD = Base.getBase(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); @@ -866,14 +870,14 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, if (!MD->isVirtual()) continue; - int64_t OffsetOffset = getCurrentOffsetOffset(); + CharUnits OffsetOffset = getCurrentOffsetOffset(); // Don't add a vcall offset if we already have one for this member function // signature. if (!VCallOffsets.AddVCallOffset(MD, OffsetOffset)) continue; - int64_t Offset = 0; + CharUnits Offset = CharUnits::Zero(); if (Overriders) { // Get the final overrider. @@ -882,11 +886,11 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, /// The vcall offset is the offset from the virtual base to the object /// where the function was overridden. - // FIXME: We should not use / 8 here. - Offset = (int64_t)(Overrider.Offset - VBaseOffset) / 8; + Offset = Overrider.Offset - VBaseOffset; } - Components.push_back(VTableComponent::MakeVCallOffset(Offset)); + Components.push_back( + VTableComponent::MakeVCallOffset(Offset)); } // And iterate over all non-virtual bases (ignoring the primary base). @@ -902,15 +906,17 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, continue; // Get the base offset of this base. - uint64_t BaseOffset = Base.getBaseOffset() + - Layout.getBaseClassOffsetInBits(BaseDecl); + CharUnits BaseOffset = Base.getBaseOffset() + + Layout.getBaseClassOffset(BaseDecl); - AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), VBaseOffset); + AddVCallOffsets(BaseSubobject(BaseDecl, BaseOffset), + VBaseOffset); } } -void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, - uint64_t OffsetInLayoutClass) { +void +VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, + CharUnits OffsetInLayoutClass) { const ASTRecordLayout &LayoutClassLayout = Context.getASTRecordLayout(LayoutClass); @@ -922,19 +928,19 @@ void VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, // Check if this is a virtual base that we haven't visited before. if (I->isVirtual() && VisitedVirtualBases.insert(BaseDecl)) { - // FIXME: We shouldn't use / 8 here. - int64_t Offset = - (int64_t)(LayoutClassLayout.getVBaseClassOffsetInBits(BaseDecl) - - OffsetInLayoutClass) / 8; + CharUnits Offset = + LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass; // Add the vbase offset offset. assert(!VBaseOffsetOffsets.count(BaseDecl) && "vbase offset offset already exists!"); - int64_t VBaseOffsetOffset = getCurrentOffsetOffset(); - VBaseOffsetOffsets.insert(std::make_pair(BaseDecl, VBaseOffsetOffset)); + CharUnits VBaseOffsetOffset = getCurrentOffsetOffset(); + VBaseOffsetOffsets.insert( + std::make_pair(BaseDecl, VBaseOffsetOffset)); - Components.push_back(VTableComponent::MakeVBaseOffset(Offset)); + Components.push_back( + VTableComponent::MakeVBaseOffset(Offset)); } // Check the base class looking for more vbase offsets. @@ -950,7 +956,7 @@ public: typedef llvm::SmallSetVector<const CXXRecordDecl *, 8> PrimaryBasesSetVectorTy; - typedef llvm::DenseMap<const CXXRecordDecl *, int64_t> + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> VBaseOffsetOffsetsMapTy; typedef llvm::DenseMap<BaseSubobject, uint64_t> @@ -966,7 +972,7 @@ private: /// MostDerivedClassOffset - If we're building a construction vtable, this /// holds the offset from the layout class to the most derived class. - const uint64_t MostDerivedClassOffset; + const CharUnits MostDerivedClassOffset; /// MostDerivedClassIsVirtual - Whether the most derived class is a virtual /// base. (This only makes sense when building a construction vtable). @@ -1001,23 +1007,26 @@ private: /// (Used for computing 'this' pointer adjustment thunks. struct MethodInfo { /// BaseOffset - The base offset of this method. - const uint64_t BaseOffset; + const CharUnits BaseOffset; /// BaseOffsetInLayoutClass - The base offset in the layout class of this /// method. - const uint64_t BaseOffsetInLayoutClass; + const CharUnits BaseOffsetInLayoutClass; /// VTableIndex - The index in the vtable that this method has. /// (For destructors, this is the index of the complete destructor). const uint64_t VTableIndex; - MethodInfo(uint64_t BaseOffset, uint64_t BaseOffsetInLayoutClass, + MethodInfo(CharUnits BaseOffset, CharUnits BaseOffsetInLayoutClass, uint64_t VTableIndex) : BaseOffset(BaseOffset), BaseOffsetInLayoutClass(BaseOffsetInLayoutClass), VTableIndex(VTableIndex) { } - MethodInfo() : BaseOffset(0), BaseOffsetInLayoutClass(0), VTableIndex(0) { } + MethodInfo() + : BaseOffset(CharUnits::Zero()), + BaseOffsetInLayoutClass(CharUnits::Zero()), + VTableIndex(0) { } }; typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; @@ -1066,7 +1075,7 @@ private: /// final overrider. ThisAdjustment ComputeThisAdjustment(const CXXMethodDecl *MD, - uint64_t BaseOffsetInLayoutClass, + CharUnits BaseOffsetInLayoutClass, FinalOverriders::OverriderInfo Overrider); /// AddMethod - Add a single virtual member function to the vtable @@ -1093,16 +1102,16 @@ private: /// C-in-D's copy of A's vtable is never referenced, so this is not /// necessary. bool IsOverriderUsed(const CXXMethodDecl *Overrider, - uint64_t BaseOffsetInLayoutClass, + CharUnits BaseOffsetInLayoutClass, const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass) const; + CharUnits FirstBaseOffsetInLayoutClass) const; /// AddMethods - Add the methods of this base subobject and all its /// primary bases to the vtable components vector. - void AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, + void AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass, + CharUnits FirstBaseOffsetInLayoutClass, PrimaryBasesSetVectorTy &PrimaryBases); // LayoutVTable - Layout the vtable for the given base class, including its @@ -1120,7 +1129,7 @@ private: void LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, bool BaseIsVirtualInLayoutClass, - uint64_t OffsetInLayoutClass); + CharUnits OffsetInLayoutClass); /// LayoutSecondaryVTables - Layout the secondary vtables for the given base /// subobject. @@ -1128,12 +1137,12 @@ private: /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base /// or a direct or indirect base of a virtual base. void LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, - uint64_t OffsetInLayoutClass); + CharUnits OffsetInLayoutClass); /// DeterminePrimaryVirtualBases - Determine the primary virtual bases in this /// class hierarchy. void DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, - uint64_t OffsetInLayoutClass, + CharUnits OffsetInLayoutClass, VisitedVirtualBasesSetTy &VBases); /// LayoutVTablesForVirtualBases - Layout vtables for all virtual bases of the @@ -1149,8 +1158,9 @@ private: public: VTableBuilder(CodeGenVTables &VTables, const CXXRecordDecl *MostDerivedClass, - uint64_t MostDerivedClassOffset, bool MostDerivedClassIsVirtual, - const CXXRecordDecl *LayoutClass) + CharUnits MostDerivedClassOffset, + bool MostDerivedClassIsVirtual, const + CXXRecordDecl *LayoutClass) : VTables(VTables), MostDerivedClass(MostDerivedClass), MostDerivedClassOffset(MostDerivedClassOffset), MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), @@ -1325,15 +1335,15 @@ ReturnAdjustment VTableBuilder::ComputeReturnAdjustment(BaseOffset Offset) { if (Offset.DerivedClass == MostDerivedClass) { // We can get the offset offset directly from our map. Adjustment.VBaseOffsetOffset = - VBaseOffsetOffsets.lookup(Offset.VirtualBase); + VBaseOffsetOffsets.lookup(Offset.VirtualBase).getQuantity(); } else { Adjustment.VBaseOffsetOffset = VTables.getVirtualBaseOffsetOffset(Offset.DerivedClass, - Offset.VirtualBase); + Offset.VirtualBase).getQuantity(); } } - Adjustment.NonVirtual = Offset.NonVirtualOffset; + Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity(); } return Adjustment; @@ -1360,8 +1370,7 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, I != E; ++I) { BaseOffset Offset = ComputeBaseOffset(Context, DerivedRD, *I); - // FIXME: Should not use * 8 here. - uint64_t OffsetToBaseSubobject = Offset.NonVirtualOffset * 8; + CharUnits OffsetToBaseSubobject = Offset.NonVirtualOffset; if (Offset.VirtualBase) { // If we have a virtual base class, the non-virtual offset is relative @@ -1372,7 +1381,7 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, /// Get the virtual base offset, relative to the most derived class /// layout. OffsetToBaseSubobject += - LayoutClassLayout.getVBaseClassOffsetInBits(Offset.VirtualBase); + LayoutClassLayout.getVBaseClassOffset(Offset.VirtualBase); } else { // Otherwise, the non-virtual offset is relative to the derived class // offset. @@ -1393,13 +1402,13 @@ VTableBuilder::ComputeThisAdjustmentBaseOffset(BaseSubobject Base, ThisAdjustment VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, - uint64_t BaseOffsetInLayoutClass, + CharUnits BaseOffsetInLayoutClass, FinalOverriders::OverriderInfo Overrider) { // Ignore adjustments for pure virtual member functions. if (Overrider.Method->isPure()) return ThisAdjustment(); - BaseSubobject OverriddenBaseSubobject(MD->getParent(), + BaseSubobject OverriddenBaseSubobject(MD->getParent(), BaseOffsetInLayoutClass); BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(), @@ -1422,18 +1431,21 @@ VTableBuilder::ComputeThisAdjustment(const CXXMethodDecl *MD, // build them. VCallAndVBaseOffsetBuilder Builder(MostDerivedClass, MostDerivedClass, /*FinalOverriders=*/0, - BaseSubobject(Offset.VirtualBase, 0), + BaseSubobject(Offset.VirtualBase, + CharUnits::Zero()), /*BaseIsVirtual=*/true, - /*OffsetInLayoutClass=*/0); + /*OffsetInLayoutClass=*/ + CharUnits::Zero()); VCallOffsets = Builder.getVCallOffsets(); } - Adjustment.VCallOffsetOffset = VCallOffsets.getVCallOffsetOffset(MD); + Adjustment.VCallOffsetOffset = + VCallOffsets.getVCallOffsetOffset(MD).getQuantity(); } // Set the non-virtual part of the adjustment. - Adjustment.NonVirtual = Offset.NonVirtualOffset; + Adjustment.NonVirtual = Offset.NonVirtualOffset.getQuantity(); return Adjustment; } @@ -1489,9 +1501,9 @@ OverridesIndirectMethodInBases(const CXXMethodDecl *MD, bool VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, - uint64_t BaseOffsetInLayoutClass, + CharUnits BaseOffsetInLayoutClass, const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass) const { + CharUnits FirstBaseOffsetInLayoutClass) const { // If the base and the first base in the primary base chain have the same // offsets, then this overrider will be used. if (BaseOffsetInLayoutClass == FirstBaseOffsetInLayoutClass) @@ -1529,7 +1541,7 @@ VTableBuilder::IsOverriderUsed(const CXXMethodDecl *Overrider, // Now check if this is the primary base that is not a primary base in the // most derived class. - if (LayoutClassLayout.getVBaseClassOffsetInBits(PrimaryBase) != + if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != FirstBaseOffsetInLayoutClass) { // We found it, stop walking the chain. break; @@ -1576,16 +1588,16 @@ FindNearestOverriddenMethod(const CXXMethodDecl *MD, } void -VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, +VTableBuilder::AddMethods(BaseSubobject Base, CharUnits BaseOffsetInLayoutClass, const CXXRecordDecl *FirstBaseInPrimaryBaseChain, - uint64_t FirstBaseOffsetInLayoutClass, + CharUnits FirstBaseOffsetInLayoutClass, PrimaryBasesSetVectorTy &PrimaryBases) { const CXXRecordDecl *RD = Base.getBase(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) { - uint64_t PrimaryBaseOffset; - uint64_t PrimaryBaseOffsetInLayoutClass; + CharUnits PrimaryBaseOffset; + CharUnits PrimaryBaseOffsetInLayoutClass; if (Layout.isPrimaryBaseVirtual()) { assert(Layout.getVBaseClassOffsetInBits(PrimaryBase) == 0 && "Primary vbase should have a zero offset!"); @@ -1594,13 +1606,13 @@ VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, Context.getASTRecordLayout(MostDerivedClass); PrimaryBaseOffset = - MostDerivedClassLayout.getVBaseClassOffsetInBits(PrimaryBase); + MostDerivedClassLayout.getVBaseClassOffset(PrimaryBase); const ASTRecordLayout &LayoutClassLayout = Context.getASTRecordLayout(LayoutClass); PrimaryBaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffsetInBits(PrimaryBase); + LayoutClassLayout.getVBaseClassOffset(PrimaryBase); } else { assert(Layout.getBaseClassOffsetInBits(PrimaryBase) == 0 && "Primary base should have a zero offset!"); @@ -1642,8 +1654,7 @@ VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, "Did not find the overridden method!"); MethodInfo &OverriddenMethodInfo = MethodInfoMap[OverriddenMD]; - MethodInfo MethodInfo(Base.getBaseOffset(), - BaseOffsetInLayoutClass, + MethodInfo MethodInfo(Base.getBaseOffset(), BaseOffsetInLayoutClass, OverriddenMethodInfo.VTableIndex); assert(!MethodInfoMap.count(MD) && @@ -1716,7 +1727,8 @@ VTableBuilder::AddMethods(BaseSubobject Base, uint64_t BaseOffsetInLayoutClass, } void VTableBuilder::LayoutVTable() { - LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, 0), + LayoutPrimaryAndSecondaryVTables(BaseSubobject(MostDerivedClass, + CharUnits::Zero()), /*BaseIsMorallyVirtual=*/false, MostDerivedClassIsVirtual, MostDerivedClassOffset); @@ -1724,7 +1736,7 @@ void VTableBuilder::LayoutVTable() { VisitedVirtualBasesSetTy VBases; // Determine the primary virtual bases. - DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset, + DeterminePrimaryVirtualBases(MostDerivedClass, MostDerivedClassOffset, VBases); VBases.clear(); @@ -1735,7 +1747,7 @@ void VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, bool BaseIsVirtualInLayoutClass, - uint64_t OffsetInLayoutClass) { + CharUnits OffsetInLayoutClass) { assert(Base.getBase()->isDynamicClass() && "class does not have a vtable!"); // Add vcall and vbase offsets for this vtable. @@ -1758,10 +1770,9 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, VBaseOffsetOffsets = Builder.getVBaseOffsetOffsets(); // Add the offset to top. - // FIXME: We should not use / 8 here. - int64_t OffsetToTop = -(int64_t)(OffsetInLayoutClass - - MostDerivedClassOffset) / 8; - Components.push_back(VTableComponent::MakeOffsetToTop(OffsetToTop)); + CharUnits OffsetToTop = MostDerivedClassOffset - OffsetInLayoutClass; + Components.push_back( + VTableComponent::MakeOffsetToTop(OffsetToTop)); // Next, add the RTTI. Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); @@ -1770,7 +1781,8 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, // Now go through all virtual member functions and add them. PrimaryBasesSetVectorTy PrimaryBases; - AddMethods(Base, OffsetInLayoutClass, Base.getBase(), OffsetInLayoutClass, + AddMethods(Base, OffsetInLayoutClass, + Base.getBase(), OffsetInLayoutClass, PrimaryBases); // Compute 'this' pointer adjustments. @@ -1779,8 +1791,9 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, // Add all address points. const CXXRecordDecl *RD = Base.getBase(); while (true) { - AddressPoints.insert(std::make_pair(BaseSubobject(RD, OffsetInLayoutClass), - AddressPoint)); + AddressPoints.insert(std::make_pair( + BaseSubobject(RD, OffsetInLayoutClass), + AddressPoint)); const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); @@ -1794,7 +1807,7 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, const ASTRecordLayout &LayoutClassLayout = Context.getASTRecordLayout(LayoutClass); - if (LayoutClassLayout.getVBaseClassOffsetInBits(PrimaryBase) != + if (LayoutClassLayout.getVBaseClassOffset(PrimaryBase) != OffsetInLayoutClass) { // We don't want to add this class (or any of its primary bases). break; @@ -1810,7 +1823,7 @@ VTableBuilder::LayoutPrimaryAndSecondaryVTables(BaseSubobject Base, void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, bool BaseIsMorallyVirtual, - uint64_t OffsetInLayoutClass) { + CharUnits OffsetInLayoutClass) { // Itanium C++ ABI 2.5.2: // Following the primary virtual table of a derived class are secondary // virtual tables for each of its proper base classes, except any primary @@ -1844,10 +1857,11 @@ void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, } // Get the base offset of this base. - uint64_t RelativeBaseOffset = Layout.getBaseClassOffsetInBits(BaseDecl); - uint64_t BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; + CharUnits RelativeBaseOffset = Layout.getBaseClassOffset(BaseDecl); + CharUnits BaseOffset = Base.getBaseOffset() + RelativeBaseOffset; - uint64_t BaseOffsetInLayoutClass = OffsetInLayoutClass + RelativeBaseOffset; + CharUnits BaseOffsetInLayoutClass = + OffsetInLayoutClass + RelativeBaseOffset; // Don't emit a secondary vtable for a primary base. We might however want // to emit secondary vtables for other bases of this base. @@ -1858,16 +1872,17 @@ void VTableBuilder::LayoutSecondaryVTables(BaseSubobject Base, } // Layout the primary vtable (and any secondary vtables) for this base. - LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), - BaseIsMorallyVirtual, - /*BaseIsVirtualInLayoutClass=*/false, - BaseOffsetInLayoutClass); + LayoutPrimaryAndSecondaryVTables( + BaseSubobject(BaseDecl, BaseOffset), + BaseIsMorallyVirtual, + /*BaseIsVirtualInLayoutClass=*/false, + BaseOffsetInLayoutClass); } } void VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, - uint64_t OffsetInLayoutClass, + CharUnits OffsetInLayoutClass, VisitedVirtualBasesSetTy &VBases) { const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); @@ -1884,8 +1899,8 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &LayoutClassLayout = Context.getASTRecordLayout(LayoutClass); - uint64_t PrimaryBaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffsetInBits(PrimaryBase); + CharUnits PrimaryBaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(PrimaryBase); // We know that the base is not a primary base in the layout class if // the base offsets are different. @@ -1904,7 +1919,7 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); - uint64_t BaseOffsetInLayoutClass; + CharUnits BaseOffsetInLayoutClass; if (I->isVirtual()) { if (!VBases.insert(BaseDecl)) @@ -1914,10 +1929,10 @@ VTableBuilder::DeterminePrimaryVirtualBases(const CXXRecordDecl *RD, Context.getASTRecordLayout(LayoutClass); BaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffsetInBits(BaseDecl); + LayoutClassLayout.getVBaseClassOffset(BaseDecl); } else { BaseOffsetInLayoutClass = - OffsetInLayoutClass + Layout.getBaseClassOffsetInBits(BaseDecl); + OffsetInLayoutClass + Layout.getBaseClassOffset(BaseDecl); } DeterminePrimaryVirtualBases(BaseDecl, BaseOffsetInLayoutClass, VBases); @@ -1942,18 +1957,19 @@ VTableBuilder::LayoutVTablesForVirtualBases(const CXXRecordDecl *RD, !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) { const ASTRecordLayout &MostDerivedClassLayout = Context.getASTRecordLayout(MostDerivedClass); - uint64_t BaseOffset = - MostDerivedClassLayout.getVBaseClassOffsetInBits(BaseDecl); + CharUnits BaseOffset = + MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); const ASTRecordLayout &LayoutClassLayout = Context.getASTRecordLayout(LayoutClass); - uint64_t BaseOffsetInLayoutClass = - LayoutClassLayout.getVBaseClassOffsetInBits(BaseDecl); - - LayoutPrimaryAndSecondaryVTables(BaseSubobject(BaseDecl, BaseOffset), - /*BaseIsMorallyVirtual=*/true, - /*BaseIsVirtualInLayoutClass=*/true, - BaseOffsetInLayoutClass); + CharUnits BaseOffsetInLayoutClass = + LayoutClassLayout.getVBaseClassOffset(BaseDecl); + + LayoutPrimaryAndSecondaryVTables( + BaseSubobject(BaseDecl, BaseOffset), + /*BaseIsMorallyVirtual=*/true, + /*BaseIsVirtualInLayoutClass=*/true, + BaseOffsetInLayoutClass); } // We only need to check the base for virtual base vtables if it actually @@ -1969,8 +1985,7 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { if (isBuildingConstructorVTable()) { Out << "Construction vtable for ('"; Out << MostDerivedClass->getQualifiedNameAsString() << "', "; - // FIXME: Don't use / 8 . - Out << MostDerivedClassOffset / 8 << ") in '"; + Out << MostDerivedClassOffset.getQuantity() << ") in '"; Out << LayoutClass->getQualifiedNameAsString(); } else { Out << "Vtable for '"; @@ -2002,15 +2017,21 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { switch (Component.getKind()) { case VTableComponent::CK_VCallOffset: - Out << "vcall_offset (" << Component.getVCallOffset() << ")"; + Out << "vcall_offset (" + << Component.getVCallOffset().getQuantity() + << ")"; break; case VTableComponent::CK_VBaseOffset: - Out << "vbase_offset (" << Component.getVBaseOffset() << ")"; + Out << "vbase_offset (" + << Component.getVBaseOffset().getQuantity() + << ")"; break; case VTableComponent::CK_OffsetToTop: - Out << "offset_to_top (" << Component.getOffsetToTop() << ")"; + Out << "offset_to_top (" + << Component.getOffsetToTop().getQuantity() + << ")"; break; case VTableComponent::CK_RTTI: @@ -2116,11 +2137,11 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { const BaseSubobject &Base = AddressPointsByIndex.find(NextIndex)->second; - // FIXME: Instead of dividing by 8, we should be using CharUnits. Out << " -- (" << Base.getBase()->getQualifiedNameAsString(); - Out << ", " << Base.getBaseOffset() / 8 << ") vtable address --\n"; + Out << ", " << Base.getBaseOffset().getQuantity(); + Out << ") vtable address --\n"; } else { - uint64_t BaseOffset = + CharUnits BaseOffset = AddressPointsByIndex.lower_bound(NextIndex)->second.getBaseOffset(); // We store the class names in a set to get a stable order. @@ -2136,9 +2157,8 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { for (std::set<std::string>::const_iterator I = ClassNames.begin(), E = ClassNames.end(); I != E; ++I) { - // FIXME: Instead of dividing by 8, we should be using CharUnits. Out << " -- (" << *I; - Out << ", " << BaseOffset / 8 << ") vtable address --\n"; + Out << ", " << BaseOffset.getQuantity() << ") vtable address --\n"; } } } @@ -2153,12 +2173,13 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { // We store the virtual base class names and their offsets in a map to get // a stable order. - std::map<std::string, int64_t> ClassNamesAndOffsets; + std::map<std::string, CharUnits> ClassNamesAndOffsets; for (VBaseOffsetOffsetsMapTy::const_iterator I = VBaseOffsetOffsets.begin(), E = VBaseOffsetOffsets.end(); I != E; ++I) { std::string ClassName = I->first->getQualifiedNameAsString(); - int64_t OffsetOffset = I->second; - ClassNamesAndOffsets.insert(std::make_pair(ClassName, OffsetOffset)); + CharUnits OffsetOffset = I->second; + ClassNamesAndOffsets.insert( + std::make_pair(ClassName, OffsetOffset)); } Out << "Virtual base offset offsets for '"; @@ -2166,10 +2187,10 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { Out << ClassNamesAndOffsets.size(); Out << (ClassNamesAndOffsets.size() == 1 ? " entry" : " entries") << ").\n"; - for (std::map<std::string, int64_t>::const_iterator I = + for (std::map<std::string, CharUnits>::const_iterator I = ClassNamesAndOffsets.begin(), E = ClassNamesAndOffsets.end(); I != E; ++I) - Out << " " << I->first << " | " << I->second << '\n'; + Out << " " << I->first << " | " << I->second.getQuantity() << '\n'; Out << "\n"; } @@ -2233,9 +2254,51 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { } Out << '\n'; + } + } + + // Compute the vtable indices for all the member functions. + // Store them in a map keyed by the index so we'll get a sorted table. + std::map<uint64_t, std::string> IndicesMap; + + for (CXXRecordDecl::method_iterator i = MostDerivedClass->method_begin(), + e = MostDerivedClass->method_end(); i != e; ++i) { + const CXXMethodDecl *MD = *i; + + // We only want virtual member functions. + if (!MD->isVirtual()) + continue; + + std::string MethodName = + PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, + MD); + + if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) { + IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Complete))] = + MethodName + " [complete]"; + IndicesMap[VTables.getMethodVTableIndex(GlobalDecl(DD, Dtor_Deleting))] = + MethodName + " [deleting]"; + } else { + IndicesMap[VTables.getMethodVTableIndex(MD)] = MethodName; + } + } + + // Print the vtable indices for all the member functions. + if (!IndicesMap.empty()) { + Out << "VTable indices for '"; + Out << MostDerivedClass->getQualifiedNameAsString(); + Out << "' (" << IndicesMap.size() << " entries).\n"; + for (std::map<uint64_t, std::string>::const_iterator I = IndicesMap.begin(), + E = IndicesMap.end(); I != E; ++I) { + uint64_t VTableIndex = I->first; + const std::string &MethodName = I->second; + + Out << llvm::format(" %4u | ", VTableIndex) << MethodName << '\n'; } } + + Out << '\n'; } } @@ -2243,14 +2306,16 @@ void VTableBuilder::dumpLayout(llvm::raw_ostream& Out) { static void CollectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context, VTableBuilder::PrimaryBasesSetVectorTy &PrimaryBases) { - while (RD) { - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - if (PrimaryBase) - PrimaryBases.insert(PrimaryBase); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); - RD = PrimaryBase; - } + if (!PrimaryBase) + return; + + CollectPrimaryBases(PrimaryBase, Context, PrimaryBases); + + if (!PrimaryBases.insert(PrimaryBase)) + assert(false && "Found a duplicate primary base!"); } void CodeGenVTables::ComputeMethodVTableIndices(const CXXRecordDecl *RD) { @@ -2410,8 +2475,9 @@ uint64_t CodeGenVTables::getMethodVTableIndex(GlobalDecl GD) { return I->second; } -int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase) { +CharUnits +CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase) { ClassPairTy ClassPair(RD, VBase); VirtualBaseClassOffsetOffsetsMapTy::iterator I = @@ -2420,9 +2486,9 @@ int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, return I->second; VCallAndVBaseOffsetBuilder Builder(RD, RD, /*FinalOverriders=*/0, - BaseSubobject(RD, 0), + BaseSubobject(RD, CharUnits::Zero()), /*BaseIsVirtual=*/false, - /*OffsetInLayoutClass=*/0); + /*OffsetInLayoutClass=*/CharUnits::Zero()); for (VCallAndVBaseOffsetBuilder::VBaseOffsetOffsetsMapTy::const_iterator I = Builder.getVBaseOffsetOffsets().begin(), @@ -2430,7 +2496,8 @@ int64_t CodeGenVTables::getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, // Insert all types. ClassPairTy ClassPair(RD, I->first); - VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second)); + VirtualBaseClassOffsetOffsets.insert( + std::make_pair(ClassPair, I->second)); } I = VirtualBaseClassOffsetOffsets.find(ClassPair); @@ -2531,7 +2598,7 @@ static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD, Fn->getVisibility() != llvm::GlobalVariable::DefaultVisibility) return; - if (MD->hasAttr<VisibilityAttr>()) + if (MD->getExplicitVisibility()) return; switch (MD->getTemplateSpecializationKind()) { @@ -2559,8 +2626,19 @@ static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD, Fn->setVisibility(llvm::GlobalValue::HiddenVisibility); } -void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, - const ThunkInfo &Thunk) { +#ifndef NDEBUG +static bool similar(const ABIArgInfo &infoL, CanQualType typeL, + const ABIArgInfo &infoR, CanQualType typeR) { + return (infoL.getKind() == infoR.getKind() && + (typeL == typeR || + (isa<PointerType>(typeL) && isa<PointerType>(typeR)) || + (isa<ReferenceType>(typeL) && isa<ReferenceType>(typeR)))); +} +#endif + +void CodeGenFunction::GenerateThunk(llvm::Function *Fn, + const CGFunctionInfo &FnInfo, + GlobalDecl GD, const ThunkInfo &Thunk) { const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); QualType ResultType = FPT->getResultType(); @@ -2580,10 +2658,11 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, E = MD->param_end(); I != E; ++I) { ParmVarDecl *Param = *I; - FunctionArgs.push_back(std::make_pair(Param, Param->getType())); + FunctionArgs.push_back(Param); } - StartFunction(GlobalDecl(), ResultType, Fn, FunctionArgs, SourceLocation()); + StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs, + SourceLocation()); CGM.getCXXABI().EmitInstanceFunctionProlog(*this); @@ -2596,16 +2675,13 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, CallArgList CallArgs; // Add our adjusted 'this' pointer. - CallArgs.push_back(std::make_pair(RValue::get(AdjustedThisPtr), ThisType)); + CallArgs.add(RValue::get(AdjustedThisPtr), ThisType); // Add the rest of the parameters. for (FunctionDecl::param_const_iterator I = MD->param_begin(), E = MD->param_end(); I != E; ++I) { - ParmVarDecl *Param = *I; - QualType ArgType = Param->getType(); - RValue Arg = EmitDelegateCallArg(Param); - - CallArgs.push_back(std::make_pair(Arg, ArgType)); + ParmVarDecl *param = *I; + EmitDelegateCallArg(CallArgs, param); } // Get our callee. @@ -2614,9 +2690,20 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, FPT->isVariadic()); llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, /*ForVTable=*/true); - const CGFunctionInfo &FnInfo = - CGM.getTypes().getFunctionInfo(ResultType, CallArgs, - FPT->getExtInfo()); +#ifndef NDEBUG + const CGFunctionInfo &CallFnInfo = + CGM.getTypes().getFunctionInfo(ResultType, CallArgs, FPT->getExtInfo()); + assert(CallFnInfo.getRegParm() == FnInfo.getRegParm() && + CallFnInfo.isNoReturn() == FnInfo.isNoReturn() && + CallFnInfo.getCallingConvention() == FnInfo.getCallingConvention()); + assert(similar(CallFnInfo.getReturnInfo(), CallFnInfo.getReturnType(), + FnInfo.getReturnInfo(), FnInfo.getReturnType())); + assert(CallFnInfo.arg_size() == FnInfo.arg_size()); + for (unsigned i = 0, e = FnInfo.arg_size(); i != e; ++i) + assert(similar(CallFnInfo.arg_begin()[i].info, + CallFnInfo.arg_begin()[i].type, + FnInfo.arg_begin()[i].info, FnInfo.arg_begin()[i].type)); +#endif // Determine whether we have a return value slot to use. ReturnValueSlot Slot; @@ -2658,8 +2745,7 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, Builder.CreateBr(AdjustEnd); EmitBlock(AdjustEnd); - llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType()); - PHI->reserveOperandSpace(2); + llvm::PHINode *PHI = Builder.CreatePHI(ReturnValue->getType(), 2); PHI->addIncoming(ReturnValue, AdjustNotNull); PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()), AdjustNull); @@ -2684,6 +2770,9 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, GlobalDecl GD, void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, bool UseAvailableExternallyLinkage) { + const CGFunctionInfo &FnInfo = CGM.getTypes().getFunctionInfo(GD); + + // FIXME: re-use FnInfo in this computation. llvm::Constant *Entry = CGM.GetAddrOfThunk(GD, Thunk); // Strip off a bitcast if we got one back. @@ -2735,7 +2824,7 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, } // Actually generate the thunk body. - CodeGenFunction(CGM).GenerateThunk(ThunkFn, GD, Thunk); + CodeGenFunction(CGM).GenerateThunk(ThunkFn, FnInfo, GD, Thunk); if (UseAvailableExternallyLinkage) ThunkFn->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage); @@ -2796,7 +2885,8 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD, if (Entry.getPointer()) return; - VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); + VTableBuilder Builder(*this, RD, CharUnits::Zero(), + /*MostDerivedClassIsVirtual=*/0, RD); // Add the VTable layout. uint64_t NumVTableComponents = Builder.getNumVTableComponents(); @@ -2864,7 +2954,8 @@ void CodeGenVTables::ComputeVTableRelatedInformation(const CXXRecordDecl *RD, // Insert all types. ClassPairTy ClassPair(RD, I->first); - VirtualBaseClassOffsetOffsets.insert(std::make_pair(ClassPair, I->second)); + VirtualBaseClassOffsetOffsets.insert( + std::make_pair(ClassPair, I->second)); } } @@ -2895,15 +2986,18 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, switch (Component.getKind()) { case VTableComponent::CK_VCallOffset: - Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVCallOffset()); + Init = llvm::ConstantInt::get(PtrDiffTy, + Component.getVCallOffset().getQuantity()); Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); break; case VTableComponent::CK_VBaseOffset: - Init = llvm::ConstantInt::get(PtrDiffTy, Component.getVBaseOffset()); + Init = llvm::ConstantInt::get(PtrDiffTy, + Component.getVBaseOffset().getQuantity()); Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); break; case VTableComponent::CK_OffsetToTop: - Init = llvm::ConstantInt::get(PtrDiffTy, Component.getOffsetToTop()); + Init = llvm::ConstantInt::get(PtrDiffTy, + Component.getOffsetToTop().getQuantity()); Init = llvm::ConstantExpr::getIntToPtr(Init, Int8PtrTy); break; case VTableComponent::CK_RTTI: @@ -3001,7 +3095,8 @@ CodeGenVTables::EmitVTableDefinition(llvm::GlobalVariable *VTable, const CXXRecordDecl *RD) { // Dump the vtable layout if necessary. if (CGM.getLangOptions().DumpVTableLayouts) { - VTableBuilder Builder(*this, RD, 0, /*MostDerivedClassIsVirtual=*/0, RD); + VTableBuilder Builder(*this, RD, CharUnits::Zero(), + /*MostDerivedClassIsVirtual=*/0, RD); Builder.dumpLayout(llvm::errs()); } @@ -3028,8 +3123,10 @@ llvm::GlobalVariable * CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base, bool BaseIsVirtual, + llvm::GlobalVariable::LinkageTypes Linkage, VTableAddressPointsMapTy& AddressPoints) { - VTableBuilder Builder(*this, Base.getBase(), Base.getBaseOffset(), + VTableBuilder Builder(*this, Base.getBase(), + Base.getBaseOffset(), /*MostDerivedClassIsVirtual=*/BaseIsVirtual, RD); // Dump the vtable layout if necessary. @@ -3044,7 +3141,8 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, llvm::SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); CGM.getCXXABI().getMangleContext(). - mangleCXXCtorVTable(RD, Base.getBaseOffset() / 8, Base.getBase(), Out); + mangleCXXCtorVTable(RD, Base.getBaseOffset().getQuantity(), Base.getBase(), + Out); Out.flush(); llvm::StringRef Name = OutName.str(); @@ -3054,8 +3152,11 @@ CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, // Create the variable that will hold the construction vtable. llvm::GlobalVariable *VTable = - CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, - llvm::GlobalValue::InternalLinkage); + CGM.CreateOrReplaceCXXRuntimeVariable(Name, ArrayType, Linkage); + CGM.setTypeVisibility(VTable, RD, CodeGenModule::TVK_ForConstructionVTable); + + // V-tables are always unnamed_addr. + VTable->setUnnamedAddr(true); // Add the thunks. VTableThunksTy VTableThunks; diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.h b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.h index 7c119fa..e830e9a 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGVTables.h @@ -1,4 +1,4 @@ -//===--- CGVTables.h - Emit LLVM Code for C++ vtables ---------------------===// +//===--- CGVTables.h - Emit LLVM Code for C++ vtables -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -17,6 +17,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/GlobalVariable.h" #include "clang/Basic/ABI.h" +#include "clang/AST/CharUnits.h" #include "GlobalDecl.h" namespace clang { @@ -33,17 +34,17 @@ class BaseSubobject { const CXXRecordDecl *Base; /// BaseOffset - The offset from the most derived class to the base class. - uint64_t BaseOffset; + CharUnits BaseOffset; public: - BaseSubobject(const CXXRecordDecl *Base, uint64_t BaseOffset) + BaseSubobject(const CXXRecordDecl *Base, CharUnits BaseOffset) : Base(Base), BaseOffset(BaseOffset) { } /// getBase - Returns the base class declaration. const CXXRecordDecl *getBase() const { return Base; } /// getBaseOffset - Returns the base class offset. - uint64_t getBaseOffset() const { return BaseOffset; } + CharUnits getBaseOffset() const { return BaseOffset; } friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) { return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset; @@ -59,19 +60,19 @@ template<> struct DenseMapInfo<clang::CodeGen::BaseSubobject> { static clang::CodeGen::BaseSubobject getEmptyKey() { return clang::CodeGen::BaseSubobject( DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(), - DenseMapInfo<uint64_t>::getEmptyKey()); + clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getEmptyKey())); } static clang::CodeGen::BaseSubobject getTombstoneKey() { return clang::CodeGen::BaseSubobject( DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(), - DenseMapInfo<uint64_t>::getTombstoneKey()); + clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getTombstoneKey())); } static unsigned getHashValue(const clang::CodeGen::BaseSubobject &Base) { return DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^ - DenseMapInfo<uint64_t>::getHashValue(Base.getBaseOffset()); + DenseMapInfo<int64_t>::getHashValue(Base.getBaseOffset().getQuantity()); } static bool isEqual(const clang::CodeGen::BaseSubobject &LHS, @@ -102,9 +103,9 @@ class CodeGenVTables { const CXXRecordDecl *> ClassPairTy; /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to - /// the address point) in bytes where the offsets for virtual bases of a class + /// the address point) in chars where the offsets for virtual bases of a class /// are stored. - typedef llvm::DenseMap<ClassPairTy, int64_t> + typedef llvm::DenseMap<ClassPairTy, CharUnits> VirtualBaseClassOffsetOffsetsMapTy; VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; @@ -234,13 +235,13 @@ public: /// stored. uint64_t getMethodVTableIndex(GlobalDecl GD); - /// getVirtualBaseOffsetOffset - Return the offset in bytes (relative to the + /// getVirtualBaseOffsetOffset - Return the offset in chars (relative to the /// vtable address point) where the offset of the virtual base that contains /// the given base is stored, otherwise, if no virtual base contains the given /// class, return 0. Base must be a virtual base class or an unambigious /// base. - int64_t getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *VBase); + CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase); /// getAddressPoint - Get the address point of the given subobject in the /// class decl. @@ -259,6 +260,7 @@ public: llvm::GlobalVariable * GenerateConstructionVTable(const CXXRecordDecl *RD, const BaseSubobject &Base, bool BaseIsVirtual, + llvm::GlobalVariable::LinkageTypes Linkage, VTableAddressPointsMapTy& AddressPoints); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp index a24bbc4..62fa1f9 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenAction.cpp @@ -216,7 +216,7 @@ void BackendConsumer::InlineAsmDiagHandler2(const llvm::SMDiagnostic &D, return; } - // Otherwise, report the backend error as occuring in the generated .s file. + // Otherwise, report the backend error as occurring in the generated .s file. // If Loc is invalid, we still need to report the error, it just gets no // location info. Diags.Report(Loc, diag::err_fe_inline_asm).AddString(Message); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp index f1b7286..626c2b0 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.cpp @@ -33,7 +33,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm) Target(CGM.getContext().Target), Builder(cgm.getModule().getContext()), BlockInfo(0), BlockPointer(0), NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1), - ExceptionSlot(0), DebugInfo(0), IndirectBranch(0), + ExceptionSlot(0), DebugInfo(0), DisableDebugInfo(false), IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), DidCallStackSave(false), UnreachableBlock(0), CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0), @@ -210,6 +210,7 @@ void CodeGenFunction::EmitMCountInstrumentation() { void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, + const CGFunctionInfo &FnInfo, const FunctionArgList &Args, SourceLocation StartLoc) { const Decl *D = GD.getDecl(); @@ -218,6 +219,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, CurCodeDecl = CurFuncDecl = D; FnRetTy = RetTy; CurFn = Fn; + CurFnInfo = &FnInfo; assert(CurFn->isDeclaration() && "Function already has body?"); // Pass inline keyword to optimizer if it appears explicitly on any @@ -239,7 +241,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, CGM.getModule().getOrInsertNamedMetadata("opencl.kernels"); llvm::Value *Op = Fn; - OpenCLMetadata->addOperand(llvm::MDNode::get(Context, &Op, 1)); + OpenCLMetadata->addOperand(llvm::MDNode::get(Context, Op)); } } @@ -275,11 +277,6 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, if (CGM.getCodeGenOpts().InstrumentForProfiling) EmitMCountInstrumentation(); - // FIXME: Leaked. - // CC info is ignored, hopefully? - CurFnInfo = &CGM.getTypes().getFunctionInfo(FnRetTy, Args, - FunctionType::ExtInfo()); - if (RetTy->isVoidType()) { // Void type; nothing to return. ReturnValue = 0; @@ -302,7 +299,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // emit the type size. for (FunctionArgList::const_iterator i = Args.begin(), e = Args.end(); i != e; ++i) { - QualType Ty = i->second; + QualType Ty = (*i)->getType(); if (Ty->isVariablyModifiedType()) EmitVLASize(Ty); @@ -332,12 +329,13 @@ static void TryMarkNoThrow(llvm::Function *F) { F->setDoesNotThrow(true); } -void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { +void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, + const CGFunctionInfo &FnInfo) { const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); // Check if we should generate debug info for this function. - if (CGM.getDebugInfo() && !FD->hasAttr<NoDebugAttr>()) - DebugInfo = CGM.getDebugInfo(); + if (CGM.getModuleDebugInfo() && !FD->hasAttr<NoDebugAttr>()) + DebugInfo = CGM.getModuleDebugInfo(); FunctionArgList Args; QualType ResTy = FD->getResultType(); @@ -346,20 +344,15 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn) { if (isa<CXXMethodDecl>(FD) && cast<CXXMethodDecl>(FD)->isInstance()) CGM.getCXXABI().BuildInstanceFunctionParams(*this, ResTy, Args); - if (FD->getNumParams()) { - const FunctionProtoType* FProto = FD->getType()->getAs<FunctionProtoType>(); - assert(FProto && "Function def must have prototype!"); - + if (FD->getNumParams()) for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) - Args.push_back(std::make_pair(FD->getParamDecl(i), - FProto->getArgType(i))); - } + Args.push_back(FD->getParamDecl(i)); SourceRange BodyRange; if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange(); // Emit the standard function prologue. - StartFunction(GD, ResTy, Fn, Args, BodyRange.getBegin()); + StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin()); // Generate the body of the function. if (isa<CXXDestructorDecl>(FD)) @@ -387,9 +380,12 @@ bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) { // If this is a label, we have to emit the code, consider something like: // if (0) { ... foo: bar(); } goto foo; + // + // TODO: If anyone cared, we could track __label__'s, since we know that you + // can't jump to one from outside their declared region. if (isa<LabelStmt>(S)) return true; - + // If this is a case/default statement, and we haven't seen a switch, we have // to emit the code. if (isa<SwitchCase>(S) && !IgnoreCaseStmts) @@ -407,26 +403,65 @@ bool CodeGenFunction::ContainsLabel(const Stmt *S, bool IgnoreCaseStmts) { return false; } +/// containsBreak - Return true if the statement contains a break out of it. +/// If the statement (recursively) contains a switch or loop with a break +/// inside of it, this is fine. +bool CodeGenFunction::containsBreak(const Stmt *S) { + // Null statement, not a label! + if (S == 0) return false; + + // If this is a switch or loop that defines its own break scope, then we can + // include it and anything inside of it. + if (isa<SwitchStmt>(S) || isa<WhileStmt>(S) || isa<DoStmt>(S) || + isa<ForStmt>(S)) + return false; + + if (isa<BreakStmt>(S)) + return true; + + // Scan subexpressions for verboten breaks. + for (Stmt::const_child_range I = S->children(); I; ++I) + if (containsBreak(*I)) + return true; + + return false; +} + + +/// ConstantFoldsToSimpleInteger - If the specified expression does not fold +/// to a constant, or if it does but contains a label, return false. If it +/// constant folds return true and set the boolean result in Result. +bool CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond, + bool &ResultBool) { + llvm::APInt ResultInt; + if (!ConstantFoldsToSimpleInteger(Cond, ResultInt)) + return false; + + ResultBool = ResultInt.getBoolValue(); + return true; +} -/// ConstantFoldsToSimpleInteger - If the sepcified expression does not fold to -/// a constant, or if it does but contains a label, return 0. If it constant -/// folds to 'true' and does not contain a label, return 1, if it constant folds -/// to 'false' and does not contain a label, return -1. -int CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond) { +/// ConstantFoldsToSimpleInteger - If the specified expression does not fold +/// to a constant, or if it does but contains a label, return false. If it +/// constant folds return true and set the folded value. +bool CodeGenFunction:: +ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APInt &ResultInt) { // FIXME: Rename and handle conversion of other evaluatable things // to bool. Expr::EvalResult Result; if (!Cond->Evaluate(Result, getContext()) || !Result.Val.isInt() || Result.HasSideEffects) - return 0; // Not foldable, not integer or not fully evaluatable. - + return false; // Not foldable, not integer or not fully evaluatable. + if (CodeGenFunction::ContainsLabel(Cond)) - return 0; // Contains a label. - - return Result.Val.getInt().getBoolValue() ? 1 : -1; + return false; // Contains a label. + + ResultInt = Result.Val.getInt(); + return true; } + /// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an if /// statement) to the specified blocks. Based on the condition, this might try /// to simplify the codegen of the conditional based on the branch. @@ -434,22 +469,24 @@ int CodeGenFunction::ConstantFoldsToSimpleInteger(const Expr *Cond) { void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock) { - if (const ParenExpr *PE = dyn_cast<ParenExpr>(Cond)) - return EmitBranchOnBoolExpr(PE->getSubExpr(), TrueBlock, FalseBlock); + Cond = Cond->IgnoreParens(); if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) { // Handle X && Y in a condition. if (CondBOp->getOpcode() == BO_LAnd) { // If we have "1 && X", simplify the code. "0 && X" would have constant // folded if the case was simple enough. - if (ConstantFoldsToSimpleInteger(CondBOp->getLHS()) == 1) { + bool ConstantBool = false; + if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), ConstantBool) && + ConstantBool) { // br(1 && X) -> br(X). return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); } // If we have "X && 1", simplify the code to use an uncond branch. // "X && 0" would have been constant folded to 0. - if (ConstantFoldsToSimpleInteger(CondBOp->getRHS()) == 1) { + if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) && + ConstantBool) { // br(X && 1) -> br(X). return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock); } @@ -468,17 +505,22 @@ void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond, eval.end(*this); return; - } else if (CondBOp->getOpcode() == BO_LOr) { + } + + if (CondBOp->getOpcode() == BO_LOr) { // If we have "0 || X", simplify the code. "1 || X" would have constant // folded if the case was simple enough. - if (ConstantFoldsToSimpleInteger(CondBOp->getLHS()) == -1) { + bool ConstantBool = false; + if (ConstantFoldsToSimpleInteger(CondBOp->getLHS(), ConstantBool) && + !ConstantBool) { // br(0 || X) -> br(X). return EmitBranchOnBoolExpr(CondBOp->getRHS(), TrueBlock, FalseBlock); } // If we have "X || 0", simplify the code to use an uncond branch. // "X || 1" would have been constant folded to 1. - if (ConstantFoldsToSimpleInteger(CondBOp->getRHS()) == -1) { + if (ConstantFoldsToSimpleInteger(CondBOp->getRHS(), ConstantBool) && + !ConstantBool) { // br(X || 0) -> br(X). return EmitBranchOnBoolExpr(CondBOp->getLHS(), TrueBlock, FalseBlock); } @@ -575,8 +617,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType, // count must be nonzero. CGF.EmitBlock(loopBB); - llvm::PHINode *cur = Builder.CreatePHI(i8p, "vla.cur"); - cur->reserveOperandSpace(2); + llvm::PHINode *cur = Builder.CreatePHI(i8p, 2, "vla.cur"); cur->addIncoming(begin, originBB); // memcpy the individual element bit-pattern. @@ -613,15 +654,16 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { DestPtr = Builder.CreateBitCast(DestPtr, BP, "tmp"); // Get size and alignment info for this aggregate. - std::pair<uint64_t, unsigned> TypeInfo = getContext().getTypeInfo(Ty); - uint64_t Size = TypeInfo.first / 8; - unsigned Align = TypeInfo.second / 8; + std::pair<CharUnits, CharUnits> TypeInfo = + getContext().getTypeInfoInChars(Ty); + CharUnits Size = TypeInfo.first; + CharUnits Align = TypeInfo.second; llvm::Value *SizeVal; const VariableArrayType *vla; // Don't bother emitting a zero-byte memset. - if (Size == 0) { + if (Size.isZero()) { // But note that getTypeInfo returns 0 for a VLA. if (const VariableArrayType *vlaType = dyn_cast_or_null<VariableArrayType>( @@ -632,7 +674,7 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { return; } } else { - SizeVal = llvm::ConstantInt::get(IntPtrTy, Size); + SizeVal = llvm::ConstantInt::get(IntPtrTy, Size.getQuantity()); vla = 0; } @@ -657,14 +699,15 @@ CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { if (vla) return emitNonZeroVLAInit(*this, Ty, DestPtr, SrcPtr, SizeVal); // Get and call the appropriate llvm.memcpy overload. - Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, Align, false); + Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, Align.getQuantity(), false); return; } // Otherwise, just memset the whole thing to zero. This is legal // because in LLVM, all default initializers (other than the ones we just // handled above) are guaranteed to have a bit pattern of all zeros. - Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal, Align, false); + Builder.CreateMemSet(DestPtr, Builder.getInt8(0), SizeVal, + Align.getQuantity(), false); } llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelDecl *L) { @@ -686,7 +729,8 @@ llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() { CGBuilderTy TmpBuilder(createBasicBlock("indirectgoto")); // Create the PHI node that indirect gotos will add entries to. - llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, "indirect.goto.dest"); + llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, 0, + "indirect.goto.dest"); // Create the indirect branch instruction. IndirectBranch = TmpBuilder.CreateIndirectBr(DestVal); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h index be646fb..169c576 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenFunction.h @@ -25,7 +25,6 @@ #include "llvm/Support/ValueHandle.h" #include "CodeGenModule.h" #include "CGBuilder.h" -#include "CGCall.h" #include "CGValue.h" namespace llvm { @@ -43,6 +42,7 @@ namespace clang { class APValue; class ASTContext; class CXXDestructorDecl; + class CXXForRangeStmt; class CXXTryStmt; class Decl; class LabelDecl; @@ -769,6 +769,11 @@ public: /// block through the normal cleanup handling code (if any) and then /// on to \arg Dest. void EmitBranchThroughCleanup(JumpDest Dest); + + /// isObviouslyBranchWithoutCleanups - Return true if a branch to the + /// specified destination obviously has no cleanups to run. 'false' is always + /// a conservatively correct answer for this method. + bool isObviouslyBranchWithoutCleanups(JumpDest Dest) const; /// EmitBranchThroughEHCleanup - Emit a branch from the current /// insert block through the EH cleanup handling code (if any) and @@ -944,6 +949,7 @@ public: const VarDecl *V); private: CGDebugInfo *DebugInfo; + bool DisableDebugInfo; /// IndirectBranch - The first time an indirect goto is seen we create a block /// with an indirect branch. Every time we see the address of a label taken, @@ -1030,7 +1036,14 @@ public: CodeGenTypes &getTypes() const { return CGM.getTypes(); } ASTContext &getContext() const; - CGDebugInfo *getDebugInfo() { return DebugInfo; } + CGDebugInfo *getDebugInfo() { + if (DisableDebugInfo) + return NULL; + return DebugInfo; + } + void disableDebugInfo() { DisableDebugInfo = true; } + void enableDebugInfo() { DisableDebugInfo = false; } + const LangOptions &getLangOptions() const { return CGM.getLangOptions(); } @@ -1100,15 +1113,13 @@ public: llvm::Constant *GenerateCopyHelperFunction(const CGBlockInfo &blockInfo); llvm::Constant *GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo); - llvm::Constant *GeneratebyrefCopyHelperFunction(const llvm::Type *, - BlockFieldFlags flags, - const VarDecl *BD); - llvm::Constant *GeneratebyrefDestroyHelperFunction(const llvm::Type *T, - BlockFieldFlags flags, - const VarDecl *BD); - void BuildBlockRelease(llvm::Value *DeclPtr, BlockFieldFlags flags); + class AutoVarEmission; + + void emitByrefStructureInit(const AutoVarEmission &emission); + void enterByrefCleanup(const AutoVarEmission &emission); + llvm::Value *LoadBlockStruct() { assert(BlockPointer && "no block pointer set!"); return BlockPointer; @@ -1122,9 +1133,11 @@ public: llvm::Value *GetAddrOfBlockDecl(const VarDecl *var, bool ByRef); const llvm::Type *BuildByRefType(const VarDecl *var); - void GenerateCode(GlobalDecl GD, llvm::Function *Fn); + void GenerateCode(GlobalDecl GD, llvm::Function *Fn, + const CGFunctionInfo &FnInfo); void StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, + const CGFunctionInfo &FnInfo, const FunctionArgList &Args, SourceLocation StartLoc); @@ -1141,7 +1154,8 @@ public: void FinishFunction(SourceLocation EndLoc=SourceLocation()); /// GenerateThunk - Generate a thunk for the given method. - void GenerateThunk(llvm::Function *Fn, GlobalDecl GD, const ThunkInfo &Thunk); + void GenerateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, + GlobalDecl GD, const ThunkInfo &Thunk); void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type, FunctionArgList &Args); @@ -1151,14 +1165,14 @@ public: /// void InitializeVTablePointer(BaseSubobject Base, const CXXRecordDecl *NearestVBase, - uint64_t OffsetFromNearestVBase, + CharUnits OffsetFromNearestVBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass); typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; void InitializeVTablePointers(BaseSubobject Base, const CXXRecordDecl *NearestVBase, - uint64_t OffsetFromNearestVBase, + CharUnits OffsetFromNearestVBase, bool BaseIsNonVirtualPrimaryBase, llvm::Constant *VTable, const CXXRecordDecl *VTableClass, @@ -1353,12 +1367,18 @@ public: /// always be accessible even if no aggregate location is provided. RValue EmitAnyExprToTemp(const Expr *E); - /// EmitsAnyExprToMem - Emits the code necessary to evaluate an + /// EmitAnyExprToMem - Emits the code necessary to evaluate an /// arbitrary expression into the given memory location. void EmitAnyExprToMem(const Expr *E, llvm::Value *Location, bool IsLocationVolatile, bool IsInitializer); + /// EmitExprAsInit - Emits the code necessary to initialize a + /// location in memory with the given initializer. + void EmitExprAsInit(const Expr *init, const VarDecl *var, + llvm::Value *loc, CharUnits alignment, + bool capturedByInit); + /// EmitAggregateCopy - Emit an aggrate copy. /// /// \param isVolatile - True iff either the source or the destination is @@ -1476,6 +1496,12 @@ public: void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, CXXCtorType CtorType, const FunctionArgList &Args); + // It's important not to confuse this and the previous function. Delegating + // constructors are the C++0x feature. The constructor delegate optimization + // is used to reduce duplication in the base and complete consturctors where + // they are substantially the same. + void EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor, + const FunctionArgList &Args); void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, @@ -1609,7 +1635,7 @@ public: llvm::GlobalValue::LinkageTypes Linkage); /// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl. - void EmitParmDecl(const VarDecl &D, llvm::Value *Arg); + void EmitParmDecl(const VarDecl &D, llvm::Value *Arg, unsigned ArgNo); /// protectFromPeepholes - Protect a value that we're intending to /// store to the side, but which will probably be used later, from @@ -1680,6 +1706,7 @@ public: void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false); void EmitCXXTryStmt(const CXXTryStmt &S); + void EmitCXXForRangeStmt(const CXXForRangeStmt &S); //===--------------------------------------------------------------------===// // LValue Expression Emission @@ -1775,7 +1802,7 @@ public: LValue EmitComplexAssignmentLValue(const BinaryOperator *E); LValue EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E); - // Note: only availabe for agg return types + // Note: only available for agg return types LValue EmitBinaryOperatorLValue(const BinaryOperator *E); LValue EmitCompoundAssignmentLValue(const CompoundAssignOperator *E); // Note: only available for agg return types @@ -2022,7 +2049,8 @@ public: const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> > &DtorsAndObjects); - void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D, + void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, + const VarDecl *D, llvm::GlobalVariable *Addr); void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest); @@ -2044,12 +2072,21 @@ public: /// that we can just remove the code. static bool ContainsLabel(const Stmt *S, bool IgnoreCaseStmts = false); + /// containsBreak - Return true if the statement contains a break out of it. + /// If the statement (recursively) contains a switch or loop with a break + /// inside of it, this is fine. + static bool containsBreak(const Stmt *S); + /// ConstantFoldsToSimpleInteger - If the specified expression does not fold - /// to a constant, or if it does but contains a label, return 0. If it - /// constant folds to 'true' and does not contain a label, return 1, if it - /// constant folds to 'false' and does not contain a label, return -1. - int ConstantFoldsToSimpleInteger(const Expr *Cond); + /// to a constant, or if it does but contains a label, return false. If it + /// constant folds return true and set the boolean result in Result. + bool ConstantFoldsToSimpleInteger(const Expr *Cond, bool &Result); + /// ConstantFoldsToSimpleInteger - If the specified expression does not fold + /// to a constant, or if it does but contains a label, return false. If it + /// constant folds return true and set the folded value. + bool ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APInt &Result); + /// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an /// if statement) to the specified blocks. Based on the condition, this might /// try to simplify the codegen of the conditional based on the branch. @@ -2061,12 +2098,12 @@ public: llvm::BasicBlock *getTrapBB(); /// EmitCallArg - Emit a single call argument. - RValue EmitCallArg(const Expr *E, QualType ArgType); + void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType); /// EmitDelegateCallArg - We are performing a delegate call; that /// is, the current function is delegating to another one. Produce /// a r-value suitable for passing the given parameter. - RValue EmitDelegateCallArg(const VarDecl *Param); + void EmitDelegateCallArg(CallArgList &args, const VarDecl *param); private: void EmitReturnOfRValue(RValue RV, QualType Ty); @@ -2131,8 +2168,7 @@ private: getContext().getCanonicalType(ActualArgType).getTypePtr() && "type mismatch in call argument!"); #endif - Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType), - ArgType)); + EmitCallArg(Args, *Arg, ArgType); } // Either we've emitted all the call args, or we have a call to a @@ -2143,11 +2179,8 @@ private: } // If we still have any arguments, emit them using the type of the argument. - for (; Arg != ArgEnd; ++Arg) { - QualType ArgType = Arg->getType(); - Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType), - ArgType)); - } + for (; Arg != ArgEnd; ++Arg) + EmitCallArg(Args, *Arg, Arg->getType()); } const TargetCodeGenInfo &getTargetHooks() const { @@ -2155,6 +2188,10 @@ private: } void EmitDeclMetadata(); + + CodeGenModule::ByrefHelpers * + buildByrefHelpers(const llvm::StructType &byrefType, + const AutoVarEmission &emission); }; /// Helper class with most of the code for saving a value for a diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp index a8453c3..83e927f 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.cpp @@ -64,7 +64,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, ABI(createCXXABI(*this)), Types(C, M, TD, getTargetCodeGenInfo().getABIInfo(), ABI), TBAA(0), - VTables(*this), Runtime(0), + VTables(*this), Runtime(0), DebugInfo(0), CFConstantStringClassRef(0), ConstantStringClassRef(0), VMContext(M.getContext()), NSConcreteGlobalBlockDecl(0), NSConcreteStackBlockDecl(0), @@ -72,22 +72,19 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, BlockObjectAssignDecl(0), BlockObjectDisposeDecl(0), BlockObjectAssign(0), BlockObjectDispose(0), BlockDescriptorType(0), GenericBlockLiteralType(0) { - if (!Features.ObjC1) - Runtime = 0; - else if (!Features.NeXTRuntime) - Runtime = CreateGNUObjCRuntime(*this); - else if (Features.ObjCNonFragileABI) - Runtime = CreateMacNonFragileABIObjCRuntime(*this); - else - Runtime = CreateMacObjCRuntime(*this); + if (Features.ObjC1) + createObjCRuntime(); // Enable TBAA unless it's suppressed. if (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0) TBAA = new CodeGenTBAA(Context, VMContext, getLangOptions(), ABI.getMangleContext()); - // If debug info generation is enabled, create the CGDebugInfo object. - DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(*this) : 0; + // If debug info or coverage generation is enabled, create the CGDebugInfo + // object. + if (CodeGenOpts.DebugInfo || CodeGenOpts.EmitGcovArcs || + CodeGenOpts.EmitGcovNotes) + DebugInfo = new CGDebugInfo(*this); Block.GlobalUniqueCount = 0; @@ -115,8 +112,6 @@ CodeGenModule::~CodeGenModule() { void CodeGenModule::createObjCRuntime() { if (!Features.NeXTRuntime) Runtime = CreateGNUObjCRuntime(*this); - else if (Features.ObjCNonFragileABI) - Runtime = CreateMacNonFragileABIObjCRuntime(*this); else Runtime = CreateMacObjCRuntime(*this); } @@ -139,6 +134,13 @@ void CodeGenModule::Release() { EmitDeclMetadata(); } +void CodeGenModule::UpdateCompletedType(const TagDecl *TD) { + // Make sure that this type is translated. + Types.UpdateCompletedType(TD); + if (DebugInfo) + DebugInfo->UpdateCompletedType(TD); +} + llvm::MDNode *CodeGenModule::getTBAAInfo(QualType QTy) { if (!TBAA) return 0; @@ -151,7 +153,12 @@ void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst, } bool CodeGenModule::isTargetDarwin() const { - return getContext().Target.getTriple().getOS() == llvm::Triple::Darwin; + return getContext().Target.getTriple().isOSDarwin(); +} + +void CodeGenModule::Error(SourceLocation loc, llvm::StringRef error) { + unsigned diagID = getDiags().getCustomDiagID(Diagnostic::Error, error); + getDiags().Report(Context.getFullLoc(loc), diagID); } /// ErrorUnsupported - Print out an error that codegen doesn't support the @@ -220,7 +227,7 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV, return; // Don't override an explicit visibility attribute. - if (RD->hasAttr<VisibilityAttr>()) + if (RD->getExplicitVisibility()) return; switch (RD->getTemplateSpecializationKind()) { @@ -501,6 +508,13 @@ void CodeGenModule::SetInternalFunctionAttributes(const Decl *D, void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, bool IsIncompleteFunction) { + if (unsigned IID = F->getIntrinsicID()) { + // If this is an intrinsic function, set the function's attributes + // to the intrinsic's attributes. + F->setAttributes(llvm::Intrinsic::getAttributes((llvm::Intrinsic::ID)IID)); + return; + } + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); if (!IsIncompleteFunction) @@ -512,7 +526,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, if (FD->hasAttr<DLLImportAttr>()) { F->setLinkage(llvm::Function::DLLImportLinkage); } else if (FD->hasAttr<WeakAttr>() || - FD->hasAttr<WeakImportAttr>()) { + FD->isWeakImported()) { // "extern_weak" is overloaded in LLVM; we probably should have // separate linkage types for this. F->setLinkage(llvm::Function::ExternalWeakLinkage); @@ -989,7 +1003,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(llvm::StringRef MangledName, } else { if (D->hasAttr<DLLImportAttr>()) GV->setLinkage(llvm::GlobalValue::DLLImportLinkage); - else if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakImportAttr>()) + else if (D->hasAttr<WeakAttr>() || D->isWeakImported()) GV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage); // Set visibility on a declaration only if it's explicit. @@ -1055,7 +1069,7 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, Ty = getTypes().ConvertTypeForMem(ASTTy); const llvm::PointerType *PTy = - llvm::PointerType::get(Ty, ASTTy.getAddressSpace()); + llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy)); llvm::StringRef MangledName = getMangledName(D); return GetOrCreateLLVMGlobal(MangledName, PTy, D); @@ -1066,7 +1080,7 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, llvm::Constant * CodeGenModule::CreateRuntimeVariable(const llvm::Type *Ty, llvm::StringRef Name) { - return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0, + return GetOrCreateLLVMGlobal(Name, llvm::PointerType::getUnqual(Ty), 0, true); } @@ -1234,7 +1248,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { // from the type of the global (this happens with unions). if (GV == 0 || GV->getType()->getElementType() != InitType || - GV->getType()->getAddressSpace() != ASTTy.getAddressSpace()) { + GV->getType()->getAddressSpace() != + getContext().getTargetAddressSpace(ASTTy)) { // Move the old entry aside so that we'll create a new one. Entry->setName(llvm::StringRef()); @@ -1281,7 +1296,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { EmitCXXGlobalVarDeclInitFunc(D, GV); // Emit global variable debug information. - if (CGDebugInfo *DI = getDebugInfo()) { + if (CGDebugInfo *DI = getModuleDebugInfo()) { DI->setLocation(D->getLocation()); DI->EmitGlobalVariable(GV, D); } @@ -1304,9 +1319,7 @@ CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, return llvm::GlobalVariable::WeakAnyLinkage; } else if (Linkage == GVA_TemplateInstantiation || Linkage == GVA_ExplicitTemplateInstantiation) - // FIXME: It seems like we can provide more specific linkage here - // (LinkOnceODR, WeakODR). - return llvm::GlobalVariable::WeakAnyLinkage; + return llvm::GlobalVariable::WeakODRLinkage; else if (!getLangOptions().CPlusPlus && ((!CodeGenOpts.NoCommon && !D->getAttr<NoCommonAttr>()) || D->getAttr<CommonAttr>()) && @@ -1391,7 +1404,14 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { const FunctionDecl *D = cast<FunctionDecl>(GD.getDecl()); - const llvm::FunctionType *Ty = getTypes().GetFunctionType(GD); + + // Compute the function info and LLVM type. + const CGFunctionInfo &FI = getTypes().getFunctionInfo(GD); + bool variadic = false; + if (const FunctionProtoType *fpt = D->getType()->getAs<FunctionProtoType>()) + variadic = fpt->isVariadic(); + const llvm::FunctionType *Ty = getTypes().GetFunctionType(FI, variadic, false); + // Get or create the prototype for the function. llvm::Constant *Entry = GetAddrOfFunction(GD, Ty); @@ -1451,7 +1471,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD) { // FIXME: this is redundant with part of SetFunctionDefinitionAttributes setGlobalVisibility(Fn, D); - CodeGenFunction(*this).GenerateCode(D, Fn); + CodeGenFunction(*this).GenerateCode(D, Fn, FI); SetFunctionDefinitionAttributes(D, Fn); SetLLVMFunctionAttributesForDefinition(D, Fn); @@ -1525,7 +1545,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { } } else if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakRefAttr>() || - D->hasAttr<WeakImportAttr>()) { + D->isWeakImported()) { GA->setLinkage(llvm::Function::WeakAnyLinkage); } @@ -1662,7 +1682,10 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { // does make plain ascii ones writable. isConstant = true; } else { - Linkage = llvm::GlobalValue::PrivateLinkage; + // FIXME: With OS X ld 123.2 (xcode 4) and LTO we would get a linker error + // when using private linkage. It is not clear if this is a bug in ld + // or a reasonable new restriction. + Linkage = llvm::GlobalValue::LinkerPrivateLinkage; isConstant = !Features.WritableStrings; } @@ -1673,6 +1696,9 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { if (isUTF16) { CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy); GV->setAlignment(Align.getQuantity()); + } else { + CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); + GV->setAlignment(Align.getQuantity()); } Fields[2] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); @@ -1765,6 +1791,9 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) { if (isUTF16) { CharUnits Align = getContext().getTypeAlignInChars(getContext().ShortTy); GV->setAlignment(Align.getQuantity()); + } else { + CharUnits Align = getContext().getTypeAlignInChars(getContext().CharTy); + GV->setAlignment(Align.getQuantity()); } Fields[1] = llvm::ConstantExpr::getGetElementPtr(GV, Zeros, 2); @@ -1835,7 +1864,7 @@ CodeGenModule::GetAddrOfConstantStringFromObjCEncode(const ObjCEncodeExpr *E) { /// GenerateWritableString -- Creates storage for a string literal. -static llvm::Constant *GenerateStringLiteral(const std::string &str, +static llvm::Constant *GenerateStringLiteral(llvm::StringRef str, bool constant, CodeGenModule &CGM, const char *GlobalName) { @@ -1860,7 +1889,7 @@ static llvm::Constant *GenerateStringLiteral(const std::string &str, /// Feature.WriteableStrings. /// /// The result has pointer to array type. -llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str, +llvm::Constant *CodeGenModule::GetAddrOfConstantString(llvm::StringRef Str, const char *GlobalName) { bool IsConstant = !Features.WritableStrings; @@ -1870,26 +1899,27 @@ llvm::Constant *CodeGenModule::GetAddrOfConstantString(const std::string &str, // Don't share any string literals if strings aren't constant. if (!IsConstant) - return GenerateStringLiteral(str, false, *this, GlobalName); + return GenerateStringLiteral(Str, false, *this, GlobalName); llvm::StringMapEntry<llvm::Constant *> &Entry = - ConstantStringMap.GetOrCreateValue(&str[0], &str[str.length()]); + ConstantStringMap.GetOrCreateValue(Str); if (Entry.getValue()) return Entry.getValue(); // Create a global variable for this. - llvm::Constant *C = GenerateStringLiteral(str, true, *this, GlobalName); + llvm::Constant *C = GenerateStringLiteral(Str, true, *this, GlobalName); Entry.setValue(C); return C; } /// GetAddrOfConstantCString - Returns a pointer to a character -/// array containing the literal and a terminating '\-' +/// array containing the literal and a terminating '\0' /// character. The result has pointer to array type. -llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &str, +llvm::Constant *CodeGenModule::GetAddrOfConstantCString(const std::string &Str, const char *GlobalName){ - return GetAddrOfConstantString(str + '\0', GlobalName); + llvm::StringRef StrWithNull(Str.c_str(), Str.size() + 1); + return GetAddrOfConstantString(StrWithNull, GlobalName); } /// EmitObjCPropertyImplementations - Emit information for synthesized @@ -1920,37 +1950,48 @@ void CodeGenModule::EmitObjCPropertyImplementations(const } } +static bool needsDestructMethod(ObjCImplementationDecl *impl) { + ObjCInterfaceDecl *iface + = const_cast<ObjCInterfaceDecl*>(impl->getClassInterface()); + for (ObjCIvarDecl *ivar = iface->all_declared_ivar_begin(); + ivar; ivar = ivar->getNextIvar()) + if (ivar->getType().isDestructedType()) + return true; + + return false; +} + /// EmitObjCIvarInitializations - Emit information for ivar initialization /// for an implementation. void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { - if (!Features.NeXTRuntime || D->getNumIvarInitializers() == 0) + // We might need a .cxx_destruct even if we don't have any ivar initializers. + if (needsDestructMethod(D)) { + IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); + Selector cxxSelector = getContext().Selectors.getSelector(0, &II); + ObjCMethodDecl *DTORMethod = + ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), + cxxSelector, getContext().VoidTy, 0, D, true, + false, true, false, ObjCMethodDecl::Required); + D->addInstanceMethod(DTORMethod); + CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); + } + + // If the implementation doesn't have any ivar initializers, we don't need + // a .cxx_construct. + if (D->getNumIvarInitializers() == 0) return; - DeclContext* DC = const_cast<DeclContext*>(dyn_cast<DeclContext>(D)); - assert(DC && "EmitObjCIvarInitializations - null DeclContext"); - IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); - Selector cxxSelector = getContext().Selectors.getSelector(0, &II); - ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create(getContext(), - D->getLocation(), - D->getLocation(), cxxSelector, - getContext().VoidTy, 0, - DC, true, false, true, false, - ObjCMethodDecl::Required); - D->addInstanceMethod(DTORMethod); - CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); - II = &getContext().Idents.get(".cxx_construct"); - cxxSelector = getContext().Selectors.getSelector(0, &II); + IdentifierInfo *II = &getContext().Idents.get(".cxx_construct"); + Selector cxxSelector = getContext().Selectors.getSelector(0, &II); // The constructor returns 'self'. ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), cxxSelector, getContext().getObjCIdType(), 0, - DC, true, false, true, false, + D, true, false, true, false, ObjCMethodDecl::Required); D->addInstanceMethod(CTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); - - } /// EmitNamespace - Emit all declarations in a namespace. @@ -1990,7 +2031,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::CXXMethod: case Decl::Function: // Skip function templates - if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate()) + if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() || + cast<FunctionDecl>(D)->isLateTemplateParsed()) return; EmitGlobal(cast<FunctionDecl>(D)); @@ -2000,6 +2042,11 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { EmitGlobal(cast<VarDecl>(D)); break; + // Indirect fields from global anonymous structs and unions can be + // ignored; only the actual variable requires IR gen support. + case Decl::IndirectField: + break; + // C++ Decls case Decl::Namespace: EmitNamespace(cast<NamespaceDecl>(D)); @@ -2014,12 +2061,15 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { break; case Decl::CXXConstructor: // Skip function templates - if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate()) + if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate() || + cast<FunctionDecl>(D)->isLateTemplateParsed()) return; EmitCXXConstructors(cast<CXXConstructorDecl>(D)); break; case Decl::CXXDestructor: + if (cast<FunctionDecl>(D)->isLateTemplateParsed()) + return; EmitCXXDestructors(cast<CXXDestructorDecl>(D)); break; @@ -2035,13 +2085,12 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::ObjCInterface: break; - case Decl::ObjCCategory: { - ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D); - if (CD->IsClassExtension() && CD->hasSynthBitfield()) - Context.ResetObjCLayout(CD->getClassInterface()); - break; - } - + case Decl::ObjCCategory: { + ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D); + if (CD->IsClassExtension() && CD->hasSynthBitfield()) + Context.ResetObjCLayout(CD->getClassInterface()); + break; + } case Decl::ObjCProtocol: Runtime->GenerateProtocol(cast<ObjCProtocolDecl>(D)); @@ -2118,7 +2167,7 @@ static void EmitGlobalDeclMetadata(CodeGenModule &CGM, Addr, GetPointerConstant(CGM.getLLVMContext(), D.getDecl()) }; - GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops, 2)); + GlobalMetadata->addOperand(llvm::MDNode::get(CGM.getLLVMContext(), Ops)); } /// Emits metadata nodes associating all the global values in the @@ -2159,7 +2208,7 @@ void CodeGenFunction::EmitDeclMetadata() { if (llvm::AllocaInst *Alloca = dyn_cast<llvm::AllocaInst>(Addr)) { llvm::Value *DAddr = GetPointerConstant(getLLVMContext(), D); - Alloca->setMetadata(DeclPtrKind, llvm::MDNode::get(Context, &DAddr, 1)); + Alloca->setMetadata(DeclPtrKind, llvm::MDNode::get(Context, DAddr)); } else if (llvm::GlobalValue *GV = dyn_cast<llvm::GlobalValue>(Addr)) { GlobalDecl GD = GlobalDecl(cast<VarDecl>(D)); EmitGlobalDeclMetadata(CGM, GlobalMetadata, GD, GV); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h index 73e6ece..99c973c 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenModule.h @@ -20,7 +20,6 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Mangle.h" -#include "CGCall.h" #include "CGVTables.h" #include "CodeGenTypes.h" #include "GlobalDecl.h" @@ -69,12 +68,14 @@ namespace clang { namespace CodeGen { + class CallArgList; class CodeGenFunction; class CodeGenTBAA; class CGCXXABI; class CGDebugInfo; class CGObjCRuntime; class BlockFieldFlags; + class FunctionArgList; struct OrderGlobalInits { unsigned int priority; @@ -246,9 +247,6 @@ class CodeGenModule : public CodeGenTypeCache { int GlobalUniqueCount; } Block; - llvm::DenseMap<uint64_t, llvm::Constant *> AssignCache; - llvm::DenseMap<uint64_t, llvm::Constant *> DestroyCache; - /// @} public: CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, @@ -281,7 +279,8 @@ public: StaticLocalDeclMap[D] = GV; } - CGDebugInfo *getDebugInfo() { return DebugInfo; } + CGDebugInfo *getModuleDebugInfo() { return DebugInfo; } + ASTContext &getContext() const { return Context; } const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; } const LangOptions &getLangOptions() const { return Features; } @@ -311,6 +310,7 @@ public: enum TypeVisibilityKind { TVK_ForVTT, TVK_ForVTable, + TVK_ForConstructionVTable, TVK_ForRTTI, TVK_ForRTTIName }; @@ -358,6 +358,7 @@ public: llvm::Constant *GetAddrOfGlobalVar(const VarDecl *D, const llvm::Type *Ty = 0); + /// GetAddrOfFunction - Return the address of the given function. If Ty is /// non-null, then this function will use the specified type if it has to /// create it. @@ -382,14 +383,35 @@ public: CastExpr::path_const_iterator PathBegin, CastExpr::path_const_iterator PathEnd); - llvm::Constant *BuildbyrefCopyHelper(const llvm::Type *T, - BlockFieldFlags flags, - unsigned Align, - const VarDecl *variable); - llvm::Constant *BuildbyrefDestroyHelper(const llvm::Type *T, - BlockFieldFlags flags, - unsigned Align, - const VarDecl *variable); + /// A pair of helper functions for a __block variable. + class ByrefHelpers : public llvm::FoldingSetNode { + public: + llvm::Constant *CopyHelper; + llvm::Constant *DisposeHelper; + + /// The alignment of the field. This is important because + /// different offsets to the field within the byref struct need to + /// have different helper functions. + CharUnits Alignment; + + ByrefHelpers(CharUnits alignment) : Alignment(alignment) {} + virtual ~ByrefHelpers(); + + void Profile(llvm::FoldingSetNodeID &id) const { + id.AddInteger(Alignment.getQuantity()); + profileImpl(id); + } + virtual void profileImpl(llvm::FoldingSetNodeID &id) const = 0; + + virtual bool needsCopy() const { return true; } + virtual void emitCopy(CodeGenFunction &CGF, + llvm::Value *dest, llvm::Value *src) = 0; + + virtual bool needsDispose() const { return true; } + virtual void emitDispose(CodeGenFunction &CGF, llvm::Value *field) = 0; + }; + + llvm::FoldingSet<ByrefHelpers> ByrefHelpersCache; /// getUniqueBlockCount - Fetches the global unique block count. int getUniqueBlockCount() { return ++Block.GlobalUniqueCount; } @@ -437,7 +459,7 @@ public: /// /// \param GlobalName If provided, the name to use for the global /// (if one is created). - llvm::Constant *GetAddrOfConstantString(const std::string& str, + llvm::Constant *GetAddrOfConstantString(llvm::StringRef Str, const char *GlobalName=0); /// GetAddrOfConstantCString - Returns a pointer to a character array @@ -451,13 +473,15 @@ public: /// GetAddrOfCXXConstructor - Return the address of the constructor of the /// given type. - llvm::GlobalValue *GetAddrOfCXXConstructor(const CXXConstructorDecl *D, - CXXCtorType Type); + llvm::GlobalValue *GetAddrOfCXXConstructor(const CXXConstructorDecl *ctor, + CXXCtorType ctorType, + const CGFunctionInfo *fnInfo = 0); /// GetAddrOfCXXDestructor - Return the address of the constructor of the /// given type. - llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *D, - CXXDtorType Type); + llvm::GlobalValue *GetAddrOfCXXDestructor(const CXXDestructorDecl *dtor, + CXXDtorType dtorType, + const CGFunctionInfo *fnInfo = 0); /// getBuiltinLibFunction - Given a builtin id for a function like /// "__builtin_fabsf", return a Function* for "fabsf". @@ -502,10 +526,8 @@ public: ///@} - void UpdateCompletedType(const TagDecl *TD) { - // Make sure that this type is translated. - Types.UpdateCompletedType(TD); - } + // UpdateCompleteType - Make sure that this type is translated. + void UpdateCompletedType(const TagDecl *TD); llvm::Constant *getMemberPointerConstant(const UnaryOperator *e); @@ -523,6 +545,9 @@ public: llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV, const AnnotateAttr *AA, unsigned LineNo); + /// Error - Emit a general error that something can't be done. + void Error(SourceLocation loc, llvm::StringRef error); + /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified stmt yet. /// \param OmitOnError - If true, then this error should only be emitted if no diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp index 3f2c6ca..53e40b2 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -74,7 +74,8 @@ llvm::MDNode *CodeGenTBAA::getTBAAInfoForNamedType(llvm::StringRef NameStr, }; // Create the mdnode. - return llvm::MDNode::get(VMContext, Ops, llvm::array_lengthof(Ops) - !Flags); + unsigned Len = llvm::array_lengthof(Ops) - !Flags; + return llvm::MDNode::get(VMContext, llvm::ArrayRef<llvm::Value*>(Ops, Len)); } static bool TypeHasMayAlias(QualType QTy) { @@ -155,7 +156,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // theoretically implement this by combining information about all the // members into a single identifying MDNode. if (!Features.CPlusPlus && - ETy->getDecl()->getTypedefForAnonDecl()) + ETy->getDecl()->getTypedefNameForAnonDecl()) return MetadataCache[Ty] = getChar(); // In C++ mode, types have linkage, so we can rely on the ODR and diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp index 5254922..8db6fe5 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.cpp @@ -65,6 +65,36 @@ void CodeGenTypes::HandleLateResolvedPointers() { } } +void CodeGenTypes::addRecordTypeName(const RecordDecl *RD, const llvm::Type *Ty, + llvm::StringRef suffix) { + llvm::SmallString<256> TypeName; + llvm::raw_svector_ostream OS(TypeName); + OS << RD->getKindName() << '.'; + + // Name the codegen type after the typedef name + // if there is no tag type name available + if (RD->getIdentifier()) { + // FIXME: We should not have to check for a null decl context here. + // Right now we do it because the implicit Obj-C decls don't have one. + if (RD->getDeclContext()) + OS << RD->getQualifiedNameAsString(); + else + RD->printName(OS); + } else if (const TypedefNameDecl *TDD = RD->getTypedefNameForAnonDecl()) { + // FIXME: We should not have to check for a null decl context here. + // Right now we do it because the implicit Obj-C decls don't have one. + if (TDD->getDeclContext()) + OS << TDD->getQualifiedNameAsString(); + else + TDD->printName(OS); + } else + OS << "anon"; + + if (!suffix.empty()) + OS << suffix; + + TheModule.addTypeName(OS.str(), Ty); +} /// ConvertType - Convert the specified type to its LLVM form. const llvm::Type *CodeGenTypes::ConvertType(QualType T, bool IsRecursive) { @@ -199,7 +229,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { #define DEPENDENT_TYPE(Class, Base) case Type::Class: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" - assert(false && "Non-canonical or dependent types aren't possible."); + llvm_unreachable("Non-canonical or dependent types aren't possible."); break; case Type::Builtin: { @@ -253,10 +283,12 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { case BuiltinType::Overload: case BuiltinType::Dependent: - assert(0 && "Unexpected builtin type!"); + case BuiltinType::BoundMember: + case BuiltinType::UnknownAny: + llvm_unreachable("Unexpected placeholder builtin type!"); break; } - assert(0 && "Unknown builtin type!"); + llvm_unreachable("Unknown builtin type!"); break; } case Type::Complex: { @@ -270,14 +302,16 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { QualType ETy = RTy.getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(ETy, PointeeType)); - return llvm::PointerType::get(PointeeType, ETy.getAddressSpace()); + unsigned AS = Context.getTargetAddressSpace(ETy); + return llvm::PointerType::get(PointeeType, AS); } case Type::Pointer: { const PointerType &PTy = cast<PointerType>(Ty); QualType ETy = PTy.getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(ETy, PointeeType)); - return llvm::PointerType::get(PointeeType, ETy.getAddressSpace()); + unsigned AS = Context.getTargetAddressSpace(ETy); + return llvm::PointerType::get(PointeeType, AS); } case Type::VariableArray: { @@ -371,30 +405,8 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { const TagDecl *TD = cast<TagType>(Ty).getDecl(); const llvm::Type *Res = ConvertTagDeclType(TD); - llvm::SmallString<256> TypeName; - llvm::raw_svector_ostream OS(TypeName); - OS << TD->getKindName() << '.'; - - // Name the codegen type after the typedef name - // if there is no tag type name available - if (TD->getIdentifier()) { - // FIXME: We should not have to check for a null decl context here. - // Right now we do it because the implicit Obj-C decls don't have one. - if (TD->getDeclContext()) - OS << TD->getQualifiedNameAsString(); - else - TD->printName(OS); - } else if (const TypedefDecl *TDD = TD->getTypedefForAnonDecl()) { - // FIXME: We should not have to check for a null decl context here. - // Right now we do it because the implicit Obj-C decls don't have one. - if (TDD->getDeclContext()) - OS << TDD->getQualifiedNameAsString(); - else - TDD->printName(OS); - } else - OS << "anon"; - - TheModule.addTypeName(OS.str(), Res); + if (const RecordDecl *RD = dyn_cast<RecordDecl>(TD)) + addRecordTypeName(RD, Res, llvm::StringRef()); return Res; } @@ -402,7 +414,8 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) { const QualType FTy = cast<BlockPointerType>(Ty).getPointeeType(); llvm::OpaqueType *PointeeType = llvm::OpaqueType::get(getLLVMContext()); PointersToResolve.push_back(std::make_pair(FTy, PointeeType)); - return llvm::PointerType::get(PointeeType, FTy.getAddressSpace()); + unsigned AS = Context.getTargetAddressSpace(FTy); + return llvm::PointerType::get(PointeeType, AS); } case Type::MemberPointer: { @@ -500,6 +513,15 @@ CodeGenTypes::getCGRecordLayout(const RecordDecl *RD) { return *Layout; } +void CodeGenTypes::addBaseSubobjectTypeName(const CXXRecordDecl *RD, + const CGRecordLayout &layout) { + llvm::StringRef suffix; + if (layout.getBaseSubobjectLLVMType() != layout.getLLVMType()) + suffix = ".base"; + + addRecordTypeName(RD, layout.getBaseSubobjectLLVMType(), suffix); +} + bool CodeGenTypes::isZeroInitializable(QualType T) { // No need to check for member pointers when not compiling C++. if (!Context.getLangOptions().CPlusPlus) diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h index 41513da..dc383cb 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h +++ b/contrib/llvm/tools/clang/lib/CodeGen/CodeGenTypes.h @@ -101,6 +101,11 @@ private: /// used to handle cyclic structures properly. void HandleLateResolvedPointers(); + /// addRecordTypeName - Compute a name from the given record decl with an + /// optional suffix and name the given LLVM type using it. + void addRecordTypeName(const RecordDecl *RD, const llvm::Type *Ty, + llvm::StringRef suffix); + public: CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD, const ABIInfo &Info, CGCXXABI &CXXABI); @@ -145,10 +150,19 @@ public: const CGRecordLayout &getCGRecordLayout(const RecordDecl*); + /// addBaseSubobjectTypeName - Add a type name for the base subobject of the + /// given record layout. + void addBaseSubobjectTypeName(const CXXRecordDecl *RD, + const CGRecordLayout &layout); + /// UpdateCompletedType - When we find the full definition for a TagDecl, /// replace the 'opaque' type we previously made for it if applicable. void UpdateCompletedType(const TagDecl *TD); + /// getNullaryFunctionInfo - Get the function info for a void() + /// function with standard CC. + const CGFunctionInfo &getNullaryFunctionInfo(); + /// getFunctionInfo - Get the function info for the specified function decl. const CGFunctionInfo &getFunctionInfo(GlobalDecl GD); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp index 95654a3..33abf3a 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This provides C++ code generation targetting the Itanium C++ ABI. The class +// This provides C++ code generation targeting the Itanium C++ ABI. The class // in this file generates structures that follow the Itanium C++ ABI, which is // documented at: // http://www.codesourcery.com/public/cxx-abi/abi.html @@ -282,8 +282,7 @@ ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(CodeGenFunction &CGF, // We're done. CGF.EmitBlock(FnEnd); - llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo()); - Callee->reserveOperandSpace(2); + llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo(), 2); Callee->addIncoming(VirtualFn, FnVirtual); Callee->addIncoming(NonVirtualFn, FnNonVirtual); return Callee; @@ -515,10 +514,10 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { if (MD->isVirtual()) { uint64_t Index = CGM.getVTables().getMethodVTableIndex(MD); - // FIXME: We shouldn't use / 8 here. - uint64_t PointerWidthInBytes = - getContext().Target.getPointerWidth(0) / 8; - uint64_t VTableOffset = (Index * PointerWidthInBytes); + const ASTContext &Context = getContext(); + CharUnits PointerWidth = + Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + uint64_t VTableOffset = (Index * PointerWidth.getQuantity()); if (IsARM) { // ARM C++ ABI 3.2.1: @@ -538,20 +537,21 @@ llvm::Constant *ItaniumCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) { MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); } } else { - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); const llvm::Type *Ty; // Check whether the function has a computable LLVM signature. if (!CodeGenTypes::VerifyFuncTypeComplete(FPT)) { // The function has a computable LLVM signature; use the correct type. - Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), FPT->isVariadic()); + Ty = Types.GetFunctionType(Types.getFunctionInfo(MD), + FPT->isVariadic()); } else { // Use an arbitrary non-function type to tell GetAddrOfFunction that the // function type is incomplete. Ty = ptrdiff_t; } + llvm::Constant *addr = CGM.GetAddrOfFunction(MD, Ty); - llvm::Constant *Addr = CGM.GetAddrOfFunction(MD, Ty); - MemPtr[0] = llvm::ConstantExpr::getPtrToInt(Addr, ptrdiff_t); + MemPtr[0] = llvm::ConstantExpr::getPtrToInt(addr, ptrdiff_t); MemPtr[1] = llvm::ConstantInt::get(ptrdiff_t, 0); } @@ -651,20 +651,21 @@ ItaniumCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF, return Builder.CreateICmpNE(MemPtr, NegativeOne, "memptr.tobool"); } - // In Itanium, a member function pointer is null if 'ptr' is null. + // In Itanium, a member function pointer is not null if 'ptr' is not null. llvm::Value *Ptr = Builder.CreateExtractValue(MemPtr, 0, "memptr.ptr"); llvm::Constant *Zero = llvm::ConstantInt::get(Ptr->getType(), 0); llvm::Value *Result = Builder.CreateICmpNE(Ptr, Zero, "memptr.tobool"); - // In ARM, it's that, plus the low bit of 'adj' must be zero. + // On ARM, a member function pointer is also non-null if the low bit of 'adj' + // (the virtual bit) is set. if (IsARM) { llvm::Constant *One = llvm::ConstantInt::get(Ptr->getType(), 1); llvm::Value *Adj = Builder.CreateExtractValue(MemPtr, 1, "memptr.adj"); llvm::Value *VirtualBit = Builder.CreateAnd(Adj, One, "memptr.virtualbit"); - llvm::Value *IsNotVirtual = Builder.CreateICmpEQ(VirtualBit, Zero, - "memptr.notvirtual"); - Result = Builder.CreateAnd(Result, IsNotVirtual); + llvm::Value *IsVirtual = Builder.CreateICmpNE(VirtualBit, Zero, + "memptr.isvirtual"); + Result = Builder.CreateOr(Result, IsVirtual); } return Result; @@ -745,7 +746,7 @@ void ItaniumCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, ImplicitParamDecl *VTTDecl = ImplicitParamDecl::Create(Context, 0, MD->getLocation(), &Context.Idents.get("vtt"), T); - Params.push_back(std::make_pair(VTTDecl, VTTDecl->getType())); + Params.push_back(VTTDecl); getVTTDecl(CGF) = VTTDecl; } } @@ -757,7 +758,7 @@ void ARMCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, // Return 'this' from certain constructors and destructors. if (HasThisReturn(CGF.CurGD)) - ResTy = Params[0].second; + ResTy = Params[0]->getType(); } void ItaniumCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { @@ -1064,10 +1065,18 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // global initialization is always single-threaded. bool ThreadsafeStatics = (getContext().getLangOptions().ThreadsafeStatics && D.isLocalVarDecl()); - - // Guard variables are 64 bits in the generic ABI and 32 bits on ARM. - const llvm::IntegerType *GuardTy - = (IsARM ? Builder.getInt32Ty() : Builder.getInt64Ty()); + + const llvm::IntegerType *GuardTy; + + // If we have a global variable with internal linkage and thread-safe statics + // are disabled, we can just let the guard variable be of type i8. + bool UseInt8GuardVariable = !ThreadsafeStatics && GV->hasInternalLinkage(); + if (UseInt8GuardVariable) + GuardTy = Builder.getInt8Ty(); + else { + // Guard variables are 64 bits in the generic ABI and 32 bits on ARM. + GuardTy = (IsARM ? Builder.getInt32Ty() : Builder.getInt64Ty()); + } const llvm::PointerType *GuardPtrTy = GuardTy->getPointerTo(); // Create the guard variable. @@ -1098,7 +1107,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // if (__cxa_guard_acquire(&obj_guard)) // ... // } - if (IsARM) { + if (IsARM && !UseInt8GuardVariable) { llvm::Value *V = Builder.CreateLoad(GuardVariable); V = Builder.CreateAnd(V, Builder.getInt32(1)); IsInitialized = Builder.CreateIsNull(V, "guard.uninitialized"); diff --git a/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 3a63eba..747e5e3 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This provides C++ code generation targetting the Microsoft Visual C++ ABI. +// This provides C++ code generation targeting the Microsoft Visual C++ ABI. // The class in this file generates structures that follow the Microsoft // Visual C++ ABI, which is actually not very well documented at all outside // of Microsoft. diff --git a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp index 2ffc840..bc2472c 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/TargetInfo.cpp @@ -16,6 +16,7 @@ #include "ABIInfo.h" #include "CodeGenFunction.h" #include "clang/AST/RecordLayout.h" +#include "clang/Frontend/CodeGenOptions.h" #include "llvm/Type.h" #include "llvm/Target/TargetData.h" #include "llvm/ADT/Triple.h" @@ -358,7 +359,7 @@ bool UseX86_MMXType(const llvm::Type *IRType) { static const llvm::Type* X86AdjustInlineAsmType(CodeGen::CodeGenFunction &CGF, llvm::StringRef Constraint, const llvm::Type* Ty) { - if (Constraint=="y" && Ty->isVectorTy()) + if ((Constraint == "y" || Constraint == "&y") && Ty->isVectorTy()) return llvm::Type::getX86_MMXTy(CGF.getLLVMContext()); return Ty; } @@ -864,6 +865,15 @@ class X86_64ABIInfo : public ABIInfo { unsigned &neededInt, unsigned &neededSSE) const; + /// The 0.98 ABI revision clarified a lot of ambiguities, + /// unfortunately in ways that were not always consistent with + /// certain previous compilers. In particular, platforms which + /// required strict binary compatibility with older versions of GCC + /// may need to exempt themselves. + bool honorsRevision0_98() const { + return !getContext().Target.getTriple().isOSDarwin(); + } + public: X86_64ABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} @@ -1252,15 +1262,24 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, // (a) If one of the classes is MEMORY, the whole argument is // passed in memory. // - // (b) If SSEUP is not preceeded by SSE, it is converted to SSE. - - // The first of these conditions is guaranteed by how we implement - // the merge (just bail). + // (b) If X87UP is not preceded by X87, the whole argument is + // passed in memory. + // + // (c) If the size of the aggregate exceeds two eightbytes and the first + // eight-byte isn’t SSE or any other eightbyte isn’t SSEUP, the whole + // argument is passed in memory. + // + // (d) If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE. + // + // Some of these are enforced by the merging logic. Others can arise + // only with unions; for example: + // union { _Complex double; unsigned; } // - // The second condition occurs in the case of unions; for example - // union { _Complex double; unsigned; }. + // Note that clauses (b) and (c) were added in 0.98. if (Hi == Memory) Lo = Memory; + if (Hi == X87Up && Lo != X87 && honorsRevision0_98()) + Lo = Memory; if (Hi == SSEUp && Lo != SSE) Hi = SSE; } @@ -1689,7 +1708,7 @@ classifyReturnType(QualType RetTy) const { // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte // is passed in the upper half of the last used SSE register. // - // SSEUP should always be preceeded by SSE, just widen. + // SSEUP should always be preceded by SSE, just widen. case SSEUp: assert(Lo == SSE && "Unexpected SSEUp classification."); ResType = Get16ByteVectorType(RetTy); @@ -1698,9 +1717,9 @@ classifyReturnType(QualType RetTy) const { // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is // returned together with the previous X87 value in %st0. case X87Up: - // If X87Up is preceeded by X87, we don't need to do + // If X87Up is preceded by X87, we don't need to do // anything. However, in some cases with unions it may not be - // preceeded by X87. In such situations we follow gcc and pass the + // preceded by X87. In such situations we follow gcc and pass the // extra bits in an SSE reg. if (Lo != X87) { HighPart = GetSSETypeAtOffset(CGT.ConvertTypeRecursive(RetTy), @@ -1799,7 +1818,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned &neededInt, const llvm::Type *HighPart = 0; switch (Hi) { // Memory was handled previously, ComplexX87 and X87 should - // never occur as hi classes, and X87Up must be preceed by X87, + // never occur as hi classes, and X87Up must be preceded by X87, // which is passed in memory. case Memory: case X87: @@ -2082,9 +2101,8 @@ llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, // Return the appropriate result. CGF.EmitBlock(ContBlock); - llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(), + llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(), 2, "vaarg.addr"); - ResAddr->reserveOperandSpace(2); ResAddr->addIncoming(RegAddr, InRegBlock); ResAddr->addIncoming(MemAddr, InMemBlock); return ResAddr; @@ -2271,27 +2289,33 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { it != ie; ++it) it->info = classifyArgumentType(it->type); - const llvm::Triple &Triple(getContext().Target.getTriple()); + // Always honor user-specified calling convention. + if (FI.getCallingConvention() != llvm::CallingConv::C) + return; + + // Calling convention as default by an ABI. llvm::CallingConv::ID DefaultCC; - if (Triple.getEnvironmentName() == "gnueabi" || - Triple.getEnvironmentName() == "eabi") + llvm::StringRef Env = getContext().Target.getTriple().getEnvironmentName(); + if (Env == "gnueabi" || Env == "eabi") DefaultCC = llvm::CallingConv::ARM_AAPCS; else DefaultCC = llvm::CallingConv::ARM_APCS; + // If user did not ask for specific calling convention explicitly (e.g. via + // pcs attribute), set effective calling convention if it's different than ABI + // default. switch (getABIKind()) { case APCS: if (DefaultCC != llvm::CallingConv::ARM_APCS) FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS); break; - case AAPCS: if (DefaultCC != llvm::CallingConv::ARM_AAPCS) FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS); break; - case AAPCS_VFP: - FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP); + if (DefaultCC != llvm::CallingConv::ARM_AAPCS_VFP) + FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP); break; } } @@ -2317,22 +2341,26 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const { // Otherwise, pass by coercing to a structure of the appropriate size. // - // FIXME: This is kind of nasty... but there isn't much choice because the ARM - // backend doesn't support byval. // FIXME: This doesn't handle alignment > 64 bits. const llvm::Type* ElemTy; unsigned SizeRegs; - if (getContext().getTypeAlign(Ty) > 32) { - ElemTy = llvm::Type::getInt64Ty(getVMContext()); - SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64; - } else { + if (getContext().getTypeSizeInChars(Ty) <= CharUnits::fromQuantity(64)) { ElemTy = llvm::Type::getInt32Ty(getVMContext()); SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32; + } else if (getABIKind() == ARMABIInfo::APCS) { + // Initial ARM ByVal support is APCS-only. + return ABIArgInfo::getIndirect(0, /*ByVal=*/true); + } else { + // FIXME: This is kind of nasty... but there isn't much choice + // because most of the ARM calling conventions don't yet support + // byval. + ElemTy = llvm::Type::getInt64Ty(getVMContext()); + SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64; } - std::vector<const llvm::Type*> LLVMFields; - LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs)); - const llvm::Type* STy = llvm::StructType::get(getVMContext(), LLVMFields, - true); + + const llvm::Type *STy = + llvm::StructType::get(getVMContext(), + llvm::ArrayType::get(ElemTy, SizeRegs), NULL, NULL); return ABIArgInfo::getDirect(STy); } @@ -2516,6 +2544,74 @@ llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, } //===----------------------------------------------------------------------===// +// PTX ABI Implementation +//===----------------------------------------------------------------------===// + +namespace { + +class PTXABIInfo : public ABIInfo { +public: + PTXABIInfo(CodeGenTypes &CGT) : ABIInfo(CGT) {} + + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType Ty) const; + + virtual void computeInfo(CGFunctionInfo &FI) const; + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CFG) const; +}; + +class PTXTargetCodeGenInfo : public TargetCodeGenInfo { +public: + PTXTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new PTXABIInfo(CGT)) {} +}; + +ABIArgInfo PTXABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + if (isAggregateTypeForABI(RetTy)) + return ABIArgInfo::getIndirect(0); + return ABIArgInfo::getDirect(); +} + +ABIArgInfo PTXABIInfo::classifyArgumentType(QualType Ty) const { + if (isAggregateTypeForABI(Ty)) + return ABIArgInfo::getIndirect(0); + + return ABIArgInfo::getDirect(); +} + +void PTXABIInfo::computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type); + + // Always honor user-specified calling convention. + if (FI.getCallingConvention() != llvm::CallingConv::C) + return; + + // Calling convention as default by an ABI. + llvm::CallingConv::ID DefaultCC; + llvm::StringRef Env = getContext().Target.getTriple().getEnvironmentName(); + if (Env == "device") + DefaultCC = llvm::CallingConv::PTX_Device; + else + DefaultCC = llvm::CallingConv::PTX_Kernel; + + FI.setEffectiveCallingConvention(DefaultCC); +} + +llvm::Value *PTXABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CFG) const { + llvm_unreachable("PTX does not support varargs"); + return 0; +} + +} + +//===----------------------------------------------------------------------===// // SystemZ ABI Implementation //===----------------------------------------------------------------------===// @@ -2815,17 +2911,24 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::arm: case llvm::Triple::thumb: - // FIXME: We want to know the float calling convention as well. - if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0) - return *(TheTargetCodeGenInfo = - new ARMTargetCodeGenInfo(Types, ARMABIInfo::APCS)); + { + ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS; - return *(TheTargetCodeGenInfo = - new ARMTargetCodeGenInfo(Types, ARMABIInfo::AAPCS)); + if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0) + Kind = ARMABIInfo::APCS; + else if (CodeGenOpts.FloatABI == "hard") + Kind = ARMABIInfo::AAPCS_VFP; + + return *(TheTargetCodeGenInfo = new ARMTargetCodeGenInfo(Types, Kind)); + } case llvm::Triple::ppc: return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types)); + case llvm::Triple::ptx32: + case llvm::Triple::ptx64: + return *(TheTargetCodeGenInfo = new PTXTargetCodeGenInfo(Types)); + case llvm::Triple::systemz: return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo(Types)); @@ -2836,10 +2939,11 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo(Types)); case llvm::Triple::x86: - switch (Triple.getOS()) { - case llvm::Triple::Darwin: + if (Triple.isOSDarwin()) return *(TheTargetCodeGenInfo = new X86_32TargetCodeGenInfo(Types, true, true)); + + switch (Triple.getOS()) { case llvm::Triple::Cygwin: case llvm::Triple::MinGW32: case llvm::Triple::AuroraUX: diff --git a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp index 5619212..2657faa 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Compilation.cpp @@ -101,6 +101,12 @@ bool Compilation::CleanupFileList(const ArgStringList &Files, llvm::sys::Path P(*it); std::string Error; + // Don't try to remove files which we don't have write access to (but may be + // able to remove). Underlying tools may have intentionally not overwritten + // them. + if (!P.canWrite()) + continue; + if (P.eraseFromDisk(false, &Error)) { // Failure is only failure if the file exists and is "regular". There is // a race condition here due to the limited interface of diff --git a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp index 4b6aef6..302779b 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Driver.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Driver.cpp @@ -30,6 +30,7 @@ #include "clang/Basic/Version.h" #include "llvm/Config/config.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/PrettyStackTrace.h" @@ -42,13 +43,6 @@ #include <map> -#ifdef __CYGWIN__ -#include <cygwin/version.h> -#if defined(CYGWIN_VERSION_DLL_MAJOR) && CYGWIN_VERSION_DLL_MAJOR<1007 -#define IS_CYGWIN15 1 -#endif -#endif - using namespace clang::driver; using namespace clang; @@ -58,15 +52,17 @@ Driver::Driver(llvm::StringRef _ClangExecutable, bool IsProduction, bool CXXIsProduction, Diagnostic &_Diags) : Opts(createDriverOptTable()), Diags(_Diags), - ClangExecutable(_ClangExecutable), DefaultHostTriple(_DefaultHostTriple), - DefaultImageName(_DefaultImageName), + ClangExecutable(_ClangExecutable), UseStdLib(true), + DefaultHostTriple(_DefaultHostTriple), DefaultImageName(_DefaultImageName), DriverTitle("clang \"gcc-compatible\" driver"), Host(0), - CCPrintOptionsFilename(0), CCPrintHeadersFilename(0), CCCIsCXX(false), - CCCEcho(false), CCCPrintBindings(false), CCPrintOptions(false), - CCPrintHeaders(false), CCCGenericGCCName("gcc"), - CheckInputsExist(true), CCCUseClang(true), CCCUseClangCXX(true), - CCCUseClangCPP(true), CCCUsePCH(true), SuppressMissingInputWarning(false) { + CCPrintOptionsFilename(0), CCPrintHeadersFilename(0), + CCLogDiagnosticsFilename(0), CCCIsCXX(false), + CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false), + CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false), + CCCGenericGCCName(""), CheckInputsExist(true), CCCUseClang(true), + CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true), + SuppressMissingInputWarning(false) { if (IsProduction) { // In a "production" build, only use clang on architectures we expect to // work, and don't use clang C++. @@ -100,11 +96,10 @@ Driver::~Driver() { delete Host; } -InputArgList *Driver::ParseArgStrings(const char **ArgBegin, - const char **ArgEnd) { +InputArgList *Driver::ParseArgStrings(llvm::ArrayRef<const char *> ArgList) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); unsigned MissingArgIndex, MissingArgCount; - InputArgList *Args = getOpts().ParseArgs(ArgBegin, ArgEnd, + InputArgList *Args = getOpts().ParseArgs(ArgList.begin(), ArgList.end(), MissingArgIndex, MissingArgCount); // Check for missing argument error. @@ -206,7 +201,7 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { return DAL; } -Compilation *Driver::BuildCompilation(int argc, const char **argv) { +Compilation *Driver::BuildCompilation(llvm::ArrayRef<const char *> ArgList) { llvm::PrettyStackTraceString CrashInfo("Compilation construction"); // FIXME: Handle environment options which effect driver behavior, somewhere @@ -218,9 +213,7 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { // FIXME: This stuff needs to go into the Compilation, not the driver. bool CCCPrintOptions = false, CCCPrintActions = false; - const char **Start = argv + 1, **End = argv + argc; - - InputArgList *Args = ParseArgStrings(Start, End); + InputArgList *Args = ParseArgStrings(ArgList.slice(1)); // -no-canonical-prefixes is used very early in main. Args->ClaimAllArgs(options::OPT_no_canonical_prefixes); @@ -238,13 +231,6 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { CCCPrintActions = Args->hasArg(options::OPT_ccc_print_phases); CCCPrintBindings = Args->hasArg(options::OPT_ccc_print_bindings); CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX; - if (CCCIsCXX) { -#ifdef IS_CYGWIN15 - CCCGenericGCCName = "g++-4"; -#else - CCCGenericGCCName = "g++"; -#endif - } CCCEcho = Args->hasArg(options::OPT_ccc_echo); if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name)) CCCGenericGCCName = A->getValue(*Args); @@ -287,6 +273,10 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { A->claim(); PrefixDirs.push_back(A->getValue(*Args, 0)); } + if (const Arg *A = Args->getLastArg(options::OPT__sysroot_EQ)) + SysRoot = A->getValue(*Args); + if (Args->hasArg(options::OPT_nostdlib)) + UseStdLib = false; Host = GetHostInfo(DefaultHostTriple.c_str()); @@ -593,7 +583,7 @@ static bool ContainsCompileAction(const Action *A) { } void Driver::BuildUniversalActions(const ToolChain &TC, - const ArgList &Args, + const DerivedArgList &Args, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building universal build actions"); // Collect the list of architectures. Duplicates are allowed, but should only @@ -688,7 +678,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC, } } -void Driver::BuildActions(const ToolChain &TC, const ArgList &Args, +void Driver::BuildActions(const ToolChain &TC, const DerivedArgList &Args, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); // Start by constructing the list of inputs and their types. @@ -721,18 +711,23 @@ void Driver::BuildActions(const ToolChain &TC, const ArgList &Args, // // Otherwise emit an error but still use a valid type to avoid // spurious errors (e.g., no inputs). - if (!Args.hasArgNoClaim(options::OPT_E)) + if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP) Diag(clang::diag::err_drv_unknown_stdin_type); Ty = types::TY_C; } else { - // Otherwise lookup by extension, and fallback to ObjectType if not - // found. We use a host hook here because Darwin at least has its own + // Otherwise lookup by extension. + // Fallback is C if invoked as C preprocessor or Object otherwise. + // We use a host hook here because Darwin at least has its own // idea of what .s is. if (const char *Ext = strrchr(Value, '.')) Ty = TC.LookupTypeForExtension(Ext + 1); - if (Ty == types::TY_INVALID) - Ty = types::TY_Object; + if (Ty == types::TY_INVALID) { + if (CCCIsCPP) + Ty = types::TY_C; + else + Ty = types::TY_Object; + } // If the driver is invoked as C++ compiler (like clang++ or c++) it // should autodetect some input files as C++ for g++ compatibility. @@ -799,6 +794,15 @@ void Driver::BuildActions(const ToolChain &TC, const ArgList &Args, } } + if (CCCIsCPP && Inputs.empty()) { + // If called as standalone preprocessor, stdin is processed + // if no other input is present. + unsigned Index = Args.getBaseArgs().MakeIndex("-"); + Arg *A = Opts->ParseOneArg(Args, Index); + A->claim(); + Inputs.push_back(std::make_pair(types::TY_C, A)); + } + if (!SuppressMissingInputWarning && Inputs.empty()) { Diag(clang::diag::err_drv_no_input_files); return; @@ -811,7 +815,8 @@ void Driver::BuildActions(const ToolChain &TC, const ArgList &Args, phases::ID FinalPhase; // -{E,M,MM} only run the preprocessor. - if ((FinalPhaseArg = Args.getLastArg(options::OPT_E)) || + if (CCCIsCPP || + (FinalPhaseArg = Args.getLastArg(options::OPT_E)) || (FinalPhaseArg = Args.getLastArg(options::OPT_M, options::OPT_MM))) { FinalPhase = phases::Preprocess; @@ -853,6 +858,10 @@ void Driver::BuildActions(const ToolChain &TC, const ArgList &Args, // Claim here to avoid the more general unused warning. InputArg->claim(); + // Suppress all unused style warnings with -Qunused-arguments + if (Args.hasArg(options::OPT_Qunused_arguments)) + continue; + // Special case '-E' warning on a previously preprocessed file to make // more sense. if (InitialPhase == phases::Compile && FinalPhase == phases::Preprocess && @@ -945,7 +954,8 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, } else if (Args.hasArg(options::OPT_emit_ast)) { return new CompileJobAction(Input, types::TY_AST); } else if (Args.hasArg(options::OPT_emit_llvm) || - Args.hasArg(options::OPT_flto) || HasO4) { + Args.hasFlag(options::OPT_flto, options::OPT_fno_lto, false) || + HasO4) { types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LTO_IR : types::TY_LTO_BC; return new CompileJobAction(Input, Output); @@ -1064,14 +1074,17 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, bool HasStatic = (C.getArgs().hasArg(options::OPT_mkernel) || C.getArgs().hasArg(options::OPT_static) || C.getArgs().hasArg(options::OPT_fapple_kext)); - bool IsIADefault = (TC->IsIntegratedAssemblerDefault() && !HasStatic); + bool IsDarwin = TC->getTriple().getOS() == llvm::Triple::Darwin; + bool IsIADefault = TC->IsIntegratedAssemblerDefault() && + !(HasStatic && IsDarwin); if (C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, IsIADefault) && !C.getArgs().hasArg(options::OPT_save_temps) && isa<AssembleJobAction>(JA) && Inputs->size() == 1 && isa<CompileJobAction>(*Inputs->begin())) { - const Tool &Compiler = TC->SelectTool(C,cast<JobAction>(**Inputs->begin())); + const Tool &Compiler = TC->SelectTool( + C, cast<JobAction>(**Inputs->begin()), (*Inputs)[0]->getInputs()); if (Compiler.hasIntegratedAssembler()) { Inputs = &(*Inputs)[0]->getInputs(); ToolForJob = &Compiler; @@ -1080,7 +1093,7 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, // Otherwise use the tool for the current job. if (!ToolForJob) - ToolForJob = &TC->SelectTool(C, *JA); + ToolForJob = &TC->SelectTool(C, *JA, *Inputs); // See if we should use an integrated preprocessor. We do so when we have // exactly one input, since this is the only use case we care about @@ -1206,7 +1219,13 @@ const char *Driver::GetNamedOutputPath(Compilation &C, } llvm::SmallString<128> BasePath(BaseInput); - llvm::StringRef BaseName = llvm::sys::path::filename(BasePath); + llvm::StringRef BaseName; + + // Dsymutil actions should use the full path. + if (isa<DsymutilJobAction>(JA)) + BaseName = BasePath; + else + BaseName = llvm::sys::path::filename(BasePath); // Determine what the derived output name should be. const char *NamedOutput; @@ -1243,7 +1262,12 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { // attempting to use this prefix when lokup up program paths. for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(), ie = PrefixDirs.end(); it != ie; ++it) { - llvm::sys::Path P(*it); + std::string Dir(*it); + if (Dir.empty()) + continue; + if (Dir[0] == '=') + Dir = SysRoot + Dir.substr(1); + llvm::sys::Path P(Dir); P.appendComponent(Name); bool Exists; if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) @@ -1253,7 +1277,12 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { const ToolChain::path_list &List = TC.getFilePaths(); for (ToolChain::path_list::const_iterator it = List.begin(), ie = List.end(); it != ie; ++it) { - llvm::sys::Path P(*it); + std::string Dir(*it); + if (Dir.empty()) + continue; + if (Dir[0] == '=') + Dir = SysRoot + Dir.substr(1); + llvm::sys::Path P(Dir); P.appendComponent(Name); bool Exists; if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) @@ -1323,7 +1352,7 @@ std::string Driver::GetTemporaryPath(const char *Suffix) const { const HostInfo *Driver::GetHostInfo(const char *TripleStr) const { llvm::PrettyStackTraceString CrashInfo("Constructing host"); - llvm::Triple Triple(TripleStr); + llvm::Triple Triple(llvm::Triple::normalize(TripleStr).c_str()); // TCE is an osless target if (Triple.getArchName() == "tce") diff --git a/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp b/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp index cd413180..198af54 100644 --- a/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/HostInfo.cpp @@ -113,14 +113,9 @@ ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args, TCTriple.setArch(Arch); // If we recognized the arch, match it to the toolchains we support. - const char *UseNewToolChain = ::getenv("CCC_ENABLE_NEW_DARWIN_TOOLCHAIN"); - if (UseNewToolChain || - Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64 || + if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) { TC = new toolchains::DarwinClang(*this, TCTriple); - } else if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { - // We still use the legacy DarwinGCC toolchain on X86. - TC = new toolchains::DarwinGCC(*this, TCTriple); } else TC = new toolchains::Darwin_Generic_GCC(*this, TCTriple); } diff --git a/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp b/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp index c3d3048..0252b3e 100644 --- a/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/OptTable.cpp @@ -20,9 +20,9 @@ using namespace clang::driver::options; // Ordering on Info. The ordering is *almost* lexicographic, with two // exceptions. First, '\0' comes at the end of the alphabet instead of -// the beginning (thus options preceed any other options which prefix +// the beginning (thus options precede any other options which prefix // them). Second, for options with the same name, the less permissive -// version should come first; a Flag option should preceed a Joined +// version should come first; a Flag option should precede a Joined // option, for example. static int StrCmpOptionName(const char *A, const char *B) { diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp index e305683..d919915 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChain.cpp @@ -47,7 +47,7 @@ bool ToolChain::HasNativeLLVMSupport() const { return false; } -/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting. +/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. // // FIXME: tblgen this. static const char *getARMTargetCPU(const ArgList &Args, @@ -101,6 +101,8 @@ static const char *getARMTargetCPU(const ArgList &Args, return "iwmmxt"; if (MArch == "xscale") return "xscale"; + if (MArch == "armv6m" || MArch == "armv6-m") + return "cortex-m0"; // If all else failed, return the most base CPU LLVM supports. return "arm7tdmi"; @@ -137,6 +139,12 @@ static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) { if (CPU == "cortex-a8" || CPU == "cortex-a9") return "v7"; + if (CPU == "cortex-m3") + return "v7m"; + + if (CPU == "cortex-m0") + return "v6m"; + return ""; } @@ -168,10 +176,10 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args) const { } std::string ToolChain::ComputeEffectiveClangTriple(const ArgList &Args) const { - // Diagnose use of -mmacosx-version-min and -miphoneos-version-min on - // non-Darwin. + // Diagnose use of Darwin OS deployment target arguments on non-Darwin. if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ, - options::OPT_miphoneos_version_min_EQ)) + options::OPT_miphoneos_version_min_EQ, + options::OPT_mios_simulator_version_min_EQ)) getDriver().Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp index 422c572..499587a 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp @@ -105,7 +105,8 @@ static const char *GetArmArchForMCpu(llvm::StringRef Value) { return "xscale"; if (Value == "arm1136j-s" || Value == "arm1136jf-s" || - Value == "arm1176jz-s" || Value == "arm1176jzf-s") + Value == "arm1176jz-s" || Value == "arm1176jzf-s" || + Value == "cortex-m0" ) return "armv6"; if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3") @@ -118,7 +119,8 @@ llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const { switch (getTriple().getArch()) { default: return getArchName(); - + + case llvm::Triple::thumb: case llvm::Triple::arm: { if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) if (const char *Arch = GetArmArchForMArch(A->getValue(Args))) @@ -133,82 +135,6 @@ llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const { } } -DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple) - : Darwin(Host, Triple) -{ - // We can only work with 4.2.1 currently. - GCCVersion[0] = 4; - GCCVersion[1] = 2; - GCCVersion[2] = 1; - - // Set up the tool chain paths to match gcc. - ToolChainDir = "i686-apple-darwin"; - ToolChainDir += llvm::utostr(DarwinVersion[0]); - ToolChainDir += "/"; - ToolChainDir += llvm::utostr(GCCVersion[0]); - ToolChainDir += '.'; - ToolChainDir += llvm::utostr(GCCVersion[1]); - ToolChainDir += '.'; - ToolChainDir += llvm::utostr(GCCVersion[2]); - - // Try the next major version if that tool chain dir is invalid. - std::string Tmp = "/usr/lib/gcc/" + ToolChainDir; - bool Exists; - if (llvm::sys::fs::exists(Tmp, Exists) || Exists) { - std::string Next = "i686-apple-darwin"; - Next += llvm::utostr(DarwinVersion[0] + 1); - Next += "/"; - Next += llvm::utostr(GCCVersion[0]); - Next += '.'; - Next += llvm::utostr(GCCVersion[1]); - Next += '.'; - Next += llvm::utostr(GCCVersion[2]); - - // Use that if it exists, otherwise hope the user isn't linking. - // - // FIXME: Drop dependency on gcc's tool chain. - Tmp = "/usr/lib/gcc/" + Next; - if (!llvm::sys::fs::exists(Tmp, Exists) && Exists) - ToolChainDir = Next; - } - - std::string Path; - if (getArchName() == "x86_64") { - Path = getDriver().Dir; - Path += "/../lib/gcc/"; - Path += ToolChainDir; - Path += "/x86_64"; - getFilePaths().push_back(Path); - - Path = "/usr/lib/gcc/"; - Path += ToolChainDir; - Path += "/x86_64"; - getFilePaths().push_back(Path); - } - - Path = getDriver().Dir; - Path += "/../lib/gcc/"; - Path += ToolChainDir; - getFilePaths().push_back(Path); - - Path = "/usr/lib/gcc/"; - Path += ToolChainDir; - getFilePaths().push_back(Path); - - Path = getDriver().Dir; - Path += "/../libexec/gcc/"; - Path += ToolChainDir; - getProgramPaths().push_back(Path); - - Path = "/usr/libexec/gcc/"; - Path += ToolChainDir; - getProgramPaths().push_back(Path); - - getProgramPaths().push_back(getDriver().getInstalledDir()); - if (getDriver().getInstalledDir() != getDriver().Dir) - getProgramPaths().push_back(getDriver().Dir); -} - Darwin::~Darwin() { // Free tool implementations. for (llvm::DenseMap<unsigned, Tool*>::iterator @@ -226,33 +152,31 @@ std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args) const { unsigned Version[3]; getTargetVersion(Version); - - // Mangle the target version into the OS triple component. For historical - // reasons that make little sense, the version passed here is the "darwin" - // version, which drops the 10 and offsets by 4. See inverse code when - // setting the OS version preprocessor define. - if (!isTargetIPhoneOS()) { - Version[0] = Version[1] + 4; - Version[1] = Version[2]; - Version[2] = 0; - } else { - // Use the environment to communicate that we are targetting iPhoneOS. - Triple.setEnvironmentName("iphoneos"); - } - + llvm::SmallString<16> Str; - llvm::raw_svector_ostream(Str) << "darwin" << Version[0] - << "." << Version[1] << "." << Version[2]; + llvm::raw_svector_ostream(Str) + << (isTargetIPhoneOS() ? "ios" : "macosx") + << Version[0] << "." << Version[1] << "." << Version[2]; Triple.setOSName(Str.str()); return Triple.getTriple(); } -Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const { +Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const { Action::ActionClass Key; - if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) - Key = Action::AnalyzeJobClass; - else + + if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) { + // Fallback to llvm-gcc for i386 kext compiles, we don't support that ABI. + if (Inputs.size() == 1 && + types::isCXX(Inputs[0]->getType()) && + getTriple().getOS() == llvm::Triple::Darwin && + getTriple().getArch() == llvm::Triple::x86 && + C.getArgs().getLastArg(options::OPT_fapple_kext)) + Key = JA.getKind(); + else + Key = Action::AnalyzeJobClass; + } else Key = JA.getKind(); // FIXME: This doesn't belong here, but ideally we will support static soon @@ -297,91 +221,12 @@ Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const { return *T; } -void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - std::string Tmp; - - // FIXME: Derive these correctly. - if (getArchName() == "x86_64") { - CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + - "/x86_64")); - // Intentionally duplicated for (temporary) gcc bug compatibility. - CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + - "/x86_64")); - } - - CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/" + ToolChainDir)); - - Tmp = getDriver().Dir + "/../lib/gcc/" + ToolChainDir; - bool Exists; - if (!llvm::sys::fs::exists(Tmp, Exists) && Exists) - CmdArgs.push_back(Args.MakeArgString("-L" + Tmp)); - Tmp = getDriver().Dir + "/../lib/gcc"; - if (!llvm::sys::fs::exists(Tmp, Exists) && Exists) - CmdArgs.push_back(Args.MakeArgString("-L" + Tmp)); - CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir)); - // Intentionally duplicated for (temporary) gcc bug compatibility. - CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir)); - Tmp = getDriver().Dir + "/../lib/" + ToolChainDir; - if (!llvm::sys::fs::exists(Tmp, Exists) && Exists) - CmdArgs.push_back(Args.MakeArgString("-L" + Tmp)); - Tmp = getDriver().Dir + "/../lib"; - if (!llvm::sys::fs::exists(Tmp, Exists) && Exists) - CmdArgs.push_back(Args.MakeArgString("-L" + Tmp)); - CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + - "/../../../" + ToolChainDir)); - CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + - "/../../..")); -} - -void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Note that this routine is only used for targetting OS X. - - // Derived from libgcc and lib specs but refactored. - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-lgcc_static"); - } else { - if (Args.hasArg(options::OPT_static_libgcc)) { - CmdArgs.push_back("-lgcc_eh"); - } else if (Args.hasArg(options::OPT_miphoneos_version_min_EQ)) { - // Derived from darwin_iphoneos_libgcc spec. - if (isTargetIPhoneOS()) { - CmdArgs.push_back("-lgcc_s.1"); - } else { - CmdArgs.push_back("-lgcc_s.10.5"); - } - } else if (Args.hasArg(options::OPT_shared_libgcc) || - Args.hasFlag(options::OPT_fexceptions, - options::OPT_fno_exceptions) || - Args.hasArg(options::OPT_fgnu_runtime)) { - // FIXME: This is probably broken on 10.3? - if (isMacosxVersionLT(10, 5)) - CmdArgs.push_back("-lgcc_s.10.4"); - else if (isMacosxVersionLT(10, 6)) - CmdArgs.push_back("-lgcc_s.10.5"); - } else { - if (isMacosxVersionLT(10, 3, 9)) - ; // Do nothing. - else if (isMacosxVersionLT(10, 5)) - CmdArgs.push_back("-lgcc_s.10.4"); - else if (isMacosxVersionLT(10, 6)) - CmdArgs.push_back("-lgcc_s.10.5"); - } - - if (isTargetIPhoneOS() || isMacosxVersionLT(10, 6)) { - CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("-lSystem"); - } else { - CmdArgs.push_back("-lSystem"); - CmdArgs.push_back("-lgcc"); - } - } -} DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple) : Darwin(Host, Triple) { + std::string UsrPrefix = "llvm-gcc-4.2/"; + getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); @@ -392,18 +237,18 @@ DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple) getProgramPaths().push_back(getDriver().Dir); // For fallback, we need to know how to find the GCC cc1 executables, so we - // also add the GCC libexec paths. This is legiy code that can be removed once - // fallback is no longer useful. + // also add the GCC libexec paths. This is legacy code that can be removed + // once fallback is no longer useful. std::string ToolChainDir = "i686-apple-darwin"; ToolChainDir += llvm::utostr(DarwinVersion[0]); ToolChainDir += "/4.2.1"; std::string Path = getDriver().Dir; - Path += "/../libexec/gcc/"; + Path += "/../" + UsrPrefix + "libexec/gcc/"; Path += ToolChainDir; getProgramPaths().push_back(Path); - Path = "/usr/libexec/gcc/"; + Path = "/usr/" + UsrPrefix + "libexec/gcc/"; Path += ToolChainDir; getProgramPaths().push_back(Path); } @@ -498,12 +343,13 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, // Select the dynamic runtime library and the target specific static library. const char *DarwinStaticLib = 0; if (isTargetIPhoneOS()) { - CmdArgs.push_back("-lgcc_s.1"); + // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1, + // it never went into the SDK. + if (!isTargetIOSSimulator()) + CmdArgs.push_back("-lgcc_s.1"); - // We may need some static functions for armv6/thumb which are required to - // be in the same linkage unit as their caller. - if (getDarwinArchName(Args) == "armv6") - DarwinStaticLib = "libclang_rt.armv6.a"; + // We currently always need a static runtime library for iOS. + DarwinStaticLib = "libclang_rt.ios.a"; } else { // The dynamic runtime library was merged with libSystem for 10.6 and // beyond; only 10.4 and 10.5 need an additional runtime library. @@ -513,7 +359,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, CmdArgs.push_back("-lgcc_s.10.5"); // For OS X, we thought we would only need a static runtime library when - // targetting 10.4, to provide versions of the static functions which were + // targeting 10.4, to provide versions of the static functions which were // omitted from 10.4.dylib. // // Unfortunately, that turned out to not be true, because Darwin system @@ -547,46 +393,69 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { const OptTable &Opts = getDriver().getOpts(); Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); - Arg *iPhoneVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ); - if (OSXVersion && iPhoneVersion) { + Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ); + Arg *iOSSimVersion = Args.getLastArg( + options::OPT_mios_simulator_version_min_EQ); + if (OSXVersion && (iOSVersion || iOSSimVersion)) { getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) - << iPhoneVersion->getAsString(Args); - iPhoneVersion = 0; - } else if (!OSXVersion && !iPhoneVersion) { - // If neither OS X nor iPhoneOS targets were specified, check for + << (iOSVersion ? iOSVersion : iOSSimVersion)->getAsString(Args); + iOSVersion = iOSSimVersion = 0; + } else if (iOSVersion && iOSSimVersion) { + getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with) + << iOSVersion->getAsString(Args) + << iOSSimVersion->getAsString(Args); + iOSSimVersion = 0; + } else if (!OSXVersion && !iOSVersion && !iOSSimVersion) { + // If not deployment target was specified on the command line, check for // environment defines. const char *OSXTarget = ::getenv("MACOSX_DEPLOYMENT_TARGET"); - const char *iPhoneOSTarget = ::getenv("IPHONEOS_DEPLOYMENT_TARGET"); + const char *iOSTarget = ::getenv("IPHONEOS_DEPLOYMENT_TARGET"); + const char *iOSSimTarget = ::getenv("IOS_SIMULATOR_DEPLOYMENT_TARGET"); // Ignore empty strings. if (OSXTarget && OSXTarget[0] == '\0') OSXTarget = 0; - if (iPhoneOSTarget && iPhoneOSTarget[0] == '\0') - iPhoneOSTarget = 0; + if (iOSTarget && iOSTarget[0] == '\0') + iOSTarget = 0; + if (iOSSimTarget && iOSSimTarget[0] == '\0') + iOSSimTarget = 0; - // Diagnose conflicting deployment targets, and choose default platform - // based on the tool chain. + // Handle conflicting deployment targets // // FIXME: Don't hardcode default here. - if (OSXTarget && iPhoneOSTarget) { - // FIXME: We should see if we can get away with warning or erroring on - // this. Perhaps put under -pedantic? + + // Do not allow conflicts with the iOS simulator target. + if (iOSSimTarget && (OSXTarget || iOSTarget)) { + getDriver().Diag(clang::diag::err_drv_conflicting_deployment_targets) + << "IOS_SIMULATOR_DEPLOYMENT_TARGET" + << (OSXTarget ? "MACOSX_DEPLOYMENT_TARGET" : + "IPHONEOS_DEPLOYMENT_TARGET"); + } + + // Allow conflicts among OSX and iOS for historical reasons, but choose the + // default platform. + if (OSXTarget && iOSTarget) { if (getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::thumb) OSXTarget = 0; else - iPhoneOSTarget = 0; + iOSTarget = 0; } if (OSXTarget) { const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget); Args.append(OSXVersion); - } else if (iPhoneOSTarget) { + } else if (iOSTarget) { const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); - iPhoneVersion = Args.MakeJoinedArg(0, O, iPhoneOSTarget); - Args.append(iPhoneVersion); + iOSVersion = Args.MakeJoinedArg(0, O, iOSTarget); + Args.append(iOSVersion); + } else if (iOSSimTarget) { + const Option *O = Opts.getOption( + options::OPT_mios_simulator_version_min_EQ); + iOSSimVersion = Args.MakeJoinedArg(0, O, iOSSimTarget); + Args.append(iOSSimVersion); } else { // Otherwise, assume we are targeting OS X. const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); @@ -595,25 +464,44 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } } + // Reject invalid architecture combinations. + if (iOSSimVersion && (getTriple().getArch() != llvm::Triple::x86 && + getTriple().getArch() != llvm::Triple::x86_64)) { + getDriver().Diag(clang::diag::err_drv_invalid_arch_for_deployment_target) + << getTriple().getArchName() << iOSSimVersion->getAsString(Args); + } + // Set the tool chain target information. unsigned Major, Minor, Micro; bool HadExtra; if (OSXVersion) { - assert(!iPhoneVersion && "Unknown target platform!"); + assert((!iOSVersion && !iOSSimVersion) && "Unknown target platform!"); if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor, Micro, HadExtra) || HadExtra || - Major != 10 || Minor >= 10 || Micro >= 10) + Major != 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(clang::diag::err_drv_invalid_version_number) << OSXVersion->getAsString(Args); } else { - assert(iPhoneVersion && "Unknown target platform!"); - if (!Driver::GetReleaseVersion(iPhoneVersion->getValue(Args), Major, Minor, + const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion; + assert(Version && "Unknown target platform!"); + if (!Driver::GetReleaseVersion(Version->getValue(Args), Major, Minor, Micro, HadExtra) || HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(clang::diag::err_drv_invalid_version_number) - << iPhoneVersion->getAsString(Args); + << Version->getAsString(Args); } - setTarget(iPhoneVersion, Major, Minor, Micro); + + bool IsIOSSim = bool(iOSSimVersion); + + // In GCC, the simulator historically was treated as being OS X in some + // contexts, like determining the link logic, despite generally being called + // with an iOS deployment target. For compatibility, we detect the + // simulator as iOS + x86, and treat it differently in a few contexts. + if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64)) + IsIOSSim = true; + + setTarget(/*IsIPhoneOS=*/ !OSXVersion, Major, Minor, Micro, IsIOSSim); } void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, @@ -716,9 +604,12 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // driver behavior; that isn't going to work in our model. We // use isDriverOption() as an approximation, although things // like -O4 are going to slip through. - if (!XarchArg || Index > Prev + 1 || - XarchArg->getOption().isDriverOption()) { - getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument) + if (!XarchArg || Index > Prev + 1) { + getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument_with_args) + << A->getAsString(Args); + continue; + } else if (XarchArg->getOption().isDriverOption()) { + getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument_isdriver) << A->getAsString(Args); continue; } @@ -922,6 +813,11 @@ const char *Darwin::GetForcedPicModel() const { return 0; } +bool Darwin::SupportsProfiling() const { + // Profiling instrumentation is only supported on x86. + return getArchName() == "i386" || getArchName() == "x86_64"; +} + bool Darwin::SupportsObjCGC() const { // Garbage collection is supported everywhere except on iPhone OS. return !isTargetIPhoneOS(); @@ -939,7 +835,7 @@ Darwin_Generic_GCC::ComputeEffectiveClangTriple(const ArgList &Args) const { Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple) { getProgramPaths().push_back(getDriver().getInstalledDir()); - if (getDriver().getInstalledDir() != getDriver().Dir.c_str()) + if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); } @@ -951,7 +847,8 @@ Generic_GCC::~Generic_GCC() { } Tool &Generic_GCC::SelectTool(const Compilation &C, - const JobAction &JA) const { + const JobAction &JA, + const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; @@ -1039,7 +936,8 @@ const char *TCEToolChain::GetForcedPicModel() const { } Tool &TCEToolChain::SelectTool(const Compilation &C, - const JobAction &JA) const { + const JobAction &JA, + const ActionList &Inputs) const { Action::ActionClass Key; Key = Action::AnalyzeJobClass; @@ -1065,7 +963,8 @@ OpenBSD::OpenBSD(const HostInfo &Host, const llvm::Triple& Triple) getFilePaths().push_back("/usr/lib"); } -Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const { +Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; @@ -1089,7 +988,7 @@ Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const { case Action::LinkJobClass: T = new tools::openbsd::Link(*this); break; default: - T = &Generic_GCC::SelectTool(C, JA); + T = &Generic_GCC::SelectTool(C, JA, Inputs); } } @@ -1115,7 +1014,8 @@ FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple) } } -Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const { +Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; @@ -1138,7 +1038,7 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const { case Action::LinkJobClass: T = new tools::freebsd::Link(*this); break; default: - T = &Generic_GCC::SelectTool(C, JA); + T = &Generic_GCC::SelectTool(C, JA, Inputs); } } @@ -1157,16 +1057,16 @@ NetBSD::NetBSD(const HostInfo &Host, const llvm::Triple& Triple) llvm::Triple::x86_64) Lib32 = true; - getProgramPaths().push_back(getDriver().Dir + "/../libexec"); - getProgramPaths().push_back("/usr/libexec"); - if (Lib32) { - getFilePaths().push_back("/usr/lib/i386"); - } else { - getFilePaths().push_back("/usr/lib"); + if (getDriver().UseStdLib) { + if (Lib32) + getFilePaths().push_back("=/usr/lib/i386"); + else + getFilePaths().push_back("=/usr/lib"); } } -Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA) const { +Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; @@ -1189,7 +1089,7 @@ Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA) const { case Action::LinkJobClass: T = new tools::netbsd::Link(*this); break; default: - T = &Generic_GCC::SelectTool(C, JA); + T = &Generic_GCC::SelectTool(C, JA, Inputs); } } @@ -1206,7 +1106,8 @@ Minix::Minix(const HostInfo &Host, const llvm::Triple& Triple) getFilePaths().push_back("/usr/gnu/lib/gcc/i686-pc-minix/4.4.3"); } -Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA) const { +Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; @@ -1221,7 +1122,7 @@ Tool &Minix::SelectTool(const Compilation &C, const JobAction &JA) const { case Action::LinkJobClass: T = new tools::minix::Link(*this); break; default: - T = &Generic_GCC::SelectTool(C, JA); + T = &Generic_GCC::SelectTool(C, JA, Inputs); } } @@ -1234,7 +1135,7 @@ AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) { getProgramPaths().push_back(getDriver().getInstalledDir()); - if (getDriver().getInstalledDir() != getDriver().Dir.c_str()) + if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); @@ -1245,7 +1146,8 @@ AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple) } -Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const { +Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; @@ -1260,7 +1162,7 @@ Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const { case Action::LinkJobClass: T = new tools::auroraux::Link(*this); break; default: - T = &Generic_GCC::SelectTool(C, JA); + T = &Generic_GCC::SelectTool(C, JA, Inputs); } } @@ -1277,16 +1179,22 @@ enum LinuxDistro { Exherbo, Fedora13, Fedora14, + Fedora15, + FedoraRawhide, OpenSuse11_3, + UbuntuHardy, + UbuntuIntrepid, UbuntuJaunty, UbuntuKarmic, UbuntuLucid, UbuntuMaverick, + UbuntuNatty, UnknownDistro }; static bool IsFedora(enum LinuxDistro Distro) { - return Distro == Fedora13 || Distro == Fedora14; + return Distro == Fedora13 || Distro == Fedora14 || + Distro == Fedora15 || Distro == FedoraRawhide; } static bool IsOpenSuse(enum LinuxDistro Distro) { @@ -1298,8 +1206,10 @@ static bool IsDebian(enum LinuxDistro Distro) { } static bool IsUbuntu(enum LinuxDistro Distro) { - return Distro == UbuntuLucid || Distro == UbuntuMaverick || - Distro == UbuntuJaunty || Distro == UbuntuKarmic; + return Distro == UbuntuHardy || Distro == UbuntuIntrepid || + Distro == UbuntuLucid || Distro == UbuntuMaverick || + Distro == UbuntuJaunty || Distro == UbuntuKarmic || + Distro == UbuntuNatty; } static bool IsDebianBased(enum LinuxDistro Distro) { @@ -1315,7 +1225,9 @@ static bool HasMultilib(llvm::Triple::ArchType Arch, enum LinuxDistro Distro) { return true; } - if (Arch == llvm::Triple::x86 && IsDebianBased(Distro)) + if (Arch == llvm::Triple::ppc64) + return true; + if ((Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) && IsDebianBased(Distro)) return true; return false; } @@ -1327,24 +1239,35 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { llvm::SmallVector<llvm::StringRef, 8> Lines; Data.split(Lines, "\n"); for (unsigned int i = 0, s = Lines.size(); i < s; ++ i) { - if (Lines[i] == "DISTRIB_CODENAME=maverick") - return UbuntuMaverick; - else if (Lines[i] == "DISTRIB_CODENAME=lucid") - return UbuntuLucid; + if (Lines[i] == "DISTRIB_CODENAME=hardy") + return UbuntuHardy; + else if (Lines[i] == "DISTRIB_CODENAME=intrepid") + return UbuntuIntrepid; else if (Lines[i] == "DISTRIB_CODENAME=jaunty") return UbuntuJaunty; else if (Lines[i] == "DISTRIB_CODENAME=karmic") return UbuntuKarmic; + else if (Lines[i] == "DISTRIB_CODENAME=lucid") + return UbuntuLucid; + else if (Lines[i] == "DISTRIB_CODENAME=maverick") + return UbuntuMaverick; + else if (Lines[i] == "DISTRIB_CODENAME=natty") + return UbuntuNatty; } return UnknownDistro; } if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) { llvm::StringRef Data = File.get()->getBuffer(); - if (Data.startswith("Fedora release 14 (Laughlin)")) + if (Data.startswith("Fedora release 15")) + return Fedora15; + else if (Data.startswith("Fedora release 14")) return Fedora14; - else if (Data.startswith("Fedora release 13 (Goddard)")) + else if (Data.startswith("Fedora release 13")) return Fedora13; + else if (Data.startswith("Fedora release") && + Data.find("Rawhide") != llvm::StringRef::npos) + return FedoraRawhide; return UnknownDistro; } @@ -1384,7 +1307,7 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) Suffix32 = "/32"; std::string Suffix64 = ""; - if (Arch == llvm::Triple::x86) + if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) Suffix64 = "/64"; std::string Lib32 = "lib"; @@ -1400,7 +1323,7 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) Lib64 = "lib64"; std::string GccTriple = ""; - if (Arch == llvm::Triple::arm) { + if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) { if (!llvm::sys::fs::exists("/usr/lib/gcc/arm-linux-gnueabi", Exists) && Exists) GccTriple = "arm-linux-gnueabi"; @@ -1423,6 +1346,9 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-manbo-linux-gnu", Exists) && Exists) GccTriple = "x86_64-manbo-linux-gnu"; + else if (!llvm::sys::fs::exists("/usr/lib/x86_64-linux-gnu/gcc", + Exists) && Exists) + GccTriple = "x86_64-linux-gnu"; } else if (Arch == llvm::Triple::x86) { if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-linux-gnu", Exists) && Exists) GccTriple = "i686-linux-gnu"; @@ -1438,11 +1364,26 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) else if (!llvm::sys::fs::exists("/usr/lib/gcc/i586-suse-linux", Exists) && Exists) GccTriple = "i586-suse-linux"; + else if (!llvm::sys::fs::exists("/usr/lib/gcc/i486-slackware-linux", Exists) + && Exists) + GccTriple = "i486-slackware-linux"; + } else if (Arch == llvm::Triple::ppc) { + if (!llvm::sys::fs::exists("/usr/lib/powerpc-linux-gnu", Exists) && Exists) + GccTriple = "powerpc-linux-gnu"; + else if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc-unknown-linux-gnu", Exists) && Exists) + GccTriple = "powerpc-unknown-linux-gnu"; + } else if (Arch == llvm::Triple::ppc64) { + if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc64-unknown-linux-gnu", Exists) && Exists) + GccTriple = "powerpc64-unknown-linux-gnu"; + else if (!llvm::sys::fs::exists("/usr/lib64/gcc/powerpc64-unknown-linux-gnu", Exists) && Exists) + GccTriple = "powerpc64-unknown-linux-gnu"; } - const char* GccVersions[] = {"4.5.2", "4.5.1", "4.5", "4.4.5", "4.4.4", - "4.4.3", "4.4", "4.3.4", "4.3.3", "4.3.2", - "4.3"}; + const char* GccVersions[] = {"4.6.0", + "4.5.2", "4.5.1", "4.5", + "4.4.5", "4.4.4", "4.4.3", "4.4", + "4.3.4", "4.3.3", "4.3.2", "4.3", + "4.2.4", "4.2.3", "4.2.2", "4.2.1", "4.2"}; std::string Base = ""; for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) { std::string Suffix = GccTriple + "/" + GccVersions[i]; @@ -1456,10 +1397,15 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) Base = t2; break; } + std::string t3 = "/usr/lib/" + GccTriple + "/gcc/" + Suffix; + if (!llvm::sys::fs::exists(t3 + "/crtbegin.o", Exists) && Exists) { + Base = t3; + break; + } } path_list &Paths = getFilePaths(); - bool Is32Bits = getArch() == llvm::Triple::x86; + bool Is32Bits = (getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::ppc); std::string Suffix; std::string Lib; @@ -1485,10 +1431,10 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) ExtraOpts.push_back("relro"); } - if (Arch == llvm::Triple::arm) + if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) ExtraOpts.push_back("-X"); - if (IsFedora(Distro) || Distro == UbuntuMaverick) + if (IsFedora(Distro) || Distro == UbuntuMaverick || Distro == UbuntuNatty) ExtraOpts.push_back("--hash-style=gnu"); if (IsDebian(Distro) || Distro == UbuntuLucid || Distro == UbuntuJaunty || @@ -1500,7 +1446,7 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) if (Distro == DebianSqueeze || IsOpenSuse(Distro) || IsFedora(Distro) || Distro == UbuntuLucid || Distro == UbuntuMaverick || - Distro == UbuntuKarmic) + Distro == UbuntuKarmic || Distro == UbuntuNatty) ExtraOpts.push_back("--build-id"); if (Distro == ArchLinux) @@ -1527,7 +1473,8 @@ bool Linux::HasNativeLLVMSupport() const { return true; } -Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA) const { +Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; @@ -1550,7 +1497,7 @@ Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA) const { case Action::LinkJobClass: T = new tools::linuxtools::Link(*this); break; default: - T = &Generic_GCC::SelectTool(C, JA); + T = &Generic_GCC::SelectTool(C, JA, Inputs); } } @@ -1564,7 +1511,7 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple) // Path mangling to find libexec getProgramPaths().push_back(getDriver().getInstalledDir()); - if (getDriver().getInstalledDir() != getDriver().Dir.c_str()) + if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); getFilePaths().push_back(getDriver().Dir + "/../lib"); @@ -1572,7 +1519,8 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple) getFilePaths().push_back("/usr/lib/gcc41"); } -Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA) const { +Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; @@ -1587,7 +1535,7 @@ Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA) const { case Action::LinkJobClass: T = new tools::dragonfly::Link(*this); break; default: - T = &Generic_GCC::SelectTool(C, JA); + T = &Generic_GCC::SelectTool(C, JA, Inputs); } } @@ -1598,7 +1546,8 @@ Windows::Windows(const HostInfo &Host, const llvm::Triple& Triple) : ToolChain(Host, Triple) { } -Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA) const { +Tool &Windows::SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const { Action::ActionClass Key; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h index 0e3645c..7a1a050 100644 --- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.h +++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.h @@ -33,7 +33,8 @@ public: Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple); ~Generic_GCC(); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const; virtual bool IsUnwindTablesDefault() const; virtual const char *GetDefaultRelocationModel() const; @@ -56,10 +57,13 @@ private: // the argument translation business. mutable bool TargetInitialized; - /// Whether we are targetting iPhoneOS target. + /// Whether we are targeting iPhoneOS target. mutable bool TargetIsIPhoneOS; - /// The OS version we are targetting. + /// Whether we are targeting the iPhoneOS simulator target. + mutable bool TargetIsIPhoneOSSimulator; + + /// The OS version we are targeting. mutable unsigned TargetVersion[3]; /// The default macosx-version-min of this tool chain; empty until @@ -80,18 +84,22 @@ public: // FIXME: Eliminate these ...Target functions and derive separate tool chains // for these targets and put version in constructor. - void setTarget(bool isIPhoneOS, unsigned Major, unsigned Minor, - unsigned Micro) const { + void setTarget(bool IsIPhoneOS, unsigned Major, unsigned Minor, + unsigned Micro, bool IsIOSSim) const { + assert((!IsIOSSim || IsIPhoneOS) && "Unexpected deployment target!"); + // FIXME: For now, allow reinitialization as long as values don't // change. This will go away when we move away from argument translation. - if (TargetInitialized && TargetIsIPhoneOS == isIPhoneOS && + if (TargetInitialized && TargetIsIPhoneOS == IsIPhoneOS && + TargetIsIPhoneOSSimulator == IsIOSSim && TargetVersion[0] == Major && TargetVersion[1] == Minor && TargetVersion[2] == Micro) return; assert(!TargetInitialized && "Target already initialized!"); TargetInitialized = true; - TargetIsIPhoneOS = isIPhoneOS; + TargetIsIPhoneOS = IsIPhoneOS; + TargetIsIPhoneOSSimulator = IsIOSSim; TargetVersion[0] = Major; TargetVersion[1] = Minor; TargetVersion[2] = Micro; @@ -102,6 +110,11 @@ public: return TargetIsIPhoneOS; } + bool isTargetIOSSimulator() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetIsIPhoneOSSimulator; + } + bool isTargetInitialized() const { return TargetInitialized; } void getTargetVersion(unsigned (&Res)[3]) const { @@ -160,7 +173,8 @@ public: virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args, const char *BoundArch) const; - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const; virtual bool IsBlocksDefault() const { // Always allow blocks on Darwin; users interested in versioning are @@ -212,6 +226,8 @@ public: virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; + virtual bool SupportsProfiling() const; + virtual bool SupportsObjCGC() const; virtual bool UseDwarfDebugFlags() const; @@ -244,29 +260,6 @@ public: /// } }; -/// DarwinGCC - The Darwin toolchain used by GCC. -class LLVM_LIBRARY_VISIBILITY DarwinGCC : public Darwin { - /// GCC version to use. - unsigned GCCVersion[3]; - - /// The directory suffix for this tool chain. - std::string ToolChainDir; - -public: - DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple); - - /// @name Darwin ToolChain Implementation - /// { - - virtual void AddLinkSearchPathArgs(const ArgList &Args, - ArgStringList &CmdArgs) const; - - virtual void AddLinkRuntimeLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const; - - /// } -}; - /// Darwin_Generic_GCC - Generic Darwin tool chain using gcc. class LLVM_LIBRARY_VISIBILITY Darwin_Generic_GCC : public Generic_GCC { public: @@ -294,42 +287,48 @@ class LLVM_LIBRARY_VISIBILITY AuroraUX : public Generic_GCC { public: AuroraUX(const HostInfo &Host, const llvm::Triple& Triple); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF { public: OpenBSD(const HostInfo &Host, const llvm::Triple& Triple); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF { public: FreeBSD(const HostInfo &Host, const llvm::Triple& Triple); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF { public: NetBSD(const HostInfo &Host, const llvm::Triple& Triple); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY Minix : public Generic_GCC { public: Minix(const HostInfo &Host, const llvm::Triple& Triple); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF { public: DragonFly(const HostInfo &Host, const llvm::Triple& Triple); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const; }; class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { @@ -338,7 +337,8 @@ public: virtual bool HasNativeLLVMSupport() const; - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const; std::string Linker; std::vector<std::string> ExtraOpts; @@ -352,7 +352,8 @@ public: TCEToolChain(const HostInfo &Host, const llvm::Triple& Triple); ~TCEToolChain(); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const; bool IsMathErrnoDefault() const; bool IsUnwindTablesDefault() const; const char* GetDefaultRelocationModel() const; @@ -369,7 +370,8 @@ class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain { public: Windows(const HostInfo &Host, const llvm::Triple& Triple); - virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const; virtual bool IsIntegratedAssemblerDefault() const; virtual bool IsUnwindTablesDefault() const; diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp index a2c95fc..7b78cd5 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.cpp +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.cpp @@ -34,14 +34,32 @@ #include "InputInfo.h" #include "ToolChains.h" +#ifdef __CYGWIN__ +#include <cygwin/version.h> +#if defined(CYGWIN_VERSION_DLL_MAJOR) && CYGWIN_VERSION_DLL_MAJOR<1007 +#define IS_CYGWIN15 1 +#endif +#endif + using namespace clang::driver; using namespace clang::driver::tools; +/// FindTargetProgramPath - Return path of the target specific version of +/// ProgName. If it doesn't exist, return path of ProgName itself. +static std::string FindTargetProgramPath(const ToolChain &TheToolChain, + const char *ProgName) { + std::string Executable(TheToolChain.getTripleString() + "-" + ProgName); + std::string Path(TheToolChain.GetProgramPath(Executable.c_str())); + if (Path != Executable) + return Path; + return TheToolChain.GetProgramPath(ProgName); +} + /// CheckPreprocessingOptions - Perform some validation of preprocessing /// arguments that is shared with gcc. static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC)) - if (!Args.hasArg(options::OPT_E)) + if (!Args.hasArg(options::OPT_E) && !D.CCCIsCPP) D.Diag(clang::diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-E"; } @@ -309,7 +327,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, } } -/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting. +/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. // // FIXME: tblgen this. static const char *getARMTargetCPU(const ArgList &Args, @@ -363,6 +381,8 @@ static const char *getARMTargetCPU(const ArgList &Args, return "iwmmxt"; if (MArch == "xscale") return "xscale"; + if (MArch == "armv6m" || MArch == "armv6-m") + return "cortex-m0"; // If all else failed, return the most base CPU LLVM supports. return "arm7tdmi"; @@ -420,10 +440,17 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { } void Clang::AddARMTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { + ArgStringList &CmdArgs, + bool KernelOrKext) const { const Driver &D = getToolChain().getDriver(); llvm::Triple Triple = getToolChain().getTriple(); + // Disable movt generation, if requested. +#ifdef DISABLE_ARM_DARWIN_USE_MOVT + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-darwin-use-movt=0"); +#endif + // Select the ABI to use. // // FIXME: Support -meabi. @@ -577,6 +604,28 @@ void Clang::AddARMTargetArgs(const ArgList &Args, } else D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); } + + // Setting -msoft-float effectively disables NEON because of the GCC + // implementation, although the same isn't true of VFP or VFP3. + if (FloatABI == "soft") { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-neon"); + } + + // Kernel code has more strict alignment requirements. + if (KernelOrKext) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-long-calls"); + + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-strict-align"); + + // The kext linker doesn't know how to deal with movw/movt. +#ifndef DISABLE_ARM_DARWIN_USE_MOVT + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-darwin-use-movt=0"); +#endif + } } void Clang::AddMIPSTargetArgs(const ArgList &Args, @@ -726,12 +775,12 @@ void Clang::AddX86TargetArgs(const ArgList &Args, CPUName = "x86-64"; else if (getToolChain().getArchName() == "i386") CPUName = "i486"; - } else if (getToolChain().getOS().startswith("netbsd")) { + } else if (getToolChain().getOS().startswith("freebsd")) { if (getToolChain().getArchName() == "x86_64") CPUName = "x86-64"; else if (getToolChain().getArchName() == "i386") CPUName = "i486"; - } else if (getToolChain().getOS().startswith("freebsd")) { + } else if (getToolChain().getOS().startswith("netbsd")) { if (getToolChain().getArchName() == "x86_64") CPUName = "x86-64"; else if (getToolChain().getArchName() == "i386") @@ -767,34 +816,112 @@ void Clang::AddX86TargetArgs(const ArgList &Args, } } -static bool needsExceptions(const ArgList &Args, types::ID InputType, - const llvm::Triple &Triple) { - // Handle -fno-exceptions. +static bool +shouldUseExceptionTablesForObjCExceptions(const ArgList &Args, + const llvm::Triple &Triple) { + // We use the zero-cost exception tables for Objective-C if the non-fragile + // ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and + // later. + + if (Args.hasArg(options::OPT_fobjc_nonfragile_abi)) + return true; + + if (Triple.getOS() != llvm::Triple::Darwin) + return false; + + return (Triple.getDarwinMajorNumber() >= 9 && + (Triple.getArch() == llvm::Triple::x86_64 || + Triple.getArch() == llvm::Triple::arm)); +} + +/// addExceptionArgs - Adds exception related arguments to the driver command +/// arguments. There's a master flag, -fexceptions and also language specific +/// flags to enable/disable C++ and Objective-C exceptions. +/// This makes it possible to for example disable C++ exceptions but enable +/// Objective-C exceptions. +static void addExceptionArgs(const ArgList &Args, types::ID InputType, + const llvm::Triple &Triple, + bool KernelOrKext, bool IsRewriter, + ArgStringList &CmdArgs) { + if (KernelOrKext) + return; + + // Exceptions are enabled by default. + bool ExceptionsEnabled = true; + + // This keeps track of whether exceptions were explicitly turned on or off. + bool DidHaveExplicitExceptionFlag = false; + if (Arg *A = Args.getLastArg(options::OPT_fexceptions, options::OPT_fno_exceptions)) { if (A->getOption().matches(options::OPT_fexceptions)) - return true; - else - return false; + ExceptionsEnabled = true; + else + ExceptionsEnabled = false; + + DidHaveExplicitExceptionFlag = true; } - // Otherwise, C++ inputs use exceptions. - if (types::isCXX(InputType)) - return true; + bool ShouldUseExceptionTables = false; - // As do Objective-C non-fragile ABI inputs and all Objective-C inputs on - // x86_64 and ARM after SnowLeopard. - if (types::isObjC(InputType)) { - if (Args.hasArg(options::OPT_fobjc_nonfragile_abi)) - return true; - if (Triple.getOS() != llvm::Triple::Darwin) - return false; - return (Triple.getDarwinMajorNumber() >= 9 && - (Triple.getArch() == llvm::Triple::x86_64 || - Triple.getArch() == llvm::Triple::arm)); + // Exception tables and cleanups can be enabled with -fexceptions even if the + // language itself doesn't support exceptions. + if (ExceptionsEnabled && DidHaveExplicitExceptionFlag) + ShouldUseExceptionTables = true; + + // Obj-C exceptions are enabled by default, regardless of -fexceptions. This + // is not necessarily sensible, but follows GCC. + if (types::isObjC(InputType) && + Args.hasFlag(options::OPT_fobjc_exceptions, + options::OPT_fno_objc_exceptions, + true)) { + CmdArgs.push_back("-fobjc-exceptions"); + + ShouldUseExceptionTables |= + shouldUseExceptionTablesForObjCExceptions(Args, Triple); } - return false; + if (types::isCXX(InputType)) { + bool CXXExceptionsEnabled = ExceptionsEnabled; + + if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions, + options::OPT_fno_cxx_exceptions, + options::OPT_fexceptions, + options::OPT_fno_exceptions)) { + if (A->getOption().matches(options::OPT_fcxx_exceptions)) + CXXExceptionsEnabled = true; + else if (A->getOption().matches(options::OPT_fno_cxx_exceptions)) + CXXExceptionsEnabled = false; + } + + if (CXXExceptionsEnabled) { + CmdArgs.push_back("-fcxx-exceptions"); + + ShouldUseExceptionTables = true; + } + } + + if (ShouldUseExceptionTables) + CmdArgs.push_back("-fexceptions"); +} + +static bool ShouldDisableCFI(const ArgList &Args, + const ToolChain &TC) { + + // FIXME: Duplicated code with ToolChains.cpp + // FIXME: This doesn't belong here, but ideally we will support static soon + // anyway. + bool HasStatic = (Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_fapple_kext)); + bool IsIADefault = TC.IsIntegratedAssemblerDefault() && !HasStatic; + bool UseIntegratedAs = Args.hasFlag(options::OPT_integrated_as, + options::OPT_no_integrated_as, + IsIADefault); + bool UseCFI = Args.hasFlag(options::OPT_fdwarf2_cfi_asm, + options::OPT_fno_dwarf2_cfi_asm, + UseIntegratedAs); + return !UseCFI; } void Clang::ConstructJob(Compilation &C, const JobAction &JA, @@ -837,8 +964,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_O_Group)) IsOpt = !A->getOption().matches(options::OPT_O0); if (Args.hasFlag(options::OPT_mrelax_all, - options::OPT_mno_relax_all, - !IsOpt)) + options::OPT_mno_relax_all, + !IsOpt)) CmdArgs.push_back("-mrelax-all"); // When using an integrated assembler, translate -Wa, and -Xassembler @@ -855,10 +982,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Value == "-force_cpusubtype_ALL") { // Do nothing, this is the default and we don't support anything else. } else if (Value == "-L") { - // We don't support -L yet, but it isn't important enough to error - // on. No one should really be using it for a semantic change. - D.Diag(clang::diag::warn_drv_unsupported_option_argument) - << A->getOption().getName() << Value; + CmdArgs.push_back("-msave-temp-labels"); } else { D.Diag(clang::diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; @@ -925,29 +1049,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Treat blocks as analysis entry points. CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); + CmdArgs.push_back("-analyzer-eagerly-assume"); + // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { - types::ID InputType = Inputs[0].getType(); - - // Checks to perform for all language types. - CmdArgs.push_back("-analyzer-checker=core"); + CmdArgs.push_back("-analyzer-checker=deadcode"); + CmdArgs.push_back("-analyzer-checker=security"); + if (getToolChain().getTriple().getOS() != llvm::Triple::Win32) CmdArgs.push_back("-analyzer-checker=unix"); - if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple) - CmdArgs.push_back("-analyzer-checker=macosx"); - - // Checks to perform for Objective-C/Objective-C++. - if (types::isObjC(InputType)) { - // Enable all checkers in 'cocoa' package. - CmdArgs.push_back("-analyzer-checker=cocoa"); - } - // NOTE: Leaving -analyzer-check-objc-mem here is intentional. - // It also checks C code. - CmdArgs.push_back("-analyzer-check-objc-mem"); - - CmdArgs.push_back("-analyzer-eagerly-assume"); + if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple) + CmdArgs.push_back("-analyzer-checker=osx"); } // Set the output format. The default is plist, for (lame) historical @@ -1011,7 +1125,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } if (!Args.hasFlag(options::OPT_fmerge_all_constants, options::OPT_fno_merge_all_constants)) - CmdArgs.push_back("-no-merge-all-constants"); + CmdArgs.push_back("-fno-merge-all-constants"); // LLVM Code Generator Options. @@ -1020,6 +1134,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } + if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) + CmdArgs.push_back("-mrtd"); + // FIXME: Set --enable-unsafe-fp-math. if (Args.hasFlag(options::OPT_fno_omit_frame_pointer, options::OPT_fomit_frame_pointer)) @@ -1054,6 +1171,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (getToolChain().getTriple().getOS() != llvm::Triple::Darwin) CmdArgs.push_back("-mconstructor-aliases"); + // Darwin's kernel doesn't support guard variables; just die if we + // try to use them. + if (KernelOrKext && + getToolChain().getTriple().getOS() == llvm::Triple::Darwin) + CmdArgs.push_back("-fforbid-guard-variables"); + if (Args.hasArg(options::OPT_mms_bitfields)) { CmdArgs.push_back("-mms-bitfields"); } @@ -1090,7 +1213,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::arm: case llvm::Triple::thumb: - AddARMTargetArgs(Args, CmdArgs); + AddARMTargetArgs(Args, CmdArgs, KernelOrKext); break; case llvm::Triple::mips: @@ -1155,6 +1278,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); + if (D.CCLogDiagnostics) { + CmdArgs.push_back("-diagnostic-log-file"); + CmdArgs.push_back(D.CCLogDiagnosticsFilename ? + D.CCLogDiagnosticsFilename : "-"); + } + // Special case debug options to only pass -g to clang. This is // wrong. Args.ClaimAllArgs(options::OPT_g_Group); @@ -1167,6 +1296,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); + if (Args.hasArg(options::OPT_ftest_coverage) || + Args.hasArg(options::OPT_coverage)) + CmdArgs.push_back("-femit-coverage-notes"); + if (Args.hasArg(options::OPT_fprofile_arcs) || + Args.hasArg(options::OPT_coverage)) + CmdArgs.push_back("-femit-coverage-data"); + Args.AddLastArg(CmdArgs, options::OPT_nostdinc); Args.AddLastArg(CmdArgs, options::OPT_nostdincxx); Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); @@ -1192,10 +1328,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, else if (A->getOption().matches(options::OPT_O) && A->getValue(Args)[0] == '\0') CmdArgs.push_back("-O2"); - else if (A->getOption().matches(options::OPT_O) && - A->getValue(Args)[0] == 'z' && - A->getValue(Args)[1] == '\0') - CmdArgs.push_back("-Os"); else A->render(Args, CmdArgs); } @@ -1236,6 +1368,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_trigraphs); } + // Map the bizarre '-Wwrite-strings' flag to a more sensible + // '-fconst-strings'; this better indicates its actual behavior. + if (Args.hasFlag(options::OPT_Wwrite_strings, options::OPT_Wno_write_strings, + false)) { + // For perfect compatibility with GCC, we do this even in the presence of + // '-w'. This flag names something other than a warning for GCC. + CmdArgs.push_back("-fconst-strings"); + } + + // GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active + // during C++ compilation, which it is by default. GCC keeps this define even + // in the presence of '-w', match this behavior bug-for-bug. + if (types::isCXX(InputType) && + Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated, + true)) { + CmdArgs.push_back("-fdeprecated-macro"); + } + // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'. if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) { if (Asm->getOption().matches(options::OPT_fasm)) @@ -1244,6 +1394,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fno-gnu-keywords"); } + if (ShouldDisableCFI(Args, getToolChain())) + CmdArgs.push_back("-fno-dwarf2-cfi-asm"); + if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_)) { CmdArgs.push_back("-ftemplate-depth"); CmdArgs.push_back(A->getValue(Args)); @@ -1317,7 +1470,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fformat_extensions); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info); - Args.AddLastArg(CmdArgs, options::OPT_pg); + if (getToolChain().SupportsProfiling()) + Args.AddLastArg(CmdArgs, options::OPT_pg); // -flax-vector-conversions is default. if (!Args.hasFlag(options::OPT_flax_vector_conversions, @@ -1354,7 +1508,24 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } - Args.AddLastArg(CmdArgs, options::OPT_fwrapv); + // Forward -ftrap_function= options to the backend. + if (Arg *A = Args.getLastArg(options::OPT_ftrap_function_EQ)) { + llvm::StringRef FuncName = A->getValue(Args); + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back(Args.MakeArgString("-trap-func=" + FuncName)); + } + + // -fno-strict-overflow implies -fwrapv if it isn't disabled, but + // -fstrict-overflow won't turn off an explicitly enabled -fwrapv. + if (Arg *A = Args.getLastArg(options::OPT_fwrapv, + options::OPT_fno_wrapv)) { + if (A->getOption().matches(options::OPT_fwrapv)) + CmdArgs.push_back("-fwrapv"); + } else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow, + options::OPT_fno_strict_overflow)) { + if (A->getOption().matches(options::OPT_fno_strict_overflow)) + CmdArgs.push_back("-fwrapv"); + } Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); Args.AddLastArg(CmdArgs, options::OPT_funroll_loops); @@ -1395,7 +1566,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fblocks=0 is default. if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, - getToolChain().IsBlocksDefault())) { + getToolChain().IsBlocksDefault()) || + (Args.hasArg(options::OPT_fgnu_runtime) && + Args.hasArg(options::OPT_fobjc_nonfragile_abi) && + !Args.hasArg(options::OPT_fno_blocks))) { CmdArgs.push_back("-fblocks"); } @@ -1411,10 +1585,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, false)) CmdArgs.push_back("-fno-elide-constructors"); - // -fexceptions=0 is default. - if (!KernelOrKext && - needsExceptions(Args, InputType, getToolChain().getTriple())) - CmdArgs.push_back("-fexceptions"); + // Add exception args. + addExceptionArgs(Args, InputType, getToolChain().getTriple(), + KernelOrKext, IsRewriter, CmdArgs); if (getToolChain().UseSjLjExceptions()) CmdArgs.push_back("-fsjlj-exceptions"); @@ -1469,6 +1642,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_borland_extensions, false)) CmdArgs.push_back("-fborland-extensions"); + // -fno-delayed-template-parsing is default. + if (Args.hasFlag(options::OPT_fdelayed_template_parsing, + options::OPT_fno_delayed_template_parsing, + false)) + CmdArgs.push_back("-fdelayed-template-parsing"); + // -fgnu-keywords default varies depending on language; only pass if // specified. if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords, @@ -1545,17 +1724,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } + // FIXME: Don't expose -fobjc-default-synthesize-properties as a top-level + // driver flag yet. This feature is still under active development + // and shouldn't be exposed as a user visible feature (which may change). + // Clang still supports this as a -cc1 option for development and testing. +#if 0 // -fobjc-default-synthesize-properties=0 is default. if (Args.hasFlag(options::OPT_fobjc_default_synthesize_properties, options::OPT_fno_objc_default_synthesize_properties, getToolChain().IsObjCDefaultSynthPropertiesDefault())) { CmdArgs.push_back("-fobjc-default-synthesize-properties"); } - - // -fno-objc-exceptions is default. - if (IsRewriter || Args.hasFlag(options::OPT_fobjc_exceptions, - options::OPT_fno_objc_exceptions)) - CmdArgs.push_back("-fobjc-exceptions"); +#endif } if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, @@ -1619,6 +1799,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, options::OPT_fno_diagnostics_fixit_info)) CmdArgs.push_back("-fno-diagnostics-fixit-info"); + + // Enable -fdiagnostics-show-name by default. + if (Args.hasFlag(options::OPT_fdiagnostics_show_name, + options::OPT_fno_diagnostics_show_name, false)) + CmdArgs.push_back("-fdiagnostics-show-name"); // Enable -fdiagnostics-show-option by default. if (Args.hasFlag(options::OPT_fdiagnostics_show_option, @@ -1631,6 +1816,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } + if (Arg *A = Args.getLastArg( + options::OPT_fdiagnostics_show_note_include_stack, + options::OPT_fno_diagnostics_show_note_include_stack)) { + if (A->getOption().matches( + options::OPT_fdiagnostics_show_note_include_stack)) + CmdArgs.push_back("-fdiagnostics-show-note-include-stack"); + else + CmdArgs.push_back("-fno-diagnostics-show-note-include-stack"); + } + // Color diagnostics are the default, unless the terminal doesn't support // them. if (Args.hasFlag(options::OPT_fcolor_diagnostics, @@ -1686,9 +1881,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } #endif + // Only allow -traditional or -traditional-cpp outside in preprocessing modes. if (Arg *A = Args.getLastArg(options::OPT_traditional, - options::OPT_traditional_cpp)) - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + options::OPT_traditional_cpp)) { + if (isa<PreprocessJobAction>(JA)) + CmdArgs.push_back("-traditional-cpp"); + else + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + } Args.AddLastArg(CmdArgs, options::OPT_dM); Args.AddLastArg(CmdArgs, options::OPT_dD); @@ -1768,6 +1968,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // care to warn the user about. Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group); Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group); + + // Disable warnings for clang -E -use-gold-plugin -emit-llvm foo.c + Args.ClaimAllArgs(options::OPT_use_gold_plugin); + Args.ClaimAllArgs(options::OPT_emit_llvm); } void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, @@ -1782,6 +1986,10 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, // Don't warn about "clang -w -c foo.s" Args.ClaimAllArgs(options::OPT_w); + // and "clang -emit-llvm -c foo.s" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and "clang -use-gold-plugin -c foo.s" + Args.ClaimAllArgs(options::OPT_use_gold_plugin); // Invoke ourselves in -cc1as mode. // @@ -1807,7 +2015,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, !IsOpt)) CmdArgs.push_back("-relax-all"); - // FIXME: Add -force_cpusubtype_ALL support, once we have it. + // Ignore explicit -force_cpusubtype_ALL option. + (void) Args.hasArg(options::OPT_force__cpusubtype__ALL); // FIXME: Add -g support, once we have it. @@ -1815,6 +2024,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + Args.AddAllArgs(CmdArgs, options::OPT_mllvm); assert(Output.isFilename() && "Unexpected lipo output."); CmdArgs.push_back("-o"); @@ -1930,7 +2140,20 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, } } - const char *GCCName = getToolChain().getDriver().getCCCGenericGCCName().c_str(); + const std::string customGCCName = D.getCCCGenericGCCName(); + const char *GCCName; + if (!customGCCName.empty()) + GCCName = customGCCName.c_str(); + else if (D.CCCIsCXX) { +#ifdef IS_CYGWIN15 + // FIXME: Detect the version of Cygwin at runtime? + GCCName = "g++-4"; +#else + GCCName = "g++"; +#endif + } else + GCCName = "gcc"; + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); @@ -2044,10 +2267,6 @@ void darwin::CC1::AddCC1Args(const ArgList &Args, CmdArgs.push_back("-fno-builtin-strcpy"); } - // gcc has some code here to deal with when no -mmacosx-version-min - // and no -miphoneos-version-min is present, but this never happens - // due to tool chain specific argument translation. - if (Args.hasArg(options::OPT_g_Flag) && !Args.hasArg(options::OPT_fno_eliminate_unused_debug_symbols)) CmdArgs.push_back("-feliminate-unused-debug-symbols"); @@ -2111,7 +2330,8 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, if (Args.hasArg(options::OPT_v)) CmdArgs.push_back("-version"); - if (Args.hasArg(options::OPT_pg)) + if (Args.hasArg(options::OPT_pg) && + getToolChain().SupportsProfiling()) CmdArgs.push_back("-p"); Args.AddLastArg(CmdArgs, options::OPT_p); @@ -2134,6 +2354,9 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, } else Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only); + // Claim Clang only -f options, they aren't worth warning about. + Args.ClaimAllArgs(options::OPT_f_clang_Group); + Args.AddAllArgs(CmdArgs, options::OPT_undef); if (Args.hasArg(options::OPT_Qn)) CmdArgs.push_back("-fno-ident"); @@ -2191,6 +2414,9 @@ void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, // The driver treats -fsyntax-only specially. Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only); + // Claim Clang only -f options, they aren't worth warning about. + Args.ClaimAllArgs(options::OPT_f_clang_Group); + if (Args.hasArg(options::OPT_g_Group) && !Args.hasArg(options::OPT_g0) && !Args.hasArg(options::OPT_fno_working_directory)) CmdArgs.push_back("-fworking-directory"); @@ -2322,7 +2548,7 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA, OutputArgs.push_back("-o"); OutputArgs.push_back(Output.getFilename()); - if (Args.hasArg(options::OPT_E)) { + if (Args.hasArg(options::OPT_E) || getToolChain().getDriver().CCCIsCPP) { AddCPPOptionsArgs(Args, CmdArgs, Inputs, OutputArgs); } else { AddCPPOptionsArgs(Args, CmdArgs, Inputs, ArgStringList()); @@ -2442,11 +2668,16 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, assert(Inputs.size() == 1 && "Unexpected number of inputs."); const InputInfo &Input = Inputs[0]; - // Bit of a hack, this is only used for original inputs. - // - // FIXME: This is broken for preprocessed .s inputs. - if (Input.isFilename() && - strcmp(Input.getFilename(), Input.getBaseInput()) == 0) { + // Determine the original source input. + const Action *SourceAction = &JA; + while (SourceAction->getKind() != Action::InputClass) { + assert(!SourceAction->getInputs().empty() && "unexpected root action!"); + SourceAction = SourceAction->getInputs()[0]; + } + + // Forward -g, assuming we are dealing with an actual assembly file. + if (SourceAction->getType() == types::TY_Asm || + SourceAction->getType() == types::TY_PP_Asm) { if (Args.hasArg(options::OPT_gstabs)) CmdArgs.push_back("--gstabs"); else if (Args.hasArg(options::OPT_g_Group)) @@ -2502,6 +2733,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, const ArgList &Args, ArgStringList &CmdArgs) const { const Driver &D = getToolChain().getDriver(); + const toolchains::Darwin &DarwinTC = getDarwinToolChain(); unsigned Version[3] = { 0, 0, 0 }; if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { @@ -2521,7 +2753,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, // will match the linker version detected at configure time. We need the // universal driver. if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle) && - !getDarwinToolChain().isTargetIPhoneOS()) { + !DarwinTC.isTargetIPhoneOS()) { // Don't pass -demangle to ld_classic. // // FIXME: This is a temporary workaround, ld should be handling this. @@ -2596,7 +2828,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, Args.AddLastArg(CmdArgs, options::OPT_all__load); Args.AddAllArgs(CmdArgs, options::OPT_allowable__client); Args.AddLastArg(CmdArgs, options::OPT_bind__at__load); - if (getDarwinToolChain().isTargetIPhoneOS()) + if (DarwinTC.isTargetIPhoneOS()) Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal); Args.AddLastArg(CmdArgs, options::OPT_dead__strip); Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms); @@ -2608,15 +2840,27 @@ void darwin::Link::AddLinkArgs(Compilation &C, Args.AddAllArgs(CmdArgs, options::OPT_image__base); Args.AddAllArgs(CmdArgs, options::OPT_init); - // Adding all arguments doesn't make sense here but this is what gcc does. One - // of this should always be present thanks to argument translation. - assert((Args.hasArg(options::OPT_mmacosx_version_min_EQ) || - Args.hasArg(options::OPT_miphoneos_version_min_EQ)) && - "Missing version argument (lost in translation)?"); - Args.AddAllArgsTranslated(CmdArgs, options::OPT_mmacosx_version_min_EQ, - "-macosx_version_min"); - Args.AddAllArgsTranslated(CmdArgs, options::OPT_miphoneos_version_min_EQ, - "-iphoneos_version_min"); + // Add the deployment target. + unsigned TargetVersion[3]; + DarwinTC.getTargetVersion(TargetVersion); + + // If we had an explicit -mios-simulator-version-min argument, honor that, + // otherwise use the traditional deployment targets. We can't just check the + // is-sim attribute because existing code follows this path, and the linker + // may not handle the argument. + // + // FIXME: We may be able to remove this, once we can verify no one depends on + // it. + if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ)) + CmdArgs.push_back("-ios_simulator_version_min"); + else if (DarwinTC.isTargetIPhoneOS()) + CmdArgs.push_back("-iphoneos_version_min"); + else + CmdArgs.push_back("-macosx_version_min"); + CmdArgs.push_back(Args.MakeArgString(llvm::Twine(TargetVersion[0]) + "." + + llvm::Twine(TargetVersion[1]) + "." + + llvm::Twine(TargetVersion[2]))); + Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); Args.AddLastArg(CmdArgs, options::OPT_multi__module); Args.AddLastArg(CmdArgs, options::OPT_single__module); @@ -2722,7 +2966,10 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, // Derived from startfile spec. if (Args.hasArg(options::OPT_dynamiclib)) { // Derived from darwin_dylib1 spec. - if (getDarwinToolChain().isTargetIPhoneOS()) { + if (getDarwinToolChain().isTargetIOSSimulator()) { + // The simulator doesn't have a versioned crt1 file. + CmdArgs.push_back("-ldylib1.o"); + } else if (getDarwinToolChain().isTargetIPhoneOS()) { if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1)) CmdArgs.push_back("-ldylib1.o"); } else { @@ -2735,7 +2982,10 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_bundle)) { if (!Args.hasArg(options::OPT_static)) { // Derived from darwin_bundle1 spec. - if (getDarwinToolChain().isTargetIPhoneOS()) { + if (getDarwinToolChain().isTargetIOSSimulator()) { + // The simulator doesn't have a versioned crt1 file. + CmdArgs.push_back("-lbundle1.o"); + } else if (getDarwinToolChain().isTargetIPhoneOS()) { if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1)) CmdArgs.push_back("-lbundle1.o"); } else { @@ -2744,7 +2994,8 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, } } } else { - if (Args.hasArg(options::OPT_pg)) { + if (Args.hasArg(options::OPT_pg) && + getToolChain().SupportsProfiling()) { if (Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_object) || Args.hasArg(options::OPT_preload)) { @@ -2761,7 +3012,10 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lcrt0.o"); } else { // Derived from darwin_crt1 spec. - if (getDarwinToolChain().isTargetIPhoneOS()) { + if (getDarwinToolChain().isTargetIOSSimulator()) { + // The simulator doesn't have a versioned crt1 file. + CmdArgs.push_back("-lcrt1.o"); + } else if (getDarwinToolChain().isTargetIPhoneOS()) { if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1)) CmdArgs.push_back("-lcrt1.o"); else @@ -3156,6 +3410,9 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { @@ -3206,12 +3463,10 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, } Args.AddAllArgs(CmdArgs, options::OPT_L); - const ToolChain::path_list Paths = getToolChain().getFilePaths(); for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end(); i != e; ++i) CmdArgs.push_back(Args.MakeArgString(llvm::StringRef("-L") + *i)); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); Args.AddAllArgs(CmdArgs, options::OPT_s); @@ -3323,8 +3578,8 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); } - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("as")); + const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(), + "as")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -3336,6 +3591,9 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { @@ -3434,8 +3692,8 @@ void netbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, "crtn.o"))); } - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("ld")); + const char *Exec = Args.MakeArgString(FindTargetProgramPath(getToolChain(), + "ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -3487,14 +3745,14 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, // Silence warning for "clang -g foo.o -o foo" Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); // and for "clang -g foo.o -o foo". Other warning options are already // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); - if (Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) { - CmdArgs.push_back("--sysroot"); - CmdArgs.push_back(A->getValue(Args)); - } + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); if (Args.hasArg(options::OPT_pie)) CmdArgs.push_back("-pie"); @@ -3517,13 +3775,19 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-m"); if (ToolChain.getArch() == llvm::Triple::x86) CmdArgs.push_back("elf_i386"); - else if (ToolChain.getArch() == llvm::Triple::arm) + else if (ToolChain.getArch() == llvm::Triple::arm + || ToolChain.getArch() == llvm::Triple::thumb) CmdArgs.push_back("armelf_linux_eabi"); + else if (ToolChain.getArch() == llvm::Triple::ppc) + CmdArgs.push_back("elf32ppclinux"); + else if (ToolChain.getArch() == llvm::Triple::ppc64) + CmdArgs.push_back("elf64ppc"); else CmdArgs.push_back("elf_x86_64"); if (Args.hasArg(options::OPT_static)) { - if (ToolChain.getArch() == llvm::Triple::arm) + if (ToolChain.getArch() == llvm::Triple::arm + || ToolChain.getArch() == llvm::Triple::thumb) CmdArgs.push_back("-Bstatic"); else CmdArgs.push_back("-static"); @@ -3532,13 +3796,19 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, } if (ToolChain.getArch() == llvm::Triple::arm || + ToolChain.getArch() == llvm::Triple::thumb || (!Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_shared))) { CmdArgs.push_back("-dynamic-linker"); if (ToolChain.getArch() == llvm::Triple::x86) CmdArgs.push_back("/lib/ld-linux.so.2"); - else if (ToolChain.getArch() == llvm::Triple::arm) + else if (ToolChain.getArch() == llvm::Triple::arm || + ToolChain.getArch() == llvm::Triple::thumb) CmdArgs.push_back("/lib/ld-linux.so.3"); + else if (ToolChain.getArch() == llvm::Triple::ppc) + CmdArgs.push_back("/lib/ld.so.1"); + else if (ToolChain.getArch() == llvm::Triple::ppc64) + CmdArgs.push_back("/lib64/ld64.so.1"); else CmdArgs.push_back("/lib64/ld-linux-x86-64.so.2"); } @@ -3573,6 +3843,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); const ToolChain::path_list Paths = ToolChain.getFilePaths(); + for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end(); i != e; ++i) CmdArgs.push_back(Args.MakeArgString(llvm::StringRef("-L") + *i)); @@ -3770,6 +4041,9 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, const Driver &D = getToolChain().getDriver(); ArgStringList CmdArgs; + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { diff --git a/contrib/llvm/tools/clang/lib/Driver/Tools.h b/contrib/llvm/tools/clang/lib/Driver/Tools.h index 10c8839..93abf75 100644 --- a/contrib/llvm/tools/clang/lib/Driver/Tools.h +++ b/contrib/llvm/tools/clang/lib/Driver/Tools.h @@ -34,7 +34,8 @@ namespace tools { const InputInfo &Output, const InputInfoList &Inputs) const; - void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; + void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, + bool KernelOrKext) const; void AddMIPSTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; void AddSparcTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp index 92fb1e8..ecd6ef4 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTConsumers.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/ASTConsumers.h" -#include "clang/Frontend/DocumentXML.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" @@ -51,39 +50,6 @@ ASTConsumer *clang::CreateASTPrinter(llvm::raw_ostream* out) { return new ASTPrinter(out); } -//===----------------------------------------------------------------------===// -/// ASTPrinterXML - XML-printer of ASTs - -namespace { - class ASTPrinterXML : public ASTConsumer { - DocumentXML Doc; - - public: - ASTPrinterXML(llvm::raw_ostream& o) : Doc("CLANG_XML", o) {} - - void Initialize(ASTContext &Context) { - Doc.initialize(Context); - } - - virtual void HandleTranslationUnit(ASTContext &Ctx) { - Doc.addSubNode("TranslationUnit"); - for (DeclContext::decl_iterator - D = Ctx.getTranslationUnitDecl()->decls_begin(), - DEnd = Ctx.getTranslationUnitDecl()->decls_end(); - D != DEnd; - ++D) - Doc.PrintDecl(*D); - Doc.toParent(); - Doc.finalize(); - } - }; -} // end anonymous namespace - - -ASTConsumer *clang::CreateASTPrinterXML(llvm::raw_ostream* out) { - return new ASTPrinterXML(out ? *out : llvm::outs()); -} - ASTConsumer *clang::CreateASTDumper() { return new ASTPrinter(0, true); } @@ -369,8 +335,9 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC, Out << "<field> " << FD << '\n'; break; } - case Decl::Typedef: { - TypedefDecl* TD = cast<TypedefDecl>(*I); + case Decl::Typedef: + case Decl::TypeAlias: { + TypedefNameDecl* TD = cast<TypedefNameDecl>(*I); Out << "<typedef> " << TD << '\n'; break; } diff --git a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp index a7942e6..2a12448 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/ASTUnit.cpp @@ -20,6 +20,8 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Job.h" +#include "clang/Driver/ArgList.h" +#include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" @@ -34,6 +36,7 @@ #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/Support/Atomic.h" @@ -42,6 +45,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Timer.h" +#include "llvm/Support/CrashRecoveryContext.h" #include <cstdlib> #include <cstdio> #include <sys/stat.h> @@ -90,8 +94,10 @@ const unsigned DefaultPreambleRebuildInterval = 5; static llvm::sys::cas_flag ActiveASTUnitObjects; ASTUnit::ASTUnit(bool _MainFileIsAST) - : CaptureDiagnostics(false), MainFileIsAST(_MainFileIsAST), + : OnlyLocalDecls(false), CaptureDiagnostics(false), + MainFileIsAST(_MainFileIsAST), CompleteTranslationUnit(true), WantTiming(getenv("LIBCLANG_TIMING")), + OwnsRemappedFileBuffers(true), NumStoredDiagnosticsFromDriver(0), ConcurrencyCheckValue(CheckUnlocked), PreambleRebuildCounter(0), SavedMainFileBuffer(0), PreambleBuffer(0), @@ -116,7 +122,7 @@ ASTUnit::~ASTUnit() { // perform this operation here because we explicitly request that the // compiler instance *not* free these buffers for each invocation of the // parser. - if (Invocation.get()) { + if (Invocation.getPtr() && OwnsRemappedFileBuffers) { PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); for (PreprocessorOptions::remapped_file_buffer_iterator FB = PPOpts.remapped_file_buffer_begin(), @@ -496,33 +502,69 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, unsigned NumRemappedFiles, bool CaptureDiagnostics) { llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true)); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> + ASTUnitCleanup(AST.get()); + llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, + llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + DiagCleanup(Diags.getPtr()); + ConfigureDiags(Diags, 0, 0, *AST, CaptureDiagnostics); AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; AST->Diagnostics = Diags; - AST->FileMgr.reset(new FileManager(FileSystemOpts)); - AST->SourceMgr.reset(new SourceManager(AST->getDiagnostics(), - AST->getFileManager())); + AST->FileMgr = new FileManager(FileSystemOpts); + AST->SourceMgr = new SourceManager(AST->getDiagnostics(), + AST->getFileManager()); AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager())); for (unsigned I = 0; I != NumRemappedFiles; ++I) { - // Create the file entry for the file that we're mapping from. - const FileEntry *FromFile - = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, - RemappedFiles[I].second->getBufferSize(), - 0); - if (!FromFile) { - AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file) - << RemappedFiles[I].first; - delete RemappedFiles[I].second; - continue; + FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; + if (const llvm::MemoryBuffer * + memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile + = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, + memBuf->getBufferSize(), + 0); + if (!FromFile) { + AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file) + << RemappedFiles[I].first; + delete memBuf; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + AST->getSourceManager().overrideFileContents(FromFile, memBuf); + + } else { + const char *fname = fileOrBuf.get<const char *>(); + const FileEntry *ToFile = AST->FileMgr->getFile(fname); + if (!ToFile) { + AST->getDiagnostics().Report(diag::err_fe_remap_missing_to_file) + << RemappedFiles[I].first << fname; + continue; + } + + // Create the file entry for the file that we're mapping from. + const FileEntry *FromFile + = AST->getFileManager().getVirtualFile(RemappedFiles[I].first, + ToFile->getSize(), + 0); + if (!FromFile) { + AST->getDiagnostics().Report(diag::err_fe_remap_missing_from_file) + << RemappedFiles[I].first; + delete memBuf; + continue; + } + + // Override the contents of the "from" file with the contents of + // the "to" file. + AST->getSourceManager().overrideFileContents(FromFile, ToFile); } - - // Override the contents of the "from" file with the contents of - // the "to" file. - AST->getSourceManager().overrideFileContents(FromFile, - RemappedFiles[I].second); } // Gather Info for preprocessor construction later on. @@ -563,12 +605,11 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, TargetOpts.CPU = ""; TargetOpts.Features.clear(); TargetOpts.Triple = TargetTriple; - AST->Target.reset(TargetInfo::CreateTargetInfo(AST->getDiagnostics(), - TargetOpts)); - AST->PP.reset(new Preprocessor(AST->getDiagnostics(), LangInfo, - *AST->Target.get(), - AST->getSourceManager(), HeaderInfo)); - Preprocessor &PP = *AST->PP.get(); + AST->Target = TargetInfo::CreateTargetInfo(AST->getDiagnostics(), + TargetOpts); + AST->PP = new Preprocessor(AST->getDiagnostics(), LangInfo, *AST->Target, + AST->getSourceManager(), HeaderInfo); + Preprocessor &PP = *AST->PP; PP.setPredefines(Reader->getSuggestedPredefines()); PP.setCounterValue(Counter); @@ -576,14 +617,14 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, // Create and initialize the ASTContext. - AST->Ctx.reset(new ASTContext(LangInfo, - AST->getSourceManager(), - *AST->Target.get(), - PP.getIdentifierTable(), - PP.getSelectorTable(), - PP.getBuiltinInfo(), - /* size_reserve = */0)); - ASTContext &Context = *AST->Ctx.get(); + AST->Ctx = new ASTContext(LangInfo, + AST->getSourceManager(), + *AST->Target, + PP.getIdentifierTable(), + PP.getSelectorTable(), + PP.getBuiltinInfo(), + /* size_reserve = */0); + ASTContext &Context = *AST->Ctx; Reader->InitializeContext(Context); @@ -803,25 +844,30 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { delete SavedMainFileBuffer; SavedMainFileBuffer = 0; - if (!Invocation.get()) { + if (!Invocation) { delete OverrideMainBuffer; return true; } // Create the compiler instance to use for building the AST. - CompilerInstance Clang; - Clang.setInvocation(Invocation.take()); - OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; + llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> + CICleanup(Clang.get()); + + Clang->setInvocation(&*Invocation); + OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second; // Set up diagnostics, capturing any diagnostics that would // otherwise be dropped. - Clang.setDiagnostics(&getDiagnostics()); + Clang->setDiagnostics(&getDiagnostics()); // Create the target instance. - Clang.getTargetOpts().Features = TargetFeatures; - Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), - Clang.getTargetOpts())); - if (!Clang.hasTarget()) { + Clang->getTargetOpts().Features = TargetFeatures; + Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), + Clang->getTargetOpts())); + if (!Clang->hasTarget()) { delete OverrideMainBuffer; return true; } @@ -830,23 +876,23 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. - Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); + Clang->getTarget().setForcedLangOptions(Clang->getLangOpts()); - assert(Clang.getFrontendOpts().Inputs.size() == 1 && + assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST && "FIXME: AST inputs not yet supported here!"); - assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR && "IR inputs not support here!"); // Configure the various subsystems. // FIXME: Should we retain the previous file manager? - FileSystemOpts = Clang.getFileSystemOpts(); - FileMgr.reset(new FileManager(Clang.getFileSystemOpts())); - SourceMgr.reset(new SourceManager(getDiagnostics(), *FileMgr)); + FileSystemOpts = Clang->getFileSystemOpts(); + FileMgr = new FileManager(FileSystemOpts); + SourceMgr = new SourceManager(getDiagnostics(), *FileMgr); TheSema.reset(); - Ctx.reset(); - PP.reset(); + Ctx = 0; + PP = 0; // Clear out old caches and data. TopLevelDecls.clear(); @@ -863,14 +909,14 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { } // Create a file manager object to provide access to and cache the filesystem. - Clang.setFileManager(&getFileManager()); + Clang->setFileManager(&getFileManager()); // Create the source manager. - Clang.setSourceManager(&getSourceManager()); + Clang->setSourceManager(&getSourceManager()); // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. - PreprocessorOptions &PreprocessorOpts = Clang.getPreprocessorOpts(); + PreprocessorOptions &PreprocessorOpts = Clang->getPreprocessorOpts(); std::string PriorImplicitPCHInclude; if (OverrideMainBuffer) { PreprocessorOpts.addRemappedFile(OriginalSourceFile, OverrideMainBuffer); @@ -901,23 +947,27 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { PreprocessorOpts.PrecompiledPreambleBytes.second = false; } - llvm::OwningPtr<TopLevelDeclTrackerAction> Act; - Act.reset(new TopLevelDeclTrackerAction(*this)); - if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, - Clang.getFrontendOpts().Inputs[0].first)) + llvm::OwningPtr<TopLevelDeclTrackerAction> Act( + new TopLevelDeclTrackerAction(*this)); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<TopLevelDeclTrackerAction> + ActCleanup(Act.get()); + + if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second, + Clang->getFrontendOpts().Inputs[0].first)) goto error; Act->Execute(); - // Steal the created target, context, and preprocessor, and take back the - // source and file managers. - TheSema.reset(Clang.takeSema()); - Consumer.reset(Clang.takeASTConsumer()); - Ctx.reset(Clang.takeASTContext()); - PP.reset(Clang.takePreprocessor()); - Clang.takeSourceManager(); - Clang.takeFileManager(); - Target.reset(Clang.takeTarget()); + // Steal the created target, context, and preprocessor. + TheSema.reset(Clang->takeSema()); + Consumer.reset(Clang->takeASTConsumer()); + Ctx = &Clang->getASTContext(); + PP = &Clang->getPreprocessor(); + Clang->setSourceManager(0); + Clang->setFileManager(0); + Target = &Clang->getTarget(); Act->EndSourceFile(); @@ -928,9 +978,8 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { PreprocessorOpts.ImplicitPCHInclude = PriorImplicitPCHInclude; } - Invocation.reset(Clang.takeInvocation()); return false; - + error: // Remove the overridden buffer we used for the preamble. if (OverrideMainBuffer) { @@ -942,9 +991,6 @@ error: } StoredDiagnostics.clear(); - Clang.takeSourceManager(); - Clang.takeFileManager(); - Invocation.reset(Clang.takeInvocation()); return true; } @@ -1146,7 +1192,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( !AnyFileChanged && R != REnd; ++R) { struct stat StatBuf; - if (stat(R->second.c_str(), &StatBuf)) { + if (FileMgr->getNoncachedStatValue(R->second, StatBuf)) { // If we can't stat the file we're remapping to, assume that something // horrible happened. AnyFileChanged = true; @@ -1184,7 +1230,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // The file was not remapped; check whether it has changed on disk. struct stat StatBuf; - if (stat(F->first(), &StatBuf)) { + if (FileMgr->getNoncachedStatValue(F->first(), StatBuf)) { // If we can't stat the file, assume that something horrible happened. AnyFileChanged = true; } else if (StatBuf.st_size != F->second.first || @@ -1292,18 +1338,23 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( PreprocessorOpts.PrecompiledPreambleBytes.second = false; // Create the compiler instance to use for building the precompiled preamble. - CompilerInstance Clang; - Clang.setInvocation(&PreambleInvocation); - OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; + llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> + CICleanup(Clang.get()); + + Clang->setInvocation(&PreambleInvocation); + OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second; // Set up diagnostics, capturing all of the diagnostics produced. - Clang.setDiagnostics(&getDiagnostics()); + Clang->setDiagnostics(&getDiagnostics()); // Create the target instance. - Clang.getTargetOpts().Features = TargetFeatures; - Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), - Clang.getTargetOpts())); - if (!Clang.hasTarget()) { + Clang->getTargetOpts().Features = TargetFeatures; + Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), + Clang->getTargetOpts())); + if (!Clang->hasTarget()) { llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); Preamble.clear(); PreambleRebuildCounter = DefaultPreambleRebuildInterval; @@ -1316,18 +1367,18 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. - Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); + Clang->getTarget().setForcedLangOptions(Clang->getLangOpts()); - assert(Clang.getFrontendOpts().Inputs.size() == 1 && + assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST && "FIXME: AST inputs not yet supported here!"); - assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR && "IR inputs not support here!"); // Clear out old caches and data. getDiagnostics().Reset(); - ProcessWarningOptions(getDiagnostics(), Clang.getDiagnosticOpts()); + ProcessWarningOptions(getDiagnostics(), Clang->getDiagnosticOpts()); StoredDiagnostics.erase( StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver, StoredDiagnostics.end()); @@ -1337,17 +1388,16 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( PreprocessedEntitiesInPreamble.clear(); // Create a file manager object to provide access to and cache the filesystem. - Clang.setFileManager(new FileManager(Clang.getFileSystemOpts())); + Clang->setFileManager(new FileManager(Clang->getFileSystemOpts())); // Create the source manager. - Clang.setSourceManager(new SourceManager(getDiagnostics(), - Clang.getFileManager())); + Clang->setSourceManager(new SourceManager(getDiagnostics(), + Clang->getFileManager())); llvm::OwningPtr<PrecompilePreambleAction> Act; Act.reset(new PrecompilePreambleAction(*this)); - if (!Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, - Clang.getFrontendOpts().Inputs[0].first)) { - Clang.takeInvocation(); + if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second, + Clang->getFrontendOpts().Inputs[0].first)) { llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); Preamble.clear(); PreambleRebuildCounter = DefaultPreambleRebuildInterval; @@ -1358,8 +1408,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( Act->Execute(); Act->EndSourceFile(); - Clang.takeInvocation(); - + if (Diagnostics->hasErrorOccurred()) { // There were errors parsing the preamble, so no precompiled header was // generated. Forget that we even tried. @@ -1383,14 +1432,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Keep track of all of the files that the source manager knows about, // so we can verify whether they have changed or not. FilesInPreamble.clear(); - SourceManager &SourceMgr = Clang.getSourceManager(); + SourceManager &SourceMgr = Clang->getSourceManager(); const llvm::MemoryBuffer *MainFileBuffer = SourceMgr.getBuffer(SourceMgr.getMainFileID()); for (SourceManager::fileinfo_iterator F = SourceMgr.fileinfo_begin(), FEnd = SourceMgr.fileinfo_end(); F != FEnd; ++F) { - const FileEntry *File = F->second->Entry; + const FileEntry *File = F->second->OrigEntry; if (!File || F->second->getRawBuffer() == MainFileBuffer) continue; @@ -1491,6 +1540,20 @@ llvm::StringRef ASTUnit::getMainFileName() const { return Invocation->getFrontendOpts().Inputs[0].second; } +ASTUnit *ASTUnit::create(CompilerInvocation *CI, + llvm::IntrusiveRefCntPtr<Diagnostic> Diags) { + llvm::OwningPtr<ASTUnit> AST; + AST.reset(new ASTUnit(false)); + ConfigureDiags(Diags, 0, 0, *AST, /*CaptureDiagnostics=*/false); + AST->Diagnostics = Diags; + AST->Invocation = CI; + AST->FileSystemOpts = CI->getFileSystemOpts(); + AST->FileMgr = new FileManager(AST->FileSystemOpts); + AST->SourceMgr = new SourceManager(*Diags, *AST->FileMgr); + + return AST.take(); +} + bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { if (!Invocation) return true; @@ -1513,6 +1576,10 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { SimpleTimer ParsingTimer(WantTiming); ParsingTimer.setOutput("Parsing " + getMainFileName()); + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<llvm::MemoryBuffer> + MemBufferCleanup(OverrideMainBuffer); + return Parse(OverrideMainBuffer); } @@ -1532,8 +1599,15 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, AST->CaptureDiagnostics = CaptureDiagnostics; AST->CompleteTranslationUnit = CompleteTranslationUnit; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; - AST->Invocation.reset(CI); + AST->Invocation = CI; + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> + ASTUnitCleanup(AST.get()); + llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, + llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + DiagCleanup(Diags.getPtr()); + return AST->LoadFromCompilerInvocation(PrecompilePreamble)? 0 : AST.take(); } @@ -1545,6 +1619,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, bool CaptureDiagnostics, RemappedFile *RemappedFiles, unsigned NumRemappedFiles, + bool RemappedFilesKeepOriginalName, bool PrecompilePreamble, bool CompleteTranslationUnit, bool CacheCodeCompletionResults, @@ -1557,63 +1632,35 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd - ArgBegin, ArgBegin); } - - llvm::SmallVector<const char *, 16> Args; - Args.push_back("<clang>"); // FIXME: Remove dummy argument. - Args.insert(Args.end(), ArgBegin, ArgEnd); - - // FIXME: Find a cleaner way to force the driver into restricted modes. We - // also want to force it to use clang. - Args.push_back("-fsyntax-only"); llvm::SmallVector<StoredDiagnostic, 4> StoredDiagnostics; - llvm::OwningPtr<CompilerInvocation> CI; + llvm::IntrusiveRefCntPtr<CompilerInvocation> CI; { CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, StoredDiagnostics); - // FIXME: We shouldn't have to pass in the path info. - driver::Driver TheDriver("clang", llvm::sys::getHostTriple(), - "a.out", false, false, *Diags); - - // Don't check that inputs exist, they have been remapped. - TheDriver.setCheckInputsExist(false); - - llvm::OwningPtr<driver::Compilation> C( - TheDriver.BuildCompilation(Args.size(), Args.data())); - - // We expect to get back exactly one command job, if we didn't something - // failed. - const driver::JobList &Jobs = C->getJobs(); - if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) { - llvm::SmallString<256> Msg; - llvm::raw_svector_ostream OS(Msg); - C->PrintJob(OS, C->getJobs(), "; ", true); - Diags->Report(diag::err_fe_expected_compiler_job) << OS.str(); + CI = clang::createInvocationFromCommandLine( + llvm::ArrayRef<const char *>(ArgBegin, ArgEnd-ArgBegin), + Diags); + if (!CI) return 0; - } - - const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin()); - if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { - Diags->Report(diag::err_fe_expected_clang_command); - return 0; - } - - const driver::ArgStringList &CCArgs = Cmd->getArguments(); - CI.reset(new CompilerInvocation); - CompilerInvocation::CreateFromArgs(*CI, - const_cast<const char **>(CCArgs.data()), - const_cast<const char **>(CCArgs.data()) + - CCArgs.size(), - *Diags); } // Override any files that need remapping - for (unsigned I = 0; I != NumRemappedFiles; ++I) - CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, - RemappedFiles[I].second); + for (unsigned I = 0; I != NumRemappedFiles; ++I) { + FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; + if (const llvm::MemoryBuffer * + memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { + CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, memBuf); + } else { + const char *fname = fileOrBuf.get<const char *>(); + CI->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, fname); + } + } + CI->getPreprocessorOpts().RemappedFilesKeepOriginalName = + RemappedFilesKeepOriginalName; // Override the resources path. CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; @@ -1633,8 +1680,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, AST.reset(new ASTUnit(false)); ConfigureDiags(Diags, ArgBegin, ArgEnd, *AST, CaptureDiagnostics); AST->Diagnostics = Diags; - - AST->FileMgr.reset(new FileManager(FileSystemOptions())); + + AST->FileSystemOpts = CI->getFileSystemOpts(); + AST->FileMgr = new FileManager(AST->FileSystemOpts); AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; AST->CompleteTranslationUnit = CompleteTranslationUnit; @@ -1642,12 +1690,23 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); AST->NumStoredDiagnosticsInPreamble = StoredDiagnostics.size(); AST->StoredDiagnostics.swap(StoredDiagnostics); - AST->Invocation.reset(CI.take()); + AST->Invocation = CI; + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit> + ASTUnitCleanup(AST.get()); + llvm::CrashRecoveryContextCleanupRegistrar<CompilerInvocation, + llvm::CrashRecoveryContextReleaseRefCleanup<CompilerInvocation> > + CICleanup(CI.getPtr()); + llvm::CrashRecoveryContextCleanupRegistrar<Diagnostic, + llvm::CrashRecoveryContextReleaseRefCleanup<Diagnostic> > + DiagCleanup(Diags.getPtr()); + return AST->LoadFromCompilerInvocation(PrecompilePreamble) ? 0 : AST.take(); } bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { - if (!Invocation.get()) + if (!Invocation) return true; SimpleTimer ParsingTimer(WantTiming); @@ -1664,9 +1723,18 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { delete R->second; } Invocation->getPreprocessorOpts().clearRemappedFiles(); - for (unsigned I = 0; I != NumRemappedFiles; ++I) - Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, - RemappedFiles[I].second); + for (unsigned I = 0; I != NumRemappedFiles; ++I) { + FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; + if (const llvm::MemoryBuffer * + memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { + Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, + memBuf); + } else { + const char *fname = fileOrBuf.get<const char *>(); + Invocation->getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first, + fname); + } + } // If we have a preamble file lying around, or if we might try to // build a precompiled preamble, do so now. @@ -1934,16 +2002,18 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, SourceManager &SourceMgr, FileManager &FileMgr, llvm::SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, llvm::SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers) { - if (!Invocation.get()) + if (!Invocation) return; SimpleTimer CompletionTimer(WantTiming); CompletionTimer.setOutput("Code completion @ " + File + ":" + llvm::Twine(Line) + ":" + llvm::Twine(Column)); - CompilerInvocation CCInvocation(*Invocation); - FrontendOptions &FrontendOpts = CCInvocation.getFrontendOpts(); - PreprocessorOptions &PreprocessorOpts = CCInvocation.getPreprocessorOpts(); + llvm::IntrusiveRefCntPtr<CompilerInvocation> + CCInvocation(new CompilerInvocation(*Invocation)); + + FrontendOptions &FrontendOpts = CCInvocation->getFrontendOpts(); + PreprocessorOptions &PreprocessorOpts = CCInvocation->getPreprocessorOpts(); FrontendOpts.ShowMacrosInCodeCompletion = IncludeMacros && CachedCompletionResults.empty(); @@ -1955,25 +2025,30 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, FrontendOpts.CodeCompletionAt.Column = Column; // Set the language options appropriately. - LangOpts = CCInvocation.getLangOpts(); + LangOpts = CCInvocation->getLangOpts(); - CompilerInstance Clang; - Clang.setInvocation(&CCInvocation); - OriginalSourceFile = Clang.getFrontendOpts().Inputs[0].second; + llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance()); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<CompilerInstance> + CICleanup(Clang.get()); + + Clang->setInvocation(&*CCInvocation); + OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].second; // Set up diagnostics, capturing any diagnostics produced. - Clang.setDiagnostics(&Diag); - ProcessWarningOptions(Diag, CCInvocation.getDiagnosticOpts()); + Clang->setDiagnostics(&Diag); + ProcessWarningOptions(Diag, CCInvocation->getDiagnosticOpts()); CaptureDroppedDiagnostics Capture(true, - Clang.getDiagnostics(), + Clang->getDiagnostics(), StoredDiagnostics); // Create the target instance. - Clang.getTargetOpts().Features = TargetFeatures; - Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(), - Clang.getTargetOpts())); - if (!Clang.hasTarget()) { - Clang.takeInvocation(); + Clang->getTargetOpts().Features = TargetFeatures; + Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), + Clang->getTargetOpts())); + if (!Clang->hasTarget()) { + Clang->setInvocation(0); return; } @@ -1981,27 +2056,33 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. - Clang.getTarget().setForcedLangOptions(Clang.getLangOpts()); + Clang->getTarget().setForcedLangOptions(Clang->getLangOpts()); - assert(Clang.getFrontendOpts().Inputs.size() == 1 && + assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang.getFrontendOpts().Inputs[0].first != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].first != IK_AST && "FIXME: AST inputs not yet supported here!"); - assert(Clang.getFrontendOpts().Inputs[0].first != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].first != IK_LLVM_IR && "IR inputs not support here!"); // Use the source and file managers that we were given. - Clang.setFileManager(&FileMgr); - Clang.setSourceManager(&SourceMgr); + Clang->setFileManager(&FileMgr); + Clang->setSourceManager(&SourceMgr); // Remap files. PreprocessorOpts.clearRemappedFiles(); PreprocessorOpts.RetainRemappedFileBuffers = true; for (unsigned I = 0; I != NumRemappedFiles; ++I) { - PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, - RemappedFiles[I].second); - OwnedBuffers.push_back(RemappedFiles[I].second); + FilenameOrMemBuf fileOrBuf = RemappedFiles[I].second; + if (const llvm::MemoryBuffer * + memBuf = fileOrBuf.dyn_cast<const llvm::MemoryBuffer *>()) { + PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, memBuf); + OwnedBuffers.push_back(memBuf); + } else { + const char *fname = fileOrBuf.get<const char *>(); + PreprocessorOpts.addRemappedFile(RemappedFiles[I].first, fname); + } } // Use the code completion consumer we were given, but adding any cached @@ -2011,7 +2092,7 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, FrontendOpts.ShowMacrosInCodeCompletion, FrontendOpts.ShowCodePatternsInCodeCompletion, FrontendOpts.ShowGlobalSymbolsInCodeCompletion); - Clang.setCodeCompletionConsumer(AugmentedConsumer); + Clang->setCodeCompletionConsumer(AugmentedConsumer); // If we have a precompiled preamble, try to use it. We only allow // the use of the precompiled preamble if we're if the completion @@ -2026,7 +2107,7 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, if (const FileStatus *MainStatus = MainPath.getFileStatus()) if (CompleteFileStatus->getUniqueID() == MainStatus->getUniqueID()) OverrideMainBuffer - = getMainBufferWithPrecompiledPreamble(CCInvocation, false, + = getMainBufferWithPrecompiledPreamble(*CCInvocation, false, Line - 1); } @@ -2063,16 +2144,11 @@ void ASTUnit::CodeComplete(llvm::StringRef File, unsigned Line, unsigned Column, llvm::OwningPtr<SyntaxOnlyAction> Act; Act.reset(new SyntaxOnlyAction); - if (Act->BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second, - Clang.getFrontendOpts().Inputs[0].first)) { + if (Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0].second, + Clang->getFrontendOpts().Inputs[0].first)) { Act->Execute(); Act->EndSourceFile(); } - - // Steal back our resources. - Clang.takeFileManager(); - Clang.takeSourceManager(); - Clang.takeInvocation(); } bool ASTUnit::Save(llvm::StringRef File) { @@ -2086,7 +2162,16 @@ bool ASTUnit::Save(llvm::StringRef File) { llvm::raw_fd_ostream::F_Binary); if (!ErrorInfo.empty() || Out.has_error()) return true; - + + serialize(Out); + Out.close(); + return Out.has_error(); +} + +bool ASTUnit::serialize(llvm::raw_ostream &OS) { + if (getDiagnostics().hasErrorOccurred()) + return true; + std::vector<unsigned char> Buffer; llvm::BitstreamWriter Stream(Buffer); ASTWriter Writer(Stream); @@ -2094,7 +2179,7 @@ bool ASTUnit::Save(llvm::StringRef File) { // Write the generated bitstream to "Out". if (!Buffer.empty()) - Out.write((char *)&Buffer.front(), Buffer.size()); - Out.close(); - return Out.has_error(); + OS.write((char *)&Buffer.front(), Buffer.size()); + + return false; } diff --git a/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp b/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp index ee3fdd8..06a1fd2 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CacheTokens.cpp @@ -288,12 +288,12 @@ PTHEntry PTHWriter::LexTokens(Lexer& L) { if ((Tok.isAtStartOfLine() || Tok.is(tok::eof)) && ParsingPreprocessorDirective) { - // Insert an eom token into the token cache. It has the same + // Insert an eod token into the token cache. It has the same // position as the next token that is not on the same line as the // preprocessor directive. Observe that we continue processing // 'Tok' when we exit this branch. Token Tmp = Tok; - Tmp.setKind(tok::eom); + Tmp.setKind(tok::eod); Tmp.clearFlag(Token::StartOfLine); Tmp.setIdentifierInfo(0); EmitToken(Tmp); @@ -473,7 +473,7 @@ void PTHWriter::GeneratePTH(const std::string &MainFile) { for (SourceManager::fileinfo_iterator I = SM.fileinfo_begin(), E = SM.fileinfo_end(); I != E; ++I) { const SrcMgr::ContentCache &C = *I->second; - const FileEntry *FE = C.Entry; + const FileEntry *FE = C.OrigEntry; // FIXME: Handle files with non-absolute paths. if (llvm::sys::path::is_relative(FE->getName())) diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp index fd593de..ace3c5a 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp @@ -22,6 +22,7 @@ #include "clang/Frontend/ChainedDiagnosticClient.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/LogDiagnosticPrinter.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Frontend/VerifyDiagnosticsClient.h" #include "clang/Frontend/Utils.h" @@ -47,7 +48,7 @@ CompilerInstance::~CompilerInstance() { } void CompilerInstance::setInvocation(CompilerInvocation *Value) { - Invocation.reset(Value); + Invocation = Value; } void CompilerInstance::setDiagnostics(Diagnostic *Value) { @@ -55,24 +56,20 @@ void CompilerInstance::setDiagnostics(Diagnostic *Value) { } void CompilerInstance::setTarget(TargetInfo *Value) { - Target.reset(Value); + Target = Value; } void CompilerInstance::setFileManager(FileManager *Value) { - FileMgr.reset(Value); + FileMgr = Value; } -void CompilerInstance::setSourceManager(SourceManager *Value) { - SourceMgr.reset(Value); +void CompilerInstance::setSourceManager(SourceManager *Value) { + SourceMgr = Value; } -void CompilerInstance::setPreprocessor(Preprocessor *Value) { - PP.reset(Value); -} +void CompilerInstance::setPreprocessor(Preprocessor *Value) { PP = Value; } -void CompilerInstance::setASTContext(ASTContext *Value) { - Context.reset(Value); -} +void CompilerInstance::setASTContext(ASTContext *Value) { Context = Value; } void CompilerInstance::setSema(Sema *S) { TheSema.reset(S); @@ -110,15 +107,47 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger)); } +static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts, + const CodeGenOptions *CodeGenOpts, + Diagnostic &Diags) { + std::string ErrorInfo; + bool OwnsStream = false; + llvm::raw_ostream *OS = &llvm::errs(); + if (DiagOpts.DiagnosticLogFile != "-") { + // Create the output stream. + llvm::raw_fd_ostream *FileOS( + new llvm::raw_fd_ostream(DiagOpts.DiagnosticLogFile.c_str(), + ErrorInfo, llvm::raw_fd_ostream::F_Append)); + if (!ErrorInfo.empty()) { + Diags.Report(diag::warn_fe_cc_log_diagnostics_failure) + << DiagOpts.DumpBuildInformation << ErrorInfo; + } else { + FileOS->SetUnbuffered(); + FileOS->SetUseAtomicWrites(true); + OS = FileOS; + OwnsStream = true; + } + } + + // Chain in the diagnostic client which will log the diagnostics. + LogDiagnosticPrinter *Logger = new LogDiagnosticPrinter(*OS, DiagOpts, + OwnsStream); + if (CodeGenOpts) + Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags); + Diags.setClient(new ChainedDiagnosticClient(Diags.takeClient(), Logger)); +} + void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv, DiagnosticClient *Client) { - Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client); + Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client, + &getCodeGenOpts()); } llvm::IntrusiveRefCntPtr<Diagnostic> CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, int Argc, const char* const *Argv, - DiagnosticClient *Client) { + DiagnosticClient *Client, + const CodeGenOptions *CodeGenOpts) { llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID)); @@ -133,6 +162,10 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, if (Opts.VerifyDiagnostics) Diags->setClient(new VerifyDiagnosticsClient(*Diags, Diags->takeClient())); + // Chain in -diagnostic-log-file dumper, if requested. + if (!Opts.DiagnosticLogFile.empty()) + SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags); + if (!Opts.DumpBuildInformation.empty()) SetUpBuildDumpLog(Opts, Argc, Argv, *Diags); @@ -145,23 +178,23 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, // File Manager void CompilerInstance::createFileManager() { - FileMgr.reset(new FileManager(getFileSystemOpts())); + FileMgr = new FileManager(getFileSystemOpts()); } // Source Manager void CompilerInstance::createSourceManager(FileManager &FileMgr) { - SourceMgr.reset(new SourceManager(getDiagnostics(), FileMgr)); + SourceMgr = new SourceManager(getDiagnostics(), FileMgr); } // Preprocessor void CompilerInstance::createPreprocessor() { - PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(), - getPreprocessorOpts(), getHeaderSearchOpts(), - getDependencyOutputOpts(), getTarget(), - getFrontendOpts(), getSourceManager(), - getFileManager())); + PP = createPreprocessor(getDiagnostics(), getLangOpts(), + getPreprocessorOpts(), getHeaderSearchOpts(), + getDependencyOutputOpts(), getTarget(), + getFrontendOpts(), getSourceManager(), + getFileManager()); } Preprocessor * @@ -209,7 +242,8 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, llvm::StringRef OutputPath = DepOpts.HeaderIncludeOutputFile; if (OutputPath == "-") OutputPath = ""; - AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath); + AttachHeaderIncludeGen(*PP, /*ShowAllHeaders=*/true, OutputPath, + /*ShowDepth=*/false); } return PP; @@ -219,10 +253,10 @@ CompilerInstance::createPreprocessor(Diagnostic &Diags, void CompilerInstance::createASTContext() { Preprocessor &PP = getPreprocessor(); - Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(), - getTarget(), PP.getIdentifierTable(), - PP.getSelectorTable(), PP.getBuiltinInfo(), - /*size_reserve=*/ 0)); + Context = new ASTContext(getLangOpts(), PP.getSourceManager(), + getTarget(), PP.getIdentifierTable(), + PP.getSelectorTable(), PP.getBuiltinInfo(), + /*size_reserve=*/ 0); } // ExternalASTSource @@ -362,19 +396,22 @@ void CompilerInstance::clearOutputFiles(bool EraseFiles) { it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) { delete it->OS; if (!it->TempFilename.empty()) { - llvm::sys::Path TempPath(it->TempFilename); - if (EraseFiles) - TempPath.eraseFromDisk(); - else { - std::string Error; - llvm::sys::Path NewOutFile(it->Filename); + if (EraseFiles) { + bool existed; + llvm::sys::fs::remove(it->TempFilename, existed); + } else { + llvm::SmallString<128> NewOutFile(it->Filename); + // If '-working-directory' was passed, the output filename should be // relative to that. - FileManager::FixupRelativePath(NewOutFile, getFileSystemOpts()); - if (TempPath.renamePathOnDisk(NewOutFile, &Error)) { + FileMgr->FixupRelativePath(NewOutFile); + if (llvm::error_code ec = llvm::sys::fs::rename(it->TempFilename, + NewOutFile.str())) { getDiagnostics().Report(diag::err_fe_unable_to_rename_temp) - << it->TempFilename << it->Filename << Error; - TempPath.eraseFromDisk(); + << it->TempFilename << it->Filename << ec.message(); + + bool existed; + llvm::sys::fs::remove(it->TempFilename, existed); } } } else if (!it->Filename.empty() && EraseFiles) diff --git a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp index 4b44c48..495c6a8 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/CompilerInvocation.cpp @@ -30,16 +30,6 @@ #include "llvm/Support/Path.h" using namespace clang; -static const char *getAnalysisName(Analyses Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis kind!"); -#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\ - case NAME: return "-" CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - static const char *getAnalysisStoreName(AnalysisStores Kind) { switch (Kind) { default: @@ -76,8 +66,6 @@ static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, std::vector<std::string> &Res) { - for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i) - Res.push_back(getAnalysisName(Opts.AnalysisList[i])); if (Opts.ShowCheckerHelp) Res.push_back("-analyzer-checker-help"); if (Opts.AnalysisStoreOpt != BasicStoreModel) { @@ -102,8 +90,6 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-analyzer-display-progress"); if (Opts.AnalyzeNestedBlocks) Res.push_back("-analyzer-opt-analyze-nested-blocks"); - if (Opts.AnalyzerStats) - Res.push_back("-analyzer-stats"); if (Opts.EagerlyAssume) Res.push_back("-analyzer-eagerly-assume"); if (!Opts.PurgeDead) @@ -112,12 +98,8 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, Res.push_back("-trim-egraph"); if (Opts.VisualizeEGDot) Res.push_back("-analyzer-viz-egraph-graphviz"); - if (Opts.VisualizeEGDot) + if (Opts.VisualizeEGUbi) Res.push_back("-analyzer-viz-egraph-ubigraph"); - if (Opts.EnableExperimentalChecks) - Res.push_back("-analyzer-experimental-checks"); - if (Opts.BufferOverflows) - Res.push_back("-analyzer-check-buffer-overflows"); for (unsigned i = 0, e = Opts.CheckersControlList.size(); i != e; ++i) { const std::pair<std::string, bool> &opt = Opts.CheckersControlList[i]; @@ -141,17 +123,23 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, Res.push_back("-dwarf-debug-flags"); Res.push_back(Opts.DwarfDebugFlags); } + if (Opts.EmitGcovArcs) + Res.push_back("-femit-coverage-data"); + if (Opts.EmitGcovNotes) + Res.push_back("-femit-coverage-notes"); if (!Opts.MergeAllConstants) Res.push_back("-fno-merge-all-constants"); if (Opts.NoCommon) Res.push_back("-fno-common"); + if (Opts.ForbidGuardVariables) + Res.push_back("-fforbid-guard-variables"); if (Opts.NoImplicitFloat) Res.push_back("-no-implicit-float"); if (Opts.OmitLeafFramePointer) Res.push_back("-momit-leaf-frame-pointer"); if (Opts.OptimizeSize) { assert(Opts.OptimizationLevel == 2 && "Invalid options!"); - Res.push_back("-Os"); + Opts.OptimizeSize == 1 ? Res.push_back("-Os") : Res.push_back("-Oz"); } else if (Opts.OptimizationLevel != 0) Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel)); if (!Opts.MainFileName.empty()) { @@ -213,6 +201,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, } if (Opts.RelaxAll) Res.push_back("-mrelax-all"); + if (Opts.SaveTempLabels) + Res.push_back("-msave-temp-labels"); + if (Opts.NoDwarf2CFIAsm) + Res.push_back("-fno-dwarf2-cfi-asm"); if (Opts.SoftFloat) Res.push_back("-msoft-float"); if (Opts.UnwindTables) @@ -223,6 +215,10 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts, } if (!Opts.VerifyModule) Res.push_back("-disable-llvm-verifier"); + for (unsigned i = 0, e = Opts.BackendOptions.size(); i != e; ++i) { + Res.push_back("-backend-option"); + Res.push_back(Opts.BackendOptions[i]); + } } static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts, @@ -273,6 +269,8 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, Res.push_back("-fcolor-diagnostics"); if (Opts.VerifyDiagnostics) Res.push_back("-verify"); + if (Opts.ShowNames) + Res.push_back("-fdiagnostics-show-name"); if (Opts.ShowOptionNames) Res.push_back("-fdiagnostics-show-option"); if (Opts.ShowCategories == 1) @@ -283,6 +281,10 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, Res.push_back("-ferror-limit"); Res.push_back(llvm::utostr(Opts.ErrorLimit)); } + if (!Opts.DiagnosticLogFile.empty()) { + Res.push_back("-diagnostic-log-file"); + Res.push_back(Opts.DiagnosticLogFile); + } if (Opts.MacroBacktraceLimit != DiagnosticOptions::DefaultMacroBacktraceLimit) { Res.push_back("-fmacro-backtrace-limit"); @@ -340,7 +342,6 @@ static const char *getActionName(frontend::ActionKind Kind) { case frontend::ASTDump: return "-ast-dump"; case frontend::ASTDumpXML: return "-ast-dump-xml"; case frontend::ASTPrint: return "-ast-print"; - case frontend::ASTPrintXML: return "-ast-print-xml"; case frontend::ASTView: return "-ast-view"; case frontend::BoostCon: return "-boostcon"; case frontend::CreateModule: return "-create-module"; @@ -578,7 +579,7 @@ static void LangOptsToArgs(const LangOptions &Opts, if (Opts.WritableStrings) Res.push_back("-fwritable-strings"); if (Opts.ConstStrings) - Res.push_back("-Wwrite-strings"); + Res.push_back("-fconst-strings"); if (!Opts.LaxVectorConversions) Res.push_back("-fno-lax-vector-conversions"); if (Opts.AltiVec) @@ -591,6 +592,8 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fcxx-exceptions"); if (Opts.SjLjExceptions) Res.push_back("-fsjlj-exceptions"); + if (Opts.TraditionalCPP) + Res.push_back("-traditional-cpp"); if (!Opts.RTTI) Res.push_back("-fno-rtti"); if (Opts.MSBitfields) @@ -689,6 +692,14 @@ static void LangOptsToArgs(const LangOptions &Opts, Res.push_back("-fconstant-string-class"); Res.push_back(Opts.ObjCConstantStringClass); } + if (Opts.FakeAddressSpaceMap) + Res.push_back("-ffake-address-space-map"); + if (Opts.ParseUnknownAnytype) + Res.push_back("-funknown-anytype"); + if (Opts.DelayedTemplateParsing) + Res.push_back("-fdelayed-template-parsing"); + if (Opts.Deprecated) + Res.push_back("-fdeprecated-macro"); } static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, @@ -725,6 +736,10 @@ static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, assert(Opts.ImplicitPTHInclude == Opts.TokenCache && "Unsupported option combination!"); } + for (unsigned i = 0, e = Opts.ChainedIncludes.size(); i != e; ++i) { + Res.push_back("-chain-include"); + Res.push_back(Opts.ChainedIncludes[i]); + } for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) { Res.push_back("-remap-file"); Res.push_back(Opts.RemappedFiles[i].first + ";" + @@ -804,8 +819,8 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, unsigned DefaultOpt = 0; if (IK == IK_OpenCL && !Args.hasArg(OPT_cl_opt_disable)) DefaultOpt = 2; - // -Os implies -O2 - return Args.hasArg(OPT_Os) ? 2 : + // -Os/-Oz implies -O2 + return (Args.hasArg(OPT_Os) || Args.hasArg (OPT_Oz)) ? 2 : Args.getLastArgIntValue(OPT_O, DefaultOpt, Diags); } @@ -813,11 +828,6 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Diagnostic &Diags) { using namespace cc1options; - Opts.AnalysisList.clear(); -#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) \ - if (Args.hasArg(OPT_analysis_##NAME)) Opts.AnalysisList.push_back(NAME); -#include "clang/Frontend/Analyses.def" - if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { llvm::StringRef Name = A->getValue(Args); AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name) @@ -870,20 +880,17 @@ static void ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); Opts.AnalyzeNestedBlocks = Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks); - Opts.AnalyzerStats = Args.hasArg(OPT_analysis_AnalyzerStats); Opts.PurgeDead = !Args.hasArg(OPT_analyzer_no_purge_dead); Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function); Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG); Opts.CFGAddImplicitDtors = Args.hasArg(OPT_analysis_CFGAddImplicitDtors); Opts.CFGAddInitializers = Args.hasArg(OPT_analysis_CFGAddInitializers); - Opts.EnableExperimentalChecks = Args.hasArg(OPT_analyzer_experimental_checks); Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags); Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags); Opts.EagerlyTrimEGraph = !Args.hasArg(OPT_analyzer_no_eagerly_trim_egraph); Opts.InlineCall = Args.hasArg(OPT_analyzer_inline_call); - Opts.BufferOverflows = Args.hasArg(OPT_analysis_WarnBufferOverflows); Opts.CheckersControlList.clear(); for (arg_iterator it = Args.filtered_begin(OPT_analyzer_checker, @@ -921,12 +928,14 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.LimitDebugInfo = Args.hasArg(OPT_flimit_debug_info); Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); + Opts.ForbidGuardVariables = Args.hasArg(OPT_fforbid_guard_variables); Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); Opts.OptimizeSize = Args.hasArg(OPT_Os); + Opts.OptimizeSize = Args.hasArg(OPT_Oz) ? 2 : Opts.OptimizeSize; Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) || Args.hasArg(OPT_ffreestanding)); Opts.UnrollLoops = Args.hasArg(OPT_funroll_loops) || @@ -945,9 +954,12 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.NoInfsFPMath = Opts.NoNaNsFPMath = Args.hasArg(OPT_cl_finite_math_only)|| Args.hasArg(OPT_cl_fast_relaxed_math); Opts.NoZeroInitializedInBSS = Args.hasArg(OPT_mno_zero_initialized_in_bss); + Opts.BackendOptions = Args.getAllArgValues(OPT_backend_option); Opts.NumRegisterParameters = Args.getLastArgIntValue(OPT_mregparm, 0, Diags); Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.OmitLeafFramePointer = Args.hasArg(OPT_momit_leaf_frame_pointer); + Opts.SaveTempLabels = Args.hasArg(OPT_msave_temp_labels); + Opts.NoDwarf2CFIAsm = Args.hasArg(OPT_fno_dwarf2_cfi_asm); Opts.SoftFloat = Args.hasArg(OPT_msoft_float); Opts.UnsafeFPMath = Args.hasArg(OPT_cl_unsafe_math_optimizations) || Args.hasArg(OPT_cl_fast_relaxed_math); @@ -962,6 +974,8 @@ static void ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.InstrumentFunctions = Args.hasArg(OPT_finstrument_functions); Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); + Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); + Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes); if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { llvm::StringRef Name = A->getValue(Args); @@ -991,6 +1005,7 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Diagnostic &Diags) { using namespace cc1options; + Opts.DiagnosticLogFile = Args.getLastArgValue(OPT_diagnostic_log_file); Opts.IgnoreWarnings = Args.hasArg(OPT_w); Opts.NoRewriteMacros = Args.hasArg(OPT_Wno_rewrite_macros); Opts.Pedantic = Args.hasArg(OPT_pedantic); @@ -1000,8 +1015,16 @@ static void ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, Opts.ShowColumn = !Args.hasArg(OPT_fno_show_column); Opts.ShowFixits = !Args.hasArg(OPT_fno_diagnostics_fixit_info); Opts.ShowLocation = !Args.hasArg(OPT_fno_show_source_location); + Opts.ShowNames = Args.hasArg(OPT_fdiagnostics_show_name); Opts.ShowOptionNames = Args.hasArg(OPT_fdiagnostics_show_option); + // Default behavior is to not to show note include stacks. + Opts.ShowNoteIncludeStack = false; + if (Arg *A = Args.getLastArg(OPT_fdiagnostics_show_note_include_stack, + OPT_fno_diagnostics_show_note_include_stack)) + if (A->getOption().matches(OPT_fdiagnostics_show_note_include_stack)) + Opts.ShowNoteIncludeStack = true; + llvm::StringRef ShowOverloads = Args.getLastArgValue(OPT_fshow_overloads_EQ, "all"); if (ShowOverloads == "best") @@ -1067,8 +1090,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ProgramAction = frontend::ASTDumpXML; break; case OPT_ast_print: Opts.ProgramAction = frontend::ASTPrint; break; - case OPT_ast_print_xml: - Opts.ProgramAction = frontend::ASTPrintXML; break; case OPT_ast_view: Opts.ProgramAction = frontend::ASTView; break; case OPT_boostcon: @@ -1179,8 +1200,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, DashX = llvm::StringSwitch<InputKind>(A->getValue(Args)) .Case("c", IK_C) .Case("cl", IK_OpenCL) - .Case("c", IK_C) - .Case("cl", IK_OpenCL) .Case("cuda", IK_CUDA) .Case("c++", IK_CXX) .Case("objective-c", IK_ObjC) @@ -1189,6 +1208,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Case("assembler-with-cpp", IK_Asm) .Case("c++-cpp-output", IK_PreprocessedCXX) .Case("objective-c-cpp-output", IK_PreprocessedObjC) + .Case("objc-cpp-output", IK_PreprocessedObjC) .Case("objective-c++-cpp-output", IK_PreprocessedObjCXX) .Case("c-header", IK_C) .Case("objective-c-header", IK_ObjC) @@ -1288,7 +1308,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, LangStandard::Kind LangStd) { - // Set some properties which depend soley on the input kind; it would be nice + // Set some properties which depend solely on the input kind; it would be nice // to move these to the language standard, and have the driver resolve the // input kind + language standard. if (IK == IK_Asm) { @@ -1332,6 +1352,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); Opts.BCPLComment = Std.hasBCPLComments(); Opts.C99 = Std.isC99(); + Opts.C1X = Std.isC1X(); Opts.CPlusPlus = Std.isCPlusPlus(); Opts.CPlusPlus0x = Std.isCPlusPlus0x(); Opts.Digraphs = Std.hasDigraphs(); @@ -1423,6 +1444,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Args.hasArg(OPT_pthread)) Opts.POSIXThreads = 1; + if (Args.hasArg(OPT_fdelayed_template_parsing)) + Opts.DelayedTemplateParsing = 1; + llvm::StringRef Vis = Args.getLastArgValue(OPT_fvisibility, "default"); if (Vis == "default") Opts.setVisibilityMode(DefaultVisibility); @@ -1457,7 +1481,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.MSCVersion = Args.getLastArgIntValue(OPT_fmsc_version, 0, Diags); Opts.Borland = Args.hasArg(OPT_fborland_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); - Opts.ConstStrings = Args.hasArg(OPT_Wwrite_strings); + Opts.ConstStrings = Args.hasFlag(OPT_fconst_strings, OPT_fno_const_strings, + Opts.ConstStrings); if (Args.hasArg(OPT_fno_lax_vector_conversions)) Opts.LaxVectorConversions = 0; if (Args.hasArg(OPT_fno_threadsafe_statics)) @@ -1466,6 +1491,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.ObjCExceptions = Args.hasArg(OPT_fobjc_exceptions); Opts.CXXExceptions = Args.hasArg(OPT_fcxx_exceptions); Opts.SjLjExceptions = Args.hasArg(OPT_fsjlj_exceptions); + Opts.TraditionalCPP = Args.hasArg(OPT_traditional_cpp); Opts.RTTI = !Args.hasArg(OPT_fno_rtti); Opts.Blocks = Args.hasArg(OPT_fblocks); @@ -1482,6 +1508,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.MathErrno = Args.hasArg(OPT_fmath_errno); Opts.InstantiationDepth = Args.getLastArgIntValue(OPT_ftemplate_depth, 1024, Diags); + Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing); Opts.NumLargeByValueCopy = Args.getLastArgIntValue(OPT_Wlarge_by_value_copy, 0, Diags); Opts.MSBitfields = Args.hasArg(OPT_mms_bitfields); @@ -1504,6 +1531,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.SinglePrecisionConstants = Args.hasArg(OPT_cl_single_precision_constant); Opts.FastRelaxedMath = Args.hasArg(OPT_cl_fast_relaxed_math); Opts.OptimizeSize = 0; + Opts.MRTD = Args.hasArg(OPT_mrtd); + Opts.FakeAddressSpaceMap = Args.hasArg(OPT_ffake_address_space_map); + Opts.ParseUnknownAnytype = Args.hasArg(OPT_funknown_anytype); + + // Record whether the __DEPRECATED define was requested. + Opts.Deprecated = Args.hasFlag(OPT_fdeprecated_macro, + OPT_fno_deprecated_macro, + Opts.Deprecated); // FIXME: Eliminate this dependency. unsigned Opt = getOptimizationLevel(Args, IK, Diags); @@ -1593,6 +1628,12 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.Includes.push_back(A->getValue(Args)); } + for (arg_iterator it = Args.filtered_begin(OPT_chain_include), + ie = Args.filtered_end(); it != ie; ++it) { + const Arg *A = *it; + Opts.ChainedIncludes.push_back(A->getValue(Args)); + } + // Include 'altivec.h' if -faltivec option present if (Args.hasArg(OPT_faltivec)) Opts.Includes.push_back("altivec.h"); diff --git a/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp new file mode 100644 index 0000000..0005f91 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -0,0 +1,90 @@ +//===--- CreateInvocationFromCommandLine.cpp - CompilerInvocation from Args ==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Construct a compiler invocation object for command line driver arguments +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/Utils.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/ArgList.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/Tool.h" +#include "llvm/Support/Host.h" +using namespace clang; + +/// createInvocationFromCommandLine - Construct a compiler invocation object for +/// a command line argument vector. +/// +/// \return A CompilerInvocation, or 0 if none was built for the given +/// argument vector. +CompilerInvocation * +clang::createInvocationFromCommandLine(llvm::ArrayRef<const char *> ArgList, + llvm::IntrusiveRefCntPtr<Diagnostic> Diags) { + if (!Diags.getPtr()) { + // No diagnostics engine was provided, so create our own diagnostics object + // with the default options. + DiagnosticOptions DiagOpts; + Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgList.size(), + ArgList.begin()); + } + + llvm::SmallVector<const char *, 16> Args; + Args.push_back("<clang>"); // FIXME: Remove dummy argument. + Args.insert(Args.end(), ArgList.begin(), ArgList.end()); + + // FIXME: Find a cleaner way to force the driver into restricted modes. We + // also want to force it to use clang. + Args.push_back("-fsyntax-only"); + + // FIXME: We shouldn't have to pass in the path info. + driver::Driver TheDriver("clang", llvm::sys::getHostTriple(), + "a.out", false, false, *Diags); + + // Don't check that inputs exist, they may have been remapped. + TheDriver.setCheckInputsExist(false); + + llvm::OwningPtr<driver::Compilation> C(TheDriver.BuildCompilation(Args)); + + // Just print the cc1 options if -### was present. + if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) { + C->PrintJob(llvm::errs(), C->getJobs(), "\n", true); + return 0; + } + + // We expect to get back exactly one command job, if we didn't something + // failed. + const driver::JobList &Jobs = C->getJobs(); + if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) { + llvm::SmallString<256> Msg; + llvm::raw_svector_ostream OS(Msg); + C->PrintJob(OS, C->getJobs(), "; ", true); + Diags->Report(diag::err_fe_expected_compiler_job) << OS.str(); + return 0; + } + + const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin()); + if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { + Diags->Report(diag::err_fe_expected_clang_command); + return 0; + } + + const driver::ArgStringList &CCArgs = Cmd->getArguments(); + CompilerInvocation *CI = new CompilerInvocation(); + CompilerInvocation::CreateFromArgs(*CI, + const_cast<const char **>(CCArgs.data()), + const_cast<const char **>(CCArgs.data()) + + CCArgs.size(), + *Diags); + return CI; +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/DeclXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/DeclXML.cpp deleted file mode 100644 index 8d3d225..0000000 --- a/contrib/llvm/tools/clang/lib/Frontend/DeclXML.cpp +++ /dev/null @@ -1,183 +0,0 @@ -//===--- DeclXML.cpp - XML implementation for Decl ASTs -------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the XML document class, which provides the means to -// dump out the AST in a XML form that exposes type details and other fields. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/DocumentXML.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/Expr.h" - -namespace clang { - -//--------------------------------------------------------- -class DocumentXML::DeclPrinter : public DeclVisitor<DocumentXML::DeclPrinter> { - DocumentXML& Doc; - - void addSubNodes(FunctionDecl* FD) { - for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) { - Visit(FD->getParamDecl(i)); - Doc.toParent(); - } - } - - void addFunctionBody(FunctionDecl* FD) { - if (FD->isThisDeclarationADefinition()) { - Doc.addSubNode("Body"); - Doc.PrintStmt(FD->getBody()); - Doc.toParent(); - } - } - - void addSubNodes(RecordDecl* RD) { - for (RecordDecl::decl_iterator i = RD->decls_begin(), - e = RD->decls_end(); i != e; ++i) { - if (!(*i)->isImplicit()) { - Visit(*i); - Doc.toParent(); - } - } - } - - void addSubNodes(CXXRecordDecl* RD) { - addSubNodes(cast<RecordDecl>(RD)); - - if (RD->isDefinition()) { - // FIXME: This breaks XML generation - //Doc.addAttribute("num_bases", RD->getNumBases()); - - for (CXXRecordDecl::base_class_iterator - base = RD->bases_begin(), - bend = RD->bases_end(); - base != bend; - ++base) { - Doc.addSubNode("Base"); - Doc.addAttribute("id", base->getType()); - AccessSpecifier as = base->getAccessSpecifierAsWritten(); - const char* as_name = ""; - switch(as) { - case AS_none: as_name = ""; break; - case AS_public: as_name = "public"; break; - case AS_protected: as_name = "protected"; break; - case AS_private: as_name = "private"; break; - } - Doc.addAttributeOptional("access", as_name); - Doc.addAttribute("is_virtual", base->isVirtual()); - Doc.toParent(); - } - } - } - - void addSubNodes(EnumDecl* ED) { - for (EnumDecl::enumerator_iterator i = ED->enumerator_begin(), - e = ED->enumerator_end(); i != e; ++i) { - Visit(*i); - Doc.toParent(); - } - } - - void addSubNodes(EnumConstantDecl* ECD) { - if (ECD->getInitExpr()) - Doc.PrintStmt(ECD->getInitExpr()); - } - - void addSubNodes(FieldDecl* FdD) { - if (FdD->isBitField()) - Doc.PrintStmt(FdD->getBitWidth()); - } - - void addSubNodes(VarDecl* V) { - if (V->getInit()) - Doc.PrintStmt(V->getInit()); - } - - void addSubNodes(ParmVarDecl* argDecl) { - if (argDecl->getDefaultArg()) - Doc.PrintStmt(argDecl->getDefaultArg()); - } - - void addSubNodes(DeclContext* ns) { - - for (DeclContext::decl_iterator - d = ns->decls_begin(), - dend = ns->decls_end(); - d != dend; - ++d) { - Visit(*d); - Doc.toParent(); - } - } - - void addSpecialAttribute(const char* pName, EnumDecl* ED) { - const QualType& enumType = ED->getIntegerType(); - if (!enumType.isNull()) - Doc.addAttribute(pName, enumType); - } - - void addIdAttribute(LinkageSpecDecl* ED) { - Doc.addAttribute("id", ED); - } - - void addIdAttribute(NamedDecl* ND) { - Doc.addAttribute("id", ND); - } - -public: - DeclPrinter(DocumentXML& doc) : Doc(doc) {} - -#define NODE_XML( CLASS, NAME ) \ - void Visit##CLASS(CLASS* T) \ - { \ - Doc.addSubNode(NAME); - -#define ID_ATTRIBUTE_XML addIdAttribute(T); -#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN); -#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN); -#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocation(T->getLocation()); -#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, T); - -#define ATTRIBUTE_ENUM_XML( FN, NAME ) \ - { \ - const char* pAttributeName = NAME; \ - const bool optional = false; \ - switch (T->FN) { \ - default: assert(0 && "unknown enum value"); - -#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ - { \ - const char* pAttributeName = NAME; \ - const bool optional = true; \ - switch (T->FN) { \ - default: assert(0 && "unknown enum value"); - -#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; -#define END_ENUM_XML } } -#define END_NODE_XML } - -#define SUB_NODE_XML( CLASS ) addSubNodes(T); -#define SUB_NODE_SEQUENCE_XML( CLASS ) addSubNodes(T); -#define SUB_NODE_OPT_XML( CLASS ) addSubNodes(T); - -#define SUB_NODE_FN_BODY_XML addFunctionBody(T); - -#include "clang/Frontend/DeclXML.def" -}; - - -//--------------------------------------------------------- -void DocumentXML::writeDeclToXML(Decl *D) { - DeclPrinter(*this).Visit(D); - toParent(); -} - -//--------------------------------------------------------- -} // NS clang - diff --git a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp index bc5a55d..5c3a231 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/DependencyFile.cpp @@ -171,7 +171,7 @@ void DependencyFileCallback::OutputDependencyFile() { *OS << '\n'; // Create phony targets if requested. - if (PhonyTarget) { + if (PhonyTarget && !Files.empty()) { // Skip the first entry, this is always the input file itself. for (std::vector<std::string>::iterator I = Files.begin() + 1, E = Files.end(); I != E; ++I) { diff --git a/contrib/llvm/tools/clang/lib/Frontend/DocumentXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/DocumentXML.cpp deleted file mode 100644 index a09db0b..0000000 --- a/contrib/llvm/tools/clang/lib/Frontend/DocumentXML.cpp +++ /dev/null @@ -1,381 +0,0 @@ -//===--- DocumentXML.cpp - XML document for ASTs --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the XML document class, which provides the means to -// dump out the AST in a XML form that exposes type details and other fields. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/DocumentXML.h" -#include "clang/AST/Decl.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/ASTContext.h" -#include "clang/Basic/SourceManager.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Config/config.h" -#include <cstdio> - -namespace clang { - -//--------------------------------------------------------- -DocumentXML::DocumentXML(const std::string& rootName, llvm::raw_ostream& out) : - Out(out), - Ctx(0), - HasCurrentNodeSubNodes(false) { - NodeStack.push(rootName); - Out << "<?xml version=\"1.0\"?>\n<" << rootName; -} - -//--------------------------------------------------------- -DocumentXML& DocumentXML::addSubNode(const std::string& name) { - if (!HasCurrentNodeSubNodes) - Out << ">\n"; - NodeStack.push(name); - HasCurrentNodeSubNodes = false; - Indent(); - Out << "<" << NodeStack.top(); - return *this; -} - -//--------------------------------------------------------- -void DocumentXML::Indent() { - for (size_t i = 0, e = (NodeStack.size() - 1) * 2; i < e; ++i) - Out << ' '; -} - -//--------------------------------------------------------- -DocumentXML& DocumentXML::toParent() { - assert(NodeStack.size() > 1 && "too much backtracking"); - - if (HasCurrentNodeSubNodes) { - Indent(); - Out << "</" << NodeStack.top() << ">\n"; - } else - Out << "/>\n"; - NodeStack.pop(); - HasCurrentNodeSubNodes = true; - return *this; -} - -//--------------------------------------------------------- -namespace { - -enum tIdType { ID_NORMAL, ID_FILE, ID_LABEL, ID_LAST }; - -unsigned getNewId(tIdType idType) { - static unsigned int idCounts[ID_LAST] = { 0 }; - return ++idCounts[idType]; -} - -//--------------------------------------------------------- -inline std::string getPrefixedId(unsigned uId, tIdType idType) { - static const char idPrefix[ID_LAST] = { '_', 'f', 'l' }; - char buffer[20]; - char* BufPtr = llvm::utohex_buffer(uId, buffer + 20); - *--BufPtr = idPrefix[idType]; - return BufPtr; -} - -//--------------------------------------------------------- -template<class T, class V> -bool addToMap(T& idMap, const V& value, tIdType idType = ID_NORMAL) { - typename T::iterator i = idMap.find(value); - bool toAdd = i == idMap.end(); - if (toAdd) - idMap.insert(typename T::value_type(value, getNewId(idType))); - return toAdd; -} - -} // anon NS - - -//--------------------------------------------------------- -std::string DocumentXML::escapeString(const char* pStr, - std::string::size_type len) { - std::string value; - value.reserve(len + 1); - char buffer[16]; - for (unsigned i = 0; i < len; ++i) { - switch (char C = pStr[i]) { - default: - if (isprint(C)) - value += C; - else { -#ifdef LLVM_ON_WIN32 - sprintf(buffer, "\\%03o", C); -#else - snprintf(buffer, sizeof(buffer), "\\%03o", C); -#endif - value += buffer; - } - break; - - case '\n': value += "\\n"; break; - case '\t': value += "\\t"; break; - case '\a': value += "\\a"; break; - case '\b': value += "\\b"; break; - case '\r': value += "\\r"; break; - - case '&': value += "&"; break; - case '<': value += "<"; break; - case '>': value += ">"; break; - case '"': value += """; break; - case '\'': value += "'"; break; - - } - } - return value; -} - -//--------------------------------------------------------- -void DocumentXML::finalize() { - assert(NodeStack.size() == 1 && "not completely backtracked"); - - addSubNode("ReferenceSection"); - addSubNode("Types"); - - for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end(); - i != e; ++i) { - if (i->first.hasLocalQualifiers()) { - writeTypeToXML(i->first); - addAttribute("id", getPrefixedId(i->second, ID_NORMAL)); - toParent(); - } - } - - for (XML::IdMap<const Type*>::iterator i = BasicTypes.begin(), - e = BasicTypes.end(); i != e; ++i) { - writeTypeToXML(i->first); - addAttribute("id", getPrefixedId(i->second, ID_NORMAL)); - toParent(); - } - - - toParent().addSubNode("Contexts"); - - for (XML::IdMap<const DeclContext*>::iterator i = Contexts.begin(), - e = Contexts.end(); i != e; ++i) { - addSubNode(i->first->getDeclKindName()); - addAttribute("id", getPrefixedId(i->second, ID_NORMAL)); - if (const NamedDecl *ND = dyn_cast<NamedDecl>(i->first)) - addAttribute("name", ND->getNameAsString()); - if (const TagDecl *TD = dyn_cast<TagDecl>(i->first)) - addAttribute("type", getPrefixedId(BasicTypes[TD->getTypeForDecl()], ID_NORMAL)); - else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(i->first)) - addAttribute("type", getPrefixedId(BasicTypes[FD->getType()->getAs<FunctionType>()], ID_NORMAL)); - - if (const DeclContext* parent = i->first->getParent()) - addAttribute("context", parent); - toParent(); - } - - toParent().addSubNode("Files"); - - for (XML::IdMap<std::string>::iterator i = SourceFiles.begin(), - e = SourceFiles.end(); i != e; ++i) { - addSubNode("File"); - addAttribute("id", getPrefixedId(i->second, ID_FILE)); - addAttribute("name", escapeString(i->first.c_str(), i->first.size())); - toParent(); - } - - toParent().toParent(); - - // write the root closing node (which has always subnodes) - Out << "</" << NodeStack.top() << ">\n"; -} - -//--------------------------------------------------------- -void DocumentXML::addAttribute(const char* pAttributeName, - const QualType& pType) { - addTypeRecursively(pType); - addAttribute(pAttributeName, getPrefixedId(Types[pType], ID_NORMAL)); -} - -//--------------------------------------------------------- -void DocumentXML::addPtrAttribute(const char* pAttributeName, - const Type* pType) { - addTypeRecursively(pType); - addAttribute(pAttributeName, getPrefixedId(BasicTypes[pType], ID_NORMAL)); -} - -//--------------------------------------------------------- -void DocumentXML::addPtrAttribute(const char* pAttributeName, - const NestedNameSpecifier* pNNS) { - switch (pNNS->getKind()) { - case NestedNameSpecifier::Identifier: { - IdentifierInfo *ii = pNNS->getAsIdentifier(); - // FIXME how should we handle those ? - addPtrAttribute(pAttributeName, ii->getName().data()); - break; - } - case NestedNameSpecifier::Namespace: { - addPtrAttribute(pAttributeName, pNNS->getAsNamespace()); - break; - } - case NestedNameSpecifier::NamespaceAlias: { - addPtrAttribute(pAttributeName, pNNS->getAsNamespaceAlias()); - break; - } - case NestedNameSpecifier::TypeSpec: { - addPtrAttribute(pAttributeName, pNNS->getAsType()); - break; - } - case NestedNameSpecifier::TypeSpecWithTemplate: { - addPtrAttribute(pAttributeName, pNNS->getAsType()); - break; - } - case NestedNameSpecifier::Global: { - addPtrAttribute(pAttributeName, "::"); - break; - } - } -} - -//--------------------------------------------------------- -void DocumentXML::addTypeRecursively(const QualType& pType) -{ - if (addToMap(Types, pType)) - { - addTypeRecursively(pType.getTypePtr()); - // beautifier: a non-qualified type shall be transparent - if (!pType.hasLocalQualifiers()) - { - Types[pType] = BasicTypes[pType.getTypePtr()]; - } - } -} - -//--------------------------------------------------------- -void DocumentXML::addTypeRecursively(const Type* pType) -{ - if (addToMap(BasicTypes, pType)) - { - addParentTypes(pType); -/* - // FIXME: doesn't work in the immediate streaming approach - if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(pType)) - { - addSubNode("VariableArraySizeExpression"); - PrintStmt(VAT->getSizeExpr()); - toParent(); - } -*/ - } -} - -//--------------------------------------------------------- -void DocumentXML::addPtrAttribute(const char* pName, const DeclContext* DC) -{ - addContextsRecursively(DC); - addAttribute(pName, getPrefixedId(Contexts[DC], ID_NORMAL)); -} - -//--------------------------------------------------------- -void DocumentXML::addPtrAttribute(const char* pAttributeName, const NamedDecl* D) -{ - if (const DeclContext* DC = dyn_cast<DeclContext>(D)) - { - addContextsRecursively(DC); - addAttribute(pAttributeName, getPrefixedId(Contexts[DC], ID_NORMAL)); - } - else - { - addToMap(Decls, D); - addAttribute(pAttributeName, getPrefixedId(Decls[D], ID_NORMAL)); - } -} - -//--------------------------------------------------------- -void DocumentXML::addPtrAttribute(const char* pName, const NamespaceDecl* D) -{ - addPtrAttribute(pName, static_cast<const DeclContext*>(D)); -} - -//--------------------------------------------------------- -void DocumentXML::addContextsRecursively(const DeclContext *DC) -{ - if (DC != 0 && addToMap(Contexts, DC)) - { - addContextsRecursively(DC->getParent()); - } -} - -//--------------------------------------------------------- -void DocumentXML::addSourceFileAttribute(const std::string& fileName) -{ - addToMap(SourceFiles, fileName, ID_FILE); - addAttribute("file", getPrefixedId(SourceFiles[fileName], ID_FILE)); -} - - -//--------------------------------------------------------- -void DocumentXML::addPtrAttribute(const char* pName, const LabelStmt* L) -{ - addToMap(Labels, L, ID_LABEL); - addAttribute(pName, getPrefixedId(Labels[L], ID_LABEL)); -} - - -//--------------------------------------------------------- -PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc) -{ - SourceManager& SM = Ctx->getSourceManager(); - SourceLocation SpellingLoc = SM.getSpellingLoc(Loc); - PresumedLoc PLoc; - if (!SpellingLoc.isInvalid()) - { - PLoc = SM.getPresumedLoc(SpellingLoc); - if (PLoc.isValid()) { - addSourceFileAttribute(PLoc.getFilename()); - addAttribute("line", PLoc.getLine()); - addAttribute("col", PLoc.getColumn()); - } - } - // else there is no error in some cases (eg. CXXThisExpr) - return PLoc; -} - -//--------------------------------------------------------- -void DocumentXML::addLocationRange(const SourceRange& R) -{ - PresumedLoc PStartLoc = addLocation(R.getBegin()); - if (R.getBegin() != R.getEnd()) - { - SourceManager& SM = Ctx->getSourceManager(); - SourceLocation SpellingLoc = SM.getSpellingLoc(R.getEnd()); - if (!SpellingLoc.isInvalid()) - { - PresumedLoc PLoc = SM.getPresumedLoc(SpellingLoc); - if (PLoc.isInvalid()) { - } else if (PStartLoc.isInvalid() || - strcmp(PLoc.getFilename(), PStartLoc.getFilename()) != 0) { - addToMap(SourceFiles, PLoc.getFilename(), ID_FILE); - addAttribute("endfile", PLoc.getFilename()); - addAttribute("endline", PLoc.getLine()); - addAttribute("endcol", PLoc.getColumn()); - } else if (PLoc.getLine() != PStartLoc.getLine()) { - addAttribute("endline", PLoc.getLine()); - addAttribute("endcol", PLoc.getColumn()); - } else { - addAttribute("endcol", PLoc.getColumn()); - } - } - } -} - -//--------------------------------------------------------- -void DocumentXML::PrintDecl(Decl *D) -{ - writeDeclToXML(D); -} - -//--------------------------------------------------------- -} // NS clang - diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp index e3d8b85..42da44c 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendAction.cpp @@ -20,6 +20,7 @@ #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Parse/ParseAST.h" #include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Serialization/ChainedIncludesSource.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ErrorHandling.h" @@ -209,8 +210,16 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener()); - /// Use PCH? - if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) { + // Convert headers to PCH and chain them. + llvm::OwningPtr<ExternalASTSource> source; + source.reset(ChainedIncludesSource::create(CI)); + if (!source) + goto failure; + CI.getASTContext().setExternalSource(source); + + } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + // Use PCH. assert(hasPCHSupport() && "This action does not have PCH support!"); ASTDeserializationListener *DeserialListener = CI.getInvocation().getFrontendOpts().ChainedPCH ? @@ -249,10 +258,10 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // matching EndSourceFile(). failure: if (isCurrentFileAST()) { - CI.takeASTContext(); - CI.takePreprocessor(); - CI.takeSourceManager(); - CI.takeFileManager(); + CI.setASTContext(0); + CI.setPreprocessor(0); + CI.setSourceManager(0); + CI.setFileManager(0); } CI.getDiagnosticClient().EndSourceFile(); @@ -304,7 +313,7 @@ void FrontendAction::EndSourceFile() { CI.takeASTConsumer(); if (!isCurrentFileAST()) { CI.takeSema(); - CI.takeASTContext(); + CI.resetAndLeakASTContext(); } } else { if (!isCurrentFileAST()) { @@ -333,10 +342,10 @@ void FrontendAction::EndSourceFile() { if (isCurrentFileAST()) { CI.takeSema(); - CI.takeASTContext(); - CI.takePreprocessor(); - CI.takeSourceManager(); - CI.takeFileManager(); + CI.resetAndLeakASTContext(); + CI.resetAndLeakPreprocessor(); + CI.resetAndLeakSourceManager(); + CI.resetAndLeakFileManager(); } setCompilerInstance(0); diff --git a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp index d8e7d29..7b06c7e 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/FrontendActions.cpp @@ -47,13 +47,6 @@ ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, return 0; } -ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI, - llvm::StringRef InFile) { - if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml")) - return CreateASTPrinterXML(OS); - return 0; -} - ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) { return CreateASTDumper(); diff --git a/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp b/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp index 45ff1d2..51dec96 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/HeaderIncludeGen.cpp @@ -22,13 +22,16 @@ class HeaderIncludesCallback : public PPCallbacks { bool HasProcessedPredefines; bool OwnsOutputFile; bool ShowAllHeaders; + bool ShowDepth; public: HeaderIncludesCallback(const Preprocessor *PP, bool ShowAllHeaders_, - llvm::raw_ostream *OutputFile_, bool OwnsOutputFile_) + llvm::raw_ostream *OutputFile_, bool OwnsOutputFile_, + bool ShowDepth_) : SM(PP->getSourceManager()), OutputFile(OutputFile_), CurrentIncludeDepth(0), HasProcessedPredefines(false), - OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_) {} + OwnsOutputFile(OwnsOutputFile_), ShowAllHeaders(ShowAllHeaders_), + ShowDepth(ShowDepth_) {} ~HeaderIncludesCallback() { if (OwnsOutputFile) @@ -41,7 +44,7 @@ public: } void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders, - llvm::StringRef OutputPath) { + llvm::StringRef OutputPath, bool ShowDepth) { llvm::raw_ostream *OutputFile = &llvm::errs(); bool OwnsOutputFile = false; @@ -63,7 +66,8 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders, } PP.addPPCallbacks(new HeaderIncludesCallback(&PP, ShowAllHeaders, - OutputFile, OwnsOutputFile)); + OutputFile, OwnsOutputFile, + ShowDepth)); } void HeaderIncludesCallback::FileChanged(SourceLocation Loc, @@ -78,15 +82,18 @@ void HeaderIncludesCallback::FileChanged(SourceLocation Loc, // Adjust the current include depth. if (Reason == PPCallbacks::EnterFile) { ++CurrentIncludeDepth; - } else { + } else if (Reason == PPCallbacks::ExitFile) { if (CurrentIncludeDepth) --CurrentIncludeDepth; // We track when we are done with the predefines by watching for the first - // place where we drop back to a nesting depth of 0. - if (CurrentIncludeDepth == 0 && !HasProcessedPredefines) + // place where we drop back to a nesting depth of 1. + if (CurrentIncludeDepth == 1 && !HasProcessedPredefines) HasProcessedPredefines = true; - } + + return; + } else + return; // Show the header if we are (a) past the predefines, or (b) showing all // headers and in the predefines at a depth past the initial file and command @@ -102,9 +109,12 @@ void HeaderIncludesCallback::FileChanged(SourceLocation Loc, Lexer::Stringify(Filename); llvm::SmallString<256> Msg; - for (unsigned i = 0; i != CurrentIncludeDepth; ++i) - Msg += '.'; - Msg += ' '; + if (ShowDepth) { + // The main source file is at depth 1, so skip one dot. + for (unsigned i = 1; i != CurrentIncludeDepth; ++i) + Msg += '.'; + Msg += ' '; + } Msg += Filename; Msg += '\n'; diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp index 566b96c..3795c65 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp @@ -80,6 +80,10 @@ public: llvm::StringRef Arch, llvm::StringRef Version); + /// AddMinGW64CXXPaths - Add the necessary paths to support + /// libstdc++ of x86_64-w64-mingw32 aka mingw-w64. + void AddMinGW64CXXPaths(llvm::StringRef Base); + /// AddDelimitedPaths - Add a list of paths delimited by the system PATH /// separator. The processing follows that of the CPATH variable for gcc. void AddDelimitedPaths(llvm::StringRef String); @@ -117,8 +121,13 @@ void InitHeaderSearch::AddPath(const llvm::Twine &Path, llvm::StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); // Handle isysroot. - if (Group == System && !IgnoreSysRoot && + if ((Group == System || Group == CXXSystem) && !IgnoreSysRoot && +#if defined(_WIN32) + !MappedPathStr.empty() && + llvm::sys::path::is_separator(MappedPathStr[0]) && +#else llvm::sys::path::is_absolute(MappedPathStr) && +#endif IsNotEmptyOrRoot) { MappedPathStorage.clear(); MappedPathStr = @@ -211,6 +220,15 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base, CXXSystem, true, false, false); } +void InitHeaderSearch::AddMinGW64CXXPaths(llvm::StringRef Base) { + AddPath(Base, + CXXSystem, true, false, false); + AddPath(Base + "/x86_64-w64-mingw32", + CXXSystem, true, false, false); + AddPath(Base + "/backward", + CXXSystem, true, false, false); +} + // FIXME: This probably should goto to some platform utils place. #ifdef _MSC_VER @@ -538,6 +556,11 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, AddPath("/usr/include/w32api", System, true, false, false); break; case llvm::Triple::MinGW32: + // FIXME: We should be aware of i686-w64-mingw32. + if (triple.getArch() == llvm::Triple::x86_64) + AddPath("c:/mingw/x86_64-w64-mingw32/include", + System, true, false, false); + AddPath("/mingw/include", System, true, false, false); AddPath("c:/mingw/include", System, true, false, false); break; case llvm::Triple::FreeBSD: @@ -568,36 +591,8 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { return; } // FIXME: temporary hack: hard-coded paths. - switch (os) { - case llvm::Triple::Cygwin: - // Cygwin-1.7 - AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4"); - // g++-4 / Cygwin-1.5 - AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2"); - // FIXME: Do we support g++-3.4.4? - AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "3.4.4"); - break; - case llvm::Triple::MinGW32: - // mingw-w64-20110207 - AddPath("c:/MinGW/include/c++/4.5.3", CXXSystem, true, false, false); - AddPath("c:/MinGW/include/c++/4.5.3/x86_64-w64-mingw32", CXXSystem, true, - false, false); - AddPath("c:/MinGW/include/c++/4.5.3/backward", CXXSystem, true, false, - false); - // mingw-w64-20101129 - AddPath("c:/MinGW/include/c++/4.5.2", CXXSystem, true, false, false); - AddPath("c:/MinGW/include/c++/4.5.2/x86_64-w64-mingw32", CXXSystem, true, - false, false); - AddPath("c:/MinGW/include/c++/4.5.2/backward", CXXSystem, true, false, - false); - // Try gcc 4.5.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0"); - // Try gcc 4.4.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); - // Try gcc 4.3.0 - AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0"); - break; - case llvm::Triple::Darwin: + + if (triple.isOSDarwin()) { switch (triple.getArch()) { default: break; @@ -627,6 +622,34 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { "arm-apple-darwin10", "v6", "", triple); break; } + return; + } + + switch (os) { + case llvm::Triple::Cygwin: + // Cygwin-1.7 + AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4"); + // g++-4 / Cygwin-1.5 + AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2"); + // FIXME: Do we support g++-3.4.4? + AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "3.4.4"); + break; + case llvm::Triple::MinGW32: + // FIXME: We should be aware of i686-w64-mingw32. + if (triple.getArch() == llvm::Triple::x86_64) { + // mingw-w64-20110207 + AddMinGW64CXXPaths("c:/mingw/x86_64-w64-mingw32/include/c++/4.5.3"); + // mingw-w64-20101129 + AddMinGW64CXXPaths("c:/mingw/x86_64-w64-mingw32/include/c++/4.5.2"); + } + // Try gcc 4.5.2 (MSYS) + AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2"); + // Try gcc 4.5.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0"); + // Try gcc 4.4.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); + // Try gcc 4.3.0 + AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0"); break; case llvm::Triple::DragonFly: AddPath("/usr/include/c++/4.1", CXXSystem, true, false, false); @@ -674,6 +697,11 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { //===------------------------------------------------------------------===// // Redhat based distros. //===------------------------------------------------------------------===// + // Fedora 15 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", + "x86_64-redhat-linux", "32", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", + "i686-redhat-linux", "", "", triple); // Fedora 14 AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.5.1", "x86_64-redhat-linux", "32", "", triple); @@ -746,7 +774,26 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { "i686-pc-linux-gnu", "", "", triple); AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1", "x86_64-unknown-linux-gnu", "", "", triple); - // Gentoo x86 2010.0 stable + + // Arch Linux gcc 4.6 + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", + "i686-pc-linux-gnu", "", "", triple); + AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.6.0", + "x86_64-unknown-linux-gnu", "", "", triple); + + // Gentoo x86 gcc 4.5.2 + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.5.2/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); + // Gentoo x86 gcc 4.4.5 + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.4.5/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); + // Gentoo x86 gcc 4.4.4 + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/i686-pc-linux-gnu/4.4.4/include/g++-v4", + "i686-pc-linux-gnu", "", "", triple); + // Gentoo x86 2010.0 stable AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/i686-pc-linux-gnu/4.4.3/include/g++-v4", "i686-pc-linux-gnu", "", "", triple); @@ -762,7 +809,15 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4", "i686-pc-linux-gnu", "", "", triple); + // Gentoo x86 llvm-gcc trunk + AddGnuCPlusPlusIncludePaths( + "/usr/lib/llvm-gcc-4.2-9999/include/c++/4.2.1", + "i686-pc-linux-gnu", "", "", triple); + // Gentoo amd64 gcc 4.5.2 + AddGnuCPlusPlusIncludePaths( + "/usr/lib/gcc/x86_64-pc-linux-gnu/4.5.2/include/g++-v4", + "x86_64-pc-linux-gnu", "32", "", triple); // Gentoo amd64 gcc 4.4.5 AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.4.5/include/g++-v4", @@ -782,7 +837,7 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) { // Gentoo amd64 stable AddGnuCPlusPlusIncludePaths( "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4", - "i686-pc-linux-gnu", "", "", triple); + "x86_64-pc-linux-gnu", "", "", triple); // Gentoo amd64 llvm-gcc trunk AddGnuCPlusPlusIncludePaths( @@ -834,7 +889,7 @@ void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang, AddDefaultCIncludePaths(triple, HSOpts); // Add the default framework include paths on Darwin. - if (triple.getOS() == llvm::Triple::Darwin) { + if (triple.isOSDarwin()) { AddPath("/System/Library/Frameworks", System, true, false, true); AddPath("/Library/Frameworks", System, true, false, true); } diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp index 91b5280..abe251d 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/InitPreprocessor.cpp @@ -247,13 +247,18 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__GNUC_PATCHLEVEL__", "1"); Builder.defineMacro("__GNUC__", "4"); Builder.defineMacro("__GXX_ABI_VERSION", "1002"); - Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible Clang Compiler\""); + + // As sad as it is, enough software depends on the __VERSION__ for version + // checks that it is necessary to report 4.2.1 (the base GCC version we claim + // compatibility with) first. + Builder.defineMacro("__VERSION__", "\"4.2.1 Compatible " + + llvm::Twine(getClangFullCPPVersion()) + "\""); // Initialize language-specific preprocessor defines. // These should all be defined in the preprocessor according to the // current language configuration. - if (!LangOpts.Microsoft) + if (!LangOpts.Microsoft && !LangOpts.TraditionalCPP) Builder.defineMacro("__STDC__"); if (LangOpts.AsmPreprocessor) Builder.defineMacro("__ASSEMBLER__"); @@ -313,8 +318,10 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.SjLjExceptions) Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__"); - if (LangOpts.CPlusPlus) { + if (LangOpts.Deprecated) Builder.defineMacro("__DEPRECATED"); + + if (LangOpts.CPlusPlus) { Builder.defineMacro("__GNUG__", "4"); Builder.defineMacro("__GXX_WEAK__"); if (LangOpts.GNUMode) @@ -328,12 +335,6 @@ static void InitializePredefinedMacros(const TargetInfo &TI, } if (LangOpts.Microsoft) { - // Filter out some microsoft extensions when trying to parse in ms-compat - // mode. - Builder.defineMacro("__int8", "__INT8_TYPE__"); - Builder.defineMacro("__int16", "__INT16_TYPE__"); - Builder.defineMacro("__int32", "__INT32_TYPE__"); - Builder.defineMacro("__int64", "__INT64_TYPE__"); // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however // VC++ appears to only like __FUNCTION__. Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__"); @@ -414,6 +415,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (!LangOpts.CharIsSigned) Builder.defineMacro("__CHAR_UNSIGNED__"); + if (!TargetInfo::isTypeSigned(TI.getWIntType())) + Builder.defineMacro("__WINT_UNSIGNED__"); + // Define exact-width integer types for stdint.h Builder.defineMacro("__INT" + llvm::Twine(TI.getCharWidth()) + "_TYPE__", "char"); @@ -531,20 +535,13 @@ static void InitializeFileRemapping(Diagnostic &Diags, continue; } - // Load the contents of the file we're mapping to. - std::string ErrorStr; - const llvm::MemoryBuffer *Buffer - = FileMgr.getBufferForFile(ToFile->getName(), &ErrorStr); - if (!Buffer) { - Diags.Report(diag::err_fe_error_opening) - << Remap->second << ErrorStr; - continue; - } - // Override the contents of the "from" file with the contents of // the "to" file. - SourceMgr.overrideFileContents(FromFile, Buffer); + SourceMgr.overrideFileContents(FromFile, ToFile); } + + SourceMgr.setOverridenFilesKeepOriginalName( + InitOpts.RemappedFilesKeepOriginalName); } /// InitializePreprocessor - Initialize the preprocessor getting it and the diff --git a/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp new file mode 100644 index 0000000..954bad4 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Frontend/LogDiagnosticPrinter.cpp @@ -0,0 +1,146 @@ +//===--- LogDiagnosticPrinter.cpp - Log Diagnostic Printer ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/LogDiagnosticPrinter.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +LogDiagnosticPrinter::LogDiagnosticPrinter(llvm::raw_ostream &os, + const DiagnosticOptions &diags, + bool _OwnsOutputStream) + : OS(os), LangOpts(0), DiagOpts(&diags), + OwnsOutputStream(_OwnsOutputStream) { +} + +LogDiagnosticPrinter::~LogDiagnosticPrinter() { + if (OwnsOutputStream) + delete &OS; +} + +static llvm::StringRef getLevelName(Diagnostic::Level Level) { + switch (Level) { + default: + return "<unknown>"; + case Diagnostic::Ignored: return "ignored"; + case Diagnostic::Note: return "note"; + case Diagnostic::Warning: return "warning"; + case Diagnostic::Error: return "error"; + case Diagnostic::Fatal: return "fatal error"; + } +} + +void LogDiagnosticPrinter::EndSourceFile() { + // We emit all the diagnostics in EndSourceFile. However, we don't emit any + // entry if no diagnostics were present. + // + // Note that DiagnosticClient has no "end-of-compilation" callback, so we will + // miss any diagnostics which are emitted after and outside the translation + // unit processing. + if (Entries.empty()) + return; + + // Write to a temporary string to ensure atomic write of diagnostic object. + llvm::SmallString<512> Msg; + llvm::raw_svector_ostream OS(Msg); + + OS << "<dict>\n"; + if (!MainFilename.empty()) { + OS << " <key>main-file</key>\n" + << " <string>" << MainFilename << "</string>\n"; + } + if (!DwarfDebugFlags.empty()) { + OS << " <key>dwarf-debug-flags</key>\n" + << " <string>" << DwarfDebugFlags << "</string>\n"; + } + OS << " <key>diagnostics</key>\n"; + OS << " <array>\n"; + for (unsigned i = 0, e = Entries.size(); i != e; ++i) { + DiagEntry &DE = Entries[i]; + + OS << " <dict>\n"; + OS << " <key>level</key>\n" + << " <string>" << getLevelName(DE.DiagnosticLevel) << "</string>\n"; + if (!DE.Filename.empty()) { + OS << " <key>filename</key>\n" + << " <string>" << DE.Filename << "</string>\n"; + } + if (DE.Line != 0) { + OS << " <key>line</key>\n" + << " <integer>" << DE.Line << "</integer>\n"; + } + if (DE.Column != 0) { + OS << " <key>column</key>\n" + << " <integer>" << DE.Column << "</integer>\n"; + } + if (!DE.Message.empty()) { + OS << " <key>message</key>\n" + << " <string>" << DE.Message << "</string>\n"; + } + OS << " </dict>\n"; + } + OS << " </array>\n"; + OS << "</dict>\n"; + + this->OS << OS.str(); +} + +void LogDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, + const DiagnosticInfo &Info) { + // Default implementation (Warnings/errors count). + DiagnosticClient::HandleDiagnostic(Level, Info); + + // Initialize the main file name, if we haven't already fetched it. + if (MainFilename.empty()) { + const SourceManager &SM = Info.getSourceManager(); + FileID FID = SM.getMainFileID(); + if (!FID.isInvalid()) { + const FileEntry *FE = SM.getFileEntryForID(FID); + if (FE && FE->getName()) + MainFilename = FE->getName(); + } + } + + // Create the diag entry. + DiagEntry DE; + DE.DiagnosticID = Info.getID(); + DE.DiagnosticLevel = Level; + + // Format the message. + llvm::SmallString<100> MessageStr; + Info.FormatDiagnostic(MessageStr); + DE.Message = MessageStr.str(); + + // Set the location information. + DE.Filename = ""; + DE.Line = DE.Column = 0; + if (Info.getLocation().isValid()) { + const SourceManager &SM = Info.getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); + + if (PLoc.isInvalid()) { + // At least print the file name if available: + FileID FID = SM.getFileID(Info.getLocation()); + if (!FID.isInvalid()) { + const FileEntry *FE = SM.getFileEntryForID(FID); + if (FE && FE->getName()) + DE.Filename = FE->getName(); + } + } else { + DE.Filename = PLoc.getFilename(); + DE.Line = PLoc.getLine(); + DE.Column = PLoc.getColumn(); + } + } + + // Record the diagnostic entry. + Entries.push_back(DE); +} diff --git a/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp b/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp index 3649c3c..5aa65d7 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/MultiplexConsumer.cpp @@ -95,6 +95,10 @@ public: virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D); virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D); + virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D); + virtual void CompletedImplicitDefinition(const FunctionDecl *D); + virtual void StaticDataMemberInstantiated(const VarDecl *D); private: std::vector<ASTMutationListener*> Listeners; }; @@ -125,6 +129,21 @@ void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->AddedCXXTemplateSpecialization(TD, D); } +void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( + const FunctionTemplateDecl *TD, const FunctionDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->AddedCXXTemplateSpecialization(TD, D); +} +void MultiplexASTMutationListener::CompletedImplicitDefinition( + const FunctionDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->CompletedImplicitDefinition(D); +} +void MultiplexASTMutationListener::StaticDataMemberInstantiated( + const VarDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->StaticDataMemberInstantiated(D); +} } // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp index 922d743..b46e047 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -432,7 +432,7 @@ struct UnknownPragmaHandler : public PragmaHandler { Callbacks->OS.write(Prefix, strlen(Prefix)); Callbacks->SetEmittedTokensOnThisLine(); // Read and print all of the pragma tokens. - while (PragmaTok.isNot(tok::eom)) { + while (PragmaTok.isNot(tok::eod)) { if (PragmaTok.hasLeadingSpace()) Callbacks->OS << ' '; std::string TokSpell = PP.getSpelling(PragmaTok); diff --git a/contrib/llvm/tools/clang/lib/Frontend/StmtXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/StmtXML.cpp deleted file mode 100644 index c113cc1..0000000 --- a/contrib/llvm/tools/clang/lib/Frontend/StmtXML.cpp +++ /dev/null @@ -1,439 +0,0 @@ -//===--- StmtXML.cpp - XML implementation for Stmt ASTs ------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the Stmt::dumpXML methods, which dump out the -// AST to an XML document. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/DocumentXML.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/DeclObjC.h" -#include "clang/AST/DeclCXX.h" -#include "clang/Basic/SourceManager.h" -using namespace clang; - -//===----------------------------------------------------------------------===// -// StmtXML Visitor -//===----------------------------------------------------------------------===// - -namespace { - class StmtXML : public StmtVisitor<StmtXML> { - DocumentXML& Doc; - - //static const char *getOpcodeStr(UnaryOperator::Opcode Op); - //static const char *getOpcodeStr(BinaryOperator::Opcode Op); - - - void addSpecialAttribute(const char* pName, StringLiteral* Str) { - Doc.addAttribute(pName, Doc.escapeString(Str->getString().data(), - Str->getString().size())); - } - - void addSpecialAttribute(const char* pName, SizeOfAlignOfExpr* S) { - if (S->isArgumentType()) - Doc.addAttribute(pName, S->getArgumentType()); - } - - void addSpecialAttribute(const char* pName, CXXTypeidExpr* S) { - if (S->isTypeOperand()) - Doc.addAttribute(pName, S->getTypeOperand()); - } - - - public: - StmtXML(DocumentXML& doc) - : Doc(doc) { - } - - void DumpSubTree(Stmt *S) { - if (S) { - Visit(S); - if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) { - for (DeclStmt::decl_iterator DI = DS->decl_begin(), - DE = DS->decl_end(); DI != DE; ++DI) { - Doc.PrintDecl(*DI); - } - } else { - for (Stmt::child_range i = S->children(); i; ++i) - DumpSubTree(*i); - } - Doc.toParent(); - } else { - Doc.addSubNode("NULL").toParent(); - } - } - - -#define NODE_XML( CLASS, NAME ) \ - void Visit##CLASS(CLASS* S) \ - { \ - typedef CLASS tStmtType; \ - Doc.addSubNode(NAME); - -#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, S->FN); -#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type") -#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, S->FN); -#define ATTRIBUTE_SPECIAL_XML( FN, NAME ) addSpecialAttribute(NAME, S); -#define ATTRIBUTE_FILE_LOCATION_XML Doc.addLocationRange(S->getSourceRange()); - - -#define ATTRIBUTE_ENUM_XML( FN, NAME ) \ - { \ - const char* pAttributeName = NAME; \ - const bool optional = false; \ - switch (S->FN) { \ - default: assert(0 && "unknown enum value"); - -#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ - { \ - const char* pAttributeName = NAME; \ - const bool optional = true; \ - switch (S->FN) { \ - default: assert(0 && "unknown enum value"); - -#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; -#define END_ENUM_XML } } -#define END_NODE_XML } - -#define ID_ATTRIBUTE_XML Doc.addAttribute("id", S); -#define SUB_NODE_XML( CLASS ) -#define SUB_NODE_SEQUENCE_XML( CLASS ) -#define SUB_NODE_OPT_XML( CLASS ) - -#include "clang/Frontend/StmtXML.def" - -#if (0) - // Stmts. - void VisitStmt(Stmt *Node); - void VisitDeclStmt(DeclStmt *Node); - void VisitLabelStmt(LabelStmt *Node); - void VisitGotoStmt(GotoStmt *Node); - - // Exprs - void VisitExpr(Expr *Node); - void VisitDeclRefExpr(DeclRefExpr *Node); - void VisitPredefinedExpr(PredefinedExpr *Node); - void VisitCharacterLiteral(CharacterLiteral *Node); - void VisitIntegerLiteral(IntegerLiteral *Node); - void VisitFloatingLiteral(FloatingLiteral *Node); - void VisitStringLiteral(StringLiteral *Str); - void VisitUnaryOperator(UnaryOperator *Node); - void VisitOffsetOfExpr(OffsetOfExpr *Node); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node); - void VisitMemberExpr(MemberExpr *Node); - void VisitExtVectorElementExpr(ExtVectorElementExpr *Node); - void VisitBinaryOperator(BinaryOperator *Node); - void VisitCompoundAssignOperator(CompoundAssignOperator *Node); - void VisitAddrLabelExpr(AddrLabelExpr *Node); - - // C++ - void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); - void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node); - void VisitCXXThisExpr(CXXThisExpr *Node); - void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node); - - // ObjC - void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); - void VisitObjCMessageExpr(ObjCMessageExpr* Node); - void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); - void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); - void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node); - void VisitObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *Node); - void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); -#endif - }; -} - -//===----------------------------------------------------------------------===// -// Stmt printing methods. -//===----------------------------------------------------------------------===// -#if (0) -void StmtXML::VisitStmt(Stmt *Node) { - // nothing special to do -} - -void StmtXML::VisitDeclStmt(DeclStmt *Node) { - for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end(); - DI != DE; ++DI) { - Doc.PrintDecl(*DI); - } -} - -void StmtXML::VisitLabelStmt(LabelStmt *Node) { - Doc.addAttribute("name", Node->getName()); -} - -void StmtXML::VisitGotoStmt(GotoStmt *Node) { - Doc.addAttribute("name", Node->getLabel()->getName()); -} - -//===----------------------------------------------------------------------===// -// Expr printing methods. -//===----------------------------------------------------------------------===// - -void StmtXML::VisitExpr(Expr *Node) { - DumpExpr(Node); -} - -void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) { - DumpExpr(Node); - - const char* pKind; - switch (Node->getDecl()->getKind()) { - case Decl::Function: pKind = "FunctionDecl"; break; - case Decl::Var: pKind = "Var"; break; - case Decl::ParmVar: pKind = "ParmVar"; break; - case Decl::EnumConstant: pKind = "EnumConstant"; break; - case Decl::Typedef: pKind = "Typedef"; break; - case Decl::Record: pKind = "Record"; break; - case Decl::Enum: pKind = "Enum"; break; - case Decl::CXXRecord: pKind = "CXXRecord"; break; - case Decl::ObjCInterface: pKind = "ObjCInterface"; break; - case Decl::ObjCClass: pKind = "ObjCClass"; break; - default: pKind = "Decl"; break; - } - - Doc.addAttribute("kind", pKind); - Doc.addAttribute("name", Node->getDecl()->getNameAsString()); - Doc.addRefAttribute(Node->getDecl()); -} - -void StmtXML::VisitPredefinedExpr(PredefinedExpr *Node) { - DumpExpr(Node); - switch (Node->getIdentType()) { - default: assert(0 && "unknown case"); - case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break; - case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break; - case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break; - } -} - -void StmtXML::VisitCharacterLiteral(CharacterLiteral *Node) { - DumpExpr(Node); - Doc.addAttribute("value", Node->getValue()); -} - -void StmtXML::VisitIntegerLiteral(IntegerLiteral *Node) { - DumpExpr(Node); - bool isSigned = Node->getType()->isSignedIntegerType(); - Doc.addAttribute("value", Node->getValue().toString(10, isSigned)); -} - -void StmtXML::VisitFloatingLiteral(FloatingLiteral *Node) { - DumpExpr(Node); - // FIXME: output float as written in source (no approximation or the like) - //Doc.addAttribute("value", Node->getValueAsApproximateDouble())); - Doc.addAttribute("value", "FIXME"); -} - -void StmtXML::VisitStringLiteral(StringLiteral *Str) { - DumpExpr(Str); - if (Str->isWide()) - Doc.addAttribute("is_wide", "1"); - - Doc.addAttribute("value", Doc.escapeString(Str->getStrData(), Str->getByteLength())); -} - - -const char *StmtXML::getOpcodeStr(UnaryOperator::Opcode Op) { - switch (Op) { - default: assert(0 && "Unknown unary operator"); - case UnaryOperator::PostInc: return "postinc"; - case UnaryOperator::PostDec: return "postdec"; - case UnaryOperator::PreInc: return "preinc"; - case UnaryOperator::PreDec: return "predec"; - case UnaryOperator::AddrOf: return "addrof"; - case UnaryOperator::Deref: return "deref"; - case UnaryOperator::Plus: return "plus"; - case UnaryOperator::Minus: return "minus"; - case UnaryOperator::Not: return "not"; - case UnaryOperator::LNot: return "lnot"; - case UnaryOperator::Real: return "__real"; - case UnaryOperator::Imag: return "__imag"; - case UnaryOperator::Extension: return "__extension__"; - } -} - - -const char *StmtXML::getOpcodeStr(BinaryOperator::Opcode Op) { - switch (Op) { - default: assert(0 && "Unknown binary operator"); - case BinaryOperator::PtrMemD: return "ptrmemd"; - case BinaryOperator::PtrMemI: return "ptrmemi"; - case BinaryOperator::Mul: return "mul"; - case BinaryOperator::Div: return "div"; - case BinaryOperator::Rem: return "rem"; - case BinaryOperator::Add: return "add"; - case BinaryOperator::Sub: return "sub"; - case BinaryOperator::Shl: return "shl"; - case BinaryOperator::Shr: return "shr"; - case BinaryOperator::LT: return "lt"; - case BinaryOperator::GT: return "gt"; - case BinaryOperator::LE: return "le"; - case BinaryOperator::GE: return "ge"; - case BinaryOperator::EQ: return "eq"; - case BinaryOperator::NE: return "ne"; - case BinaryOperator::And: return "and"; - case BinaryOperator::Xor: return "xor"; - case BinaryOperator::Or: return "or"; - case BinaryOperator::LAnd: return "land"; - case BinaryOperator::LOr: return "lor"; - case BinaryOperator::Assign: return "assign"; - case BinaryOperator::MulAssign: return "mulassign"; - case BinaryOperator::DivAssign: return "divassign"; - case BinaryOperator::RemAssign: return "remassign"; - case BinaryOperator::AddAssign: return "addassign"; - case BinaryOperator::SubAssign: return "subassign"; - case BinaryOperator::ShlAssign: return "shlassign"; - case BinaryOperator::ShrAssign: return "shrassign"; - case BinaryOperator::AndAssign: return "andassign"; - case BinaryOperator::XorAssign: return "xorassign"; - case BinaryOperator::OrAssign: return "orassign"; - case BinaryOperator::Comma: return "comma"; - } -} - -void StmtXML::VisitUnaryOperator(UnaryOperator *Node) { - DumpExpr(Node); - Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode())); -} - -void StmtXML::OffsetOfExpr(OffsetOfExpr *Node) { - DumpExpr(Node); -} - -void StmtXML::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { - DumpExpr(Node); - Doc.addAttribute("is_sizeof", Node->isSizeOf() ? "sizeof" : "alignof"); - Doc.addAttribute("is_type", Node->isArgumentType() ? "1" : "0"); - if (Node->isArgumentType()) - DumpTypeExpr(Node->getArgumentType()); -} - -void StmtXML::VisitMemberExpr(MemberExpr *Node) { - DumpExpr(Node); - Doc.addAttribute("is_deref", Node->isArrow() ? "1" : "0"); - Doc.addAttribute("name", Node->getMemberDecl()->getNameAsString()); - Doc.addRefAttribute(Node->getMemberDecl()); -} - -void StmtXML::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { - DumpExpr(Node); - Doc.addAttribute("name", Node->getAccessor().getName()); -} - -void StmtXML::VisitBinaryOperator(BinaryOperator *Node) { - DumpExpr(Node); - Doc.addAttribute("op_code", getOpcodeStr(Node->getOpcode())); -} - -void StmtXML::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { - VisitBinaryOperator(Node); -/* FIXME: is this needed in the AST? - DumpExpr(Node); - CurrentNode = CurrentNode->addSubNode("ComputeLHSTy"); - DumpType(Node->getComputationLHSType()); - CurrentNode = CurrentNode->Parent->addSubNode("ComputeResultTy"); - DumpType(Node->getComputationResultType()); - Doc.toParent(); -*/ -} - -// GNU extensions. - -void StmtXML::VisitAddrLabelExpr(AddrLabelExpr *Node) { - DumpExpr(Node); - Doc.addAttribute("name", Node->getLabel()->getName()); -} - -//===----------------------------------------------------------------------===// -// C++ Expressions -//===----------------------------------------------------------------------===// - -void StmtXML::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { - DumpExpr(Node); - Doc.addAttribute("kind", Node->getCastName()); - DumpTypeExpr(Node->getTypeAsWritten()); -} - -void StmtXML::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { - DumpExpr(Node); - Doc.addAttribute("value", Node->getValue() ? "true" : "false"); -} - -void StmtXML::VisitCXXThisExpr(CXXThisExpr *Node) { - DumpExpr(Node); -} - -void StmtXML::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { - DumpExpr(Node); - DumpTypeExpr(Node->getTypeAsWritten()); -} - -//===----------------------------------------------------------------------===// -// Obj-C Expressions -//===----------------------------------------------------------------------===// - -void StmtXML::VisitObjCMessageExpr(ObjCMessageExpr* Node) { - DumpExpr(Node); - Doc.addAttribute("selector", Node->getSelector().getAsString()); - IdentifierInfo* clsName = Node->getClassName(); - if (clsName) - Doc.addAttribute("class", clsName->getName()); -} - -void StmtXML::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { - DumpExpr(Node); - DumpTypeExpr(Node->getEncodedType()); -} - -void StmtXML::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { - DumpExpr(Node); - Doc.addAttribute("selector", Node->getSelector().getAsString()); -} - -void StmtXML::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { - DumpExpr(Node); - Doc.addAttribute("protocol", Node->getProtocol()->getNameAsString()); -} - -void StmtXML::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { - DumpExpr(Node); - Doc.addAttribute("property", Node->getProperty()->getNameAsString()); -} - -void StmtXML::VisitObjCImplicitSetterGetterRefExpr( - ObjCImplicitSetterGetterRefExpr *Node) { - DumpExpr(Node); - ObjCMethodDecl *Getter = Node->getGetterMethod(); - ObjCMethodDecl *Setter = Node->getSetterMethod(); - Doc.addAttribute("Getter", Getter->getSelector().getAsString()); - Doc.addAttribute("Setter", Setter ? Setter->getSelector().getAsString().c_str() : "(null)"); -} - -void StmtXML::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { - DumpExpr(Node); - Doc.addAttribute("kind", Node->getDecl()->getDeclKindName()); - Doc.addAttribute("decl", Node->getDecl()->getNameAsString()); - if (Node->isFreeIvar()) - Doc.addAttribute("isFreeIvar", "1"); -} -#endif -//===----------------------------------------------------------------------===// -// Stmt method implementations -//===----------------------------------------------------------------------===// - -/// dumpAll - This does a dump of the specified AST fragment and all subtrees. -void DocumentXML::PrintStmt(const Stmt *S) { - StmtXML P(*this); - P.DumpSubTree(const_cast<Stmt*>(S)); -} - diff --git a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp index 0849153..47c942c 100644 --- a/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/contrib/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp @@ -53,8 +53,11 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() { delete &OS; } -void TextDiagnosticPrinter:: -PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) { +void TextDiagnosticPrinter::PrintIncludeStack(Diagnostic::Level Level, + SourceLocation Loc, + const SourceManager &SM) { + if (!DiagOpts->ShowNoteIncludeStack && Level == Diagnostic::Note) return; + if (Loc.isInvalid()) return; PresumedLoc PLoc = SM.getPresumedLoc(Loc); @@ -62,7 +65,7 @@ PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) { return; // Print out the other include frames first. - PrintIncludeStack(PLoc.getIncludeLoc(), SM); + PrintIncludeStack(Level, PLoc.getIncludeLoc(), SM); if (DiagOpts->ShowLocation) OS << "In file included from " << PLoc.getFilename() @@ -289,7 +292,8 @@ static void SelectInterestingSourceRegion(std::string &SourceLine, } } -void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, +void TextDiagnosticPrinter::EmitCaretDiagnostic(Diagnostic::Level Level, + SourceLocation Loc, CharSourceRange *Ranges, unsigned NumRanges, const SourceManager &SM, @@ -313,7 +317,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first; // FIXME: Map ranges? - EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns, + EmitCaretDiagnostic(Level, OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns, OnMacroInst + 1, MacroSkipStart, MacroSkipEnd); // Map the location. @@ -339,7 +343,7 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, // "included from" lines. if (LastWarningLoc != PLoc.getIncludeLoc()) { LastWarningLoc = PLoc.getIncludeLoc(); - PrintIncludeStack(LastWarningLoc, SM); + PrintIncludeStack(Level, LastWarningLoc, SM); } if (DiagOpts->ShowLocation) { @@ -351,8 +355,9 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, } OS << "note: instantiated from:\n"; - EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns, - OnMacroInst + 1, MacroSkipStart, MacroSkipEnd); + EmitCaretDiagnostic(Level, Loc, Ranges, NumRanges, SM, Hints, NumHints, + Columns, OnMacroInst + 1, MacroSkipStart, + MacroSkipEnd); return; } @@ -805,12 +810,12 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, // "included from" lines. if (LastWarningLoc != PLoc.getIncludeLoc()) { LastWarningLoc = PLoc.getIncludeLoc(); - PrintIncludeStack(LastWarningLoc, SM); + PrintIncludeStack(Level, LastWarningLoc, SM); StartOfLocationInfo = OS.tell(); } // Compute the column number. - if (DiagOpts->ShowLocation && PLoc.isValid()) { + if (DiagOpts->ShowLocation) { if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); @@ -903,6 +908,13 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, llvm::SmallString<100> OutStr; Info.FormatDiagnostic(OutStr); + if (DiagOpts->ShowNames && + !DiagnosticIDs::isBuiltinNote(Info.getID())) { + OutStr += " ["; + OutStr += DiagnosticIDs::getName(Info.getID()); + OutStr += "]"; + } + std::string OptionName; if (DiagOpts->ShowOptionNames) { // Was this a warning mapped to an error using -Werror or pragma? @@ -1034,7 +1046,7 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, } } - EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(), + EmitCaretDiagnostic(Level, LastLoc, Ranges, NumRanges, LastLoc.getManager(), Info.getFixItHints(), Info.getNumFixItHints(), DiagOpts->MessageLength, diff --git a/contrib/llvm/tools/clang/lib/Frontend/TypeXML.cpp b/contrib/llvm/tools/clang/lib/Frontend/TypeXML.cpp deleted file mode 100644 index a8c8f75..0000000 --- a/contrib/llvm/tools/clang/lib/Frontend/TypeXML.cpp +++ /dev/null @@ -1,119 +0,0 @@ -//===--- DocumentXML.cpp - XML document for ASTs --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file implements the XML document class, which provides the means to -// dump out the AST in a XML form that exposes type details and other fields. -// -//===----------------------------------------------------------------------===// - -#include "clang/Frontend/DocumentXML.h" -#include "clang/AST/TypeVisitor.h" -#include "clang/AST/Type.h" -#include "clang/AST/Decl.h" - -namespace clang { - namespace XML { - namespace { - -//--------------------------------------------------------- -class TypeWriter : public TypeVisitor<TypeWriter> { - DocumentXML& Doc; - -public: - TypeWriter(DocumentXML& doc) : Doc(doc) {} - -#define NODE_XML( CLASS, NAME ) \ - void Visit##CLASS(const CLASS* T) { \ - Doc.addSubNode(NAME); - -#define ID_ATTRIBUTE_XML // done by the Document class itself -#define ATTRIBUTE_XML( FN, NAME ) Doc.addAttribute(NAME, T->FN); -#define TYPE_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "type") -#define CONTEXT_ATTRIBUTE_XML( FN ) ATTRIBUTE_XML(FN, "context") -#define ATTRIBUTE_OPT_XML( FN, NAME ) Doc.addAttributeOptional(NAME, T->FN); - -#define ATTRIBUTE_ENUM_XML( FN, NAME ) \ - { \ - const char* pAttributeName = NAME; \ - const bool optional = false; \ - switch (T->FN) { \ - default: assert(0 && "unknown enum value"); - -#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \ - { \ - const char* pAttributeName = NAME; \ - const bool optional = true; \ - switch (T->FN) { \ - default: assert(0 && "unknown enum value"); - -#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break; -#define END_ENUM_XML } } -#define END_NODE_XML } - -#include "clang/Frontend/TypeXML.def" - -}; - -//--------------------------------------------------------- - } // anon clang - } // NS XML - -//--------------------------------------------------------- -class DocumentXML::TypeAdder : public TypeVisitor<DocumentXML::TypeAdder> { - DocumentXML& Doc; - - void addIfType(const Type* pType) { - Doc.addTypeRecursively(pType); - } - - void addIfType(const QualType& pType) { - Doc.addTypeRecursively(pType); - } - - template<class T> void addIfType(T) {} - -public: - TypeAdder(DocumentXML& doc) : Doc(doc) {} - -#define NODE_XML( CLASS, NAME ) \ - void Visit##CLASS(const CLASS* T) \ - { - -#define ID_ATTRIBUTE_XML -#define TYPE_ATTRIBUTE_XML( FN ) Doc.addTypeRecursively(T->FN); -#define CONTEXT_ATTRIBUTE_XML( FN ) -#define ATTRIBUTE_XML( FN, NAME ) addIfType(T->FN); -#define ATTRIBUTE_OPT_XML( FN, NAME ) -#define ATTRIBUTE_ENUM_XML( FN, NAME ) -#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) -#define ENUM_XML( VALUE, NAME ) -#define END_ENUM_XML -#define END_NODE_XML } - -#include "clang/Frontend/TypeXML.def" -}; - -//--------------------------------------------------------- -void DocumentXML::addParentTypes(const Type* pType) { - TypeAdder(*this).Visit(pType); -} - -//--------------------------------------------------------- -void DocumentXML::writeTypeToXML(const Type* pType) { - XML::TypeWriter(*this).Visit(const_cast<Type*>(pType)); -} - -//--------------------------------------------------------- -void DocumentXML::writeTypeToXML(const QualType& pType) { - XML::TypeWriter(*this).VisitQualType(const_cast<QualType*>(&pType)); -} - -//--------------------------------------------------------- -} // NS clang - diff --git a/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 65fad6d..664b533 100644 --- a/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/contrib/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -37,7 +37,6 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) { case ASTDump: return new ASTDumpAction(); case ASTDumpXML: return new ASTDumpXMLAction(); case ASTPrint: return new ASTPrintAction(); - case ASTPrintXML: return new ASTPrintXMLAction(); case ASTView: return new ASTViewAction(); case BoostCon: return new BoostConAction(); case CreateModule: return 0; diff --git a/contrib/llvm/tools/clang/lib/Headers/avxintrin.h b/contrib/llvm/tools/clang/lib/Headers/avxintrin.h index 884d31c..2eb2f85 100644 --- a/contrib/llvm/tools/clang/lib/Headers/avxintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/avxintrin.h @@ -385,41 +385,23 @@ _mm256_dp_ps(__m256 a, __m256 b, const int c) #define _CMP_GT_OQ 0x1e /* Greater-than (ordered, non-signaling) */ #define _CMP_TRUE_US 0x1f /* True (unordered, signaling) */ -static __inline __m128d __attribute__((__always_inline__, __nodebug__)) -_mm_cmp_pd(__m128d a, __m128d b, const int c) -{ - return (__m128d)__builtin_ia32_cmppd((__v2df)a, (__v2df)b, c); -} +#define _mm_cmp_pd(a, b, c) \ + (__m128d)__builtin_ia32_cmppd((__v2df)(a), (__v2df)(b), (c)) -static __inline __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_cmp_ps(__m128 a, __m128 b, const int c) -{ - return (__m128)__builtin_ia32_cmpps((__v4sf)a, (__v4sf)b, c); -} +#define _mm_cmp_ps(a, b, c) \ + (__m128)__builtin_ia32_cmpps((__v4sf)(a), (__v4sf)(b), (c)) -static __inline __m256d __attribute__((__always_inline__, __nodebug__)) -_mm256_cmp_pd(__m256d a, __m256d b, const int c) -{ - return (__m256d)__builtin_ia32_cmppd256((__v4df)a, (__v4df)b, c); -} +#define _mm256_cmp_pd(a, b, c) \ + (__m256d)__builtin_ia32_cmppd256((__v4df)(a), (__v4df)(b), (c)) -static __inline __m256 __attribute__((__always_inline__, __nodebug__)) -_mm256_cmp_ps(__m256 a, __m256 b, const int c) -{ - return (__m256)__builtin_ia32_cmpps256((__v8sf)a, (__v8sf)b, c); -} +#define _mm256_cmp_ps(a, b, c) \ + (__m256)__builtin_ia32_cmpps256((__v8sf)(a), (__v8sf)(b), (c)) -static __inline __m128d __attribute__((__always_inline__, __nodebug__)) -_mm_cmp_sd(__m128d a, __m128d b, const int c) -{ - return (__m128d)__builtin_ia32_cmpsd((__v2df)a, (__v2df)b, c); -} +#define _mm_cmp_sd(a, b, c) \ + (__m128d)__builtin_ia32_cmpsd((__v2df)(a), (__v2df)(b), (c)) -static __inline __m128 __attribute__((__always_inline__, __nodebug__)) -_mm_cmp_ss(__m128 a, __m128 b, const int c) -{ - return (__m128)__builtin_ia32_cmpss((__v4sf)a, (__v4sf)b, c); -} +#define _mm_cmp_ss(a, b, c) \ + (__m128)__builtin_ia32_cmpss((__v4sf)(a), (__v4sf)(b), (c)) /* Vector extract */ static __inline __m128d __attribute__((__always_inline__, __nodebug__)) diff --git a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h index 11b2581..0c1d730 100644 --- a/contrib/llvm/tools/clang/lib/Headers/emmintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/emmintrin.h @@ -466,7 +466,7 @@ _mm_loadr_pd(double const *dp) static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) _mm_loadu_pd(double const *dp) { - return __builtin_ia32_loadupd(dp); + return (__m128d){ dp[0], dp[1] }; } static __inline__ __m128d __attribute__((__always_inline__, __nodebug__)) @@ -1210,16 +1210,18 @@ _mm_movemask_epi8(__m128i a) } #define _mm_shuffle_epi32(a, imm) \ - ((__m128i)__builtin_shufflevector((__v4si)(a), (__v4si) {0}, \ + ((__m128i)__builtin_shufflevector((__v4si)(a), (__v4si) _mm_set1_epi32(0), \ (imm) & 0x3, ((imm) & 0xc) >> 2, \ ((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6)) + + #define _mm_shufflelo_epi16(a, imm) \ - ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) {0}, \ + ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) _mm_set1_epi16(0), \ (imm) & 0x3, ((imm) & 0xc) >> 2, \ ((imm) & 0x30) >> 4, ((imm) & 0xc0) >> 6, \ 4, 5, 6, 7)) #define _mm_shufflehi_epi16(a, imm) \ - ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) {0}, 0, 1, 2, 3, \ + ((__m128i)__builtin_shufflevector((__v8hi)(a), (__v8hi) _mm_set1_epi16(0), 0, 1, 2, 3, \ 4 + (((imm) & 0x03) >> 0), \ 4 + (((imm) & 0x0c) >> 2), \ 4 + (((imm) & 0x30) >> 4), \ diff --git a/contrib/llvm/tools/clang/lib/Headers/mm3dnow.h b/contrib/llvm/tools/clang/lib/Headers/mm3dnow.h new file mode 100644 index 0000000..2f456ad --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Headers/mm3dnow.h @@ -0,0 +1,161 @@ +/*===---- mm3dnow.h - 3DNow! intrinsics ------------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef _MM3DNOW_H_INCLUDED +#define _MM3DNOW_H_INCLUDED + +#include <mmintrin.h> + +typedef float __v2sf __attribute__((__vector_size__(8))); + +static __inline__ void __attribute__((__always_inline__, __nodebug__)) +_m_femms() { + __builtin_ia32_femms(); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pavgusb(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pavgusb((__v8qi)__m1, (__v8qi)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pf2id(__m64 __m) { + return (__m64)__builtin_ia32_pf2id((__v2sf)__m); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfacc(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfacc((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfadd(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfadd((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfcmpeq(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfcmpeq((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfcmpge(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfcmpge((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfcmpgt(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfcmpgt((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfmax(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfmax((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfmin(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfmin((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfmul(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfmul((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfrcp(__m64 __m) { + return (__m64)__builtin_ia32_pfrcp((__v2sf)__m); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfrcpit1(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfrcpit1((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfrcpit2(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfrcpit2((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfrsqrt(__m64 __m) { + return (__m64)__builtin_ia32_pfrsqrt((__v2sf)__m); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfrsqrtit1(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfrsqrtit1((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfsub(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfsub((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfsubr(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfsubr((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pi2fd(__m64 __m) { + return (__m64)__builtin_ia32_pi2fd((__v2si)__m); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pmulhrw(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pmulhrw((__v4hi)__m1, (__v4hi)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pf2iw(__m64 __m) { + return (__m64)__builtin_ia32_pf2iw((__v2sf)__m); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfnacc(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfnacc((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pfpnacc(__m64 __m1, __m64 __m2) { + return (__m64)__builtin_ia32_pfpnacc((__v2sf)__m1, (__v2sf)__m2); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pi2fw(__m64 __m) { + return (__m64)__builtin_ia32_pi2fw((__v2si)__m); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pswapdsf(__m64 __m) { + return (__m64)__builtin_ia32_pswapdsf((__v2sf)__m); +} + +static __inline__ __m64 __attribute__((__always_inline__, __nodebug__)) +_m_pswapdsi(__m64 __m) { + return (__m64)__builtin_ia32_pswapdsi((__v2si)__m); +} + +#endif diff --git a/contrib/llvm/tools/clang/lib/Headers/mm_malloc.h b/contrib/llvm/tools/clang/lib/Headers/mm_malloc.h index e7da543..ec92362 100644 --- a/contrib/llvm/tools/clang/lib/Headers/mm_malloc.h +++ b/contrib/llvm/tools/clang/lib/Headers/mm_malloc.h @@ -40,6 +40,7 @@ extern "C" int posix_memalign(void **memptr, size_t alignment, size_t size); #endif #endif +#if !(defined(_WIN32) && defined(_mm_malloc)) static __inline__ void *__attribute__((__always_inline__, __nodebug__, __malloc__)) _mm_malloc(size_t size, size_t align) @@ -67,5 +68,6 @@ _mm_free(void *p) { free(p); } +#endif #endif /* __MM_MALLOC_H */ diff --git a/contrib/llvm/tools/clang/lib/Headers/stddef.h b/contrib/llvm/tools/clang/lib/Headers/stddef.h index 7cc0bc1..9e87ee89 100644 --- a/contrib/llvm/tools/clang/lib/Headers/stddef.h +++ b/contrib/llvm/tools/clang/lib/Headers/stddef.h @@ -26,7 +26,10 @@ #ifndef __STDDEF_H #define __STDDEF_H +#ifndef _PTRDIFF_T +#define _PTRDIFF_T typedef __typeof__(((int*)0)-((int*)0)) ptrdiff_t; +#endif #ifndef _SIZE_T #define _SIZE_T typedef __typeof__(sizeof(int)) size_t; @@ -51,7 +54,7 @@ typedef __WCHAR_TYPE__ wchar_t; #endif /* __STDDEF_H */ /* Some C libraries expect to see a wint_t here. Others (notably MinGW) will use -__WINT_TYPE__ directly; accomodate both by requiring __need_wint_t */ +__WINT_TYPE__ directly; accommodate both by requiring __need_wint_t */ #if defined(__need_wint_t) #if !defined(_WINT_T) #define _WINT_T diff --git a/contrib/llvm/tools/clang/lib/Headers/stdint.h b/contrib/llvm/tools/clang/lib/Headers/stdint.h index 9498ed5..6f1a876 100644 --- a/contrib/llvm/tools/clang/lib/Headers/stdint.h +++ b/contrib/llvm/tools/clang/lib/Headers/stdint.h @@ -46,7 +46,7 @@ * and 64-bit widths regardless of whether there are corresponding exact-width * types. * - * To accomodate targets that are missing types that are exactly 8, 16, 32, or + * To accommodate targets that are missing types that are exactly 8, 16, 32, or * 64 bits wide, this implementation takes an approach of cascading * redefintions, redefining __int_leastN_t to successively smaller exact-width * types. It is therefore important that the types are defined in order of @@ -58,7 +58,7 @@ * * In violation of the standard, some targets do not implement a type that is * wide enough to represent all of the required widths (8-, 16-, 32-, 64-bit). - * To accomodate these targets, a required minimum-width type is only + * To accommodate these targets, a required minimum-width type is only * defined if there exists an exact-width type of equal or greater width. */ @@ -609,11 +609,15 @@ typedef __UINTMAX_TYPE__ uintmax_t; # define UINT_FAST8_MAX __UINT_LEAST8_MAX #endif /* __INT_LEAST8_MIN */ +/* Some utility macros */ +#define __INTN_MIN(n) __stdint_join3( INT, n, _MIN) +#define __INTN_MAX(n) __stdint_join3( INT, n, _MAX) +#define __UINTN_MAX(n) __stdint_join3(UINT, n, _MAX) +#define __INTN_C(n, v) __stdint_join3( INT, n, _C(v)) +#define __UINTN_C(n, v) __stdint_join3(UINT, n, _C(v)) + /* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */ /* C99 7.18.3 Limits of other integer types. */ -#define __INTN_MIN(n) __stdint_join3( INT, n, _MIN) -#define __INTN_MAX(n) __stdint_join3( INT, n, _MAX) -#define __UINTN_MAX(n) __stdint_join3(UINT, n, _MAX) #define INTPTR_MIN __INTN_MIN(__INTPTR_WIDTH__) #define INTPTR_MAX __INTN_MAX(__INTPTR_WIDTH__) @@ -630,23 +634,26 @@ typedef __UINTMAX_TYPE__ uintmax_t; /* C99 7.18.3 Limits of other integer types. */ #define SIG_ATOMIC_MIN __INTN_MIN(__SIG_ATOMIC_WIDTH__) #define SIG_ATOMIC_MAX __INTN_MAX(__SIG_ATOMIC_WIDTH__) -#define WINT_MIN __INTN_MIN(__WINT_WIDTH__) -#define WINT_MAX __INTN_MAX(__WINT_WIDTH__) +#ifdef __WINT_UNSIGNED__ +# define WINT_MIN __UINTN_C(__WINT_WIDTH__, 0) +# define WINT_MAX __UINTN_MAX(__WINT_WIDTH__) +#else +# define WINT_MIN __INTN_MIN(__WINT_WIDTH__) +# define WINT_MAX __INTN_MAX(__WINT_WIDTH__) +#endif -/* FIXME: if we ever support a target with unsigned wchar_t, this should be - * 0 .. Max. - */ #ifndef WCHAR_MAX -#define WCHAR_MAX __INTN_MAX(__WCHAR_WIDTH__) +# define WCHAR_MAX __WCHAR_MAX__ #endif #ifndef WCHAR_MIN -#define WCHAR_MIN __INTN_MIN(__WCHAR_WIDTH__) +# if __WCHAR_MAX__ == __INTN_MAX(__WCHAR_WIDTH__) +# define WCHAR_MIN __INTN_MIN(__WCHAR_WIDTH__) +# else +# define WCHAR_MIN __UINTN_C(__WCHAR_WIDTH__, 0) +# endif #endif /* 7.18.4.2 Macros for greatest-width integer constants. */ -#define __INTN_C(n, v) __stdint_join3( INT, n, _C(v)) -#define __UINTN_C(n, v) __stdint_join3(UINT, n, _C(v)) - #define INTMAX_C(v) __INTN_C(__INTMAX_WIDTH__, v) #define UINTMAX_C(v) __UINTN_C(__INTMAX_WIDTH__, v) diff --git a/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h b/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h index 42dd3e8..00760ed 100644 --- a/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h +++ b/contrib/llvm/tools/clang/lib/Headers/xmmintrin.h @@ -539,7 +539,7 @@ _mm_load_ps(const float *p) static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_loadu_ps(const float *p) { - return __builtin_ia32_loadups(p); + return (__m128){ p[0], p[1], p[2], p[3] }; } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) diff --git a/contrib/llvm/tools/clang/lib/Index/DeclReferenceMap.cpp b/contrib/llvm/tools/clang/lib/Index/DeclReferenceMap.cpp index d6e30ab..3fd4336 100644 --- a/contrib/llvm/tools/clang/lib/Index/DeclReferenceMap.cpp +++ b/contrib/llvm/tools/clang/lib/Index/DeclReferenceMap.cpp @@ -55,7 +55,7 @@ void RefMapper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { } void RefMapper::VisitTypedefTypeLoc(TypedefTypeLoc TL) { - NamedDecl *ND = TL.getTypedefDecl(); + NamedDecl *ND = TL.getTypedefNameDecl(); Map.insert(std::make_pair(ND, ASTLocation(CurrentDecl, ND, TL.getNameLoc()))); } diff --git a/contrib/llvm/tools/clang/lib/Index/Entity.cpp b/contrib/llvm/tools/clang/lib/Index/Entity.cpp index 749dcc8..afac05c 100644 --- a/contrib/llvm/tools/clang/lib/Index/Entity.cpp +++ b/contrib/llvm/tools/clang/lib/Index/Entity.cpp @@ -141,7 +141,7 @@ Entity EntityGetter::VisitVarDecl(VarDecl *D) { } Entity EntityGetter::VisitFunctionDecl(FunctionDecl *D) { - // If it's static it cannot be refered to by another translation unit. + // If it's static it cannot be referred to by another translation unit. if (D->getStorageClass() == SC_Static) return Entity(D); diff --git a/contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp b/contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp index e424f91..e102a6d 100644 --- a/contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/HeaderMap.cpp @@ -199,8 +199,8 @@ void HeaderMap::dump() const { /// LookupFile - Check to see if the specified relative filename is located in /// this HeaderMap. If so, open it and return its FileEntry. -const FileEntry *HeaderMap::LookupFile(llvm::StringRef Filename, - FileManager &FM) const { +const FileEntry *HeaderMap::LookupFile( + llvm::StringRef Filename, FileManager &FM) const { const HMapHeader &Hdr = getHeader(); unsigned NumBuckets = getEndianAdjustedWord(Hdr.NumBuckets); diff --git a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp index b028e33..372078c 100644 --- a/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/HeaderSearch.cpp @@ -114,8 +114,11 @@ const char *DirectoryLookup::getName() const { /// LookupFile - Lookup the specified file in this search path, returning it /// if it exists or returning null if not. -const FileEntry *DirectoryLookup::LookupFile(llvm::StringRef Filename, - HeaderSearch &HS) const { +const FileEntry *DirectoryLookup::LookupFile( + llvm::StringRef Filename, + HeaderSearch &HS, + llvm::SmallVectorImpl<char> *SearchPath, + llvm::SmallVectorImpl<char> *RelativePath) const { llvm::SmallString<1024> TmpDir; if (isNormalDir()) { // Concatenate the requested file onto the directory. @@ -123,21 +126,46 @@ const FileEntry *DirectoryLookup::LookupFile(llvm::StringRef Filename, TmpDir += getDir()->getName(); TmpDir.push_back('/'); TmpDir.append(Filename.begin(), Filename.end()); - return HS.getFileMgr().getFile(TmpDir.str()); + if (SearchPath != NULL) { + llvm::StringRef SearchPathRef(getDir()->getName()); + SearchPath->clear(); + SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); + } + if (RelativePath != NULL) { + RelativePath->clear(); + RelativePath->append(Filename.begin(), Filename.end()); + } + return HS.getFileMgr().getFile(TmpDir.str(), /*openFile=*/true); } if (isFramework()) - return DoFrameworkLookup(Filename, HS); + return DoFrameworkLookup(Filename, HS, SearchPath, RelativePath); assert(isHeaderMap() && "Unknown directory lookup"); - return getHeaderMap()->LookupFile(Filename, HS.getFileMgr()); + const FileEntry * const Result = getHeaderMap()->LookupFile( + Filename, HS.getFileMgr()); + if (Result) { + if (SearchPath != NULL) { + llvm::StringRef SearchPathRef(getName()); + SearchPath->clear(); + SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); + } + if (RelativePath != NULL) { + RelativePath->clear(); + RelativePath->append(Filename.begin(), Filename.end()); + } + } + return Result; } /// DoFrameworkLookup - Do a lookup of the specified file in the current /// DirectoryLookup, which is a framework directory. -const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename, - HeaderSearch &HS) const { +const FileEntry *DirectoryLookup::DoFrameworkLookup( + llvm::StringRef Filename, + HeaderSearch &HS, + llvm::SmallVectorImpl<char> *SearchPath, + llvm::SmallVectorImpl<char> *RelativePath) const { FileManager &FileMgr = HS.getFileMgr(); // Framework names must have a '/' in the filename. @@ -183,19 +211,37 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename, FrameworkDirCache = getFrameworkDir(); } + if (RelativePath != NULL) { + RelativePath->clear(); + RelativePath->append(Filename.begin()+SlashPos+1, Filename.end()); + } + // Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h" unsigned OrigSize = FrameworkName.size(); FrameworkName += "Headers/"; + + if (SearchPath != NULL) { + SearchPath->clear(); + // Without trailing '/'. + SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1); + } + FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end()); - if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str())) + if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(), + /*openFile=*/true)) { return FE; + } // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h" const char *Private = "Private"; FrameworkName.insert(FrameworkName.begin()+OrigSize, Private, Private+strlen(Private)); - return FileMgr.getFile(FrameworkName.str()); + if (SearchPath != NULL) + SearchPath->insert(SearchPath->begin()+OrigSize, Private, + Private+strlen(Private)); + + return FileMgr.getFile(FrameworkName.str(), /*openFile=*/true); } @@ -209,11 +255,14 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup(llvm::StringRef Filename, /// for system #include's or not (i.e. using <> instead of ""). CurFileEnt, if /// non-null, indicates where the #including file is, in case a relative search /// is needed. -const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename, - bool isAngled, - const DirectoryLookup *FromDir, - const DirectoryLookup *&CurDir, - const FileEntry *CurFileEnt) { +const FileEntry *HeaderSearch::LookupFile( + llvm::StringRef Filename, + bool isAngled, + const DirectoryLookup *FromDir, + const DirectoryLookup *&CurDir, + const FileEntry *CurFileEnt, + llvm::SmallVectorImpl<char> *SearchPath, + llvm::SmallVectorImpl<char> *RelativePath) { // If 'Filename' is absolute, check to see if it exists and no searching. if (llvm::sys::path::is_absolute(Filename)) { CurDir = 0; @@ -221,8 +270,14 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename, // If this was an #include_next "/absolute/file", fail. if (FromDir) return 0; + if (SearchPath != NULL) + SearchPath->clear(); + if (RelativePath != NULL) { + RelativePath->clear(); + RelativePath->append(Filename.begin(), Filename.end()); + } // Otherwise, just return the file. - return FileMgr.getFile(Filename); + return FileMgr.getFile(Filename, /*openFile=*/true); } // Step #0, unless disabled, check to see if the file is in the #includer's @@ -237,7 +292,7 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename, TmpDir += CurFileEnt->getDir()->getName(); TmpDir.push_back('/'); TmpDir.append(Filename.begin(), Filename.end()); - if (const FileEntry *FE = FileMgr.getFile(TmpDir.str())) { + if (const FileEntry *FE = FileMgr.getFile(TmpDir.str(),/*openFile=*/true)) { // Leave CurDir unset. // This file is a system header or C++ unfriendly if the old file is. // @@ -246,6 +301,15 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename, // of evaluation. unsigned DirInfo = getFileInfo(CurFileEnt).DirInfo; getFileInfo(FE).DirInfo = DirInfo; + if (SearchPath != NULL) { + llvm::StringRef SearchPathRef(CurFileEnt->getDir()->getName()); + SearchPath->clear(); + SearchPath->append(SearchPathRef.begin(), SearchPathRef.end()); + } + if (RelativePath != NULL) { + RelativePath->clear(); + RelativePath->append(Filename.begin(), Filename.end()); + } return FE; } } @@ -283,7 +347,7 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename, // Check each directory in sequence to see if it contains this file. for (; i != SearchDirs.size(); ++i) { const FileEntry *FE = - SearchDirs[i].LookupFile(Filename, *this); + SearchDirs[i].LookupFile(Filename, *this, SearchPath, RelativePath); if (!FE) continue; CurDir = &SearchDirs[i]; @@ -308,7 +372,9 @@ const FileEntry *HeaderSearch::LookupFile(llvm::StringRef Filename, /// for the designated file, otherwise return null. const FileEntry *HeaderSearch:: LookupSubframeworkHeader(llvm::StringRef Filename, - const FileEntry *ContextFileEnt) { + const FileEntry *ContextFileEnt, + llvm::SmallVectorImpl<char> *SearchPath, + llvm::SmallVectorImpl<char> *RelativePath) { assert(ContextFileEnt && "No context file?"); // Framework names must have a '/' in the filename. Find it. @@ -356,17 +422,34 @@ LookupSubframeworkHeader(llvm::StringRef Filename, const FileEntry *FE = 0; + if (RelativePath != NULL) { + RelativePath->clear(); + RelativePath->append(Filename.begin()+SlashPos+1, Filename.end()); + } + // Check ".../Frameworks/HIToolbox.framework/Headers/HIToolbox.h" llvm::SmallString<1024> HeadersFilename(FrameworkName); HeadersFilename += "Headers/"; + if (SearchPath != NULL) { + SearchPath->clear(); + // Without trailing '/'. + SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1); + } + HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end()); - if (!(FE = FileMgr.getFile(HeadersFilename.str()))) { + if (!(FE = FileMgr.getFile(HeadersFilename.str(), /*openFile=*/true))) { // Check ".../Frameworks/HIToolbox.framework/PrivateHeaders/HIToolbox.h" HeadersFilename = FrameworkName; HeadersFilename += "PrivateHeaders/"; + if (SearchPath != NULL) { + SearchPath->clear(); + // Without trailing '/'. + SearchPath->append(HeadersFilename.begin(), HeadersFilename.end()-1); + } + HeadersFilename.append(Filename.begin()+SlashPos+1, Filename.end()); - if (!(FE = FileMgr.getFile(HeadersFilename.str()))) + if (!(FE = FileMgr.getFile(HeadersFilename.str(), /*openFile=*/true))) return 0; } diff --git a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp index b17198b..16cc4f8 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Lexer.cpp @@ -71,9 +71,22 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, "We assume that the input buffer has a null character at the end" " to simplify lexing!"); + // Check whether we have a BOM in the beginning of the buffer. If yes - act + // accordingly. Right now we support only UTF-8 with and without BOM, so, just + // skip the UTF-8 BOM if it's present. + if (BufferStart == BufferPtr) { + // Determine the size of the BOM. + size_t BOMLength = llvm::StringSwitch<size_t>(BufferStart) + .StartsWith("\xEF\xBB\xBF", 3) // UTF-8 BOM + .Default(0); + + // Skip the BOM. + BufferPtr += BOMLength; + } + Is_PragmaLexer = false; IsInConflictMarker = false; - + // Start of the file is a start of line. IsAtStartOfLine = true; @@ -178,7 +191,7 @@ Lexer *Lexer::Create_PragmaLexer(SourceLocation SpellingLoc, InstantiationLocEnd, TokLen); // Ensure that the lexer thinks it is inside a directive, so that end \n will - // return an EOM token. + // return an EOD token. L->ParsingPreprocessorDirective = true; // This lexer really is for _Pragma. @@ -221,6 +234,54 @@ void Lexer::Stringify(llvm::SmallVectorImpl<char> &Str) { /// after trigraph expansion and escaped-newline folding. In particular, this /// wants to get the true, uncanonicalized, spelling of things like digraphs /// UCNs, etc. +llvm::StringRef Lexer::getSpelling(SourceLocation loc, + llvm::SmallVectorImpl<char> &buffer, + const SourceManager &SM, + const LangOptions &options, + bool *invalid) { + // Break down the source location. + std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(loc); + + // Try to the load the file buffer. + bool invalidTemp = false; + llvm::StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); + if (invalidTemp) { + if (invalid) *invalid = true; + return llvm::StringRef(); + } + + const char *tokenBegin = file.data() + locInfo.second; + + // Lex from the start of the given location. + Lexer lexer(SM.getLocForStartOfFile(locInfo.first), options, + file.begin(), tokenBegin, file.end()); + Token token; + lexer.LexFromRawLexer(token); + + unsigned length = token.getLength(); + + // Common case: no need for cleaning. + if (!token.needsCleaning()) + return llvm::StringRef(tokenBegin, length); + + // Hard case, we need to relex the characters into the string. + buffer.clear(); + buffer.reserve(length); + + for (const char *ti = tokenBegin, *te = ti + length; ti != te; ) { + unsigned charSize; + buffer.push_back(Lexer::getCharAndSizeNoWarn(ti, charSize, options)); + ti += charSize; + } + + return llvm::StringRef(buffer.data(), buffer.size()); +} + +/// getSpelling() - Return the 'spelling' of this token. The spelling of a +/// token are the characters used to represent the token in the source file +/// after trigraph expansion and escaped-newline folding. In particular, this +/// wants to get the true, uncanonicalized, spelling of things like digraphs +/// UCNs, etc. std::string Lexer::getSpelling(const Token &Tok, const SourceManager &SourceMgr, const LangOptions &Features, bool *Invalid) { assert((int)Tok.getLength() >= 0 && "Token character range is bogus!"); @@ -626,7 +687,7 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset, else return Loc; - return AdvanceToTokenCharacter(Loc, Len, SM, Features); + return Loc.getFileLocWithOffset(Len); } //===----------------------------------------------------------------------===// @@ -1407,7 +1468,7 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { return SaveBCPLComment(Result, CurPtr); // If we are inside a preprocessor directive and we see the end of line, - // return immediately, so that the lexer can return this as an EOM token. + // return immediately, so that the lexer can return this as an EOD token. if (ParsingPreprocessorDirective || CurPtr == BufferEnd) { BufferPtr = CurPtr; return false; @@ -1534,7 +1595,7 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr, /// some tokens, this will store the first token and return true. bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { // Scan one character past where we should, looking for a '/' character. Once - // we find it, check to see if it was preceeded by a *. This common + // we find it, check to see if it was preceded by a *. This common // optimization helps people who like to put a lot of * characters in their // comments. @@ -1715,14 +1776,14 @@ std::string Lexer::ReadToEndOfLine() { assert(CurPtr[-1] == Char && "Trigraphs for newline?"); BufferPtr = CurPtr-1; - // Next, lex the character, which should handle the EOM transition. + // Next, lex the character, which should handle the EOD transition. Lex(Tmp); if (Tmp.is(tok::code_completion)) { if (PP && PP->getCodeCompletionHandler()) PP->getCodeCompletionHandler()->CodeCompleteNaturalLanguage(); Lex(Tmp); } - assert(Tmp.is(tok::eom) && "Unexpected token!"); + assert(Tmp.is(tok::eod) && "Unexpected token!"); // Finally, we're done, return the string we found. return Result; @@ -1758,7 +1819,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { // Done parsing the "line". ParsingPreprocessorDirective = false; // Update the location of token as well as BufferPtr. - FormTokenWithChars(Result, CurPtr, tok::eom); + FormTokenWithChars(Result, CurPtr, tok::eod); // Restore comment saving mode, in case it was disabled for directive. SetCommentRetentionState(PP->getCommentRetentionState()); @@ -2006,7 +2067,7 @@ LexNextToken: case '\n': case '\r': // If we are inside a preprocessor directive and we see the end of line, - // we know we are done with the directive, so return an EOM token. + // we know we are done with the directive, so return an EOD token. if (ParsingPreprocessorDirective) { // Done parsing the "line". ParsingPreprocessorDirective = false; @@ -2017,7 +2078,7 @@ LexNextToken: // Since we consumed a newline, we are back at the start of a line. IsAtStartOfLine = true; - Kind = tok::eom; + Kind = tok::eod; break; } // The returned token is at the start of the line. @@ -2043,7 +2104,7 @@ LexNextToken: // If the next token is obviously a // or /* */ comment, skip it efficiently // too (without going through the big switch stmt). if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() && - Features.BCPLComment) { + Features.BCPLComment && !Features.TraditionalCPP) { if (SkipBCPLComment(Result, CurPtr+2)) return; // There is a token to return. goto SkipIgnoredUnits; @@ -2232,8 +2293,10 @@ LexNextToken: // this as "foo / bar" and langauges with BCPL comments would lex it as // "foo". Check to see if the character after the second slash is a '*'. // If so, we will lex that as a "/" instead of the start of a comment. - if (Features.BCPLComment || - getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') { + // However, we never do this in -traditional-cpp mode. + if ((Features.BCPLComment || + getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') && + !Features.TraditionalCPP) { if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result))) return; // There is a token to return. @@ -2335,6 +2398,21 @@ LexNextToken: CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::lessequal; } else if (Features.Digraphs && Char == ':') { // '<:' -> '[' + if (Features.CPlusPlus0x && + getCharAndSize(CurPtr + SizeTmp, SizeTmp2) == ':') { + // C++0x [lex.pptoken]p3: + // Otherwise, if the next three characters are <:: and the subsequent + // character is neither : nor >, the < is treated as a preprocessor + // token by itself and not as the first character of the alternative + // token <:. + unsigned SizeTmp3; + char After = getCharAndSize(CurPtr + SizeTmp + SizeTmp2, SizeTmp3); + if (After != ':' && After != '>') { + Kind = tok::less; + break; + } + } + CurPtr = ConsumeChar(CurPtr, SizeTmp, Result); Kind = tok::l_square; } else if (Features.Digraphs && Char == '%') { // '<%' -> '{' diff --git a/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp b/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp index 16d7b36..37e7bf4 100644 --- a/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/LiteralSupport.cpp @@ -710,7 +710,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, ++begin; // FIXME: The "Value" is an uint64_t so we can handle char literals of - // upto 64-bits. + // up to 64-bits. // FIXME: This extensively assumes that 'char' is 8-bits. assert(PP.getTargetInfo().getCharWidth() == 8 && "Assumes char is 8 bits"); diff --git a/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp b/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp index 89f6368..dee7da3 100644 --- a/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/MacroArgs.cpp @@ -284,7 +284,7 @@ const Token &MacroArgs::getStringifiedArgument(unsigned ArgNo, assert(ArgNo < NumUnexpArgTokens && "Invalid argument number!"); if (StringifiedArgs.empty()) { StringifiedArgs.resize(getNumArguments()); - memset(&StringifiedArgs[0], 0, + memset((void*)&StringifiedArgs[0], 0, sizeof(StringifiedArgs[0])*getNumArguments()); } if (StringifiedArgs[ArgNo].isNot(tok::string_literal)) diff --git a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp index 3e871ae..af3fa6e 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPDirectives.cpp @@ -81,17 +81,17 @@ void Preprocessor::ReleaseMacroInfo(MacroInfo *MI) { } /// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the -/// current line until the tok::eom token is found. +/// current line until the tok::eod token is found. void Preprocessor::DiscardUntilEndOfDirective() { Token Tmp; do { LexUnexpandedToken(Tmp); assert(Tmp.isNot(tok::eof) && "EOF seen while discarding directive tokens"); - } while (Tmp.isNot(tok::eom)); + } while (Tmp.isNot(tok::eod)); } /// ReadMacroName - Lex and validate a macro name, which occurs after a -/// #define or #undef. This sets the token kind to eom and discards the rest +/// #define or #undef. This sets the token kind to eod and discards the rest /// of the macro line if the macro name is invalid. isDefineUndef is 1 if /// this is due to a a #define, 2 if #undef directive, 0 if it is something /// else (e.g. #ifdef). @@ -107,7 +107,7 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) { } // Missing macro name? - if (MacroNameTok.is(tok::eom)) { + if (MacroNameTok.is(tok::eod)) { Diag(MacroNameTok, diag::err_pp_missing_macro_name); return; } @@ -143,13 +143,13 @@ void Preprocessor::ReadMacroName(Token &MacroNameTok, char isDefineUndef) { } // Invalid macro name, read and discard the rest of the line. Then set the - // token kind to tok::eom. - MacroNameTok.setKind(tok::eom); + // token kind to tok::eod. + MacroNameTok.setKind(tok::eod); return DiscardUntilEndOfDirective(); } -/// CheckEndOfDirective - Ensure that the next token is a tok::eom token. If -/// not, emit a diagnostic and consume up until the eom. If EnableMacros is +/// CheckEndOfDirective - Ensure that the next token is a tok::eod token. If +/// not, emit a diagnostic and consume up until the eod. If EnableMacros is /// true, then we consider macros that expand to zero tokens as being ok. void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) { Token Tmp; @@ -166,7 +166,7 @@ void Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) { while (Tmp.is(tok::comment)) // Skip comments in -C mode. LexUnexpandedToken(Tmp); - if (Tmp.isNot(tok::eom)) { + if (Tmp.isNot(tok::eod)) { // Add a fixit in GNU/C99/C++ mode. Don't offer a fixit for strict-C89, // or if this is a macro-style preprocessing directive, because it is more // trouble than it is worth to insert /**/ and check that there is no /**/ @@ -238,7 +238,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, // We just parsed a # character at the start of a line, so we're in // directive mode. Tell the lexer this so any newlines we see will be - // converted into an EOM token (this terminates the macro). + // converted into an EOD token (this terminates the macro). CurPPLexer->ParsingPreprocessorDirective = true; if (CurLexer) CurLexer->SetCommentRetentionState(false); @@ -425,7 +425,7 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() { if (!CondInfo.FoundNonSkip) { CondInfo.FoundNonSkip = true; - // Scan until the eom token. + // Scan until the eod token. CurPTHLexer->ParsingPreprocessorDirective = true; DiscardUntilEndOfDirective(); CurPTHLexer->ParsingPreprocessorDirective = false; @@ -469,10 +469,13 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() { /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file, /// return null on failure. isAngled indicates whether the file reference is /// for system #include's or not (i.e. using <> instead of ""). -const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename, - bool isAngled, - const DirectoryLookup *FromDir, - const DirectoryLookup *&CurDir) { +const FileEntry *Preprocessor::LookupFile( + llvm::StringRef Filename, + bool isAngled, + const DirectoryLookup *FromDir, + const DirectoryLookup *&CurDir, + llvm::SmallVectorImpl<char> *SearchPath, + llvm::SmallVectorImpl<char> *RelativePath) { // If the header lookup mechanism may be relative to the current file, pass in // info about where the current file is. const FileEntry *CurFileEnt = 0; @@ -494,8 +497,9 @@ const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename, // Do a standard file entry lookup. CurDir = CurDirLookup; - const FileEntry *FE = - HeaderInfo.LookupFile(Filename, isAngled, FromDir, CurDir, CurFileEnt); + const FileEntry *FE = HeaderInfo.LookupFile( + Filename, isAngled, FromDir, CurDir, CurFileEnt, + SearchPath, RelativePath); if (FE) return FE; // Otherwise, see if this is a subframework header. If so, this is relative @@ -503,7 +507,8 @@ const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename, // headers on the #include stack and pass them to HeaderInfo. if (IsFileLexer()) { if ((CurFileEnt = SourceMgr.getFileEntryForID(CurPPLexer->getFileID()))) - if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt))) + if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt, + SearchPath, RelativePath))) return FE; } @@ -512,7 +517,8 @@ const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename, if (IsFileLexer(ISEntry)) { if ((CurFileEnt = SourceMgr.getFileEntryForID(ISEntry.ThePPLexer->getFileID()))) - if ((FE = HeaderInfo.LookupSubframeworkHeader(Filename, CurFileEnt))) + if ((FE = HeaderInfo.LookupSubframeworkHeader( + Filename, CurFileEnt, SearchPath, RelativePath))) return FE; } } @@ -535,7 +541,7 @@ void Preprocessor::HandleDirective(Token &Result) { // We just parsed a # character at the start of a line, so we're in directive // mode. Tell the lexer this so any newlines we see will be converted into an - // EOM token (which terminates the directive). + // EOD token (which terminates the directive). CurPPLexer->ParsingPreprocessorDirective = true; ++NumDirectives; @@ -563,7 +569,7 @@ void Preprocessor::HandleDirective(Token &Result) { TryAgain: switch (Result.getKind()) { - case tok::eom: + case tok::eod: return; // null directive. case tok::comment: // Handle stuff like "# /*foo*/ define X" in -E -C mode. @@ -686,7 +692,7 @@ static bool GetLineValue(Token &DigitTok, unsigned &Val, if (DigitTok.isNot(tok::numeric_constant)) { PP.Diag(DigitTok, DiagID); - if (DigitTok.isNot(tok::eom)) + if (DigitTok.isNot(tok::eod)) PP.DiscardUntilEndOfDirective(); return true; } @@ -758,9 +764,9 @@ void Preprocessor::HandleLineDirective(Token &Tok) { Token StrTok; Lex(StrTok); - // If the StrTok is "eom", then it wasn't present. Otherwise, it must be a - // string followed by eom. - if (StrTok.is(tok::eom)) + // If the StrTok is "eod", then it wasn't present. Otherwise, it must be a + // string followed by eod. + if (StrTok.is(tok::eod)) ; // ok else if (StrTok.isNot(tok::string_literal)) { Diag(StrTok, diag::err_pp_line_invalid_filename); @@ -779,7 +785,7 @@ void Preprocessor::HandleLineDirective(Token &Tok) { FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString(), Literal.GetStringLength()); - // Verify that there is nothing after the string, other than EOM. Because + // Verify that there is nothing after the string, other than EOD. Because // of C99 6.10.4p5, macros that expand to empty tokens are ok. CheckEndOfDirective("line", true); } @@ -800,7 +806,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, unsigned FlagVal; Token FlagTok; PP.Lex(FlagTok); - if (FlagTok.is(tok::eom)) return false; + if (FlagTok.is(tok::eod)) return false; if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag, PP)) return true; @@ -808,7 +814,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, IsFileEntry = true; PP.Lex(FlagTok); - if (FlagTok.is(tok::eom)) return false; + if (FlagTok.is(tok::eod)) return false; if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag,PP)) return true; } else if (FlagVal == 2) { @@ -834,7 +840,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, } PP.Lex(FlagTok); - if (FlagTok.is(tok::eom)) return false; + if (FlagTok.is(tok::eod)) return false; if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag,PP)) return true; } @@ -849,7 +855,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, IsSystemHeader = true; PP.Lex(FlagTok); - if (FlagTok.is(tok::eom)) return false; + if (FlagTok.is(tok::eod)) return false; if (GetLineValue(FlagTok, FlagVal, diag::err_pp_linemarker_invalid_flag, PP)) return true; @@ -863,7 +869,7 @@ static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, IsExternCHeader = true; PP.Lex(FlagTok); - if (FlagTok.is(tok::eom)) return false; + if (FlagTok.is(tok::eod)) return false; // There are no more valid flags here. PP.Diag(FlagTok, diag::err_pp_linemarker_invalid_flag); @@ -893,9 +899,9 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) { bool IsSystemHeader = false, IsExternCHeader = false; int FilenameID = -1; - // If the StrTok is "eom", then it wasn't present. Otherwise, it must be a - // string followed by eom. - if (StrTok.is(tok::eom)) + // If the StrTok is "eod", then it wasn't present. Otherwise, it must be a + // string followed by eod. + if (StrTok.is(tok::eod)) ; // ok else if (StrTok.isNot(tok::string_literal)) { Diag(StrTok, diag::err_pp_linemarker_invalid_filename); @@ -978,12 +984,12 @@ void Preprocessor::HandleIdentSCCSDirective(Token &Tok) { if (StrTok.isNot(tok::string_literal) && StrTok.isNot(tok::wide_string_literal)) { Diag(StrTok, diag::err_pp_malformed_ident); - if (StrTok.isNot(tok::eom)) + if (StrTok.isNot(tok::eod)) DiscardUntilEndOfDirective(); return; } - // Verify that there is nothing after the string, other than EOM. + // Verify that there is nothing after the string, other than EOD. CheckEndOfDirective("ident"); if (Callbacks) { @@ -1052,14 +1058,14 @@ bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, /// /// This code concatenates and consumes tokens up to the '>' token. It returns /// false if the > was found, otherwise it returns true if it finds and consumes -/// the EOM marker. +/// the EOD marker. bool Preprocessor::ConcatenateIncludeName( llvm::SmallString<128> &FilenameBuffer, SourceLocation &End) { Token CurTok; Lex(CurTok); - while (CurTok.isNot(tok::eom)) { + while (CurTok.isNot(tok::eod)) { End = CurTok.getLocation(); // FIXME: Provide code completion for #includes. @@ -1095,8 +1101,8 @@ bool Preprocessor::ConcatenateIncludeName( Lex(CurTok); } - // If we hit the eom marker, emit an error and return true so that the caller - // knows the EOM has been read. + // If we hit the eod marker, emit an error and return true so that the caller + // knows the EOD has been read. Diag(CurTok.getLocation(), diag::err_pp_expects_filename); return true; } @@ -1120,8 +1126,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, SourceLocation End; switch (FilenameTok.getKind()) { - case tok::eom: - // If the token kind is EOM, the error has already been diagnosed. + case tok::eod: + // If the token kind is EOD, the error has already been diagnosed. return; case tok::angle_string_literal: @@ -1135,7 +1141,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // case, glue the tokens together into FilenameBuffer and interpret those. FilenameBuffer.push_back('<'); if (ConcatenateIncludeName(FilenameBuffer, End)) - return; // Found <eom> but no ">"? Diagnostic already emitted. + return; // Found <eod> but no ">"? Diagnostic already emitted. Filename = FilenameBuffer.str(); break; default: @@ -1153,7 +1159,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, return; } - // Verify that there is nothing after the filename, other than EOM. Note that + // Verify that there is nothing after the filename, other than EOD. Note that // we allow macros that expand to nothing after the filename, because this // falls into the category of "#include pp-tokens new-line" specified in // C99 6.10.2p4. @@ -1167,7 +1173,13 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // Search include directories. const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(Filename, isAngled, LookupFrom, CurDir); + llvm::SmallString<1024> SearchPath; + llvm::SmallString<1024> RelativePath; + // We get the raw path only if we have 'Callbacks' to which we later pass + // the path. + const FileEntry *File = LookupFile( + Filename, isAngled, LookupFrom, CurDir, + Callbacks ? &SearchPath : NULL, Callbacks ? &RelativePath : NULL); if (File == 0) { Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; @@ -1175,9 +1187,9 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, // Notify the callback object that we've seen an inclusion directive. if (Callbacks) - Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File, - End); - + Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File, + End, SearchPath, RelativePath); + // The #included file will be considered to be a system header if either it is // in a system include directory, or if the #includer is a system include // header. @@ -1302,7 +1314,7 @@ bool Preprocessor::ReadMacroDefinitionArgList(MacroInfo *MI) { MI->setIsC99Varargs(); MI->setArgumentList(&Arguments[0], Arguments.size(), BP); return false; - case tok::eom: // #define X( + case tok::eod: // #define X( Diag(Tok, diag::err_pp_missing_rparen_in_macro_def); return true; default: @@ -1366,7 +1378,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { ReadMacroName(MacroNameTok, 1); // Error reading macro name? If so, diagnostic already issued. - if (MacroNameTok.is(tok::eom)) + if (MacroNameTok.is(tok::eod)) return; Token LastTok = MacroNameTok; @@ -1384,7 +1396,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { // If this is a function-like macro definition, parse the argument list, // marking each of the identifiers as being used as macro arguments. Also, // check other constraints on the first token of the macro body. - if (Tok.is(tok::eom)) { + if (Tok.is(tok::eod)) { // If there is no body to this macro, we have no special handling here. } else if (Tok.hasLeadingSpace()) { // This is a normal token with leading space. Clear the leading space @@ -1439,13 +1451,13 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { Diag(Tok, diag::warn_missing_whitespace_after_macro_name); } - if (!Tok.is(tok::eom)) + if (!Tok.is(tok::eod)) LastTok = Tok; // Read the rest of the macro body. if (MI->isObjectLike()) { // Object-like macros are very simple, just read their body. - while (Tok.isNot(tok::eom)) { + while (Tok.isNot(tok::eod)) { LastTok = Tok; MI->AddTokenToBody(Tok); // Get the next token of the macro. @@ -1456,7 +1468,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { // Otherwise, read the body of a function-like macro. While we are at it, // check C99 6.10.3.2p1: ensure that # operators are followed by macro // parameters in function-like macro expansions. - while (Tok.isNot(tok::eom)) { + while (Tok.isNot(tok::eod)) { LastTok = Tok; if (Tok.isNot(tok::hash)) { @@ -1478,7 +1490,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { // the '#' because '#' is often a comment character. However, change // the kind of the token to tok::unknown so that the preprocessor isn't // confused. - if (getLangOptions().AsmPreprocessor && Tok.isNot(tok::eom)) { + if (getLangOptions().AsmPreprocessor && Tok.isNot(tok::eod)) { LastTok.setKind(tok::unknown); } else { Diag(Tok, diag::err_pp_stringize_not_parameter); @@ -1504,7 +1516,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { // Disable __VA_ARGS__ again. Ident__VA_ARGS__->setIsPoisoned(true); - // Check that there is no paste (##) operator at the begining or end of the + // Check that there is no paste (##) operator at the beginning or end of the // replacement list. unsigned NumTokens = MI->getNumTokens(); if (NumTokens != 0) { @@ -1573,7 +1585,7 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) { ReadMacroName(MacroNameTok, 2); // Error reading macro name? If so, diagnostic already issued. - if (MacroNameTok.is(tok::eom)) + if (MacroNameTok.is(tok::eod)) return; // Check to see if this is the last token on the #undef line. @@ -1619,7 +1631,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result, bool isIfndef, ReadMacroName(MacroNameTok); // Error reading macro name? If so, diagnostic already issued. - if (MacroNameTok.is(tok::eom)) { + if (MacroNameTok.is(tok::eod)) { // Skip code until we get to #endif. This helps with recovery by not // emitting an error when the #endif is reached. SkipExcludedConditionalBlock(DirectiveTok.getLocation(), diff --git a/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp b/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp index 1451c5a..8fcfc70 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPExpressions.cpp @@ -180,7 +180,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, default: // Non-value token. PP.Diag(PeekTok, diag::err_pp_expr_bad_token_start_expr); return true; - case tok::eom: + case tok::eod: case tok::r_paren: // If there is no expression, report and exit. PP.Diag(PeekTok, diag::err_pp_expected_value_in_expr); @@ -372,7 +372,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, /// token. This returns: /// ~0 - Invalid token. /// 14 -> 3 - various operators. -/// 0 - 'eom' or ')' +/// 0 - 'eod' or ')' static unsigned getPrecedence(tok::TokenKind Kind) { switch (Kind) { default: return ~0U; @@ -397,8 +397,8 @@ static unsigned getPrecedence(tok::TokenKind Kind) { case tok::question: return 4; case tok::comma: return 3; case tok::colon: return 2; - case tok::r_paren: return 0; // Lowest priority, end of expr. - case tok::eom: return 0; // Lowest priority, end of macro. + case tok::r_paren: return 0;// Lowest priority, end of expr. + case tok::eod: return 0;// Lowest priority, end of directive. } } @@ -713,7 +713,7 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { DefinedTracker DT; if (EvaluateValue(ResVal, Tok, DT, true, *this)) { // Parse error, skip the rest of the macro line. - if (Tok.isNot(tok::eom)) + if (Tok.isNot(tok::eod)) DiscardUntilEndOfDirective(); // Restore 'DisableMacroExpansion'. @@ -724,7 +724,7 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { // If we are at the end of the expression after just parsing a value, there // must be no (unparenthesized) binary operators involved, so we can exit // directly. - if (Tok.is(tok::eom)) { + if (Tok.is(tok::eod)) { // If the expression we parsed was of the form !defined(macro), return the // macro in IfNDefMacro. if (DT.State == DefinedTracker::NotDefinedMacro) @@ -740,7 +740,7 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { if (EvaluateDirectiveSubExpr(ResVal, getPrecedence(tok::question), Tok, true, *this)) { // Parse error, skip the rest of the macro line. - if (Tok.isNot(tok::eom)) + if (Tok.isNot(tok::eod)) DiscardUntilEndOfDirective(); // Restore 'DisableMacroExpansion'. @@ -748,9 +748,9 @@ EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro) { return false; } - // If we aren't at the tok::eom token, something bad happened, like an extra + // If we aren't at the tok::eod token, something bad happened, like an extra // ')' token. - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { Diag(Tok, diag::err_pp_expected_eol); DiscardUntilEndOfDirective(); } diff --git a/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp b/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp index eef42b6..bf0a7fb 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPLexerChange.cpp @@ -301,7 +301,7 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) { // We handle this by scanning for the closest real lexer, switching it to // raw mode and preprocessor mode. This will cause it to return \n as an - // explicit EOM token. + // explicit EOD token. PreprocessorLexer *FoundLexer = 0; bool LexerWasInPPMode = false; for (unsigned i = 0, e = IncludeMacroStack.size(); i != e; ++i) { @@ -309,11 +309,11 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) { if (ISI.ThePPLexer == 0) continue; // Scan for a real lexer. // Once we find a real lexer, mark it as raw mode (disabling macro - // expansions) and preprocessor mode (return EOM). We know that the lexer + // expansions) and preprocessor mode (return EOD). We know that the lexer // was *not* in raw mode before, because the macro that the comment came // from was expanded. However, it could have already been in preprocessor // mode (#if COMMENT) in which case we have to return it to that mode and - // return EOM. + // return EOD. FoundLexer = ISI.ThePPLexer; FoundLexer->LexingRawMode = true; LexerWasInPPMode = FoundLexer->ParsingPreprocessorDirective; @@ -326,22 +326,22 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) { // the next token. if (!HandleEndOfTokenLexer(Tok)) Lex(Tok); - // Discarding comments as long as we don't have EOF or EOM. This 'comments + // Discarding comments as long as we don't have EOF or EOD. This 'comments // out' the rest of the line, including any tokens that came from other macros // that were active, as in: // #define submacro a COMMENT b // submacro c // which should lex to 'a' only: 'b' and 'c' should be removed. - while (Tok.isNot(tok::eom) && Tok.isNot(tok::eof)) + while (Tok.isNot(tok::eod) && Tok.isNot(tok::eof)) Lex(Tok); - // If we got an eom token, then we successfully found the end of the line. - if (Tok.is(tok::eom)) { + // If we got an eod token, then we successfully found the end of the line. + if (Tok.is(tok::eod)) { assert(FoundLexer && "Can't get end of line without an active lexer"); // Restore the lexer back to normal mode instead of raw mode. FoundLexer->LexingRawMode = false; - // If the lexer was already in preprocessor mode, just return the EOM token + // If the lexer was already in preprocessor mode, just return the EOD token // to finish the preprocessor line. if (LexerWasInPPMode) return; @@ -352,7 +352,7 @@ void Preprocessor::HandleMicrosoftCommentPaste(Token &Tok) { // If we got an EOF token, then we reached the end of the token stream but // didn't find an explicit \n. This can only happen if there was no lexer - // active (an active lexer would return EOM at EOF if there was no \n in + // active (an active lexer would return EOD at EOF if there was no \n in // preprocessor directive mode), so just return EOF as our token. - assert(!FoundLexer && "Lexer should return EOM before EOF in PP mode"); + assert(!FoundLexer && "Lexer should return EOD before EOF in PP mode"); } diff --git a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp index ba92614..d6e0d3a 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PPMacroExpansion.cpp @@ -176,8 +176,6 @@ bool Preprocessor::isNextPPTokenLParen() { /// expanded as a macro, handle it and return the next token as 'Identifier'. bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, MacroInfo *MI) { - if (Callbacks) Callbacks->MacroExpands(Identifier, MI); - // If this is a macro expansion in the "#if !defined(x)" line for the file, // then the macro could expand to different things in other contexts, we need // to disable the optimization in this case. @@ -185,6 +183,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // If this is a builtin macro, like __LINE__ or _Pragma, handle it specially. if (MI->isBuiltinMacro()) { + if (Callbacks) Callbacks->MacroExpands(Identifier, MI); ExpandBuiltinMacro(Identifier); return false; } @@ -225,8 +224,13 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, // Notice that this macro has been used. markMacroAsUsed(MI); + if (Callbacks) Callbacks->MacroExpands(Identifier, MI); + // If we started lexing a macro, enter the macro expansion body. + // Remember where the token is instantiated. + SourceLocation InstantiateLoc = Identifier.getLocation(); + // If this macro expands to no tokens, don't bother to push it onto the // expansion stack, only to take it right back off. if (MI->getNumTokens() == 0) { @@ -249,6 +253,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, if (HadLeadingSpace) Identifier.setFlag(Token::LeadingSpace); } Identifier.setFlag(Token::LeadingEmptyMacro); + LastEmptyMacroInstantiationLoc = InstantiateLoc; ++NumFastMacroExpanded; return false; @@ -267,9 +272,6 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, bool isAtStartOfLine = Identifier.isAtStartOfLine(); bool hasLeadingSpace = Identifier.hasLeadingSpace(); - // Remember where the token is instantiated. - SourceLocation InstantiateLoc = Identifier.getLocation(); - // Replace the result token. Identifier = MI->getReplacementToken(0); @@ -355,9 +357,9 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, LexUnexpandedToken(Tok); } - if (Tok.is(tok::eof) || Tok.is(tok::eom)) { // "#if f(<eof>" & "#if f(\n" + if (Tok.is(tok::eof) || Tok.is(tok::eod)) { // "#if f(<eof>" & "#if f(\n" Diag(MacroName, diag::err_unterm_macro_invoc); - // Do not lose the EOF/EOM. Return it to the client. + // Do not lose the EOF/EOD. Return it to the client. MacroName = Tok; return 0; } else if (Tok.is(tok::r_paren)) { @@ -410,9 +412,9 @@ MacroArgs *Preprocessor::ReadFunctionLikeMacroArgs(Token &MacroName, return 0; } - // Empty arguments are standard in C99 and supported as an extension in + // Empty arguments are standard in C99 and C++0x, and are supported as an extension in // other modes. - if (ArgTokens.size() == ArgTokenStart && !Features.C99) + if (ArgTokens.size() == ArgTokenStart && !Features.C99 && !Features.CPlusPlus0x) Diag(Tok, diag::ext_empty_fnmacro_arg); // Add a marker EOF token to the end of the token list for this argument. @@ -530,6 +532,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { return llvm::StringSwitch<bool>(II->getName()) .Case("attribute_analyzer_noreturn", true) + .Case("attribute_availability", true) .Case("attribute_cf_returns_not_retained", true) .Case("attribute_cf_returns_retained", true) .Case("attribute_deprecated_with_message", true) @@ -540,12 +543,14 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("attribute_ns_consumed", true) .Case("attribute_cf_consumed", true) .Case("attribute_objc_ivar_unused", true) + .Case("attribute_objc_method_family", true) .Case("attribute_overloadable", true) .Case("attribute_unavailable_with_message", true) .Case("blocks", LangOpts.Blocks) .Case("cxx_exceptions", LangOpts.Exceptions) .Case("cxx_rtti", LangOpts.RTTI) .Case("enumerator_attributes", true) + .Case("generic_selections", true) .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI) .Case("objc_weak_class", LangOpts.ObjCNonFragileABI) .Case("ownership_holds", true) @@ -556,10 +561,14 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("cxx_auto_type", LangOpts.CPlusPlus0x) .Case("cxx_decltype", LangOpts.CPlusPlus0x) .Case("cxx_default_function_template_args", LangOpts.CPlusPlus0x) + .Case("cxx_delegating_constructors", LangOpts.CPlusPlus0x) .Case("cxx_deleted_functions", LangOpts.CPlusPlus0x) .Case("cxx_inline_namespaces", LangOpts.CPlusPlus0x) //.Case("cxx_lambdas", false) + .Case("cxx_noexcept", LangOpts.CPlusPlus0x) //.Case("cxx_nullptr", false) + .Case("cxx_override_control", LangOpts.CPlusPlus0x) + .Case("cxx_range_for", LangOpts.CPlusPlus0x) .Case("cxx_reference_qualified_functions", LangOpts.CPlusPlus0x) .Case("cxx_rvalue_references", LangOpts.CPlusPlus0x) .Case("cxx_strong_enums", LangOpts.CPlusPlus0x) @@ -581,10 +590,11 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("is_convertible_to", LangOpts.CPlusPlus) .Case("is_empty", LangOpts.CPlusPlus) .Case("is_enum", LangOpts.CPlusPlus) + .Case("is_literal", LangOpts.CPlusPlus) .Case("is_pod", LangOpts.CPlusPlus) .Case("is_polymorphic", LangOpts.CPlusPlus) + .Case("is_trivial", LangOpts.CPlusPlus) .Case("is_union", LangOpts.CPlusPlus) - .Case("is_literal", LangOpts.CPlusPlus) .Case("tls", PP.getTargetInfo().isTLSSupported()) .Default(false); } @@ -626,8 +636,8 @@ static bool EvaluateHasIncludeCommon(Token &Tok, SourceLocation EndLoc; switch (Tok.getKind()) { - case tok::eom: - // If the token kind is EOM, the error has already been diagnosed. + case tok::eod: + // If the token kind is EOD, the error has already been diagnosed. return false; case tok::angle_string_literal: @@ -644,7 +654,7 @@ static bool EvaluateHasIncludeCommon(Token &Tok, // case, glue the tokens together into FilenameBuffer and interpret those. FilenameBuffer.push_back('<'); if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc)) - return false; // Found <eom> but no ">"? Diagnostic already emitted. + return false; // Found <eod> but no ">"? Diagnostic already emitted. Filename = FilenameBuffer.str(); break; default: @@ -660,7 +670,8 @@ static bool EvaluateHasIncludeCommon(Token &Tok, // Search include directories. const DirectoryLookup *CurDir; - const FileEntry *File = PP.LookupFile(Filename, isAngled, LookupFrom, CurDir); + const FileEntry *File = + PP.LookupFile(Filename, isAngled, LookupFrom, CurDir, NULL, NULL); // Get the result value. Result = true means the file exists. bool Result = File != 0; diff --git a/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp index 975753b..e5ef0fd 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PTHLexer.cpp @@ -125,7 +125,7 @@ LexNextToken: return PP->Lex(Tok); } - if (TKind == tok::eom) { + if (TKind == tok::eod) { assert(ParsingPreprocessorDirective); ParsingPreprocessorDirective = false; return; @@ -527,7 +527,7 @@ PTHManager *PTHManager::Create(const std::string &file, Diagnostic &Diags) { // Get the number of IdentifierInfos and pre-allocate the identifier cache. uint32_t NumIds = ReadLE32(IData); - // Pre-allocate the peristent ID -> IdentifierInfo* cache. We use calloc() + // Pre-allocate the persistent ID -> IdentifierInfo* cache. We use calloc() // so that we in the best case only zero out memory once when the OS returns // us new pages. IdentifierInfo** PerIDCache = 0; diff --git a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp index 80d3bb1..0c18091 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Pragma.cpp @@ -229,8 +229,8 @@ void Preprocessor::HandleMicrosoft__pragma(Token &Tok) { PragmaToks.front().setFlag(Token::LeadingSpace); - // Replace the ')' with an EOM to mark the end of the pragma. - PragmaToks.back().setKind(tok::eom); + // Replace the ')' with an EOD to mark the end of the pragma. + PragmaToks.back().setKind(tok::eod); Token *TokArray = new Token[PragmaToks.size()]; std::copy(PragmaToks.begin(), PragmaToks.end(), TokArray); @@ -283,7 +283,7 @@ void Preprocessor::HandlePragmaPoison(Token &PoisonTok) { if (CurPPLexer) CurPPLexer->LexingRawMode = false; // If we reached the end of line, we're done. - if (Tok.is(tok::eom)) return; + if (Tok.is(tok::eod)) return; // Can only poison identifiers. if (Tok.isNot(tok::raw_identifier)) { @@ -348,8 +348,8 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { Token FilenameTok; CurPPLexer->LexIncludeFilename(FilenameTok); - // If the token kind is EOM, the error has already been diagnosed. - if (FilenameTok.is(tok::eom)) + // If the token kind is EOD, the error has already been diagnosed. + if (FilenameTok.is(tok::eod)) return; // Reserve a buffer to get the spelling. @@ -368,7 +368,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { // Search include directories for this file. const DirectoryLookup *CurDir; - const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir); + const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir, NULL, NULL); if (File == 0) { Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; return; @@ -381,7 +381,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { // Lex tokens at the end of the message and include them in the message. std::string Message; Lex(DependencyTok); - while (DependencyTok.isNot(tok::eom)) { + while (DependencyTok.isNot(tok::eod)) { Message += getSpelling(DependencyTok) + " "; Lex(DependencyTok); } @@ -470,7 +470,7 @@ void Preprocessor::HandlePragmaComment(Token &Tok) { } Lex(Tok); // eat the r_paren. - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); return; } @@ -541,7 +541,7 @@ void Preprocessor::HandlePragmaMessage(Token &Tok) { Lex(Tok); // eat the r_paren. } - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { Diag(Tok.getLocation(), diag::err_pragma_message_malformed); return; } @@ -737,10 +737,10 @@ bool Preprocessor::LexOnOffSwitch(tok::OnOffSwitch &Result) { return true; } - // Verify that this is followed by EOM. + // Verify that this is followed by EOD. LexUnexpandedToken(Tok); - if (Tok.isNot(tok::eom)) - Diag(Tok, diag::ext_pragma_syntax_eom); + if (Tok.isNot(tok::eod)) + Diag(Tok, diag::ext_pragma_syntax_eod); return false; } @@ -883,7 +883,7 @@ public: PP.LexUnexpandedToken(Tok); } - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_diagnostic_invalid_token); return; } diff --git a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp index 3a43ac1..9555611 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PreprocessingRecord.cpp @@ -146,12 +146,15 @@ void PreprocessingRecord::MacroUndefined(const Token &Id, MacroDefinitions.erase(Pos); } -void PreprocessingRecord::InclusionDirective(SourceLocation HashLoc, - const clang::Token &IncludeTok, - llvm::StringRef FileName, - bool IsAngled, - const FileEntry *File, - clang::SourceLocation EndLoc) { +void PreprocessingRecord::InclusionDirective( + SourceLocation HashLoc, + const clang::Token &IncludeTok, + llvm::StringRef FileName, + bool IsAngled, + const FileEntry *File, + clang::SourceLocation EndLoc, + llvm::StringRef SearchPath, + llvm::StringRef RelativePath) { InclusionDirective::InclusionKind Kind = InclusionDirective::Include; switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) { diff --git a/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp b/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp index 6fe414b..31fd667 100644 --- a/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/Preprocessor.cpp @@ -89,6 +89,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro. // This gets unpoisoned where it is allowed. (Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned(); + SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use); // Initialize the pragma handlers. PragmaHandlers = new PragmaNamespace(llvm::StringRef()); @@ -96,6 +97,23 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, // Initialize builtin macros like __LINE__ and friends. RegisterBuiltinMacros(); + + if(Features.Borland) { + Ident__exception_info = getIdentifierInfo("_exception_info"); + Ident___exception_info = getIdentifierInfo("__exception_info"); + Ident_GetExceptionInfo = getIdentifierInfo("GetExceptionInformation"); + Ident__exception_code = getIdentifierInfo("_exception_code"); + Ident___exception_code = getIdentifierInfo("__exception_code"); + Ident_GetExceptionCode = getIdentifierInfo("GetExceptionCode"); + Ident__abnormal_termination = getIdentifierInfo("_abnormal_termination"); + Ident___abnormal_termination = getIdentifierInfo("__abnormal_termination"); + Ident_AbnormalTermination = getIdentifierInfo("AbnormalTermination"); + } else { + Ident__exception_info = Ident__exception_code = Ident__abnormal_termination = 0; + Ident___exception_info = Ident___exception_code = Ident___abnormal_termination = 0; + Ident_GetExceptionInfo = Ident_GetExceptionCode = Ident_AbnormalTermination = 0; + } + } Preprocessor::~Preprocessor() { @@ -278,7 +296,6 @@ void Preprocessor::CodeCompleteNaturalLanguage() { CodeComplete->CodeCompleteNaturalLanguage(); } - /// getSpelling - This method is used to get the spelling of a token into a /// SmallVector. Note that the returned StringRef may not point to the /// supplied buffer if a copy can be avoided. @@ -400,6 +417,34 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const { return II; } +void Preprocessor::SetPoisonReason(IdentifierInfo *II, unsigned DiagID) { + PoisonReasons[II] = DiagID; +} + +void Preprocessor::PoisonSEHIdentifiers(bool Poison) { + assert(Ident__exception_code && Ident__exception_info); + assert(Ident___exception_code && Ident___exception_info); + Ident__exception_code->setIsPoisoned(Poison); + Ident___exception_code->setIsPoisoned(Poison); + Ident_GetExceptionCode->setIsPoisoned(Poison); + Ident__exception_info->setIsPoisoned(Poison); + Ident___exception_info->setIsPoisoned(Poison); + Ident_GetExceptionInfo->setIsPoisoned(Poison); + Ident__abnormal_termination->setIsPoisoned(Poison); + Ident___abnormal_termination->setIsPoisoned(Poison); + Ident_AbnormalTermination->setIsPoisoned(Poison); +} + +void Preprocessor::HandlePoisonedIdentifier(Token & Identifier) { + assert(Identifier.getIdentifierInfo() && + "Can't handle identifiers without identifier info!"); + llvm::DenseMap<IdentifierInfo*,unsigned>::const_iterator it = + PoisonReasons.find(Identifier.getIdentifierInfo()); + if(it == PoisonReasons.end()) + Diag(Identifier, diag::err_pp_used_poisoned_id); + else + Diag(Identifier,it->second) << Identifier.getIdentifierInfo(); +} /// HandleIdentifier - This callback is invoked when the lexer reads an /// identifier. This callback looks up the identifier in the map and/or @@ -418,10 +463,7 @@ void Preprocessor::HandleIdentifier(Token &Identifier) { // If this identifier was poisoned, and if it was not produced from a macro // expansion, emit an error. if (II.isPoisoned() && CurPPLexer) { - if (&II != Ident__VA_ARGS__) // We warn about __VA_ARGS__ with poisoning. - Diag(Identifier, diag::err_pp_used_poisoned_id); - else - Diag(Identifier, diag::ext_pp_bad_vaargs_use); + HandlePoisonedIdentifier(Identifier); } // If this is a macro to be expanded, do it. diff --git a/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp index e005c49..808a81b 100644 --- a/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/PreprocessorLexer.cpp @@ -34,7 +34,7 @@ void PreprocessorLexer::LexIncludeFilename(Token &FilenameTok) { ParsingFilename = false; // No filename? - if (FilenameTok.is(tok::eom)) + if (FilenameTok.is(tok::eod)) PP->Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); } diff --git a/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp b/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp index caa44bf..65aff0d 100644 --- a/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp +++ b/contrib/llvm/tools/clang/lib/Lex/TokenLexer.cpp @@ -367,11 +367,7 @@ void TokenLexer::Lex(Token &Tok) { // won't be handled by Preprocessor::HandleIdentifier because this is coming // from a macro expansion. if (II->isPoisoned() && TokenIsFromPaste) { - // We warn about __VA_ARGS__ with poisoning. - if (II->isStr("__VA_ARGS__")) - PP.Diag(Tok, diag::ext_pp_bad_vaargs_use); - else - PP.Diag(Tok, diag::err_pp_used_poisoned_id); + PP.HandlePoisonedIdentifier(Tok); } if (!DisableMacroExpansion && II->isHandleIdentifierCase()) @@ -546,7 +542,7 @@ unsigned TokenLexer::isNextTokenLParen() const { /// isParsingPreprocessorDirective - Return true if we are in the middle of a /// preprocessor directive. bool TokenLexer::isParsingPreprocessorDirective() const { - return Tokens[NumTokens-1].is(tok::eom) && !isAtEnd(); + return Tokens[NumTokens-1].is(tok::eod) && !isAtEnd(); } /// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp index edb1675..21917b2 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseAST.cpp @@ -21,6 +21,8 @@ #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Stmt.h" #include "clang/Parse/Parser.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/CrashRecoveryContext.h" #include <cstdio> using namespace clang; @@ -37,8 +39,15 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, ASTContext &Ctx, bool PrintStats, bool CompleteTranslationUnit, CodeCompleteConsumer *CompletionConsumer) { - Sema S(PP, Ctx, *Consumer, CompleteTranslationUnit, CompletionConsumer); - ParseAST(S, PrintStats); + + llvm::OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer, + CompleteTranslationUnit, + CompletionConsumer)); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleaupSema(S.get()); + + ParseAST(*S.get(), PrintStats); } void clang::ParseAST(Sema &S, bool PrintStats) { @@ -50,7 +59,15 @@ void clang::ParseAST(Sema &S, bool PrintStats) { ASTConsumer *Consumer = &S.getASTConsumer(); - Parser P(S.getPreprocessor(), S); + llvm::OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S)); + Parser &P = *ParseOP.get(); + + PrettyStackTraceParserEntry CrashInfo(P); + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<Parser> + CleaupParser(ParseOP.get()); + S.getPreprocessor().EnterMainSourceFile(); P.Initialize(); S.Initialize(); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp index 3994738..87e2f34 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/Parser.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Scope.h" +#include "clang/AST/DeclTemplate.h" using namespace clang; /// ParseCXXInlineMethodDef - We parsed and verified that the specified @@ -37,13 +38,6 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, true, move(TemplateParams)); else { // FIXME: pass template information through - if (VS.isOverrideSpecified()) - Diag(VS.getOverrideLoc(), diag::ext_override_inline) << "override"; - if (VS.isFinalSpecified()) - Diag(VS.getFinalLoc(), diag::ext_override_inline) << "final"; - if (VS.isNewSpecified()) - Diag(VS.getNewLoc(), diag::ext_override_inline) << "new"; - FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, move(TemplateParams), 0, VS, 0, /*IsDefinition*/true); @@ -53,6 +47,37 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, D.complete(FnD); + // In delayed template parsing mode, if we are within a class template + // or if we are about to parse function member template then consume + // the tokens and store them for parsing at the end of the translation unit. + if (getLang().DelayedTemplateParsing && + ((Actions.CurContext->isDependentContext() || + TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) && + !Actions.IsInsideALocalClassWithinATemplateFunction()) && + !D.getDeclSpec().isFriendSpecified()) { + + if (FnD) { + LateParsedTemplatedFunction *LPT = + new LateParsedTemplatedFunction(this, FnD); + + FunctionDecl *FD = 0; + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(FnD)) + FD = FunTmpl->getTemplatedDecl(); + else + FD = cast<FunctionDecl>(FnD); + Actions.CheckForFunctionRedefinition(FD); + + LateParsedTemplateMap[FD] = LPT; + Actions.MarkAsLateParsedTemplate(FD); + LexTemplateFunctionForLateParsing(LPT->Toks); + } else { + CachedTokens Toks; + LexTemplateFunctionForLateParsing(Toks); + } + + return FnD; + } + // Consume the tokens and store them for later parsing. LexedMethod* LM = new LexedMethod(this, FnD); @@ -94,6 +119,14 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, ParsingDeclarator &D, } } + + if (!FnD) { + // If semantic analysis could not build a function declaration, + // just throw away the late-parsed declaration. + delete getCurrentClass().LateParsedDeclarations.back(); + getCurrentClass().LateParsedDeclarations.pop_back(); + } + return FnD; } @@ -261,7 +294,7 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D); if (Tok.is(tok::kw_try)) { - ParseFunctionTryBlock(LM.D); + ParseFunctionTryBlock(LM.D, FnScope); assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, Tok.getLocation()) && "ParseFunctionTryBlock went over the cached tokens!"); @@ -276,13 +309,14 @@ void Parser::ParseLexedMethodDef(LexedMethod &LM) { // Error recovery. if (!Tok.is(tok::l_brace)) { + FnScope.Exit(); Actions.ActOnFinishFunctionBody(LM.D, 0); return; } } else Actions.ActOnDefaultCtorInitializers(LM.D); - ParseFunctionStatementBody(LM.D); + ParseFunctionStatementBody(LM.D, FnScope); if (Tok.getLocation() != origLoc) { // Due to parsing error, we either went over the cached tokens or diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp index 077edd7..a20e90b 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDecl.cpp @@ -13,6 +13,7 @@ #include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Basic/OpenCL.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/PrettyDeclStackTrace.h" @@ -32,7 +33,7 @@ using namespace clang; TypeResult Parser::ParseTypeName(SourceRange *Range, Declarator::TheContext Context) { // Parse the common declaration-specifiers piece. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); // Parse the abstract-declarator, if present. @@ -111,8 +112,11 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); + // Availability attributes have their own grammar. + if (AttrName->isStr("availability")) + ParseAvailabilityAttribute(*AttrName, AttrNameLoc, attrs, endLoc); // check if we have a "parameterized" attribute - if (Tok.is(tok::l_paren)) { + else if (Tok.is(tok::l_paren)) { ConsumeParen(); // ignore the left paren loc for now if (Tok.is(tok::identifier)) { @@ -122,8 +126,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, if (Tok.is(tok::r_paren)) { // __attribute__(( mode(byte) )) ConsumeParen(); // ignore the right paren loc for now - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, - ParmName, ParmLoc, 0, 0)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + ParmName, ParmLoc, 0, 0); } else if (Tok.is(tok::comma)) { ConsumeToken(); // __attribute__(( format(printf, 1, 2) )) @@ -146,9 +150,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, } if (ArgExprsOk && Tok.is(tok::r_paren)) { ConsumeParen(); // ignore the right paren loc for now - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, - AttrNameLoc, ParmName, ParmLoc, - ArgExprs.take(), ArgExprs.size())); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size()); } } } else { // not an identifier @@ -157,8 +160,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, // parse a possibly empty comma separated list of expressions // __attribute__(( nonnull() )) ConsumeParen(); // ignore the right paren loc for now - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0); break; case tok::kw_char: case tok::kw_wchar_t: @@ -168,6 +171,7 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, case tok::kw_short: case tok::kw_int: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_float: @@ -175,9 +179,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, case tok::kw_void: case tok::kw_typeof: { AttributeList *attr - = AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0); - attrs.add(attr); + = attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0); if (attr->getKind() == AttributeList::AT_IBOutletCollection) Diag(Tok, diag::err_iboutletcollection_builtintype); // If it's a builtin type name, eat it and expect a rparen @@ -209,16 +212,16 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, // Match the ')'. if (ArgExprsOk && Tok.is(tok::r_paren)) { ConsumeParen(); // ignore the right paren loc for now - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, - AttrNameLoc, 0, SourceLocation(), - ArgExprs.take(), ArgExprs.size())); + attrs.addNew(AttrName, AttrNameLoc, 0, + AttrNameLoc, 0, SourceLocation(), + ArgExprs.take(), ArgExprs.size()); } break; } } } else { - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) @@ -260,14 +263,14 @@ void Parser::ParseMicrosoftDeclSpec(ParsedAttributes &attrs) { ExprResult ArgExpr(ParseAssignmentExpression()); if (!ArgExpr.isInvalid()) { Expr *ExprList = ArgExpr.take(); - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), &ExprList, 1, true)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), &ExprList, 1, true); } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) SkipUntil(tok::r_paren, false); } else { - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, - 0, SourceLocation(), 0, 0, true)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, + 0, SourceLocation(), 0, 0, true); } } if (ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) @@ -286,8 +289,8 @@ void Parser::ParseMicrosoftTypeAttributes(ParsedAttributes &attrs) { if (Tok.is(tok::kw___ptr64) || Tok.is(tok::kw___w64)) // FIXME: Support these properly! continue; - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, true)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, true); } } @@ -296,8 +299,8 @@ void Parser::ParseBorlandTypeAttributes(ParsedAttributes &attrs) { while (Tok.is(tok::kw___pascal)) { IdentifierInfo *AttrName = Tok.getIdentifierInfo(); SourceLocation AttrNameLoc = ConsumeToken(); - attrs.add(AttrFactory.Create(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, true)); + attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, true); } } @@ -305,12 +308,334 @@ void Parser::ParseOpenCLAttributes(ParsedAttributes &attrs) { // Treat these like attributes while (Tok.is(tok::kw___kernel)) { SourceLocation AttrNameLoc = ConsumeToken(); - attrs.add(AttrFactory.Create(PP.getIdentifierInfo("opencl_kernel_function"), - AttrNameLoc, 0, AttrNameLoc, 0, - SourceLocation(), 0, 0, false)); + attrs.addNew(PP.getIdentifierInfo("opencl_kernel_function"), + AttrNameLoc, 0, AttrNameLoc, 0, + SourceLocation(), 0, 0, false); } } +void Parser::ParseOpenCLQualifiers(DeclSpec &DS) { + SourceLocation Loc = Tok.getLocation(); + switch(Tok.getKind()) { + // OpenCL qualifiers: + case tok::kw___private: + case tok::kw_private: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("address_space"), Loc, 0); + break; + + case tok::kw___global: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_global); + break; + + case tok::kw___local: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_local); + break; + + case tok::kw___constant: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("address_space"), Loc, LangAS::opencl_constant); + break; + + case tok::kw___read_only: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_only); + break; + + case tok::kw___write_only: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_write_only); + break; + + case tok::kw___read_write: + DS.getAttributes().addNewInteger( + Actions.getASTContext(), + PP.getIdentifierInfo("opencl_image_access"), Loc, CLIA_read_write); + break; + default: break; + } +} + +/// \brief Parse a version number. +/// +/// version: +/// simple-integer +/// simple-integer ',' simple-integer +/// simple-integer ',' simple-integer ',' simple-integer +VersionTuple Parser::ParseVersionTuple(SourceRange &Range) { + Range = Tok.getLocation(); + + if (!Tok.is(tok::numeric_constant)) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + // Parse the major (and possibly minor and subminor) versions, which + // are stored in the numeric constant. We utilize a quirk of the + // lexer, which is that it handles something like 1.2.3 as a single + // numeric constant, rather than two separate tokens. + llvm::SmallString<512> Buffer; + Buffer.resize(Tok.getLength()+1); + const char *ThisTokBegin = &Buffer[0]; + + // Get the spelling of the token, which eliminates trigraphs, etc. + bool Invalid = false; + unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid); + if (Invalid) + return VersionTuple(); + + // Parse the major version. + unsigned AfterMajor = 0; + unsigned Major = 0; + while (AfterMajor < ActualLength && isdigit(ThisTokBegin[AfterMajor])) { + Major = Major * 10 + ThisTokBegin[AfterMajor] - '0'; + ++AfterMajor; + } + + if (AfterMajor == 0) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + if (AfterMajor == ActualLength) { + ConsumeToken(); + + // We only had a single version component. + if (Major == 0) { + Diag(Tok, diag::err_zero_version); + return VersionTuple(); + } + + return VersionTuple(Major); + } + + if (ThisTokBegin[AfterMajor] != '.' || (AfterMajor + 1 == ActualLength)) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + // Parse the minor version. + unsigned AfterMinor = AfterMajor + 1; + unsigned Minor = 0; + while (AfterMinor < ActualLength && isdigit(ThisTokBegin[AfterMinor])) { + Minor = Minor * 10 + ThisTokBegin[AfterMinor] - '0'; + ++AfterMinor; + } + + if (AfterMinor == ActualLength) { + ConsumeToken(); + + // We had major.minor. + if (Major == 0 && Minor == 0) { + Diag(Tok, diag::err_zero_version); + return VersionTuple(); + } + + return VersionTuple(Major, Minor); + } + + // If what follows is not a '.', we have a problem. + if (ThisTokBegin[AfterMinor] != '.') { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + + // Parse the subminor version. + unsigned AfterSubminor = AfterMinor + 1; + unsigned Subminor = 0; + while (AfterSubminor < ActualLength && isdigit(ThisTokBegin[AfterSubminor])) { + Subminor = Subminor * 10 + ThisTokBegin[AfterSubminor] - '0'; + ++AfterSubminor; + } + + if (AfterSubminor != ActualLength) { + Diag(Tok, diag::err_expected_version); + SkipUntil(tok::comma, tok::r_paren, true, true, true); + return VersionTuple(); + } + ConsumeToken(); + return VersionTuple(Major, Minor, Subminor); +} + +/// \brief Parse the contents of the "availability" attribute. +/// +/// availability-attribute: +/// 'availability' '(' platform ',' version-arg-list ')' +/// +/// platform: +/// identifier +/// +/// version-arg-list: +/// version-arg +/// version-arg ',' version-arg-list +/// +/// version-arg: +/// 'introduced' '=' version +/// 'deprecated' '=' version +/// 'removed' = version +/// 'unavailable' +void Parser::ParseAvailabilityAttribute(IdentifierInfo &Availability, + SourceLocation AvailabilityLoc, + ParsedAttributes &attrs, + SourceLocation *endLoc) { + SourceLocation PlatformLoc; + IdentifierInfo *Platform = 0; + + enum { Introduced, Deprecated, Obsoleted, Unknown }; + AvailabilityChange Changes[Unknown]; + + // Opening '('. + SourceLocation LParenLoc; + if (!Tok.is(tok::l_paren)) { + Diag(Tok, diag::err_expected_lparen); + return; + } + LParenLoc = ConsumeParen(); + + // Parse the platform name, + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_availability_expected_platform); + SkipUntil(tok::r_paren); + return; + } + Platform = Tok.getIdentifierInfo(); + PlatformLoc = ConsumeToken(); + + // Parse the ',' following the platform name. + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "", tok::r_paren)) + return; + + // If we haven't grabbed the pointers for the identifiers + // "introduced", "deprecated", and "obsoleted", do so now. + if (!Ident_introduced) { + Ident_introduced = PP.getIdentifierInfo("introduced"); + Ident_deprecated = PP.getIdentifierInfo("deprecated"); + Ident_obsoleted = PP.getIdentifierInfo("obsoleted"); + Ident_unavailable = PP.getIdentifierInfo("unavailable"); + } + + // Parse the set of introductions/deprecations/removals. + SourceLocation UnavailableLoc; + do { + if (Tok.isNot(tok::identifier)) { + Diag(Tok, diag::err_availability_expected_change); + SkipUntil(tok::r_paren); + return; + } + IdentifierInfo *Keyword = Tok.getIdentifierInfo(); + SourceLocation KeywordLoc = ConsumeToken(); + + if (Keyword == Ident_unavailable) { + if (UnavailableLoc.isValid()) { + Diag(KeywordLoc, diag::err_availability_redundant) + << Keyword << SourceRange(UnavailableLoc); + } + UnavailableLoc = KeywordLoc; + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + continue; + } + + if (Tok.isNot(tok::equal)) { + Diag(Tok, diag::err_expected_equal_after) + << Keyword; + SkipUntil(tok::r_paren); + return; + } + ConsumeToken(); + + SourceRange VersionRange; + VersionTuple Version = ParseVersionTuple(VersionRange); + + if (Version.empty()) { + SkipUntil(tok::r_paren); + return; + } + + unsigned Index; + if (Keyword == Ident_introduced) + Index = Introduced; + else if (Keyword == Ident_deprecated) + Index = Deprecated; + else if (Keyword == Ident_obsoleted) + Index = Obsoleted; + else + Index = Unknown; + + if (Index < Unknown) { + if (!Changes[Index].KeywordLoc.isInvalid()) { + Diag(KeywordLoc, diag::err_availability_redundant) + << Keyword + << SourceRange(Changes[Index].KeywordLoc, + Changes[Index].VersionRange.getEnd()); + } + + Changes[Index].KeywordLoc = KeywordLoc; + Changes[Index].Version = Version; + Changes[Index].VersionRange = VersionRange; + } else { + Diag(KeywordLoc, diag::err_availability_unknown_change) + << Keyword << VersionRange; + } + + if (Tok.isNot(tok::comma)) + break; + + ConsumeToken(); + } while (true); + + // Closing ')'. + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + if (RParenLoc.isInvalid()) + return; + + if (endLoc) + *endLoc = RParenLoc; + + // The 'unavailable' availability cannot be combined with any other + // availability changes. Make sure that hasn't happened. + if (UnavailableLoc.isValid()) { + bool Complained = false; + for (unsigned Index = Introduced; Index != Unknown; ++Index) { + if (Changes[Index].KeywordLoc.isValid()) { + if (!Complained) { + Diag(UnavailableLoc, diag::warn_availability_and_unavailable) + << SourceRange(Changes[Index].KeywordLoc, + Changes[Index].VersionRange.getEnd()); + Complained = true; + } + + // Clear out the availability. + Changes[Index] = AvailabilityChange(); + } + } + } + + // Record this attribute + attrs.addNew(&Availability, AvailabilityLoc, + 0, SourceLocation(), + Platform, PlatformLoc, + Changes[Introduced], + Changes[Deprecated], + Changes[Obsoleted], + UnavailableLoc, false, false); +} + void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { Diag(attrs.Range.getBegin(), diag::err_attributes_not_allowed) << attrs.Range; @@ -329,7 +654,7 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { /// [C++] namespace-definition /// [C++] using-directive /// [C++] using-declaration -/// [C++0x] static_assert-declaration +/// [C++0x/C1X] static_assert-declaration /// others... [FIXME] /// Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, @@ -364,6 +689,7 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, DeclEnd, attrs); break; case tok::kw_static_assert: + case tok::kw__Static_assert: ProhibitAttributes(attrs); SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; @@ -381,33 +707,42 @@ Parser::DeclGroupPtrTy Parser::ParseDeclaration(StmtVector &Stmts, ///[C90/C++]init-declarator-list ';' [TODO] /// [OMP] threadprivate-directive [TODO] /// +/// for-range-declaration: [C++0x 6.5p1: stmt.ranged] +/// attribute-specifier-seq[opt] type-specifier-seq declarator +/// /// If RequireSemi is false, this does not check for a ';' at the end of the /// declaration. If it is true, it checks for and eats it. +/// +/// If FRI is non-null, we might be parsing a for-range-declaration instead +/// of a simple-declaration. If we find that we are, we also parse the +/// for-range-initializer, and place it here. Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, unsigned Context, SourceLocation &DeclEnd, ParsedAttributes &attrs, - bool RequireSemi) { + bool RequireSemi, + ForRangeInit *FRI) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); DS.takeAttributesFrom(attrs); + ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, getDeclSpecContextFromDeclaratorContext(Context)); StmtResult R = Actions.ActOnVlaStmt(DS); if (R.isUsable()) Stmts.push_back(R.release()); - + // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { if (RequireSemi) ConsumeToken(); Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, - DS); + DS); DS.complete(TheDecl); return Actions.ConvertDeclToDeclGroup(TheDecl); } - - return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd); + + return ParseDeclGroup(DS, Context, /*FunctionDefs=*/ false, &DeclEnd, FRI); } /// ParseDeclGroup - Having concluded that this is either a function @@ -416,7 +751,8 @@ Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration(StmtVector &Stmts, Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, bool AllowFunctionDefinitions, - SourceLocation *DeclEnd) { + SourceLocation *DeclEnd, + ForRangeInit *FRI) { // Parse the first declarator. ParsingDeclarator D(*this, DS, static_cast<Declarator::TheContext>(Context)); ParseDeclarator(D); @@ -462,8 +798,24 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, } } + if (ParseAttributesAfterDeclarator(D)) + return DeclGroupPtrTy(); + + // C++0x [stmt.iter]p1: Check if we have a for-range-declarator. If so, we + // must parse and analyze the for-range-initializer before the declaration is + // analyzed. + if (FRI && Tok.is(tok::colon)) { + FRI->ColonLoc = ConsumeToken(); + // FIXME: handle braced-init-list here. + FRI->RangeExpr = ParseExpression(); + Decl *ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); + Actions.ActOnCXXForRangeDecl(ThisDecl); + Actions.FinalizeDeclaration(ThisDecl); + return Actions.FinalizeDeclaratorGroup(getCurScope(), DS, &ThisDecl, 1); + } + llvm::SmallVector<Decl *, 8> DeclsInGroup; - Decl *FirstDecl = ParseDeclarationAfterDeclarator(D); + Decl *FirstDecl = ParseDeclarationAfterDeclaratorAndAttributes(D); D.complete(FirstDecl); if (FirstDecl) DeclsInGroup.push_back(FirstDecl); @@ -517,6 +869,26 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, DeclsInGroup.size()); } +/// Parse an optional simple-asm-expr and attributes, and attach them to a +/// declarator. Returns true on an error. +bool Parser::ParseAttributesAfterDeclarator(Declarator &D) { + // If a simple-asm-expr is present, parse it. + if (Tok.is(tok::kw_asm)) { + SourceLocation Loc; + ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + if (AsmLabel.isInvalid()) { + SkipUntil(tok::semi, true, true); + return true; + } + + D.setAsmLabel(AsmLabel.release()); + D.SetRangeEnd(Loc); + } + + MaybeParseGNUAttributes(D); + return false; +} + /// \brief Parse 'declaration' after parsing 'declaration-specifiers /// declarator'. This method parses the remainder of the declaration /// (including any attributes or initializer, among other things) and @@ -540,21 +912,14 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, /// Decl *Parser::ParseDeclarationAfterDeclarator(Declarator &D, const ParsedTemplateInfo &TemplateInfo) { - // If a simple-asm-expr is present, parse it. - if (Tok.is(tok::kw_asm)) { - SourceLocation Loc; - ExprResult AsmLabel(ParseSimpleAsm(&Loc)); - if (AsmLabel.isInvalid()) { - SkipUntil(tok::semi, true, true); - return 0; - } - - D.setAsmLabel(AsmLabel.release()); - D.SetRangeEnd(Loc); - } + if (ParseAttributesAfterDeclarator(D)) + return 0; - MaybeParseGNUAttributes(D); + return ParseDeclarationAfterDeclaratorAndAttributes(D, TemplateInfo); +} +Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, + const ParsedTemplateInfo &TemplateInfo) { // Inform the current actions module that we just parsed this declarator. Decl *ThisDecl = 0; switch (TemplateInfo.Kind) { @@ -780,21 +1145,25 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, // // C++ doesn't need this, and isTagName doesn't take SS. if (SS == 0) { - const char *TagName = 0; + const char *TagName = 0, *FixitTagName = 0; tok::TokenKind TagKind = tok::unknown; switch (Actions.isTagName(*Tok.getIdentifierInfo(), getCurScope())) { default: break; - case DeclSpec::TST_enum: TagName="enum" ;TagKind=tok::kw_enum ;break; - case DeclSpec::TST_union: TagName="union" ;TagKind=tok::kw_union ;break; - case DeclSpec::TST_struct:TagName="struct";TagKind=tok::kw_struct;break; - case DeclSpec::TST_class: TagName="class" ;TagKind=tok::kw_class ;break; + case DeclSpec::TST_enum: + TagName="enum" ; FixitTagName = "enum " ; TagKind=tok::kw_enum ;break; + case DeclSpec::TST_union: + TagName="union" ; FixitTagName = "union " ;TagKind=tok::kw_union ;break; + case DeclSpec::TST_struct: + TagName="struct"; FixitTagName = "struct ";TagKind=tok::kw_struct;break; + case DeclSpec::TST_class: + TagName="class" ; FixitTagName = "class " ;TagKind=tok::kw_class ;break; } if (TagName) { Diag(Loc, diag::err_use_of_tag_name_without_tag) << Tok.getIdentifierInfo() << TagName << getLang().CPlusPlus - << FixItHint::CreateInsertion(Tok.getLocation(),TagName); + << FixItHint::CreateInsertion(Tok.getLocation(),FixitTagName); // Parse this as a tag as if the missing tag were present. if (TagKind == tok::kw_enum) @@ -887,9 +1256,12 @@ Parser::getDeclSpecContextFromDeclaratorContext(unsigned Context) { void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, - DeclSpecContext DSContext) { - DS.SetRangeStart(Tok.getLocation()); - DS.SetRangeEnd(Tok.getLocation()); + DeclSpecContext DSContext) { + if (DS.getSourceRange().isInvalid()) { + DS.SetRangeStart(Tok.getLocation()); + DS.SetRangeEnd(Tok.getLocation()); + } + while (1) { bool isInvalid = false; const char *PrevSpec = 0; @@ -1013,7 +1385,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ConsumeToken(); // The C++ scope. assert(Tok.is(tok::annot_template_id) && "ParseOptionalCXXScopeSpecifier not working"); - AnnotateTemplateIdTokenAsType(&SS); + AnnotateTemplateIdTokenAsType(); continue; } @@ -1056,7 +1428,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), - getCurScope(), &SS); + getCurScope(), &SS, + false, false, ParsedType(), + /*NonTrivialSourceInfo=*/true); // If the referenced identifier is not a type, then this declspec is // erroneous: We already checked about that it has no type specifier, and @@ -1105,6 +1479,24 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, continue; } + case tok::kw___is_signed: + // GNU libstdc++ 4.4 uses __is_signed as an identifier, but Clang + // typically treats it as a trait. If we see __is_signed as it appears + // in libstdc++, e.g., + // + // static const bool __is_signed; + // + // then treat __is_signed as an identifier rather than as a keyword. + if (DS.getTypeSpecType() == TST_bool && + DS.getTypeQualifiers() == DeclSpec::TQ_const && + DS.getStorageClassSpec() == DeclSpec::SCS_static) { + Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); + Tok.setKind(tok::identifier); + } + + // We're done with the declaration-specifiers. + goto DoneWithDeclSpec; + // typedef-name case tok::identifier: { // In C++, check to see if this is a scope specifier like foo::bar::, if @@ -1247,7 +1639,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DiagID, getLang()); break; case tok::kw_auto: - if (getLang().CPlusPlus0x || getLang().ObjC2) { + if (getLang().CPlusPlus0x) { if (isKnownToBeTypeSpecifier(GetLookAheadToken(1))) { isInvalid = DS.SetStorageClassSpec(DeclSpec::SCS_auto, Loc, PrevSpec, DiagID, getLang()); @@ -1315,6 +1707,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID); break; + case tok::kw___int64: + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, + DiagID); + break; case tok::kw_signed: isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); @@ -1370,6 +1766,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DS.getStorageClassSpec() == DeclSpec::SCS_typedef) { PrevSpec = ""; // Not used by the diagnostic. DiagID = diag::err_bool_redeclaration; + // For better error recovery. + Tok.setKind(tok::identifier); isInvalid = true; } else { isInvalid = DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec, @@ -1394,6 +1792,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___pixel: isInvalid = DS.SetTypeAltiVecPixel(true, Loc, PrevSpec, DiagID); break; + case tok::kw___unknown_anytype: + isInvalid = DS.SetTypeSpecType(TST_unknown_anytype, Loc, + PrevSpec, DiagID); + break; // class-specifier: case tok::kw_class: @@ -1444,6 +1846,20 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, ParseDecltypeSpecifier(DS); continue; + // OpenCL qualifiers: + case tok::kw_private: + if (!getLang().OpenCL) + goto DoneWithDeclSpec; + case tok::kw___private: + case tok::kw___global: + case tok::kw___local: + case tok::kw___constant: + case tok::kw___read_only: + case tok::kw___write_only: + case tok::kw___read_write: + ParseOpenCLQualifiers(DS); + break; + case tok::less: // GCC ObjC supports types like "<SomeProtocol>" as a synonym for // "id<SomeProtocol>". This is hopelessly old fashioned and dangerous, @@ -1473,7 +1889,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } DS.SetRangeEnd(Tok.getLocation()); - ConsumeToken(); + if (DiagID != diag::err_bool_redeclaration) + ConsumeToken(); } } @@ -1592,6 +2009,10 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID); break; + case tok::kw___int64: + isInvalid = DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, + DiagID); + break; case tok::kw_signed: isInvalid = DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); break; @@ -1695,6 +2116,20 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, bool& isInvalid, ParseDecltypeSpecifier(DS); return true; + // OpenCL qualifiers: + case tok::kw_private: + if (!getLang().OpenCL) + return false; + case tok::kw___private: + case tok::kw___global: + case tok::kw___local: + case tok::kw___constant: + case tok::kw___read_only: + case tok::kw___write_only: + case tok::kw___read_write: + ParseOpenCLQualifiers(DS); + break; + // C++0x auto support. case tok::kw_auto: if (!getLang().CPlusPlus0x) @@ -1856,7 +2291,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, } // Parse all the comma separated declarators. - DeclSpec DS; + DeclSpec DS(AttrFactory); if (!Tok.is(tok::at)) { struct CFieldCallback : FieldCallback { @@ -1917,7 +2352,7 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); // If attributes exist after struct contents, parse them. MaybeParseGNUAttributes(attrs); @@ -1967,7 +2402,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, } // If attributes exist after tag, parse them. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); CXXScopeSpec &SS = DS.getTypeSpecScope(); @@ -2121,7 +2556,6 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, bool Owned = false; bool IsDependent = false; - SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; const char *PrevSpec = 0; unsigned DiagID; Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK, @@ -2148,8 +2582,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, return; } - if (DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, PrevSpec, DiagID, - Type.get())) + if (DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, Type.get())) Diag(StartLoc, DiagID) << PrevSpec; return; @@ -2170,10 +2605,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.is(tok::l_brace)) ParseEnumBody(StartLoc, TagDecl); - // FIXME: The DeclSpec should keep the locations of both the keyword - // and the name (if there is one). - if (DS.SetTypeSpecType(DeclSpec::TST_enum, TSTLoc, PrevSpec, DiagID, - TagDecl, Owned)) + if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, TagDecl, Owned)) Diag(StartLoc, DiagID) << PrevSpec; } @@ -2208,7 +2642,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { SourceLocation IdentLoc = ConsumeToken(); // If attributes exist after the enumerator, parse them. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); SourceLocation EqualLoc; @@ -2252,7 +2686,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { SourceLocation RBraceLoc = MatchRHSPunctuation(tok::r_brace, LBraceLoc); // If attributes exist after the identifier list, parse them. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); Actions.ActOnEnumBody(StartLoc, LBraceLoc, RBraceLoc, EnumDecl, @@ -2268,10 +2702,22 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { bool Parser::isTypeQualifier() const { switch (Tok.getKind()) { default: return false; + + // type-qualifier only in OpenCL + case tok::kw_private: + return getLang().OpenCL; + // type-qualifier case tok::kw_const: case tok::kw_volatile: case tok::kw_restrict: + case tok::kw___private: + case tok::kw___local: + case tok::kw___global: + case tok::kw___constant: + case tok::kw___read_only: + case tok::kw___read_write: + case tok::kw___write_only: return true; } } @@ -2285,6 +2731,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { // type-specifiers case tok::kw_short: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw__Complex: @@ -2353,6 +2800,7 @@ bool Parser::isTypeSpecifierQualifier() { // type-specifiers case tok::kw_short: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw__Complex: @@ -2399,7 +2847,19 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw___w64: case tok::kw___ptr64: case tok::kw___pascal: + + case tok::kw___private: + case tok::kw___local: + case tok::kw___global: + case tok::kw___constant: + case tok::kw___read_only: + case tok::kw___read_write: + case tok::kw___write_only: + return true; + + case tok::kw_private: + return getLang().OpenCL; } } @@ -2412,6 +2872,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { switch (Tok.getKind()) { default: return false; + case tok::kw_private: + return getLang().OpenCL; + case tok::identifier: // foo::bar // Unfortunate hack to support "Class.factoryMethod" notation. if (getLang().ObjC1 && NextToken().is(tok::period)) @@ -2461,6 +2924,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // type-specifiers case tok::kw_short: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw__Complex: @@ -2498,8 +2962,8 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_virtual: case tok::kw_explicit: - // typedef-name - case tok::annot_typename: + // static_assert-declaration + case tok::kw__Static_assert: // GNU typeof support. case tok::kw_typeof: @@ -2512,6 +2976,11 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::less: return getLang().ObjC1; + // typedef-name + case tok::annot_typename: + return !DisambiguatingWithExpression || + !isStartOfObjCClassMessageMissingOpenBracket(); + case tok::kw___declspec: case tok::kw___cdecl: case tok::kw___stdcall: @@ -2521,6 +2990,15 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw___ptr64: case tok::kw___forceinline: case tok::kw___pascal: + + case tok::kw___private: + case tok::kw___local: + case tok::kw___global: + case tok::kw___constant: + case tok::kw___read_only: + case tok::kw___read_write: + case tok::kw___write_only: + return true; } } @@ -2564,7 +3042,7 @@ bool Parser::isConstructorDeclarator() { DeclScopeObj.EnterDeclaratorScope(); // Optionally skip Microsoft attributes. - ParsedAttributes Attrs; + ParsedAttributes Attrs(AttrFactory); MaybeParseMicrosoftAttributes(Attrs); // Check whether the next token(s) are part of a declaration @@ -2592,14 +3070,16 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, bool CXX0XAttributesAllowed) { if (getLang().CPlusPlus0x && isCXX0XAttributeSpecifier()) { SourceLocation Loc = Tok.getLocation(); - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); ParseCXX0XAttributes(attrs); if (CXX0XAttributesAllowed) DS.takeAttributesFrom(attrs); else Diag(Loc, diag::err_attributes_not_allowed); } - + + SourceLocation EndLoc; + while (1) { bool isInvalid = false; const char *PrevSpec = 0; @@ -2624,6 +3104,21 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, getLang()); break; + + // OpenCL qualifiers: + case tok::kw_private: + if (!getLang().OpenCL) + goto DoneWithTypeQuals; + case tok::kw___private: + case tok::kw___global: + case tok::kw___local: + case tok::kw___constant: + case tok::kw___read_only: + case tok::kw___write_only: + case tok::kw___read_write: + ParseOpenCLQualifiers(DS); + break; + case tok::kw___w64: case tok::kw___ptr64: case tok::kw___cdecl: @@ -2652,6 +3147,8 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, // If this is not a type-qualifier token, we're done reading type // qualifiers. First verify that DeclSpec's are consistent. DS.Finish(Diags, PP); + if (EndLoc.isValid()) + DS.SetRangeEnd(EndLoc); return; } @@ -2660,7 +3157,7 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, assert(PrevSpec && "Method did not return previous specifier!"); Diag(Tok, DiagID) << PrevSpec; } - ConsumeToken(); + EndLoc = ConsumeToken(); } } @@ -2719,7 +3216,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, SourceLocation Loc = ConsumeToken(); D.SetRangeEnd(Loc); - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseTypeQualifierListOpt(DS); D.ExtendWithDeclSpec(DS); @@ -2729,7 +3226,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Sema will have to catch (syntactically invalid) pointers into global // scope. It has to catch pointers into namespace scope anyway. D.AddTypeInfo(DeclaratorChunk::getMemberPointer(SS,DS.getTypeQualifiers(), - Loc, DS.takeAttributes()), + Loc), + DS.getAttributes(), /* Don't replace range end. */SourceLocation()); return; } @@ -2753,7 +3251,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, if (Kind == tok::star || Kind == tok::caret) { // Is a pointer. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseTypeQualifierListOpt(DS); D.ExtendWithDeclSpec(DS); @@ -2765,17 +3263,18 @@ void Parser::ParseDeclaratorInternal(Declarator &D, D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, DS.getConstSpecLoc(), DS.getVolatileSpecLoc(), - DS.getRestrictSpecLoc(), - DS.takeAttributes()), + DS.getRestrictSpecLoc()), + DS.getAttributes(), SourceLocation()); else // Remember that we parsed a Block type, and remember the type-quals. D.AddTypeInfo(DeclaratorChunk::getBlockPointer(DS.getTypeQualifiers(), - Loc, DS.takeAttributes()), + Loc), + DS.getAttributes(), SourceLocation()); } else { // Is a reference - DeclSpec DS; + DeclSpec DS(AttrFactory); // Complain about rvalue references in C++03, but then go on and build // the declarator. @@ -2823,8 +3322,8 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Remember that we parsed a reference type. It doesn't have type-quals. D.AddTypeInfo(DeclaratorChunk::getReference(DS.getTypeQualifiers(), Loc, - DS.takeAttributes(), Kind == tok::amp), + DS.getAttributes(), SourceLocation()); } } @@ -2989,7 +3488,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { if (!isCXXFunctionDeclarator(warnIfAmbiguous)) break; } - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); ParseFunctionDeclarator(ConsumeParen(), D, attrs); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); @@ -3026,7 +3525,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { // In either case, we need to eat any attributes to be able to determine what // sort of paren this is. // - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); bool RequiresArg = false; if (Tok.is(tok::kw___attribute)) { ParseGNUAttributes(attrs); @@ -3072,13 +3571,12 @@ void Parser::ParseParenDeclarator(Declarator &D) { if (isGrouping) { bool hadGroupingParens = D.hasGroupingParens(); D.setGroupingParens(true); - if (!attrs.empty()) - D.addAttributes(attrs.getList(), SourceLocation()); ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); // Match the ')'. SourceLocation EndLoc = MatchRHSPunctuation(tok::r_paren, StartLoc); - D.AddTypeInfo(DeclaratorChunk::getParen(StartLoc, EndLoc), EndLoc); + D.AddTypeInfo(DeclaratorChunk::getParen(StartLoc, EndLoc), + attrs, EndLoc); D.setGroupingParens(hadGroupingParens); return; @@ -3125,6 +3623,10 @@ void Parser::ParseParenDeclarator(Declarator &D) { /// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]", /// C++0x "ref-qualifier[opt]" and "exception-specification[opt]". /// +/// [C++0x] exception-specification: +/// dynamic-exception-specification +/// noexcept-specification +/// void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, ParsedAttributes &attrs, bool RequiresArg) { @@ -3138,18 +3640,17 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); - SourceLocation RParenLoc = ConsumeParen(); // Eat the closing ')'. - SourceLocation EndLoc = RParenLoc; + SourceLocation EndLoc = ConsumeParen(); // Eat the closing ')'. // cv-qualifier-seq[opt]. - DeclSpec DS; + DeclSpec DS(AttrFactory); SourceLocation RefQualifierLoc; bool RefQualifierIsLValueRef = true; - bool hasExceptionSpec = false; - SourceLocation ThrowLoc; - bool hasAnyExceptionSpec = false; - llvm::SmallVector<ParsedType, 2> Exceptions; - llvm::SmallVector<SourceRange, 2> ExceptionRanges; + ExceptionSpecificationType ESpecType = EST_None; + SourceRange ESpecRange; + llvm::SmallVector<ParsedType, 2> DynamicExceptions; + llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges; + ExprResult NoexceptExpr; if (getLang().CPlusPlus) { MaybeParseCXX0XAttributes(attrs); @@ -3161,21 +3662,19 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { if (!getLang().CPlusPlus0x) Diag(Tok, diag::ext_ref_qualifier); - + RefQualifierIsLValueRef = Tok.is(tok::amp); RefQualifierLoc = ConsumeToken(); EndLoc = RefQualifierLoc; } - + // Parse exception-specification[opt]. - if (Tok.is(tok::kw_throw)) { - hasExceptionSpec = true; - ThrowLoc = Tok.getLocation(); - ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges, - hasAnyExceptionSpec); - assert(Exceptions.size() == ExceptionRanges.size() && - "Produced different number of exception types and ranges."); - } + ESpecType = MaybeParseExceptionSpecification(ESpecRange, + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr); + if (ESpecType != EST_None) + EndLoc = ESpecRange.getEnd(); // Parse trailing-return-type. if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) { @@ -3185,22 +3684,22 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Remember that we parsed a function type, and remember the attributes. // int() -> no prototype, no '...'. - D.AddTypeInfo(DeclaratorChunk::getFunction(attrs, - /*prototype*/getLang().CPlusPlus, + D.AddTypeInfo(DeclaratorChunk::getFunction(/*prototype*/getLang().CPlusPlus, /*variadic*/ false, SourceLocation(), /*arglist*/ 0, 0, DS.getTypeQualifiers(), RefQualifierIsLValueRef, RefQualifierLoc, - hasExceptionSpec, ThrowLoc, - hasAnyExceptionSpec, - Exceptions.data(), - ExceptionRanges.data(), - Exceptions.size(), - LParenLoc, RParenLoc, D, + ESpecType, ESpecRange.getBegin(), + DynamicExceptions.data(), + DynamicExceptionRanges.data(), + DynamicExceptions.size(), + NoexceptExpr.isUsable() ? + NoexceptExpr.get() : 0, + LParenLoc, EndLoc, D, TrailingReturnType), - EndLoc); + attrs, EndLoc); return; } @@ -3264,7 +3763,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, // Parse the declaration-specifiers. // Just use the ParsingDeclaration "scope" of the declarator. - DeclSpec DS; + DeclSpec DS(AttrFactory); // Skip any Microsoft attributes before a param. if (getLang().Microsoft && Tok.is(tok::l_square)) @@ -3388,17 +3887,16 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, } // If we have the closing ')', eat it. - SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - SourceLocation EndLoc = RParenLoc; + SourceLocation EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - DeclSpec DS; + DeclSpec DS(AttrFactory); SourceLocation RefQualifierLoc; bool RefQualifierIsLValueRef = true; - bool hasExceptionSpec = false; - SourceLocation ThrowLoc; - bool hasAnyExceptionSpec = false; - llvm::SmallVector<ParsedType, 2> Exceptions; - llvm::SmallVector<SourceRange, 2> ExceptionRanges; + ExceptionSpecificationType ESpecType = EST_None; + SourceRange ESpecRange; + llvm::SmallVector<ParsedType, 2> DynamicExceptions; + llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges; + ExprResult NoexceptExpr; if (getLang().CPlusPlus) { MaybeParseCXX0XAttributes(attrs); @@ -3418,15 +3916,17 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, EndLoc = RefQualifierLoc; } + // FIXME: We should leave the prototype scope before parsing the exception + // specification, and then reenter it when parsing the trailing return type. + // FIXMEFIXME: Why? That wouldn't be right for the noexcept clause. + // Parse exception-specification[opt]. - if (Tok.is(tok::kw_throw)) { - hasExceptionSpec = true; - ThrowLoc = Tok.getLocation(); - ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges, - hasAnyExceptionSpec); - assert(Exceptions.size() == ExceptionRanges.size() && - "Produced different number of exception types and ranges."); - } + ESpecType = MaybeParseExceptionSpecification(ESpecRange, + DynamicExceptions, + DynamicExceptionRanges, + NoexceptExpr); + if (ESpecType != EST_None) + EndLoc = ESpecRange.getEnd(); // Parse trailing-return-type. if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) { @@ -3434,28 +3934,25 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, } } - // FIXME: We should leave the prototype scope before parsing the exception - // specification, and then reenter it when parsing the trailing return type. - // Leave prototype scope. PrototypeScope.Exit(); // Remember that we parsed a function type, and remember the attributes. - D.AddTypeInfo(DeclaratorChunk::getFunction(attrs, - /*proto*/true, IsVariadic, + D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/true, IsVariadic, EllipsisLoc, ParamInfo.data(), ParamInfo.size(), DS.getTypeQualifiers(), RefQualifierIsLValueRef, RefQualifierLoc, - hasExceptionSpec, ThrowLoc, - hasAnyExceptionSpec, - Exceptions.data(), - ExceptionRanges.data(), - Exceptions.size(), - LParenLoc, RParenLoc, D, + ESpecType, ESpecRange.getBegin(), + DynamicExceptions.data(), + DynamicExceptionRanges.data(), + DynamicExceptions.size(), + NoexceptExpr.isUsable() ? + NoexceptExpr.get() : 0, + LParenLoc, EndLoc, D, TrailingReturnType), - EndLoc); + attrs, EndLoc); } /// ParseFunctionDeclaratorIdentifierList - While parsing a function declarator @@ -3524,16 +4021,15 @@ void Parser::ParseFunctionDeclaratorIdentifierList(SourceLocation LParenLoc, // Remember that we parsed a function type, and remember the attributes. This // function type is always a K&R style function type, which is not varargs and // has no prototype. - D.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(), - /*proto*/false, /*varargs*/false, + ParsedAttributes attrs(AttrFactory); + D.AddTypeInfo(DeclaratorChunk::getFunction(/*proto*/false, /*varargs*/false, SourceLocation(), &ParamInfo[0], ParamInfo.size(), /*TypeQuals*/0, true, SourceLocation(), - /*exception*/false, - SourceLocation(), false, 0, 0, 0, - LParenLoc, RLoc, D), - RLoc); + EST_None, SourceLocation(), 0, 0, + 0, 0, LParenLoc, RLoc, D), + attrs, RLoc); } /// [C90] direct-declarator '[' constant-expression[opt] ']' @@ -3548,14 +4044,14 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // This code does a fast path to handle some of the most obvious cases. if (Tok.getKind() == tok::r_square) { SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Remember that we parsed the empty array type. ExprResult NumElements; - D.AddTypeInfo(DeclaratorChunk::getArray(0, attrs, false, false, 0, + D.AddTypeInfo(DeclaratorChunk::getArray(0, false, false, 0, StartLoc, EndLoc), - EndLoc); + attrs, EndLoc); return; } else if (Tok.getKind() == tok::numeric_constant && GetLookAheadToken(1).is(tok::r_square)) { @@ -3564,14 +4060,14 @@ void Parser::ParseBracketDeclarator(Declarator &D) { ConsumeToken(); SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Remember that we parsed a array type, and remember its features. - D.AddTypeInfo(DeclaratorChunk::getArray(0, attrs, false, 0, + D.AddTypeInfo(DeclaratorChunk::getArray(0, false, 0, ExprRes.release(), StartLoc, EndLoc), - EndLoc); + attrs, EndLoc); return; } @@ -3582,7 +4078,7 @@ void Parser::ParseBracketDeclarator(Declarator &D) { // If there is a type-qualifier-list, read it now. // Type qualifiers in an array subscript are a C99 feature. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseTypeQualifierListOpt(DS, false /*no attributes*/); // If we haven't already read 'static', check to see if there is one after the @@ -3630,15 +4126,15 @@ void Parser::ParseBracketDeclarator(Declarator &D) { SourceLocation EndLoc = MatchRHSPunctuation(tok::r_square, StartLoc); - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Remember that we parsed a array type, and remember its features. - D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), attrs, + D.AddTypeInfo(DeclaratorChunk::getArray(DS.getTypeQualifiers(), StaticLoc.isValid(), isStar, NumElements.release(), StartLoc, EndLoc), - EndLoc); + attrs, EndLoc); } /// [GNU] typeof-specifier: @@ -3656,10 +4152,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { bool isCastExpr; ParsedType CastTy; SourceRange CastRange; - ExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, - isCastExpr, - CastTy, - CastRange); + ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, isCastExpr, + CastTy, CastRange); if (hasParens) DS.setTypeofParensRange(CastRange); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp index b3ad25b..8c0aa1b 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseDeclCXX.cpp @@ -69,11 +69,9 @@ Decl *Parser::ParseNamespace(unsigned Context, } // Read label attributes, if present. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); if (Tok.is(tok::kw___attribute)) { attrTok = Tok; - - // FIXME: save these somewhere. ParseGNUAttributes(attrs); } @@ -111,14 +109,14 @@ Decl *Parser::ParseNamespace(unsigned Context, ParseScope NamespaceScope(this, Scope::DeclScope); Decl *NamespcDecl = - Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, IdentLoc, Ident, - LBrace, attrs.getList()); + Actions.ActOnStartNamespaceDef(getCurScope(), InlineLoc, NamespaceLoc, + IdentLoc, Ident, LBrace, attrs.getList()); PrettyDeclStackTraceEntry CrashInfo(Actions, NamespcDecl, NamespaceLoc, "parsing namespace"); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); @@ -138,9 +136,9 @@ Decl *Parser::ParseNamespace(unsigned Context, /// alias definition. /// Decl *Parser::ParseNamespaceAlias(SourceLocation NamespaceLoc, - SourceLocation AliasLoc, - IdentifierInfo *Alias, - SourceLocation &DeclEnd) { + SourceLocation AliasLoc, + IdentifierInfo *Alias, + SourceLocation &DeclEnd) { assert(Tok.is(tok::equal) && "Not equal token"); ConsumeToken(); // eat the '='. @@ -194,16 +192,21 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { ParseScope LinkageScope(this, Scope::DeclScope); Decl *LinkageSpec = Actions.ActOnStartLinkageSpecification(getCurScope(), - /*FIXME: */SourceLocation(), + DS.getSourceRange().getBegin(), Loc, Lang, - Tok.is(tok::l_brace)? Tok.getLocation() + Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation()); - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); if (Tok.isNot(tok::l_brace)) { + // Reset the source range in DS, as the leading "extern" + // does not really belong to the inner declaration ... + DS.SetRangeStart(SourceLocation()); + DS.SetRangeEnd(SourceLocation()); + // ... but anyway remember that such an "extern" was seen. DS.setExternInLinkageSpec(true); ParseExternalDeclaration(attrs, &DS); return Actions.ActOnFinishLinkageSpecification(getCurScope(), LinkageSpec, @@ -216,7 +219,7 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, unsigned Context) { SourceLocation LBrace = ConsumeBrace(); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); ParseExternalDeclaration(attrs); @@ -255,7 +258,7 @@ Decl *Parser::ParseUsingDirectiveOrDeclaration(unsigned Context, return ParseUsingDirective(Context, UsingLoc, DeclEnd, attrs); } - // Otherwise, it must be a using-declaration. + // Otherwise, it must be a using-declaration or an alias-declaration. // Using declarations can't have attributes. ProhibitAttributes(attrs); @@ -325,14 +328,17 @@ Decl *Parser::ParseUsingDirective(unsigned Context, IdentLoc, NamespcName, attrs.getList()); } -/// ParseUsingDeclaration - Parse C++ using-declaration. Assumes that -/// 'using' was already seen. +/// ParseUsingDeclaration - Parse C++ using-declaration or alias-declaration. +/// Assumes that 'using' was already seen. /// /// using-declaration: [C++ 7.3.p3: namespace.udecl] /// 'using' 'typename'[opt] ::[opt] nested-name-specifier /// unqualified-id /// 'using' :: unqualified-id /// +/// alias-declaration: C++0x [decl.typedef]p2 +/// 'using' identifier = type-id ; +/// Decl *Parser::ParseUsingDeclaration(unsigned Context, const ParsedTemplateInfo &TemplateInfo, SourceLocation UsingLoc, @@ -342,10 +348,6 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, SourceLocation TypenameLoc; bool IsTypeName; - // TODO: in C++0x, if we have template parameters this must be a - // template alias: - // template <...> using id = type; - // Ignore optional 'typename'. // FIXME: This is wrong; we should parse this as a typename-specifier. if (Tok.is(tok::kw_typename)) { @@ -379,17 +381,48 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } - // Parse (optional) attributes (most likely GNU strong-using extension). - ParsedAttributes attrs; - MaybeParseGNUAttributes(attrs); + ParsedAttributes attrs(AttrFactory); + + // Maybe this is an alias-declaration. + bool IsAliasDecl = Tok.is(tok::equal); + TypeResult TypeAlias; + if (IsAliasDecl) { + // TODO: Do we want to support attributes somewhere in an alias declaration? + // Can't follow GCC since it doesn't support them yet! + ConsumeToken(); + + if (!getLang().CPlusPlus0x) + Diag(Tok.getLocation(), diag::ext_alias_declaration); + + // Name must be an identifier. + if (Name.getKind() != UnqualifiedId::IK_Identifier) { + Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier); + // No removal fixit: can't recover from this. + SkipUntil(tok::semi); + return 0; + } else if (IsTypeName) + Diag(TypenameLoc, diag::err_alias_declaration_not_identifier) + << FixItHint::CreateRemoval(SourceRange(TypenameLoc, + SS.isNotEmpty() ? SS.getEndLoc() : TypenameLoc)); + else if (SS.isNotEmpty()) + Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier) + << FixItHint::CreateRemoval(SS.getRange()); + + TypeAlias = ParseTypeName(0, Declarator::AliasDeclContext); + } else + // Parse (optional) attributes (most likely GNU strong-using extension). + MaybeParseGNUAttributes(attrs); // Eat ';'. DeclEnd = Tok.getLocation(); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, - !attrs.empty() ? "attributes list" : "using declaration", + !attrs.empty() ? "attributes list" : + IsAliasDecl ? "alias declaration" : "using declaration", tok::semi); // Diagnose an attempt to declare a templated using-declaration. + // TODO: in C++0x, alias-declarations can be templates: + // template <...> using id = type; if (TemplateInfo.Kind) { SourceRange R = TemplateInfo.getSourceRange(); Diag(UsingLoc, diag::err_templated_using_declaration) @@ -401,18 +434,30 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } + if (IsAliasDecl) + return Actions.ActOnAliasDeclaration(getCurScope(), AS, UsingLoc, Name, + TypeAlias); + return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, Name, attrs.getList(), IsTypeName, TypenameLoc); } -/// ParseStaticAssertDeclaration - Parse C++0x static_assert-declaratoion. +/// ParseStaticAssertDeclaration - Parse C++0x or C1X static_assert-declaration. +/// +/// [C++0x] static_assert-declaration: +/// static_assert ( constant-expression , string-literal ) ; /// -/// static_assert-declaration: -/// static_assert ( constant-expression , string-literal ) ; +/// [C1X] static_assert-declaration: +/// _Static_assert ( constant-expression , string-literal ) ; /// Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ - assert(Tok.is(tok::kw_static_assert) && "Not a static_assert declaration"); + assert((Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) && + "Not a static_assert declaration"); + + if (Tok.is(tok::kw__Static_assert) && !getLang().C1X) + Diag(Tok, diag::ext_c1x_static_assert); + SourceLocation StaticAssertLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) { @@ -441,14 +486,15 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ if (AssertMessage.isInvalid()) return 0; - MatchRHSPunctuation(tok::r_paren, LParenLoc); + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); DeclEnd = Tok.getLocation(); ExpectAndConsumeSemi(diag::err_expected_semi_after_static_assert); return Actions.ActOnStaticAssertDeclaration(StaticAssertLoc, AssertExpr.take(), - AssertMessage.take()); + AssertMessage.take(), + RParenLoc); } /// ParseDecltypeSpecifier - Parse a C++0x decltype specifier. @@ -508,14 +554,14 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { /// simple-template-id /// Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, - CXXScopeSpec *SS) { + CXXScopeSpec &SS) { // Check whether we have a template-id that names a type. if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { - AnnotateTemplateIdTokenAsType(SS); + AnnotateTemplateIdTokenAsType(); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); ParsedType Type = getTypeAnnotation(Tok); @@ -544,7 +590,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, TemplateNameKind TNK = TNK_Type_template; TemplateTy Template; if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, getCurScope(), - SS, Template, TNK)) { + &SS, Template, TNK)) { Diag(IdLoc, diag::err_unknown_template_name) << Id; } @@ -561,7 +607,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, SourceLocation(), true)) return true; if (TNK == TNK_Dependent_template_name) - AnnotateTemplateIdTokenAsType(SS); + AnnotateTemplateIdTokenAsType(); // If we didn't end up with a typename token, there's nothing more we // can do. @@ -577,7 +623,9 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, } // We have an identifier; check whether it is actually a type. - ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), SS, true); + ParsedType Type = Actions.getTypeName(*Id, IdLoc, getCurScope(), &SS, true, + false, ParsedType(), + /*NonTrivialTypeSourceInfo=*/true); if (!Type) { Diag(IdLoc, diag::err_expected_class_name); return true; @@ -587,10 +635,10 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, EndLocation = IdLoc; // Fake up a Declarator to use with ActOnTypeName. - DeclSpec DS; + DeclSpec DS(AttrFactory); DS.SetRangeStart(IdLoc); DS.SetRangeEnd(EndLocation); - DS.getTypeSpecScope() = *SS; + DS.getTypeSpecScope() = SS; const char *PrevSpec = 0; unsigned DiagID; @@ -674,7 +722,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, SuppressingAccessChecks = true; } - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); // If attributes exist after tag, parse them. if (Tok.is(tok::kw___attribute)) ParseGNUAttributes(attrs); @@ -688,22 +736,30 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // styles of attributes? MaybeParseCXX0XAttributes(attrs); - if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_pod)) { - // GNU libstdc++ 4.2 uses __is_pod as the name of a struct template, but - // __is_pod is a keyword in GCC >= 4.3. Therefore, when we see the - // token sequence "struct __is_pod", make __is_pod into a normal - // identifier rather than a keyword, to allow libstdc++ 4.2 to work - // properly. - Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); - Tok.setKind(tok::identifier); - } - - if (TagType == DeclSpec::TST_struct && Tok.is(tok::kw___is_empty)) { - // GNU libstdc++ 4.2 uses __is_empty as the name of a struct template, but - // __is_empty is a keyword in GCC >= 4.3. Therefore, when we see the - // token sequence "struct __is_empty", make __is_empty into a normal - // identifier rather than a keyword, to allow libstdc++ 4.2 to work - // properly. + if (TagType == DeclSpec::TST_struct && + !Tok.is(tok::identifier) && + Tok.getIdentifierInfo() && + (Tok.is(tok::kw___is_arithmetic) || + Tok.is(tok::kw___is_convertible) || + Tok.is(tok::kw___is_empty) || + Tok.is(tok::kw___is_floating_point) || + Tok.is(tok::kw___is_function) || + Tok.is(tok::kw___is_fundamental) || + Tok.is(tok::kw___is_integral) || + Tok.is(tok::kw___is_member_function_pointer) || + Tok.is(tok::kw___is_member_pointer) || + Tok.is(tok::kw___is_pod) || + Tok.is(tok::kw___is_pointer) || + Tok.is(tok::kw___is_same) || + Tok.is(tok::kw___is_scalar) || + Tok.is(tok::kw___is_signed) || + Tok.is(tok::kw___is_unsigned) || + Tok.is(tok::kw___is_void))) { + // GNU libstdc++ 4.2 and libc++ uaw certain intrinsic names as the + // name of struct templates, but some are keywords in GCC >= 4.3 + // and Clang. Therefore, when we see the token sequence "struct + // X", make X into a normal identifier rather than a keyword, to + // allow libstdc++ 4.2 and libc++ to work properly. Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); Tok.setKind(tok::identifier); } @@ -737,7 +793,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // a class (or template thereof). TemplateArgList TemplateArgs; SourceLocation LAngleLoc, RAngleLoc; - if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, &SS, + if (ParseTemplateIdAfterTemplateName(TemplateTy(), NameLoc, SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) { // We couldn't parse the template argument list at all, so don't @@ -779,7 +835,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); NameLoc = ConsumeToken(); - if (TemplateId->Kind != TNK_Type_template) { + if (TemplateId->Kind != TNK_Type_template && + TemplateId->Kind != TNK_Dependent_template_name) { // The template-name in the simple-template-id refers to // something other than a class template. Give an appropriate // error message and skip to the ';'. @@ -808,7 +865,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // There are four options here. If we have 'struct foo;', then this // is either a forward declaration or a friend declaration, which // have to be treated differently. If we have 'struct foo {...', - // 'struct foo :...' or 'struct foo <class-virt-specifier>' then this is a + // 'struct foo :...' or 'struct foo final[opt]' then this is a // definition. Otherwise we have something like 'struct foo xyz', a reference. // However, in some contexts, things look like declarations but are just // references, e.g. @@ -821,7 +878,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TUK = Sema::TUK_Reference; else if (Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon)) || - isCXX0XClassVirtSpecifier() != ClassVirtSpecifiers::CVS_None) { + isCXX0XFinalKeyword()) { if (DS.isFriendSpecified()) { // C++ [class.friend]p2: // A class shall not be defined in a friend declaration. @@ -891,15 +948,14 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } else if (TUK == Sema::TUK_Reference || (TUK == Sema::TUK_Friend && TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { - TypeResult - = Actions.ActOnTemplateIdType(TemplateId->Template, - TemplateId->TemplateNameLoc, - TemplateId->LAngleLoc, - TemplateArgsPtr, - TemplateId->RAngleLoc); - - TypeResult = Actions.ActOnTagTemplateIdType(SS, TypeResult, TUK, - TagType, StartLoc); + TypeResult = Actions.ActOnTagTemplateIdType(TUK, TagType, + StartLoc, + TemplateId->SS, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); } else { // This is an explicit specialization or a class template // partial specialization. @@ -1007,26 +1063,24 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace) || (getLang().CPlusPlus && Tok.is(tok::colon)) || - isCXX0XClassVirtSpecifier() != ClassVirtSpecifiers::CVS_None); + isCXX0XFinalKeyword()); if (getLang().CPlusPlus) ParseCXXMemberSpecification(StartLoc, TagType, TagOrTempResult.get()); else ParseStructUnionBody(StartLoc, TagType, TagOrTempResult.get()); } - // FIXME: The DeclSpec should keep the locations of both the keyword and the - // name (if there is one). - SourceLocation TSTLoc = NameLoc.isValid()? NameLoc : StartLoc; - const char *PrevSpec = 0; unsigned DiagID; bool Result; if (!TypeResult.isInvalid()) { - Result = DS.SetTypeSpecType(DeclSpec::TST_typename, TSTLoc, + Result = DS.SetTypeSpecType(DeclSpec::TST_typename, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, PrevSpec, DiagID, TypeResult.get()); } else if (!TagOrTempResult.isInvalid()) { - Result = DS.SetTypeSpecType(TagType, TSTLoc, PrevSpec, DiagID, - TagOrTempResult.get(), Owned); + Result = DS.SetTypeSpecType(TagType, StartLoc, + NameLoc.isValid() ? NameLoc : StartLoc, + PrevSpec, DiagID, TagOrTempResult.get(), Owned); } else { DS.SetTypeSpecError(); return; @@ -1072,7 +1126,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, case tok::kw_mutable: // struct foo {...} mutable x; // As shown above, type qualifiers and storage class specifiers absolutely // can occur after class specifiers according to the grammar. However, - // almost noone actually writes code like this. If we see one of these, + // almost no one actually writes code like this. If we see one of these, // it is much more likely that someone missed a semi colon and the // type/storage class specifier we're seeing is part of the *next* // intended declaration, as in: @@ -1195,7 +1249,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { // Parse the class-name. SourceLocation EndLocation; - TypeResult BaseType = ParseClassName(EndLocation, &SS); + TypeResult BaseType = ParseClassName(EndLocation, SS); if (BaseType.isInvalid()) return true; @@ -1270,14 +1324,10 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, /// virt-specifier: /// override /// final -/// new VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier() const { if (!getLang().CPlusPlus) return VirtSpecifiers::VS_None; - if (Tok.is(tok::kw_new)) - return VirtSpecifiers::VS_New; - if (Tok.is(tok::identifier)) { IdentifierInfo *II = Tok.getIdentifierInfo(); @@ -1323,61 +1373,22 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { } } -/// isCXX0XClassVirtSpecifier - Determine whether the next token is a C++0x -/// class-virt-specifier. -/// -/// class-virt-specifier: -/// final -/// explicit -ClassVirtSpecifiers::Specifier Parser::isCXX0XClassVirtSpecifier() const { +/// isCXX0XFinalKeyword - Determine whether the next token is a C++0x +/// contextual 'final' keyword. +bool Parser::isCXX0XFinalKeyword() const { if (!getLang().CPlusPlus) - return ClassVirtSpecifiers::CVS_None; - - if (Tok.is(tok::kw_explicit)) - return ClassVirtSpecifiers::CVS_Explicit; - - if (Tok.is(tok::identifier)) { - IdentifierInfo *II = Tok.getIdentifierInfo(); - - // Initialize the contextual keywords. - if (!Ident_final) { - Ident_final = &PP.getIdentifierTable().get("final"); - Ident_override = &PP.getIdentifierTable().get("override"); - } - - if (II == Ident_final) - return ClassVirtSpecifiers::CVS_Final; - } - - return ClassVirtSpecifiers::CVS_None; -} - -/// ParseOptionalCXX0XClassVirtSpecifierSeq - Parse a class-virt-specifier-seq. -/// -/// class-virt-specifier-seq: -/// class-virt-specifier -/// class-virt-specifier-seq class-virt-specifier -void Parser::ParseOptionalCXX0XClassVirtSpecifierSeq(ClassVirtSpecifiers &CVS) { - while (true) { - ClassVirtSpecifiers::Specifier Specifier = isCXX0XClassVirtSpecifier(); - if (Specifier == ClassVirtSpecifiers::CVS_None) - return; - - // C++ [class]p1: - // A class-virt-specifier-seq shall contain at most one of each - // class-virt-specifier. - const char *PrevSpec = 0; - if (CVS.SetSpecifier(Specifier, Tok.getLocation(), PrevSpec)) - Diag(Tok.getLocation(), diag::err_duplicate_class_virt_specifier) - << PrevSpec - << FixItHint::CreateRemoval(Tok.getLocation()); + return false; - if (!getLang().CPlusPlus0x) - Diag(Tok.getLocation(), diag::ext_override_control_keyword) - << ClassVirtSpecifiers::getSpecifierName(Specifier); + if (!Tok.is(tok::identifier)) + return false; - ConsumeToken(); + // Initialize the contextual keywords. + if (!Ident_final) { + Ident_final = &PP.getIdentifierTable().get("final"); + Ident_override = &PP.getIdentifierTable().get("override"); } + + return Tok.getIdentifierInfo() == Ident_final; } /// ParseCXXClassMemberDeclaration - Parse a C++ class member declaration. @@ -1418,6 +1429,17 @@ void Parser::ParseOptionalCXX0XClassVirtSpecifierSeq(ClassVirtSpecifiers &CVS) { void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, const ParsedTemplateInfo &TemplateInfo, ParsingDeclRAIIObject *TemplateDiags) { + if (Tok.is(tok::at)) { + if (getLang().ObjC1 && NextToken().isObjCAtKeyword(tok::objc_defs)) + Diag(Tok, diag::err_at_defs_cxx); + else + Diag(Tok, diag::err_at_in_class); + + ConsumeToken(); + SkipUntil(tok::r_brace); + return; + } + // Access declarations. if (!TemplateInfo.Kind && (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && @@ -1459,7 +1481,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, } // static_assert-declaration - if (Tok.is(tok::kw_static_assert)) { + if (Tok.is(tok::kw_static_assert) || Tok.is(tok::kw__Static_assert)) { // FIXME: Check for templates SourceLocation DeclEnd; ParseStaticAssertDeclaration(DeclEnd); @@ -1487,7 +1509,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // is a bitfield. ColonProtectionRAIIObject X(*this); - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); // Optional C++0x attribute-specifier MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); @@ -1542,7 +1564,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { // If so, skip until the semi-colon or a }. - SkipUntil(tok::r_brace, true); + SkipUntil(tok::r_brace, true, true); if (Tok.is(tok::semi)) ConsumeToken(); return; @@ -1763,8 +1785,24 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (TagDecl) Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); - ClassVirtSpecifiers CVS; - ParseOptionalCXX0XClassVirtSpecifierSeq(CVS); + SourceLocation FinalLoc; + + // Parse the optional 'final' keyword. + if (getLang().CPlusPlus && Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + + // Initialize the contextual keywords. + if (!Ident_final) { + Ident_final = &PP.getIdentifierTable().get("final"); + Ident_override = &PP.getIdentifierTable().get("override"); + } + + if (II == Ident_final) + FinalLoc = ConsumeToken(); + + if (!getLang().CPlusPlus0x) + Diag(FinalLoc, diag::ext_override_control_keyword) << "final"; + } if (Tok.is(tok::colon)) { ParseBaseClause(TagDecl); @@ -1783,7 +1821,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, SourceLocation LBraceLoc = ConsumeBrace(); if (TagDecl) - Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, CVS, + Actions.ActOnStartCXXMemberDeclarations(getCurScope(), TagDecl, FinalLoc, LBraceLoc); // C++ 11p3: Members of a class defined with the keyword class are private @@ -1836,7 +1874,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, } // If attributes exist after class contents, parse them. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); if (TagDecl) @@ -1893,6 +1931,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) { assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'"); + // Poison the SEH identifiers so they are flagged as illegal in constructor initializers + PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); SourceLocation ColonLoc = ConsumeToken(); llvm::SmallVector<CXXCtorInitializer*, 4> MemInitializers; @@ -1956,7 +1996,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { - AnnotateTemplateIdTokenAsType(&SS); + AnnotateTemplateIdTokenAsType(); assert(Tok.is(tok::annot_typename) && "template-id -> type failed"); TemplateTypeTy = getTypeAnnotation(Tok); } @@ -1999,10 +2039,81 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { EllipsisLoc); } -/// ParseExceptionSpecification - Parse a C++ exception-specification -/// (C++ [except.spec]). +/// \brief Parse a C++ exception-specification if present (C++0x [except.spec]). /// /// exception-specification: +/// dynamic-exception-specification +/// noexcept-specification +/// +/// noexcept-specification: +/// 'noexcept' +/// 'noexcept' '(' constant-expression ')' +ExceptionSpecificationType +Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange, + llvm::SmallVectorImpl<ParsedType> &DynamicExceptions, + llvm::SmallVectorImpl<SourceRange> &DynamicExceptionRanges, + ExprResult &NoexceptExpr) { + ExceptionSpecificationType Result = EST_None; + + // See if there's a dynamic specification. + if (Tok.is(tok::kw_throw)) { + Result = ParseDynamicExceptionSpecification(SpecificationRange, + DynamicExceptions, + DynamicExceptionRanges); + assert(DynamicExceptions.size() == DynamicExceptionRanges.size() && + "Produced different number of exception types and ranges."); + } + + // If there's no noexcept specification, we're done. + if (Tok.isNot(tok::kw_noexcept)) + return Result; + + // If we already had a dynamic specification, parse the noexcept for, + // recovery, but emit a diagnostic and don't store the results. + SourceRange NoexceptRange; + ExceptionSpecificationType NoexceptType = EST_None; + + SourceLocation KeywordLoc = ConsumeToken(); + if (Tok.is(tok::l_paren)) { + // There is an argument. + SourceLocation LParenLoc = ConsumeParen(); + NoexceptType = EST_ComputedNoexcept; + NoexceptExpr = ParseConstantExpression(); + // The argument must be contextually convertible to bool. We use + // ActOnBooleanCondition for this purpose. + if (!NoexceptExpr.isInvalid()) + NoexceptExpr = Actions.ActOnBooleanCondition(getCurScope(), KeywordLoc, + NoexceptExpr.get()); + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + NoexceptRange = SourceRange(KeywordLoc, RParenLoc); + } else { + // There is no argument. + NoexceptType = EST_BasicNoexcept; + NoexceptRange = SourceRange(KeywordLoc, KeywordLoc); + } + + if (Result == EST_None) { + SpecificationRange = NoexceptRange; + Result = NoexceptType; + + // If there's a dynamic specification after a noexcept specification, + // parse that and ignore the results. + if (Tok.is(tok::kw_throw)) { + Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification); + ParseDynamicExceptionSpecification(NoexceptRange, DynamicExceptions, + DynamicExceptionRanges); + } + } else { + Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification); + } + + return Result; +} + +/// ParseDynamicExceptionSpecification - Parse a C++ +/// dynamic-exception-specification (C++ [except.spec]). +/// +/// dynamic-exception-specification: /// 'throw' '(' type-id-list [opt] ')' /// [MS] 'throw' '(' '...' ')' /// @@ -2010,46 +2121,47 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { /// type-id ... [opt] /// type-id-list ',' type-id ... [opt] /// -bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, - llvm::SmallVectorImpl<ParsedType> - &Exceptions, - llvm::SmallVectorImpl<SourceRange> - &Ranges, - bool &hasAnyExceptionSpec) { +ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification( + SourceRange &SpecificationRange, + llvm::SmallVectorImpl<ParsedType> &Exceptions, + llvm::SmallVectorImpl<SourceRange> &Ranges) { assert(Tok.is(tok::kw_throw) && "expected throw"); - ConsumeToken(); + SpecificationRange.setBegin(ConsumeToken()); if (!Tok.is(tok::l_paren)) { - return Diag(Tok, diag::err_expected_lparen_after) << "throw"; + Diag(Tok, diag::err_expected_lparen_after) << "throw"; + SpecificationRange.setEnd(SpecificationRange.getBegin()); + return EST_DynamicNone; } SourceLocation LParenLoc = ConsumeParen(); // Parse throw(...), a Microsoft extension that means "this function // can throw anything". if (Tok.is(tok::ellipsis)) { - hasAnyExceptionSpec = true; SourceLocation EllipsisLoc = ConsumeToken(); if (!getLang().Microsoft) Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec); - EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - return false; + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + SpecificationRange.setEnd(RParenLoc); + return EST_MSAny; } // Parse the sequence of type-ids. SourceRange Range; while (Tok.isNot(tok::r_paren)) { TypeResult Res(ParseTypeName(&Range)); - + if (Tok.is(tok::ellipsis)) { // C++0x [temp.variadic]p5: // - In a dynamic-exception-specification (15.4); the pattern is a // type-id. SourceLocation Ellipsis = ConsumeToken(); + Range.setEnd(Ellipsis); if (!Res.isInvalid()) Res = Actions.ActOnPackExpansion(Res.get(), Ellipsis); } - + if (!Res.isInvalid()) { Exceptions.push_back(Res.get()); Ranges.push_back(Range); @@ -2061,8 +2173,8 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc, break; } - EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); - return false; + SpecificationRange.setEnd(MatchRHSPunctuation(tok::r_paren, LParenLoc)); + return Exceptions.empty() ? EST_DynamicNone : EST_Dynamic; } /// ParseTrailingReturnType - Parse a trailing return type on a new-style @@ -2236,8 +2348,8 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, break; } - attrs.add(AttrFactory.Create(AttrName, AttrLoc, 0, AttrLoc, 0, - SourceLocation(), 0, 0, false, true)); + attrs.addNew(AttrName, AttrLoc, 0, AttrLoc, 0, + SourceLocation(), 0, 0, false, true); AttrParsed = true; break; } @@ -2257,9 +2369,9 @@ void Parser::ParseCXX0XAttributes(ParsedAttributesWithRange &attrs, ExprVector ArgExprs(Actions); ArgExprs.push_back(ArgExpr.release()); - attrs.add(AttrFactory.Create(AttrName, AttrLoc, 0, AttrLoc, - 0, ParamLoc, ArgExprs.take(), 1, - false, true)); + attrs.addNew(AttrName, AttrLoc, 0, AttrLoc, + 0, ParamLoc, ArgExprs.take(), 1, + false, true); AttrParsed = true; break; @@ -2301,8 +2413,8 @@ ExprResult Parser::ParseCXX0XAlignArgument(SourceLocation Start) { SourceLocation TypeLoc = Tok.getLocation(); ParsedType Ty = ParseTypeName().get(); SourceRange TypeRange(Start, Tok.getLocation()); - return Actions.ActOnSizeOfAlignOfExpr(TypeLoc, false, true, - Ty.getAsOpaquePtr(), TypeRange); + return Actions.ActOnUnaryExprOrTypeTraitExpr(TypeLoc, UETT_AlignOf, true, + Ty.getAsOpaquePtr(), TypeRange); } else return ParseConstantExpression(); } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp index 616c251..91fe1e1 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExpr.cpp @@ -174,7 +174,6 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// expression: [C99 6.5.17] /// assignment-expression ...[opt] /// expression ',' assignment-expression ...[opt] -/// ExprResult Parser::ParseExpression() { ExprResult LHS(ParseAssignmentExpression()); return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); @@ -212,7 +211,6 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { } /// ParseAssignmentExpression - Parse an expr that doesn't include commas. -/// ExprResult Parser::ParseAssignmentExpression() { if (Tok.is(tok::code_completion)) { Actions.CodeCompleteOrdinaryName(getCurScope(), Sema::PCC_Expression); @@ -222,7 +220,7 @@ ExprResult Parser::ParseAssignmentExpression() { if (Tok.is(tok::kw_throw)) return ParseThrowExpression(); - ExprResult LHS(ParseCastExpression(false)); + ExprResult LHS = ParseCastExpression(false, false, ParsedType()); return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment); } @@ -415,8 +413,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { /// due to member pointers. /// ExprResult Parser::ParseCastExpression(bool isUnaryExpression, - bool isAddressOfOperand, - ParsedType TypeOfCast) { + bool isAddressOfOperand, + ParsedType TypeOfCast) { bool NotCastExpr; ExprResult Res = ParseCastExpression(isUnaryExpression, isAddressOfOperand, @@ -465,6 +463,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// [C++] boolean-literal [C++ 2.13.5] /// [C++0x] 'nullptr' [C++0x 2.14.7] /// '(' expression ')' +/// [C1X] generic-selection /// '__func__' [C99 6.4.2.2] /// [GNU] '__FUNCTION__' /// [GNU] '__PRETTY_FUNCTION__' @@ -491,6 +490,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// [C++] 'this' [C++ 9.3.2] /// [G++] unary-type-trait '(' type-id ')' /// [G++] binary-type-trait '(' type-id ',' type-id ')' [TODO] +/// [EMBT] array-type-trait '(' type-id ',' integer ')' /// [clang] '^' block-literal /// /// constant: [C99 6.4.4] @@ -520,6 +520,34 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '::'[opt] 'delete' cast-expression /// '::'[opt] 'delete' '[' ']' cast-expression /// +/// [GNU/Embarcadero] unary-type-trait: +/// '__is_arithmetic' +/// '__is_floating_point' +/// '__is_integral' +/// '__is_lvalue_expr' +/// '__is_rvalue_expr' +/// '__is_complete_type' +/// '__is_void' +/// '__is_array' +/// '__is_function' +/// '__is_reference' +/// '__is_lvalue_reference' +/// '__is_rvalue_reference' +/// '__is_fundamental' +/// '__is_object' +/// '__is_scalar' +/// '__is_compound' +/// '__is_pointer' +/// '__is_member_object_pointer' +/// '__is_member_function_pointer' +/// '__is_member_pointer' +/// '__is_const' +/// '__is_volatile' +/// '__is_trivial' +/// '__is_standard_layout' +/// '__is_signed' +/// '__is_unsigned' +/// /// [GNU] unary-type-trait: /// '__has_nothrow_assign' /// '__has_nothrow_copy' @@ -535,11 +563,22 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '__is_enum' /// '__is_pod' /// '__is_polymorphic' +/// '__is_trivial' /// '__is_union' /// /// binary-type-trait: /// [GNU] '__is_base_of' /// [MS] '__is_convertible_to' +/// '__is_convertible' +/// '__is_same' +/// +/// [Embarcadero] array-type-trait: +/// '__array_rank' +/// '__array_extent' +/// +/// [Embarcadero] expression-trait: +/// '__is_lvalue_expr' +/// '__is_rvalue_expr' /// ExprResult Parser::ParseCastExpression(bool isUnaryExpression, bool isAddressOfOperand, @@ -610,6 +649,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_nullptr: return Actions.ActOnCXXNullPtrLiteral(ConsumeToken()); + case tok::annot_primary_expr: + assert(Res.get() == 0 && "Stray primary-expression annotation?"); + Res = getExprAnnotation(Tok); + ConsumeToken(); + break; + case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant @@ -683,7 +728,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (ParsedType Typ = Actions.getTypeName(II, ILoc, getCurScope())) if (Typ.get()->isObjCObjectOrInterfaceType()) { // Fake up a Declarator to use with ActOnTypeName. - DeclSpec DS; + DeclSpec DS(AttrFactory); DS.SetRangeStart(ILoc); DS.SetRangeEnd(ILoc); const char *PrevSpec = 0; @@ -731,6 +776,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::wide_string_literal: Res = ParseStringLiteralExpression(); break; + case tok::kw__Generic: // primary-expression: generic-selection [C1X 6.5.1] + Res = ParseGenericSelectionExpression(); + break; case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: @@ -788,7 +836,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___alignof: // unary-expression: '__alignof' unary-expression // unary-expression: '__alignof' '(' type-name ')' // unary-expression: 'alignof' '(' type-id ')' - return ParseSizeofAlignofExpression(); + case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression + return ParseUnaryExprOrTypeTraitExpression(); case tok::ampamp: { // unary-expression: '&&' identifier SourceLocation AmpAmpLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) @@ -825,7 +874,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ParsedType Type = getTypeAnnotation(Tok); // Fake up a Declarator to use with ActOnTypeName. - DeclSpec DS; + DeclSpec DS(AttrFactory); DS.SetRangeStart(Tok.getLocation()); DS.SetRangeEnd(Tok.getLastLoc()); @@ -854,6 +903,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_short: case tok::kw_int: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_float: @@ -875,7 +925,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // postfix-expression: simple-type-specifier '(' expression-list[opt] ')' // - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseCXXSimpleTypeSpecifier(DS); if (Tok.isNot(tok::l_paren)) return ExprError(Diag(Tok, diag::err_expected_lparen_after_type) @@ -904,7 +954,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // cast expression. CXXScopeSpec SS; ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); - AnnotateTemplateIdTokenAsType(&SS); + AnnotateTemplateIdTokenAsType(); return ParseCastExpression(isUnaryExpression, isAddressOfOperand, NotCastExpr, TypeOfCast); } @@ -978,14 +1028,39 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return move(Result); } - case tok::kw___is_pod: // [GNU] unary-type-trait + case tok::kw___is_abstract: // [GNU] unary-type-trait case tok::kw___is_class: - case tok::kw___is_enum: - case tok::kw___is_union: case tok::kw___is_empty: - case tok::kw___is_polymorphic: - case tok::kw___is_abstract: + case tok::kw___is_enum: case tok::kw___is_literal: + case tok::kw___is_arithmetic: + case tok::kw___is_integral: + case tok::kw___is_floating_point: + case tok::kw___is_complete_type: + case tok::kw___is_void: + case tok::kw___is_array: + case tok::kw___is_function: + case tok::kw___is_reference: + case tok::kw___is_lvalue_reference: + case tok::kw___is_rvalue_reference: + case tok::kw___is_fundamental: + case tok::kw___is_object: + case tok::kw___is_scalar: + case tok::kw___is_compound: + case tok::kw___is_pointer: + case tok::kw___is_member_object_pointer: + case tok::kw___is_member_function_pointer: + case tok::kw___is_member_pointer: + case tok::kw___is_const: + case tok::kw___is_volatile: + case tok::kw___is_standard_layout: + case tok::kw___is_signed: + case tok::kw___is_unsigned: + case tok::kw___is_literal_type: + case tok::kw___is_pod: + case tok::kw___is_polymorphic: + case tok::kw___is_trivial: + case tok::kw___is_union: case tok::kw___has_trivial_constructor: case tok::kw___has_trivial_copy: case tok::kw___has_trivial_assign: @@ -998,9 +1073,19 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___builtin_types_compatible_p: case tok::kw___is_base_of: + case tok::kw___is_same: + case tok::kw___is_convertible: case tok::kw___is_convertible_to: return ParseBinaryTypeTrait(); + case tok::kw___array_rank: + case tok::kw___array_extent: + return ParseArrayTypeTrait(); + + case tok::kw___is_lvalue_expr: + case tok::kw___is_rvalue_expr: + return ParseExpressionTrait(); + case tok::at: { SourceLocation AtLoc = ConsumeToken(); return ParseObjCAtExpression(AtLoc); @@ -1256,10 +1341,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } } -/// ParseExprAfterTypeofSizeofAlignof - We parsed a typeof/sizeof/alignof and -/// we are at the start of an expression or a parenthesized type-id. -/// OpTok is the operand token (typeof/sizeof/alignof). Returns the expression -/// (isCastExpr == false) or the type (isCastExpr == true). +/// ParseExprAfterUnaryExprOrTypeTrait - We parsed a typeof/sizeof/alignof/ +/// vec_step and we are at the start of an expression or a parenthesized +/// type-id. OpTok is the operand token (typeof/sizeof/alignof). Returns the +/// expression (isCastExpr == false) or the type (isCastExpr == true). /// /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression @@ -1273,15 +1358,20 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { /// typeof ( type-name ) /// [GNU/C++] typeof unary-expression /// +/// [OpenCL 1.1 6.11.12] vec_step built-in function: +/// vec_step ( expressions ) +/// vec_step ( type-name ) +/// ExprResult -Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, - bool &isCastExpr, - ParsedType &CastTy, - SourceRange &CastRange) { +Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, + bool &isCastExpr, + ParsedType &CastTy, + SourceRange &CastRange) { assert((OpTok.is(tok::kw_typeof) || OpTok.is(tok::kw_sizeof) || - OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof)) && - "Not a typeof/sizeof/alignof expression!"); + OpTok.is(tok::kw___alignof) || OpTok.is(tok::kw_alignof) || + OpTok.is(tok::kw_vec_step)) && + "Not a typeof/sizeof/alignof/vec_step expression!"); ExprResult Operand; @@ -1345,7 +1435,7 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, } -/// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression. +/// ParseUnaryExprOrTypeTraitExpression - Parse a sizeof or alignof expression. /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' @@ -1353,10 +1443,10 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok, /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' -ExprResult Parser::ParseSizeofAlignofExpression() { +ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof) - || Tok.is(tok::kw_alignof)) && - "Not a sizeof/alignof expression!"); + || Tok.is(tok::kw_alignof) || Tok.is(tok::kw_vec_step)) && + "Not a sizeof/alignof/vec_step expression!"); Token OpTok = Tok; ConsumeToken(); @@ -1403,24 +1493,31 @@ ExprResult Parser::ParseSizeofAlignofExpression() { bool isCastExpr; ParsedType CastTy; SourceRange CastRange; - ExprResult Operand = ParseExprAfterTypeofSizeofAlignof(OpTok, - isCastExpr, - CastTy, - CastRange); + ExprResult Operand = ParseExprAfterUnaryExprOrTypeTrait(OpTok, + isCastExpr, + CastTy, + CastRange); + + UnaryExprOrTypeTrait ExprKind = UETT_SizeOf; + if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw___alignof)) + ExprKind = UETT_AlignOf; + else if (OpTok.is(tok::kw_vec_step)) + ExprKind = UETT_VecStep; if (isCastExpr) - return Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(), - OpTok.is(tok::kw_sizeof), - /*isType=*/true, - CastTy.getAsOpaquePtr(), - CastRange); + return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), + ExprKind, + /*isType=*/true, + CastTy.getAsOpaquePtr(), + CastRange); // If we get here, the operand to the sizeof/alignof was an expresion. if (!Operand.isInvalid()) - Operand = Actions.ActOnSizeOfAlignOfExpr(OpTok.getLocation(), - OpTok.is(tok::kw_sizeof), - /*isType=*/false, - Operand.release(), CastRange); + Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), + ExprKind, + /*isType=*/false, + Operand.release(), + CastRange); return move(Operand); } @@ -1618,15 +1715,18 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, ConsumeCodeCompletionToken(); return ExprError(); } + + // None of these cases should fall through with an invalid Result + // unless they've already reported an error. if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); StmtResult Stmt(ParseCompoundStatement(attrs, true)); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. - if (!Stmt.isInvalid() && Tok.is(tok::r_paren)) + if (!Stmt.isInvalid()) Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.take(), Tok.getLocation()); } else if (ExprType >= CompoundLiteral && @@ -1724,6 +1824,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, Result = ParseExpression(); ExprType = SimpleExpr; + + // Don't build a paren expression unless we actually match a ')'. if (!Result.isInvalid() && Tok.is(tok::r_paren)) Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.take()); } @@ -1784,6 +1886,100 @@ ExprResult Parser::ParseStringLiteralExpression() { return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size()); } +/// ParseGenericSelectionExpression - Parse a C1X generic-selection +/// [C1X 6.5.1.1]. +/// +/// generic-selection: +/// _Generic ( assignment-expression , generic-assoc-list ) +/// generic-assoc-list: +/// generic-association +/// generic-assoc-list , generic-association +/// generic-association: +/// type-name : assignment-expression +/// default : assignment-expression +ExprResult Parser::ParseGenericSelectionExpression() { + assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected"); + SourceLocation KeyLoc = ConsumeToken(); + + if (!getLang().C1X) + Diag(KeyLoc, diag::ext_c1x_generic_selection); + + SourceLocation LParenLoc = Tok.getLocation(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, "")) + return ExprError(); + + ExprResult ControllingExpr; + { + // C1X 6.5.1.1p3 "The controlling expression of a generic selection is + // not evaluated." + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + ControllingExpr = ParseAssignmentExpression(); + if (ControllingExpr.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + } + + if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "")) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + SourceLocation DefaultLoc; + TypeVector Types(Actions); + ExprVector Exprs(Actions); + while (1) { + ParsedType Ty; + if (Tok.is(tok::kw_default)) { + // C1X 6.5.1.1p2 "A generic selection shall have no more than one default + // generic association." + if (!DefaultLoc.isInvalid()) { + Diag(Tok, diag::err_duplicate_default_assoc); + Diag(DefaultLoc, diag::note_previous_default_assoc); + SkipUntil(tok::r_paren); + return ExprError(); + } + DefaultLoc = ConsumeToken(); + Ty = ParsedType(); + } else { + ColonProtectionRAIIObject X(*this); + TypeResult TR = ParseTypeName(); + if (TR.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + Ty = TR.release(); + } + Types.push_back(Ty); + + if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "")) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + // FIXME: These expressions should be parsed in a potentially potentially + // evaluated context. + ExprResult ER(ParseAssignmentExpression()); + if (ER.isInvalid()) { + SkipUntil(tok::r_paren); + return ExprError(); + } + Exprs.push_back(ER.release()); + + if (Tok.isNot(tok::comma)) + break; + ConsumeToken(); + } + + SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + if (RParenLoc.isInvalid()) + return ExprError(); + + return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, + ControllingExpr.release(), + move_arg(Types), move_arg(Exprs)); +} + /// ParseExpressionList - Used for C/C++ (argument-)expression-list. /// /// argument-expression-list: @@ -1837,7 +2033,7 @@ void Parser::ParseBlockId() { } // Parse the specifier-qualifier-list piece. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); // Parse the block-declarator. @@ -1845,7 +2041,7 @@ void Parser::ParseBlockId() { ParseDeclarator(DeclaratorInfo); // We do this for: ^ __attribute__((noreturn)) {, as DS has the attributes. - DeclaratorInfo.addAttributes(DS.takeAttributes()); + DeclaratorInfo.takeAttributes(DS.getAttributes(), SourceLocation()); MaybeParseGNUAttributes(DeclaratorInfo); @@ -1881,7 +2077,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { Actions.ActOnBlockStart(CaretLoc, getCurScope()); // Parse the return type if present. - DeclSpec DS; + DeclSpec DS(AttrFactory); Declarator ParamInfo(DS, Declarator::BlockLiteralContext); // FIXME: Since the return type isn't actually parsed, it can't be used to // fill ParamInfo with an initial valid range, so do it manually. @@ -1913,16 +2109,17 @@ ExprResult Parser::ParseBlockLiteralExpression() { ParseBlockId(); } else { // Otherwise, pretend we saw (void). - ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(), - true, false, + ParsedAttributes attrs(AttrFactory); + ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, SourceLocation(), 0, 0, 0, true, SourceLocation(), - false, SourceLocation(), - false, 0, 0, 0, + EST_None, + SourceLocation(), + 0, 0, 0, 0, CaretLoc, CaretLoc, ParamInfo), - CaretLoc); + attrs, CaretLoc); MaybeParseGNUAttributes(ParamInfo); @@ -1940,6 +2137,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { } StmtResult Stmt(ParseCompoundStatementBody()); + BlockScope.Exit(); if (!Stmt.isInvalid()) Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.take(), getCurScope()); else diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp index d8db711..8bf6f63 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseExprCXX.cpp @@ -20,6 +20,55 @@ using namespace clang; +static int SelectDigraphErrorMessage(tok::TokenKind Kind) { + switch (Kind) { + case tok::kw_template: return 0; + case tok::kw_const_cast: return 1; + case tok::kw_dynamic_cast: return 2; + case tok::kw_reinterpret_cast: return 3; + case tok::kw_static_cast: return 4; + default: + assert(0 && "Unknown type for digraph error message."); + return -1; + } +} + +// Are the two tokens adjacent in the same source file? +static bool AreTokensAdjacent(Preprocessor &PP, Token &First, Token &Second) { + SourceManager &SM = PP.getSourceManager(); + SourceLocation FirstLoc = SM.getSpellingLoc(First.getLocation()); + SourceLocation FirstEnd = FirstLoc.getFileLocWithOffset(First.getLength()); + return FirstEnd == SM.getSpellingLoc(Second.getLocation()); +} + +// Suggest fixit for "<::" after a cast. +static void FixDigraph(Parser &P, Preprocessor &PP, Token &DigraphToken, + Token &ColonToken, tok::TokenKind Kind, bool AtDigraph) { + // Pull '<:' and ':' off token stream. + if (!AtDigraph) + PP.Lex(DigraphToken); + PP.Lex(ColonToken); + + SourceRange Range; + Range.setBegin(DigraphToken.getLocation()); + Range.setEnd(ColonToken.getLocation()); + P.Diag(DigraphToken.getLocation(), diag::err_missing_whitespace_digraph) + << SelectDigraphErrorMessage(Kind) + << FixItHint::CreateReplacement(Range, "< ::"); + + // Update token information to reflect their change in token type. + ColonToken.setKind(tok::coloncolon); + ColonToken.setLocation(ColonToken.getLocation().getFileLocWithOffset(-1)); + ColonToken.setLength(2); + DigraphToken.setKind(tok::less); + DigraphToken.setLength(1); + + // Push new tokens back to token stream. + PP.EnterToken(ColonToken); + if (!AtDigraph) + PP.EnterToken(DigraphToken); +} + /// \brief Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which @@ -60,7 +109,8 @@ using namespace clang; bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext, - bool *MayBePseudoDestructor) { + bool *MayBePseudoDestructor, + bool IsTypename) { assert(getLang().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -111,7 +161,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // Code completion for a nested-name-specifier, where the code // code completion token follows the '::'. Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext); - ConsumeCodeCompletionToken(); + SourceLocation ccLoc = ConsumeCodeCompletionToken(); + // Include code completion token into the range of the scope otherwise + // when we try to annotate the scope tokens the dangling code completion + // token will cause assertion in + // Preprocessor::AnnotatePreviousCachedTokens. + SS.setEndLoc(ccLoc); } } @@ -173,7 +228,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ObjectType, EnteringContext, Template)) { - if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName, + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, TemplateKWLoc, false)) return true; } else @@ -197,35 +252,37 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, return false; } - if (TemplateId->Kind == TNK_Type_template || - TemplateId->Kind == TNK_Dependent_template_name) { - AnnotateTemplateIdTokenAsType(&SS); + // Consume the template-id token. + ConsumeToken(); + + assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); + SourceLocation CCLoc = ConsumeToken(); - assert(Tok.is(tok::annot_typename) && - "AnnotateTemplateIdTokenAsType isn't working"); - Token TypeToken = Tok; - ConsumeToken(); - assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); - SourceLocation CCLoc = ConsumeToken(); - - if (!HasScopeSpecifier) - HasScopeSpecifier = true; - - if (ParsedType T = getTypeAnnotation(TypeToken)) { - if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), T, CCLoc, SS)) - SS.SetInvalid(SourceRange(SS.getBeginLoc(), CCLoc)); - - continue; - } else { - SourceLocation Start = SS.getBeginLoc().isValid()? SS.getBeginLoc() - : CCLoc; - SS.SetInvalid(SourceRange(Start, CCLoc)); - } - - continue; + if (!HasScopeSpecifier) + HasScopeSpecifier = true; + + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + + if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), + /*FIXME:*/SourceLocation(), + SS, + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc, + CCLoc, + EnteringContext)) { + SourceLocation StartLoc + = SS.getBeginLoc().isValid()? SS.getBeginLoc() + : TemplateId->TemplateNameLoc; + SS.SetInvalid(SourceRange(StartLoc, CCLoc)); } - - assert(false && "FIXME: Only type template names supported here"); + + TemplateId->Destroy(); + continue; } @@ -284,6 +341,29 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, continue; } + // Check for '<::' which should be '< ::' instead of '[:' when following + // a template name. + if (Next.is(tok::l_square) && Next.getLength() == 2) { + Token SecondToken = GetLookAheadToken(2); + if (SecondToken.is(tok::colon) && + AreTokensAdjacent(PP, Next, SecondToken)) { + TemplateTy Template; + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&II, Tok.getLocation()); + bool MemberOfUnknownSpecialization; + if (Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, + TemplateName, + ObjectType, + EnteringContext, + Template, + MemberOfUnknownSpecialization)) { + FixDigraph(*this, PP, Next, SecondToken, tok::kw_template, + /*AtDigraph*/false); + } + } + } + // nested-name-specifier: // type-name '<' if (Next.is(tok::less)) { @@ -305,19 +385,23 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // specializations) still want to see the original template-id // token. ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName, + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, SourceLocation(), false)) return true; continue; } if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && - IsTemplateArgumentList(1)) { + (IsTypename || IsTemplateArgumentList(1))) { // We have something like t::getAs<T>, where getAs is a // member of an unknown specialization. However, this will only // parse correctly as a template, so suggest the keyword 'template' // before 'getAs' and treat this as a dependent template name. - Diag(Tok.getLocation(), diag::err_missing_dependent_template_keyword) + unsigned DiagID = diag::err_missing_dependent_template_keyword; + if (getLang().Microsoft) + DiagID = diag::warn_missing_dependent_template_keyword; + + Diag(Tok.getLocation(), DiagID) << II.getName() << FixItHint::CreateInsertion(Tok.getLocation(), "template "); @@ -328,7 +412,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, EnteringContext, Template)) { // Consume the identifier. ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName, + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName, SourceLocation(), false)) return true; } @@ -446,6 +530,13 @@ ExprResult Parser::ParseCXXCasts() { SourceLocation OpLoc = ConsumeToken(); SourceLocation LAngleBracketLoc = Tok.getLocation(); + // Check for "<::" which is parsed as "[:". If found, fix token stream, + // diagnose error, suggest fix, and recover parsing. + Token Next = NextToken(); + if (Tok.is(tok::l_square) && Tok.getLength() == 2 && Next.is(tok::colon) && + AreTokensAdjacent(PP, Tok, Next)) + FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true); + if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName)) return ExprError(); @@ -525,7 +616,15 @@ ExprResult Parser::ParseCXXTypeid() { RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); if (RParenLoc.isInvalid()) return ExprError(); - + + // If we are a foo<int> that identifies a single function, resolve it now... + Expr* e = Result.get(); + if (e->getType() == Actions.Context.OverloadTy) { + ExprResult er = + Actions.ResolveAndFixSingleFunctionTemplateSpecialization(e); + if (er.isUsable()) + Result = er.release(); + } Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false, Result.release(), RParenLoc); } @@ -790,7 +889,7 @@ bool Parser::ParseCXXCondition(ExprResult &ExprOut, } // type-specifier-seq - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); // declarator @@ -846,6 +945,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const { case tok::annot_typename: case tok::kw_short: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_void: @@ -857,8 +957,7 @@ bool Parser::isCXXSimpleTypeSpecifier() const { case tok::kw_char16_t: case tok::kw_char32_t: case tok::kw_bool: - // FIXME: C++0x decltype support. - // GNU typeof support. + case tok::kw_decltype: case tok::kw_typeof: return true; @@ -938,6 +1037,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::kw_long: DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec, DiagID); break; + case tok::kw___int64: + DS.SetTypeSpecWidth(DeclSpec::TSW_longlong, Loc, PrevSpec, DiagID); + break; case tok::kw_signed: DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec, DiagID); break; @@ -1157,7 +1259,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateArgList TemplateArgs; if (Tok.is(tok::less) && ParseTemplateIdAfterTemplateName(Template, Id.StartLocation, - &SS, true, LAngleLoc, + SS, true, LAngleLoc, TemplateArgs, RAngleLoc)) return true; @@ -1180,6 +1282,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, TemplateId->TemplateNameLoc = Id.StartLocation; } + TemplateId->SS = SS; TemplateId->Template = Template; TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; @@ -1199,7 +1302,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, // Constructor and destructor names. TypeResult Type - = Actions.ActOnTemplateIdType(Template, NameLoc, + = Actions.ActOnTemplateIdType(SS, Template, NameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc); if (Type.isInvalid()) @@ -1380,7 +1483,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // ptr-operator conversion-declarator[opt] // Parse the type-specifier-seq. - DeclSpec DS; + DeclSpec DS(AttrFactory); if (ParseCXXTypeSpecifierSeq(DS)) // FIXME: ObjectType? return true; @@ -1465,7 +1568,9 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, Actions.isCurrentClassName(*Id, getCurScope(), &SS)) { // We have parsed a constructor name. Result.setConstructorName(Actions.getTypeName(*Id, IdLoc, getCurScope(), - &SS, false), + &SS, false, false, + ParsedType(), + /*NonTrivialTypeSourceInfo=*/true), IdLoc, IdLoc); } else { // We have parsed an identifier. @@ -1503,7 +1608,9 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, Result.setConstructorName(Actions.getTypeName(*TemplateId->Name, TemplateId->TemplateNameLoc, getCurScope(), - &SS, false), + &SS, false, false, + ParsedType(), + /*NontrivialTypeSourceInfo=*/true), TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); TemplateId->Destroy(); @@ -1608,6 +1715,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, /// /// new-type-id: /// type-specifier-seq new-declarator[opt] +/// [GNU] attributes type-specifier-seq new-declarator[opt] /// /// new-declarator: /// ptr-operator new-declarator[opt] @@ -1629,7 +1737,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { SourceLocation PlacementLParen, PlacementRParen; SourceRange TypeIdParens; - DeclSpec DS; + DeclSpec DS(AttrFactory); Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); if (Tok.is(tok::l_paren)) { // If it turns out to be a placement, we change the type location. @@ -1653,12 +1761,14 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { // We still need the type. if (Tok.is(tok::l_paren)) { TypeIdParens.setBegin(ConsumeParen()); + MaybeParseGNUAttributes(DeclaratorInfo); ParseSpecifierQualifierList(DS); DeclaratorInfo.SetSourceRange(DS.getSourceRange()); ParseDeclarator(DeclaratorInfo); TypeIdParens.setEnd(MatchRHSPunctuation(tok::r_paren, TypeIdParens.getBegin())); } else { + MaybeParseGNUAttributes(DeclaratorInfo); if (ParseCXXTypeSpecifierSeq(DS)) DeclaratorInfo.setInvalidType(true); else { @@ -1671,6 +1781,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { } else { // A new-type-id is a simplified type-id, where essentially the // direct-declarator is replaced by a direct-new-declarator. + MaybeParseGNUAttributes(DeclaratorInfo); if (ParseCXXTypeSpecifierSeq(DS)) DeclaratorInfo.setInvalidType(true); else { @@ -1731,10 +1842,12 @@ void Parser::ParseDirectNewDeclarator(Declarator &D) { first = false; SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc); - D.AddTypeInfo(DeclaratorChunk::getArray(0, ParsedAttributes(), + + ParsedAttributes attrs(AttrFactory); + D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false, Size.release(), LLoc, RLoc), - RLoc); + attrs, RLoc); if (RLoc.isInvalid()) return; @@ -1803,23 +1916,48 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { switch(kind) { - default: llvm_unreachable("Not a known unary type trait"); + default: assert(false && "Not a known unary type trait."); case tok::kw___has_nothrow_assign: return UTT_HasNothrowAssign; - case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy; case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor; + case tok::kw___has_nothrow_copy: return UTT_HasNothrowCopy; case tok::kw___has_trivial_assign: return UTT_HasTrivialAssign; - case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy; case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor; + case tok::kw___has_trivial_copy: return UTT_HasTrivialCopy; case tok::kw___has_trivial_destructor: return UTT_HasTrivialDestructor; case tok::kw___has_virtual_destructor: return UTT_HasVirtualDestructor; case tok::kw___is_abstract: return UTT_IsAbstract; + case tok::kw___is_arithmetic: return UTT_IsArithmetic; + case tok::kw___is_array: return UTT_IsArray; case tok::kw___is_class: return UTT_IsClass; + case tok::kw___is_complete_type: return UTT_IsCompleteType; + case tok::kw___is_compound: return UTT_IsCompound; + case tok::kw___is_const: return UTT_IsConst; case tok::kw___is_empty: return UTT_IsEmpty; case tok::kw___is_enum: return UTT_IsEnum; + case tok::kw___is_floating_point: return UTT_IsFloatingPoint; + case tok::kw___is_function: return UTT_IsFunction; + case tok::kw___is_fundamental: return UTT_IsFundamental; + case tok::kw___is_integral: return UTT_IsIntegral; + case tok::kw___is_lvalue_reference: return UTT_IsLvalueReference; + case tok::kw___is_member_function_pointer: return UTT_IsMemberFunctionPointer; + case tok::kw___is_member_object_pointer: return UTT_IsMemberObjectPointer; + case tok::kw___is_member_pointer: return UTT_IsMemberPointer; + case tok::kw___is_object: return UTT_IsObject; + case tok::kw___is_literal: return UTT_IsLiteral; + case tok::kw___is_literal_type: return UTT_IsLiteral; case tok::kw___is_pod: return UTT_IsPOD; + case tok::kw___is_pointer: return UTT_IsPointer; case tok::kw___is_polymorphic: return UTT_IsPolymorphic; + case tok::kw___is_reference: return UTT_IsReference; + case tok::kw___is_rvalue_reference: return UTT_IsRvalueReference; + case tok::kw___is_scalar: return UTT_IsScalar; + case tok::kw___is_signed: return UTT_IsSigned; + case tok::kw___is_standard_layout: return UTT_IsStandardLayout; + case tok::kw___is_trivial: return UTT_IsTrivial; case tok::kw___is_union: return UTT_IsUnion; - case tok::kw___is_literal: return UTT_IsLiteral; + case tok::kw___is_unsigned: return UTT_IsUnsigned; + case tok::kw___is_void: return UTT_IsVoid; + case tok::kw___is_volatile: return UTT_IsVolatile; } } @@ -1827,11 +1965,29 @@ static BinaryTypeTrait BinaryTypeTraitFromTokKind(tok::TokenKind kind) { switch(kind) { default: llvm_unreachable("Not a known binary type trait"); case tok::kw___is_base_of: return BTT_IsBaseOf; + case tok::kw___is_convertible: return BTT_IsConvertible; + case tok::kw___is_same: return BTT_IsSame; case tok::kw___builtin_types_compatible_p: return BTT_TypeCompatible; case tok::kw___is_convertible_to: return BTT_IsConvertibleTo; } } +static ArrayTypeTrait ArrayTypeTraitFromTokKind(tok::TokenKind kind) { + switch(kind) { + default: llvm_unreachable("Not a known binary type trait"); + case tok::kw___array_rank: return ATT_ArrayRank; + case tok::kw___array_extent: return ATT_ArrayExtent; + } +} + +static ExpressionTrait ExpressionTraitFromTokKind(tok::TokenKind kind) { + switch(kind) { + default: assert(false && "Not a known unary expression trait."); + case tok::kw___is_lvalue_expr: return ET_IsLValueExpr; + case tok::kw___is_rvalue_expr: return ET_IsRValueExpr; + } +} + /// ParseUnaryTypeTrait - Parse the built-in unary type-trait /// pseudo-functions that allow implementation of the TR1/C++0x type traits /// templates. @@ -1897,6 +2053,72 @@ ExprResult Parser::ParseBinaryTypeTrait() { return Actions.ActOnBinaryTypeTrait(BTT, Loc, LhsTy.get(), RhsTy.get(), RParen); } +/// ParseArrayTypeTrait - Parse the built-in array type-trait +/// pseudo-functions. +/// +/// primary-expression: +/// [Embarcadero] '__array_rank' '(' type-id ')' +/// [Embarcadero] '__array_extent' '(' type-id ',' expression ')' +/// +ExprResult Parser::ParseArrayTypeTrait() { + ArrayTypeTrait ATT = ArrayTypeTraitFromTokKind(Tok.getKind()); + SourceLocation Loc = ConsumeToken(); + + SourceLocation LParen = Tok.getLocation(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen)) + return ExprError(); + + TypeResult Ty = ParseTypeName(); + if (Ty.isInvalid()) { + SkipUntil(tok::comma); + SkipUntil(tok::r_paren); + return ExprError(); + } + + switch (ATT) { + case ATT_ArrayRank: { + SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), NULL, RParen); + } + case ATT_ArrayExtent: { + if (ExpectAndConsume(tok::comma, diag::err_expected_comma)) { + SkipUntil(tok::r_paren); + return ExprError(); + } + + ExprResult DimExpr = ParseExpression(); + SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + + return Actions.ActOnArrayTypeTrait(ATT, Loc, Ty.get(), DimExpr.get(), RParen); + } + default: + break; + } + return ExprError(); +} + +/// ParseExpressionTrait - Parse built-in expression-trait +/// pseudo-functions like __is_lvalue_expr( xxx ). +/// +/// primary-expression: +/// [Embarcadero] expression-trait '(' expression ')' +/// +ExprResult Parser::ParseExpressionTrait() { + ExpressionTrait ET = ExpressionTraitFromTokKind(Tok.getKind()); + SourceLocation Loc = ConsumeToken(); + + SourceLocation LParen = Tok.getLocation(); + if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen)) + return ExprError(); + + ExprResult Expr = ParseExpression(); + + SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen); + + return Actions.ActOnExpressionTrait(ET, Loc, Expr.get(), RParen); +} + + /// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a /// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate /// based on the context past the parens. diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp index 82dda2b..2c9278a 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseInit.cpp @@ -354,7 +354,7 @@ ExprResult Parser::ParseBraceInitializer() { InitExprsOk = false; // We have two ways to try to recover from this error: if the code looks - // gramatically ok (i.e. we have a comma coming up) try to continue + // grammatically ok (i.e. we have a comma coming up) try to continue // parsing the rest of the initializer. This allows us to emit // diagnostics for later elements that we find. If we don't see a comma, // assume there is a parse error, and just skip to recover. diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp index f32a322..fdbedc5 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseObjc.cpp @@ -41,11 +41,11 @@ Decl *Parser::ParseObjCAtDirectives() { case tok::objc_class: return ParseObjCAtClassDeclaration(AtLoc); case tok::objc_interface: { - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); return ParseObjCAtInterfaceDeclaration(AtLoc, attrs); } case tok::objc_protocol: { - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); return ParseObjCAtProtocolDeclaration(AtLoc, attrs); } case tok::objc_implementation: @@ -327,7 +327,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, // If this is a method prototype, parse it. if (Tok.is(tok::minus) || Tok.is(tok::plus)) { Decl *methodPrototype = - ParseObjCMethodPrototype(interfaceDecl, MethodImplKind); + ParseObjCMethodPrototype(interfaceDecl, MethodImplKind, false); allMethods.push_back(methodPrototype); // Consume the ';' here, since ParseObjCMethodPrototype() is re-used for // method definitions. @@ -340,7 +340,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, ParseObjCMethodDecl(Tok.getLocation(), tok::minus, interfaceDecl, - MethodImplKind); + MethodImplKind, false); continue; } // Ignore excess semicolons. @@ -371,7 +371,7 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, // FIXME: as the name implies, this rule allows function definitions. // We could pass a flag or check for functions during semantic analysis. - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs)); continue; } @@ -439,11 +439,10 @@ void Parser::ParseObjCInterfaceDeclList(Decl *interfaceDecl, OCDS, AtLoc, MethodImplKind); // Parse all the comma separated declarators. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseStructDeclaration(DS, Callback); - ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list, "", - tok::at); + ExpectAndConsume(tok::semi, diag::err_expected_semi_decl_list); break; } } @@ -582,12 +581,14 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS, Decl *ClassDecl) { /// __attribute__((deprecated)) /// Decl *Parser::ParseObjCMethodPrototype(Decl *IDecl, - tok::ObjCKeywordKind MethodImplKind) { + tok::ObjCKeywordKind MethodImplKind, + bool MethodDefinition) { assert((Tok.is(tok::minus) || Tok.is(tok::plus)) && "expected +/-"); tok::TokenKind methodType = Tok.getKind(); SourceLocation mLoc = ConsumeToken(); - Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind); + Decl *MDecl = ParseObjCMethodDecl(mLoc, methodType, IDecl,MethodImplKind, + MethodDefinition); // Since this rule is used for both method declarations and definitions, // the caller is (optionally) responsible for consuming the ';'. return MDecl; @@ -720,10 +721,12 @@ bool Parser::isTokIdentifier_in() const { /// objc-type-qualifier /// objc-type-qualifiers objc-type-qualifier /// -void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter) { +void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, + ObjCTypeNameContext Context) { while (1) { if (Tok.is(tok::code_completion)) { - Actions.CodeCompleteObjCPassingType(getCurScope(), DS, IsParameter); + Actions.CodeCompleteObjCPassingType(getCurScope(), DS, + Context == OTN_ParameterType); ConsumeCodeCompletionToken(); } @@ -760,18 +763,19 @@ void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS, bool IsParameter) { /// '(' objc-type-qualifiers[opt] type-name ')' /// '(' objc-type-qualifiers[opt] ')' /// -ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, bool IsParameter) { +ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, + ObjCTypeNameContext Context) { assert(Tok.is(tok::l_paren) && "expected ("); SourceLocation LParenLoc = ConsumeParen(); SourceLocation TypeStartLoc = Tok.getLocation(); // Parse type qualifiers, in, inout, etc. - ParseObjCTypeQualifierList(DS, IsParameter); + ParseObjCTypeQualifierList(DS, Context); ParsedType Ty; if (isTypeSpecifierQualifier()) { - TypeResult TypeSpec = ParseTypeName(); + TypeResult TypeSpec = ParseTypeName(0, Declarator::ObjCPrototypeContext); if (!TypeSpec.isInvalid()) Ty = TypeSpec.get(); } @@ -821,7 +825,8 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, bool IsParameter) { Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, Decl *IDecl, - tok::ObjCKeywordKind MethodImplKind) { + tok::ObjCKeywordKind MethodImplKind, + bool MethodDefinition) { ParsingDeclRAIIObject PD(*this); if (Tok.is(tok::code_completion)) { @@ -834,12 +839,12 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ParsedType ReturnType; ObjCDeclSpec DSRet; if (Tok.is(tok::l_paren)) - ReturnType = ParseObjCTypeName(DSRet, false); + ReturnType = ParseObjCTypeName(DSRet, OTN_ResultType); // If attributes exist before the method, parse them. - ParsedAttributes attrs; + ParsedAttributes methodAttrs(AttrFactory); if (getLang().ObjC2) - MaybeParseGNUAttributes(attrs); + MaybeParseGNUAttributes(methodAttrs); if (Tok.is(tok::code_completion)) { Actions.CodeCompleteObjCMethodDecl(getCurScope(), mType == tok::minus, @@ -864,7 +869,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, if (Tok.isNot(tok::colon)) { // If attributes exist after the method, parse them. if (getLang().ObjC2) - MaybeParseGNUAttributes(attrs); + MaybeParseGNUAttributes(methodAttrs); Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent); Decl *Result @@ -872,7 +877,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, mType, IDecl, DSRet, ReturnType, Sel, 0, CParamInfo.data(), CParamInfo.size(), - attrs.getList(), MethodImplKind); + methodAttrs.getList(), MethodImplKind, + false, MethodDefinition); PD.complete(Result); return Result; } @@ -881,8 +887,11 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, llvm::SmallVector<Sema::ObjCArgInfo, 12> ArgInfos; ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope|Scope::DeclScope); + + AttributePool allParamAttrs(AttrFactory); while (1) { + ParsedAttributes paramAttrs(AttrFactory); Sema::ObjCArgInfo ArgInfo; // Each iteration parses a single keyword argument. @@ -894,14 +903,13 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ArgInfo.Type = ParsedType(); if (Tok.is(tok::l_paren)) // Parse the argument type if present. - ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, true); + ArgInfo.Type = ParseObjCTypeName(ArgInfo.DeclSpec, OTN_ParameterType); // If attributes exist before the argument name, parse them. ArgInfo.ArgAttrs = 0; if (getLang().ObjC2) { - ParsedAttributes attrs; - MaybeParseGNUAttributes(attrs); - ArgInfo.ArgAttrs = attrs.getList(); + MaybeParseGNUAttributes(paramAttrs); + ArgInfo.ArgAttrs = paramAttrs.getList(); } // Code completion for the next piece of the selector. @@ -930,6 +938,9 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ArgInfos.push_back(ArgInfo); KeyIdents.push_back(SelIdent); + // Make sure the attributes persist. + allParamAttrs.takeAllFrom(paramAttrs.getPool()); + // Code completion for the next piece of the selector. if (Tok.is(tok::code_completion)) { ConsumeCodeCompletionToken(); @@ -960,7 +971,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, ConsumeToken(); break; } - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); // Parse the declarator. Declarator ParmDecl(DS, Declarator::PrototypeContext); @@ -977,7 +988,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, // FIXME: Add support for optional parameter list... // If attributes exist after the method, parse them. if (getLang().ObjC2) - MaybeParseGNUAttributes(attrs); + MaybeParseGNUAttributes(methodAttrs); if (KeyIdents.size() == 0) { // Leave prototype scope. @@ -992,8 +1003,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, mType, IDecl, DSRet, ReturnType, Sel, &ArgInfos[0], CParamInfo.data(), CParamInfo.size(), - attrs.getList(), - MethodImplKind, isVariadic); + methodAttrs.getList(), + MethodImplKind, isVariadic, MethodDefinition); // Leave prototype scope. PrototypeScope.Exit(); @@ -1165,7 +1176,7 @@ void Parser::ParseObjCClassInstanceVariables(Decl *interfaceDecl, } Callback(*this, interfaceDecl, visibility, AllIvarDecls); // Parse all the comma separated declarators. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseStructDeclaration(DS, Callback); if (Tok.is(tok::semi)) { @@ -1376,7 +1387,7 @@ Decl *Parser::ParseObjCAtEndDeclaration(SourceRange atEnd) { } else { // missing @implementation - Diag(atEnd.getBegin(), diag::warn_expected_implementation); + Diag(atEnd.getBegin(), diag::err_expected_implementation); } return Result; } @@ -1609,7 +1620,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { ConsumeParen(); ParseScope CatchScope(this, Scope::DeclScope|Scope::AtCatchScope); if (Tok.isNot(tok::ellipsis)) { - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); // For some odd reason, the name of the exception variable is // optional. As a result, we need to use "PrototypeContext", because @@ -1717,9 +1728,12 @@ Decl *Parser::ParseObjCMethodDefinition() { // specified Declarator for the method. Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl); - if (PP.isCodeCompletionEnabled()) - if (trySkippingFunctionBodyForCodeCompletion()) + if (PP.isCodeCompletionEnabled()) { + if (trySkippingFunctionBodyForCodeCompletion()) { + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(MDecl, 0); + } + } StmtResult FnBody(ParseCompoundStatementBody()); @@ -1728,12 +1742,11 @@ Decl *Parser::ParseObjCMethodDefinition() { FnBody = Actions.ActOnCompoundStmt(BraceLoc, BraceLoc, MultiStmtArg(Actions), false); - // TODO: Pass argument information. - Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); - // Leave the function body scope. BodyScope.Exit(); - + + // TODO: Pass argument information. + Actions.ActOnFinishFunctionBody(MDecl, FnBody.take()); return MDecl; } @@ -1839,7 +1852,7 @@ bool Parser::ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr) { // typename-specifier // simple-type-specifier // expression (that starts with one of the above) - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseCXXSimpleTypeSpecifier(DS); if (Tok.is(tok::l_paren)) { @@ -2337,7 +2350,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { return ExprError(Diag(Tok, diag::err_expected_colon)); ++nColons; - ConsumeToken(); // Eat the ':'. + ConsumeToken(); // Eat the ':' or '::'. if (Tok.is(tok::r_paren)) break; @@ -2353,7 +2366,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { SourceLocation Loc; SelIdent = ParseObjCSelectorPiece(Loc); KeyIdents.push_back(SelIdent); - if (!SelIdent && Tok.isNot(tok::colon)) + if (!SelIdent && Tok.isNot(tok::colon) && Tok.isNot(tok::coloncolon)) break; } } diff --git a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp index dfd0da0..46225c8 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp @@ -74,7 +74,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, return; } PP.Lex(Tok); - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "visibility"; return; @@ -168,7 +168,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, SourceLocation RParenLoc = Tok.getLocation(); PP.Lex(Tok); - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack"; return; } @@ -177,6 +177,38 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, LParenLoc, RParenLoc); } +// #pragma ms_struct on +// #pragma ms_struct off +void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &MSStructTok) { + Sema::PragmaMSStructKind Kind = Sema::PMSST_OFF; + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct); + return; + } + const IdentifierInfo *II = Tok.getIdentifierInfo(); + if (II->isStr("on")) { + Kind = Sema::PMSST_ON; + PP.Lex(Tok); + } + else if (II->isStr("off") || II->isStr("reset")) + PP.Lex(Tok); + else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct); + return; + } + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "ms_struct"; + return; + } + Actions.ActOnPragmaMSStruct(Kind); +} + // #pragma 'align' '=' {'native','natural','mac68k','power','reset'} // #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'} static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok, @@ -228,7 +260,7 @@ static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok, SourceLocation KindLoc = Tok.getLocation(); PP.Lex(Tok); - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << (IsOptions ? "options" : "align"); return; @@ -302,7 +334,7 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, } PP.Lex(Tok); - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "unused"; return; @@ -359,7 +391,7 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, PP.Lex(Tok); } - if (Tok.isNot(tok::eom)) { + if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak"; return; } @@ -387,7 +419,7 @@ void PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &Tok) { - PP.Lex(Tok); + PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::identifier)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "OPENCL"; diff --git a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h index bee6af3..1d3138f 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h +++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.h @@ -58,6 +58,16 @@ public: virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; + +class PragmaMSStructHandler : public PragmaHandler { + Sema &Actions; +public: + explicit PragmaMSStructHandler(Sema &A) : PragmaHandler("ms_struct"), + Actions(A) {} + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; class PragmaUnusedHandler : public PragmaHandler { Sema &Actions; diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp index 2d97583..f0ab531 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseStmt.cpp @@ -40,6 +40,7 @@ using namespace clang; /// jump-statement /// [C++] declaration-statement /// [C++] try-block +/// [MS] seh-try-block /// [OBC] objc-throw-statement /// [OBC] objc-try-catch-statement /// [OBC] objc-synchronized-statement @@ -81,12 +82,13 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { ParenBraceBracketBalancer BalancerRAIIObj(*this); - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // Cases in this switch statement should fall through if the parser expects // the token to end in a semicolon (in which case SemiError should be set), // or they directly 'return;' if not. +Retry: tok::TokenKind Kind = Tok.getKind(); SourceLocation AtLoc; switch (Kind) { @@ -101,13 +103,103 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { ConsumeCodeCompletionToken(); return ParseStatementOrDeclaration(Stmts, OnlyStatement); - case tok::identifier: - if (NextToken().is(tok::colon)) { // C99 6.8.1: labeled-statement + case tok::identifier: { + Token Next = NextToken(); + if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement // identifier ':' statement return ParseLabeledStatement(attrs); } - // PASS THROUGH. - + + if (Next.isNot(tok::coloncolon)) { + CXXScopeSpec SS; + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation NameLoc = Tok.getLocation(); + Sema::NameClassification Classification + = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next); + switch (Classification.getKind()) { + case Sema::NC_Keyword: + // The identifier was corrected to a keyword. Update the token + // to this keyword, and try again. + if (Name->getTokenID() != tok::identifier) { + Tok.setIdentifierInfo(Name); + Tok.setKind(Name->getTokenID()); + goto Retry; + } + + // Fall through via the normal error path. + // FIXME: This seems like it could only happen for context-sensitive + // keywords. + + case Sema::NC_Error: + // Handle errors here by skipping up to the next semicolon or '}', and + // eat the semicolon if that's what stopped us. + SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return StmtError(); + + case Sema::NC_Unknown: + // Either we don't know anything about this identifier, or we know that + // we're in a syntactic context we haven't handled yet. + break; + + case Sema::NC_Type: + Tok.setKind(tok::annot_typename); + setTypeAnnotation(Tok, Classification.getType()); + Tok.setAnnotationEndLoc(NameLoc); + PP.AnnotateCachedTokens(Tok); + break; + + case Sema::NC_Expression: + Tok.setKind(tok::annot_primary_expr); + setExprAnnotation(Tok, Classification.getExpression()); + Tok.setAnnotationEndLoc(NameLoc); + PP.AnnotateCachedTokens(Tok); + break; + + case Sema::NC_TypeTemplate: + case Sema::NC_FunctionTemplate: { + ConsumeToken(); // the identifier + UnqualifiedId Id; + Id.setIdentifier(Name, NameLoc); + if (AnnotateTemplateIdToken( + TemplateTy::make(Classification.getTemplateName()), + Classification.getTemplateNameKind(), + SS, Id, SourceLocation(), + /*AllowTypeAnnotation=*/false)) { + // Handle errors here by skipping up to the next semicolon or '}', and + // eat the semicolon if that's what stopped us. + SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return StmtError(); + } + + // If the next token is '::', jump right into parsing a + // nested-name-specifier. We don't want to leave the template-id + // hanging. + if (NextToken().is(tok::coloncolon) && TryAnnotateCXXScopeToken(false)){ + // Handle errors here by skipping up to the next semicolon or '}', and + // eat the semicolon if that's what stopped us. + SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return StmtError(); + } + + // We've annotated a template-id, so try again now. + goto Retry; + } + + case Sema::NC_NestedNameSpecifier: + // FIXME: Implement this! + break; + } + } + + // Fall through + } + default: { if ((getLang().CPlusPlus || !OnlyStatement) && isDeclarationStatement()) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; @@ -121,21 +213,7 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { return StmtError(); } - // FIXME: Use the attributes - // expression[opt] ';' - ExprResult Expr(ParseExpression()); - if (Expr.isInvalid()) { - // If the expression is invalid, skip ahead to the next semicolon or '}'. - // Not doing this opens us up to the possibility of infinite loops if - // ParseExpression does not consume any tokens. - SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); - if (Tok.is(tok::semi)) - ConsumeToken(); - return StmtError(); - } - // Otherwise, eat the semicolon. - ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); - return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); + return ParseExprStatement(attrs); } case tok::kw_case: // C99 6.8.1: labeled-statement @@ -146,8 +224,10 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { case tok::l_brace: // C99 6.8.2: compound-statement return ParseCompoundStatement(attrs); case tok::semi: { // C99 6.8.3p3: expression[opt] ';' - bool LeadingEmptyMacro = Tok.hasLeadingEmptyMacro(); - return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacro); + SourceLocation LeadingEmptyMacroLoc; + if (Tok.hasLeadingEmptyMacro()) + LeadingEmptyMacroLoc = PP.getLastEmptyMacroInstantiationLoc(); + return Actions.ActOnNullStmt(ConsumeToken(), LeadingEmptyMacroLoc); } case tok::kw_if: // C99 6.8.4.1: if-statement @@ -193,6 +273,9 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { case tok::kw_try: // C++ 15: try-block return ParseCXXTryBlock(attrs); + + case tok::kw___try: + return ParseSEHTryBlock(attrs); } // If we reached this code, the statement must end in a semicolon. @@ -210,6 +293,145 @@ Parser::ParseStatementOrDeclaration(StmtVector &Stmts, bool OnlyStatement) { return move(Res); } +/// \brief Parse an expression statement. +StmtResult Parser::ParseExprStatement(ParsedAttributes &Attrs) { + // If a case keyword is missing, this is where it should be inserted. + Token OldToken = Tok; + + // FIXME: Use the attributes + // expression[opt] ';' + ExprResult Expr(ParseExpression()); + if (Expr.isInvalid()) { + // If the expression is invalid, skip ahead to the next semicolon or '}'. + // Not doing this opens us up to the possibility of infinite loops if + // ParseExpression does not consume any tokens. + SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); + if (Tok.is(tok::semi)) + ConsumeToken(); + return StmtError(); + } + + if (Tok.is(tok::colon) && getCurScope()->isSwitchScope() && + Actions.CheckCaseExpression(Expr.get())) { + // If a constant expression is followed by a colon inside a switch block, + // suggest a missing case keyword. + Diag(OldToken, diag::err_expected_case_before_expression) + << FixItHint::CreateInsertion(OldToken.getLocation(), "case "); + + // Recover parsing as a case statement. + return ParseCaseStatement(Attrs, /*MissingCase=*/true, Expr); + } + + // Otherwise, eat the semicolon. + ExpectAndConsumeSemi(diag::err_expected_semi_after_expr); + return Actions.ActOnExprStmt(Actions.MakeFullExpr(Expr.get())); +} + +StmtResult Parser::ParseSEHTryBlock(ParsedAttributes & Attrs) { + assert(Tok.is(tok::kw___try) && "Expected '__try'"); + SourceLocation Loc = ConsumeToken(); + return ParseSEHTryBlockCommon(Loc); +} + +/// ParseSEHTryBlockCommon +/// +/// seh-try-block: +/// '__try' compound-statement seh-handler +/// +/// seh-handler: +/// seh-except-block +/// seh-finally-block +/// +StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) { + if(Tok.isNot(tok::l_brace)) + return StmtError(Diag(Tok,diag::err_expected_lbrace)); + + ParsedAttributesWithRange attrs(AttrFactory); + StmtResult TryBlock(ParseCompoundStatement(attrs)); + if(TryBlock.isInvalid()) + return move(TryBlock); + + StmtResult Handler; + if(Tok.is(tok::kw___except)) { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHExceptBlock(Loc); + } else if (Tok.is(tok::kw___finally)) { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHFinallyBlock(Loc); + } else { + return StmtError(Diag(Tok,diag::err_seh_expected_handler)); + } + + if(Handler.isInvalid()) + return move(Handler); + + return Actions.ActOnSEHTryBlock(false /* IsCXXTry */, + TryLoc, + TryBlock.take(), + Handler.take()); +} + +/// ParseSEHExceptBlock - Handle __except +/// +/// seh-except-block: +/// '__except' '(' seh-filter-expression ')' compound-statement +/// +StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { + PoisonIdentifierRAIIObject raii(Ident__exception_code, false), + raii2(Ident___exception_code, false), + raii3(Ident_GetExceptionCode, false); + + if(ExpectAndConsume(tok::l_paren,diag::err_expected_lparen)) + return StmtError(); + + ParseScope ExpectScope(this, Scope::DeclScope | Scope::ControlScope); + + if (getLang().Borland) { + Ident__exception_info->setIsPoisoned(false); + Ident___exception_info->setIsPoisoned(false); + Ident_GetExceptionInfo->setIsPoisoned(false); + } + ExprResult FilterExpr(ParseExpression()); + + if (getLang().Borland) { + Ident__exception_info->setIsPoisoned(true); + Ident___exception_info->setIsPoisoned(true); + Ident_GetExceptionInfo->setIsPoisoned(true); + } + + if(FilterExpr.isInvalid()) + return StmtError(); + + if(ExpectAndConsume(tok::r_paren,diag::err_expected_rparen)) + return StmtError(); + + ParsedAttributesWithRange attrs(AttrFactory); + StmtResult Block(ParseCompoundStatement(attrs)); + + if(Block.isInvalid()) + return move(Block); + + return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.take(), Block.take()); +} + +/// ParseSEHFinallyBlock - Handle __finally +/// +/// seh-finally-block: +/// '__finally' compound-statement +/// +StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) { + PoisonIdentifierRAIIObject raii(Ident__abnormal_termination, false), + raii2(Ident___abnormal_termination, false), + raii3(Ident_AbnormalTermination, false); + + ParsedAttributesWithRange attrs(AttrFactory); + StmtResult Block(ParseCompoundStatement(attrs)); + if(Block.isInvalid()) + return move(Block); + + return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.take()); +} + /// ParseLabeledStatement - We have an identifier and a ':' after it. /// /// labeled-statement: @@ -251,8 +473,9 @@ StmtResult Parser::ParseLabeledStatement(ParsedAttributes &attrs) { /// 'case' constant-expression ':' statement /// [GNU] 'case' constant-expression '...' constant-expression ':' statement /// -StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) { - assert(Tok.is(tok::kw_case) && "Not a case stmt!"); +StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs, bool MissingCase, + ExprResult Expr) { + assert((MissingCase || Tok.is(tok::kw_case)) && "Not a case stmt!"); // FIXME: Use attributes? // It is very very common for code to contain many case statements recursively @@ -280,7 +503,8 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) { // While we have case statements, eat and stack them. do { - SourceLocation CaseLoc = ConsumeToken(); // eat the 'case'. + SourceLocation CaseLoc = MissingCase ? Expr.get()->getExprLoc() : + ConsumeToken(); // eat the 'case'. if (Tok.is(tok::code_completion)) { Actions.CodeCompleteCase(getCurScope()); @@ -292,7 +516,8 @@ StmtResult Parser::ParseCaseStatement(ParsedAttributes &attrs) { /// expression. ColonProtectionRAIIObject ColonProtection(*this); - ExprResult LHS(ParseConstantExpression()); + ExprResult LHS(MissingCase ? Expr : ParseConstantExpression()); + MissingCase = false; if (LHS.isInvalid()) { SkipUntil(tok::colon); return StmtError(); @@ -493,14 +718,14 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { IdentifierInfo *II = Tok.getIdentifierInfo(); SourceLocation IdLoc = ConsumeToken(); - DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, true)); + DeclsInGroup.push_back(Actions.LookupOrCreateLabel(II, IdLoc, LabelLoc)); if (!Tok.is(tok::comma)) break; ConsumeToken(); } - DeclSpec DS; + DeclSpec DS(AttrFactory); DeclGroupPtrTy Res = Actions.FinalizeDeclaratorGroup(getCurScope(), DS, DeclsInGroup.data(), DeclsInGroup.size()); StmtResult R = Actions.ActOnDeclStmt(Res, LabelLoc, Tok.getLocation()); @@ -528,7 +753,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { while (Tok.is(tok::kw___extension__)) ConsumeToken(); - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); // If this is the start of a declaration, parse it as such. @@ -775,7 +1000,7 @@ StmtResult Parser::ParseSwitchStatement(ParsedAttributes &attrs) { // while, for, and switch statements are local to the if, while, for, or // switch statement (including the controlled statement). // - unsigned ScopeFlags = Scope::BreakScope; + unsigned ScopeFlags = Scope::BreakScope | Scope::SwitchScope; if (C99orCXX) ScopeFlags |= Scope::DeclScope | Scope::ControlScope; ParseScope SwitchScope(this, ScopeFlags); @@ -977,6 +1202,7 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { /// 'for' '(' declaration expr[opt] ';' expr[opt] ')' statement /// [C++] 'for' '(' for-init-statement condition[opt] ';' expression[opt] ')' /// [C++] statement +/// [C++0x] 'for' '(' for-range-declaration : for-range-initializer ) statement /// [OBJC2] 'for' '(' declaration 'in' expr ')' statement /// [OBJC2] 'for' '(' expr 'in' expr ')' statement /// @@ -984,6 +1210,11 @@ StmtResult Parser::ParseDoStatement(ParsedAttributes &attrs) { /// [C++] expression-statement /// [C++] simple-declaration /// +/// [C++0x] for-range-declaration: +/// [C++0x] attribute-specifier-seq[opt] type-specifier-seq declarator +/// [C++0x] for-range-initializer: +/// [C++0x] expression +/// [C++0x] braced-init-list [TODO] StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { // FIXME: Use attributes? @@ -1025,11 +1256,12 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { SourceLocation LParenLoc = ConsumeParen(); ExprResult Value; - bool ForEach = false; + bool ForEach = false, ForRange = false; StmtResult FirstPart; bool SecondPartIsInvalid = false; FullExprArg SecondPart(Actions); ExprResult Collection; + ForRangeInit ForRangeInit; FullExprArg ThirdPart(Actions); Decl *SecondVar = 0; @@ -1049,16 +1281,24 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { if (!C99orCXXorObjC) // Use of C99-style for loops in C90 mode? Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); + // In C++0x, "for (T NS:a" might not be a typo for :: + bool MightBeForRangeStmt = getLang().CPlusPlus; + ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; StmtVector Stmts(Actions); DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext, - DeclEnd, attrs, false); + DeclEnd, attrs, false, + MightBeForRangeStmt ? + &ForRangeInit : 0); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); - if (Tok.is(tok::semi)) { // for (int x = 4; + if (ForRangeInit.ParsedForRangeDecl()) { + ForRange = true; + } else if (Tok.is(tok::semi)) { // for (int x = 4; ConsumeToken(); } else if ((ForEach = isTokIdentifier_in())) { Actions.ActOnForEachDeclStmt(DG); @@ -1107,7 +1347,7 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { } } } - if (!ForEach) { + if (!ForEach && !ForRange) { assert(!SecondPart.get() && "Shouldn't have a second expression yet."); // Parse the second part of the for specifier. if (Tok.is(tok::semi)) { // for (...;; @@ -1149,6 +1389,17 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { // Match the ')'. SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); + // We need to perform most of the semantic analysis for a C++0x for-range + // statememt before parsing the body, in order to be able to deduce the type + // of an auto-typed loop variable. + StmtResult ForRangeStmt; + if (ForRange) + ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, LParenLoc, + FirstPart.take(), + ForRangeInit.ColonLoc, + ForRangeInit.RangeExpr.get(), + RParenLoc); + // C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if // there is no compound stmt. C90 does not have this clause. We only do this // if the body isn't a compound statement to avoid push/pop in common cases. @@ -1175,15 +1426,19 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { if (Body.isInvalid()) return StmtError(); - if (!ForEach) - return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart, - SecondVar, ThirdPart, RParenLoc, Body.take()); + if (ForEach) + // FIXME: It isn't clear how to communicate the late destruction of + // C++ temporaries used to create the collection. + return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, + FirstPart.take(), + Collection.take(), RParenLoc, + Body.take()); + + if (ForRange) + return Actions.FinishCXXForRangeStmt(ForRangeStmt.take(), Body.take()); - // FIXME: It isn't clear how to communicate the late destruction of - // C++ temporaries used to create the collection. - return Actions.ActOnObjCForCollectionStmt(ForLoc, LParenLoc, FirstPart.take(), - Collection.take(), RParenLoc, - Body.take()); + return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart.take(), SecondPart, + SecondVar, ThirdPart, RParenLoc, Body.take()); } /// ParseGotoStatement @@ -1267,7 +1522,16 @@ StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) { return StmtError(); } - R = ParseExpression(); + // FIXME: This is a hack to allow something like C++0x's generalized + // initializer lists, but only enough of this feature to allow Clang to + // parse libstdc++ 4.5's headers. + if (Tok.is(tok::l_brace) && getLang().CPlusPlus) { + R = ParseInitializer(); + if (R.isUsable() && !getLang().CPlusPlus0x) + Diag(R.get()->getLocStart(), diag::ext_generalized_initializer_lists) + << R.get()->getSourceRange(); + } else + R = ParseExpression(); if (R.isInvalid()) { // Skip to the semicolon, but don't consume it. SkipUntil(tok::semi, false, true); return StmtError(); @@ -1350,7 +1614,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { msAsm = true; return FuzzyParseMicrosoftAsmStatement(AsmLoc); } - DeclSpec DS; + DeclSpec DS(AttrFactory); SourceLocation Loc = Tok.getLocation(); ParseTypeQualifierListOpt(DS, true, false); @@ -1522,14 +1786,17 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<IdentifierInfo *> &Names, return true; } -Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { +Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { assert(Tok.is(tok::l_brace)); SourceLocation LBraceLoc = Tok.getLocation(); - if (PP.isCodeCompletionEnabled()) - if (trySkippingFunctionBodyForCodeCompletion()) + if (PP.isCodeCompletionEnabled()) { + if (trySkippingFunctionBodyForCodeCompletion()) { + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, 0); - + } + } + PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc, "parsing function body"); @@ -1543,6 +1810,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, MultiStmtArg(Actions), false); + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); } @@ -1551,7 +1819,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl) { /// function-try-block: /// 'try' ctor-initializer[opt] compound-statement handler-seq /// -Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { +Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { assert(Tok.is(tok::kw_try) && "Expected 'try'"); SourceLocation TryLoc = ConsumeToken(); @@ -1562,9 +1830,12 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { if (Tok.is(tok::colon)) ParseConstructorInitializer(Decl); - if (PP.isCodeCompletionEnabled()) - if (trySkippingFunctionBodyForCodeCompletion()) + if (PP.isCodeCompletionEnabled()) { + if (trySkippingFunctionBodyForCodeCompletion()) { + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, 0); + } + } SourceLocation LBraceLoc = Tok.getLocation(); StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc)); @@ -1574,6 +1845,7 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl) { FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, MultiStmtArg(Actions), false); + BodyScope.Exit(); return Actions.ActOnFinishFunctionBody(Decl, FnBody.take()); } @@ -1622,32 +1894,58 @@ StmtResult Parser::ParseCXXTryBlock(ParsedAttributes &attrs) { /// handler-seq: /// handler handler-seq[opt] /// +/// [Borland] try-block: +/// 'try' compound-statement seh-except-block +/// 'try' compound-statment seh-finally-block +/// StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); StmtResult TryBlock(ParseCompoundStatement(attrs)); if (TryBlock.isInvalid()) return move(TryBlock); - StmtVector Handlers(Actions); - MaybeParseCXX0XAttributes(attrs); - ProhibitAttributes(attrs); - - if (Tok.isNot(tok::kw_catch)) - return StmtError(Diag(Tok, diag::err_expected_catch)); - while (Tok.is(tok::kw_catch)) { - StmtResult Handler(ParseCXXCatchBlock()); - if (!Handler.isInvalid()) - Handlers.push_back(Handler.release()); + // Borland allows SEH-handlers with 'try' + if(Tok.is(tok::kw___except) || Tok.is(tok::kw___finally)) { + // TODO: Factor into common return ParseSEHHandlerCommon(...) + StmtResult Handler; + if(Tok.is(tok::kw___except)) { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHExceptBlock(Loc); + } + else { + SourceLocation Loc = ConsumeToken(); + Handler = ParseSEHFinallyBlock(Loc); + } + if(Handler.isInvalid()) + return move(Handler); + + return Actions.ActOnSEHTryBlock(true /* IsCXXTry */, + TryLoc, + TryBlock.take(), + Handler.take()); } - // Don't bother creating the full statement if we don't have any usable - // handlers. - if (Handlers.empty()) - return StmtError(); + else { + StmtVector Handlers(Actions); + MaybeParseCXX0XAttributes(attrs); + ProhibitAttributes(attrs); + + if (Tok.isNot(tok::kw_catch)) + return StmtError(Diag(Tok, diag::err_expected_catch)); + while (Tok.is(tok::kw_catch)) { + StmtResult Handler(ParseCXXCatchBlock()); + if (!Handler.isInvalid()) + Handlers.push_back(Handler.release()); + } + // Don't bother creating the full statement if we don't have any usable + // handlers. + if (Handlers.empty()) + return StmtError(); - return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers)); + return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(), move_arg(Handlers)); + } } /// ParseCXXCatchBlock - Parse a C++ catch block, called handler in the standard @@ -1679,7 +1977,7 @@ StmtResult Parser::ParseCXXCatchBlock() { // without default arguments. Decl *ExceptionDecl = 0; if (Tok.isNot(tok::ellipsis)) { - DeclSpec DS; + DeclSpec DS(AttrFactory); if (ParseCXXTypeSpecifierSeq(DS)) return StmtError(); Declarator ExDecl(DS, Declarator::CXXCatchContext); @@ -1695,7 +1993,7 @@ StmtResult Parser::ParseCXXCatchBlock() { return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); StmtResult Block(ParseCompoundStatement(attrs)); if (Block.isInvalid()) return move(Block); diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp index 59ced8b..12e38da 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTemplate.cpp @@ -17,6 +17,8 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "RAIIObjectsForParser.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ASTConsumer.h" using namespace clang; /// \brief Parse a template declaration, explicit instantiation, or @@ -196,7 +198,7 @@ Parser::ParseSingleDeclarationAfterTemplate( return 0; } - ParsedAttributesWithRange prefixAttrs; + ParsedAttributesWithRange prefixAttrs(AttrFactory); MaybeParseCXX0XAttributes(prefixAttrs); if (Tok.is(tok::kw_using)) @@ -205,7 +207,7 @@ Parser::ParseSingleDeclarationAfterTemplate( // Parse the declaration specifiers, stealing the accumulated // diagnostics from the template parameters. - ParsingDeclSpec DS(DiagsFromTParams); + ParsingDeclSpec DS(*this, &DiagsFromTParams); DS.takeAttributesFrom(prefixAttrs); @@ -598,7 +600,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { // Parse the declaration-specifiers (i.e., the type). // FIXME: The type should probably be restricted in some way... Not all // declarators (parts of declarators?) are accepted for parameters. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); // Parse this as a typename. @@ -661,7 +663,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { bool Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, SourceLocation TemplateNameLoc, - const CXXScopeSpec *SS, + const CXXScopeSpec &SS, bool ConsumeLastToken, SourceLocation &LAngleLoc, TemplateArgList &TemplateArgs, @@ -756,7 +758,7 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, /// formed, this function returns true. /// bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, - const CXXScopeSpec *SS, + CXXScopeSpec &SS, UnqualifiedId &TemplateName, SourceLocation TemplateKWLoc, bool AllowTypeAnnotation) { @@ -790,7 +792,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Build the annotation token. if (TNK == TNK_Type_template && AllowTypeAnnotation) { TypeResult Type - = Actions.ActOnTemplateIdType(Template, TemplateNameLoc, + = Actions.ActOnTemplateIdType(SS, + Template, TemplateNameLoc, LAngleLoc, TemplateArgsPtr, RAngleLoc); if (Type.isInvalid()) { @@ -803,8 +806,8 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, Tok.setKind(tok::annot_typename); setTypeAnnotation(Tok, Type.get()); - if (SS && SS->isNotEmpty()) - Tok.setLocation(SS->getBeginLoc()); + if (SS.isNotEmpty()) + Tok.setLocation(SS.getBeginLoc()); else if (TemplateKWLoc.isValid()) Tok.setLocation(TemplateKWLoc); else @@ -823,6 +826,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateId->Name = 0; TemplateId->Operator = TemplateName.OperatorFunctionId.Operator; } + TemplateId->SS = SS; TemplateId->Template = Template; TemplateId->Kind = TNK; TemplateId->LAngleLoc = LAngleLoc; @@ -854,7 +858,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, /// If there was a failure when forming the type from the template-id, /// a type annotation token will still be created, but will have a /// NULL type pointer to signify an error. -void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { +void Parser::AnnotateTemplateIdTokenAsType() { assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens"); TemplateIdAnnotation *TemplateId @@ -868,7 +872,8 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { TemplateId->NumArgs); TypeResult Type - = Actions.ActOnTemplateIdType(TemplateId->Template, + = Actions.ActOnTemplateIdType(TemplateId->SS, + TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, @@ -876,8 +881,8 @@ void Parser::AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS) { // Create the new "type" annotation token. Tok.setKind(tok::annot_typename); setTypeAnnotation(Tok, Type.isInvalid() ? ParsedType() : Type.get()); - if (SS && SS->isNotEmpty()) // it was a C++ qualified type name. - Tok.setLocation(SS->getBeginLoc()); + if (TemplateId->SS.isNotEmpty()) // it was a C++ qualified type name. + Tok.setLocation(TemplateId->SS.getBeginLoc()); // End location stays the same // Replace the template-id annotation token, and possible the scope-specifier @@ -1122,3 +1127,125 @@ SourceRange Parser::ParsedTemplateInfo::getSourceRange() const { R.setBegin(ExternLoc); return R; } + +void Parser::LateTemplateParserCallback(void *P, const FunctionDecl *FD) { + ((Parser*)P)->LateTemplateParser(FD); +} + + +void Parser::LateTemplateParser(const FunctionDecl *FD) { + LateParsedTemplatedFunction *LPT = LateParsedTemplateMap[FD]; + if (LPT) { + ParseLateTemplatedFuncDef(*LPT); + return; + } + + llvm_unreachable("Late templated function without associated lexed tokens"); +} + +/// \brief Late parse a C++ function template in Microsoft mode. +void Parser::ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT) { + if(!LMT.D) + return; + + // If this is a member template, introduce the template parameter scope. + ParseScope TemplateScope(this, Scope::TemplateParamScope); + + // Get the FunctionDecl. + FunctionDecl *FD = 0; + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(LMT.D)) + FD = FunTmpl->getTemplatedDecl(); + else + FD = cast<FunctionDecl>(LMT.D); + + // Reinject the template parameters. + DeclaratorDecl* Declarator = dyn_cast<DeclaratorDecl>(FD); + if (Declarator && Declarator->getNumTemplateParameterLists() != 0) { + Actions.ActOnReenterDeclaratorTemplateScope(getCurScope(), Declarator); + Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + } else { + Actions.ActOnReenterTemplateScope(getCurScope(), LMT.D); + + DeclContext *DD = FD->getLexicalParent(); + while (DD && DD->isRecord()) { + if (ClassTemplatePartialSpecializationDecl* MD = + dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(DD)) + Actions.ActOnReenterTemplateScope(getCurScope(), MD); + else if (CXXRecordDecl* MD = dyn_cast_or_null<CXXRecordDecl>(DD)) + Actions.ActOnReenterTemplateScope(getCurScope(), + MD->getDescribedClassTemplate()); + + DD = DD->getLexicalParent(); + } + } + assert(!LMT.Toks.empty() && "Empty body!"); + + // Append the current token at the end of the new token stream so that it + // doesn't get lost. + LMT.Toks.push_back(Tok); + PP.EnterTokenStream(LMT.Toks.data(), LMT.Toks.size(), true, false); + + // Consume the previously pushed token. + ConsumeAnyToken(); + assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) + && "Inline method not starting with '{', ':' or 'try'"); + + // Parse the method body. Function body parsing code is similar enough + // to be re-used for method bodies as well. + ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); + + // Recreate the DeclContext. + Sema::ContextRAII SavedContext(Actions, Actions.getContainingDC(FD)); + + if (FunctionTemplateDecl *FunctionTemplate + = dyn_cast_or_null<FunctionTemplateDecl>(LMT.D)) + Actions.ActOnStartOfFunctionDef(getCurScope(), + FunctionTemplate->getTemplatedDecl()); + if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(LMT.D)) + Actions.ActOnStartOfFunctionDef(getCurScope(), Function); + + + if (Tok.is(tok::kw_try)) { + ParseFunctionTryBlock(LMT.D, FnScope); + return; + } + if (Tok.is(tok::colon)) { + ParseConstructorInitializer(LMT.D); + + // Error recovery. + if (!Tok.is(tok::l_brace)) { + Actions.ActOnFinishFunctionBody(LMT.D, 0); + return; + } + } else + Actions.ActOnDefaultCtorInitializers(LMT.D); + + ParseFunctionStatementBody(LMT.D, FnScope); + Actions.MarkAsLateParsedTemplate(FD, false); + + DeclGroupPtrTy grp = Actions.ConvertDeclToDeclGroup(LMT.D); + if (grp) + Actions.getASTConsumer().HandleTopLevelDecl(grp.get()); +} + +/// \brief Lex a delayed template function for late parsing. +void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) { + tok::TokenKind kind = Tok.getKind(); + // We may have a constructor initializer or function-try-block here. + if (kind == tok::colon || kind == tok::kw_try) + ConsumeAndStoreUntil(tok::l_brace, Toks); + else { + Toks.push_back(Tok); + ConsumeBrace(); + } + // Consume everything up to (and including) the matching right brace. + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); + + // If we're in a function-try-block, we need to store all the catch blocks. + if (kind == tok::kw_try) { + while (Tok.is(tok::kw_catch)) { + ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false); + ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); + } + } +} diff --git a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp index a603c37..1c4e2b3 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParseTentative.cpp @@ -58,6 +58,7 @@ bool Parser::isCXXDeclarationStatement() { case tok::kw_using: // static_assert-declaration case tok::kw_static_assert: + case tok::kw__Static_assert: return true; // simple-declaration default: @@ -658,10 +659,12 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___is_convertible_to: case tok::kw___is_empty: case tok::kw___is_enum: + case tok::kw___is_literal: + case tok::kw___is_literal_type: case tok::kw___is_pod: case tok::kw___is_polymorphic: + case tok::kw___is_trivial: case tok::kw___is_union: - case tok::kw___is_literal: case tok::kw___uuidof: return TPResult::True(); @@ -673,6 +676,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw_float: case tok::kw_int: case tok::kw_long: + case tok::kw___int64: case tok::kw_restrict: case tok::kw_short: case tok::kw_signed: @@ -907,7 +911,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { if (TemplateId->Kind != TNK_Type_template) return TPResult::False(); CXXScopeSpec SS; - AnnotateTemplateIdTokenAsType(&SS); + AnnotateTemplateIdTokenAsType(); assert(Tok.is(tok::annot_typename)); goto case_typename; } @@ -968,6 +972,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { case tok::kw_short: case tok::kw_int: case tok::kw_long: + case tok::kw___int64: case tok::kw_signed: case tok::kw_unsigned: case tok::kw_float: @@ -1151,7 +1156,7 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() { return TPResult::True(); // '...' is a sign of a function declarator. } - ParsedAttributes attrs; + ParsedAttributes attrs(AttrFactory); MaybeParseMicrosoftAttributes(attrs); // decl-specifier-seq @@ -1238,6 +1243,16 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { if (!SkipUntil(tok::r_paren)) return TPResult::Error(); } + if (Tok.is(tok::kw_noexcept)) { + ConsumeToken(); + // Possibly an expression as well. + if (Tok.is(tok::l_paren)) { + // Find the matching rparen. + ConsumeParen(); + if (!SkipUntil(tok::r_paren)) + return TPResult::Error(); + } + } return TPResult::Ambiguous(); } diff --git a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp index 07e592c..4d08699 100644 --- a/contrib/llvm/tools/clang/lib/Parse/Parser.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/Parser.cpp @@ -19,10 +19,11 @@ #include "llvm/Support/raw_ostream.h" #include "RAIIObjectsForParser.h" #include "ParsePragma.h" +#include "clang/AST/DeclTemplate.h" using namespace clang; Parser::Parser(Preprocessor &pp, Sema &actions) - : CrashInfo(*this), PP(pp), Actions(actions), Diags(PP.getDiagnostics()), + : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), ColonIsSacred(false), InMessageExpression(false), TemplateParameterDepth(0) { Tok.setKind(tok::eof); @@ -44,6 +45,9 @@ Parser::Parser(Preprocessor &pp, Sema &actions) PackHandler.reset(new PragmaPackHandler(actions)); PP.AddPragmaHandler(PackHandler.get()); + + MSStructHandler.reset(new PragmaMSStructHandler(actions)); + PP.AddPragmaHandler(MSStructHandler.get()); UnusedHandler.reset(new PragmaUnusedHandler(actions, *this)); PP.AddPragmaHandler(UnusedHandler.get()); @@ -362,6 +366,11 @@ Parser::~Parser() { for (unsigned i = 0, e = NumCachedScopes; i != e; ++i) delete ScopeCache[i]; + // Free LateParsedTemplatedFunction nodes. + for (LateParsedTemplateMapT::iterator it = LateParsedTemplateMap.begin(); + it != LateParsedTemplateMap.end(); ++it) + delete it->second; + // Remove the pragma handlers we installed. PP.RemovePragmaHandler(AlignHandler.get()); AlignHandler.reset(); @@ -371,6 +380,8 @@ Parser::~Parser() { OptionsHandler.reset(); PP.RemovePragmaHandler(PackHandler.get()); PackHandler.reset(); + PP.RemovePragmaHandler(MSStructHandler.get()); + MSStructHandler.reset(); PP.RemovePragmaHandler(UnusedHandler.get()); UnusedHandler.reset(); PP.RemovePragmaHandler(WeakHandler.get()); @@ -422,6 +433,37 @@ void Parser::Initialize() { Ident_vector = &PP.getIdentifierTable().get("vector"); Ident_pixel = &PP.getIdentifierTable().get("pixel"); } + + Ident_introduced = 0; + Ident_deprecated = 0; + Ident_obsoleted = 0; + Ident_unavailable = 0; + + Ident__exception_code = Ident__exception_info = Ident__abnormal_termination = 0; + Ident___exception_code = Ident___exception_info = Ident___abnormal_termination = 0; + Ident_GetExceptionCode = Ident_GetExceptionInfo = Ident_AbnormalTermination = 0; + + if(getLang().Borland) { + Ident__exception_info = PP.getIdentifierInfo("_exception_info"); + Ident___exception_info = PP.getIdentifierInfo("__exception_info"); + Ident_GetExceptionInfo = PP.getIdentifierInfo("GetExceptionInformation"); + Ident__exception_code = PP.getIdentifierInfo("_exception_code"); + Ident___exception_code = PP.getIdentifierInfo("__exception_code"); + Ident_GetExceptionCode = PP.getIdentifierInfo("GetExceptionCode"); + Ident__abnormal_termination = PP.getIdentifierInfo("_abnormal_termination"); + Ident___abnormal_termination = PP.getIdentifierInfo("__abnormal_termination"); + Ident_AbnormalTermination = PP.getIdentifierInfo("AbnormalTermination"); + + PP.SetPoisonReason(Ident__exception_code,diag::err_seh___except_block); + PP.SetPoisonReason(Ident___exception_code,diag::err_seh___except_block); + PP.SetPoisonReason(Ident_GetExceptionCode,diag::err_seh___except_block); + PP.SetPoisonReason(Ident__exception_info,diag::err_seh___except_filter); + PP.SetPoisonReason(Ident___exception_info,diag::err_seh___except_filter); + PP.SetPoisonReason(Ident_GetExceptionInfo,diag::err_seh___except_filter); + PP.SetPoisonReason(Ident__abnormal_termination,diag::err_seh___finally_block); + PP.SetPoisonReason(Ident___abnormal_termination,diag::err_seh___finally_block); + PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block); + } } /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the @@ -433,11 +475,15 @@ bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { Result = DeclGroupPtrTy(); if (Tok.is(tok::eof)) { + // Late template parsing can begin. + if (getLang().DelayedTemplateParsing) + Actions.SetLateTemplateParser(LateTemplateParserCallback, this); + Actions.ActOnEndOfTranslationUnit(); return true; } - ParsedAttributesWithRange attrs; + ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); MaybeParseMicrosoftAttributes(attrs); @@ -513,14 +559,16 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw_asm: { ProhibitAttributes(attrs); - ExprResult Result(ParseSimpleAsm()); + SourceLocation StartLoc = Tok.getLocation(); + SourceLocation EndLoc; + ExprResult Result(ParseSimpleAsm(&EndLoc)); ExpectAndConsume(tok::semi, diag::err_expected_semi_after, "top-level asm block"); if (Result.isInvalid()) return DeclGroupPtrTy(); - SingleDecl = Actions.ActOnFileScopeAsmDecl(Tok.getLocation(), Result.get()); + SingleDecl = Actions.ActOnFileScopeAsmDecl(Result.get(), StartLoc, EndLoc); break; } case tok::at: @@ -550,6 +598,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::kw_template: case tok::kw_export: // As in 'export template' case tok::kw_static_assert: + case tok::kw__Static_assert: // A function definition cannot start with a these keywords. { SourceLocation DeclEnd; @@ -743,6 +792,8 @@ Parser::ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, /// Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, const ParsedTemplateInfo &TemplateInfo) { + // Poison the SEH identifiers so they are flagged as illegal in function bodies + PoisonSEHIdentifiersRAIIObject PoisonSEHIdentifiers(*this, true); const DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); // If this is C90 and the declspecs were completely missing, fudge in an @@ -778,6 +829,44 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, return 0; } + // In delayed template parsing mode, for function template we consume the + // tokens and store them for late parsing at the end of the translation unit. + if (getLang().DelayedTemplateParsing && + TemplateInfo.Kind == ParsedTemplateInfo::Template) { + MultiTemplateParamsArg TemplateParameterLists(Actions, + TemplateInfo.TemplateParams->data(), + TemplateInfo.TemplateParams->size()); + + ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); + Scope *ParentScope = getCurScope()->getParent(); + + Decl *DP = Actions.HandleDeclarator(ParentScope, D, + move(TemplateParameterLists), + /*IsFunctionDefinition=*/true); + D.complete(DP); + D.getMutableDeclSpec().abort(); + + if (DP) { + LateParsedTemplatedFunction *LPT = new LateParsedTemplatedFunction(this, DP); + + FunctionDecl *FnD = 0; + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(DP)) + FnD = FunTmpl->getTemplatedDecl(); + else + FnD = cast<FunctionDecl>(DP); + Actions.CheckForFunctionRedefinition(FnD); + + LateParsedTemplateMap[FnD] = LPT; + Actions.MarkAsLateParsedTemplate(FnD); + LexTemplateFunctionForLateParsing(LPT->Toks); + } else { + CachedTokens Toks; + LexTemplateFunctionForLateParsing(Toks); + } + return DP; + } + + // Enter a scope for the function body. ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); @@ -799,7 +888,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, D.getMutableDeclSpec().abort(); if (Tok.is(tok::kw_try)) - return ParseFunctionTryBlock(Res); + return ParseFunctionTryBlock(Res, BodyScope); // If we have a colon, then we're probably parsing a C++ // ctor-initializer. @@ -808,13 +897,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // Recover from error. if (!Tok.is(tok::l_brace)) { + BodyScope.Exit(); Actions.ActOnFinishFunctionBody(Res, 0); return Res; } } else Actions.ActOnDefaultCtorInitializers(Res); - return ParseFunctionStatementBody(Res); + return ParseFunctionStatementBody(Res, BodyScope); } /// ParseKNRParamDeclarations - Parse 'declaration-list[opt]' which provides @@ -832,7 +922,7 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { SourceLocation DSStart = Tok.getLocation(); // Parse the common declaration-specifiers piece. - DeclSpec DS; + DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); // C99 6.9.1p6: 'each declaration in the declaration list shall have at @@ -1029,10 +1119,14 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { // simple-template-id SourceLocation TypenameLoc = ConsumeToken(); CXXScopeSpec SS; - if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), false)) + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/ParsedType(), false, + 0, /*IsTypename*/true)) return true; if (!SS.isSet()) { - Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); + if (getLang().Microsoft) + Diag(Tok.getLocation(), diag::warn_expected_qualified_after_typename); + else + Diag(Tok.getLocation(), diag::err_expected_qualified_after_typename); return true; } @@ -1051,15 +1145,18 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { return true; } - AnnotateTemplateIdTokenAsType(0); - assert(Tok.is(tok::annot_typename) && - "AnnotateTemplateIdTokenAsType isn't working properly"); - if (Tok.getAnnotationValue()) - Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, - SourceLocation(), - getTypeAnnotation(Tok)); - else - Ty = true; + ASTTemplateArgsPtr TemplateArgsPtr(Actions, + TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + + Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, + /*FIXME:*/SourceLocation(), + TemplateId->Template, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, + TemplateArgsPtr, + TemplateId->RAngleLoc); + TemplateId->Destroy(); } else { Diag(Tok, diag::err_expected_type_name_after_typename) << SS.getRange(); @@ -1088,7 +1185,9 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { if (ParsedType Ty = Actions.getTypeName(*Tok.getIdentifierInfo(), Tok.getLocation(), getCurScope(), &SS, false, - NextToken().is(tok::period))) { + NextToken().is(tok::period), + ParsedType(), + /*NonTrivialTypeSourceInfo*/true)) { // This is a typename. Replace the current token in-place with an // annotation type token. Tok.setKind(tok::annot_typename); @@ -1124,7 +1223,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { Template, MemberOfUnknownSpecialization)) { // Consume the identifier. ConsumeToken(); - if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) { + if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName)) { // If an unrecoverable error occurred, we need to return true here, // because the token stream is in a damaged state. We may not return // a valid identifier. @@ -1147,7 +1246,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { // template-id annotation in a context where we weren't allowed // to produce a type annotation token. Update the template-id // annotation token to a type annotation token now. - AnnotateTemplateIdTokenAsType(&SS); + AnnotateTemplateIdTokenAsType(); return false; } } @@ -1184,7 +1283,8 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { assert(getLang().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); - assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) && + assert((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + (Tok.is(tok::annot_template_id) && NextToken().is(tok::coloncolon)))&& "Cannot be a type or scope token!"); CXXScopeSpec SS; diff --git a/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h b/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h index 583f184..3765f92 100644 --- a/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h +++ b/contrib/llvm/tools/clang/lib/Parse/RAIIObjectsForParser.h @@ -112,7 +112,31 @@ namespace clang { P.BraceCount = BraceCount; } }; - + + class PoisonSEHIdentifiersRAIIObject { + PoisonIdentifierRAIIObject Ident_AbnormalTermination; + PoisonIdentifierRAIIObject Ident_GetExceptionCode; + PoisonIdentifierRAIIObject Ident_GetExceptionInfo; + PoisonIdentifierRAIIObject Ident__abnormal_termination; + PoisonIdentifierRAIIObject Ident__exception_code; + PoisonIdentifierRAIIObject Ident__exception_info; + PoisonIdentifierRAIIObject Ident___abnormal_termination; + PoisonIdentifierRAIIObject Ident___exception_code; + PoisonIdentifierRAIIObject Ident___exception_info; + public: + PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue) + : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue), + Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue), + Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue), + Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue), + Ident__exception_code(Self.Ident__exception_code, NewValue), + Ident__exception_info(Self.Ident__exception_info, NewValue), + Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue), + Ident___exception_code(Self.Ident___exception_code, NewValue), + Ident___exception_info(Self.Ident___exception_info, NewValue) { + } + }; + } // end namespace clang #endif diff --git a/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp b/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp index 0263f65..d6e34ef 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/RewriteObjC.cpp @@ -1426,7 +1426,8 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, RecName += "_IMPL"; IdentifierInfo *II = &Context->Idents.get(RecName); RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), II); + SourceLocation(), SourceLocation(), + II); assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, @@ -1472,7 +1473,8 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV, RecName += "_IMPL"; IdentifierInfo *II = &Context->Idents.get(RecName); RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), II); + SourceLocation(), SourceLocation(), + II); assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT, @@ -2109,7 +2111,8 @@ Stmt *RewriteObjC::RewriteAtEncode(ObjCEncodeExpr *Exp) { std::string StrEncoding; Context->getObjCEncodingForType(Exp->getEncodedType(), StrEncoding); Expr *Replacement = StringLiteral::Create(*Context,StrEncoding.c_str(), - StrEncoding.length(), false,StrType, + StrEncoding.length(), + false, false, StrType, SourceLocation()); ReplaceStmt(Exp, Replacement); @@ -2128,7 +2131,8 @@ Stmt *RewriteObjC::RewriteAtSelector(ObjCSelectorExpr *Exp) { SelExprs.push_back(StringLiteral::Create(*Context, Exp->getSelector().getAsString().c_str(), Exp->getSelector().getAsString().size(), - false, argType, SourceLocation())); + false, false, argType, + SourceLocation())); CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, &SelExprs[0], SelExprs.size()); ReplaceStmt(Exp, SelExp); @@ -2361,6 +2365,7 @@ void RewriteObjC::SynthSelGetUidFunctionDecl() { getSimpleFunctionType(Context->getObjCSelType(), &ArgTys[0], ArgTys.size()); SelGetUidFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), SelGetUidIdent, getFuncType, 0, SC_Extern, SC_None, false); @@ -2457,6 +2462,7 @@ void RewriteObjC::SynthSuperContructorFunctionDecl() { &ArgTys[0], ArgTys.size()); SuperContructorFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), msgSendIdent, msgSendType, 0, SC_Extern, SC_None, false); @@ -2477,6 +2483,7 @@ void RewriteObjC::SynthMsgSendFunctionDecl() { true /*isVariadic*/); MsgSendFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), msgSendIdent, msgSendType, 0, SC_Extern, SC_None, false); @@ -2487,7 +2494,7 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() { IdentifierInfo *msgSendIdent = &Context->Idents.get("objc_msgSendSuper"); llvm::SmallVector<QualType, 16> ArgTys; RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), + SourceLocation(), SourceLocation(), &Context->Idents.get("objc_super")); QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); @@ -2500,6 +2507,7 @@ void RewriteObjC::SynthMsgSendSuperFunctionDecl() { true /*isVariadic*/); MsgSendSuperFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), msgSendIdent, msgSendType, 0, SC_Extern, SC_None, false); @@ -2520,6 +2528,7 @@ void RewriteObjC::SynthMsgSendStretFunctionDecl() { true /*isVariadic*/); MsgSendStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), msgSendIdent, msgSendType, 0, SC_Extern, SC_None, false); @@ -2532,7 +2541,7 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { &Context->Idents.get("objc_msgSendSuper_stret"); llvm::SmallVector<QualType, 16> ArgTys; RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), + SourceLocation(), SourceLocation(), &Context->Idents.get("objc_super")); QualType argT = Context->getPointerType(Context->getTagDeclType(RD)); assert(!argT.isNull() && "Can't build 'struct objc_super *' type"); @@ -2545,6 +2554,7 @@ void RewriteObjC::SynthMsgSendSuperStretFunctionDecl() { true /*isVariadic*/); MsgSendSuperStretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), msgSendIdent, msgSendType, 0, SC_Extern, SC_None, false); @@ -2565,6 +2575,7 @@ void RewriteObjC::SynthMsgSendFpretFunctionDecl() { true /*isVariadic*/); MsgSendFpretFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), msgSendIdent, msgSendType, 0, SC_Extern, SC_None, false); @@ -2579,6 +2590,7 @@ void RewriteObjC::SynthGetClassFunctionDecl() { &ArgTys[0], ArgTys.size()); GetClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), getClassIdent, getClassType, 0, SC_Extern, SC_None, false); @@ -2594,6 +2606,7 @@ void RewriteObjC::SynthGetSuperClassFunctionDecl() { &ArgTys[0], ArgTys.size()); GetSuperClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), getSuperClassIdent, getClassType, 0, SC_Extern, @@ -2610,6 +2623,7 @@ void RewriteObjC::SynthGetMetaClassFunctionDecl() { &ArgTys[0], ArgTys.size()); GetMetaClassFunctionDecl = FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), getClassIdent, getClassType, 0, SC_Extern, SC_None, false); @@ -2645,8 +2659,8 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { Preamble += utostr(Exp->getString()->getByteLength()) + "};\n"; VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - &Context->Idents.get(S), strType, 0, - SC_Static, SC_None); + SourceLocation(), &Context->Idents.get(S), + strType, 0, SC_Static, SC_None); DeclRefExpr *DRE = new (Context) DeclRefExpr(NewVD, strType, VK_LValue, SourceLocation()); Expr *Unop = new (Context) UnaryOperator(DRE, UO_AddrOf, @@ -2665,7 +2679,7 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) { QualType RewriteObjC::getSuperStructType() { if (!SuperStructDecl) { SuperStructDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), + SourceLocation(), SourceLocation(), &Context->Idents.get("objc_super")); QualType FieldTypes[2]; @@ -2677,6 +2691,7 @@ QualType RewriteObjC::getSuperStructType() { // Create fields for (unsigned i = 0; i < 2; ++i) { SuperStructDecl->addDecl(FieldDecl::Create(*Context, SuperStructDecl, + SourceLocation(), SourceLocation(), 0, FieldTypes[i], 0, /*BitWidth=*/0, @@ -2691,7 +2706,7 @@ QualType RewriteObjC::getSuperStructType() { QualType RewriteObjC::getConstantStringStructType() { if (!ConstantStringDecl) { ConstantStringDecl = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), + SourceLocation(), SourceLocation(), &Context->Idents.get("__NSConstantStringImpl")); QualType FieldTypes[4]; @@ -2708,6 +2723,7 @@ QualType RewriteObjC::getConstantStringStructType() { for (unsigned i = 0; i < 4; ++i) { ConstantStringDecl->addDecl(FieldDecl::Create(*Context, ConstantStringDecl, + SourceLocation(), SourceLocation(), 0, FieldTypes[i], 0, /*BitWidth=*/0, @@ -2782,7 +2798,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, ClsExprs.push_back(StringLiteral::Create(*Context, ClassDecl->getIdentifier()->getNameStart(), ClassDecl->getIdentifier()->getLength(), - false, argType, SourceLocation())); + false, false, argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetMetaClassFunctionDecl, &ClsExprs[0], ClsExprs.size(), @@ -2861,8 +2877,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, ClsExprs.push_back(StringLiteral::Create(*Context, clsName->getNameStart(), clsName->getLength(), - false, argType, - SourceLocation())); + false, false, + argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, &ClsExprs[0], ClsExprs.size(), @@ -2893,7 +2909,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, ClsExprs.push_back(StringLiteral::Create(*Context, ClassDecl->getIdentifier()->getNameStart(), ClassDecl->getIdentifier()->getLength(), - false, argType, SourceLocation())); + false, false, argType, SourceLocation())); CallExpr *Cls = SynthesizeCallToFunctionDecl(GetClassFunctionDecl, &ClsExprs[0], ClsExprs.size(), @@ -2975,7 +2991,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, SelExprs.push_back(StringLiteral::Create(*Context, Exp->getSelector().getAsString().c_str(), Exp->getSelector().getAsString().size(), - false, argType, SourceLocation())); + false, false, argType, SourceLocation())); CallExpr *SelExp = SynthesizeCallToFunctionDecl(SelGetUidFunctionDecl, &SelExprs[0], SelExprs.size(), StartLoc, @@ -3102,10 +3118,11 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, SourceLocation()); // Build sizeof(returnType) - SizeOfAlignOfExpr *sizeofExpr = new (Context) SizeOfAlignOfExpr(true, - Context->getTrivialTypeSourceInfo(returnType), - Context->getSizeType(), - SourceLocation(), SourceLocation()); + UnaryExprOrTypeTraitExpr *sizeofExpr = + new (Context) UnaryExprOrTypeTraitExpr(UETT_SizeOf, + Context->getTrivialTypeSourceInfo(returnType), + Context->getSizeType(), SourceLocation(), + SourceLocation()); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) // FIXME: Value of 8 is base on ppc32/x86 ABI for the most common cases. // For X86 it is more complicated and some kind of target specific routine @@ -3149,7 +3166,7 @@ QualType RewriteObjC::getProtocolType() { TypeSourceInfo *TInfo = Context->getTrivialTypeSourceInfo(Context->getObjCIdType()); ProtocolTypeDecl = TypedefDecl::Create(*Context, TUDecl, - SourceLocation(), + SourceLocation(), SourceLocation(), &Context->Idents.get("Protocol"), TInfo); } @@ -3164,7 +3181,7 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) { std::string Name = "_OBJC_PROTOCOL_" + Exp->getProtocol()->getNameAsString(); IdentifierInfo *ID = &Context->Idents.get(Name); VarDecl *VD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - ID, getProtocolType(), 0, + SourceLocation(), ID, getProtocolType(), 0, SC_Extern, SC_None); DeclRefExpr *DRE = new (Context) DeclRefExpr(VD, getProtocolType(), VK_LValue, SourceLocation()); @@ -3745,7 +3762,7 @@ void RewriteObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, std::string &Result) { ObjCInterfaceDecl *CDecl = IDecl->getClassInterface(); - // Explictly declared @interface's are already synthesized. + // Explicitly declared @interface's are already synthesized. if (CDecl->isImplicitInterfaceDecl()) { // FIXME: Implementation of a class with no @interface (legacy) doese not // produce correct synthesis as yet. @@ -4315,20 +4332,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, S += " "; std::string FieldName = (*I)->getNameAsString(); std::string ArgName = "_" + FieldName; - // Handle nested closure invocation. For example: - // - // void (^myImportedBlock)(void); - // myImportedBlock = ^(void) { setGlobalInt(x + y); }; - // - // void (^anotherBlock)(void); - // anotherBlock = ^(void) { - // myImportedBlock(); // import and invoke the closure - // }; - // - if (isTopLevelBlockPointerType((*I)->getType())) { - S += "struct __block_impl *"; - Constructor += ", void *" + ArgName; - } else { + { std::string TypeString; RewriteByRefString(TypeString, FieldName, (*I)); TypeString += " *"; @@ -4366,11 +4370,7 @@ std::string RewriteObjC::SynthesizeBlockImpl(BlockExpr *CE, std::string Tag, } else Constructor += ", "; - if (isTopLevelBlockPointerType((*I)->getType())) - Constructor += Name + "((struct __block_impl *)_" - + Name + "->__forwarding)"; - else - Constructor += Name + "(_" + Name + "->__forwarding)"; + Constructor += Name + "(_" + Name + "->__forwarding)"; } Constructor += " {\n"; @@ -4601,7 +4601,7 @@ void RewriteObjC::GetInnerBlockDeclRefExprs(Stmt *S, /// convertFunctionTypeOfBlocks - This routine converts a function type /// whose result type may be a block pointer or whose argument type(s) -/// might be block pointers to an equivalent funtion type replacing +/// might be block pointers to an equivalent function type replacing /// all block pointers to function pointers. QualType RewriteObjC::convertFunctionTypeOfBlocks(const FunctionType *FT) { const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FT); @@ -4672,7 +4672,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { // FTP will be null for closures that don't take arguments. RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), + SourceLocation(), SourceLocation(), &Context->Idents.get("__block_impl")); QualType PtrBlock = Context->getPointerType(Context->getTagDeclType(RD)); @@ -4706,7 +4706,9 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { //PE->dump(); FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), - &Context->Idents.get("FuncPtr"), Context->VoidPtrTy, 0, + SourceLocation(), + &Context->Idents.get("FuncPtr"), + Context->VoidPtrTy, 0, /*BitWidth=*/0, /*Mutable=*/true); MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(), FD->getType(), VK_LValue, @@ -4758,6 +4760,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { } FieldDecl *FD = FieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), &Context->Idents.get("__forwarding"), Context->VoidPtrTy, 0, /*BitWidth=*/0, /*Mutable=*/true); @@ -4767,7 +4770,7 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { OK_Ordinary); llvm::StringRef Name = VD->getName(); - FD = FieldDecl::Create(*Context, 0, SourceLocation(), + FD = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), &Context->Idents.get(Name), Context->VoidPtrTy, 0, /*BitWidth=*/0, /*Mutable=*/true); @@ -4777,7 +4780,8 @@ Stmt *RewriteObjC::RewriteBlockDeclRefExpr(Expr *DeclRefExp) { // Need parens to enforce precedence. - ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), + ParenExpr *PE = new (Context) ParenExpr(DeclRefExp->getExprLoc(), + DeclRefExp->getExprLoc(), ME); ReplaceStmt(DeclRefExp, PE); return PE; @@ -4949,7 +4953,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { QualType DeclT; if (VarDecl *VD = dyn_cast<VarDecl>(ND)) DeclT = VD->getType(); - else if (TypedefDecl *TDD = dyn_cast<TypedefDecl>(ND)) + else if (TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(ND)) DeclT = TDD->getUnderlyingType(); else if (FieldDecl *FD = dyn_cast<FieldDecl>(ND)) DeclT = FD->getType(); @@ -5053,7 +5057,7 @@ std::string RewriteObjC::SynthesizeByrefCopyDestroyHelper(VarDecl *VD, unsigned VoidPtrSize = static_cast<unsigned>(Context->getTypeSize(Context->VoidPtrTy)); - unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/8; + unsigned offset = (VoidPtrSize*4 + IntSize + IntSize)/Context->getCharWidth(); S += " _Block_object_assign((char*)dst + "; S += utostr(offset); S += ", *(void * *) ((char*)src + "; @@ -5124,8 +5128,11 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n"; ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n"; } - - Ty.getAsStringInternal(Name, Context->PrintingPolicy); + + QualType T = Ty; + (void)convertBlockPointerToFunctionPointer(T); + T.getAsStringInternal(Name, Context->PrintingPolicy); + ByrefType += " " + Name + ";\n"; ByrefType += "};\n"; // Insert this type in global scope. It is needed by helper function. @@ -5183,7 +5190,12 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { ByrefType += utostr(flag); } ByrefType += "};\n"; - ReplaceText(DeclLoc, endBuf-startBuf+Name.size(), ByrefType); + unsigned nameSize = Name.size(); + // for block or function pointer declaration. Name is aleady + // part of the declaration. + if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) + nameSize = 1; + ReplaceText(DeclLoc, endBuf-startBuf+nameSize, ByrefType); } else { SourceLocation startLoc; @@ -5263,8 +5275,8 @@ void RewriteObjC::CollectBlockDeclRefInfo(BlockExpr *Exp) { FunctionDecl *RewriteObjC::SynthBlockInitFunctionDecl(llvm::StringRef name) { IdentifierInfo *ID = &Context->Idents.get(name); QualType FType = Context->getFunctionNoProtoType(Context->VoidPtrTy); - return FunctionDecl::Create(*Context, TUDecl,SourceLocation(), - ID, FType, 0, SC_Extern, + return FunctionDecl::Create(*Context, TUDecl, SourceLocation(), + SourceLocation(), ID, FType, 0, SC_Extern, SC_None, false, false); } @@ -5345,10 +5357,11 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, // Initialize the block descriptor. std::string DescData = "__" + FuncName + "_block_desc_" + BlockNumber + "_DATA"; - VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, SourceLocation(), - &Context->Idents.get(DescData.c_str()), - Context->VoidPtrTy, 0, - SC_Static, SC_None); + VarDecl *NewVD = VarDecl::Create(*Context, TUDecl, + SourceLocation(), SourceLocation(), + &Context->Idents.get(DescData.c_str()), + Context->VoidPtrTy, 0, + SC_Static, SC_None); UnaryOperator *DescRefExpr = new (Context) UnaryOperator(new (Context) DeclRefExpr(NewVD, Context->VoidPtrTy, @@ -5407,7 +5420,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, IdentifierInfo *II = &Context->Idents.get(RecName.c_str() + sizeof("struct")); RecordDecl *RD = RecordDecl::Create(*Context, TTK_Struct, TUDecl, - SourceLocation(), II); + SourceLocation(), SourceLocation(), + II); assert(RD && "SynthBlockInitExpr(): Can't find RecordDecl"); QualType castT = Context->getPointerType(Context->getTagDeclType(RD)); @@ -5507,27 +5521,34 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { for (Stmt::child_range CI = S->children(); CI; ++CI) if (*CI) { Stmt *newStmt; - Stmt *S = (*CI); - if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(S)) { + Stmt *ChildStmt = (*CI); + if (ObjCIvarRefExpr *IvarRefExpr = dyn_cast<ObjCIvarRefExpr>(ChildStmt)) { Expr *OldBase = IvarRefExpr->getBase(); bool replaced = false; - newStmt = RewriteObjCNestedIvarRefExpr(S, replaced); + newStmt = RewriteObjCNestedIvarRefExpr(ChildStmt, replaced); if (replaced) { if (ObjCIvarRefExpr *IRE = dyn_cast<ObjCIvarRefExpr>(newStmt)) ReplaceStmt(OldBase, IRE->getBase()); else - ReplaceStmt(S, newStmt); + ReplaceStmt(ChildStmt, newStmt); } } else - newStmt = RewriteFunctionBodyOrGlobalInitializer(S); - if (newStmt) - *CI = newStmt; + newStmt = RewriteFunctionBodyOrGlobalInitializer(ChildStmt); + if (newStmt) { + if (Expr *PropOrImplicitRefExpr = dyn_cast<Expr>(ChildStmt)) + if (PropSetters[PropOrImplicitRefExpr] == S) { + S = newStmt; + newStmt = 0; + } + if (newStmt) + *CI = newStmt; + } // If dealing with an assignment with LHS being a property reference // expression, the entire assignment tree is rewritten into a property // setter messaging. This involvs the RHS too. Do not attempt to rewrite // RHS again. - if (Expr *Exp = dyn_cast<Expr>(S)) + if (Expr *Exp = dyn_cast<Expr>(ChildStmt)) if (isa<ObjCPropertyRefExpr>(Exp)) { if (PropSetters[Exp]) { ++CI; @@ -5546,13 +5567,14 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { // Rewrite the block body in place. Stmt *SaveCurrentBody = CurrentBody; CurrentBody = BE->getBody(); + CollectPropertySetters(CurrentBody); PropParentMap = 0; RewriteFunctionBodyOrGlobalInitializer(BE->getBody()); CurrentBody = SaveCurrentBody; PropParentMap = 0; ImportedLocalExternalDecls.clear(); // Now we snarf the rewritten text and stash it away for later use. - std::string Str = Rewrite.getRewrittenText(BE->getSourceRange()); + std::string Str = Rewrite.ConvertToString(BE->getBody()); RewrittenBlockExprs[BE] = Str; Stmt *blockTranscribed = SynthBlockInitExpr(BE, InnerBlockDeclRefs); @@ -5714,7 +5736,7 @@ Stmt *RewriteObjC::RewriteFunctionBodyOrGlobalInitializer(Stmt *S) { RewriteTypeOfDecl(VD); } } - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) { if (isTopLevelBlockPointerType(TD->getUnderlyingType())) RewriteBlockPointerDecl(TD); else if (TD->getUnderlyingType()->isFunctionPointerType()) @@ -5884,7 +5906,7 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) { } return; } - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { if (isTopLevelBlockPointerType(TD->getUnderlyingType())) RewriteBlockPointerDecl(TD); else if (TD->getUnderlyingType()->isFunctionPointerType()) diff --git a/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp b/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp index 92e2b03..51fe379 100644 --- a/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp +++ b/contrib/llvm/tools/clang/lib/Rewrite/Rewriter.cpp @@ -26,7 +26,23 @@ llvm::raw_ostream &RewriteBuffer::write(llvm::raw_ostream &os) const { return os; } -void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) { +/// \brief Return true if this character is non-new-line whitespace: +/// ' ', '\t', '\f', '\v', '\r'. +static inline bool isWhitespace(unsigned char c) { + switch (c) { + case ' ': + case '\t': + case '\f': + case '\v': + case '\r': + return true; + default: + return false; + } +} + +void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size, + bool removeLineIfEmpty) { // Nothing to remove, exit early. if (Size == 0) return; @@ -38,6 +54,34 @@ void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) { // Add a delta so that future changes are offset correctly. AddReplaceDelta(OrigOffset, -Size); + + if (removeLineIfEmpty) { + // Find the line that the remove occurred and if it is completely empty + // remove the line as well. + + iterator curLineStart = begin(); + unsigned curLineStartOffs = 0; + iterator posI = begin(); + for (unsigned i = 0; i != RealOffset; ++i) { + if (*posI == '\n') { + curLineStart = posI; + ++curLineStart; + curLineStartOffs = i + 1; + } + ++posI; + } + + unsigned lineSize = 0; + posI = curLineStart; + while (posI != end() && isWhitespace(*posI)) { + ++posI; + ++lineSize; + } + if (posI != end() && *posI == '\n') { + Buffer.erase(curLineStartOffs, lineSize + 1/* + '\n'*/); + AddReplaceDelta(curLineStartOffs, -(lineSize + 1/* + '\n'*/)); + } + } } void RewriteBuffer::InsertText(unsigned OrigOffset, llvm::StringRef Str, @@ -72,7 +116,8 @@ void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength, /// getRangeSize - Return the size in bytes of the specified range if they /// are in the same file. If not, this returns -1. -int Rewriter::getRangeSize(const CharSourceRange &Range) const { +int Rewriter::getRangeSize(const CharSourceRange &Range, + RewriteOptions opts) const { if (!isRewritable(Range.getBegin()) || !isRewritable(Range.getEnd())) return -1; @@ -91,8 +136,8 @@ int Rewriter::getRangeSize(const CharSourceRange &Range) const { RewriteBuffers.find(StartFileID); if (I != RewriteBuffers.end()) { const RewriteBuffer &RB = I->second; - EndOff = RB.getMappedOffset(EndOff, true); - StartOff = RB.getMappedOffset(StartOff); + EndOff = RB.getMappedOffset(EndOff, opts.IncludeInsertsAtEndOfRange); + StartOff = RB.getMappedOffset(StartOff, !opts.IncludeInsertsAtBeginOfRange); } @@ -104,8 +149,8 @@ int Rewriter::getRangeSize(const CharSourceRange &Range) const { return EndOff-StartOff; } -int Rewriter::getRangeSize(SourceRange Range) const { - return getRangeSize(CharSourceRange::getTokenRange(Range)); +int Rewriter::getRangeSize(SourceRange Range, RewriteOptions opts) const { + return getRangeSize(CharSourceRange::getTokenRange(Range), opts); } @@ -194,12 +239,24 @@ bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str, return false; } +bool Rewriter::InsertTextAfterToken(SourceLocation Loc, llvm::StringRef Str) { + if (!isRewritable(Loc)) return true; + FileID FID; + unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); + RewriteOptions rangeOpts; + rangeOpts.IncludeInsertsAtBeginOfRange = false; + StartOffs += getRangeSize(SourceRange(Loc, Loc), rangeOpts); + getEditBuffer(FID).InsertText(StartOffs, Str, /*InsertAfter*/true); + return false; +} + /// RemoveText - Remove the specified text region. -bool Rewriter::RemoveText(SourceLocation Start, unsigned Length) { +bool Rewriter::RemoveText(SourceLocation Start, unsigned Length, + RewriteOptions opts) { if (!isRewritable(Start)) return true; FileID FID; unsigned StartOffs = getLocationOffsetAndFileID(Start, FID); - getEditBuffer(FID).RemoveText(StartOffs, Length); + getEditBuffer(FID).RemoveText(StartOffs, Length, opts.RemoveLineIfEmpty); return false; } @@ -216,6 +273,20 @@ bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength, return false; } +bool Rewriter::ReplaceText(SourceRange range, SourceRange replacementRange) { + if (!isRewritable(range.getBegin())) return true; + if (!isRewritable(range.getEnd())) return true; + if (replacementRange.isInvalid()) return true; + SourceLocation start = range.getBegin(); + unsigned origLength = getRangeSize(range); + unsigned newLength = getRangeSize(replacementRange); + FileID FID; + unsigned newOffs = getLocationOffsetAndFileID(replacementRange.getBegin(), + FID); + llvm::StringRef MB = SourceMgr->getBufferData(FID); + return ReplaceText(start, origLength, MB.substr(newOffs, newLength)); +} + /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty /// printer to generate the replacement code. This returns true if the input /// could not be rewritten, or false if successful. @@ -234,3 +305,93 @@ bool Rewriter::ReplaceStmt(Stmt *From, Stmt *To) { ReplaceText(From->getLocStart(), Size, Str); return false; } + +std::string Rewriter::ConvertToString(Stmt *From) { + std::string SStr; + llvm::raw_string_ostream S(SStr); + From->printPretty(S, 0, PrintingPolicy(*LangOpts)); + return S.str(); +} + +bool Rewriter::IncreaseIndentation(CharSourceRange range, + SourceLocation parentIndent) { + using llvm::StringRef; + + if (!isRewritable(range.getBegin())) return true; + if (!isRewritable(range.getEnd())) return true; + if (!isRewritable(parentIndent)) return true; + + FileID StartFileID, EndFileID, parentFileID; + unsigned StartOff, EndOff, parentOff; + + StartOff = getLocationOffsetAndFileID(range.getBegin(), StartFileID); + EndOff = getLocationOffsetAndFileID(range.getEnd(), EndFileID); + parentOff = getLocationOffsetAndFileID(parentIndent, parentFileID); + + if (StartFileID != EndFileID || StartFileID != parentFileID) + return true; + if (StartOff >= EndOff || parentOff >= StartOff) + return true; + + FileID FID = StartFileID; + StringRef MB = SourceMgr->getBufferData(FID); + + unsigned parentLineNo = SourceMgr->getLineNumber(FID, parentOff) - 1; + unsigned startLineNo = SourceMgr->getLineNumber(FID, StartOff) - 1; + unsigned endLineNo = SourceMgr->getLineNumber(FID, EndOff) - 1; + + const SrcMgr::ContentCache * + Content = SourceMgr->getSLocEntry(FID).getFile().getContentCache(); + + // Find where the line starts for the three offsets. + unsigned parentLineOffs = Content->SourceLineCache[parentLineNo]; + unsigned startLineOffs = Content->SourceLineCache[startLineNo]; + unsigned endLineOffs = Content->SourceLineCache[endLineNo]; + + if (startLineOffs == endLineOffs || startLineOffs == parentLineOffs) + return true; + + // Find the whitespace at the start of each line. + StringRef parentSpace, startSpace, endSpace; + { + unsigned i = parentLineOffs; + while (isWhitespace(MB[i])) + ++i; + parentSpace = MB.substr(parentLineOffs, i-parentLineOffs); + + i = startLineOffs; + while (isWhitespace(MB[i])) + ++i; + startSpace = MB.substr(startLineOffs, i-startLineOffs); + + i = endLineOffs; + while (isWhitespace(MB[i])) + ++i; + endSpace = MB.substr(endLineOffs, i-endLineOffs); + } + if (parentSpace.size() >= startSpace.size()) + return true; + if (!startSpace.startswith(parentSpace)) + return true; + + llvm::StringRef indent = startSpace.substr(parentSpace.size()); + + // Indent the lines between start/end offsets. + RewriteBuffer &RB = getEditBuffer(FID); + for (unsigned i = startLineOffs; i != endLineOffs; ++i) { + if (MB[i] == '\n') { + unsigned startOfLine = i+1; + if (startOfLine == endLineOffs) + break; + StringRef origIndent; + unsigned ws = startOfLine; + while (isWhitespace(MB[ws])) + ++ws; + origIndent = MB.substr(startOfLine, ws-startOfLine); + if (origIndent.startswith(startSpace)) + RB.InsertText(startOfLine, indent, /*InsertAfter=*/false); + } + } + + return false; +} diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index 6a42224..e482172 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -24,12 +24,13 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" #include "clang/Analysis/CFGStmtMap.h" -#include "clang/Analysis/Analyses/UninitializedValuesV2.h" +#include "clang/Analysis/Analyses/UninitializedValues.h" #include "llvm/ADT/BitVector.h" #include "llvm/Support/Casting.h" @@ -129,12 +130,27 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { // normal. We need to look pass the destructors for the return // statement (if it exists). CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); + bool hasNoReturnDtor = false; + for ( ; ri != re ; ++ri) { CFGElement CE = *ri; + + // FIXME: The right solution is to just sever the edges in the + // CFG itself. + if (const CFGImplicitDtor *iDtor = ri->getAs<CFGImplicitDtor>()) + if (iDtor->isNoReturn(AC.getASTContext())) { + hasNoReturnDtor = true; + HasFakeEdge = true; + break; + } + if (isa<CFGStmt>(CE)) break; } + if (hasNoReturnDtor) + continue; + // No more CFGElements in the block? if (ri == re) { if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { @@ -363,17 +379,145 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, //===----------------------------------------------------------------------===// namespace { +/// ContainsReference - A visitor class to search for references to +/// a particular declaration (the needle) within any evaluated component of an +/// expression (recursively). +class ContainsReference : public EvaluatedExprVisitor<ContainsReference> { + bool FoundReference; + const DeclRefExpr *Needle; + +public: + ContainsReference(ASTContext &Context, const DeclRefExpr *Needle) + : EvaluatedExprVisitor<ContainsReference>(Context), + FoundReference(false), Needle(Needle) {} + + void VisitExpr(Expr *E) { + // Stop evaluating if we already have a reference. + if (FoundReference) + return; + + EvaluatedExprVisitor<ContainsReference>::VisitExpr(E); + } + + void VisitDeclRefExpr(DeclRefExpr *E) { + if (E == Needle) + FoundReference = true; + else + EvaluatedExprVisitor<ContainsReference>::VisitDeclRefExpr(E); + } + + bool doesContainReference() const { return FoundReference; } +}; +} + +/// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an +/// uninitialized variable. This manages the different forms of diagnostic +/// emitted for particular types of uses. Returns true if the use was diagnosed +/// as a warning. If a pariticular use is one we omit warnings for, returns +/// false. +static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, + const Expr *E, bool isAlwaysUninit) { + bool isSelfInit = false; + + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (isAlwaysUninit) { + // Inspect the initializer of the variable declaration which is + // being referenced prior to its initialization. We emit + // specialized diagnostics for self-initialization, and we + // specifically avoid warning about self references which take the + // form of: + // + // int x = x; + // + // This is used to indicate to GCC that 'x' is intentionally left + // uninitialized. Proven code paths which access 'x' in + // an uninitialized state after this will still warn. + // + // TODO: Should we suppress maybe-uninitialized warnings for + // variables initialized in this way? + if (const Expr *Initializer = VD->getInit()) { + if (DRE == Initializer->IgnoreParenImpCasts()) + return false; + + ContainsReference CR(S.Context, DRE); + CR.Visit(const_cast<Expr*>(Initializer)); + isSelfInit = CR.doesContainReference(); + } + if (isSelfInit) { + S.Diag(DRE->getLocStart(), + diag::warn_uninit_self_reference_in_init) + << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange(); + } else { + S.Diag(DRE->getLocStart(), diag::warn_uninit_var) + << VD->getDeclName() << DRE->getSourceRange(); + } + } else { + S.Diag(DRE->getLocStart(), diag::warn_maybe_uninit_var) + << VD->getDeclName() << DRE->getSourceRange(); + } + } else { + const BlockExpr *BE = cast<BlockExpr>(E); + S.Diag(BE->getLocStart(), + isAlwaysUninit ? diag::warn_uninit_var_captured_by_block + : diag::warn_maybe_uninit_var_captured_by_block) + << VD->getDeclName(); + } + + // Report where the variable was declared when the use wasn't within + // the initializer of that declaration. + if (!isSelfInit) + S.Diag(VD->getLocStart(), diag::note_uninit_var_def) + << VD->getDeclName(); + + return true; +} + +static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) { + // Don't issue a fixit if there is already an initializer. + if (VD->getInit()) + return; + + // Suggest possible initialization (if any). + const char *initialization = 0; + QualType VariableTy = VD->getType().getCanonicalType(); + + if (VariableTy->getAs<ObjCObjectPointerType>()) { + // Check if 'nil' is defined. + if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) + initialization = " = nil"; + else + initialization = " = 0"; + } + else if (VariableTy->isRealFloatingType()) + initialization = " = 0.0"; + else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) + initialization = " = false"; + else if (VariableTy->isEnumeralType()) + return; + else if (VariableTy->isScalarType()) + initialization = " = 0"; + + if (initialization) { + SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd()); + S.Diag(loc, diag::note_var_fixit_add_initialization) + << FixItHint::CreateInsertion(loc, initialization); + } +} + +typedef std::pair<const Expr*, bool> UninitUse; + +namespace { struct SLocSort { - bool operator()(const Expr *a, const Expr *b) { - SourceLocation aLoc = a->getLocStart(); - SourceLocation bLoc = b->getLocStart(); + bool operator()(const UninitUse &a, const UninitUse &b) { + SourceLocation aLoc = a.first->getLocStart(); + SourceLocation bLoc = b.first->getLocStart(); return aLoc.getRawEncoding() < bLoc.getRawEncoding(); } }; class UninitValsDiagReporter : public UninitVariablesHandler { Sema &S; - typedef llvm::SmallVector<const Expr *, 2> UsesVec; + typedef llvm::SmallVector<UninitUse, 2> UsesVec; typedef llvm::DenseMap<const VarDecl *, UsesVec*> UsesMap; UsesMap *uses; @@ -383,7 +527,8 @@ public: flushDiagnostics(); } - void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd) { + void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd, + bool isAlwaysUninit) { if (!uses) uses = new UsesMap(); @@ -391,7 +536,7 @@ public: if (!vec) vec = new UsesVec(); - vec->push_back(ex); + vec->push_back(std::make_pair(ex, isAlwaysUninit)); } void flushDiagnostics() { @@ -409,54 +554,19 @@ public: // a stable ordering. std::sort(vec->begin(), vec->end(), SLocSort()); - for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; ++vi) - { - if (const DeclRefExpr *dr = dyn_cast<DeclRefExpr>(*vi)) { - S.Diag(dr->getLocStart(), diag::warn_uninit_var) - << vd->getDeclName() << dr->getSourceRange(); - } - else { - const BlockExpr *be = cast<BlockExpr>(*vi); - S.Diag(be->getLocStart(), diag::warn_uninit_var_captured_by_block) - << vd->getDeclName(); - } - - // Report where the variable was declared. - S.Diag(vd->getLocStart(), diag::note_uninit_var_def) - << vd->getDeclName(); - - // Only report the fixit once. - if (fixitIssued) + for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; + ++vi) { + if (!DiagnoseUninitializedUse(S, vd, vi->first, + /*isAlwaysUninit=*/vi->second)) continue; - - fixitIssued = true; - - // Suggest possible initialization (if any). - const char *initialization = 0; - QualType vdTy = vd->getType().getCanonicalType(); - - if (vdTy->getAs<ObjCObjectPointerType>()) { - // Check if 'nil' is defined. - if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) - initialization = " = nil"; - else - initialization = " = 0"; - } - else if (vdTy->isRealFloatingType()) - initialization = " = 0.0"; - else if (vdTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) - initialization = " = false"; - else if (vdTy->isEnumeralType()) - continue; - else if (vdTy->isScalarType()) - initialization = " = 0"; - - if (initialization) { - SourceLocation loc = S.PP.getLocForEndOfToken(vd->getLocEnd()); - S.Diag(loc, diag::note_var_fixit_add_initialization) - << FixItHint::CreateInsertion(loc, initialization); + + // Suggest a fixit hint the first time we diagnose a use of a variable. + if (!fixitIssued) { + SuggestInitializationFixit(S, vd); + fixitIssued = true; } } + delete vec; } delete uses; @@ -531,25 +641,41 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Emit delayed diagnostics. if (!fscope->PossiblyUnreachableDiags.empty()) { bool analyzed = false; - if (CFGReachabilityAnalysis *cra = AC.getCFGReachablityAnalysis()) - if (CFGStmtMap *csm = AC.getCFGStmtMap()) { - analyzed = true; - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator - i = fscope->PossiblyUnreachableDiags.begin(), - e = fscope->PossiblyUnreachableDiags.end(); - i != e; ++i) { - const sema::PossiblyUnreachableDiag &D = *i; - if (const CFGBlock *blk = csm->getBlock(D.stmt)) { + + // Register the expressions with the CFGBuilder. + for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + i = fscope->PossiblyUnreachableDiags.begin(), + e = fscope->PossiblyUnreachableDiags.end(); + i != e; ++i) { + if (const Stmt *stmt = i->stmt) + AC.registerForcedBlockExpression(stmt); + } + + if (AC.getCFG()) { + analyzed = true; + for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + i = fscope->PossiblyUnreachableDiags.begin(), + e = fscope->PossiblyUnreachableDiags.end(); + i != e; ++i) + { + const sema::PossiblyUnreachableDiag &D = *i; + bool processed = false; + if (const Stmt *stmt = i->stmt) { + const CFGBlock *block = AC.getBlockForRegisteredExpression(stmt); + assert(block); + if (CFGReverseBlockReachabilityAnalysis *cra = AC.getCFGReachablityAnalysis()) { // Can this block be reached from the entrance? - if (cra->isReachable(&AC.getCFG()->getEntry(), blk)) + if (cra->isReachable(&AC.getCFG()->getEntry(), block)) S.Diag(D.Loc, D.PD); - } - else { - // Emit the warning anyway if we cannot map to a basic block. - S.Diag(D.Loc, D.PD); + processed = true; } } + if (!processed) { + // Emit the warning anyway if we cannot map to a basic block. + S.Diag(D.Loc, D.PD); + } } + } if (!analyzed) flushDiagnostics(S, fscope); @@ -569,25 +695,10 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, CheckUnreachable(S, AC); if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart()) + != Diagnostic::Ignored || + Diags.getDiagnosticLevel(diag::warn_maybe_uninit_var, D->getLocStart()) != Diagnostic::Ignored) { - ASTContext &ctx = D->getASTContext(); - llvm::OwningPtr<CFG> tmpCFG; - bool useAlternateCFG = false; - if (ctx.getLangOptions().CPlusPlus) { - // Temporary workaround: implicit dtors in the CFG can confuse - // the path-sensitivity in the uninitialized values analysis. - // For now create (if necessary) a separate CFG without implicit dtors. - // FIXME: We should not need to do this, as it results in multiple - // CFGs getting constructed. - CFG::BuildOptions B; - B.AddEHEdges = false; - B.AddImplicitDtors = false; - B.AddInitializers = true; - tmpCFG.reset(CFG::buildCFG(D, AC.getBody(), &ctx, B)); - useAlternateCFG = true; - } - CFG *cfg = useAlternateCFG ? tmpCFG.get() : AC.getCFG(); - if (cfg) { + if (CFG *cfg = AC.getCFG()) { UninitValsDiagReporter reporter(S); runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC, reporter); diff --git a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp index c0a3053..619a5b9 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp @@ -12,28 +12,89 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/AttributeList.h" +#include "clang/AST/Expr.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; -AttributeList::AttributeList(llvm::BumpPtrAllocator &Alloc, - IdentifierInfo *aName, SourceLocation aLoc, - IdentifierInfo *sName, SourceLocation sLoc, - IdentifierInfo *pName, SourceLocation pLoc, - Expr **ExprList, unsigned numArgs, - bool declspec, bool cxx0x) - : AttrName(aName), AttrLoc(aLoc), ScopeName(sName), - ScopeLoc(sLoc), - ParmName(pName), ParmLoc(pLoc), NumArgs(numArgs), Next(0), - DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false) { - - if (numArgs == 0) - Args = 0; - else { - // Allocate the Args array using the BumpPtrAllocator. - Args = Alloc.Allocate<Expr*>(numArgs); - memcpy(Args, ExprList, numArgs*sizeof(Args[0])); +size_t AttributeList::allocated_size() const { + if (IsAvailability) return AttributeFactory::AvailabilityAllocSize; + return (sizeof(AttributeList) + NumArgs * sizeof(Expr*)); +} + +AttributeFactory::AttributeFactory() { + // Go ahead and configure all the inline capacity. This is just a memset. + FreeLists.resize(InlineFreeListsCapacity); +} +AttributeFactory::~AttributeFactory() {} + +static size_t getFreeListIndexForSize(size_t size) { + assert(size >= sizeof(AttributeList)); + assert((size % sizeof(void*)) == 0); + return ((size - sizeof(AttributeList)) / sizeof(void*)); +} + +void *AttributeFactory::allocate(size_t size) { + // Check for a previously reclaimed attribute. + size_t index = getFreeListIndexForSize(size); + if (index < FreeLists.size()) { + if (AttributeList *attr = FreeLists[index]) { + FreeLists[index] = attr->NextInPool; + return attr; + } } + + // Otherwise, allocate something new. + return Alloc.Allocate(size, llvm::AlignOf<AttributeFactory>::Alignment); +} + +void AttributeFactory::reclaimPool(AttributeList *cur) { + assert(cur && "reclaiming empty pool!"); + do { + // Read this here, because we're going to overwrite NextInPool + // when we toss 'cur' into the appropriate queue. + AttributeList *next = cur->NextInPool; + + size_t size = cur->allocated_size(); + size_t freeListIndex = getFreeListIndexForSize(size); + + // Expand FreeLists to the appropriate size, if required. + if (freeListIndex >= FreeLists.size()) + FreeLists.resize(freeListIndex+1); + + // Add 'cur' to the appropriate free-list. + cur->NextInPool = FreeLists[freeListIndex]; + FreeLists[freeListIndex] = cur; + + cur = next; + } while (cur); +} + +void AttributePool::takePool(AttributeList *pool) { + assert(pool); + + // Fast path: this pool is empty. + if (!Head) { + Head = pool; + return; + } + + // Reverse the pool onto the current head. This optimizes for the + // pattern of pulling a lot of pools into a single pool. + do { + AttributeList *next = pool->NextInPool; + pool->NextInPool = Head; + Head = pool; + pool = next; + } while (pool); +} + +AttributeList * +AttributePool::createIntegerAttribute(ASTContext &C, IdentifierInfo *Name, + SourceLocation TokLoc, int Arg) { + Expr *IArg = IntegerLiteral::Create(C, llvm::APInt(32, (uint64_t) Arg), + C.IntTy, TokLoc); + return create(Name, TokLoc, 0, TokLoc, 0, TokLoc, &IArg, 1, 0); } AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { @@ -83,6 +144,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("may_alias", AT_may_alias) .Case("base_check", AT_base_check) .Case("deprecated", AT_deprecated) + .Case("availability", AT_availability) .Case("visibility", AT_visibility) .Case("destructor", AT_destructor) .Case("format_arg", AT_format_arg) @@ -94,10 +156,12 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("unavailable", AT_unavailable) .Case("overloadable", AT_overloadable) .Case("address_space", AT_address_space) + .Case("opencl_image_access", AT_opencl_image_access) .Case("always_inline", AT_always_inline) .Case("returns_twice", IgnoredAttribute) .Case("vec_type_hint", IgnoredAttribute) .Case("objc_exception", AT_objc_exception) + .Case("objc_method_family", AT_objc_method_family) .Case("ext_vector_type", AT_ext_vector_type) .Case("neon_vector_type", AT_neon_vector_type) .Case("neon_polyvector_type", AT_neon_polyvector_type) @@ -137,5 +201,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) { .Case("nocommon", AT_nocommon) .Case("opencl_kernel_function", AT_opencl_kernel_function) .Case("uuid", AT_uuid) + .Case("pcs", AT_pcs) + .Case("ms_struct", AT_MsStruct) .Default(UnknownAttribute); } diff --git a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp index b7037ce..2334ab5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -375,12 +375,21 @@ void CodeCompletionResult::computeCursorKindAndAvailability() { switch (Kind) { case RK_Declaration: // Set the availability based on attributes. - Availability = CXAvailability_Available; - if (Declaration->getAttr<UnavailableAttr>()) - Availability = CXAvailability_NotAvailable; - else if (Declaration->getAttr<DeprecatedAttr>()) + switch (Declaration->getAvailability()) { + case AR_Available: + case AR_NotYetIntroduced: + Availability = CXAvailability_Available; + break; + + case AR_Deprecated: Availability = CXAvailability_Deprecated; + break; + case AR_Unavailable: + Availability = CXAvailability_NotAvailable; + break; + } + if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Declaration)) if (Function->isDeleted()) Availability = CXAvailability_NotAvailable; diff --git a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp index 037594a..0f20d10 100644 --- a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp @@ -47,278 +47,130 @@ void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) { EndLocation = TemplateId->RAngleLoc; } -CXXScopeSpec::CXXScopeSpec(const CXXScopeSpec &Other) - : Range(Other.Range), ScopeRep(Other.ScopeRep), Buffer(0), - BufferSize(Other.BufferSize), BufferCapacity(Other.BufferSize) -{ - if (BufferSize) { - Buffer = static_cast<char *>(malloc(BufferSize)); - memcpy(Buffer, Other.Buffer, BufferSize); - } -} - -CXXScopeSpec &CXXScopeSpec::operator=(const CXXScopeSpec &Other) { - Range = Other.Range; - ScopeRep = Other.ScopeRep; - if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) { - // Re-use our storage. - BufferSize = Other.BufferSize; - memcpy(Buffer, Other.Buffer, BufferSize); - return *this; - } - - if (BufferCapacity) - free(Buffer); - if (Other.Buffer) { - BufferSize = Other.BufferSize; - BufferCapacity = BufferSize; - Buffer = static_cast<char *>(malloc(BufferSize)); - memcpy(Buffer, Other.Buffer, BufferSize); - } else { - Buffer = 0; - BufferSize = 0; - BufferCapacity = 0; - } - return *this; -} - -CXXScopeSpec::~CXXScopeSpec() { - if (BufferCapacity) - free(Buffer); -} - -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); - } -} void CXXScopeSpec::Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL, SourceLocation ColonColonLoc) { - ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, - TemplateKWLoc.isValid(), - TL.getTypePtr()); + Builder.Extend(Context, TemplateKWLoc, TL, ColonColonLoc); if (Range.getBegin().isInvalid()) Range.setBegin(TL.getBeginLoc()); Range.setEnd(ColonColonLoc); - // Push source-location info into the buffer. - SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity); - SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); - - assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() && + assert(Range == Builder.getSourceRange() && "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::Extend(ASTContext &Context, IdentifierInfo *Identifier, SourceLocation IdentifierLoc, SourceLocation ColonColonLoc) { - ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, Identifier); + Builder.Extend(Context, Identifier, IdentifierLoc, ColonColonLoc); + if (Range.getBegin().isInvalid()) Range.setBegin(IdentifierLoc); Range.setEnd(ColonColonLoc); - // Push source-location info into the buffer. - SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity); - SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); - - assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() && + assert(Range == Builder.getSourceRange() && "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::Extend(ASTContext &Context, NamespaceDecl *Namespace, SourceLocation NamespaceLoc, SourceLocation ColonColonLoc) { - ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, Namespace); + Builder.Extend(Context, Namespace, NamespaceLoc, ColonColonLoc); + if (Range.getBegin().isInvalid()) Range.setBegin(NamespaceLoc); Range.setEnd(ColonColonLoc); - // Push source-location info into the buffer. - SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity); - SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); - - assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() && + assert(Range == Builder.getSourceRange() && "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::Extend(ASTContext &Context, NamespaceAliasDecl *Alias, SourceLocation AliasLoc, SourceLocation ColonColonLoc) { - ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, Alias); + Builder.Extend(Context, Alias, AliasLoc, ColonColonLoc); + if (Range.getBegin().isInvalid()) Range.setBegin(AliasLoc); Range.setEnd(ColonColonLoc); - // Push source-location info into the buffer. - SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity); - SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); - - assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() && + assert(Range == Builder.getSourceRange() && "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc) { - assert(!ScopeRep && "Already have a nested-name-specifier!?"); - ScopeRep = NestedNameSpecifier::GlobalSpecifier(Context); - Range = SourceRange(ColonColonLoc); + Builder.MakeGlobal(Context, ColonColonLoc); - // Push source-location info into the buffer. - SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); + Range = SourceRange(ColonColonLoc); - assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() && + assert(Range == Builder.getSourceRange() && "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange R) { - ScopeRep = Qualifier; + Builder.MakeTrivial(Context, Qualifier, R); Range = R; - - // 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 CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) { if (!Other) { Range = SourceRange(); - ScopeRep = 0; + Builder.Clear(); return; } - - if (BufferCapacity) - free(Buffer); - - // 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. + Range = Other.getSourceRange(); - ScopeRep = Other.getNestedNameSpecifier(); - Buffer = static_cast<char *>(Other.getOpaqueData()); - BufferSize = Other.getDataLength(); - BufferCapacity = 0; + Builder.Adopt(Other); } NestedNameSpecifierLoc CXXScopeSpec::getWithLocInContext(ASTContext &Context) const { - if (isEmpty() || isInvalid()) + if (!Builder.getRepresentation()) 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(ScopeRep, Buffer); - - void *Mem = Context.Allocate(BufferSize, llvm::alignOf<void *>()); - memcpy(Mem, Buffer, BufferSize); - return NestedNameSpecifierLoc(ScopeRep, Mem); + return Builder.getWithLocInContext(Context); } /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. -DeclaratorChunk DeclaratorChunk::getFunction(const ParsedAttributes &attrs, - bool hasProto, bool isVariadic, +DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, SourceLocation EllipsisLoc, ParamInfo *ArgInfo, unsigned NumArgs, unsigned TypeQuals, bool RefQualifierIsLvalueRef, SourceLocation RefQualifierLoc, - bool hasExceptionSpec, - SourceLocation ThrowLoc, - bool hasAnyExceptionSpec, + ExceptionSpecificationType + ESpecType, + SourceLocation ESpecLoc, ParsedType *Exceptions, SourceRange *ExceptionRanges, unsigned NumExceptions, - SourceLocation LPLoc, - SourceLocation RPLoc, + Expr *NoexceptExpr, + SourceLocation LocalRangeBegin, + SourceLocation LocalRangeEnd, Declarator &TheDeclarator, ParsedType TrailingReturnType) { DeclaratorChunk I; - I.Kind = Function; - I.Loc = LPLoc; - I.EndLoc = RPLoc; - I.Fun.AttrList = attrs.getList(); - I.Fun.hasPrototype = hasProto; - I.Fun.isVariadic = isVariadic; - I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); - I.Fun.DeleteArgInfo = false; - I.Fun.TypeQuals = TypeQuals; - I.Fun.NumArgs = NumArgs; - I.Fun.ArgInfo = 0; + I.Kind = Function; + I.Loc = LocalRangeBegin; + I.EndLoc = LocalRangeEnd; + I.Fun.AttrList = 0; + I.Fun.hasPrototype = hasProto; + I.Fun.isVariadic = isVariadic; + I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); + I.Fun.DeleteArgInfo = false; + I.Fun.TypeQuals = TypeQuals; + I.Fun.NumArgs = NumArgs; + I.Fun.ArgInfo = 0; I.Fun.RefQualifierIsLValueRef = RefQualifierIsLvalueRef; - I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); - I.Fun.hasExceptionSpec = hasExceptionSpec; - I.Fun.ThrowLoc = ThrowLoc.getRawEncoding(); - I.Fun.hasAnyExceptionSpec = hasAnyExceptionSpec; - I.Fun.NumExceptions = NumExceptions; - I.Fun.Exceptions = 0; + I.Fun.RefQualifierLoc = RefQualifierLoc.getRawEncoding(); + I.Fun.ExceptionSpecType = ESpecType; + I.Fun.ExceptionSpecLoc = ESpecLoc.getRawEncoding(); + I.Fun.NumExceptions = 0; + I.Fun.Exceptions = 0; + I.Fun.NoexceptExpr = 0; I.Fun.TrailingReturnType = TrailingReturnType.getAsOpaquePtr(); // new[] an argument array if needed. @@ -338,13 +190,25 @@ DeclaratorChunk DeclaratorChunk::getFunction(const ParsedAttributes &attrs, } memcpy(I.Fun.ArgInfo, ArgInfo, sizeof(ArgInfo[0])*NumArgs); } - // new[] an exception array if needed - if (NumExceptions) { - I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions]; - for (unsigned i = 0; i != NumExceptions; ++i) { - I.Fun.Exceptions[i].Ty = Exceptions[i]; - I.Fun.Exceptions[i].Range = ExceptionRanges[i]; + + // Check what exception specification information we should actually store. + switch (ESpecType) { + default: break; // By default, save nothing. + case EST_Dynamic: + // new[] an exception array if needed + if (NumExceptions) { + I.Fun.NumExceptions = NumExceptions; + I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions]; + for (unsigned i = 0; i != NumExceptions; ++i) { + I.Fun.Exceptions[i].Ty = Exceptions[i]; + I.Fun.Exceptions[i].Range = ExceptionRanges[i]; + } } + break; + + case EST_ComputedNoexcept: + I.Fun.NoexceptExpr = NoexceptExpr; + break; } return I; } @@ -445,6 +309,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_typeofExpr: return "typeof"; case DeclSpec::TST_auto: return "auto"; case DeclSpec::TST_decltype: return "(decltype)"; + case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_error: return "(error)"; } llvm_unreachable("Unknown typespec!"); @@ -515,12 +380,14 @@ bool DeclSpec::SetStorageClassSpecThread(SourceLocation Loc, bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID) { - if (TypeSpecWidth != TSW_unspecified && - // Allow turning long -> long long. - (W != TSW_longlong || TypeSpecWidth != TSW_long)) + // Overwrite TSWLoc only if TypeSpecWidth was unspecified, so that + // for 'long long' we will keep the source location of the first 'long'. + if (TypeSpecWidth == TSW_unspecified) + TSWLoc = Loc; + // Allow turning long -> long long. + else if (W != TSW_longlong || TypeSpecWidth != TSW_long) return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID); TypeSpecWidth = W; - TSWLoc = Loc; if (TypeAltiVecVector && !TypeAltiVecBool && ((TypeSpecWidth == TSW_long) || (TypeSpecWidth == TSW_longlong))) { PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); @@ -554,6 +421,14 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, ParsedType Rep) { + return SetTypeSpecType(T, Loc, Loc, PrevSpec, DiagID, Rep); +} + +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, + SourceLocation TagNameLoc, + const char *&PrevSpec, + unsigned &DiagID, + ParsedType Rep) { assert(isTypeRep(T) && "T does not store a type"); assert(Rep && "no type provided!"); if (TypeSpecType != TST_unspecified) { @@ -563,7 +438,8 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, } TypeSpecType = T; TypeRep = Rep; - TSTLoc = Loc; + TSTLoc = TagKwLoc; + TSTNameLoc = TagNameLoc; TypeSpecOwned = false; return false; } @@ -582,6 +458,7 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, TypeSpecType = T; ExprRep = Rep; TSTLoc = Loc; + TSTNameLoc = Loc; TypeSpecOwned = false; return false; } @@ -590,6 +467,14 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, Decl *Rep, bool Owned) { + return SetTypeSpecType(T, Loc, Loc, PrevSpec, DiagID, Rep, Owned); +} + +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, + SourceLocation TagNameLoc, + const char *&PrevSpec, + unsigned &DiagID, + Decl *Rep, bool Owned) { assert(isDeclRep(T) && "T does not store a decl"); // Unlike the other cases, we don't assert that we actually get a decl. @@ -600,7 +485,8 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, } TypeSpecType = T; DeclRep = Rep; - TSTLoc = Loc; + TSTLoc = TagKwLoc; + TSTNameLoc = TagNameLoc; TypeSpecOwned = Owned; return false; } @@ -615,13 +501,13 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, DiagID = diag::err_invalid_decl_spec_combination; return true; } + TSTLoc = Loc; + TSTNameLoc = Loc; if (TypeAltiVecVector && (T == TST_bool) && !TypeAltiVecBool) { TypeAltiVecBool = true; - TSTLoc = Loc; return false; } TypeSpecType = T; - TSTLoc = Loc; TypeSpecOwned = false; if (TypeAltiVecVector && !TypeAltiVecBool && (TypeSpecType == TST_double)) { PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType); @@ -653,6 +539,7 @@ bool DeclSpec::SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, } TypeAltiVecPixel = isAltiVecPixel; TSTLoc = Loc; + TSTNameLoc = Loc; return false; } @@ -660,6 +547,7 @@ bool DeclSpec::SetTypeSpecError() { TypeSpecType = TST_error; TypeSpecOwned = false; TSTLoc = SourceLocation(); + TSTNameLoc = SourceLocation(); return false; } @@ -929,6 +817,8 @@ void UnqualifiedId::setOperatorFunctionId(SourceLocation OperatorLoc, bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, const char *&PrevSpec) { + LastLocation = Loc; + if (Specifiers & VS) { PrevSpec = getSpecifierName(VS); return true; @@ -940,7 +830,6 @@ bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, default: assert(0 && "Unknown specifier!"); case VS_Override: VS_overrideLoc = Loc; break; case VS_Final: VS_finalLoc = Loc; break; - case VS_New: VS_newLoc = Loc; break; } return false; @@ -951,33 +840,5 @@ const char *VirtSpecifiers::getSpecifierName(Specifier VS) { default: assert(0 && "Unknown specifier"); case VS_Override: return "override"; case VS_Final: return "final"; - case VS_New: return "new"; } } - -bool ClassVirtSpecifiers::SetSpecifier(Specifier CVS, SourceLocation Loc, - const char *&PrevSpec) { - if (Specifiers & CVS) { - PrevSpec = getSpecifierName(CVS); - return true; - } - - Specifiers |= CVS; - - switch (CVS) { - default: assert(0 && "Unknown specifier!"); - case CVS_Final: CVS_finalLoc = Loc; break; - case CVS_Explicit: CVS_explicitLoc = Loc; break; - } - - return false; -} - -const char *ClassVirtSpecifiers::getSpecifierName(Specifier CVS) { - switch (CVS) { - default: assert(0 && "Unknown specifier"); - case CVS_Final: return "final"; - case CVS_Explicit: return "explicit"; - } -} - diff --git a/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp b/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp new file mode 100644 index 0000000..af548fe --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Sema/DelayedDiagnostic.cpp @@ -0,0 +1,51 @@ +//===--- DelayedDiagnostic.cpp - Delayed declarator diagnostics -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DelayedDiagnostic class implementation, which +// is used to record diagnostics that are being conditionally produced +// during declarator parsing. +// +// This file also defines AccessedEntity. +// +//===----------------------------------------------------------------------===// +#include "clang/Sema/DelayedDiagnostic.h" +#include <string.h> +using namespace clang; +using namespace sema; + +DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc, + const NamedDecl *D, + llvm::StringRef Msg) { + DelayedDiagnostic DD; + DD.Kind = Deprecation; + DD.Triggered = false; + DD.Loc = Loc; + DD.DeprecationData.Decl = D; + char *MessageData = 0; + if (Msg.size()) { + MessageData = new char [Msg.size()]; + memcpy(MessageData, Msg.data(), Msg.size()); + } + + DD.DeprecationData.Message = MessageData; + DD.DeprecationData.MessageLen = Msg.size(); + return DD; +} + +void DelayedDiagnostic::Destroy() { + switch (Kind) { + case Access: + getAccessData().~AccessedEntity(); + break; + + case Deprecation: + delete [] DeprecationData.Message; + break; + } +} diff --git a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp index 3f16ed7..95420a3 100644 --- a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp @@ -104,7 +104,8 @@ IdentifierResolver::~IdentifierResolver() { /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, - ASTContext &Context, Scope *S) const { + ASTContext &Context, Scope *S, + bool ExplicitInstantiationOrSpecialization) const { Ctx = Ctx->getRedeclContext(); if (Ctx->isFunctionOrMethod()) { @@ -135,7 +136,10 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, return false; } - return D->getDeclContext()->getRedeclContext()->Equals(Ctx); + DeclContext *DCtx = D->getDeclContext()->getRedeclContext(); + return ExplicitInstantiationOrSpecialization + ? Ctx->InEnclosingNamespaceSetOf(DCtx) + : Ctx->Equals(DCtx); } /// AddDecl - Link the decl to its shadowed decl chain. @@ -164,6 +168,44 @@ void IdentifierResolver::AddDecl(NamedDecl *D) { IDI->AddDecl(D); } +void IdentifierResolver::InsertDeclAfter(iterator Pos, NamedDecl *D) { + DeclarationName Name = D->getDeclName(); + void *Ptr = Name.getFETokenInfo<void>(); + + if (!Ptr) { + AddDecl(D); + return; + } + + if (isDeclPtr(Ptr)) { + // We only have a single declaration: insert before or after it, + // as appropriate. + if (Pos == iterator()) { + // Add the new declaration before the existing declaration. + NamedDecl *PrevD = static_cast<NamedDecl*>(Ptr); + RemoveDecl(PrevD); + AddDecl(D); + AddDecl(PrevD); + } else { + // Add new declaration after the existing declaration. + AddDecl(D); + } + + return; + } + + if (IdentifierInfo *II = Name.getAsIdentifierInfo()) + II->setIsFromAST(false); + + // General case: insert the declaration at the appropriate point in the + // list, which already has at least two elements. + IdDeclInfo *IDI = toIdDeclInfo(Ptr); + if (Pos.isIterator()) { + IDI->InsertDecl(Pos.getIterator() + 1, D); + } else + IDI->InsertDecl(IDI->decls_begin(), D); +} + /// RemoveDecl - Unlink the decl from its shadowed decl chain. /// The decl must already be part of the decl chain. void IdentifierResolver::RemoveDecl(NamedDecl *D) { diff --git a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp index b73f0e9..867d78f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp @@ -149,6 +149,11 @@ static std::pair<unsigned,unsigned> return std::make_pair((unsigned) diag::note_protected_by_vla_typedef, 0); } + if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) { + if (TD->getUnderlyingType()->isVariablyModifiedType()) + return std::make_pair((unsigned) diag::note_protected_by_vla_type_alias, 0); + } + return std::make_pair(0U, 0U); } diff --git a/contrib/llvm/tools/clang/lib/Sema/Scope.cpp b/contrib/llvm/tools/clang/lib/Sema/Scope.cpp new file mode 100644 index 0000000..833a59f --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Sema/Scope.cpp @@ -0,0 +1,57 @@ +//===- Scope.cpp - Lexical scope information --------------------*- 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 Scope class, which is used for recording +// information about a lexical scope. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/Scope.h" + +using namespace clang; + +void Scope::Init(Scope *parent, unsigned flags) { + AnyParent = parent; + Flags = flags; + + if (parent) { + Depth = parent->Depth + 1; + PrototypeDepth = parent->PrototypeDepth; + PrototypeIndex = 0; + FnParent = parent->FnParent; + BreakParent = parent->BreakParent; + ContinueParent = parent->ContinueParent; + ControlParent = parent->ControlParent; + BlockParent = parent->BlockParent; + TemplateParamParent = parent->TemplateParamParent; + } else { + Depth = 0; + PrototypeDepth = 0; + PrototypeIndex = 0; + FnParent = BreakParent = ContinueParent = BlockParent = 0; + ControlParent = 0; + TemplateParamParent = 0; + } + + // If this scope is a function or contains breaks/continues, remember it. + if (flags & FnScope) FnParent = this; + if (flags & BreakScope) BreakParent = this; + if (flags & ContinueScope) ContinueParent = this; + if (flags & ControlScope) ControlParent = this; + if (flags & BlockScope) BlockParent = this; + if (flags & TemplateParamScope) TemplateParamParent = this; + + // If this is a prototype scope, record that. + if (flags & FunctionPrototypeScope) PrototypeDepth++; + + DeclsInScope.clear(); + UsingDirectives.clear(); + Entity = 0; + ErrorTrap.reset(); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp index 0c39e13..7707fb1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp @@ -67,12 +67,14 @@ void Sema::ActOnTranslationUnitScope(Scope *S) { TInfo = Context.getTrivialTypeSourceInfo(Context.Int128Ty); PushOnScopeChains(TypedefDecl::Create(Context, CurContext, SourceLocation(), + SourceLocation(), &Context.Idents.get("__int128_t"), TInfo), TUScope); TInfo = Context.getTrivialTypeSourceInfo(Context.UnsignedInt128Ty); PushOnScopeChains(TypedefDecl::Create(Context, CurContext, SourceLocation(), + SourceLocation(), &Context.Idents.get("__uint128_t"), TInfo), TUScope); Context.setInt128Installed(); @@ -87,7 +89,8 @@ void Sema::ActOnTranslationUnitScope(Scope *S) { QualType SelT = Context.getPointerType(Context.ObjCBuiltinSelTy); TypeSourceInfo *SelInfo = Context.getTrivialTypeSourceInfo(SelT); TypedefDecl *SelTypedef - = TypedefDecl::Create(Context, CurContext, SourceLocation(), + = TypedefDecl::Create(Context, CurContext, + SourceLocation(), SourceLocation(), &Context.Idents.get("SEL"), SelInfo); PushOnScopeChains(SelTypedef, TUScope); Context.setObjCSelType(Context.getTypeDeclType(SelTypedef)); @@ -109,7 +112,8 @@ void Sema::ActOnTranslationUnitScope(Scope *S) { T = Context.getObjCObjectPointerType(T); TypeSourceInfo *IdInfo = Context.getTrivialTypeSourceInfo(T); TypedefDecl *IdTypedef - = TypedefDecl::Create(Context, CurContext, SourceLocation(), + = TypedefDecl::Create(Context, CurContext, + SourceLocation(), SourceLocation(), &Context.Idents.get("id"), IdInfo); PushOnScopeChains(IdTypedef, TUScope); Context.setObjCIdType(Context.getTypeDeclType(IdTypedef)); @@ -121,7 +125,8 @@ void Sema::ActOnTranslationUnitScope(Scope *S) { T = Context.getObjCObjectPointerType(T); TypeSourceInfo *ClassInfo = Context.getTrivialTypeSourceInfo(T); TypedefDecl *ClassTypedef - = TypedefDecl::Create(Context, CurContext, SourceLocation(), + = TypedefDecl::Create(Context, CurContext, + SourceLocation(), SourceLocation(), &Context.Idents.get("Class"), ClassInfo); PushOnScopeChains(ClassTypedef, TUScope); Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); @@ -136,7 +141,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), - PackContext(0), VisContext(0), + PackContext(0), MSStructPragmaOn(false), VisContext(0), + LateTemplateParser(0), OpaqueParser(0), IdResolver(pp.getLangOptions()), CXXTypeInfoDecl(0), MSVCGuidDecl(0), GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), @@ -178,7 +184,7 @@ Sema::~Sema() { if (PackContext) FreePackedContext(); if (VisContext) FreeVisContext(); delete TheTargetAttributesSema; - + MSStructPragmaOn = false; // Kill all the active scopes. for (unsigned I = 1, E = FunctionScopes.size(); I != E; ++I) delete FunctionScopes[I]; @@ -195,39 +201,58 @@ Sema::~Sema() { ExternalSema->ForgetSema(); } +ASTMutationListener *Sema::getASTMutationListener() const { + return getASTConsumer().GetASTMutationListener(); +} + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// The result is of the given category. -void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, - CastKind Kind, ExprValueKind VK, - const CXXCastPath *BasePath) { - QualType ExprTy = Context.getCanonicalType(Expr->getType()); +ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, + CastKind Kind, ExprValueKind VK, + const CXXCastPath *BasePath) { + QualType ExprTy = Context.getCanonicalType(E->getType()); QualType TypeTy = Context.getCanonicalType(Ty); if (ExprTy == TypeTy) - return; + return Owned(E); // If this is a derived-to-base cast to a through a virtual base, we // need a vtable. if (Kind == CK_DerivedToBase && BasePathInvolvesVirtualBase(*BasePath)) { - QualType T = Expr->getType(); + QualType T = E->getType(); if (const PointerType *Pointer = T->getAs<PointerType>()) T = Pointer->getPointeeType(); if (const RecordType *RecordTy = T->getAs<RecordType>()) - MarkVTableUsed(Expr->getLocStart(), + MarkVTableUsed(E->getLocStart(), cast<CXXRecordDecl>(RecordTy->getDecl())); } - if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { + if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(E)) { if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) { ImpCast->setType(Ty); ImpCast->setValueKind(VK); - return; + return Owned(E); } } - Expr = ImplicitCastExpr::Create(Context, Ty, Kind, Expr, BasePath, VK); + return Owned(ImplicitCastExpr::Create(Context, Ty, Kind, E, BasePath, VK)); +} + +/// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding +/// to the conversion from scalar type ScalarTy to the Boolean type. +CastKind Sema::ScalarTypeToBooleanCastKind(QualType ScalarTy) { + switch (ScalarTy->getScalarTypeKind()) { + case Type::STK_Bool: return CK_NoOp; + case Type::STK_Pointer: return CK_PointerToBoolean; + case Type::STK_MemberPointer: return CK_MemberPointerToBoolean; + case Type::STK_Integral: return CK_IntegralToBoolean; + case Type::STK_Floating: return CK_FloatingToBoolean; + case Type::STK_IntegralComplex: return CK_IntegralComplexToBoolean; + case Type::STK_FloatingComplex: return CK_FloatingComplexToBoolean; + } + return CK_Invalid; } ExprValueKind Sema::CastCategory(Expr *E) { @@ -352,22 +377,30 @@ void Sema::ActOnEndOfTranslationUnit() { } } - // If DefinedUsedVTables ends up marking any virtual member functions it - // might lead to more pending template instantiations, which we then need - // to instantiate. - DefineUsedVTables(); - - // C++: Perform implicit template instantiations. - // - // FIXME: When we perform these implicit instantiations, we do not - // carefully keep track of the point of instantiation (C++ [temp.point]). - // This means that name lookup that occurs within the template - // instantiation will always happen at the end of the translation unit, - // so it will find some names that should not be found. Although this is - // common behavior for C++ compilers, it is technically wrong. In the - // future, we either need to be able to filter the results of name lookup - // or we need to perform template instantiations earlier. - PerformPendingInstantiations(); + bool SomethingChanged; + do { + SomethingChanged = false; + + // If DefinedUsedVTables ends up marking any virtual member functions it + // might lead to more pending template instantiations, which we then need + // to instantiate. + if (DefineUsedVTables()) + SomethingChanged = true; + + // C++: Perform implicit template instantiations. + // + // FIXME: When we perform these implicit instantiations, we do not + // carefully keep track of the point of instantiation (C++ [temp.point]). + // This means that name lookup that occurs within the template + // instantiation will always happen at the end of the translation unit, + // so it will find some names that should not be found. Although this is + // common behavior for C++ compilers, it is technically wrong. In the + // future, we either need to be able to filter the results of name lookup + // or we need to perform template instantiations earlier. + if (PerformPendingInstantiations()) + SomethingChanged = true; + + } while (SomethingChanged); } // Remove file scoped decls that turned out to be used. @@ -451,16 +484,32 @@ void Sema::ActOnEndOfTranslationUnit() { const FunctionDecl *DiagD; if (!FD->hasBody(DiagD)) DiagD = FD; - Diag(DiagD->getLocation(), - isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function - : diag::warn_unused_function) - << DiagD->getDeclName(); + if (DiagD->isDeleted()) + continue; // Deleted functions are supposed to be unused. + if (DiagD->isReferenced()) { + if (isa<CXXMethodDecl>(DiagD)) + Diag(DiagD->getLocation(), diag::warn_unneeded_member_function) + << DiagD->getDeclName(); + else + Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) + << /*function*/0 << DiagD->getDeclName(); + } else { + Diag(DiagD->getLocation(), + isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function + : diag::warn_unused_function) + << DiagD->getDeclName(); + } } else { const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition(); if (!DiagD) DiagD = cast<VarDecl>(*I); - Diag(DiagD->getLocation(), diag::warn_unused_variable) - << DiagD->getDeclName(); + if (DiagD->isReferenced()) { + Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) + << /*variable*/1 << DiagD->getDeclName(); + } else { + Diag(DiagD->getLocation(), diag::warn_unused_variable) + << DiagD->getDeclName(); + } } } @@ -585,6 +634,27 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { return Builder; } +/// \brief Looks through the macro-instantiation chain for the given +/// location, looking for a macro instantiation with the given name. +/// If one is found, returns true and sets the location to that +/// instantiation loc. +bool Sema::findMacroSpelling(SourceLocation &locref, llvm::StringRef name) { + SourceLocation loc = locref; + if (!loc.isMacroID()) return false; + + // There's no good way right now to look at the intermediate + // instantiations, so just jump to the instantiation location. + loc = getSourceManager().getInstantiationLoc(loc); + + // If that's written with the name, stop here. + llvm::SmallVector<char, 16> buffer; + if (getPreprocessor().getSpelling(loc, buffer) == name) { + locref = loc; + return true; + } + return false; +} + /// \brief Determines the active Scope associated with the given declaration /// context. /// diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp index 4f9bf1c..411d424 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp @@ -1011,16 +1011,16 @@ static void DiagnoseAccessPath(Sema &S, // Find an original declaration. while (D->isOutOfLine()) { NamedDecl *PrevDecl = 0; - if (isa<VarDecl>(D)) - PrevDecl = cast<VarDecl>(D)->getPreviousDeclaration(); - else if (isa<FunctionDecl>(D)) - PrevDecl = cast<FunctionDecl>(D)->getPreviousDeclaration(); - else if (isa<TypedefDecl>(D)) - PrevDecl = cast<TypedefDecl>(D)->getPreviousDeclaration(); - else if (isa<TagDecl>(D)) { + if (VarDecl *VD = dyn_cast<VarDecl>(D)) + PrevDecl = VD->getPreviousDeclaration(); + else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + PrevDecl = FD->getPreviousDeclaration(); + else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(D)) + PrevDecl = TND->getPreviousDeclaration(); + else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { if (isa<RecordDecl>(D) && cast<RecordDecl>(D)->isInjectedClassName()) break; - PrevDecl = cast<TagDecl>(D)->getPreviousDeclaration(); + PrevDecl = TD->getPreviousDeclaration(); } if (!PrevDecl) break; D = PrevDecl; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp index 794b0b1..53dd297 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp @@ -129,6 +129,12 @@ void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) { } } +void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) { + if (!MSStructPragmaOn) + return; + RD->addAttr(::new (Context) MsStructAttr(SourceLocation(), Context)); +} + void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc, SourceLocation KindLoc) { @@ -263,6 +269,10 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, } } +void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) { + MSStructPragmaOn = (Kind == PMSST_ON); +} + void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, SourceLocation PragmaLoc) { @@ -297,7 +307,7 @@ void Sema::AddPushedVisibilityAttribute(Decl *D) { if (!VisContext) return; - if (D->hasAttr<VisibilityAttr>()) + if (isa<NamedDecl>(D) && cast<NamedDecl>(D)->getExplicitVisibility()) return; VisStack *Stack = static_cast<VisStack*>(VisContext); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp index 506d261..ed54f0f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCXXCast.cpp @@ -42,21 +42,21 @@ enum CastType { -static void CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, +static void CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK, const SourceRange &OpRange, const SourceRange &DestRange); -static void CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, +static void CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK, const SourceRange &OpRange, const SourceRange &DestRange, CastKind &Kind); -static void CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, +static void CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK, const SourceRange &OpRange, CastKind &Kind, CXXCastPath &BasePath); -static void CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, +static void CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK, const SourceRange &OpRange, const SourceRange &DestRange, @@ -100,7 +100,7 @@ static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType, QualType OrigDestType, unsigned &msg, CastKind &Kind, CXXCastPath &BasePath); -static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, +static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType, QualType DestType,bool CStyle, const SourceRange &OpRange, @@ -108,12 +108,12 @@ static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, CastKind &Kind, CXXCastPath &BasePath); -static TryCastResult TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, +static TryCastResult TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastKind &Kind); -static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, +static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, @@ -121,24 +121,13 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, CXXCastPath &BasePath); static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, bool CStyle, unsigned &msg); -static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, +static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastKind &Kind); -static ExprResult -ResolveAndFixSingleFunctionTemplateSpecialization( - Sema &Self, Expr *SrcExpr, - bool DoFunctionPointerConverion = false, - bool Complain = false, - const SourceRange& OpRangeForComplaining = SourceRange(), - QualType DestTypeForComplaining = QualType(), - unsigned DiagIDForComplaining = 0); - - - /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. ExprResult Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, @@ -159,8 +148,9 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, ExprResult Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, - TypeSourceInfo *DestTInfo, Expr *Ex, + TypeSourceInfo *DestTInfo, Expr *E, SourceRange AngleBrackets, SourceRange Parens) { + ExprResult Ex = Owned(E); QualType DestType = DestTInfo->getType(); SourceRange OpRange(OpLoc, Parens.getEnd()); @@ -168,11 +158,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, // If the type is dependent, we won't do the semantic analysis now. // FIXME: should we check this in a more fine-grained manner? - bool TypeDependent = DestType->isDependentType() || Ex->isTypeDependent(); - - if (Ex->isBoundMemberFunction(Context)) - Diag(Ex->getLocStart(), diag::err_invalid_use_of_bound_member_func) - << Ex->getSourceRange(); + bool TypeDependent = DestType->isDependentType() || Ex.get()->isTypeDependent(); ExprValueKind VK = VK_RValue; if (TypeDependent) @@ -182,42 +168,54 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, default: llvm_unreachable("Unknown C++ cast!"); case tok::kw_const_cast: - if (!TypeDependent) + if (!TypeDependent) { CheckConstCast(*this, Ex, DestType, VK, OpRange, DestRange); + if (Ex.isInvalid()) + return ExprError(); + } return Owned(CXXConstCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - VK, Ex, DestTInfo, OpLoc, + VK, Ex.take(), DestTInfo, OpLoc, Parens.getEnd())); case tok::kw_dynamic_cast: { CastKind Kind = CK_Dependent; CXXCastPath BasePath; - if (!TypeDependent) + if (!TypeDependent) { CheckDynamicCast(*this, Ex, DestType, VK, OpRange, DestRange, Kind, BasePath); + if (Ex.isInvalid()) + return ExprError(); + } return Owned(CXXDynamicCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - VK, Kind, Ex, &BasePath, DestTInfo, + VK, Kind, Ex.take(), &BasePath, DestTInfo, OpLoc, Parens.getEnd())); } case tok::kw_reinterpret_cast: { CastKind Kind = CK_Dependent; - if (!TypeDependent) + if (!TypeDependent) { CheckReinterpretCast(*this, Ex, DestType, VK, OpRange, DestRange, Kind); + if (Ex.isInvalid()) + return ExprError(); + } return Owned(CXXReinterpretCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - VK, Kind, Ex, 0, + VK, Kind, Ex.take(), 0, DestTInfo, OpLoc, Parens.getEnd())); } case tok::kw_static_cast: { CastKind Kind = CK_Dependent; CXXCastPath BasePath; - if (!TypeDependent) + if (!TypeDependent) { CheckStaticCast(*this, Ex, DestType, VK, OpRange, Kind, BasePath); + if (Ex.isInvalid()) + return ExprError(); + } return Owned(CXXStaticCastExpr::Create(Context, DestType.getNonLValueExprType(Context), - VK, Kind, Ex, &BasePath, + VK, Kind, Ex.take(), &BasePath, DestTInfo, OpLoc, Parens.getEnd())); } } @@ -303,6 +301,11 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, /// Diagnose a failed cast. static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType, SourceRange opRange, Expr *src, QualType destType) { + if (src->getType() == S.Context.BoundMemberTy) { + (void) S.CheckPlaceholderExpr(src); // will always fail + return; + } + if (msg == diag::err_bad_cxx_cast_generic && tryDiagnoseOverloadedCast(S, castType, opRange, src, destType)) return; @@ -388,15 +391,17 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { UnwrappedDestType = Self.Context.getCanonicalType(DestType); llvm::SmallVector<Qualifiers, 8> cv1, cv2; - // Find the qualifications. + // Find the qualifiers. We only care about cvr-qualifiers for the + // purpose of this check, because other qualifiers (address spaces, + // Objective-C GC, etc.) are part of the type's identity. while (UnwrapDissimilarPointerTypes(UnwrappedSrcType, UnwrappedDestType)) { Qualifiers SrcQuals; Self.Context.getUnqualifiedArrayType(UnwrappedSrcType, SrcQuals); - cv1.push_back(SrcQuals); + cv1.push_back(Qualifiers::fromCVRMask(SrcQuals.getCVRQualifiers())); Qualifiers DestQuals; Self.Context.getUnqualifiedArrayType(UnwrappedDestType, DestQuals); - cv2.push_back(DestQuals); + cv2.push_back(Qualifiers::fromCVRMask(DestQuals.getCVRQualifiers())); } if (cv1.empty()) return false; @@ -424,11 +429,11 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType) { /// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime- /// checked downcasts in class hierarchies. static void -CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, +CheckDynamicCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK, const SourceRange &OpRange, const SourceRange &DestRange, CastKind &Kind, CXXCastPath &BasePath) { - QualType OrigDestType = DestType, OrigSrcType = SrcExpr->getType(); + QualType OrigDestType = DestType, OrigSrcType = SrcExpr.get()->getType(); DestType = Self.Context.getCanonicalType(DestType); // C++ 5.2.7p1: T shall be a pointer or reference to a complete class type, @@ -475,11 +480,11 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, SrcPointee = SrcPointer->getPointeeType(); } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr) - << OrigSrcType << SrcExpr->getSourceRange(); + << OrigSrcType << SrcExpr.get()->getSourceRange(); return; } } else if (DestReference->isLValueReferenceType()) { - if (!SrcExpr->isLValue()) { + if (!SrcExpr.get()->isLValue()) { Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_rvalue) << CT_Dynamic << OrigSrcType << OrigDestType << OpRange; } @@ -492,11 +497,11 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, if (SrcRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, Self.PDiag(diag::err_bad_dynamic_cast_incomplete) - << SrcExpr->getSourceRange())) + << SrcExpr.get()->getSourceRange())) return; } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_class) - << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); + << SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange(); return; } @@ -508,7 +513,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, // C++ 5.2.7p1: The dynamic_cast operator shall not cast away constness. if (!DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { - Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away) + Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_qualifiers_away) << CT_Dynamic << OrigSrcType << OrigDestType << OpRange; return; } @@ -543,7 +548,7 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, assert(SrcDecl && "Definition missing"); if (!cast<CXXRecordDecl>(SrcDecl)->isPolymorphic()) { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_polymorphic) - << SrcPointee.getUnqualifiedType() << SrcExpr->getSourceRange(); + << SrcPointee.getUnqualifiedType() << SrcExpr.get()->getSourceRange(); } Self.MarkVTableUsed(OpRange.getBegin(), cast<CXXRecordDecl>(SrcRecord->getDecl())); @@ -558,17 +563,20 @@ CheckDynamicCast(Sema &Self, Expr *&SrcExpr, QualType DestType, /// const char *str = "literal"; /// legacy_function(const_cast\<char*\>(str)); void -CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, ExprValueKind &VK, +CheckConstCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK, const SourceRange &OpRange, const SourceRange &DestRange) { VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue) - Self.DefaultFunctionArrayLvalueConversion(SrcExpr); + if (VK == VK_RValue) { + SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); + if (SrcExpr.isInvalid()) // if conversion failed, don't report another error + return; + } unsigned msg = diag::err_bad_cxx_cast_generic; - if (TryConstCast(Self, SrcExpr, DestType, /*CStyle*/false, msg) != TC_Success + if (TryConstCast(Self, SrcExpr.get(), DestType, /*CStyle*/false, msg) != TC_Success && msg != 0) Self.Diag(OpRange.getBegin(), msg) << CT_Const - << SrcExpr->getType() << DestType << OpRange; + << SrcExpr.get()->getType() << DestType << OpRange; } /// CheckReinterpretCast - Check that a reinterpret_cast\<DestType\>(SrcExpr) is @@ -577,27 +585,32 @@ CheckConstCast(Sema &Self, Expr *&SrcExpr, QualType DestType, ExprValueKind &VK, /// like this: /// char *bytes = reinterpret_cast\<char*\>(int_ptr); void -CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, +CheckReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK, const SourceRange &OpRange, const SourceRange &DestRange, CastKind &Kind) { VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue) - Self.DefaultFunctionArrayLvalueConversion(SrcExpr); + if (VK == VK_RValue) { + SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); + if (SrcExpr.isInvalid()) // if conversion failed, don't report another error + return; + } unsigned msg = diag::err_bad_cxx_cast_generic; if (TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg, Kind) != TC_Success && msg != 0) { - if (SrcExpr->getType() == Self.Context.OverloadTy) { + if (SrcExpr.isInvalid()) // if conversion failed, don't report another error + return; + if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { //FIXME: &f<int>; is overloaded and resolvable Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_overload) - << OverloadExpr::find(SrcExpr).Expression->getName() + << OverloadExpr::find(SrcExpr.get()).Expression->getName() << DestType << OpRange; - Self.NoteAllOverloadCandidates(SrcExpr); + Self.NoteAllOverloadCandidates(SrcExpr.get()); } else { - diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr, DestType); + diagnoseBadCast(Self, msg, CT_Reinterpret, OpRange, SrcExpr.get(), DestType); } } } @@ -607,23 +620,25 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType, /// Refer to C++ 5.2.9 for details. Static casts are mostly used for making /// implicit conversions explicit and getting rid of data loss warnings. void -CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, +CheckStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ExprValueKind &VK, const SourceRange &OpRange, CastKind &Kind, CXXCastPath &BasePath) { // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (DestType->isVoidType()) { - Self.IgnoredValueConversions(SrcExpr); - if (SrcExpr->getType() == Self.Context.OverloadTy) { + SrcExpr = Self.IgnoredValueConversions(SrcExpr.take()); + if (SrcExpr.isInvalid()) // if conversion failed, don't report another error + return; + if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { ExprResult SingleFunctionExpression = - ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr, + Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr.get(), false, // Decay Function to ptr true, // Complain OpRange, DestType, diag::err_bad_static_cast_overload); if (SingleFunctionExpression.isUsable()) { - SrcExpr = SingleFunctionExpression.release(); + SrcExpr = SingleFunctionExpression; Kind = CK_ToVoid; } } @@ -633,29 +648,35 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, } VK = Expr::getValueKindForType(DestType); - if (VK == VK_RValue && !DestType->isRecordType()) - Self.DefaultFunctionArrayLvalueConversion(SrcExpr); + if (VK == VK_RValue && !DestType->isRecordType()) { + SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.take()); + if (SrcExpr.isInvalid()) // if conversion failed, don't report another error + return; + } unsigned msg = diag::err_bad_cxx_cast_generic; if (TryStaticCast(Self, SrcExpr, DestType, /*CStyle*/false, OpRange, msg, Kind, BasePath) != TC_Success && msg != 0) { - if (SrcExpr->getType() == Self.Context.OverloadTy) { - OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression; + if (SrcExpr.isInvalid()) + return; + if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { + OverloadExpr* oe = OverloadExpr::find(SrcExpr.get()).Expression; Self.Diag(OpRange.getBegin(), diag::err_bad_static_cast_overload) - << oe->getName() << DestType << OpRange << oe->getQualifierRange(); - Self.NoteAllOverloadCandidates(SrcExpr); + << oe->getName() << DestType << OpRange + << oe->getQualifierLoc().getSourceRange(); + Self.NoteAllOverloadCandidates(SrcExpr.get()); } else { - diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr, DestType); + diagnoseBadCast(Self, msg, CT_Static, OpRange, SrcExpr.get(), DestType); } } else if (Kind == CK_BitCast) - Self.CheckCastAlign(SrcExpr, DestType, OpRange); + Self.CheckCastAlign(SrcExpr.get(), DestType, OpRange); } /// TryStaticCast - Check if a static cast can be performed, and do so if /// possible. If @p CStyle, ignore access restrictions on hierarchy casting /// and casting away constness. -static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, +static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastKind &Kind, @@ -680,7 +701,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // C++ 5.2.9p5, reference downcast. // See the function for details. // DR 427 specifies that this is to be applied before paragraph 2. - tcr = TryStaticReferenceDowncast(Self, SrcExpr, DestType, CStyle, OpRange, + tcr = TryStaticReferenceDowncast(Self, SrcExpr.get(), DestType, CStyle, OpRange, msg, Kind, BasePath); if (tcr != TC_NotApplicable) return tcr; @@ -688,7 +709,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // C++0x [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2 // T2" if "cv2 T2" is reference-compatible with "cv1 T1". - tcr = TryLValueToRValueCast(Self, SrcExpr, DestType, CStyle, Kind, BasePath, + tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind, BasePath, msg); if (tcr != TC_NotApplicable) return tcr; @@ -697,6 +718,8 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // [...] if the declaration "T t(e);" is well-formed, [...]. tcr = TryStaticImplicitCast(Self, SrcExpr, DestType, CStyle, OpRange, msg, Kind); + if (SrcExpr.isInvalid()) + return TC_Failed; if (tcr != TC_NotApplicable) return tcr; @@ -708,7 +731,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // In the CStyle case, the earlier attempt to const_cast should have taken // care of reverse qualification conversions. - QualType SrcType = Self.Context.getCanonicalType(SrcExpr->getType()); + QualType SrcType = Self.Context.getCanonicalType(SrcExpr.get()->getType()); // C++0x 5.2.9p9: A value of a scoped enumeration type can be explicitly // converted to an integral type. [...] A value of a scoped enumeration type @@ -772,7 +795,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr, // This is definitely the intended conversion, but it might fail due // to a const violation. if (!CStyle && !DestPointee.isAtLeastAsQualifiedAs(SrcPointee)) { - msg = diag::err_bad_cxx_cast_const_away; + msg = diag::err_bad_cxx_cast_qualifiers_away; return TC_Failed; } Kind = CK_BitCast; @@ -963,7 +986,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, // Must preserve cv, as always, unless we're in C-style mode. if (!CStyle && !DestType.isAtLeastAsQualifiedAs(SrcType)) { - msg = diag::err_bad_cxx_cast_const_away; + msg = diag::err_bad_cxx_cast_qualifiers_away; return TC_Failed; } @@ -1038,7 +1061,7 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, /// where B is a base class of D [...]. /// TryCastResult -TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, +TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastKind &Kind, @@ -1049,9 +1072,9 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, bool WasOverloadedFunction = false; DeclAccessPair FoundOverload; - if (SrcExpr->getType() == Self.Context.OverloadTy) { + if (SrcExpr.get()->getType() == Self.Context.OverloadTy) { if (FunctionDecl *Fn - = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false, + = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(), DestType, false, FoundOverload)) { CXXMethodDecl *M = cast<CXXMethodDecl>(Fn); SrcType = Self.Context.getMemberPointerType(Fn->getType(), @@ -1122,7 +1145,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, if (WasOverloadedFunction) { // Resolve the address of the overloaded function again, this time // allowing complaints if something goes wrong. - FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr, + FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr.get(), DestType, true, FoundOverload); @@ -1132,7 +1155,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, } SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn); - if (!SrcExpr) { + if (!SrcExpr.isUsable()) { msg = 0; return TC_Failed; } @@ -1149,7 +1172,7 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, /// An expression e can be explicitly converted to a type T using a /// @c static_cast if the declaration "T t(e);" is well-formed [...]. TryCastResult -TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, +TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, CastKind &Kind) { if (DestType->isRecordType()) { @@ -1163,7 +1186,8 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, InitializedEntity Entity = InitializedEntity::InitializeTemporary(DestType); InitializationKind InitKind = InitializationKind::CreateCast(/*FIXME:*/OpRange, CStyle); - InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExpr, 1); + Expr *SrcExprRaw = SrcExpr.get(); + InitializationSequence InitSeq(Self, Entity, InitKind, &SrcExprRaw, 1); // At this point of CheckStaticCast, if the destination is a reference, // or the expression is an overload expression this has to work. @@ -1176,7 +1200,7 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, return TC_NotApplicable; ExprResult Result - = InitSeq.Perform(Self, Entity, InitKind, MultiExprArg(Self, &SrcExpr, 1)); + = InitSeq.Perform(Self, Entity, InitKind, MultiExprArg(Self, &SrcExprRaw, 1)); if (Result.isInvalid()) { msg = 0; return TC_Failed; @@ -1187,7 +1211,7 @@ TryStaticImplicitCast(Sema &Self, Expr *&SrcExpr, QualType DestType, else Kind = CK_NoOp; - SrcExpr = Result.takeAs<Expr>(); + SrcExpr = move(Result); return TC_Success; } @@ -1240,16 +1264,21 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, // Unwrap the pointers. Ignore qualifiers. Terminate early if the types are // completely equal. - // FIXME: const_cast should probably not be able to convert between pointers - // to different address spaces. // C++ 5.2.11p3 describes the core semantics of const_cast. All cv specifiers // in multi-level pointers may change, but the level count must be the same, // as must be the final pointee type. while (SrcType != DestType && Self.Context.UnwrapSimilarPointerTypes(SrcType, DestType)) { - Qualifiers Quals; - SrcType = Self.Context.getUnqualifiedArrayType(SrcType, Quals); - DestType = Self.Context.getUnqualifiedArrayType(DestType, Quals); + Qualifiers SrcQuals, DestQuals; + SrcType = Self.Context.getUnqualifiedArrayType(SrcType, SrcQuals); + DestType = Self.Context.getUnqualifiedArrayType(DestType, DestQuals); + + // const_cast is permitted to strip cvr-qualifiers, only. Make sure that + // the other qualifiers (e.g., address spaces) are identical. + SrcQuals.removeCVRQualifiers(); + DestQuals.removeCVRQualifiers(); + if (SrcQuals != DestQuals) + return TC_NotApplicable; } // Since we're dealing in canonical types, the remainder must be the same. @@ -1259,43 +1288,8 @@ static TryCastResult TryConstCast(Sema &Self, Expr *SrcExpr, QualType DestType, return TC_Success; } -// A helper function to resolve and fix an overloaded expression that -// can be resolved because it identifies a single function -// template specialization -// Last three arguments should only be supplied if Complain = true -static ExprResult ResolveAndFixSingleFunctionTemplateSpecialization( - Sema &Self, Expr *SrcExpr, - bool DoFunctionPointerConverion, - bool Complain, - const SourceRange& OpRangeForComplaining, - QualType DestTypeForComplaining, - unsigned DiagIDForComplaining) { - assert(SrcExpr->getType() == Self.Context.OverloadTy); - DeclAccessPair Found; - Expr* SingleFunctionExpression = 0; - if (FunctionDecl* Fn = Self.ResolveSingleFunctionTemplateSpecialization( - SrcExpr, false, // false -> Complain - &Found)) { - if (!Self.DiagnoseUseOfDecl(Fn, SrcExpr->getSourceRange().getBegin())) { - // mark the expression as resolved to Fn - SingleFunctionExpression = Self.FixOverloadedFunctionReference(SrcExpr, - Found, Fn); - - if (DoFunctionPointerConverion) - Self.DefaultFunctionArrayLvalueConversion(SingleFunctionExpression); - } - } - if (!SingleFunctionExpression && Complain) { - OverloadExpr* oe = OverloadExpr::find(SrcExpr).Expression; - Self.Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining) - << oe->getName() << DestTypeForComplaining << OpRangeForComplaining - << oe->getQualifierRange(); - Self.NoteAllOverloadCandidates(SrcExpr); - } - return SingleFunctionExpression; -} -static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, +static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg, @@ -1303,19 +1297,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, bool IsLValueCast = false; DestType = Self.Context.getCanonicalType(DestType); - QualType SrcType = SrcExpr->getType(); + QualType SrcType = SrcExpr.get()->getType(); // Is the source an overloaded name? (i.e. &foo) // If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ... if (SrcType == Self.Context.OverloadTy) { // ... unless foo<int> resolves to an lvalue unambiguously ExprResult SingleFunctionExpr = - ResolveAndFixSingleFunctionTemplateSpecialization(Self, SrcExpr, + Self.ResolveAndFixSingleFunctionTemplateSpecialization(SrcExpr.get(), Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr ); if (SingleFunctionExpr.isUsable()) { - SrcExpr = SingleFunctionExpr.release(); - SrcType = SrcExpr->getType(); + SrcExpr = move(SingleFunctionExpr); + SrcType = SrcExpr.get()->getType(); } else return TC_NotApplicable; @@ -1323,7 +1317,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) { bool LValue = DestTypeTmp->isLValueReferenceType(); - if (LValue && !SrcExpr->isLValue()) { + if (LValue && !SrcExpr.get()->isLValue()) { // Cannot cast non-lvalue to lvalue reference type. See the similar // comment in const_cast. msg = diag::err_bad_cxx_cast_rvalue; @@ -1333,6 +1327,23 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, // C++ 5.2.10p10: [...] a reference cast reinterpret_cast<T&>(x) has the // same effect as the conversion *reinterpret_cast<T*>(&x) with the // built-in & and * operators. + + const char *inappropriate = 0; + switch (SrcExpr.get()->getObjectKind()) { + case OK_Ordinary: + break; + case OK_BitField: inappropriate = "bit-field"; break; + case OK_VectorComponent: inappropriate = "vector element"; break; + case OK_ObjCProperty: inappropriate = "property expression"; break; + } + if (inappropriate) { + Self.Diag(OpRange.getBegin(), diag::err_bad_reinterpret_cast_reference) + << inappropriate << DestType + << OpRange << SrcExpr.get()->getSourceRange(); + msg = 0; SrcExpr = ExprError(); + return TC_NotApplicable; + } + // This code does this transformation for the checked types. DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType()); SrcType = Self.Context.getPointerType(SrcType); @@ -1359,7 +1370,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, // A reinterpret_cast followed by a const_cast can, though, so in C-style, // we accept it. if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) { - msg = diag::err_bad_cxx_cast_const_away; + msg = diag::err_bad_cxx_cast_qualifiers_away; return TC_Failed; } @@ -1472,7 +1483,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away constness. // The C-style cast operator can. if (!CStyle && CastsAwayConstness(Self, SrcType, DestType)) { - msg = diag::err_bad_cxx_cast_const_away; + msg = diag::err_bad_cxx_cast_qualifiers_away; return TC_Failed; } @@ -1525,39 +1536,39 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *&SrcExpr, return TC_Success; } -bool +ExprResult Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, - Expr *&CastExpr, CastKind &Kind, + Expr *CastExpr, CastKind &Kind, CXXCastPath &BasePath, bool FunctionalStyle) { - if (CastExpr->isBoundMemberFunction(Context)) - return Diag(CastExpr->getLocStart(), - diag::err_invalid_use_of_bound_member_func) - << CastExpr->getSourceRange(); - // This test is outside everything else because it's the only case where // a non-lvalue-reference target type does not lead to decay. // C++ 5.2.9p4: Any expression can be explicitly converted to type "cv void". if (CastTy->isVoidType()) { - IgnoredValueConversions(CastExpr); - bool ret = false; // false is 'able to convert' + Kind = CK_ToVoid; + + ExprResult CastExprRes = IgnoredValueConversions(CastExpr); + if (CastExprRes.isInvalid()) + return ExprError(); + CastExpr = CastExprRes.take(); + + if (CastExpr->getType() == Context.BoundMemberTy) + return CheckPlaceholderExpr(CastExpr); // will always fail + if (CastExpr->getType() == Context.OverloadTy) { ExprResult SingleFunctionExpr = - ResolveAndFixSingleFunctionTemplateSpecialization(*this, - CastExpr, - /* Decay Function to ptr */ false, - /* Complain */ true, - R, CastTy, diag::err_bad_cstyle_cast_overload); - if (SingleFunctionExpr.isUsable()) { - CastExpr = SingleFunctionExpr.release(); - Kind = CK_ToVoid; - } - else - ret = true; + ResolveAndFixSingleFunctionTemplateSpecialization( + CastExpr, /* Decay Function to ptr */ false, + /* Complain */ true, R, CastTy, + diag::err_bad_cstyle_cast_overload); + if (SingleFunctionExpr.isInvalid()) + return ExprError(); + CastExpr = SingleFunctionExpr.take(); } - else - Kind = CK_ToVoid; - return ret; + + assert(!CastExpr->getType()->isPlaceholderType()); + + return Owned(CastExpr); } // Make sure we determine the value kind before we bail out for @@ -1567,11 +1578,24 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, // If the type is dependent, we won't do any other semantic analysis now. if (CastTy->isDependentType() || CastExpr->isTypeDependent()) { Kind = CK_Dependent; - return false; + return Owned(CastExpr); + } + + if (VK == VK_RValue && !CastTy->isRecordType()) { + ExprResult CastExprRes = DefaultFunctionArrayLvalueConversion(CastExpr); + if (CastExprRes.isInvalid()) + return ExprError(); + CastExpr = CastExprRes.take(); } - if (VK == VK_RValue && !CastTy->isRecordType()) - DefaultFunctionArrayLvalueConversion(CastExpr); + // AltiVec vector initialization with a single literal. + if (const VectorType *vecTy = CastTy->getAs<VectorType>()) + if (vecTy->getVectorKind() == VectorType::AltiVecVector + && (CastExpr->getType()->isIntegerType() + || CastExpr->getType()->isFloatingType())) { + Kind = CK_VectorSplat; + return Owned(CastExpr); + } // C++ [expr.cast]p5: The conversions performed by // - a const_cast, @@ -1592,25 +1616,32 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, if (tcr == TC_NotApplicable) { // ... or if that is not possible, a static_cast, ignoring const, ... - tcr = TryStaticCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, Kind, - BasePath); + ExprResult CastExprRes = Owned(CastExpr); + tcr = TryStaticCast(*this, CastExprRes, CastTy, /*CStyle*/true, R, msg, + Kind, BasePath); + if (CastExprRes.isInvalid()) + return ExprError(); + CastExpr = CastExprRes.take(); if (tcr == TC_NotApplicable) { // ... and finally a reinterpret_cast, ignoring const. - tcr = TryReinterpretCast(*this, CastExpr, CastTy, /*CStyle*/true, R, msg, - Kind); + CastExprRes = Owned(CastExpr); + tcr = TryReinterpretCast(*this, CastExprRes, CastTy, /*CStyle*/true, R, + msg, Kind); + if (CastExprRes.isInvalid()) + return ExprError(); + CastExpr = CastExprRes.take(); } } if (tcr != TC_Success && msg != 0) { if (CastExpr->getType() == Context.OverloadTy) { DeclAccessPair Found; - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(CastExpr, + FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(CastExpr, CastTy, /* Complain */ true, Found); - assert(!Fn - && "cast failed but able to resolve overload expression!!"); + assert(!Fn && "cast failed but able to resolve overload expression!!"); (void)Fn; } else { @@ -1621,5 +1652,8 @@ Sema::CXXCheckCStyleCast(SourceRange R, QualType CastTy, ExprValueKind &VK, else if (Kind == CK_BitCast) CheckCastAlign(CastExpr, CastTy, R); - return tcr != TC_Success; + if (tcr != TC_Success) + return ExprError(); + + return Owned(CastExpr); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp index 7ad4b45..7049f6b 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -255,7 +255,7 @@ bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) { QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); if (T->isDependentType()) return true; - else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { + else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) { if (TD->getUnderlyingType()->isRecordType() || (Context.getLangOptions().CPlusPlus0x && TD->getUnderlyingType()->isEnumeralType())) @@ -549,7 +549,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, } else if (isa<RecordDecl>(SD)) { RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T); RecordTL.setNameLoc(IdentifierLoc); - } else if (isa<TypedefDecl>(SD)) { + } else if (isa<TypedefNameDecl>(SD)) { TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T); TypedefTL.setNameLoc(IdentifierLoc); } else if (isa<EnumDecl>(SD)) { @@ -641,20 +641,87 @@ bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, } bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, - ParsedType Type, + SourceLocation TemplateLoc, + CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation RAngleLoc, SourceLocation CCLoc, - CXXScopeSpec &SS) { + bool EnteringContext) { if (SS.isInvalid()) return true; - TypeSourceInfo *TSInfo; - QualType T = GetTypeFromParser(Type, &TSInfo); + // Translate the parser's template argument list in our AST format. + TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); + translateTemplateArguments(TemplateArgsIn, TemplateArgs); + + if (DependentTemplateName *DTN = Template.get().getAsDependentTemplateName()){ + // Handle a dependent template specialization for which we cannot resolve + // the template name. + assert(DTN->getQualifier() + == static_cast<NestedNameSpecifier*>(SS.getScopeRep())); + QualType T = Context.getDependentTemplateSpecializationType(ETK_None, + DTN->getQualifier(), + DTN->getIdentifier(), + TemplateArgs); + + // Create source-location information for this type. + TypeLocBuilder Builder; + DependentTemplateSpecializationTypeLoc SpecTL + = Builder.push<DependentTemplateSpecializationTypeLoc>(T); + SpecTL.setLAngleLoc(LAngleLoc); + SpecTL.setRAngleLoc(RAngleLoc); + SpecTL.setKeywordLoc(SourceLocation()); + SpecTL.setNameLoc(TemplateNameLoc); + SpecTL.setQualifierLoc(SS.getWithLocInContext(Context)); + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) + SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); + + SS.Extend(Context, TemplateLoc, Builder.getTypeLocInContext(Context, T), + CCLoc); + return false; + } + + + if (Template.get().getAsOverloadedTemplate() || + isa<FunctionTemplateDecl>(Template.get().getAsTemplateDecl())) { + SourceRange R(TemplateNameLoc, RAngleLoc); + if (SS.getRange().isValid()) + R.setBegin(SS.getRange().getBegin()); + + Diag(CCLoc, diag::err_non_type_template_in_nested_name_specifier) + << Template.get() << R; + NoteAllFoundTemplates(Template.get()); + return true; + } + + // We were able to resolve the template name to an actual template. + // Build an appropriate nested-name-specifier. + QualType T = CheckTemplateIdType(Template.get(), TemplateNameLoc, + TemplateArgs); if (T.isNull()) return true; - assert(TSInfo && "Not TypeSourceInfo in nested-name-specifier?"); - // FIXME: location of the 'template' keyword? - SS.Extend(Context, SourceLocation(), TSInfo->getTypeLoc(), CCLoc); + // FIXME: Template aliases will need to check the resulting type to make + // sure that it's either dependent or a tag type. + + // Provide source-location information for the template specialization + // type. + TypeLocBuilder Builder; + TemplateSpecializationTypeLoc SpecTL + = Builder.push<TemplateSpecializationTypeLoc>(T); + + SpecTL.setLAngleLoc(LAngleLoc); + SpecTL.setRAngleLoc(RAngleLoc); + SpecTL.setTemplateNameLoc(TemplateNameLoc); + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) + SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); + + + SS.Extend(Context, TemplateLoc, Builder.getTypeLocInContext(Context, T), + CCLoc); return false; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp index 3ffa748..5b645df 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -180,6 +180,7 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__sync_bool_compare_and_swap: case Builtin::BI__sync_lock_test_and_set: case Builtin::BI__sync_lock_release: + case Builtin::BI__sync_swap: return SemaBuiltinAtomicOverloaded(move(TheCallResult)); } @@ -313,9 +314,14 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { for (specific_attr_iterator<NonNullAttr> i = FDecl->specific_attr_begin<NonNullAttr>(), e = FDecl->specific_attr_end<NonNullAttr>(); i != e; ++i) { - CheckNonNullArguments(*i, TheCall); + CheckNonNullArguments(*i, TheCall->getArgs(), + TheCall->getCallee()->getLocStart()); } + // Memset handling + if (FnInfo->isStr("memset")) + CheckMemsetArguments(TheCall); + return false; } @@ -414,7 +420,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { BUILTIN_ROW(__sync_val_compare_and_swap), BUILTIN_ROW(__sync_bool_compare_and_swap), BUILTIN_ROW(__sync_lock_test_and_set), - BUILTIN_ROW(__sync_lock_release) + BUILTIN_ROW(__sync_lock_release), + BUILTIN_ROW(__sync_swap) }; #undef BUILTIN_ROW @@ -467,6 +474,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { NumFixed = 0; ResultType = Context.VoidTy; break; + case Builtin::BI__sync_swap: BuiltinIndex = 14; break; } // Now that we know how many fixed arguments we expect, first check that we @@ -491,14 +499,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // deduce the types of the rest of the arguments accordingly. Walk // the remaining arguments, converting them to the deduced value type. for (unsigned i = 0; i != NumFixed; ++i) { - Expr *Arg = TheCall->getArg(i+1); + ExprResult Arg = TheCall->getArg(i+1); // If the argument is an implicit cast, then there was a promotion due to // "...", just remove it now. - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg.get())) { Arg = ICE->getSubExpr(); ICE->setSubExpr(0); - TheCall->setArg(i+1, Arg); + TheCall->setArg(i+1, Arg.get()); } // GCC does an implicit conversion to the pointer or integer ValType. This @@ -506,7 +514,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { CastKind Kind = CK_Invalid; ExprValueKind VK = VK_RValue; CXXCastPath BasePath; - if (CheckCastTypes(Arg->getSourceRange(), ValType, Arg, Kind, VK, BasePath)) + Arg = CheckCastTypes(Arg.get()->getSourceRange(), ValType, Arg.take(), Kind, VK, BasePath); + if (Arg.isInvalid()) return ExprError(); // Okay, we have something that *can* be converted to the right type. Check @@ -515,8 +524,8 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // pass in 42. The 42 gets converted to char. This is even more strange // for things like 45.123 -> char, etc. // FIXME: Do this check. - ImpCastExprToType(Arg, ValType, Kind, VK, &BasePath); - TheCall->setArg(i+1, Arg); + Arg = ImpCastExprToType(Arg.take(), ValType, Kind, VK, &BasePath); + TheCall->setArg(i+1, Arg.get()); } // Switch the DeclRefExpr to refer to the new decl. @@ -525,9 +534,10 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // Set the callee in the CallExpr. // FIXME: This leaks the original parens and implicit casts. - Expr *PromotedCall = DRE; - UsualUnaryConversions(PromotedCall); - TheCall->setCallee(PromotedCall); + ExprResult PromotedCall = UsualUnaryConversions(DRE); + if (PromotedCall.isInvalid()) + return ExprError(); + TheCall->setCallee(PromotedCall.take()); // Change the result type of the call to match the original value type. This // is arbitrary, but the codegen for these builtins ins design to handle it @@ -552,12 +562,6 @@ bool Sema::CheckObjCString(Expr *Arg) { return true; } - size_t NulPos = Literal->getString().find('\0'); - if (NulPos != llvm::StringRef::npos) { - Diag(getLocationOfStringLiteralByte(Literal, NulPos), - diag::warn_cfstring_literal_contains_nul_character) - << Arg->getSourceRange(); - } if (Literal->containsNonAsciiOrNull()) { llvm::StringRef String = Literal->getString(); unsigned NumBytes = String.size(); @@ -650,29 +654,31 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { << SourceRange(TheCall->getArg(2)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); - Expr *OrigArg0 = TheCall->getArg(0); - Expr *OrigArg1 = TheCall->getArg(1); + ExprResult OrigArg0 = TheCall->getArg(0); + ExprResult OrigArg1 = TheCall->getArg(1); // Do standard promotions between the two arguments, returning their common // type. QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false); + if (OrigArg0.isInvalid() || OrigArg1.isInvalid()) + return true; // Make sure any conversions are pushed back into the call; this is // type safe since unordered compare builtins are declared as "_Bool // foo(...)". - TheCall->setArg(0, OrigArg0); - TheCall->setArg(1, OrigArg1); + TheCall->setArg(0, OrigArg0.get()); + TheCall->setArg(1, OrigArg1.get()); - if (OrigArg0->isTypeDependent() || OrigArg1->isTypeDependent()) + if (OrigArg0.get()->isTypeDependent() || OrigArg1.get()->isTypeDependent()) return false; // If the common type isn't a real floating type, then the arguments were // invalid for this operation. if (!Res->isRealFloatingType()) - return Diag(OrigArg0->getLocStart(), + return Diag(OrigArg0.get()->getLocStart(), diag::err_typecheck_call_invalid_ordered_compare) - << OrigArg0->getType() << OrigArg1->getType() - << SourceRange(OrigArg0->getLocStart(), OrigArg1->getLocEnd()); + << OrigArg0.get()->getType() << OrigArg1.get()->getType() + << SourceRange(OrigArg0.get()->getLocStart(), OrigArg1.get()->getLocEnd()); return false; } @@ -860,7 +866,7 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, /// SemaBuiltinObjectSize - Handle __builtin_object_size(void *ptr, /// int type). This simply type checks that type is one of the defined /// constants (0-3). -// For compatability check 0-3, llvm only handles 0 and 2. +// For compatibility check 0-3, llvm only handles 0 and 2. bool Sema::SemaBuiltinObjectSize(CallExpr *TheCall) { llvm::APSInt Result; @@ -903,6 +909,8 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, if (E->isTypeDependent() || E->isValueDependent()) return false; + E = E->IgnoreParens(); + switch (E->getStmtClass()) { case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { @@ -925,11 +933,6 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, goto tryAgain; } - case Stmt::ParenExprClass: { - E = cast<ParenExpr>(E)->getSubExpr(); - goto tryAgain; - } - case Stmt::OpaqueValueExprClass: if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) { E = src; @@ -1036,15 +1039,15 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall, void Sema::CheckNonNullArguments(const NonNullAttr *NonNull, - const CallExpr *TheCall) { + const Expr * const *ExprArgs, + SourceLocation CallSiteLoc) { for (NonNullAttr::args_iterator i = NonNull->args_begin(), e = NonNull->args_end(); i != e; ++i) { - const Expr *ArgExpr = TheCall->getArg(*i); + const Expr *ArgExpr = ExprArgs[*i]; if (ArgExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) - Diag(TheCall->getCallee()->getLocStart(), diag::warn_null_arg) - << ArgExpr->getSourceRange(); + Diag(CallSiteLoc, diag::warn_null_arg) << ArgExpr->getSourceRange(); } } @@ -1218,10 +1221,12 @@ void CheckFormatHandler::HandleZeroPosition(const char *startPos, } void CheckFormatHandler::HandleNullChar(const char *nullCharacter) { - // The presence of a null character is likely an error. - S.Diag(getLocationOfByte(nullCharacter), - diag::warn_printf_format_string_contains_null_char) - << getFormatStringRange(); + if (!IsObjCLiteral) { + // The presence of a null character is likely an error. + S.Diag(getLocationOfByte(nullCharacter), + diag::warn_printf_format_string_contains_null_char) + << getFormatStringRange(); + } } const Expr *CheckFormatHandler::getDataArg(unsigned i) const { @@ -1825,6 +1830,54 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, } } +//===--- CHECK: Standard memory functions ---------------------------------===// + +/// \brief Check for dangerous or invalid arguments to memset(). +/// +/// This issues warnings on known problematic or dangerous or unspecified +/// arguments to the standard 'memset' function call. +/// +/// \param Call The call expression to diagnose. +void Sema::CheckMemsetArguments(const CallExpr *Call) { + // It is possible to have a non-standard definition of memset. Validate + // we have the proper number of arguments, and if not, abort further + // checking. + if (Call->getNumArgs() != 3) + return; + + const Expr *Dest = Call->getArg(0)->IgnoreParenImpCasts(); + + // The type checking for this warning is moderately expensive, only do it + // when enabled. + if (getDiagnostics().getDiagnosticLevel(diag::warn_non_pod_memset, + Dest->getExprLoc()) == + Diagnostic::Ignored) + return; + + QualType DestTy = Dest->getType(); + if (const PointerType *DestPtrTy = DestTy->getAs<PointerType>()) { + QualType PointeeTy = DestPtrTy->getPointeeType(); + if (PointeeTy->isVoidType()) + return; + + // Check the C++11 POD definition regardless of language mode; it is more + // relaxed than earlier definitions and we don't want spurrious warnings. + if (PointeeTy->isCXX11PODType()) + return; + + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::warn_non_pod_memset) + << PointeeTy << Call->getCallee()->getSourceRange()); + + SourceRange ArgRange = Call->getArg(0)->getSourceRange(); + DiagRuntimeBehavior( + Dest->getExprLoc(), Dest, + PDiag(diag::note_non_pod_memset_silence) + << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); + } +} + //===--- CHECK: Return Address of Stack Variable --------------------------===// static Expr *EvalVal(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars); @@ -1928,14 +1981,12 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) { E->getType()->isObjCQualifiedIdType()) && "EvalAddr only works on pointers"); + E = E->IgnoreParens(); + // Our "symbolic interpreter" is just a dispatch off the currently // viewed AST node. We then recursively traverse the AST by calling // EvalAddr and EvalVal appropriately. switch (E->getStmtClass()) { - case Stmt::ParenExprClass: - // Ignore parentheses. - return EvalAddr(cast<ParenExpr>(E)->getSubExpr(), refVars); - case Stmt::DeclRefExprClass: { DeclRefExpr *DR = cast<DeclRefExpr>(E); @@ -2065,6 +2116,8 @@ do { // Our "symbolic interpreter" is just a dispatch off the currently // viewed AST node. We then recursively traverse the AST by calling // EvalAddr and EvalVal appropriately. + + E = E->IgnoreParens(); switch (E->getStmtClass()) { case Stmt::ImplicitCastExprClass: { ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E); @@ -2098,12 +2151,6 @@ do { return NULL; } - case Stmt::ParenExprClass: { - // Ignore parentheses. - E = cast<ParenExpr>(E)->getSubExpr(); - continue; - } - case Stmt::UnaryOperatorClass: { // The only unary operator that make sense to handle here // is Deref. All others don't resolve to a "name." This includes @@ -2782,10 +2829,48 @@ void AnalyzeAssignment(Sema &S, BinaryOperator *E) { } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. +void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, + SourceLocation CContext, unsigned diag) { + S.Diag(E->getExprLoc(), diag) + << SourceType << T << E->getSourceRange() << SourceRange(CContext); +} + +/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext, unsigned diag) { - S.Diag(E->getExprLoc(), diag) - << E->getType() << T << E->getSourceRange() << SourceRange(CContext); + DiagnoseImpCast(S, E, E->getType(), T, CContext, diag); +} + +/// Diagnose an implicit cast from a literal expression. Also attemps to supply +/// fixit hints when the cast wouldn't lose information to simply write the +/// expression with the expected type. +void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T, + SourceLocation CContext) { + // Emit the primary warning first, then try to emit a fixit hint note if + // reasonable. + S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer) + << FL->getType() << T << FL->getSourceRange() << SourceRange(CContext); + + const llvm::APFloat &Value = FL->getValue(); + + // Don't attempt to fix PPC double double literals. + if (&Value.getSemantics() == &llvm::APFloat::PPCDoubleDouble) + return; + + // Try to convert this exactly to an 64-bit integer. FIXME: It would be + // nice to support arbitrarily large integers here. + bool isExact = false; + uint64_t IntegerPart; + if (Value.convertToInteger(&IntegerPart, 64, /*isSigned=*/true, + llvm::APFloat::rmTowardZero, &isExact) + != llvm::APFloat::opOK || !isExact) + return; + + llvm::APInt IntegerValue(64, IntegerPart, /*isSigned=*/true); + + std::string LiteralValue = IntegerValue.toString(10, /*isSigned=*/true); + S.Diag(FL->getExprLoc(), diag::note_fix_integral_float_as_integer) + << FixItHint::CreateReplacement(FL->getSourceRange(), LiteralValue); } std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { @@ -2797,6 +2882,11 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { return ValueInRange.toString(10); } +static bool isFromSystemMacro(Sema &S, SourceLocation loc) { + SourceManager &smgr = S.Context.getSourceManager(); + return loc.isMacroID() && smgr.isInSystemHeader(smgr.getSpellingLoc(loc)); +} + void CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, bool *ICContext = 0) { if (E->isTypeDependent() || E->isValueDependent()) return; @@ -2806,11 +2896,12 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if (Source == Target) return; if (Target->isDependentType()) return; - // If the conversion context location is invalid or instantiated - // from a system macro, don't complain. - if (CC.isInvalid() || - (CC.isMacroID() && S.Context.getSourceManager().isInSystemHeader( - S.Context.getSourceManager().getSpellingLoc(CC)))) + // If the conversion context location is invalid don't complain. + // We also don't want to emit a warning if the issue occurs from the + // instantiation of a system macro. The problem is that 'getSpellingLoc()' + // is slow, so we delay this check as long as possible. Once we detect + // we are in that scenario, we just return. + if (CC.isInvalid()) return; // Never diagnose implicit casts to bool. @@ -2819,8 +2910,11 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // Strip vector types. if (isa<VectorType>(Source)) { - if (!isa<VectorType>(Target)) + if (!isa<VectorType>(Target)) { + if (isFromSystemMacro(S, CC)) + return; return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar); + } Source = cast<VectorType>(Source)->getElementType().getTypePtr(); Target = cast<VectorType>(Target)->getElementType().getTypePtr(); @@ -2828,8 +2922,12 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // Strip complex types. if (isa<ComplexType>(Source)) { - if (!isa<ComplexType>(Target)) + if (!isa<ComplexType>(Target)) { + if (isFromSystemMacro(S, CC)) + return; + return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_complex_scalar); + } Source = cast<ComplexType>(Source)->getElementType().getTypePtr(); Target = cast<ComplexType>(Target)->getElementType().getTypePtr(); @@ -2857,17 +2955,22 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; } + if (isFromSystemMacro(S, CC)) + return; + DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision); } return; } - // If the target is integral, always warn. + // If the target is integral, always warn. if ((TargetBT && TargetBT->isInteger())) { + if (isFromSystemMacro(S, CC)) + return; + Expr *InnerE = E->IgnoreParenImpCasts(); - if (FloatingLiteral *LiteralExpr = dyn_cast<FloatingLiteral>(InnerE)) { - DiagnoseImpCast(S, LiteralExpr, T, CC, - diag::warn_impcast_literal_float_to_integer); + if (FloatingLiteral *FL = dyn_cast<FloatingLiteral>(InnerE)) { + DiagnoseFloatingLiteralImpCast(S, FL, T, CC); } else { DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_integer); } @@ -2887,6 +2990,9 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // TODO: this should happen for bitfield stores, too. llvm::APSInt Value(32); if (E->isIntegerConstantExpr(Value, S.Context)) { + if (isFromSystemMacro(S, CC)) + return; + std::string PrettySourceValue = Value.toString(10); std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); @@ -2898,6 +3004,10 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // People want to build with -Wshorten-64-to-32 and not -Wconversion // and by god we'll let them. + + if (isFromSystemMacro(S, CC)) + return; + if (SourceRange.Width == 64 && TargetRange.Width == 32) return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_64_32); return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision); @@ -2906,6 +3016,10 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, if ((TargetRange.NonNegative && !SourceRange.NonNegative) || (!TargetRange.NonNegative && SourceRange.NonNegative && SourceRange.Width == TargetRange.Width)) { + + if (isFromSystemMacro(S, CC)) + return; + unsigned DiagID = diag::warn_impcast_integer_sign; // Traditionally, gcc has warned about this under -Wsign-compare. @@ -2922,15 +3036,31 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } // Diagnose conversions between different enumeration types. + // In C, we pretend that the type of an EnumConstantDecl is its enumeration + // type, to give us better diagnostics. + QualType SourceType = E->getType(); + if (!S.getLangOptions().CPlusPlus) { + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + if (EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(DRE->getDecl())) { + EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext()); + SourceType = S.Context.getTypeDeclType(Enum); + Source = S.Context.getCanonicalType(SourceType).getTypePtr(); + } + } + if (const EnumType *SourceEnum = Source->getAs<EnumType>()) if (const EnumType *TargetEnum = Target->getAs<EnumType>()) if ((SourceEnum->getDecl()->getIdentifier() || - SourceEnum->getDecl()->getTypedefForAnonDecl()) && + SourceEnum->getDecl()->getTypedefNameForAnonDecl()) && (TargetEnum->getDecl()->getIdentifier() || - TargetEnum->getDecl()->getTypedefForAnonDecl()) && - SourceEnum != TargetEnum) - return DiagnoseImpCast(S, E, T, CC, + TargetEnum->getDecl()->getTypedefNameForAnonDecl()) && + SourceEnum != TargetEnum) { + if (isFromSystemMacro(S, CC)) + return; + + return DiagnoseImpCast(S, E, SourceType, T, CC, diag::warn_impcast_different_enum_types); + } return; } @@ -3039,7 +3169,7 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { if (isa<StmtExpr>(E)) return; // Don't descend into unevaluated contexts. - if (isa<SizeOfAlignOfExpr>(E)) return; + if (isa<UnaryExprOrTypeTraitExpr>(E)) return; // Now just recurse over the expression's children. CC = E->getExprLoc(); @@ -3169,10 +3299,11 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { << TRange << Op->getSourceRange(); } -void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) { +static void CheckArrayAccess_Check(Sema &S, + const clang::ArraySubscriptExpr *E) { const Expr *BaseExpr = E->getBase()->IgnoreParenImpCasts(); const ConstantArrayType *ArrayTy = - Context.getAsConstantArrayType(BaseExpr->getType()); + S.Context.getAsConstantArrayType(BaseExpr->getType()); if (!ArrayTy) return; @@ -3180,7 +3311,7 @@ void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) { if (IndexExpr->isValueDependent()) return; llvm::APSInt index; - if (!IndexExpr->isIntegerConstantExpr(index, Context)) + if (!IndexExpr->isIntegerConstantExpr(index, S.Context)) return; if (index.isUnsigned() || !index.isNegative()) { @@ -3195,15 +3326,16 @@ void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) { if (index.slt(size)) return; - DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr, - PDiag(diag::warn_array_index_exceeds_bounds) - << index.toString(10, true) << size.toString(10, true) - << IndexExpr->getSourceRange()); + S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr, + S.PDiag(diag::warn_array_index_exceeds_bounds) + << index.toString(10, true) + << size.toString(10, true) + << IndexExpr->getSourceRange()); } else { - DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr, - PDiag(diag::warn_array_index_precedes_bounds) - << index.toString(10, true) - << IndexExpr->getSourceRange()); + S.DiagRuntimeBehavior(E->getBase()->getLocStart(), BaseExpr, + S.PDiag(diag::warn_array_index_precedes_bounds) + << index.toString(10, true) + << IndexExpr->getSourceRange()); } const NamedDecl *ND = NULL; @@ -3212,8 +3344,28 @@ void Sema::CheckArrayAccess(const clang::ArraySubscriptExpr *E) { if (const MemberExpr *ME = dyn_cast<MemberExpr>(BaseExpr)) ND = dyn_cast<NamedDecl>(ME->getMemberDecl()); if (ND) - DiagRuntimeBehavior(ND->getLocStart(), BaseExpr, - PDiag(diag::note_array_index_out_of_bounds) - << ND->getDeclName()); + S.DiagRuntimeBehavior(ND->getLocStart(), BaseExpr, + S.PDiag(diag::note_array_index_out_of_bounds) + << ND->getDeclName()); } +void Sema::CheckArrayAccess(const Expr *expr) { + while (true) { + expr = expr->IgnoreParens(); + switch (expr->getStmtClass()) { + case Stmt::ArraySubscriptExprClass: + CheckArrayAccess_Check(*this, cast<ArraySubscriptExpr>(expr)); + return; + case Stmt::ConditionalOperatorClass: { + const ConditionalOperator *cond = cast<ConditionalOperator>(expr); + if (const Expr *lhs = cond->getLHS()) + CheckArrayAccess(lhs); + if (const Expr *rhs = cond->getRHS()) + CheckArrayAccess(rhs); + return; + } + default: + return; + } + } +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp index bab665a..cc8726d 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp @@ -667,8 +667,39 @@ QualType clang::getDeclUsageType(ASTContext &C, NamedDecl *ND) { T = Value->getType(); else return QualType(); - - return T.getNonReferenceType(); + + // Dig through references, function pointers, and block pointers to + // get down to the likely type of an expression when the entity is + // used. + do { + if (const ReferenceType *Ref = T->getAs<ReferenceType>()) { + T = Ref->getPointeeType(); + continue; + } + + if (const PointerType *Pointer = T->getAs<PointerType>()) { + if (Pointer->getPointeeType()->isFunctionType()) { + T = Pointer->getPointeeType(); + continue; + } + + break; + } + + if (const BlockPointerType *Block = T->getAs<BlockPointerType>()) { + T = Block->getPointeeType(); + continue; + } + + if (const FunctionType *Function = T->getAs<FunctionType>()) { + T = Function->getResultType(); + continue; + } + + break; + } while (true); + + return T; } void ResultBuilder::AdjustResultPriorityForDecl(Result &R) { @@ -1482,7 +1513,8 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, case Sema::PCC_Statement: { AddTypedefResult(Results); - if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns()) { + if (SemaRef.getLangOptions().CPlusPlus && Results.includeCodePatterns() && + SemaRef.getLangOptions().CXXExceptions) { Builder.AddTypedTextChunk("try"); Builder.AddChunk(CodeCompletionString::CK_LeftBrace); Builder.AddPlaceholderChunk("statements"); @@ -1655,15 +1687,17 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Results.AddResult(Result("true")); Results.AddResult(Result("false")); - // dynamic_cast < type-id > ( expression ) - Builder.AddTypedTextChunk("dynamic_cast"); - Builder.AddChunk(CodeCompletionString::CK_LeftAngle); - Builder.AddPlaceholderChunk("type"); - Builder.AddChunk(CodeCompletionString::CK_RightAngle); - Builder.AddChunk(CodeCompletionString::CK_LeftParen); - Builder.AddPlaceholderChunk("expression"); - Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Builder.TakeString())); + if (SemaRef.getLangOptions().RTTI) { + // dynamic_cast < type-id > ( expression ) + Builder.AddTypedTextChunk("dynamic_cast"); + Builder.AddChunk(CodeCompletionString::CK_LeftAngle); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_RightAngle); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); + } // static_cast < type-id > ( expression ) Builder.AddTypedTextChunk("static_cast"); @@ -1695,13 +1729,15 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddChunk(CodeCompletionString::CK_RightParen); Results.AddResult(Result(Builder.TakeString())); - // typeid ( expression-or-type ) - Builder.AddTypedTextChunk("typeid"); - Builder.AddChunk(CodeCompletionString::CK_LeftParen); - Builder.AddPlaceholderChunk("expression-or-type"); - Builder.AddChunk(CodeCompletionString::CK_RightParen); - Results.AddResult(Result(Builder.TakeString())); - + if (SemaRef.getLangOptions().RTTI) { + // typeid ( expression-or-type ) + Builder.AddTypedTextChunk("typeid"); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + Builder.AddPlaceholderChunk("expression-or-type"); + Builder.AddChunk(CodeCompletionString::CK_RightParen); + Results.AddResult(Result(Builder.TakeString())); + } + // new T ( ... ) Builder.AddTypedTextChunk("new"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); @@ -1738,11 +1774,13 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Builder.AddPlaceholderChunk("expression"); Results.AddResult(Result(Builder.TakeString())); - // throw expression - Builder.AddTypedTextChunk("throw"); - Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); - Builder.AddPlaceholderChunk("expression"); - Results.AddResult(Result(Builder.TakeString())); + if (SemaRef.getLangOptions().CXXExceptions) { + // throw expression + Builder.AddTypedTextChunk("throw"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("expression"); + Results.AddResult(Result(Builder.TakeString())); + } // FIXME: Rethrow? } @@ -1785,9 +1823,9 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, /// /// This routine provides a fast path where we provide constant strings for /// common type names. -const char *GetCompletionTypeString(QualType T, - ASTContext &Context, - CodeCompletionAllocator &Allocator) { +static const char *GetCompletionTypeString(QualType T, + ASTContext &Context, + CodeCompletionAllocator &Allocator) { PrintingPolicy Policy(Context.PrintingPolicy); Policy.AnonymousTagLocations = false; @@ -1799,7 +1837,7 @@ const char *GetCompletionTypeString(QualType T, // Anonymous tag types are constant strings. if (const TagType *TagT = dyn_cast<TagType>(T)) if (TagDecl *Tag = TagT->getDecl()) - if (!Tag->getIdentifier() && !Tag->getTypedefForAnonDecl()) { + if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) { switch (Tag->getTagKind()) { case TTK_Struct: return "struct <anonymous>"; case TTK_Class: return "class <anonymous>"; @@ -1902,7 +1940,7 @@ static std::string FormatFunctionParameter(ASTContext &Context, // Look through typedefs. if (TypedefTypeLoc *TypedefTL = dyn_cast<TypedefTypeLoc>(&TL)) { if (TypeSourceInfo *InnerTSInfo - = TypedefTL->getTypedefDecl()->getTypeSourceInfo()) { + = TypedefTL->getTypedefNameDecl()->getTypeSourceInfo()) { TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc(); continue; } @@ -2602,6 +2640,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) { case Decl::ObjCProtocol: return CXCursor_ObjCProtocolDecl; case Decl::ParmVar: return CXCursor_ParmDecl; case Decl::Typedef: return CXCursor_TypedefDecl; + case Decl::TypeAlias: return CXCursor_TypeAliasDecl; case Decl::Var: return CXCursor_VarDecl; case Decl::Namespace: return CXCursor_Namespace; case Decl::NamespaceAlias: return CXCursor_NamespaceAlias; @@ -4816,8 +4855,12 @@ void Sema::CodeCompleteObjCInstanceMessage(Scope *S, ExprTy *Receiver, // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. - if (RecExpr) - DefaultFunctionArrayLvalueConversion(RecExpr); + if (RecExpr) { + ExprResult Conv = DefaultFunctionArrayLvalueConversion(RecExpr); + if (Conv.isInvalid()) // conversion failed. bail. + return; + RecExpr = Conv.take(); + } QualType ReceiverType = RecExpr? RecExpr->getType() : Super? Context.getObjCObjectPointerType( Context.getObjCInterfaceType(Super)) @@ -5327,16 +5370,65 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, Class = cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl() ->getClassInterface(); + // Determine the type of the property we're synthesizing. + QualType PropertyType = Context.getObjCIdType(); + if (Class) { + if (ObjCPropertyDecl *Property + = Class->FindPropertyDeclaration(PropertyName)) { + PropertyType + = Property->getType().getNonReferenceType().getUnqualifiedType(); + + // Give preference to ivars + Results.setPreferredType(PropertyType); + } + } + // Add all of the instance variables in this class and its superclasses. Results.EnterNewScope(); + bool SawSimilarlyNamedIvar = false; + std::string NameWithPrefix; + NameWithPrefix += '_'; + NameWithPrefix += PropertyName->getName().str(); + std::string NameWithSuffix = PropertyName->getName().str(); + NameWithSuffix += '_'; for(; Class; Class = Class->getSuperClass()) { - // FIXME: We could screen the type of each ivar for compatibility with - // the property, but is that being too paternal? - for (ObjCInterfaceDecl::ivar_iterator IVar = Class->ivar_begin(), - IVarEnd = Class->ivar_end(); - IVar != IVarEnd; ++IVar) - Results.AddResult(Result(*IVar, 0), CurContext, 0, false); + for (ObjCIvarDecl *Ivar = Class->all_declared_ivar_begin(); Ivar; + Ivar = Ivar->getNextIvar()) { + Results.AddResult(Result(Ivar, 0), CurContext, 0, false); + + // Determine whether we've seen an ivar with a name similar to the + // property. + if ((PropertyName == Ivar->getIdentifier() || + NameWithPrefix == Ivar->getName() || + NameWithSuffix == Ivar->getName())) { + SawSimilarlyNamedIvar = true; + + // Reduce the priority of this result by one, to give it a slight + // advantage over other results whose names don't match so closely. + if (Results.size() && + Results.data()[Results.size() - 1].Kind + == CodeCompletionResult::RK_Declaration && + Results.data()[Results.size() - 1].Declaration == Ivar) + Results.data()[Results.size() - 1].Priority--; + } + } + } + + if (!SawSimilarlyNamedIvar) { + // Create ivar result _propName, that the user can use to synthesize + // an ivar of the appropriate type. + unsigned Priority = CCP_MemberDeclaration + 1; + typedef CodeCompletionResult Result; + CodeCompletionAllocator &Allocator = Results.getAllocator(); + CodeCompletionBuilder Builder(Allocator, Priority,CXAvailability_Available); + + Builder.AddResultTypeChunk(GetCompletionTypeString(PropertyType, Context, + Allocator)); + Builder.AddTypedTextChunk(Allocator.CopyString(NameWithPrefix)); + Results.AddResult(Result(Builder.TakeString(), Priority, + CXCursor_ObjCIvarDecl)); } + Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp index d6efd7a..7214988 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp @@ -17,6 +17,7 @@ #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "TypeLocBuilder.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -24,6 +25,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/CharUnits.h" @@ -61,7 +63,8 @@ Sema::DeclGroupPtrTy Sema::ConvertDeclToDeclGroup(Decl *Ptr) { ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS, bool isClassName, bool HasTrailingDot, - ParsedType ObjectTypePtr) { + ParsedType ObjectTypePtr, + bool WantNontrivialTypeSourceInfo) { // Determine where we will perform name lookup. DeclContext *LookupCtx = 0; if (ObjectTypePtr) { @@ -87,10 +90,15 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, // We know from the grammar that this name refers to a type, // so build a dependent node to describe the type. + if (WantNontrivialTypeSourceInfo) + return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get(); + + NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context); QualType T = - CheckTypenameType(ETK_None, SS->getScopeRep(), II, - SourceLocation(), SS->getRange(), NameLoc); - return ParsedType::make(T); + CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc, + II, NameLoc); + + return ParsedType::make(T); } return ParsedType(); @@ -189,10 +197,23 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, if (T.isNull()) T = Context.getTypeDeclType(TD); - if (SS) - T = getElaboratedType(ETK_None, *SS, T); - + if (SS && SS->isNotEmpty()) { + if (WantNontrivialTypeSourceInfo) { + // Construct a type with type-source information. + TypeLocBuilder Builder; + Builder.pushTypeSpec(T).setNameLoc(NameLoc); + + T = getElaboratedType(ETK_None, *SS, T); + ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T); + ElabTL.setKeywordLoc(SourceLocation()); + ElabTL.setQualifierLoc(SS->getWithLocInContext(Context)); + return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); + } else { + T = getElaboratedType(ETK_None, *SS, T); + } + } } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { + (void)DiagnoseUseOfDecl(IDecl, NameLoc); if (!HasTrailingDot) T = Context.getObjCInterfaceType(IDecl); } @@ -229,6 +250,33 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { return DeclSpec::TST_unspecified; } +/// isMicrosoftMissingTypename - In Microsoft mode, within class scope, +/// if a CXXScopeSpec's type is equal to the type of one of the base classes +/// then downgrade the missing typename error to a warning. +/// This is needed for MSVC compatibility; Example: +/// @code +/// template<class T> class A { +/// public: +/// typedef int TYPE; +/// }; +/// template<class T> class B : public A<T> { +/// public: +/// A<T>::TYPE a; // no typename required because A<T> is a base class. +/// }; +/// @endcode +bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS) { + if (CurContext->isRecord()) { + const Type *Ty = SS->getScopeRep()->getAsType(); + + CXXRecordDecl *RD = cast<CXXRecordDecl>(CurContext); + for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(), + BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) + if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base->getType())) + return true; + } + return false; +} + bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, @@ -263,7 +311,9 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, Diag(Result->getLocation(), diag::note_previous_decl) << Result->getDeclName(); - SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS); + SuggestedType = getTypeName(*Result->getIdentifier(), IILoc, S, SS, + false, false, ParsedType(), + /*NonTrivialTypeSourceInfo=*/true); return true; } } else if (Lookup.empty()) { @@ -304,7 +354,11 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, Diag(IILoc, diag::err_typename_nested_not_found) << &II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { - Diag(SS->getRange().getBegin(), diag::err_typename_missing) + unsigned DiagID = diag::err_typename_missing; + if (getLangOptions().Microsoft && isMicrosoftMissingTypename(SS)) + DiagID = diag::warn_typename_missing; + + Diag(SS->getRange().getBegin(), DiagID) << (NestedNameSpecifier *)SS->getScopeRep() << II.getName() << SourceRange(SS->getRange().getBegin(), IILoc) << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename "); @@ -317,6 +371,328 @@ bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II, return true; } +/// \brief Determine whether the given result set contains either a type name +/// or +static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) { + bool CheckTemplate = R.getSema().getLangOptions().CPlusPlus && + NextToken.is(tok::less); + + for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) { + if (isa<TypeDecl>(*I) || isa<ObjCInterfaceDecl>(*I)) + return true; + + if (CheckTemplate && isa<TemplateDecl>(*I)) + return true; + } + + return false; +} + +Sema::NameClassification Sema::ClassifyName(Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *&Name, + SourceLocation NameLoc, + const Token &NextToken) { + DeclarationNameInfo NameInfo(Name, NameLoc); + ObjCMethodDecl *CurMethod = getCurMethodDecl(); + + if (NextToken.is(tok::coloncolon)) { + BuildCXXNestedNameSpecifier(S, *Name, NameLoc, NextToken.getLocation(), + QualType(), false, SS, 0, false); + + } + + LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); + LookupParsedName(Result, S, &SS, !CurMethod); + + // Perform lookup for Objective-C instance variables (including automatically + // synthesized instance variables), if we're in an Objective-C method. + // FIXME: This lookup really, really needs to be folded in to the normal + // unqualified lookup mechanism. + if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) { + ExprResult E = LookupInObjCMethod(Result, S, Name, true); + if (E.get() || E.isInvalid()) + return E; + + // Synthesize ivars lazily. + if (getLangOptions().ObjCDefaultSynthProperties && + getLangOptions().ObjCNonFragileABI2) { + if (SynthesizeProvisionalIvar(Result, Name, NameLoc)) { + if (const ObjCPropertyDecl *Property = + canSynthesizeProvisionalIvar(Name)) { + Diag(NameLoc, diag::warn_synthesized_ivar_access) << Name; + Diag(Property->getLocation(), diag::note_property_declare); + } + + // FIXME: This is strange. Shouldn't we just take the ivar returned + // from SynthesizeProvisionalIvar and continue with that? + E = LookupInObjCMethod(Result, S, Name, true); + if (E.get() || E.isInvalid()) + return E; + } + } + } + + bool SecondTry = false; + bool IsFilteredTemplateName = false; + +Corrected: + switch (Result.getResultKind()) { + case LookupResult::NotFound: + // If an unqualified-id is followed by a '(', then we have a function + // call. + if (!SS.isSet() && NextToken.is(tok::l_paren)) { + // In C++, this is an ADL-only call. + // FIXME: Reference? + if (getLangOptions().CPlusPlus) + return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); + + // C90 6.3.2.2: + // If the expression that precedes the parenthesized argument list in a + // function call consists solely of an identifier, and if no + // declaration is visible for this identifier, the identifier is + // implicitly declared exactly as if, in the innermost block containing + // the function call, the declaration + // + // extern int identifier (); + // + // appeared. + // + // We also allow this in C99 as an extension. + if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) { + Result.addDecl(D); + Result.resolveKind(); + return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false); + } + } + + // In C, we first see whether there is a tag type by the same name, in + // which case it's likely that the user just forget to write "enum", + // "struct", or "union". + if (!getLangOptions().CPlusPlus && !SecondTry) { + Result.clear(LookupTagName); + LookupParsedName(Result, S, &SS); + if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) { + const char *TagName = 0; + const char *FixItTagName = 0; + switch (Tag->getTagKind()) { + case TTK_Class: + TagName = "class"; + FixItTagName = "class "; + break; + + case TTK_Enum: + TagName = "enum"; + FixItTagName = "enum "; + break; + + case TTK_Struct: + TagName = "struct"; + FixItTagName = "struct "; + break; + + case TTK_Union: + TagName = "union"; + FixItTagName = "union "; + break; + } + + Diag(NameLoc, diag::err_use_of_tag_name_without_tag) + << Name << TagName << getLangOptions().CPlusPlus + << FixItHint::CreateInsertion(NameLoc, FixItTagName); + break; + } + + Result.clear(LookupOrdinaryName); + } + + // Perform typo correction to determine if there is another name that is + // close to this name. + if (!SecondTry) { + if (DeclarationName Corrected = CorrectTypo(Result, S, &SS)) { + unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; + unsigned QualifiedDiag = diag::err_no_member_suggest; + + NamedDecl *FirstDecl = Result.empty()? 0 : *Result.begin(); + NamedDecl *UnderlyingFirstDecl + = FirstDecl? FirstDecl->getUnderlyingDecl() : 0; + if (getLangOptions().CPlusPlus && NextToken.is(tok::less) && + UnderlyingFirstDecl && isa<TemplateDecl>(UnderlyingFirstDecl)) { + UnqualifiedDiag = diag::err_no_template_suggest; + QualifiedDiag = diag::err_no_member_template_suggest; + } else if (UnderlyingFirstDecl && + (isa<TypeDecl>(UnderlyingFirstDecl) || + isa<ObjCInterfaceDecl>(UnderlyingFirstDecl) || + isa<ObjCCompatibleAliasDecl>(UnderlyingFirstDecl))) { + UnqualifiedDiag = diag::err_unknown_typename_suggest; + QualifiedDiag = diag::err_unknown_nested_typename_suggest; + } + + if (SS.isEmpty()) + Diag(NameLoc, UnqualifiedDiag) + << Name << Corrected + << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString()); + else + Diag(NameLoc, QualifiedDiag) + << Name << computeDeclContext(SS, false) << Corrected + << SS.getRange() + << FixItHint::CreateReplacement(NameLoc, Corrected.getAsString()); + + // Update the name, so that the caller has the new name. + Name = Corrected.getAsIdentifierInfo(); + + // Typo correction corrected to a keyword. + if (Result.empty()) + return Corrected.getAsIdentifierInfo(); + + Diag(FirstDecl->getLocation(), diag::note_previous_decl) + << FirstDecl->getDeclName(); + + // If we found an Objective-C instance variable, let + // LookupInObjCMethod build the appropriate expression to + // reference the ivar. + // FIXME: This is a gross hack. + if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) { + Result.clear(); + ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier())); + return move(E); + } + + goto Corrected; + } + } + + // We failed to correct; just fall through and let the parser deal with it. + Result.suppressDiagnostics(); + return NameClassification::Unknown(); + + case LookupResult::NotFoundInCurrentInstantiation: + // We performed name lookup into the current instantiation, and there were + // dependent bases, so we treat this result the same way as any other + // dependent nested-name-specifier. + + // C++ [temp.res]p2: + // A name used in a template declaration or definition and that is + // dependent on a template-parameter is assumed not to name a type + // unless the applicable name lookup finds a type name or the name is + // qualified by the keyword typename. + // + // FIXME: If the next token is '<', we might want to ask the parser to + // perform some heroics to see if we actually have a + // template-argument-list, which would indicate a missing 'template' + // keyword here. + return BuildDependentDeclRefExpr(SS, NameInfo, /*TemplateArgs=*/0); + + case LookupResult::Found: + case LookupResult::FoundOverloaded: + case LookupResult::FoundUnresolvedValue: + break; + + case LookupResult::Ambiguous: + if (getLangOptions().CPlusPlus && NextToken.is(tok::less) && + hasAnyAcceptableTemplateNames(Result)) { + // C++ [temp.local]p3: + // A lookup that finds an injected-class-name (10.2) can result in an + // ambiguity in certain cases (for example, if it is found in more than + // one base class). If all of the injected-class-names that are found + // refer to specializations of the same class template, and if the name + // is followed by a template-argument-list, the reference refers to the + // class template itself and not a specialization thereof, and is not + // ambiguous. + // + // This filtering can make an ambiguous result into an unambiguous one, + // so try again after filtering out template names. + FilterAcceptableTemplateNames(Result); + if (!Result.isAmbiguous()) { + IsFilteredTemplateName = true; + break; + } + } + + // Diagnose the ambiguity and return an error. + return NameClassification::Error(); + } + + if (getLangOptions().CPlusPlus && NextToken.is(tok::less) && + (IsFilteredTemplateName || hasAnyAcceptableTemplateNames(Result))) { + // C++ [temp.names]p3: + // After name lookup (3.4) finds that a name is a template-name or that + // an operator-function-id or a literal- operator-id refers to a set of + // overloaded functions any member of which is a function template if + // this is followed by a <, the < is always taken as the delimiter of a + // template-argument-list and never as the less-than operator. + if (!IsFilteredTemplateName) + FilterAcceptableTemplateNames(Result); + + if (!Result.empty()) { + bool IsFunctionTemplate; + TemplateName Template; + if (Result.end() - Result.begin() > 1) { + IsFunctionTemplate = true; + Template = Context.getOverloadedTemplateName(Result.begin(), + Result.end()); + } else { + TemplateDecl *TD + = cast<TemplateDecl>((*Result.begin())->getUnderlyingDecl()); + IsFunctionTemplate = isa<FunctionTemplateDecl>(TD); + + if (SS.isSet() && !SS.isInvalid()) + Template = Context.getQualifiedTemplateName(SS.getScopeRep(), + /*TemplateKeyword=*/false, + TD); + else + Template = TemplateName(TD); + } + + if (IsFunctionTemplate) { + // Function templates always go through overload resolution, at which + // point we'll perform the various checks (e.g., accessibility) we need + // to based on which function we selected. + Result.suppressDiagnostics(); + + return NameClassification::FunctionTemplate(Template); + } + + return NameClassification::TypeTemplate(Template); + } + } + + NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl(); + if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) { + DiagnoseUseOfDecl(Type, NameLoc); + QualType T = Context.getTypeDeclType(Type); + return ParsedType::make(T); + } + + ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(FirstDecl); + if (!Class) { + // FIXME: It's unfortunate that we don't have a Type node for handling this. + if (ObjCCompatibleAliasDecl *Alias + = dyn_cast<ObjCCompatibleAliasDecl>(FirstDecl)) + Class = Alias->getClassInterface(); + } + + if (Class) { + DiagnoseUseOfDecl(Class, NameLoc); + + if (NextToken.is(tok::period)) { + // Interface. <something> is parsed as a property reference expression. + // Just return "unknown" as a fall-through for now. + Result.suppressDiagnostics(); + return NameClassification::Unknown(); + } + + QualType T = Context.getObjCInterfaceType(Class); + return ParsedType::make(T); + } + + if (!Result.empty() && (*Result.begin())->isCXXClassMember()) + return BuildPossibleImplicitMemberExpr(SS, Result, 0); + + bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); + return BuildDeclarationNameExpr(SS, Result, ADL); +} + // Determines the context to return to after temporarily entering a // context. This depends in an unnecessarily complicated way on the // exact ordering of callbacks from the parser. @@ -472,11 +848,30 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { } S->AddDecl(D); - IdResolver.AddDecl(D); + + if (isa<LabelDecl>(D) && !cast<LabelDecl>(D)->isGnuLocal()) { + // Implicitly-generated labels may end up getting generated in an order that + // isn't strictly lexical, which breaks name lookup. Be careful to insert + // the label at the appropriate place in the identifier chain. + for (I = IdResolver.begin(D->getDeclName()); I != IEnd; ++I) { + DeclContext *IDC = (*I)->getLexicalDeclContext()->getRedeclContext(); + if (IDC == CurContext) { + if (!S->isDeclScope(*I)) + continue; + } else if (IDC->Encloses(CurContext)) + break; + } + + IdResolver.InsertDeclAfter(I, D); + } else { + IdResolver.AddDecl(D); + } } -bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S) { - return IdResolver.isDeclInScope(D, Ctx, Context, S); +bool Sema::isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S, + bool ExplicitInstantiationOrSpecialization) { + return IdResolver.isDeclInScope(D, Ctx, Context, S, + ExplicitInstantiationOrSpecialization); } Scope *Sema::getScopeForDeclContext(Scope *S, DeclContext *DC) { @@ -498,12 +893,13 @@ static bool isOutOfScopePreviousDeclaration(NamedDecl *, /// as determined by isDeclInScope. static void FilterLookupForScope(Sema &SemaRef, LookupResult &R, DeclContext *Ctx, Scope *S, - bool ConsiderLinkage) { + bool ConsiderLinkage, + bool ExplicitInstantiationOrSpecialization) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); - if (SemaRef.isDeclInScope(D, Ctx, S)) + if (SemaRef.isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization)) continue; if (ConsiderLinkage && @@ -841,7 +1237,7 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, FunctionDecl *New = FunctionDecl::Create(Context, Context.getTranslationUnitDecl(), - Loc, II, R, /*TInfo=*/0, + Loc, Loc, II, R, /*TInfo=*/0, SC_Extern, SC_None, false, /*hasPrototype=*/true); @@ -851,10 +1247,15 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, // FunctionDecl. if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(R)) { llvm::SmallVector<ParmVarDecl*, 16> Params; - for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) - Params.push_back(ParmVarDecl::Create(Context, New, SourceLocation(), 0, - FT->getArgType(i), /*TInfo=*/0, - SC_None, SC_None, 0)); + for (unsigned i = 0, e = FT->getNumArgs(); i != e; ++i) { + ParmVarDecl *parm = + ParmVarDecl::Create(Context, New, SourceLocation(), + SourceLocation(), 0, + FT->getArgType(i), /*TInfo=*/0, + SC_None, SC_None, 0); + parm->setScopeInfo(0, i); + Params.push_back(parm); + } New->setParams(Params.data(), Params.size()); } @@ -871,12 +1272,12 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned bid, return New; } -/// MergeTypeDefDecl - We just parsed a typedef 'New' which has the +/// MergeTypedefNameDecl - We just parsed a typedef 'New' which has the /// same name and scope as a previous declaration 'Old'. Figure out /// how to resolve this situation, merging decls or emitting /// diagnostics as appropriate. If there was an error, set New to be invalid. /// -void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { +void Sema::MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls) { // If the new decl is known invalid already, don't bother doing any // merging checks. if (New->isInvalidDecl()) return; @@ -936,7 +1337,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { // Determine the "old" type we'll use for checking and diagnostics. QualType OldType; - if (TypedefDecl *OldTypedef = dyn_cast<TypedefDecl>(Old)) + if (TypedefNameDecl *OldTypedef = dyn_cast<TypedefNameDecl>(Old)) OldType = OldTypedef->getUnderlyingType(); else OldType = Context.getTypeDeclType(Old); @@ -947,8 +1348,11 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { if (OldType != New->getUnderlyingType() && Context.getCanonicalType(OldType) != Context.getCanonicalType(New->getUnderlyingType())) { + int Kind = 0; + if (isa<TypeAliasDecl>(Old)) + Kind = 1; Diag(New->getLocation(), diag::err_redefinition_different_typedef) - << New->getUnderlyingType() << OldType; + << Kind << New->getUnderlyingType() << OldType; if (Old->getLocation().isValid()) Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); @@ -958,8 +1362,8 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { // declaration was a typedef. // FIXME: this is a potential source of wierdness if the type // spellings don't match exactly. - if (isa<TypedefDecl>(Old)) - New->setPreviousDeclaration(cast<TypedefDecl>(Old)); + if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Old)) + New->setPreviousDeclaration(Typedef); if (getLangOptions().Microsoft) return; @@ -993,7 +1397,7 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, LookupResult &OldDecls) { // }; // // since that was the intent of DR56. - if (!isa<TypedefDecl >(Old)) + if (!isa<TypedefNameDecl>(Old)) return; Diag(New->getLocation(), diag::err_redefinition) @@ -1033,23 +1437,58 @@ DeclHasAttr(const Decl *D, const Attr *A) { return false; } -/// MergeDeclAttributes - append attributes from the Old decl to the New one. -static void MergeDeclAttributes(Decl *New, Decl *Old, ASTContext &C) { - if (!Old->hasAttrs()) +/// mergeDeclAttributes - Copy attributes from the Old decl to the New one. +static void mergeDeclAttributes(Decl *newDecl, const Decl *oldDecl, + ASTContext &C) { + if (!oldDecl->hasAttrs()) return; + + bool foundAny = newDecl->hasAttrs(); + // Ensure that any moving of objects within the allocated map is done before // we process them. - if (!New->hasAttrs()) - New->setAttrs(AttrVec()); + if (!foundAny) newDecl->setAttrs(AttrVec()); + for (specific_attr_iterator<InheritableAttr> - i = Old->specific_attr_begin<InheritableAttr>(), - e = Old->specific_attr_end<InheritableAttr>(); i != e; ++i) { - if (!DeclHasAttr(New, *i)) { - InheritableAttr *NewAttr = cast<InheritableAttr>((*i)->clone(C)); - NewAttr->setInherited(true); - New->addAttr(NewAttr); + i = oldDecl->specific_attr_begin<InheritableAttr>(), + e = oldDecl->specific_attr_end<InheritableAttr>(); i != e; ++i) { + if (!DeclHasAttr(newDecl, *i)) { + InheritableAttr *newAttr = cast<InheritableAttr>((*i)->clone(C)); + newAttr->setInherited(true); + newDecl->addAttr(newAttr); + foundAny = true; } } + + if (!foundAny) newDecl->dropAttrs(); +} + +/// mergeParamDeclAttributes - Copy attributes from the old parameter +/// to the new one. +static void mergeParamDeclAttributes(ParmVarDecl *newDecl, + const ParmVarDecl *oldDecl, + ASTContext &C) { + if (!oldDecl->hasAttrs()) + return; + + bool foundAny = newDecl->hasAttrs(); + + // Ensure that any moving of objects within the allocated map is + // done before we process them. + if (!foundAny) newDecl->setAttrs(AttrVec()); + + for (specific_attr_iterator<InheritableParamAttr> + i = oldDecl->specific_attr_begin<InheritableParamAttr>(), + e = oldDecl->specific_attr_end<InheritableParamAttr>(); i != e; ++i) { + if (!DeclHasAttr(newDecl, *i)) { + InheritableAttr *newAttr = cast<InheritableParamAttr>((*i)->clone(C)); + newAttr->setInherited(true); + newDecl->addAttr(newAttr); + foundAny = true; + } + } + + if (!foundAny) newDecl->dropAttrs(); } namespace { @@ -1145,10 +1584,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { New->getStorageClass() == SC_Static && Old->getStorageClass() != SC_Static && !canRedefineFunction(Old, getLangOptions())) { - Diag(New->getLocation(), diag::err_static_non_static) - << New; - Diag(Old->getLocation(), PrevDiag); - return true; + if (getLangOptions().Microsoft) { + Diag(New->getLocation(), diag::warn_static_non_static) << New; + Diag(Old->getLocation(), PrevDiag); + } else { + Diag(New->getLocation(), diag::err_static_non_static) << New; + Diag(Old->getLocation(), PrevDiag); + return true; + } } // If a function is first declared with a calling convention, but is @@ -1191,8 +1634,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { } // Merge regparm attribute. - if (OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) { - if (NewTypeInfo.getRegParm()) { + if (OldTypeInfo.getHasRegParm() != NewTypeInfo.getHasRegParm() || + OldTypeInfo.getRegParm() != NewTypeInfo.getRegParm()) { + if (NewTypeInfo.getHasRegParm()) { Diag(New->getLocation(), diag::err_regparm_mismatch) << NewType->getRegParmType() << OldType->getRegParmType(); @@ -1335,10 +1779,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { ParamEnd = OldProto->arg_type_end(); ParamType != ParamEnd; ++ParamType) { ParmVarDecl *Param = ParmVarDecl::Create(Context, New, + SourceLocation(), SourceLocation(), 0, *ParamType, /*TInfo=*/0, SC_None, SC_None, 0); + Param->setScopeInfo(0, Params.size()); Param->setImplicit(); Params.push_back(Param); } @@ -1450,7 +1896,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD) { /// \returns false bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { // Merge the attributes - MergeDeclAttributes(New, Old, Context); + mergeDeclAttributes(New, Old, Context); // Merge the storage class. if (Old->getStorageClass() != SC_Extern && @@ -1465,14 +1911,33 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old) { if (Old->isDeleted()) New->setDeleted(); + // Merge attributes from the parameters. These can mismatch with K&R + // declarations. + if (New->getNumParams() == Old->getNumParams()) + for (unsigned i = 0, e = New->getNumParams(); i != e; ++i) + mergeParamDeclAttributes(New->getParamDecl(i), Old->getParamDecl(i), + Context); + if (getLangOptions().CPlusPlus) return MergeCXXFunctionDecl(New, Old); return false; } -/// MergeVarDecl - We parsed a variable 'New' which has the same name and scope -/// as a previous declaration 'Old'. Figure out how to merge their types, +void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, + const ObjCMethodDecl *oldMethod) { + // Merge the attributes. + mergeDeclAttributes(newMethod, oldMethod, Context); + + // Merge attributes from the parameters. + for (ObjCMethodDecl::param_iterator oi = oldMethod->param_begin(), + ni = newMethod->param_begin(), ne = newMethod->param_end(); + ni != ne; ++ni, ++oi) + mergeParamDeclAttributes(*ni, *oi, Context); +} + +/// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and +/// scope as a previous declaration 'Old'. Figure out how to merge their types, /// emitting diagnostics as appropriate. /// /// Declarations using the auto type specifier (C++ [decl.spec.auto]) call back @@ -1489,8 +1954,10 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) { if (AT && !AT->isDeduced()) { // We don't know what the new type is until the initializer is attached. return; - } else if (Context.hasSameType(New->getType(), Old->getType())) - return; + } else if (Context.hasSameType(New->getType(), Old->getType())) { + // These could still be something that needs exception specs checked. + return MergeVarDeclExceptionSpecs(New, Old); + } // C++ [basic.link]p10: // [...] the types specified by all declarations referring to a given // object or function shall be identical, except that declarations for an @@ -1564,7 +2031,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { New->setInvalidDecl(); } - MergeDeclAttributes(New, Old, Context); + mergeDeclAttributes(New, Old, Context); // Merge the types. MergeVarDeclTypes(New, Old); @@ -1664,12 +2131,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, - DeclSpec &DS) { - // FIXME: Error on inline/virtual/explicit - // FIXME: Warn on useless __thread - // FIXME: Warn on useless const/volatile - // FIXME: Warn on useless static/extern/typedef/private_extern/mutable - // FIXME: Warn on useless attributes + DeclSpec &DS) { Decl *TagD = 0; TagDecl *Tag = 0; if (DS.getTypeSpecType() == DeclSpec::TST_class || @@ -1703,6 +2165,10 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, return 0; return ActOnFriendTypeDecl(S, DS, MultiTemplateParamsArg(*this, 0, 0)); } + + // Track whether we warned about the fact that there aren't any + // declarators. + bool emittedWarning = false; if (RecordDecl *Record = dyn_cast_or_null<RecordDecl>(Tag)) { ProcessDeclAttributeList(S, Record, DS.getAttributes().getList()); @@ -1715,6 +2181,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); + emittedWarning = true; } } @@ -1740,12 +2207,16 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DS.getStorageClassSpec() != DeclSpec::SCS_typedef) if (EnumDecl *Enum = dyn_cast_or_null<EnumDecl>(Tag)) if (Enum->enumerator_begin() == Enum->enumerator_end() && - !Enum->getIdentifier() && !Enum->isInvalidDecl()) + !Enum->getIdentifier() && !Enum->isInvalidDecl()) { Diag(Enum->getLocation(), diag::ext_no_declarators) << DS.getSourceRange(); + emittedWarning = true; + } + + // Skip all the checks below if we have a type error. + if (DS.getTypeSpecType() == DeclSpec::TST_error) return TagD; - if (!DS.isMissingDeclaratorOk() && - DS.getTypeSpecType() != DeclSpec::TST_error) { + if (!DS.isMissingDeclaratorOk()) { // Warn about typedefs of enums without names, since this is an // extension in both Microsoft and GNU. if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef && @@ -1757,7 +2228,40 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Diag(DS.getSourceRange().getBegin(), diag::ext_no_declarators) << DS.getSourceRange(); - } + emittedWarning = true; + } + + // We're going to complain about a bunch of spurious specifiers; + // only do this if we're declaring a tag, because otherwise we + // should be getting diag::ext_no_declarators. + if (emittedWarning || (TagD && TagD->isInvalidDecl())) + return TagD; + + // Note that a linkage-specification sets a storage class, but + // 'extern "C" struct foo;' is actually valid and not theoretically + // useless. + if (DeclSpec::SCS scs = DS.getStorageClassSpec()) + if (!DS.isExternInLinkageSpec()) + Diag(DS.getStorageClassSpecLoc(), diag::warn_standalone_specifier) + << DeclSpec::getSpecifierName(scs); + + if (DS.isThreadSpecified()) + Diag(DS.getThreadSpecLoc(), diag::warn_standalone_specifier) << "__thread"; + if (DS.getTypeQualifiers()) { + if (DS.getTypeQualifiers() & DeclSpec::TQ_const) + Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "const"; + if (DS.getTypeQualifiers() & DeclSpec::TQ_volatile) + Diag(DS.getConstSpecLoc(), diag::warn_standalone_specifier) << "volatile"; + // Restrict is covered above. + } + if (DS.isInlineSpecified()) + Diag(DS.getInlineSpecLoc(), diag::warn_standalone_specifier) << "inline"; + if (DS.isVirtualSpecified()) + Diag(DS.getVirtualSpecLoc(), diag::warn_standalone_specifier) << "virtual"; + if (DS.isExplicitSpecified()) + Diag(DS.getExplicitSpecLoc(), diag::warn_standalone_specifier) <<"explicit"; + + // FIXME: Warn on useless attributes return TagD; } @@ -2062,7 +2566,9 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // Create a declaration for this anonymous struct/union. NamedDecl *Anon = 0; if (RecordDecl *OwningClass = dyn_cast<RecordDecl>(Owner)) { - Anon = FieldDecl::Create(Context, OwningClass, Record->getLocation(), + Anon = FieldDecl::Create(Context, OwningClass, + DS.getSourceRange().getBegin(), + Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, @@ -2086,8 +2592,9 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, VarDecl::StorageClass SCAsWritten = StorageClassSpecToVarDeclStorageClass(SCSpec); - Anon = VarDecl::Create(Context, Owner, Record->getLocation(), - /*IdentifierInfo=*/0, + Anon = VarDecl::Create(Context, Owner, + DS.getSourceRange().getBegin(), + Record->getLocation(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, SC, SCAsWritten); } @@ -2151,6 +2658,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, NamedDecl* Anon = FieldDecl::Create(Context, cast<RecordDecl>(CurContext), DS.getSourceRange().getBegin(), + DS.getSourceRange().getBegin(), /*IdentifierInfo=*/0, Context.getTypeDeclType(Record), TInfo, @@ -2379,6 +2887,26 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false); } +/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13: +/// If T is the name of a class, then each of the following shall have a +/// name different from T: +/// - every static data member of class T; +/// - every member function of class T +/// - every member of class T that is itself a type; +/// \returns true if the declaration name violates these rules. +bool Sema::DiagnoseClassNameShadow(DeclContext *DC, + DeclarationNameInfo NameInfo) { + DeclarationName Name = NameInfo.getName(); + + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) + if (Record->getIdentifier() && Record->getDeclName() == Name) { + Diag(NameInfo.getLoc(), diag::err_member_name_of_class) << Name; + return true; + } + + return false; +} + Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists, bool IsFunctionDefinition) { @@ -2466,23 +2994,12 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, D.setInvalidType(); } } - - // C++ [class.mem]p13: - // If T is the name of a class, then each of the following shall have a - // name different from T: - // - every static data member of class T; - // - every member function of class T - // - every member of class T that is itself a type; - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(DC)) - if (Record->getIdentifier() && Record->getDeclName() == Name) { - Diag(D.getIdentifierLoc(), diag::err_member_name_of_class) - << Name; - - // If this is a typedef, we'll end up spewing multiple diagnostics. - // Just return early; it's safer. - if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) - return 0; - } + + if (DiagnoseClassNameShadow(DC, NameInfo)) + // If this is a typedef, we'll end up spewing multiple diagnostics. + // Just return early; it's safer. + if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) + return 0; NamedDecl *New; @@ -2777,6 +3294,15 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewTD, D); + return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration); +} + +/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which +/// declares a typedef-name, either using the 'typedef' type specifier or via +/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'. +NamedDecl* +Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, + LookupResult &Previous, bool &Redeclaration) { // C99 6.7.7p2: If a typedef name specifies a variably modified type // then it shall have block scope. // Note that variably modified types must be fixed before merging the decl so @@ -2792,18 +3318,17 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, Oversized); if (!FixedTy.isNull()) { - Diag(D.getIdentifierLoc(), diag::warn_illegal_constant_array_size); + Diag(NewTD->getLocation(), diag::warn_illegal_constant_array_size); NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy)); } else { if (SizeIsNegative) - Diag(D.getIdentifierLoc(), diag::err_typecheck_negative_array_size); + Diag(NewTD->getLocation(), diag::err_typecheck_negative_array_size); else if (T->isVariableArrayType()) - Diag(D.getIdentifierLoc(), diag::err_vla_decl_in_file_scope); + Diag(NewTD->getLocation(), diag::err_vla_decl_in_file_scope); else if (Oversized.getBoolValue()) - Diag(D.getIdentifierLoc(), diag::err_array_too_large) - << Oversized.toString(10); + Diag(NewTD->getLocation(), diag::err_array_too_large) << Oversized.toString(10); else - Diag(D.getIdentifierLoc(), diag::err_vm_decl_in_file_scope); + Diag(NewTD->getLocation(), diag::err_vm_decl_in_file_scope); NewTD->setInvalidDecl(); } } @@ -2811,10 +3336,11 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Merge the decl with the existing one if appropriate. If the decl is // in an outer scope, it isn't the same thing. - FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false); + FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false, + /*ExplicitInstantiationOrSpecialization=*/false); if (!Previous.empty()) { Redeclaration = true; - MergeTypeDefDecl(NewTD, Previous); + MergeTypedefNameDecl(NewTD, Previous); } // If this is the C FILE type, notify the AST context. @@ -2952,8 +3478,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool isExplicitSpecialization = false; VarDecl *NewVD; if (!getLangOptions().CPlusPlus) { - NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), - II, R, TInfo, SC, SCAsWritten); + NewVD = VarDecl::Create(Context, DC, D.getSourceRange().getBegin(), + D.getIdentifierLoc(), II, + R, TInfo, SC, SCAsWritten); if (D.isInvalidType()) NewVD->setInvalidDecl(); @@ -2988,7 +3515,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. isExplicitSpecialization = false; - unsigned NumMatchedTemplateParamLists = TemplateParamLists.size(); bool Invalid = false; if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( @@ -2999,9 +3525,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, /*never a friend*/ false, isExplicitSpecialization, Invalid)) { - // All but one template parameter lists have been matching. - --NumMatchedTemplateParamLists; - if (TemplateParams->size() > 0) { // There is no such thing as a variable template. Diag(D.getIdentifierLoc(), diag::err_template_variable) @@ -3017,13 +3540,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); - isExplicitSpecialization = true; } } - NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(), - II, R, TInfo, SC, SCAsWritten); + NewVD = VarDecl::Create(Context, DC, D.getSourceRange().getBegin(), + D.getIdentifierLoc(), II, + R, TInfo, SC, SCAsWritten); // If this decl has an auto type in need of deduction, make a note of the // Decl so we can diagnose uses of it in its own initializer. @@ -3036,9 +3559,9 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, SetNestedNameSpecifier(NewVD, D); - if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { + if (TemplateParamLists.size() > 0 && D.getCXXScopeSpec().isSet()) { NewVD->setTemplateParameterListsInfo(Context, - NumMatchedTemplateParamLists, + TemplateParamLists.size(), TemplateParamLists.release()); } } @@ -3092,7 +3615,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). - FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage()); + FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage(), + isExplicitSpecialization); if (!getLangOptions().CPlusPlus) CheckVariableDeclaration(NewVD, Previous, Redeclaration); @@ -3169,10 +3693,11 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { return; // Don't diagnose declarations at file scope. - DeclContext *NewDC = D->getDeclContext(); - if (NewDC->isFileContext()) + if (D->hasGlobalStorage()) return; - + + DeclContext *NewDC = D->getDeclContext(); + // Only diagnose if we're shadowing an unambiguous field or variable. if (R.getResultKind() != LookupResult::Found) return; @@ -3189,17 +3714,6 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { if (VarDecl *shadowedVar = dyn_cast<VarDecl>(ShadowedDecl)) if (shadowedVar->isExternC()) { - // Don't warn for this case: - // - // @code - // extern int bob; - // void f() { - // extern int bob; - // } - // @endcode - if (D->isExternC()) - return; - // For shadowing external vars, make sure that we point to the global // declaration, not a locally scoped extern declaration. for (VarDecl::redecl_iterator @@ -3528,8 +4042,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, FunctionTemplateDecl *FunctionTemplate = 0; bool isExplicitSpecialization = false; bool isFunctionTemplateSpecialization = false; - unsigned NumMatchedTemplateParamLists = 0; - + if (!getLangOptions().CPlusPlus) { // Determine whether the function was written with a // prototype. This true when: @@ -3540,7 +4053,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); - NewFD = FunctionDecl::Create(Context, DC, + NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), NameInfo, R, TInfo, SC, SCAsWritten, isInline, HasPrototype); if (D.isInvalidType()) @@ -3549,7 +4062,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Set the lexical context. NewFD->setLexicalDeclContext(CurContext); // Filter out previous declarations that don't match the scope. - FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage()); + FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(), + /*ExplicitInstantiationOrSpecialization=*/false); } else { isFriend = D.getDeclSpec().isFriendSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); @@ -3566,14 +4080,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, AbstractReturnType)) D.setInvalidType(); - - if (isFriend) { - // C++ [class.friend]p5 - // A function can be defined in a friend declaration of a - // class . . . . Such a function is implicitly inline. - isInline |= IsFunctionDefinition; - } - if (Name.getNameKind() == DeclarationName::CXXConstructorName) { // This is a C++ constructor declaration. assert(DC->isRecord() && @@ -3584,6 +4090,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Create the new declaration NewFD = CXXConstructorDecl::Create(Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), NameInfo, R, TInfo, isExplicit, isInline, /*isImplicitlyDeclared=*/false); @@ -3594,6 +4101,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD = CXXDestructorDecl::Create(Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), NameInfo, R, TInfo, isInline, /*isImplicitlyDeclared=*/false); @@ -3603,8 +4111,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Create a FunctionDecl to satisfy the function definition parsing // code path. - NewFD = FunctionDecl::Create(Context, DC, D.getIdentifierLoc(), - Name, R, TInfo, SC, SCAsWritten, isInline, + NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), + D.getIdentifierLoc(), Name, R, TInfo, + SC, SCAsWritten, isInline, /*hasPrototype=*/true); D.setInvalidType(); } @@ -3617,8 +4126,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, CheckConversionDeclarator(D, R, SC); NewFD = CXXConversionDecl::Create(Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), NameInfo, R, TInfo, - isInline, isExplicit); + isInline, isExplicit, + SourceLocation()); isVirtualOkay = true; } else if (DC->isRecord()) { @@ -3636,7 +4147,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } bool isStatic = SC == SC_Static; - + // [class.free]p1: // Any allocation function for a class T is a static member // (even if not explicitly declared static). @@ -3649,25 +4160,34 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (Name.getCXXOverloadedOperator() == OO_Delete || Name.getCXXOverloadedOperator() == OO_Array_Delete) isStatic = true; - + // This is a C++ method declaration. NewFD = CXXMethodDecl::Create(Context, cast<CXXRecordDecl>(DC), + D.getSourceRange().getBegin(), NameInfo, R, TInfo, - isStatic, SCAsWritten, isInline); + isStatic, SCAsWritten, isInline, + SourceLocation()); isVirtualOkay = !isStatic; } else { // Determine whether the function was written with a // prototype. This true when: // - we're in C++ (where every function has a prototype), - NewFD = FunctionDecl::Create(Context, DC, + NewFD = FunctionDecl::Create(Context, DC, D.getSourceRange().getBegin(), NameInfo, R, TInfo, SC, SCAsWritten, isInline, true/*HasPrototype*/); } + + if (isFriend && !isInline && IsFunctionDefinition) { + // C++ [class.friend]p5 + // A function can be defined in a friend declaration of a + // class . . . . Such a function is implicitly inline. + NewFD->setImplicitlyInline(); + } + SetNestedNameSpecifier(NewFD, D); isExplicitSpecialization = false; isFunctionTemplateSpecialization = false; - NumMatchedTemplateParamLists = TemplateParamLists.size(); if (D.isInvalidType()) NewFD->setInvalidDecl(); @@ -3680,7 +4200,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // determine whether we have a template or a template specialization. bool Invalid = false; if (TemplateParameterList *TemplateParams - = MatchTemplateParametersToScopeSpecifier( + = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getSourceRange().getBegin(), D.getCXXScopeSpec(), TemplateParamLists.get(), @@ -3688,54 +4208,71 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, isFriend, isExplicitSpecialization, Invalid)) { - // All but one template parameter lists have been matching. - --NumMatchedTemplateParamLists; - - if (TemplateParams->size() > 0) { - // This is a function template - - // Check that we can declare a template here. - if (CheckTemplateDeclScope(S, TemplateParams)) - return 0; - - FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, - NewFD->getLocation(), - Name, TemplateParams, - NewFD); - FunctionTemplate->setLexicalDeclContext(CurContext); - NewFD->setDescribedFunctionTemplate(FunctionTemplate); - } else { - // This is a function template specialization. - isFunctionTemplateSpecialization = true; - - // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". - if (isFriend && isFunctionTemplateSpecialization) { - // We want to remove the "template<>", found here. - SourceRange RemoveRange = TemplateParams->getSourceRange(); - - // If we remove the template<> and the name is not a - // template-id, we're actually silently creating a problem: - // the friend declaration will refer to an untemplated decl, - // and clearly the user wants a template specialization. So - // we need to insert '<>' after the name. - SourceLocation InsertLoc; - if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { - InsertLoc = D.getName().getSourceRange().getEnd(); - InsertLoc = PP.getLocForEndOfToken(InsertLoc); - } + if (TemplateParams->size() > 0) { + // This is a function template - Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) - << Name << RemoveRange - << FixItHint::CreateRemoval(RemoveRange) - << FixItHint::CreateInsertion(InsertLoc, "<>"); - } - } + // Check that we can declare a template here. + if (CheckTemplateDeclScope(S, TemplateParams)) + return 0; + + // A destructor cannot be a template. + if (Name.getNameKind() == DeclarationName::CXXDestructorName) { + Diag(NewFD->getLocation(), diag::err_destructor_template); + return 0; } - if (NumMatchedTemplateParamLists > 0 && D.getCXXScopeSpec().isSet()) { - NewFD->setTemplateParameterListsInfo(Context, - NumMatchedTemplateParamLists, - TemplateParamLists.release()); + FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, + NewFD->getLocation(), + Name, TemplateParams, + NewFD); + FunctionTemplate->setLexicalDeclContext(CurContext); + NewFD->setDescribedFunctionTemplate(FunctionTemplate); + + // For source fidelity, store the other template param lists. + if (TemplateParamLists.size() > 1) { + NewFD->setTemplateParameterListsInfo(Context, + TemplateParamLists.size() - 1, + TemplateParamLists.release()); + } + } else { + // This is a function template specialization. + isFunctionTemplateSpecialization = true; + // For source fidelity, store all the template param lists. + NewFD->setTemplateParameterListsInfo(Context, + TemplateParamLists.size(), + TemplateParamLists.release()); + + // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". + if (isFriend) { + // We want to remove the "template<>", found here. + SourceRange RemoveRange = TemplateParams->getSourceRange(); + + // If we remove the template<> and the name is not a + // template-id, we're actually silently creating a problem: + // the friend declaration will refer to an untemplated decl, + // and clearly the user wants a template specialization. So + // we need to insert '<>' after the name. + SourceLocation InsertLoc; + if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { + InsertLoc = D.getName().getSourceRange().getEnd(); + InsertLoc = PP.getLocForEndOfToken(InsertLoc); + } + + Diag(D.getIdentifierLoc(), diag::err_template_spec_decl_friend) + << Name << RemoveRange + << FixItHint::CreateRemoval(RemoveRange) + << FixItHint::CreateInsertion(InsertLoc, "<>"); + } + } + } + else { + // All template param lists were matched against the scope specifier: + // this is NOT (an explicit specialization of) a template. + if (TemplateParamLists.size() > 0) + // For source fidelity, store all the template param lists. + NewFD->setTemplateParameterListsInfo(Context, + TemplateParamLists.size(), + TemplateParamLists.release()); } if (Invalid) { @@ -3802,7 +4339,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } // Filter out previous declarations that don't match the scope. - FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage()); + FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(), + isExplicitSpecialization || + isFunctionTemplateSpecialization); if (isFriend) { // For now, claim that the objects have no previous declaration. @@ -3863,8 +4402,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // In C++, the empty parameter-type-list must be spelled "void"; a // typedef of void is not permitted. if (getLangOptions().CPlusPlus && - Param->getType().getUnqualifiedType() != Context.VoidTy) - Diag(Param->getLocation(), diag::err_param_typedef_of_void); + Param->getType().getUnqualifiedType() != Context.VoidTy) { + bool IsTypeAlias = false; + if (const TypedefType *TT = Param->getType()->getAs<TypedefType>()) + IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl()); + Diag(Param->getLocation(), diag::err_param_typedef_of_void) + << IsTypeAlias; + } } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) { for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param); @@ -3892,6 +4436,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, AE = FT->arg_type_end(); AI != AE; ++AI) { ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, D.getIdentifierLoc(), *AI); + Param->setScopeInfo(0, Params.size()); Params.push_back(Param); } } else { @@ -3977,9 +4522,15 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, Previous)) NewFD->setInvalidDecl(); } else if (isFunctionTemplateSpecialization) { - if (CheckFunctionTemplateSpecialization(NewFD, - (HasExplicitTemplateArgs ? &TemplateArgs : 0), - Previous)) + if (CurContext->isDependentContext() && CurContext->isRecord() + && !isFriend) { + Diag(NewFD->getLocation(), diag::err_function_specialization_in_class) + << NewFD->getDeclName(); + NewFD->setInvalidDecl(); + return 0; + } else if (CheckFunctionTemplateSpecialization(NewFD, + (HasExplicitTemplateArgs ? &TemplateArgs : 0), + Previous)) NewFD->setInvalidDecl(); } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { if (CheckMemberSpecialization(NewFD, Previous)) @@ -4049,7 +4600,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // are situations where these conditions don't apply and we // can actually do this check immediately. if (isFriend && - (NumMatchedTemplateParamLists || + (TemplateParamLists.size() || D.getCXXScopeSpec().getScopeRep()->isDependent() || CurContext->isDependentContext())) { // ignore these @@ -4146,7 +4697,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, RegisterLocallyScopedExternCDecl(NewFD, Previous, S); // Set this FunctionDecl's range up to the right paren. - NewFD->setLocEnd(D.getSourceRange().getEnd()); + NewFD->setRangeEnd(D.getSourceRange().getEnd()); if (getLangOptions().CPlusPlus) { if (FunctionTemplate) { @@ -4420,8 +4971,7 @@ void Sema::CheckMain(FunctionDecl* FD) { // Darwin passes an undocumented fourth argument of type char**. If // other platforms start sprouting these, the logic below will start // getting shifty. - if (nparams == 4 && - Context.Target.getTriple().getOS() == llvm::Triple::Darwin) + if (nparams == 4 && Context.Target.getTriple().isOSDarwin()) HasExtraParameters = false; if (HasExtraParameters) { @@ -4493,6 +5043,46 @@ bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { return true; } +namespace { + // Visits an initialization expression to see if OrigDecl is evaluated in + // its own initialization and throws a warning if it does. + class SelfReferenceChecker + : public EvaluatedExprVisitor<SelfReferenceChecker> { + Sema &S; + Decl *OrigDecl; + + public: + typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited; + + SelfReferenceChecker(Sema &S, Decl *OrigDecl) : Inherited(S.Context), + S(S), OrigDecl(OrigDecl) { } + + void VisitExpr(Expr *E) { + if (isa<ObjCMessageExpr>(*E)) return; + Inherited::VisitExpr(E); + } + + void VisitImplicitCastExpr(ImplicitCastExpr *E) { + CheckForSelfReference(E); + Inherited::VisitImplicitCastExpr(E); + } + + void CheckForSelfReference(ImplicitCastExpr *E) { + if (E->getCastKind() != CK_LValueToRValue) return; + Expr* SubExpr = E->getSubExpr()->IgnoreParenImpCasts(); + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SubExpr); + if (!DRE) return; + Decl* ReferenceDecl = DRE->getDecl(); + if (OrigDecl != ReferenceDecl) return; + LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName, + Sema::NotForRedeclaration); + S.Diag(SubExpr->getLocStart(), diag::warn_uninit_self_reference_in_init) + << Result.getLookupName() << OrigDecl->getLocation() + << SubExpr->getSourceRange(); + } + }; +} + /// AddInitializerToDecl - Adds the initializer Init to the /// declaration dcl. If DirectInit is true, this is C++ direct /// initialization rather than copy initialization. @@ -4503,6 +5093,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, if (RealDecl == 0 || RealDecl->isInvalidDecl()) return; + // Check for self-references within variable initializers. + if (VarDecl *vd = dyn_cast<VarDecl>(RealDecl)) { + // Variables declared within a function/method body are handled + // by a dataflow analysis. + if (!vd->hasLocalStorage() && !vd->isStaticLocal()) + SelfReferenceChecker(*this, RealDecl).VisitExpr(Init); + } + else { + SelfReferenceChecker(*this, RealDecl).VisitExpr(Init); + } + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(RealDecl)) { // With declarators parsed the way they are, the parser cannot // distinguish between a normal initializer and a pure-specifier. @@ -4533,15 +5134,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (TypeMayContainAuto && VDecl->getType()->getContainedAutoType()) { - QualType DeducedType; - if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) { + TypeSourceInfo *DeducedType = 0; + if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType)) Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure) << VDecl->getDeclName() << VDecl->getType() << Init->getType() << Init->getSourceRange(); + if (!DeducedType) { RealDecl->setInvalidDecl(); return; } - VDecl->setType(DeducedType); + VDecl->setTypeSourceInfo(DeducedType); + VDecl->setType(DeducedType->getType()); // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. @@ -4952,7 +5555,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, const RecordType *Record = Context.getBaseElementType(Type)->getAs<RecordType>(); - if (Record && getLangOptions().CPlusPlus && !getLangOptions().CPlusPlus0x && + if (Record && getLangOptions().CPlusPlus && cast<CXXRecordDecl>(Record->getDecl())->isPOD()) { // C++03 [dcl.init]p9: // If no initializer is specified for an object, and the @@ -4965,7 +5568,6 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, // any, have an indeterminate initial value); if the object // or any of its subobjects are of const-qualified type, the // program is ill-formed. - // FIXME: DPG thinks it is very fishy that C++0x disables this. } else { // Check for jumps past the implicit initializer. C++0x // clarifies that this applies to a "variable with automatic @@ -4990,6 +5592,47 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, } } +void Sema::ActOnCXXForRangeDecl(Decl *D) { + VarDecl *VD = dyn_cast<VarDecl>(D); + if (!VD) { + Diag(D->getLocation(), diag::err_for_range_decl_must_be_var); + D->setInvalidDecl(); + return; + } + + VD->setCXXForRangeDecl(true); + + // for-range-declaration cannot be given a storage class specifier. + int Error = -1; + switch (VD->getStorageClassAsWritten()) { + case SC_None: + break; + case SC_Extern: + Error = 0; + break; + case SC_Static: + Error = 1; + break; + case SC_PrivateExtern: + Error = 2; + break; + case SC_Auto: + Error = 3; + break; + case SC_Register: + Error = 4; + break; + } + // FIXME: constexpr isn't allowed here. + //if (DS.isConstexprSpecified()) + // Error = 5; + if (Error != -1) { + Diag(VD->getOuterLocStart(), diag::err_for_range_storage_class) + << VD->getDeclName() << Error; + D->setInvalidDecl(); + } +} + void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isInvalidDecl()) return; @@ -5058,7 +5701,7 @@ Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, if (Decl *D = Group[i]) Decls.push_back(D); - return BuildDeclaratorGroup(Decls.data(), Decls.size(), + return BuildDeclaratorGroup(Decls.data(), Decls.size(), DS.getTypeSpecType() == DeclSpec::TST_auto); } @@ -5195,12 +5838,18 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // the enclosing context. This prevents them from accidentally // looking like class members in C++. ParmVarDecl *New = CheckParameter(Context.getTranslationUnitDecl(), - TInfo, parmDeclType, II, - D.getIdentifierLoc(), + D.getSourceRange().getBegin(), + D.getIdentifierLoc(), II, + parmDeclType, TInfo, StorageClass, StorageClassAsWritten); if (D.isInvalidType()) - New->setInvalidDecl(); + New->setInvalidDecl(); + + assert(S->isFunctionPrototypeScope()); + assert(S->getFunctionPrototypeDepth() >= 1); + New->setScopeInfo(S->getFunctionPrototypeDepth() - 1, + S->getNextFunctionPrototypeIndex()); // Add the parameter declaration into this scope. S->AddDecl(New); @@ -5220,7 +5869,10 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC, SourceLocation Loc, QualType T) { - ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, 0, + /* FIXME: setting StartLoc == Loc. + Would it be worth to modify callers so as to provide proper source + location for the unnamed parameters, embedding the parameter's type? */ + ParmVarDecl *Param = ParmVarDecl::Create(Context, DC, Loc, Loc, 0, T, Context.getTrivialTypeSourceInfo(T, Loc), SC_None, SC_None, 0); Param->setImplicit(); @@ -5272,14 +5924,13 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, } } -ParmVarDecl *Sema::CheckParameter(DeclContext *DC, - TypeSourceInfo *TSInfo, QualType T, - IdentifierInfo *Name, - SourceLocation NameLoc, +ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, + SourceLocation NameLoc, IdentifierInfo *Name, + QualType T, TypeSourceInfo *TSInfo, VarDecl::StorageClass StorageClass, VarDecl::StorageClass StorageClassAsWritten) { - ParmVarDecl *New = ParmVarDecl::Create(Context, DC, NameLoc, Name, - adjustParameterType(T), TSInfo, + ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name, + adjustParameterType(T), TSInfo, StorageClass, StorageClassAsWritten, 0); @@ -5331,7 +5982,8 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, // Implicitly declare the argument as type 'int' for lack of a better // type. - DeclSpec DS; + AttributeFactory attrs; + DeclSpec DS(attrs); const char* PrevSpec; // unused unsigned DiagID; // unused DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc, @@ -5374,7 +6026,7 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) { return false; // Don't warn about inline functions. - if (FD->isInlineSpecified()) + if (FD->isInlined()) return false; // Don't warn about function templates. @@ -5400,6 +6052,22 @@ static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD) { return MissingPrototype; } +void Sema::CheckForFunctionRedefinition(FunctionDecl *FD) { + // Don't complain if we're in GNU89 mode and the previous definition + // was an extern inline function. + const FunctionDecl *Definition; + if (FD->hasBody(Definition) && + !canRedefineFunction(Definition, getLangOptions())) { + if (getLangOptions().GNUMode && Definition->isInlineSpecified() && + Definition->getStorageClass() == SC_Extern) + Diag(FD->getLocation(), diag::err_redefinition_extern_inline) + << FD->getDeclName() << getLangOptions().CPlusPlus; + else + Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName(); + Diag(Definition->getLocation(), diag::note_previous_definition); + } +} + Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { // Clear the last template instantiation error context. LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation(); @@ -5417,19 +6085,8 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { PushFunctionScope(); // See if this is a redefinition. - // But don't complain if we're in GNU89 mode and the previous definition - // was an extern inline function. - const FunctionDecl *Definition; - if (FD->hasBody(Definition) && - !canRedefineFunction(Definition, getLangOptions())) { - if (getLangOptions().GNUMode && Definition->isInlineSpecified() && - Definition->getStorageClass() == SC_Extern) - Diag(FD->getLocation(), diag::err_redefinition_extern_inline) - << FD->getDeclName() << getLangOptions().CPlusPlus; - else - Diag(FD->getLocation(), diag::err_redefinition) << FD->getDeclName(); - Diag(Definition->getLocation(), diag::note_previous_definition); - } + if (!FD->isLateTemplateParsed()) + CheckForFunctionRedefinition(FD); // Builtin functions cannot be defined. if (unsigned BuiltinID = FD->getBuiltinID()) { @@ -5481,7 +6138,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D) { DLLImportAttr *DA = FD->getAttr<DLLImportAttr>(); if (DA && (!FD->getAttr<DLLExportAttr>())) { // dllimport attribute cannot be directly applied to definition. - if (!DA->isInherited()) { + // Microsoft accepts dllimport for functions defined within class scope. + if (!DA->isInherited() && + !(LangOpts.Microsoft && FD->getLexicalDeclContext()->isRecord())) { Diag(FD->getLocation(), diag::err_attribute_can_be_applied_only_to_symbol_declaration) << "dllimport"; @@ -5615,7 +6274,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. - if (PP.getDiagnostics().hasErrorOccurred()) + if (PP.getDiagnostics().hasErrorOccurred() || + PP.getDiagnostics().getSuppressAllDiagnostics()) ExprTemporaries.clear(); else if (!isa<FunctionTemplateDecl>(dcl)) { // Since the body is valid, issue any analysis-based warnings that are @@ -5666,17 +6326,18 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, // Set a Declarator for the implicit definition: int foo(); const char *Dummy; - DeclSpec DS; + AttributeFactory attrFactory; + DeclSpec DS(attrFactory); unsigned DiagID; bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID); (void)Error; // Silence warning. assert(!Error && "Error setting up implicit decl!"); Declarator D(DS, Declarator::BlockContext); - D.AddTypeInfo(DeclaratorChunk::getFunction(ParsedAttributes(), - false, false, SourceLocation(), 0, + D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, SourceLocation(), 0, 0, 0, true, SourceLocation(), - false, SourceLocation(), - false, 0,0,0, Loc, Loc, D), + EST_None, SourceLocation(), + 0, 0, 0, 0, Loc, Loc, D), + DS.getAttributes(), SourceLocation()); D.SetIdentifier(&II, Loc); @@ -5784,6 +6445,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, // Scope manipulation handled by caller. TypedefDecl *NewTD = TypedefDecl::Create(Context, CurContext, + D.getSourceRange().getBegin(), D.getIdentifierLoc(), D.getIdentifier(), TInfo); @@ -5810,7 +6472,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, // Do nothing if the tag is not anonymous or already has an // associated typedef (from an earlier typedef in this decl group). if (tagFromDeclSpec->getIdentifier()) break; - if (tagFromDeclSpec->getTypedefForAnonDecl()) break; + if (tagFromDeclSpec->getTypedefNameForAnonDecl()) break; // A well-formed anonymous tag must always be a TUK_Definition. assert(tagFromDeclSpec->isThisDeclarationADefinition()); @@ -5820,7 +6482,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, break; // Otherwise, set this is the anon-decl typedef for the tag. - tagFromDeclSpec->setTypedefForAnonDecl(NewTD); + tagFromDeclSpec->setTypedefNameForAnonDecl(NewTD); break; } @@ -5897,36 +6559,33 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // FIXME: Check explicit specializations more carefully. bool isExplicitSpecialization = false; - unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size(); bool Invalid = false; // We only need to do this matching if we have template parameters // or a scope specifier, which also conveniently avoids this work // for non-C++ cases. - if (NumMatchedTemplateParamLists || + if (TemplateParameterLists.size() > 0 || (SS.isNotEmpty() && TUK != TUK_Reference)) { if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, TemplateParameterLists.get(), - TemplateParameterLists.size(), + TemplateParameterLists.size(), TUK == TUK_Friend, isExplicitSpecialization, Invalid)) { - // All but one template parameter lists have been matching. - --NumMatchedTemplateParamLists; - if (TemplateParams->size() > 0) { // This is a declaration or definition of a class template (which may // be a member of another template). + if (Invalid) return 0; - + OwnedDecl = false; DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS, Name, NameLoc, Attr, - TemplateParams, - AS); - TemplateParameterLists.release(); + TemplateParams, AS, + TemplateParameterLists.size() - 1, + (TemplateParameterList**) TemplateParameterLists.release()); return Result.get(); } else { // The "template<>" header is extraneous. @@ -6164,7 +6823,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // okay according to the likely resolution of an open issue; // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407 if (getLangOptions().CPlusPlus) { - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(PrevDecl)) { + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(PrevDecl)) { if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { TagDecl *Tag = TT->getDecl(); if (Tag->getDeclName() == Name && @@ -6184,7 +6843,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // in the same scope (so that the definition/declaration completes or // rementions the tag), reuse the decl. if (TUK == TUK_Reference || TUK == TUK_Friend || - isDeclInScope(PrevDecl, SearchDC, S)) { + isDeclInScope(PrevDecl, SearchDC, S, isExplicitSpecialization)) { // Make sure that this wasn't declared as an enum and now used as a // struct or something similar. if (!isAcceptableTagRedeclaration(PrevTagDecl, Kind, KWLoc, *Name)) { @@ -6322,30 +6981,34 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, !Previous.isForRedeclaration()) { unsigned Kind = 0; if (isa<TypedefDecl>(PrevDecl)) Kind = 1; - else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2; + else if (isa<TypeAliasDecl>(PrevDecl)) Kind = 2; + else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 3; Diag(NameLoc, diag::err_tag_reference_non_tag) << Kind; Diag(PrevDecl->getLocation(), diag::note_declared_at); Invalid = true; // Otherwise, only diagnose if the declaration is in scope. - } else if (!isDeclInScope(PrevDecl, SearchDC, S)) { + } else if (!isDeclInScope(PrevDecl, SearchDC, S, + isExplicitSpecialization)) { // do nothing // Diagnose implicit declarations introduced by elaborated types. } else if (TUK == TUK_Reference || TUK == TUK_Friend) { unsigned Kind = 0; if (isa<TypedefDecl>(PrevDecl)) Kind = 1; - else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 2; + else if (isa<TypeAliasDecl>(PrevDecl)) Kind = 2; + else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 3; Diag(NameLoc, diag::err_tag_reference_conflict) << Kind; Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; Invalid = true; // Otherwise it's a declaration. Call out a particularly common // case here. - } else if (isa<TypedefDecl>(PrevDecl)) { + } else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(PrevDecl)) { + unsigned Kind = 0; + if (isa<TypeAliasDecl>(PrevDecl)) Kind = 1; Diag(NameLoc, diag::err_tag_definition_of_typedef) - << Name - << cast<TypedefDecl>(PrevDecl)->getUnderlyingType(); + << Name << Kind << TND->getUnderlyingType(); Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; Invalid = true; @@ -6385,7 +7048,7 @@ CreateNewDecl: if (Kind == TTK_Enum) { // FIXME: Tag decls should be chained to any simultaneous vardecls, e.g.: // enum X { A, B, C } D; D should chain to X. - New = EnumDecl::Create(Context, SearchDC, Loc, Name, KWLoc, + New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, cast_or_null<EnumDecl>(PrevDecl), ScopedEnum, ScopedEnumUsesClassTag, !EnumUnderlying.isNull()); // If this is an undefined enum, warn. @@ -6431,13 +7094,13 @@ CreateNewDecl: // struct X { int A; } D; D should chain to X. if (getLangOptions().CPlusPlus) { // FIXME: Look for a way to use RecordDecl for simple structs. - New = CXXRecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc, + New = CXXRecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name, cast_or_null<CXXRecordDecl>(PrevDecl)); - + if (isStdBadAlloc && (!StdBadAlloc || getStdBadAlloc()->isImplicit())) StdBadAlloc = cast<CXXRecordDecl>(New); } else - New = RecordDecl::Create(Context, Kind, SearchDC, Loc, Name, KWLoc, + New = RecordDecl::Create(Context, Kind, SearchDC, KWLoc, Loc, Name, cast_or_null<RecordDecl>(PrevDecl)); } @@ -6445,9 +7108,9 @@ CreateNewDecl: if (SS.isNotEmpty()) { if (SS.isSet()) { New->setQualifierInfo(SS.getWithLocInContext(Context)); - if (NumMatchedTemplateParamLists > 0) { + if (TemplateParameterLists.size() > 0) { New->setTemplateParameterListsInfo(Context, - NumMatchedTemplateParamLists, + TemplateParameterLists.size(), (TemplateParameterList**) TemplateParameterLists.release()); } } @@ -6466,6 +7129,8 @@ CreateNewDecl: // the #pragma tokens are effectively skipped over during the // parsing of the struct). AddAlignmentAttributesForRecord(RD); + + AddMsStructLayoutForRecord(RD); } // If this is a specialization of a member class (of a class template), @@ -6541,7 +7206,7 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { } void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, - ClassVirtSpecifiers &CVS, + SourceLocation FinalLoc, SourceLocation LBraceLoc) { AdjustDeclIfTemplate(TagD); CXXRecordDecl *Record = cast<CXXRecordDecl>(TagD); @@ -6551,10 +7216,8 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, if (!Record->getIdentifier()) return; - if (CVS.isFinalSpecified()) - Record->addAttr(new (Context) FinalAttr(CVS.getFinalLoc(), Context)); - if (CVS.isExplicitSpecified()) - Record->addAttr(new (Context) ExplicitAttr(CVS.getExplicitLoc(), Context)); + if (FinalLoc.isValid()) + Record->addAttr(new (Context) FinalAttr(FinalLoc, Context)); // C++ [class]p2: // [...] The class-name is also inserted into the scope of the @@ -6562,10 +7225,9 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, // purposes of access checking, the injected-class-name is treated // as if it were a public member name. CXXRecordDecl *InjectedClassName - = CXXRecordDecl::Create(Context, Record->getTagKind(), - CurContext, Record->getLocation(), + = CXXRecordDecl::Create(Context, Record->getTagKind(), CurContext, + Record->getLocStart(), Record->getLocation(), Record->getIdentifier(), - Record->getTagKeywordLoc(), /*PrevDecl=*/0, /*DelayTypeCreation=*/true); Context.getTypeDeclType(InjectedClassName, Record); @@ -6852,7 +7514,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } } - FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, TInfo, + FieldDecl *NewFD = FieldDecl::Create(Context, Record, TSSL, Loc, II, T, TInfo, BitWidth, Mutable); if (InvalidDecl) NewFD->setInvalidDecl(); @@ -7152,8 +7814,8 @@ Decl *Sema::ActOnIvar(Scope *S, } // Construct the decl. - ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, - EnclosingContext, Loc, II, T, + ObjCIvarDecl *NewID = ObjCIvarDecl::Create(Context, EnclosingContext, + DeclStart, Loc, II, T, TInfo, ac, (Expr *)BitfieldWidth); if (II) { @@ -7216,7 +7878,7 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Decl *EnclosingDecl, Expr * BW = IntegerLiteral::Create(Context, Zero, Context.CharTy, DeclLoc); Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(EnclosingDecl), - DeclLoc, 0, + DeclLoc, DeclLoc, 0, Context.CharTy, Context.CreateTypeSourceInfo(Context.CharTy), ObjCIvarDecl::Private, BW, @@ -7281,20 +7943,27 @@ void Sema::ActOnFields(Scope* S, continue; } else if (FDTy->isIncompleteArrayType() && Record && ((i == NumFields - 1 && !Record->isUnion()) || - (getLangOptions().Microsoft && + ((getLangOptions().Microsoft || getLangOptions().CPlusPlus) && (i == NumFields - 1 || Record->isUnion())))) { // Flexible array member. - // Microsoft is more permissive regarding flexible array. + // Microsoft and g++ is more permissive regarding flexible array. // It will accept flexible array in union and also // as the sole element of a struct/class. if (getLangOptions().Microsoft) { if (Record->isUnion()) - Diag(FD->getLocation(), diag::ext_flexible_array_union) + Diag(FD->getLocation(), diag::ext_flexible_array_union_ms) + << FD->getDeclName(); + else if (NumFields == 1) + Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_ms) + << FD->getDeclName() << Record->getTagKind(); + } else if (getLangOptions().CPlusPlus) { + if (Record->isUnion()) + Diag(FD->getLocation(), diag::ext_flexible_array_union_gnu) << FD->getDeclName(); else if (NumFields == 1) - Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate) + Diag(FD->getLocation(), diag::ext_flexible_array_empty_aggregate_gnu) << FD->getDeclName() << Record->getTagKind(); - } else if (NumNamedMembers < 1) { + } else if (NumNamedMembers < 1) { Diag(FD->getLocation(), diag::err_flexible_array_empty_struct) << FD->getDeclName(); FD->setInvalidDecl(); @@ -7547,7 +8216,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, << (EnumVal.isUnsigned() || EnumVal.isNonNegative()); else if (!Context.hasSameType(Val->getType(), Context.IntTy)) { // Force the type of the expression to 'int'. - ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast); + Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).take(); } } @@ -7560,12 +8229,12 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) { if (getLangOptions().Microsoft) { Diag(IdLoc, diag::ext_enumerator_too_large) << EltTy; - ImpCastExprToType(Val, EltTy, CK_IntegralCast); + Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take(); } else Diag(IdLoc, diag::err_enumerator_too_large) << EltTy; } else - ImpCastExprToType(Val, EltTy, CK_IntegralCast); + Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).take(); } else { // C++0x [dcl.enum]p5: @@ -7949,11 +8618,14 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, NumPositiveBits, NumNegativeBits); } -Decl *Sema::ActOnFileScopeAsmDecl(SourceLocation Loc, Expr *expr) { +Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr, + SourceLocation StartLoc, + SourceLocation EndLoc) { StringLiteral *AsmString = cast<StringLiteral>(expr); FileScopeAsmDecl *New = FileScopeAsmDecl::Create(Context, CurContext, - Loc, AsmString); + AsmString, StartLoc, + EndLoc); CurContext->addDecl(New); return New; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index 893cf6a..7f93ab7 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -24,6 +24,26 @@ using namespace clang; using namespace sema; +/// These constants match the enumerated choices of +/// warn_attribute_wrong_decl_type and err_attribute_wrong_decl_type. +enum { + ExpectedFunction, + ExpectedUnion, + ExpectedVariableOrFunction, + ExpectedFunctionOrMethod, + ExpectedParameter, + ExpectedParameterOrMethod, + ExpectedFunctionMethodOrBlock, + ExpectedClassOrVirtualMethod, + ExpectedFunctionMethodOrParameter, + ExpectedClass, + ExpectedVirtualMethod, + ExpectedClassMember, + ExpectedVariable, + ExpectedMethod, + ExpectedVariableFunctionOrLabel +}; + //===----------------------------------------------------------------------===// // Helper functions //===----------------------------------------------------------------------===// @@ -35,7 +55,7 @@ static const FunctionType *getFunctionType(const Decl *d, Ty = decl->getType(); else if (const FieldDecl *decl = dyn_cast<FieldDecl>(d)) Ty = decl->getType(); - else if (const TypedefDecl* decl = dyn_cast<TypedefDecl>(d)) + else if (const TypedefNameDecl* decl = dyn_cast<TypedefNameDecl>(d)) Ty = decl->getUnderlyingType(); else return 0; @@ -81,8 +101,8 @@ static bool isFunctionOrMethodOrBlock(const Decl *d) { /// Return true if the given decl has a declarator that should have /// been processed by Sema::GetTypeForDeclarator. static bool hasDeclarator(const Decl *d) { - // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl. - return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefDecl>(d); + // In some sense, TypedefNameDecl really *ought* to be a DeclaratorDecl. + return isa<DeclaratorDecl>(d) || isa<BlockDecl>(d) || isa<TypedefNameDecl>(d); } /// hasFunctionProto - Return true if the given decl has a argument @@ -182,7 +202,7 @@ static inline bool isCFStringType(QualType T, ASTContext &Ctx) { static void HandleExtVectorTypeAttr(Scope *scope, Decl *d, const AttributeList &Attr, Sema &S) { - TypedefDecl *tDecl = dyn_cast<TypedefDecl>(d); + TypedefNameDecl *tDecl = dyn_cast<TypedefNameDecl>(d); if (tDecl == 0) { S.Diag(Attr.getLoc(), diag::err_typecheck_ext_vector_not_typedef); return; @@ -241,6 +261,13 @@ static void HandlePackedAttr(Decl *d, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } +static void HandleMsStructAttr(Decl *d, const AttributeList &Attr, Sema &S) { + if (TagDecl *TD = dyn_cast<TagDecl>(d)) + TD->addAttr(::new (S.Context) MsStructAttr(Attr.getLoc(), S.Context)); + else + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); +} + static void HandleIBAction(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() > 0) { @@ -332,7 +359,7 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { // ignore it as well if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -474,8 +501,8 @@ static void HandleOwnershipAttr(Decl *d, const AttributeList &AL, Sema &S) { } if (!isFunction(d) || !hasFunctionProto(d)) { - S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL.getName() - << 0 /*function*/; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL.getName() << ExpectedFunction; return; } @@ -615,7 +642,7 @@ static void HandleWeakRefAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variables and functions*/; + << Attr.getName() << ExpectedVariableOrFunction; return; } @@ -701,7 +728,7 @@ static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (S.Context.Target.getTriple().getOS() == llvm::Triple::Darwin) { + if (S.Context.Target.getTriple().isOSDarwin()) { S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin); return; } @@ -722,7 +749,7 @@ static void HandleNakedAttr(Decl *d, const AttributeList &Attr, if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -732,14 +759,14 @@ static void HandleNakedAttr(Decl *d, const AttributeList &Attr, static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Check the attribute arguments. - if (Attr.getNumArgs() != 0) { + if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -748,7 +775,7 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr, static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Check the attribute arguments. - if (Attr.getNumArgs() != 0) { + if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } @@ -780,7 +807,7 @@ static void HandleNoCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) NoCommonAttr(Attr.getLoc(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 12 /* variable */; + << Attr.getName() << ExpectedVariable; } static void HandleCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) { @@ -789,7 +816,7 @@ static void HandleCommonAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) CommonAttr(Attr.getLoc(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 12 /* variable */; + << Attr.getName() << ExpectedVariable; } static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) { @@ -799,7 +826,7 @@ static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) { if (!isa<ObjCMethodDecl>(d)) { S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << attr.getName() << 0 /*function*/; + << attr.getName() << ExpectedFunctionOrMethod; return; } @@ -807,7 +834,7 @@ static void HandleNoReturnAttr(Decl *d, const AttributeList &attr, Sema &S) { } bool Sema::CheckNoReturnAttr(const AttributeList &attr) { - if (attr.getNumArgs() != 0) { + if (attr.hasParameterOrArguments()) { Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; attr.setInvalid(); return true; @@ -834,7 +861,7 @@ static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr, S.Diag(Attr.getLoc(), Attr.isCXX0XAttribute() ? diag::err_attribute_wrong_decl_type : diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunctionMethodOrBlock; return; } } @@ -870,7 +897,7 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr, */ if (!isa<RecordDecl>(d)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << 9 /*class*/; + << Attr.getName() << ExpectedClass; return; } @@ -907,7 +934,7 @@ static void HandleVecReturnAttr(Decl *d, const AttributeList &Attr, static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isFunctionOrMethod(d) && !isa<ParmVarDecl>(d)) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) - << Attr.getName() << 8 /*function, method, or parameter*/; + << Attr.getName() << ExpectedFunctionMethodOrParameter; return; } // FIXME: Actually store the attribute on the declaration @@ -915,7 +942,7 @@ static void HandleDependencyAttr(Decl *d, const AttributeList &Attr, Sema &S) { static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { + if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } @@ -923,7 +950,7 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isa<VarDecl>(d) && !isa<ObjCIvarDecl>(d) && !isFunctionOrMethod(d) && !isa<TypeDecl>(d) && !isa<LabelDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 14 /*variable, function, labels*/; + << Attr.getName() << ExpectedVariableFunctionOrLabel; return; } @@ -932,7 +959,7 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { + if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } @@ -944,7 +971,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) { } } else if (!isFunctionOrMethod(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variable and function*/; + << Attr.getName() << ExpectedVariableOrFunction; return; } @@ -953,9 +980,8 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) { static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. - if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << "0 or 1"; + if (Attr.getNumArgs() > 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; return; } @@ -974,7 +1000,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -984,9 +1010,8 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. - if (Attr.getNumArgs() != 0 && Attr.getNumArgs() != 1) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << "0 or 1"; + if (Attr.getNumArgs() > 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; return; } @@ -1005,7 +1030,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -1016,8 +1041,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) { static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) { unsigned NumArgs = Attr.getNumArgs(); if (NumArgs > 1) { - S.Diag(Attr.getLoc(), - diag::err_attribute_wrong_number_arguments) << "0 or 1"; + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; return; } @@ -1039,8 +1063,7 @@ static void HandleDeprecatedAttr(Decl *d, const AttributeList &Attr, Sema &S) { static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) { unsigned NumArgs = Attr.getNumArgs(); if (NumArgs > 1) { - S.Diag(Attr.getLoc(), - diag::err_attribute_wrong_number_arguments) << "0 or 1"; + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 1; return; } @@ -1058,6 +1081,59 @@ static void HandleUnavailableAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) UnavailableAttr(Attr.getLoc(), S.Context, Str)); } +static void HandleAvailabilityAttr(Decl *d, const AttributeList &Attr, + Sema &S) { + IdentifierInfo *Platform = Attr.getParameterName(); + SourceLocation PlatformLoc = Attr.getParameterLoc(); + + llvm::StringRef PlatformName + = AvailabilityAttr::getPrettyPlatformName(Platform->getName()); + if (PlatformName.empty()) { + S.Diag(PlatformLoc, diag::warn_availability_unknown_platform) + << Platform; + + PlatformName = Platform->getName(); + } + + AvailabilityChange Introduced = Attr.getAvailabilityIntroduced(); + AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated(); + AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted(); + bool IsUnavailable = Attr.getUnavailableLoc().isValid(); + + // Ensure that Introduced < Deprecated < Obsoleted (although not all + // of these steps are needed). + if (Introduced.isValid() && Deprecated.isValid() && + !(Introduced.Version < Deprecated.Version)) { + S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering) + << 1 << PlatformName << Deprecated.Version.getAsString() + << 0 << Introduced.Version.getAsString(); + return; + } + + if (Introduced.isValid() && Obsoleted.isValid() && + !(Introduced.Version < Obsoleted.Version)) { + S.Diag(Introduced.KeywordLoc, diag::warn_availability_version_ordering) + << 2 << PlatformName << Obsoleted.Version.getAsString() + << 0 << Introduced.Version.getAsString(); + return; + } + + if (Deprecated.isValid() && Obsoleted.isValid() && + !(Deprecated.Version < Obsoleted.Version)) { + S.Diag(Deprecated.KeywordLoc, diag::warn_availability_version_ordering) + << 2 << PlatformName << Obsoleted.Version.getAsString() + << 1 << Deprecated.Version.getAsString(); + return; + } + + d->addAttr(::new (S.Context) AvailabilityAttr(Attr.getLoc(), S.Context, + Platform, + Introduced.Version, + Deprecated.Version, + Obsoleted.Version, + IsUnavailable)); +} + static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() != 1) { @@ -1094,6 +1170,51 @@ static void HandleVisibilityAttr(Decl *d, const AttributeList &Attr, Sema &S) { d->addAttr(::new (S.Context) VisibilityAttr(Attr.getLoc(), S.Context, type)); } +static void HandleObjCMethodFamilyAttr(Decl *decl, const AttributeList &attr, + Sema &S) { + ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(decl); + if (!method) { + S.Diag(attr.getLoc(), diag::err_attribute_wrong_decl_type) + << ExpectedMethod; + return; + } + + if (attr.getNumArgs() != 0 || !attr.getParameterName()) { + if (!attr.getParameterName() && attr.getNumArgs() == 1) { + S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "objc_method_family" << 1; + } else { + S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; + } + attr.setInvalid(); + return; + } + + llvm::StringRef param = attr.getParameterName()->getName(); + ObjCMethodFamilyAttr::FamilyKind family; + if (param == "none") + family = ObjCMethodFamilyAttr::OMF_None; + else if (param == "alloc") + family = ObjCMethodFamilyAttr::OMF_alloc; + else if (param == "copy") + family = ObjCMethodFamilyAttr::OMF_copy; + else if (param == "init") + family = ObjCMethodFamilyAttr::OMF_init; + else if (param == "mutableCopy") + family = ObjCMethodFamilyAttr::OMF_mutableCopy; + else if (param == "new") + family = ObjCMethodFamilyAttr::OMF_new; + else { + // Just warn and ignore it. This is future-proof against new + // families being used in system headers. + S.Diag(attr.getParameterLoc(), diag::warn_unknown_method_family); + return; + } + + decl->addAttr(new (S.Context) ObjCMethodFamilyAttr(attr.getLoc(), + S.Context, family)); +} + static void HandleObjCExceptionAttr(Decl *D, const AttributeList &Attr, Sema &S) { if (Attr.getNumArgs() != 0) { @@ -1115,7 +1236,7 @@ static void HandleObjCNSObject(Decl *D, const AttributeList &Attr, Sema &S) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; return; } - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { QualType T = TD->getUnderlyingType(); if (!T->isPointerType() || !T->getAs<PointerType>()->getPointeeType()->isRecordType()) { @@ -1168,8 +1289,7 @@ static void HandleBlocksAttr(Decl *d, const AttributeList &Attr, Sema &S) { static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. if (Attr.getNumArgs() > 2) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << "0, 1 or 2"; + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2; return; } @@ -1247,12 +1367,12 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) { } } else { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 6 /*function, method or block */; + << Attr.getName() << ExpectedFunctionMethodOrBlock; return; } } else { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 6 /*function, method or block */; + << Attr.getName() << ExpectedFunctionMethodOrBlock; return; } d->addAttr(::new (S.Context) SentinelAttr(Attr.getLoc(), S.Context, sentinel, @@ -1268,7 +1388,7 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) if (!isFunction(D) && !isa<ObjCMethodDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunctionOrMethod; return; } @@ -1289,14 +1409,14 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) static void HandleWeakAttr(Decl *d, const AttributeList &attr, Sema &S) { // check the attribute arguments. - if (attr.getNumArgs() != 0) { + if (attr.hasParameterOrArguments()) { S.Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } if (!isa<VarDecl>(d) && !isa<FunctionDecl>(d)) { S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << attr.getName() << 2 /*variables and functions*/; + << attr.getName() << ExpectedVariableOrFunction; return; } @@ -1320,27 +1440,19 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) { // weak_import only applies to variable & function declarations. bool isDef = false; - if (VarDecl *VD = dyn_cast<VarDecl>(D)) { - isDef = (!VD->hasExternalStorage() || VD->getInit()); - } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - isDef = FD->hasBody(); - } else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D)) { - // We ignore weak import on properties and methods - return; - } else if (!(S.LangOpts.ObjCNonFragileABI && isa<ObjCInterfaceDecl>(D))) { - // Don't issue the warning for darwin as target; yet, ignore the attribute. - if (S.Context.Target.getTriple().getOS() != llvm::Triple::Darwin || - !isa<ObjCInterfaceDecl>(D)) + if (!D->canBeWeakImported(isDef)) { + if (isDef) + S.Diag(Attr.getLoc(), + diag::warn_attribute_weak_import_invalid_on_definition) + << "weak_import" << 2 /*variable and function*/; + else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) || + (S.Context.Target.getTriple().isOSDarwin() && + isa<ObjCInterfaceDecl>(D))) { + // Nothing to warn about here. + } else S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variable and function*/; - return; - } + << Attr.getName() << ExpectedVariableOrFunction; - // Merge should handle any subsequent violations. - if (isDef) { - S.Diag(Attr.getLoc(), - diag::warn_attribute_weak_import_invalid_on_definition) - << "weak_import" << 2 /*variable and function*/; return; } @@ -1409,7 +1521,7 @@ static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) { static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { + if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } @@ -1419,7 +1531,7 @@ static void HandleNothrowAttr(Decl *d, const AttributeList &Attr, Sema &S) { static void HandleConstAttr(Decl *d, const AttributeList &Attr, Sema &S) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { + if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } @@ -1506,7 +1618,7 @@ static void HandleFormatArgAttr(Decl *d, const AttributeList &Attr, Sema &S) { } if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -1674,7 +1786,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isFunctionOrMethodOrBlock(d) || !hasFunctionProto(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -1807,7 +1919,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, // Try to find the underlying union declaration. RecordDecl *RD = 0; - TypedefDecl *TD = dyn_cast<TypedefDecl>(d); + TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(d); if (TD && TD->getUnderlyingType()->isUnionType()) RD = TD->getUnderlyingType()->getAsUnionType()->getDecl(); else @@ -1815,7 +1927,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, if (!RD || !RD->isUnion()) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 1 /*union*/; + << Attr.getName() << ExpectedUnion; return; } @@ -1998,7 +2110,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { } QualType OldTy; - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) OldTy = TD->getUnderlyingType(); else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) OldTy = VD->getType(); @@ -2097,7 +2209,7 @@ static void HandleModeAttr(Decl *D, const AttributeList &Attr, Sema &S) { } // Install the new type. - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { // FIXME: preserve existing source info. TD->setTypeSourceInfo(S.Context.getTrivialTypeSourceInfo(NewTy)); } else @@ -2113,7 +2225,7 @@ static void HandleNoDebugAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isFunctionOrMethod(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -2129,7 +2241,7 @@ static void HandleNoInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -2146,7 +2258,7 @@ static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr, if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -2157,14 +2269,14 @@ static void HandleNoInstrumentFunctionAttr(Decl *d, const AttributeList &Attr, static void HandleConstantAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (S.LangOpts.CUDA) { // check the attribute arguments. - if (Attr.getNumArgs() != 0) { + if (Attr.hasParameterOrArguments()) { S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; return; } if (!isa<VarDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 12 /*variable*/; + << Attr.getName() << ExpectedVariable; return; } @@ -2184,7 +2296,7 @@ static void HandleDeviceAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isa<FunctionDecl>(d) && !isa<VarDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 2 /*variable and function*/; + << Attr.getName() << ExpectedVariableOrFunction; return; } @@ -2204,7 +2316,7 @@ static void HandleGlobalAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -2239,7 +2351,7 @@ static void HandleHostAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isa<FunctionDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -2259,7 +2371,7 @@ static void HandleSharedAttr(Decl *d, const AttributeList &Attr, Sema &S) { if (!isa<VarDecl>(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 12 /*variable*/; + << Attr.getName() << ExpectedVariable; return; } @@ -2279,7 +2391,7 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) { FunctionDecl *Fn = dyn_cast<FunctionDecl>(d); if (Fn == 0) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunction; return; } @@ -2302,7 +2414,7 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) { if (!isa<ObjCMethodDecl>(d)) { S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << attr.getName() << 0 /*function*/; + << attr.getName() << ExpectedFunctionOrMethod; return; } @@ -2322,6 +2434,30 @@ static void HandleCallConvAttr(Decl *d, const AttributeList &attr, Sema &S) { case AttributeList::AT_pascal: d->addAttr(::new (S.Context) PascalAttr(attr.getLoc(), S.Context)); return; + case AttributeList::AT_pcs: { + Expr *Arg = attr.getArg(0); + StringLiteral *Str = dyn_cast<StringLiteral>(Arg); + if (Str == 0 || Str->isWide()) { + S.Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "pcs" << 1; + attr.setInvalid(); + return; + } + + llvm::StringRef StrRef = Str->getString(); + PcsAttr::PCSType PCS; + if (StrRef == "aapcs") + PCS = PcsAttr::AAPCS; + else if (StrRef == "aapcs-vfp") + PCS = PcsAttr::AAPCS_VFP; + else { + S.Diag(attr.getLoc(), diag::err_invalid_pcs); + attr.setInvalid(); + return; + } + + d->addAttr(::new (S.Context) PcsAttr(attr.getLoc(), S.Context, PCS)); + } default: llvm_unreachable("unexpected attribute kind"); return; @@ -2337,19 +2473,42 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { if (attr.isInvalid()) return true; - if (attr.getNumArgs() != 0) { + if ((attr.getNumArgs() != 0 && + !(attr.getKind() == AttributeList::AT_pcs && attr.getNumArgs() == 1)) || + attr.getParameterName()) { Diag(attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0; attr.setInvalid(); return true; } - // TODO: diagnose uses of these conventions on the wrong target. + // TODO: diagnose uses of these conventions on the wrong target. Or, better + // move to TargetAttributesSema one day. switch (attr.getKind()) { case AttributeList::AT_cdecl: CC = CC_C; break; case AttributeList::AT_fastcall: CC = CC_X86FastCall; break; case AttributeList::AT_stdcall: CC = CC_X86StdCall; break; case AttributeList::AT_thiscall: CC = CC_X86ThisCall; break; case AttributeList::AT_pascal: CC = CC_X86Pascal; break; + case AttributeList::AT_pcs: { + Expr *Arg = attr.getArg(0); + StringLiteral *Str = dyn_cast<StringLiteral>(Arg); + if (Str == 0 || Str->isWide()) { + Diag(attr.getLoc(), diag::err_attribute_argument_n_not_string) + << "pcs" << 1; + attr.setInvalid(); + return true; + } + + llvm::StringRef StrRef = Str->getString(); + if (StrRef == "aapcs") { + CC = CC_AAPCS; + break; + } else if (StrRef == "aapcs-vfp") { + CC = CC_AAPCS_VFP; + break; + } + // FALLS THROUGH + } default: llvm_unreachable("unexpected attribute kind"); return true; } @@ -2365,7 +2524,7 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &attr, Sema &S) { if (!isa<ObjCMethodDecl>(d)) { S.Diag(attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << attr.getName() << 0 /*function*/; + << attr.getName() << ExpectedFunctionOrMethod; return; } @@ -2416,14 +2575,14 @@ static void HandleLaunchBoundsAttr(Decl *d, const AttributeList &Attr, Sema &S){ if (S.LangOpts.CUDA) { // check the attribute arguments. if (Attr.getNumArgs() != 1 && Attr.getNumArgs() != 2) { - S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) - << "1 or 2"; + // FIXME: 0 is not okay. + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) << 2; return; } if (!isFunctionOrMethod(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << 0 /*function*/; + << Attr.getName() << ExpectedFunctionOrMethod; return; } @@ -2472,7 +2631,7 @@ static void HandleNSConsumedAttr(Decl *d, const AttributeList &attr, Sema &S) { ParmVarDecl *param = dyn_cast<ParmVarDecl>(d); if (!param) { S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(attr.getLoc()) << attr.getName() << 4 /*parameter*/; + << SourceRange(attr.getLoc()) << attr.getName() << ExpectedParameter; return; } @@ -2501,7 +2660,7 @@ static void HandleNSConsumesSelfAttr(Decl *d, const AttributeList &attr, Sema &S) { if (!isa<ObjCMethodDecl>(d)) { S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) - << SourceRange(attr.getLoc()) << attr.getName() << 13 /*method*/; + << SourceRange(attr.getLoc()) << attr.getName() << ExpectedMethod; return; } @@ -2520,7 +2679,7 @@ static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &attr, else { S.Diag(d->getLocStart(), diag::warn_attribute_wrong_decl_type) << SourceRange(attr.getLoc()) << attr.getName() - << 3 /* function or method */; + << ExpectedFunctionOrMethod; return; } @@ -2664,6 +2823,7 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, case AttributeList::AT_IBOutletCollection: HandleIBOutletCollection(D, Attr, S); break; case AttributeList::AT_address_space: + case AttributeList::AT_opencl_image_access: case AttributeList::AT_objc_gc: case AttributeList::AT_vector_size: case AttributeList::AT_neon_vector_type: @@ -2684,6 +2844,7 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, case AttributeList::AT_analyzer_noreturn: HandleAnalyzerNoReturnAttr (D, Attr, S); break; case AttributeList::AT_annotate: HandleAnnotateAttr (D, Attr, S); break; + case AttributeList::AT_availability:HandleAvailabilityAttr(D, Attr, S); break; case AttributeList::AT_carries_dependency: HandleDependencyAttr (D, Attr, S); break; case AttributeList::AT_common: HandleCommonAttr (D, Attr, S); break; @@ -2736,6 +2897,7 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, HandleInitPriorityAttr(D, Attr, S); break; case AttributeList::AT_packed: HandlePackedAttr (D, Attr, S); break; + case AttributeList::AT_MsStruct: HandleMsStructAttr (D, Attr, S); break; case AttributeList::AT_section: HandleSectionAttr (D, Attr, S); break; case AttributeList::AT_unavailable: HandleUnavailableAttr (D, Attr, S); break; case AttributeList::AT_unused: HandleUnusedAttr (D, Attr, S); break; @@ -2752,6 +2914,9 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, case AttributeList::AT_objc_exception: HandleObjCExceptionAttr(D, Attr, S); break; + case AttributeList::AT_objc_method_family: + HandleObjCMethodFamilyAttr(D, Attr, S); + break; case AttributeList::AT_nsobject: HandleObjCNSObject (D, Attr, S); break; case AttributeList::AT_blocks: HandleBlocksAttr (D, Attr, S); break; case AttributeList::AT_sentinel: HandleSentinelAttr (D, Attr, S); break; @@ -2772,6 +2937,7 @@ static void ProcessInheritableDeclAttr(Scope *scope, Decl *D, case AttributeList::AT_fastcall: case AttributeList::AT_thiscall: case AttributeList::AT_pascal: + case AttributeList::AT_pcs: HandleCallConvAttr(D, Attr, S); break; case AttributeList::AT_opencl_kernel_function: @@ -2837,6 +3003,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) { NamedDecl *NewD = 0; if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { NewD = FunctionDecl::Create(FD->getASTContext(), FD->getDeclContext(), + FD->getInnerLocStart(), FD->getLocation(), DeclarationName(II), FD->getType(), FD->getTypeSourceInfo()); if (FD->getQualifier()) { @@ -2845,7 +3012,7 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II) { } } else if (VarDecl *VD = dyn_cast<VarDecl>(ND)) { NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(), - VD->getLocation(), II, + VD->getInnerLocStart(), VD->getLocation(), II, VD->getType(), VD->getTypeSourceInfo(), VD->getStorageClass(), VD->getStorageClassAsWritten()); @@ -2986,14 +3153,14 @@ void Sema::DelayedDiagnostics::popParsingDecl(Sema &S, ParsingDeclState state, // Destroy all the delayed diagnostics we're about to pop off. for (unsigned i = state.SavedStackSize, e = DD.StackSize; i != e; ++i) - DD.Stack[i].destroy(); + DD.Stack[i].Destroy(); DD.StackSize = state.SavedStackSize; } static bool isDeclDeprecated(Decl *D) { do { - if (D->hasAttr<DeprecatedAttr>()) + if (D->isDeprecated()) return true; } while ((D = cast_or_null<Decl>(D->getDeclContext()))); return false; @@ -3016,7 +3183,7 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message, SourceLocation Loc, - bool UnknownObjCClass) { + const ObjCInterfaceDecl *UnknownObjCClass) { // Delay if we're currently parsing a declaration. if (DelayedDiagnostics.shouldDelayDiagnostics()) { DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D, Message)); @@ -3032,7 +3199,9 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, llvm::StringRef Message, else { if (!UnknownObjCClass) Diag(Loc, diag::warn_deprecated) << D->getDeclName(); - else + else { Diag(Loc, diag::warn_deprecated_fwdclass_message) << D->getDeclName(); + Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); + } } } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp index f483262..27632a1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp @@ -18,9 +18,11 @@ #include "clang/Sema/Lookup.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/CharUnits.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclVisitor.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" @@ -287,17 +289,37 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { ParmVarDecl *NewParam = New->getParamDecl(p); if (OldParam->hasDefaultArg() && NewParam->hasDefaultArg()) { + + unsigned DiagDefaultParamID = + diag::err_param_default_argument_redefinition; + + // MSVC accepts that default parameters be redefined for member functions + // of template class. The new default parameter's value is ignored. + Invalid = true; + if (getLangOptions().Microsoft) { + CXXMethodDecl* MD = dyn_cast<CXXMethodDecl>(New); + if (MD && MD->getParent()->getDescribedClassTemplate()) { + // Merge the old default argument into the new parameter. + NewParam->setHasInheritedDefaultArg(); + if (OldParam->hasUninstantiatedDefaultArg()) + NewParam->setUninstantiatedDefaultArg( + OldParam->getUninstantiatedDefaultArg()); + else + NewParam->setDefaultArg(OldParam->getInit()); + DiagDefaultParamID = diag::warn_param_default_argument_redefinition; + Invalid = false; + } + } + // FIXME: If we knew where the '=' was, we could easily provide a fix-it // hint here. Alternatively, we could walk the type-source information // for NewParam to find the last source location in the type... but it // isn't worth the effort right now. This is the kind of test case that // is hard to get right: - // int f(int); // void g(int (*fp)(int) = f); // void g(int (*fp)(int) = &f); - Diag(NewParam->getLocation(), - diag::err_param_default_argument_redefinition) + Diag(NewParam->getLocation(), DiagDefaultParamID) << NewParam->getDefaultArgRange(); // Look for the function declaration where the default argument was @@ -312,7 +334,6 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { Diag(OldParam->getLocation(), diag::note_previous_definition) << OldParam->getDefaultArgRange(); - Invalid = true; } else if (OldParam->hasDefaultArg()) { // Merge the old default argument into the new parameter. // It's important to use getInit() here; getDefaultArg() @@ -382,6 +403,48 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old) { return Invalid; } +/// \brief Merge the exception specifications of two variable declarations. +/// +/// This is called when there's a redeclaration of a VarDecl. The function +/// checks if the redeclaration might have an exception specification and +/// validates compatibility and merges the specs if necessary. +void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) { + // Shortcut if exceptions are disabled. + if (!getLangOptions().CXXExceptions) + return; + + assert(Context.hasSameType(New->getType(), Old->getType()) && + "Should only be called if types are otherwise the same."); + + QualType NewType = New->getType(); + QualType OldType = Old->getType(); + + // We're only interested in pointers and references to functions, as well + // as pointers to member functions. + if (const ReferenceType *R = NewType->getAs<ReferenceType>()) { + NewType = R->getPointeeType(); + OldType = OldType->getAs<ReferenceType>()->getPointeeType(); + } else if (const PointerType *P = NewType->getAs<PointerType>()) { + NewType = P->getPointeeType(); + OldType = OldType->getAs<PointerType>()->getPointeeType(); + } else if (const MemberPointerType *M = NewType->getAs<MemberPointerType>()) { + NewType = M->getPointeeType(); + OldType = OldType->getAs<MemberPointerType>()->getPointeeType(); + } + + if (!NewType->isFunctionProtoType()) + return; + + // There's lots of special cases for functions. For function pointers, system + // libraries are hopefully not as broken so that we don't need these + // workarounds. + if (CheckEquivalentExceptionSpec( + OldType->getAs<FunctionProtoType>(), Old->getLocation(), + NewType->getAs<FunctionProtoType>(), New->getLocation())) { + New->setInvalidDecl(); + } +} + /// CheckCXXDefaultArguments - Verify that the default arguments for a /// function declaration are well-formed according to C++ /// [dcl.fct.default]. @@ -520,10 +583,9 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl); assert(CXXBaseDecl && "Base type is not a C++ type"); - // C++ [class.derived]p2: - // If a class is marked with the class-virt-specifier final and it appears - // as a base-type-specifier in a base-clause (10 class.derived), the program - // is ill-formed. + // C++ [class]p3: + // If a class is marked final and it appears as a base-type-specifier in + // base-clause, the program is ill-formed. if (CXXBaseDecl->hasAttr<FinalAttr>()) { Diag(BaseLoc, diag::err_class_marked_final_used_as_base) << CXXBaseDecl->getDeclName(); @@ -876,26 +938,6 @@ void Sema::CheckOverrideControl(const Decl *D) { << MD->getDeclName(); return; } - - // C++0x [class.derived]p8: - // In a class definition marked with the class-virt-specifier explicit, - // if a virtual member function that is neither implicitly-declared nor a - // destructor overrides a member function of a base class and it is not - // marked with the virt-specifier override, the program is ill-formed. - if (MD->getParent()->hasAttr<ExplicitAttr>() && !isa<CXXDestructorDecl>(MD) && - HasOverriddenMethods && !MD->hasAttr<OverrideAttr>()) { - llvm::SmallVector<const CXXMethodDecl*, 4> - OverriddenMethods(MD->begin_overridden_methods(), - MD->end_overridden_methods()); - - Diag(MD->getLocation(), diag::err_function_overriding_without_override) - << MD->getDeclName() - << (unsigned)OverriddenMethods.size(); - - for (unsigned I = 0; I != OverriddenMethods.size(); ++I) - Diag(OverriddenMethods[I]->getLocation(), - diag::note_overridden_virtual_function); - } } /// CheckIfOverriddenFunctionIsMarkedFinal - Checks whether a virtual member @@ -1068,6 +1110,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MD->addAttr(new (Context) FinalAttr(VS.getFinalLoc(), Context)); } + if (VS.getLastLocation().isValid()) { + // Update the end location of a method that has a virt-specifiers. + if (CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Member)) + MD->setRangeEnd(VS.getLastLocation()); + } + CheckOverrideControl(Member); assert((Name || isInstField) && "No identifier for non-field ?"); @@ -1225,10 +1273,9 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, if (!NotUnknownSpecialization) { // When the scope specifier can refer to a member of an unknown // specialization, we take it as a type name. - BaseType = CheckTypenameType(ETK_None, - (NestedNameSpecifier *)SS.getScopeRep(), - *MemberOrBase, SourceLocation(), - SS.getRange(), IdLoc); + BaseType = CheckTypenameType(ETK_None, SourceLocation(), + SS.getWithLocInContext(Context), + *MemberOrBase, IdLoc); if (BaseType.isNull()) return true; @@ -1356,7 +1403,7 @@ static bool InitExprContainsUninitializedFields(const Stmt *S, *L = ME->getMemberLoc(); return true; } - } else if (isa<SizeOfAlignOfExpr>(S)) { + } else if (isa<UnaryExprOrTypeTraitExpr>(S)) { // sizeof/alignof doesn't reference contents, do not warn. return false; } else if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(S)) { @@ -1476,17 +1523,61 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr **Args, MemInitResult Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr **Args, unsigned NumArgs, + SourceLocation NameLoc, SourceLocation LParenLoc, SourceLocation RParenLoc, - CXXRecordDecl *ClassDecl, - SourceLocation EllipsisLoc) { + CXXRecordDecl *ClassDecl) { SourceLocation Loc = TInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!LangOpts.CPlusPlus0x) return Diag(Loc, diag::err_delegation_0x_only) << TInfo->getTypeLoc().getLocalSourceRange(); - return Diag(Loc, diag::err_delegation_unimplemented) - << TInfo->getTypeLoc().getLocalSourceRange(); + // Initialize the object. + InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation( + QualType(ClassDecl->getTypeForDecl(), 0)); + InitializationKind Kind = + InitializationKind::CreateDirect(NameLoc, LParenLoc, RParenLoc); + + InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs); + + ExprResult DelegationInit = + InitSeq.Perform(*this, DelegationEntity, Kind, + MultiExprArg(*this, Args, NumArgs), 0); + if (DelegationInit.isInvalid()) + return true; + + CXXConstructExpr *ConExpr = cast<CXXConstructExpr>(DelegationInit.get()); + CXXConstructorDecl *Constructor = ConExpr->getConstructor(); + assert(Constructor && "Delegating constructor with no target?"); + + CheckImplicitConversions(DelegationInit.get(), LParenLoc); + + // C++0x [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + DelegationInit = MaybeCreateExprWithCleanups(DelegationInit); + if (DelegationInit.isInvalid()) + return true; + + // If we are in a dependent context, template instantiation will + // perform this type-checking again. Just save the arguments that we + // received in a ParenListExpr. + // FIXME: This isn't quite ideal, since our ASTs don't capture all + // of the information that we have about the base + // initializer. However, deconstructing the ASTs is a dicey process, + // and this approach is far more likely to get the corner cases right. + if (CurContext->isDependentContext()) { + ExprResult Init + = Owned(new (Context) ParenListExpr(Context, LParenLoc, Args, + NumArgs, RParenLoc)); + return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, + Constructor, Init.takeAs<Expr>(), + RParenLoc); + } + + return new (Context) CXXCtorInitializer(Context, Loc, LParenLoc, Constructor, + DelegationInit.takeAs<Expr>(), + RParenLoc); } MemInitResult @@ -1538,9 +1629,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, if (!Dependent) { if (Context.hasSameUnqualifiedType(QualType(ClassDecl->getTypeForDecl(),0), BaseType)) - return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs, - LParenLoc, RParenLoc, ClassDecl, - EllipsisLoc); + return BuildDelegatingInitializer(BaseTInfo, Args, NumArgs, BaseLoc, + LParenLoc, RParenLoc, ClassDecl); FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec, VirtualBaseSpec); @@ -1684,7 +1774,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, QualType ParamType = Param->getType().getNonReferenceType(); Expr *CopyCtorArg = - DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, + DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param, Constructor->getLocation(), ParamType, VK_LValue, 0); @@ -1695,9 +1785,9 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, CXXCastPath BasePath; BasePath.push_back(BaseSpec); - SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy, - CK_UncheckedDerivedToBase, - VK_LValue, &BasePath); + CopyCtorArg = SemaRef.ImpCastExprToType(CopyCtorArg, ArgTy, + CK_UncheckedDerivedToBase, + VK_LValue, &BasePath).take(); InitializationKind InitKind = InitializationKind::CreateDirect(Constructor->getLocation(), @@ -1745,7 +1835,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, QualType ParamType = Param->getType().getNonReferenceType(); Expr *MemberExprBase = - DeclRefExpr::Create(SemaRef.Context, 0, SourceRange(), Param, + DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), Param, Loc, ParamType, VK_LValue, 0); // Build a reference to this field within the parameter. @@ -1783,7 +1873,7 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, IterationVarName = &SemaRef.Context.Idents.get(OS.str()); } VarDecl *IterationVar - = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, + = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, Loc, IterationVarName, SizeType, SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None, SC_None); @@ -1978,6 +2068,30 @@ static bool CollectFieldInitializer(BaseAndFieldInfo &Info, return false; } + +bool +Sema::SetDelegatingInitializer(CXXConstructorDecl *Constructor, + CXXCtorInitializer *Initializer) { + Constructor->setNumCtorInitializers(1); + CXXCtorInitializer **initializer = + new (Context) CXXCtorInitializer*[1]; + memcpy(initializer, &Initializer, sizeof (CXXCtorInitializer*)); + Constructor->setCtorInitializers(initializer); + + // FIXME: This doesn't catch indirect loops yet + CXXConstructorDecl *Target = Initializer->getTargetConstructor(); + while (Target) { + if (Target == Constructor) { + Diag(Initializer->getSourceLocation(), diag::err_delegating_ctor_loop) + << Constructor; + return true; + } + Target = Target->getTargetConstructor(); + } + + return false; +} + bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, @@ -2340,10 +2454,23 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl, if (CheckRedundantInit(*this, Init, Members[Field]) || CheckRedundantUnionInit(*this, Init, MemberUnions)) HadError = true; - } else { + } else if (Init->isBaseInitializer()) { void *Key = GetKeyForBase(Context, QualType(Init->getBaseClass(), 0)); if (CheckRedundantInit(*this, Init, Members[Key])) HadError = true; + } else { + assert(Init->isDelegatingInitializer()); + // This must be the only initializer + if (i != 0 || NumMemInits > 1) { + Diag(MemInits[0]->getSourceLocation(), + diag::err_delegating_initializer_alone) + << MemInits[0]->getSourceRange(); + HadError = true; + // We will treat this as being the only initializer. + } + SetDelegatingInitializer(Constructor, *MemInits); + // Return immediately as the initializer is set. + return; } } @@ -2380,10 +2507,13 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, continue; CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (FieldClassDecl->isInvalidDecl()) + continue; if (FieldClassDecl->hasTrivialDestructor()) continue; CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl); + assert(Dtor && "No dtor found for FieldClassDecl!"); CheckDestructorAccess(Field->getLocation(), Dtor, PDiag(diag::err_access_dtor_field) << Field->getDeclName() @@ -2404,12 +2534,16 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, if (Base->isVirtual()) DirectVirtualBases.insert(RT); - // Ignore trivial destructors. CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + // If our base class is invalid, we probably can't get its dtor anyway. + if (BaseClassDecl->isInvalidDecl()) + continue; + // Ignore trivial destructors. if (BaseClassDecl->hasTrivialDestructor()) continue; CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl); + assert(Dtor && "No dtor found for BaseClassDecl!"); // FIXME: caret should be on the start of the class name CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor, @@ -2431,12 +2565,16 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, if (DirectVirtualBases.count(RT)) continue; - // Ignore trivial destructors. CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); + // If our base class is invalid, we probably can't get its dtor anyway. + if (BaseClassDecl->isInvalidDecl()) + continue; + // Ignore trivial destructors. if (BaseClassDecl->hasTrivialDestructor()) continue; CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl); + assert(Dtor && "No dtor found for BaseClassDecl!"); CheckDestructorAccess(ClassDecl->getLocation(), Dtor, PDiag(diag::err_access_dtor_vbase) << VBase->getType()); @@ -2786,7 +2924,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { for (CXXRecordDecl::method_iterator M = Record->method_begin(), MEnd = Record->method_end(); M != MEnd; ++M) { - DiagnoseHiddenVirtualMethods(Record, *M); + if (!(*M)->isStatic()) + DiagnoseHiddenVirtualMethods(Record, *M); } } @@ -2801,12 +2940,14 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { } /// \brief Data used with FindHiddenVirtualMethod -struct FindHiddenVirtualMethodData { - Sema *S; - CXXMethodDecl *Method; - llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverridenAndUsingBaseMethods; - llvm::SmallVector<CXXMethodDecl *, 8> OverloadedMethods; -}; +namespace { + struct FindHiddenVirtualMethodData { + Sema *S; + CXXMethodDecl *Method; + llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverridenAndUsingBaseMethods; + llvm::SmallVector<CXXMethodDecl *, 8> OverloadedMethods; + }; +} /// \brief Member lookup function that determines whether a given C++ /// method overloads virtual methods in a base class without overriding any, @@ -2917,53 +3058,101 @@ namespace { /// implicitly-declared special member functions. class ImplicitExceptionSpecification { ASTContext &Context; - bool AllowsAllExceptions; + // We order exception specifications thus: + // noexcept is the most restrictive, but is only used in C++0x. + // throw() comes next. + // Then a throw(collected exceptions) + // Finally no specification. + // throw(...) is used instead if any called function uses it. + ExceptionSpecificationType ComputedEST; llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen; llvm::SmallVector<QualType, 4> Exceptions; - + + void ClearExceptions() { + ExceptionsSeen.clear(); + Exceptions.clear(); + } + public: explicit ImplicitExceptionSpecification(ASTContext &Context) - : Context(Context), AllowsAllExceptions(false) { } - - /// \brief Whether the special member function should have any - /// exception specification at all. - bool hasExceptionSpecification() const { - return !AllowsAllExceptions; + : Context(Context), ComputedEST(EST_BasicNoexcept) { + if (!Context.getLangOptions().CPlusPlus0x) + ComputedEST = EST_DynamicNone; } - - /// \brief Whether the special member function should have a - /// throw(...) exception specification (a Microsoft extension). - bool hasAnyExceptionSpecification() const { - return false; + + /// \brief Get the computed exception specification type. + ExceptionSpecificationType getExceptionSpecType() const { + assert(ComputedEST != EST_ComputedNoexcept && + "noexcept(expr) should not be a possible result"); + return ComputedEST; } - + /// \brief The number of exceptions in the exception specification. unsigned size() const { return Exceptions.size(); } - + /// \brief The set of exceptions in the exception specification. const QualType *data() const { return Exceptions.data(); } - - /// \brief Note that + + /// \brief Integrate another called method into the collected data. void CalledDecl(CXXMethodDecl *Method) { - // If we already know that we allow all exceptions, do nothing. - if (AllowsAllExceptions || !Method) + // If we have an MSAny spec already, don't bother. + if (!Method || ComputedEST == EST_MSAny) return; - + const FunctionProtoType *Proto = Method->getType()->getAs<FunctionProtoType>(); - + + ExceptionSpecificationType EST = Proto->getExceptionSpecType(); + // If this function can throw any exceptions, make a note of that. - if (!Proto->hasExceptionSpec() || Proto->hasAnyExceptionSpec()) { - AllowsAllExceptions = true; - ExceptionsSeen.clear(); - Exceptions.clear(); + if (EST == EST_MSAny || EST == EST_None) { + ClearExceptions(); + ComputedEST = EST; return; } - + + // If this function has a basic noexcept, it doesn't affect the outcome. + if (EST == EST_BasicNoexcept) + return; + + // If we have a throw-all spec at this point, ignore the function. + if (ComputedEST == EST_None) + return; + + // If we're still at noexcept(true) and there's a nothrow() callee, + // change to that specification. + if (EST == EST_DynamicNone) { + if (ComputedEST == EST_BasicNoexcept) + ComputedEST = EST_DynamicNone; + return; + } + + // Check out noexcept specs. + if (EST == EST_ComputedNoexcept) { + FunctionProtoType::NoexceptResult NR = Proto->getNoexceptSpec(Context); + assert(NR != FunctionProtoType::NR_NoNoexcept && + "Must have noexcept result for EST_ComputedNoexcept."); + assert(NR != FunctionProtoType::NR_Dependent && + "Should not generate implicit declarations for dependent cases, " + "and don't know how to handle them anyway."); + + // noexcept(false) -> no spec on the new function + if (NR == FunctionProtoType::NR_Throw) { + ClearExceptions(); + ComputedEST = EST_None; + } + // noexcept(true) won't change anything either. + return; + } + + assert(EST == EST_Dynamic && "EST case not considered earlier."); + assert(ComputedEST != EST_None && + "Shouldn't collect exceptions when throw-all is guaranteed."); + ComputedEST = EST_Dynamic; // Record the exceptions in this function's exception specification. for (FunctionProtoType::exception_iterator E = Proto->exception_begin(), EEnd = Proto->exception_end(); - E != EEnd; ++E) + E != EEnd; ++E) if (ExceptionsSeen.insert(Context.getCanonicalType(*E))) Exceptions.push_back(*E); } @@ -3006,6 +3195,25 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { } } +void Sema::ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D) { + if (!D) + return; + + int NumParamList = D->getNumTemplateParameterLists(); + for (int i = 0; i < NumParamList; i++) { + TemplateParameterList* Params = D->getTemplateParameterList(i); + for (TemplateParameterList::iterator Param = Params->begin(), + ParamEnd = Params->end(); + Param != ParamEnd; ++Param) { + NamedDecl *Named = cast<NamedDecl>(*Param); + if (Named->getDeclName()) { + S->AddDecl(Named); + IdResolver.AddDecl(Named); + } + } + } +} + void Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { if (!D) return; @@ -3256,9 +3464,9 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, // be used as the identifier in the declarator for a destructor // declaration. QualType DeclaratorType = GetTypeFromParser(D.getName().DestructorName); - if (isa<TypedefType>(DeclaratorType)) + if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>()) Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) - << DeclaratorType; + << DeclaratorType << isa<TypeAliasDecl>(TT->getDecl()); // C++ [class.dtor]p2: // A destructor is used to destroy objects of its class type. A @@ -3488,14 +3696,16 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { /// definition. Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, SourceLocation InlineLoc, + SourceLocation NamespaceLoc, SourceLocation IdentLoc, IdentifierInfo *II, SourceLocation LBrace, AttributeList *AttrList) { - // anonymous namespace starts at its left brace + SourceLocation StartLoc = InlineLoc.isValid() ? InlineLoc : NamespaceLoc; + // For anonymous namespace, take the location of the left brace. + SourceLocation Loc = II ? IdentLoc : LBrace; NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, - (II ? IdentLoc : LBrace) , II); - Namespc->setLBracLoc(LBrace); + StartLoc, Loc, II); Namespc->setInline(InlineLoc.isValid()); Scope *DeclRegionScope = NamespcScope->getParent(); @@ -3654,7 +3864,7 @@ static inline NamespaceDecl *getNamespaceDecl(NamedDecl *D) { void Sema::ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace) { NamespaceDecl *Namespc = dyn_cast_or_null<NamespaceDecl>(Dcl); assert(Namespc && "Invalid parameter, expected NamespaceDecl"); - Namespc->setRBracLoc(RBrace); + Namespc->setRBraceLoc(RBrace); PopDeclContext(); if (Namespc->hasAttr<VisibilityAttr>()) PopPragmaVisibility(); @@ -3677,7 +3887,7 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() { // The "std" namespace has not yet been defined, so build one implicitly. StdNamespace = NamespaceDecl::Create(Context, Context.getTranslationUnitDecl(), - SourceLocation(), + SourceLocation(), SourceLocation(), &PP.getIdentifierTable().get("std")); getStdNamespace()->setImplicit(true); } @@ -3685,6 +3895,19 @@ NamespaceDecl *Sema::getOrCreateStdNamespace() { return getStdNamespace(); } +/// \brief Determine whether a using statement is in a context where it will be +/// apply in all contexts. +static bool IsUsingDirectiveInToplevelContext(DeclContext *CurContext) { + switch (CurContext->getDeclKind()) { + case Decl::TranslationUnit: + return true; + case Decl::LinkageSpec: + return IsUsingDirectiveInToplevelContext(CurContext->getParent()); + default: + return false; + } +} + Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, SourceLocation NamespcLoc, @@ -3769,6 +3992,12 @@ Decl *Sema::ActOnUsingDirective(Scope *S, UDir = UsingDirectiveDecl::Create(Context, CurContext, UsingLoc, NamespcLoc, SS.getWithLocInContext(Context), IdentLoc, Named, CommonAncestor); + + if (IsUsingDirectiveInToplevelContext(CurContext) && + !SourceMgr.isFromMainFile(SourceMgr.getInstantiationLoc(IdentLoc))) { + Diag(IdentLoc, diag::warn_using_directive_in_header); + } + PushUsingDirective(S, UDir); } else { Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange(); @@ -3870,8 +4099,8 @@ IsEquivalentForUsingDecl(ASTContext &Context, NamedDecl *D1, NamedDecl *D2, return true; } - if (TypedefDecl *TD1 = dyn_cast<TypedefDecl>(D1)) - if (TypedefDecl *TD2 = dyn_cast<TypedefDecl>(D2)) { + if (TypedefNameDecl *TD1 = dyn_cast<TypedefNameDecl>(D1)) + if (TypedefNameDecl *TD2 = dyn_cast<TypedefNameDecl>(D2)) { SuppressRedeclaration = true; return Context.hasSameType(TD1->getUnderlyingType(), TD2->getUnderlyingType()); @@ -4470,6 +4699,61 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, return true; } +Decl *Sema::ActOnAliasDeclaration(Scope *S, + AccessSpecifier AS, + SourceLocation UsingLoc, + UnqualifiedId &Name, + TypeResult Type) { + assert((S->getFlags() & Scope::DeclScope) && + "got alias-declaration outside of declaration scope"); + + if (Type.isInvalid()) + return 0; + + bool Invalid = false; + DeclarationNameInfo NameInfo = GetNameFromUnqualifiedId(Name); + TypeSourceInfo *TInfo = 0; + GetTypeFromParser(Type.get(), &TInfo); + + if (DiagnoseClassNameShadow(CurContext, NameInfo)) + return 0; + + if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo, + UPPC_DeclarationType)) + Invalid = true; + + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); + LookupName(Previous, S); + + // Warn about shadowing the name of a template parameter. + if (Previous.isSingleResult() && + Previous.getFoundDecl()->isTemplateParameter()) { + if (DiagnoseTemplateParameterShadow(Name.StartLocation, + Previous.getFoundDecl())) + Invalid = true; + Previous.clear(); + } + + assert(Name.Kind == UnqualifiedId::IK_Identifier && + "name in alias declaration must be an identifier"); + TypeAliasDecl *NewTD = TypeAliasDecl::Create(Context, CurContext, UsingLoc, + Name.StartLocation, + Name.Identifier, TInfo); + + NewTD->setAccess(AS); + + if (Invalid) + NewTD->setInvalidDecl(); + + bool Redeclaration = false; + ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration); + + if (!Redeclaration) + PushOnScopeChains(NewTD, S); + + return NewTD; +} + Decl *Sema::ActOnNamespaceAliasDef(Scope *S, SourceLocation NamespaceLoc, SourceLocation AliasLoc, @@ -4609,7 +4893,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( // exception-specification. [...] ImplicitExceptionSpecification ExceptSpec(Context); - // Direct base-class destructors. + // Direct base-class constructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->bases_begin(), BEnd = ClassDecl->bases_end(); B != BEnd; ++B) { @@ -4625,8 +4909,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( ExceptSpec.CalledDecl(Constructor); } } - - // Virtual base-class destructors. + + // Virtual base-class constructors. for (CXXRecordDecl::base_class_iterator B = ClassDecl->vbases_begin(), BEnd = ClassDecl->vbases_end(); B != BEnd; ++B) { @@ -4639,8 +4923,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( ExceptSpec.CalledDecl(Constructor); } } - - // Field destructors. + + // Field constructors. for (RecordDecl::field_iterator F = ClassDecl->field_begin(), FEnd = ClassDecl->field_end(); F != FEnd; ++F) { @@ -4657,19 +4941,19 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( } FunctionProtoType::ExtProtoInfo EPI; - EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification(); - EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification(); + EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); EPI.NumExceptions = ExceptSpec.size(); EPI.Exceptions = ExceptSpec.data(); - + // Create the actual constructor declaration. CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); + SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(ClassType); - DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation()); + DeclarationNameInfo NameInfo(Name, ClassLoc); CXXConstructorDecl *DefaultCon - = CXXConstructorDecl::Create(Context, ClassDecl, NameInfo, + = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Context.getFunctionType(Context.VoidTy, 0, 0, EPI), /*TInfo=*/0, @@ -4714,6 +4998,10 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, Constructor->setUsed(); MarkVTableUsed(CurrentLocation, ClassDecl); + + if (ASTMutationListener *L = getASTMutationListener()) { + L->CompletedImplicitDefinition(Constructor); + } } void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { @@ -4865,15 +5153,16 @@ void Sema::DeclareInheritedConstructors(CXXRecordDecl *ClassDecl) { // user-writtern inline constructor [...] DeclarationNameInfo DNI(CreatedCtorName, UsingLoc); CXXConstructorDecl *NewCtor = CXXConstructorDecl::Create( - Context, ClassDecl, DNI, QualType(NewCtorType, 0), /*TInfo=*/0, - BaseCtor->isExplicit(), /*Inline=*/true, + Context, ClassDecl, UsingLoc, DNI, QualType(NewCtorType, 0), + /*TInfo=*/0, BaseCtor->isExplicit(), /*Inline=*/true, /*ImplicitlyDeclared=*/true); NewCtor->setAccess(BaseCtor->getAccess()); // Build up the parameter decls and add them. llvm::SmallVector<ParmVarDecl *, 16> ParamDecls; for (unsigned i = 0; i < params; ++i) { - ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor, UsingLoc, + ParamDecls.push_back(ParmVarDecl::Create(Context, NewCtor, + UsingLoc, UsingLoc, /*IdentifierInfo=*/0, BaseCtorType->getArgType(i), /*TInfo=*/0, SC_None, @@ -4931,24 +5220,24 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { ExceptSpec.CalledDecl( LookupDestructor(cast<CXXRecordDecl>(RecordTy->getDecl()))); } - + // Create the actual destructor declaration. FunctionProtoType::ExtProtoInfo EPI; - EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification(); - EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification(); + EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); EPI.NumExceptions = ExceptSpec.size(); EPI.Exceptions = ExceptSpec.data(); QualType Ty = Context.getFunctionType(Context.VoidTy, 0, 0, EPI); - + CanQualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); + SourceLocation ClassLoc = ClassDecl->getLocation(); DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); - DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation()); + DeclarationNameInfo NameInfo(Name, ClassLoc); CXXDestructorDecl *Destructor - = CXXDestructorDecl::Create(Context, ClassDecl, NameInfo, Ty, 0, - /*isInline=*/true, - /*isImplicitlyDeclared=*/true); + = CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Ty, 0, + /*isInline=*/true, + /*isImplicitlyDeclared=*/true); Destructor->setAccess(AS_public); Destructor->setImplicit(); Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); @@ -4998,6 +5287,10 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, Destructor->setUsed(); MarkVTableUsed(CurrentLocation, ClassDecl); + + if (ASTMutationListener *L = getASTMutationListener()) { + L->CompletedImplicitDefinition(Destructor); + } } /// \brief Builds a statement that copies the given entity from \p From to @@ -5133,7 +5426,7 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, OS << "__i" << Depth; IterationVarName = &S.Context.Idents.get(OS.str()); } - VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc, + VarDecl *IterationVar = VarDecl::Create(S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType, S.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None, SC_None); @@ -5328,30 +5621,30 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { ExceptSpec.CalledDecl(CopyAssign); } } - + // An implicitly-declared copy assignment operator is an inline public // member of its class. FunctionProtoType::ExtProtoInfo EPI; - EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification(); - EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification(); + EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); EPI.NumExceptions = ExceptSpec.size(); EPI.Exceptions = ExceptSpec.data(); DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); - DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation()); + SourceLocation ClassLoc = ClassDecl->getLocation(); + DeclarationNameInfo NameInfo(Name, ClassLoc); CXXMethodDecl *CopyAssignment - = CXXMethodDecl::Create(Context, ClassDecl, NameInfo, + = CXXMethodDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Context.getFunctionType(RetType, &ArgType, 1, EPI), /*TInfo=*/0, /*isStatic=*/false, /*StorageClassAsWritten=*/SC_None, - /*isInline=*/true); + /*isInline=*/true, + SourceLocation()); CopyAssignment->setAccess(AS_public); CopyAssignment->setImplicit(); CopyAssignment->setTrivial(ClassDecl->hasTrivialCopyAssignment()); // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, - ClassDecl->getLocation(), - /*Id=*/0, + ClassLoc, ClassLoc, /*Id=*/0, ArgType, /*TInfo=*/0, SC_None, SC_None, 0); @@ -5440,21 +5733,19 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Construct the "from" expression, which is an implicit cast to the // appropriately-qualified base type. Expr *From = OtherRef; - ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals), - CK_UncheckedDerivedToBase, - VK_LValue, &BasePath); + From = ImpCastExprToType(From, Context.getQualifiedType(BaseType, OtherQuals), + CK_UncheckedDerivedToBase, + VK_LValue, &BasePath).take(); // Dereference "this". ExprResult To = CreateBuiltinUnaryOp(Loc, UO_Deref, This); // Implicitly cast "this" to the appropriately-qualified base type. - Expr *ToE = To.takeAs<Expr>(); - ImpCastExprToType(ToE, - Context.getCVRQualifiedType(BaseType, - CopyAssignOperator->getTypeQualifiers()), - CK_UncheckedDerivedToBase, - VK_LValue, &BasePath); - To = Owned(ToE); + To = ImpCastExprToType(To.take(), + Context.getCVRQualifiedType(BaseType, + CopyAssignOperator->getTypeQualifiers()), + CK_UncheckedDerivedToBase, + VK_LValue, &BasePath); // Build the copy. StmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType, @@ -5659,6 +5950,10 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, /*isStmtExpr=*/false); assert(!Body.isInvalid() && "Compound statement creation cannot fail"); CopyAssignOperator->setBody(Body.takeAs<Stmt>()); + + if (ASTMutationListener *L = getASTMutationListener()) { + L->CompletedImplicitDefinition(CopyAssignOperator); + } } CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( @@ -5790,20 +6085,20 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ExceptSpec.CalledDecl(CopyConstructor); } } - + // An implicitly-declared copy constructor is an inline public // member of its class. FunctionProtoType::ExtProtoInfo EPI; - EPI.HasExceptionSpec = ExceptSpec.hasExceptionSpecification(); - EPI.HasAnyExceptionSpec = ExceptSpec.hasAnyExceptionSpecification(); + EPI.ExceptionSpecType = ExceptSpec.getExceptionSpecType(); EPI.NumExceptions = ExceptSpec.size(); EPI.Exceptions = ExceptSpec.data(); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); - DeclarationNameInfo NameInfo(Name, ClassDecl->getLocation()); + SourceLocation ClassLoc = ClassDecl->getLocation(); + DeclarationNameInfo NameInfo(Name, ClassLoc); CXXConstructorDecl *CopyConstructor - = CXXConstructorDecl::Create(Context, ClassDecl, NameInfo, + = CXXConstructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, Context.getFunctionType(Context.VoidTy, &ArgType, 1, EPI), /*TInfo=*/0, @@ -5818,7 +6113,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // Add the parameter to the constructor. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyConstructor, - ClassDecl->getLocation(), + ClassLoc, ClassLoc, /*IdentifierInfo=*/0, ArgType, /*TInfo=*/0, SC_None, @@ -5859,6 +6154,10 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, } CopyConstructor->setUsed(); + + if (ASTMutationListener *L = getASTMutationListener()) { + L->CompletedImplicitDefinition(CopyConstructor); + } } ExprResult @@ -5903,6 +6202,13 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, unsigned NumExprs = ExprArgs.size(); Expr **Exprs = (Expr **)ExprArgs.release(); + for (specific_attr_iterator<NonNullAttr> + i = Constructor->specific_attr_begin<NonNullAttr>(), + e = Constructor->specific_attr_end<NonNullAttr>(); i != e; ++i) { + const NonNullAttr *NonNull = *i; + CheckNonNullArguments(NonNull, ExprArgs.get(), ConstructLoc); + } + MarkDeclarationReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, Constructor, Elidable, Exprs, NumExprs, @@ -5932,20 +6238,29 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD, } void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { + if (VD->isInvalidDecl()) return; + CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl()); - if (!ClassDecl->isInvalidDecl() && !VD->isInvalidDecl() && - !ClassDecl->hasTrivialDestructor() && !ClassDecl->isDependentContext()) { - CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); - MarkDeclarationReferenced(VD->getLocation(), Destructor); - CheckDestructorAccess(VD->getLocation(), Destructor, - PDiag(diag::err_access_dtor_var) - << VD->getDeclName() - << VD->getType()); + if (ClassDecl->isInvalidDecl()) return; + if (ClassDecl->hasTrivialDestructor()) return; + if (ClassDecl->isDependentContext()) return; - // TODO: this should be re-enabled for static locals by !CXAAtExit - if (!VD->isInvalidDecl() && VD->hasGlobalStorage() && !VD->isStaticLocal()) - Diag(VD->getLocation(), diag::warn_global_destructor); - } + CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); + MarkDeclarationReferenced(VD->getLocation(), Destructor); + CheckDestructorAccess(VD->getLocation(), Destructor, + PDiag(diag::err_access_dtor_var) + << VD->getDeclName() + << VD->getType()); + + if (!VD->hasGlobalStorage()) return; + + // Emit warning for non-trivial dtor in global scope (a real global, + // class-static, function-static). + Diag(VD->getLocation(), diag::warn_exit_time_destructor); + + // TODO: this should be re-enabled for static locals by !CXAAtExit + if (!VD->isStaticLocal()) + Diag(VD->getLocation(), diag::warn_global_destructor); } /// AddCXXDirectInitializerToDecl - This action is called immediately after @@ -5983,15 +6298,17 @@ void Sema::AddCXXDirectInitializerToDecl(Decl *RealDecl, } Expr *Init = Exprs.get()[0]; - QualType DeducedType; - if (!DeduceAutoType(VDecl->getType(), Init, DeducedType)) { + TypeSourceInfo *DeducedType = 0; + if (!DeduceAutoType(VDecl->getTypeSourceInfo(), Init, DeducedType)) Diag(VDecl->getLocation(), diag::err_auto_var_deduction_failure) << VDecl->getDeclName() << VDecl->getType() << Init->getType() << Init->getSourceRange(); + if (!DeducedType) { RealDecl->setInvalidDecl(); return; } - VDecl->setType(DeducedType); + VDecl->setTypeSourceInfo(DeducedType); + VDecl->setType(DeducedType->getType()); // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. @@ -6523,8 +6840,7 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, // FIXME: Add all the various semantics of linkage specifications LinkageSpecDecl *D = LinkageSpecDecl::Create(Context, CurContext, - LangLoc, Language, - LBraceLoc.isValid()); + ExternLoc, LangLoc, Language); CurContext->addDecl(D); PushDeclContext(S, D); return D; @@ -6535,20 +6851,26 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, /// valid, it's the position of the closing '}' brace in a linkage /// specification that uses braces. Decl *Sema::ActOnFinishLinkageSpecification(Scope *S, - Decl *LinkageSpec, - SourceLocation RBraceLoc) { - if (LinkageSpec) + Decl *LinkageSpec, + SourceLocation RBraceLoc) { + if (LinkageSpec) { + if (RBraceLoc.isValid()) { + LinkageSpecDecl* LSDecl = cast<LinkageSpecDecl>(LinkageSpec); + LSDecl->setRBraceLoc(RBraceLoc); + } PopDeclContext(); + } return LinkageSpec; } /// \brief Perform semantic analysis for the variable declaration that /// occurs within a C++ catch clause, returning the newly-created /// variable. -VarDecl *Sema::BuildExceptionDeclaration(Scope *S, +VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, - IdentifierInfo *Name, - SourceLocation Loc) { + SourceLocation StartLoc, + SourceLocation Loc, + IdentifierInfo *Name) { bool Invalid = false; QualType ExDeclType = TInfo->getType(); @@ -6608,19 +6930,15 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, Diag(Loc, diag::err_objc_object_catch); Invalid = true; } else if (T->isObjCObjectPointerType()) { - if (!getLangOptions().NeXTRuntime) { - Diag(Loc, diag::err_objc_pointer_cxx_catch_gnu); - Invalid = true; - } else if (!getLangOptions().ObjCNonFragileABI) { + if (!getLangOptions().ObjCNonFragileABI) { Diag(Loc, diag::err_objc_pointer_cxx_catch_fragile); Invalid = true; } } } - VarDecl *ExDecl = VarDecl::Create(Context, CurContext, Loc, - Name, ExDeclType, TInfo, SC_None, - SC_None); + VarDecl *ExDecl = VarDecl::Create(Context, CurContext, StartLoc, Loc, Name, + ExDeclType, TInfo, SC_None, SC_None); ExDecl->setExceptionVariable(true); if (!Invalid) { @@ -6703,9 +7021,9 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { } VarDecl *ExDecl = BuildExceptionDeclaration(S, TInfo, - D.getIdentifier(), - D.getIdentifierLoc()); - + D.getSourceRange().getBegin(), + D.getIdentifierLoc(), + D.getIdentifier()); if (Invalid) ExDecl->setInvalidDecl(); @@ -6719,21 +7037,23 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { return ExDecl; } -Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, +Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, - Expr *AssertMessageExpr_) { + Expr *AssertMessageExpr_, + SourceLocation RParenLoc) { StringLiteral *AssertMessage = cast<StringLiteral>(AssertMessageExpr_); if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent()) { llvm::APSInt Value(32); if (!AssertExpr->isIntegerConstantExpr(Value, Context)) { - Diag(AssertLoc, diag::err_static_assert_expression_is_not_constant) << + Diag(StaticAssertLoc, + diag::err_static_assert_expression_is_not_constant) << AssertExpr->getSourceRange(); return 0; } if (Value == 0) { - Diag(AssertLoc, diag::err_static_assert_failed) + Diag(StaticAssertLoc, diag::err_static_assert_failed) << AssertMessage->getString() << AssertExpr->getSourceRange(); } } @@ -6741,8 +7061,8 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation AssertLoc, if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression)) return 0; - Decl *Decl = StaticAssertDecl::Create(Context, CurContext, AssertLoc, - AssertExpr, AssertMessage); + Decl *Decl = StaticAssertDecl::Create(Context, CurContext, StaticAssertLoc, + AssertExpr, AssertMessage, RParenLoc); CurContext->addDecl(Decl); return Decl; @@ -6815,7 +7135,6 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); bool isExplicitSpecialization = false; - unsigned NumMatchedTemplateParamLists = TempParamLists.size(); bool Invalid = false; if (TemplateParameterList *TemplateParams @@ -6825,16 +7144,16 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, /*friend*/ true, isExplicitSpecialization, Invalid)) { - --NumMatchedTemplateParamLists; - if (TemplateParams->size() > 0) { // This is a declaration of a class template. if (Invalid) return 0; - + return CheckClassTemplate(S, TagSpec, TUK_Friend, TagLoc, SS, Name, NameLoc, Attr, - TemplateParams, AS_public).take(); + TemplateParams, AS_public, + TempParamLists.size() - 1, + (TemplateParameterList**) TempParamLists.release()).take(); } else { // The "template<>" header is extraneous. Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) @@ -6848,7 +7167,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, assert(SS.isNotEmpty() && "valid templated tag with no SS and no direct?"); bool isAllExplicitSpecializations = true; - for (unsigned I = 0; I != NumMatchedTemplateParamLists; ++I) { + for (unsigned I = TempParamLists.size(); I-- > 0; ) { if (TempParamLists.get()[I]->size()) { isAllExplicitSpecializations = false; break; @@ -6861,10 +7180,11 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, // about the template header and build an appropriate non-templated // friend. TODO: for source fidelity, remember the headers. if (isAllExplicitSpecializations) { + NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); ElaboratedTypeKeyword Keyword = TypeWithKeyword::getKeywordForTagTypeKind(Kind); - QualType T = CheckTypenameType(Keyword, SS.getScopeRep(), *Name, - TagLoc, SS.getRange(), NameLoc); + QualType T = CheckTypenameType(Keyword, TagLoc, QualifierLoc, + *Name, NameLoc); if (T.isNull()) return 0; @@ -6872,12 +7192,12 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, if (isa<DependentNameType>(T)) { DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); TL.setKeywordLoc(TagLoc); - TL.setQualifierRange(SS.getRange()); + TL.setQualifierLoc(QualifierLoc); TL.setNameLoc(NameLoc); } else { ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc()); TL.setKeywordLoc(TagLoc); - TL.setQualifierRange(SS.getRange()); + TL.setQualifierLoc(QualifierLoc); cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(NameLoc); } @@ -6896,7 +7216,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); TL.setKeywordLoc(TagLoc); - TL.setQualifierRange(SS.getRange()); + TL.setQualifierLoc(SS.getWithLocInContext(Context)); TL.setNameLoc(NameLoc); FriendDecl *Friend = FriendDecl::Create(Context, CurContext, NameLoc, @@ -7359,10 +7679,14 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, /// /// \param InitRange the source range that covers the "0" initializer. bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) { + SourceLocation EndLoc = InitRange.getEnd(); + if (EndLoc.isValid()) + Method->setRangeEnd(EndLoc); + if (Method->isVirtual() || Method->getParent()->isDependentContext()) { Method->setPure(); return false; - } + } if (!Method->isInvalidDecl()) Diag(Method->getLocation(), diag::err_non_virtual_pure) @@ -7379,7 +7703,7 @@ bool Sema::CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange) { /// class X. void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) { // If there is no declaration, there was an error parsing it. - if (D == 0) return; + if (D == 0 || D->isInvalidDecl()) return; // We should only get called for declarations with scope specifiers, like: // int foo::bar; @@ -7391,7 +7715,7 @@ void Sema::ActOnCXXEnterDeclInitializer(Scope *S, Decl *D) { /// initializer for the out-of-line declaration 'D'. void Sema::ActOnCXXExitDeclInitializer(Scope *S, Decl *D) { // If there is no declaration, there was an error parsing it. - if (D == 0) return; + if (D == 0 || D->isInvalidDecl()) return; assert(D->isOutOfLine()); ExitDeclaratorContext(S); @@ -7472,6 +7796,7 @@ bool Sema::DefineUsedVTables() { // the members of a class as "used", so we check the size each // time through the loop and prefer indices (with are stable) to // iterators (which are not). + bool DefinedAnything = false; for (unsigned I = 0; I != VTableUses.size(); ++I) { CXXRecordDecl *Class = VTableUses[I].first->getDefinition(); if (!Class) @@ -7524,6 +7849,7 @@ bool Sema::DefineUsedVTables() { // Mark all of the virtual members of this class as referenced, so // that we can build a vtable. Then, tell the AST consumer that a // vtable for this class is required. + DefinedAnything = true; MarkVirtualMembersReferenced(Loc, Class); CXXRecordDecl *Canonical = cast<CXXRecordDecl>(Class->getCanonicalDecl()); Consumer.HandleVTable(Class, VTablesUsed[Canonical]); @@ -7537,7 +7863,7 @@ bool Sema::DefineUsedVTables() { } VTableUses.clear(); - return true; + return DefinedAnything; } void Sema::MarkVirtualMembersReferenced(SourceLocation Loc, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp index 652318f..7b235ba 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp @@ -28,7 +28,7 @@ static void DiagnoseObjCImplementedDeprecations(Sema &S, NamedDecl *ND, SourceLocation ImplLoc, int select) { - if (ND && ND->getAttr<DeprecatedAttr>()) { + if (ND && ND->isDeprecated()) { S.Diag(ImplLoc, diag::warn_deprecated_def) << select; if (select == 0) S.Diag(ND->getLocation(), diag::note_method_declared_at); @@ -174,7 +174,8 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, if (PrevDecl && SuperClassDecl == 0) { // The previous declaration was not a class decl. Check if we have a // typedef. If we do, get the underlying class type. - if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(PrevDecl)) { + if (const TypedefNameDecl *TDecl = + dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { QualType T = TDecl->getUnderlyingType(); if (T->isObjCObjectType()) { if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) @@ -193,7 +194,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, } } - if (!dyn_cast_or_null<TypedefDecl>(PrevDecl)) { + if (!dyn_cast_or_null<TypedefNameDecl>(PrevDecl)) { if (!SuperClassDecl) Diag(SuperLoc, diag::err_undef_superclass) << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); @@ -242,7 +243,8 @@ Decl *Sema::ActOnCompatiblityAlias(SourceLocation AtLoc, // Check for class declaration NamedDecl *CDeclU = LookupSingleName(TUScope, ClassName, ClassLocation, LookupOrdinaryName, ForRedeclaration); - if (const TypedefDecl *TDecl = dyn_cast_or_null<TypedefDecl>(CDeclU)) { + if (const TypedefNameDecl *TDecl = + dyn_cast_or_null<TypedefNameDecl>(CDeclU)) { QualType T = TDecl->getUnderlyingType(); if (T->isObjCObjectType()) { if (NamedDecl *IDecl = T->getAs<ObjCObjectType>()->getInterface()) { @@ -1242,7 +1244,7 @@ Sema::ActOnForwardClassDeclaration(SourceLocation AtClassLoc, // @class XCElementToggler; // // FIXME: Make an extension? - TypedefDecl *TDD = dyn_cast<TypedefDecl>(PrevDecl); + TypedefNameDecl *TDD = dyn_cast<TypedefNameDecl>(PrevDecl); if (!TDD || !TDD->getUnderlyingType()->isObjCObjectType()) { Diag(AtClassLoc, diag::err_redefinition_different_kind) << IdentList[i]; Diag(PrevDecl->getLocation(), diag::note_previous_definition); @@ -1369,15 +1371,14 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, PrevObjCMethod->setDefined(impl); // If a method is deprecated, push it in the global pool. // This is used for better diagnostics. - if (Method->getAttr<DeprecatedAttr>()) { - if (!PrevObjCMethod->getAttr<DeprecatedAttr>()) + if (Method->isDeprecated()) { + if (!PrevObjCMethod->isDeprecated()) List->Method = Method; } // If new method is unavailable, push it into global pool // unless previous one is deprecated. - if (Method->getAttr<UnavailableAttr>()) { - if (!PrevObjCMethod->getAttr<UnavailableAttr>() && - !PrevObjCMethod->getAttr<DeprecatedAttr>()) + if (Method->isUnavailable()) { + if (PrevObjCMethod->getAvailability() < AR_Deprecated) List->Method = Method; } return; @@ -1475,7 +1476,7 @@ void Sema::CompareMethodParamsInBaseAndSuper(Decl *ClassDecl, assert(PrevI != SuperMethodDecl->param_end() && "Param mismatch"); QualType T1 = Context.getCanonicalType((*ParamI)->getType()); QualType T2 = Context.getCanonicalType((*PrevI)->getType()); - // If type of arguement of method in this class does not match its + // If type of argument of method in this class does not match its // respective argument type in the super class method, issue warning; if (!Context.typesAreCompatible(T1, T2)) { Diag((*ParamI)->getLocation(), diag::ext_typecheck_base_super) @@ -1535,7 +1536,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, SourceLocation L = ClassDecl->getLocation(); AtEnd.setBegin(L); AtEnd.setEnd(L); - Diag(L, diag::warn_missing_atend); + Diag(L, diag::err_missing_atend); } // FIXME: Remove these and use the ObjCContainerDecl/DeclContext. @@ -1697,21 +1698,7 @@ void Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, /// objective-c's type qualifier from the parser version of the same info. static Decl::ObjCDeclQualifier CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { - Decl::ObjCDeclQualifier ret = Decl::OBJC_TQ_None; - if (PQTVal & ObjCDeclSpec::DQ_In) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_In); - if (PQTVal & ObjCDeclSpec::DQ_Inout) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Inout); - if (PQTVal & ObjCDeclSpec::DQ_Out) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Out); - if (PQTVal & ObjCDeclSpec::DQ_Bycopy) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Bycopy); - if (PQTVal & ObjCDeclSpec::DQ_Byref) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Byref); - if (PQTVal & ObjCDeclSpec::DQ_Oneway) - ret = (Decl::ObjCDeclQualifier)(ret | Decl::OBJC_TQ_Oneway); - - return ret; + return (Decl::ObjCDeclQualifier) (unsigned) PQTVal; } static inline @@ -1736,7 +1723,7 @@ Decl *Sema::ActOnMethodDeclaration( ObjCArgInfo *ArgInfo, DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args AttributeList *AttrList, tok::ObjCKeywordKind MethodDeclKind, - bool isVariadic) { + bool isVariadic, bool MethodDefinition) { // Make sure we can establish a context for the method. if (!ClassDecl) { Diag(MethodLoc, diag::error_missing_method_context); @@ -1789,25 +1776,24 @@ Decl *Sema::ActOnMethodDeclaration( if (R.isSingleResult()) { NamedDecl *PrevDecl = R.getFoundDecl(); if (S->isDeclScope(PrevDecl)) { - // FIXME. This should be an error; but will break projects. - Diag(ArgInfo[i].NameLoc, diag::warn_method_param_redefinition) + Diag(ArgInfo[i].NameLoc, + (MethodDefinition ? diag::warn_method_param_redefinition + : diag::warn_method_param_declaration)) << ArgInfo[i].Name; Diag(PrevDecl->getLocation(), diag::note_previous_declaration); } } - ParmVarDecl* Param - = ParmVarDecl::Create(Context, ObjCMethod, ArgInfo[i].NameLoc, - ArgInfo[i].Name, ArgType, DI, - SC_None, SC_None, 0); + SourceLocation StartLoc = DI + ? DI->getTypeLoc().getBeginLoc() + : ArgInfo[i].NameLoc; - if (ArgType->isObjCObjectType()) { - Diag(ArgInfo[i].NameLoc, - diag::err_object_cannot_be_passed_returned_by_value) - << 1 << ArgType; - Param->setInvalidDecl(); - } + ParmVarDecl* Param = CheckParameter(ObjCMethod, StartLoc, + ArgInfo[i].NameLoc, ArgInfo[i].Name, + ArgType, DI, SC_None, SC_None); + + Param->setObjCMethodScopeInfo(i); Param->setObjCDeclQualifier( CvtQTToAstBitMask(ArgInfo[i].DeclSpec.getObjCDeclQualifier())); @@ -1888,16 +1874,9 @@ Decl *Sema::ActOnMethodDeclaration( Diag(PrevMethod->getLocation(), diag::note_previous_declaration); } - // If the interface declared this method, and it was deprecated there, - // mark it deprecated here. + // Merge information down from the interface declaration if we have one. if (InterfaceMD) - if (Attr *DA = InterfaceMD->getAttr<DeprecatedAttr>()) { - StringLiteral *SE = StringLiteral::CreateEmpty(Context, 1); - ObjCMethod->addAttr(::new (Context) - DeprecatedAttr(DA->getLocation(), - Context, - SE->getString())); - } + mergeObjCMethodDecls(ObjCMethod, InterfaceMD); return ObjCMethod; } @@ -1935,7 +1914,9 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, for (unsigned i = 0; i < Ivars.size(); i++) { FieldDecl* ID = cast<FieldDecl>(Ivars[i]); RecordDecl *Record = dyn_cast<RecordDecl>(TagD); - Decl *FD = ObjCAtDefsFieldDecl::Create(Context, Record, ID->getLocation(), + Decl *FD = ObjCAtDefsFieldDecl::Create(Context, Record, + /*FIXME: StartL=*/ID->getLocation(), + ID->getLocation(), ID->getIdentifier(), ID->getType(), ID->getBitWidth()); Decls.push_back(FD); @@ -1953,17 +1934,17 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, } /// \brief Build a type-check a new Objective-C exception variable declaration. -VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, - QualType T, - IdentifierInfo *Name, - SourceLocation NameLoc, +VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T, + SourceLocation StartLoc, + SourceLocation IdLoc, + IdentifierInfo *Id, bool Invalid) { // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage // duration shall not be qualified by an address-space qualifier." // Since all parameters have automatic store duration, they can not have // an address space. if (T.getAddressSpace() != 0) { - Diag(NameLoc, diag::err_arg_with_address_space); + Diag(IdLoc, diag::err_arg_with_address_space); Invalid = true; } @@ -1975,14 +1956,14 @@ VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, // Okay: we don't know what this type will instantiate to. } else if (!T->isObjCObjectPointerType()) { Invalid = true; - Diag(NameLoc ,diag::err_catch_param_not_objc_type); + Diag(IdLoc ,diag::err_catch_param_not_objc_type); } else if (T->isObjCQualifiedIdType()) { Invalid = true; - Diag(NameLoc, diag::err_illegal_qualifiers_on_catch_parm); + Diag(IdLoc, diag::err_illegal_qualifiers_on_catch_parm); } - VarDecl *New = VarDecl::Create(Context, CurContext, NameLoc, Name, T, TInfo, - SC_None, SC_None); + VarDecl *New = VarDecl::Create(Context, CurContext, StartLoc, IdLoc, Id, + T, TInfo, SC_None, SC_None); New->setExceptionVariable(true); if (Invalid) @@ -2023,8 +2004,10 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { << Context.getTypeDeclType(OwnedDecl); } - VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType, D.getIdentifier(), - D.getIdentifierLoc(), + VarDecl *New = BuildObjCExceptionDecl(TInfo, ExceptionType, + D.getSourceRange().getBegin(), + D.getIdentifierLoc(), + D.getIdentifier(), D.isInvalidType()); // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp index 5d7993b..f1033dc 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp @@ -96,16 +96,24 @@ bool Sema::CheckDistantExceptionSpec(QualType T) { } bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { + OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); + bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; bool MissingExceptionSpecification = false; bool MissingEmptyExceptionSpecification = false; - if (!CheckEquivalentExceptionSpec(PDiag(diag::err_mismatched_exception_spec), + unsigned DiagID = diag::err_mismatched_exception_spec; + if (getLangOptions().Microsoft) + DiagID = diag::warn_mismatched_exception_spec; + + if (!CheckEquivalentExceptionSpec(PDiag(DiagID), PDiag(diag::note_previous_declaration), Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), New->getType()->getAs<FunctionProtoType>(), New->getLocation(), &MissingExceptionSpecification, - &MissingEmptyExceptionSpecification)) + &MissingEmptyExceptionSpecification, + /*AllowNoexceptAllMatchWithNoSpec=*/true, + IsOperatorNew)) return false; // The failure was something other than an empty exception @@ -129,9 +137,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { Context.getSourceManager().isInSystemHeader(Old->getLocation())) && Old->isExternC()) { FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); - EPI.HasExceptionSpec = true; - EPI.HasAnyExceptionSpec = false; - EPI.NumExceptions = 0; + EPI.ExceptionSpecType = EST_DynamicNone; QualType NewType = Context.getFunctionType(NewProto->getResultType(), NewProto->arg_type_begin(), NewProto->getNumArgs(), @@ -145,10 +151,14 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { = Old->getType()->getAs<FunctionProtoType>(); FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); - EPI.HasExceptionSpec = OldProto->hasExceptionSpec(); - EPI.HasAnyExceptionSpec = OldProto->hasAnyExceptionSpec(); - EPI.NumExceptions = OldProto->getNumExceptions(); - EPI.Exceptions = OldProto->exception_begin(); + EPI.ExceptionSpecType = OldProto->getExceptionSpecType(); + if (EPI.ExceptionSpecType == EST_Dynamic) { + EPI.NumExceptions = OldProto->getNumExceptions(); + EPI.Exceptions = OldProto->exception_begin(); + } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { + // FIXME: We can't just take the expression from the old prototype. It + // likely contains references to the old prototype's parameters. + } // Update the type of the function with the appropriate exception // specification. @@ -160,7 +170,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { // If exceptions are disabled, suppress the warning about missing // exception specifications for new and delete operators. - if (!getLangOptions().Exceptions) { + if (!getLangOptions().CXXExceptions) { switch (New->getDeclName().getCXXOverloadedOperator()) { case OO_New: case OO_Array_New: @@ -178,30 +188,53 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { // Warn about the lack of exception specification. llvm::SmallString<128> ExceptionSpecString; llvm::raw_svector_ostream OS(ExceptionSpecString); - OS << "throw("; - bool OnFirstException = true; - for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(), - EEnd = OldProto->exception_end(); - E != EEnd; - ++E) { - if (OnFirstException) - OnFirstException = false; - else - OS << ", "; - - OS << E->getAsString(Context.PrintingPolicy); + switch (OldProto->getExceptionSpecType()) { + case EST_DynamicNone: + OS << "throw()"; + break; + + case EST_Dynamic: { + OS << "throw("; + bool OnFirstException = true; + for (FunctionProtoType::exception_iterator E = OldProto->exception_begin(), + EEnd = OldProto->exception_end(); + E != EEnd; + ++E) { + if (OnFirstException) + OnFirstException = false; + else + OS << ", "; + + OS << E->getAsString(Context.PrintingPolicy); + } + OS << ")"; + break; + } + + case EST_BasicNoexcept: + OS << "noexcept"; + break; + + case EST_ComputedNoexcept: + OS << "noexcept("; + OldProto->getNoexceptExpr()->printPretty(OS, Context, 0, + Context.PrintingPolicy); + OS << ")"; + break; + + default: + assert(false && "This spec type is compatible with none."); } - OS << ")"; OS.flush(); - SourceLocation AfterParenLoc; + SourceLocation FixItLoc; if (TypeSourceInfo *TSInfo = New->getTypeSourceInfo()) { TypeLoc TL = TSInfo->getTypeLoc().IgnoreParens(); if (const FunctionTypeLoc *FTLoc = dyn_cast<FunctionTypeLoc>(&TL)) - AfterParenLoc = PP.getLocForEndOfToken(FTLoc->getRParenLoc()); + FixItLoc = PP.getLocForEndOfToken(FTLoc->getLocalRangeEnd()); } - if (AfterParenLoc.isInvalid()) + if (FixItLoc.isInvalid()) Diag(New->getLocation(), diag::warn_missing_exception_specification) << New << OS.str(); else { @@ -209,7 +242,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { // late-specified return types. Diag(New->getLocation(), diag::warn_missing_exception_specification) << New << OS.str() - << FixItHint::CreateInsertion(AfterParenLoc, " " + OS.str().str()); + << FixItHint::CreateInsertion(FixItLoc, " " + OS.str().str()); } if (!Old->getLocation().isInvalid()) @@ -218,7 +251,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { return false; } - Diag(New->getLocation(), diag::err_mismatched_exception_spec); + Diag(New->getLocation(), DiagID); Diag(Old->getLocation(), diag::note_previous_declaration); return true; } @@ -230,26 +263,29 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { bool Sema::CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc) { + unsigned DiagID = diag::err_mismatched_exception_spec; + if (getLangOptions().Microsoft) + DiagID = diag::warn_mismatched_exception_spec; return CheckEquivalentExceptionSpec( - PDiag(diag::err_mismatched_exception_spec), + PDiag(DiagID), PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc); } -/// CheckEquivalentExceptionSpec - Check if the two types have equivalent -/// exception specifications. Exception specifications are equivalent if -/// they allow exactly the same set of exception types. It does not matter how -/// that is achieved. See C++ [except.spec]p2. -bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, +/// CheckEquivalentExceptionSpec - Check if the two types have compatible +/// exception specifications. See C++ [except.spec]p3. +bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, - const FunctionProtoType *Old, + const FunctionProtoType *Old, SourceLocation OldLoc, - const FunctionProtoType *New, + const FunctionProtoType *New, SourceLocation NewLoc, bool *MissingExceptionSpecification, - bool *MissingEmptyExceptionSpecification) { + bool*MissingEmptyExceptionSpecification, + bool AllowNoexceptAllMatchWithNoSpec, + bool IsOperatorNew) { // Just completely ignore this under -fno-exceptions. - if (!getLangOptions().Exceptions) + if (!getLangOptions().CXXExceptions) return false; if (MissingExceptionSpecification) @@ -258,29 +294,133 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, if (MissingEmptyExceptionSpecification) *MissingEmptyExceptionSpecification = false; - bool OldAny = !Old->hasExceptionSpec() || Old->hasAnyExceptionSpec(); - bool NewAny = !New->hasExceptionSpec() || New->hasAnyExceptionSpec(); - if (getLangOptions().Microsoft) { - // Treat throw(whatever) as throw(...) to be compatible with MS headers. - if (New->hasExceptionSpec() && New->getNumExceptions() > 0) - NewAny = true; - if (Old->hasExceptionSpec() && Old->getNumExceptions() > 0) - OldAny = true; + // C++0x [except.spec]p3: Two exception-specifications are compatible if: + // - both are non-throwing, regardless of their form, + // - both have the form noexcept(constant-expression) and the constant- + // expressions are equivalent, + // - one exception-specification is a noexcept-specification allowing all + // exceptions and the other is of the form throw(type-id-list), or + // - both are dynamic-exception-specifications that have the same set of + // adjusted types. + // + // C++0x [except.spec]p12: An exception-specifcation is non-throwing if it is + // of the form throw(), noexcept, or noexcept(constant-expression) where the + // constant-expression yields true. + // + // CWG 1073 Proposed resolution: Strike the third bullet above. + // + // C++0x [except.spec]p4: If any declaration of a function has an exception- + // specifier that is not a noexcept-specification allowing all exceptions, + // all declarations [...] of that function shall have a compatible + // exception-specification. + // + // That last point basically means that noexcept(false) matches no spec. + // It's considered when AllowNoexceptAllMatchWithNoSpec is true. + + ExceptionSpecificationType OldEST = Old->getExceptionSpecType(); + ExceptionSpecificationType NewEST = New->getExceptionSpecType(); + + // Shortcut the case where both have no spec. + if (OldEST == EST_None && NewEST == EST_None) + return false; + + FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(Context); + FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(Context); + if (OldNR == FunctionProtoType::NR_BadNoexcept || + NewNR == FunctionProtoType::NR_BadNoexcept) + return false; + + // Dependent noexcept specifiers are compatible with each other, but nothing + // else. + // One noexcept is compatible with another if the argument is the same + if (OldNR == NewNR && + OldNR != FunctionProtoType::NR_NoNoexcept && + NewNR != FunctionProtoType::NR_NoNoexcept) + return false; + if (OldNR != NewNR && + OldNR != FunctionProtoType::NR_NoNoexcept && + NewNR != FunctionProtoType::NR_NoNoexcept) { + Diag(NewLoc, DiagID); + if (NoteID.getDiagID() != 0) + Diag(OldLoc, NoteID); + return true; + } + + // The MS extension throw(...) is compatible with itself. + if (OldEST == EST_MSAny && NewEST == EST_MSAny) + return false; + + // It's also compatible with no spec. + if ((OldEST == EST_None && NewEST == EST_MSAny) || + (OldEST == EST_MSAny && NewEST == EST_None)) + return false; + + // It's also compatible with noexcept(false). + if (OldEST == EST_MSAny && NewNR == FunctionProtoType::NR_Throw) + return false; + if (NewEST == EST_MSAny && OldNR == FunctionProtoType::NR_Throw) + return false; + + // As described above, noexcept(false) matches no spec only for functions. + if (AllowNoexceptAllMatchWithNoSpec) { + if (OldEST == EST_None && NewNR == FunctionProtoType::NR_Throw) + return false; + if (NewEST == EST_None && OldNR == FunctionProtoType::NR_Throw) + return false; } - if (OldAny && NewAny) + // Any non-throwing specifications are compatible. + bool OldNonThrowing = OldNR == FunctionProtoType::NR_Nothrow || + OldEST == EST_DynamicNone; + bool NewNonThrowing = NewNR == FunctionProtoType::NR_Nothrow || + NewEST == EST_DynamicNone; + if (OldNonThrowing && NewNonThrowing) return false; - if (OldAny || NewAny) { + + // As a special compatibility feature, under C++0x we accept no spec and + // throw(std::bad_alloc) as equivalent for operator new and operator new[]. + // This is because the implicit declaration changed, but old code would break. + if (getLangOptions().CPlusPlus0x && IsOperatorNew) { + const FunctionProtoType *WithExceptions = 0; + if (OldEST == EST_None && NewEST == EST_Dynamic) + WithExceptions = New; + else if (OldEST == EST_Dynamic && NewEST == EST_None) + WithExceptions = Old; + if (WithExceptions && WithExceptions->getNumExceptions() == 1) { + // One has no spec, the other throw(something). If that something is + // std::bad_alloc, all conditions are met. + QualType Exception = *WithExceptions->exception_begin(); + if (CXXRecordDecl *ExRecord = Exception->getAsCXXRecordDecl()) { + IdentifierInfo* Name = ExRecord->getIdentifier(); + if (Name && Name->getName() == "bad_alloc") { + // It's called bad_alloc, but is it in std? + DeclContext* DC = ExRecord->getDeclContext(); + DC = DC->getEnclosingNamespaceContext(); + if (NamespaceDecl* NS = dyn_cast<NamespaceDecl>(DC)) { + IdentifierInfo* NSName = NS->getIdentifier(); + DC = DC->getParent(); + if (NSName && NSName->getName() == "std" && + DC->getEnclosingNamespaceContext()->isTranslationUnit()) { + return false; + } + } + } + } + } + } + + // At this point, the only remaining valid case is two matching dynamic + // specifications. We return here unless both specifications are dynamic. + if (OldEST != EST_Dynamic || NewEST != EST_Dynamic) { if (MissingExceptionSpecification && Old->hasExceptionSpec() && !New->hasExceptionSpec()) { // The old type has an exception specification of some sort, but // the new type does not. *MissingExceptionSpecification = true; - if (MissingEmptyExceptionSpecification && - !Old->hasAnyExceptionSpec() && Old->getNumExceptions() == 0) { - // The old type has a throw() exception specification and the - // new type has no exception specification, and the caller asked + if (MissingEmptyExceptionSpecification && OldNonThrowing) { + // The old type has a throw() or noexcept(true) exception specification + // and the new type has no exception specification, and the caller asked // to handle this itself. *MissingEmptyExceptionSpecification = true; } @@ -294,8 +434,11 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, return true; } + assert(OldEST == EST_Dynamic && NewEST == EST_Dynamic && + "Exception compatibility logic error: non-dynamic spec slipped through."); + bool Success = true; - // Both have a definite exception spec. Collect the first set, then compare + // Both have a dynamic exception spec. Collect the first set, then compare // to the second. llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; for (FunctionProtoType::exception_iterator I = Old->exception_begin(), @@ -331,7 +474,7 @@ bool Sema::CheckExceptionSpecSubset( const FunctionProtoType *Subset, SourceLocation SubLoc) { // Just auto-succeed under -fno-exceptions. - if (!getLangOptions().Exceptions) + if (!getLangOptions().CXXExceptions) return false; // FIXME: As usual, we could be more specific in our error messages, but @@ -340,19 +483,66 @@ bool Sema::CheckExceptionSpecSubset( if (!SubLoc.isValid()) SubLoc = SuperLoc; + ExceptionSpecificationType SuperEST = Superset->getExceptionSpecType(); + // If superset contains everything, we're done. - if (!Superset->hasExceptionSpec() || Superset->hasAnyExceptionSpec()) + if (SuperEST == EST_None || SuperEST == EST_MSAny) + return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); + + // If there are dependent noexcept specs, assume everything is fine. Unlike + // with the equivalency check, this is safe in this case, because we don't + // want to merge declarations. Checks after instantiation will catch any + // omissions we make here. + // We also shortcut checking if a noexcept expression was bad. + + FunctionProtoType::NoexceptResult SuperNR =Superset->getNoexceptSpec(Context); + if (SuperNR == FunctionProtoType::NR_BadNoexcept || + SuperNR == FunctionProtoType::NR_Dependent) + return false; + + // Another case of the superset containing everything. + if (SuperNR == FunctionProtoType::NR_Throw) return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); + ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); + // It does not. If the subset contains everything, we've failed. - if (!Subset->hasExceptionSpec() || Subset->hasAnyExceptionSpec()) { + if (SubEST == EST_None || SubEST == EST_MSAny) { + Diag(SubLoc, DiagID); + if (NoteID.getDiagID() != 0) + Diag(SuperLoc, NoteID); + return true; + } + + FunctionProtoType::NoexceptResult SubNR = Subset->getNoexceptSpec(Context); + if (SubNR == FunctionProtoType::NR_BadNoexcept || + SubNR == FunctionProtoType::NR_Dependent) + return false; + + // Another case of the subset containing everything. + if (SubNR == FunctionProtoType::NR_Throw) { + Diag(SubLoc, DiagID); + if (NoteID.getDiagID() != 0) + Diag(SuperLoc, NoteID); + return true; + } + + // If the subset contains nothing, we're done. + if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow) + return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); + + // Otherwise, if the superset contains nothing, we've failed. + if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) { Diag(SubLoc, DiagID); if (NoteID.getDiagID() != 0) Diag(SuperLoc, NoteID); return true; } - // Neither contains everything. Do a proper comparison. + assert(SuperEST == EST_Dynamic && SubEST == EST_Dynamic && + "Exception spec subset: non-dynamic case slipped through."); + + // Neither contains everything or nothing. Do a proper comparison. for (FunctionProtoType::exception_iterator SubI = Subset->exception_begin(), SubE = Subset->exception_end(); SubI != SubE; ++SubI) { // Take one type from the subset. diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp index 415ab3f..20b92b8 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp @@ -16,6 +16,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -56,7 +57,7 @@ using namespace sema; /// referenced), false otherwise. /// bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, - bool UnknownObjCClass) { + const ObjCInterfaceDecl *UnknownObjCClass) { if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, // emit them now. @@ -68,7 +69,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, Diag(Suppressed[I].first, Suppressed[I].second); // Clear out the list of suppressed diagnostics, so that we don't emit - // them again for this specialization. However, we don't remove this + // them again for this specialization. However, we don't obsolete this // entry from the table, because we want to avoid ever emitting these // diagnostics again. Suppressed.clear(); @@ -82,13 +83,28 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, return true; } - // See if the decl is deprecated. - if (const DeprecatedAttr *DA = D->getAttr<DeprecatedAttr>()) - EmitDeprecationWarning(D, DA->getMessage(), Loc, UnknownObjCClass); + // See if this is a deleted function. + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isDeleted()) { + Diag(Loc, diag::err_deleted_function_use); + Diag(D->getLocation(), diag::note_unavailable_here) << true; + return true; + } + } - // See if the decl is unavailable - if (const UnavailableAttr *UA = D->getAttr<UnavailableAttr>()) { - if (UA->getMessage().empty()) { + // See if this declaration is unavailable or deprecated. + std::string Message; + switch (D->getAvailability(&Message)) { + case AR_Available: + case AR_NotYetIntroduced: + break; + + case AR_Deprecated: + EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass); + break; + + case AR_Unavailable: + if (Message.empty()) { if (!UnknownObjCClass) Diag(Loc, diag::err_unavailable) << D->getDeclName(); else @@ -97,17 +113,9 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, } else Diag(Loc, diag::err_unavailable_message) - << D->getDeclName() << UA->getMessage(); - Diag(D->getLocation(), diag::note_unavailable_here) << 0; - } - - // See if this is a deleted function. - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - if (FD->isDeleted()) { - Diag(Loc, diag::err_deleted_function_use); - Diag(D->getLocation(), diag::note_unavailable_here) << true; - return true; - } + << D->getDeclName() << Message; + Diag(D->getLocation(), diag::note_unavailable_here) << 0; + break; } // Warn if this is used but marked unused. @@ -117,6 +125,23 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, return false; } +/// \brief Retrieve the message suffix that should be added to a +/// diagnostic complaining about the given function being deleted or +/// unavailable. +std::string Sema::getDeletedOrUnavailableSuffix(const FunctionDecl *FD) { + // FIXME: C++0x implicitly-deleted special member functions could be + // detected here so that we could improve diagnostics to say, e.g., + // "base class 'A' had a deleted copy constructor". + if (FD->isDeleted()) + return std::string(); + + std::string Message; + if (FD->getAvailability(&Message)) + return ": " + Message; + + return std::string(); +} + /// DiagnoseSentinelCalls - This routine checks on method dispatch calls /// (and other functions in future), which have been declared with sentinel /// attribute. It warns if call does not have the sentinel argument. @@ -232,13 +257,13 @@ SourceRange Sema::getExprRange(ExprTy *E) const { //===----------------------------------------------------------------------===// /// DefaultFunctionArrayConversion (C99 6.3.2.1p3, C99 6.3.2.1p4). -void Sema::DefaultFunctionArrayConversion(Expr *&E) { +ExprResult Sema::DefaultFunctionArrayConversion(Expr *E) { QualType Ty = E->getType(); assert(!Ty.isNull() && "DefaultFunctionArrayConversion - missing type"); if (Ty->isFunctionType()) - ImpCastExprToType(E, Context.getPointerType(Ty), - CK_FunctionToPointerDecay); + E = ImpCastExprToType(E, Context.getPointerType(Ty), + CK_FunctionToPointerDecay).take(); else if (Ty->isArrayType()) { // In C90 mode, arrays only promote to pointers if the array expression is // an lvalue. The relevant legalese is C90 6.2.2.1p3: "an lvalue that has @@ -252,25 +277,48 @@ void Sema::DefaultFunctionArrayConversion(Expr *&E) { // T" can be converted to an rvalue of type "pointer to T". // if (getLangOptions().C99 || getLangOptions().CPlusPlus || E->isLValue()) - ImpCastExprToType(E, Context.getArrayDecayedType(Ty), - CK_ArrayToPointerDecay); + E = ImpCastExprToType(E, Context.getArrayDecayedType(Ty), + CK_ArrayToPointerDecay).take(); + } + return Owned(E); +} + +static void CheckForNullPointerDereference(Sema &S, Expr *E) { + // Check to see if we are dereferencing a null pointer. If so, + // and if not volatile-qualified, this is undefined behavior that the + // optimizer will delete, so warn about it. People sometimes try to use this + // to get a deterministic trap and are surprised by clang's behavior. This + // only handles the pattern "*null", which is a very syntactic check. + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts())) + if (UO->getOpcode() == UO_Deref && + UO->getSubExpr()->IgnoreParenCasts()-> + isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) && + !UO->getType().isVolatileQualified()) { + S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, + S.PDiag(diag::warn_indirection_through_null) + << UO->getSubExpr()->getSourceRange()); + S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, + S.PDiag(diag::note_indirection_through_null)); } } -void Sema::DefaultLvalueConversion(Expr *&E) { +ExprResult Sema::DefaultLvalueConversion(Expr *E) { // C++ [conv.lval]p1: // A glvalue of a non-function, non-array type T can be // converted to a prvalue. - if (!E->isGLValue()) return; + if (!E->isGLValue()) return Owned(E); QualType T = E->getType(); assert(!T.isNull() && "r-value conversion on typeless expression?"); // Create a load out of an ObjCProperty l-value, if necessary. if (E->getObjectKind() == OK_ObjCProperty) { - ConvertPropertyForRValue(E); + ExprResult Res = ConvertPropertyForRValue(E); + if (Res.isInvalid()) + return Owned(E); + E = Res.take(); if (!E->isGLValue()) - return; + return Owned(E); } // We don't want to throw lvalue-to-rvalue casts on top of @@ -279,7 +327,7 @@ void Sema::DefaultLvalueConversion(Expr *&E) { (E->getType() == Context.OverloadTy || T->isDependentType() || T->isRecordType())) - return; + return Owned(E); // The C standard is actually really unclear on this point, and // DR106 tells us what the result should be but not why. It's @@ -287,7 +335,9 @@ void Sema::DefaultLvalueConversion(Expr *&E) { // lvalue-to-rvalue at all. Note that expressions of unqualified // 'void' type are never l-values, but qualified void can be. if (T->isVoidType()) - return; + return Owned(E); + + CheckForNullPointerDereference(*this, E); // C++ [conv.lval]p1: // [...] If T is a non-class type, the type of the prvalue is the @@ -301,27 +351,34 @@ void Sema::DefaultLvalueConversion(Expr *&E) { if (T.hasQualifiers()) T = T.getUnqualifiedType(); - if (const ArraySubscriptExpr *ae = dyn_cast<ArraySubscriptExpr>(E)) - CheckArrayAccess(ae); + CheckArrayAccess(E); - E = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, - E, 0, VK_RValue); + return Owned(ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, + E, 0, VK_RValue)); } -void Sema::DefaultFunctionArrayLvalueConversion(Expr *&E) { - DefaultFunctionArrayConversion(E); - DefaultLvalueConversion(E); +ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) { + ExprResult Res = DefaultFunctionArrayConversion(E); + if (Res.isInvalid()) + return ExprError(); + Res = DefaultLvalueConversion(Res.take()); + if (Res.isInvalid()) + return ExprError(); + return move(Res); } /// UsualUnaryConversions - Performs various conversions that are common to most /// operators (C99 6.3). The conversions of array and function types are -/// sometimes surpressed. For example, the array->pointer conversion doesn't +/// sometimes suppressed. For example, the array->pointer conversion doesn't /// apply if the array is an argument to the sizeof or address (&) operators. /// In these instances, this routine should *not* be called. -Expr *Sema::UsualUnaryConversions(Expr *&E) { +ExprResult Sema::UsualUnaryConversions(Expr *E) { // First, convert to an r-value. - DefaultFunctionArrayLvalueConversion(E); + ExprResult Res = DefaultFunctionArrayLvalueConversion(E); + if (Res.isInvalid()) + return Owned(E); + E = Res.take(); QualType Ty = E->getType(); assert(!Ty.isNull() && "UsualUnaryConversions - missing type"); @@ -345,60 +402,66 @@ Expr *Sema::UsualUnaryConversions(Expr *&E) { QualType PTy = Context.isPromotableBitField(E); if (!PTy.isNull()) { - ImpCastExprToType(E, PTy, CK_IntegralCast); - return E; + E = ImpCastExprToType(E, PTy, CK_IntegralCast).take(); + return Owned(E); } if (Ty->isPromotableIntegerType()) { QualType PT = Context.getPromotedIntegerType(Ty); - ImpCastExprToType(E, PT, CK_IntegralCast); - return E; + E = ImpCastExprToType(E, PT, CK_IntegralCast).take(); + return Owned(E); } } - - return E; + return Owned(E); } /// DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that /// do not have a prototype. Arguments that have type float are promoted to /// double. All other argument types are converted by UsualUnaryConversions(). -void Sema::DefaultArgumentPromotion(Expr *&Expr) { - QualType Ty = Expr->getType(); +ExprResult Sema::DefaultArgumentPromotion(Expr *E) { + QualType Ty = E->getType(); assert(!Ty.isNull() && "DefaultArgumentPromotion - missing type"); - UsualUnaryConversions(Expr); + ExprResult Res = UsualUnaryConversions(E); + if (Res.isInvalid()) + return Owned(E); + E = Res.take(); // If this is a 'float' (CVR qualified or typedef) promote to double. if (Ty->isSpecificBuiltinType(BuiltinType::Float)) - return ImpCastExprToType(Expr, Context.DoubleTy, CK_FloatingCast); + E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).take(); + + return Owned(E); } /// DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but /// will warn if the resulting type is not a POD type, and rejects ObjC -/// interfaces passed by value. This returns true if the argument type is -/// completely illegal. -bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT, +/// interfaces passed by value. +ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, FunctionDecl *FDecl) { - DefaultArgumentPromotion(Expr); + ExprResult ExprRes = DefaultArgumentPromotion(E); + if (ExprRes.isInvalid()) + return ExprError(); + E = ExprRes.take(); // __builtin_va_start takes the second argument as a "varargs" argument, but // it doesn't actually do anything with it. It doesn't need to be non-pod // etc. if (FDecl && FDecl->getBuiltinID() == Builtin::BI__builtin_va_start) - return false; + return Owned(E); - if (Expr->getType()->isObjCObjectType() && - DiagRuntimeBehavior(Expr->getLocStart(), 0, + if (E->getType()->isObjCObjectType() && + DiagRuntimeBehavior(E->getLocStart(), 0, PDiag(diag::err_cannot_pass_objc_interface_to_vararg) - << Expr->getType() << CT)) - return true; + << E->getType() << CT)) + return ExprError(); - if (!Expr->getType()->isPODType() && - DiagRuntimeBehavior(Expr->getLocStart(), 0, + if (!E->getType()->isPODType() && + DiagRuntimeBehavior(E->getLocStart(), 0, PDiag(diag::warn_cannot_pass_non_pod_arg_to_vararg) - << Expr->getType() << CT)) - return true; + << E->getType() << CT)) + return ExprError(); - return false; + return Owned(E); } /// UsualArithmeticConversions - Performs various conversions that are common to @@ -407,19 +470,24 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT, /// responsible for emitting appropriate error diagnostics. /// FIXME: verify the conversion rules for "complex int" are consistent with /// GCC. -QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, +QualType Sema::UsualArithmeticConversions(ExprResult &lhsExpr, ExprResult &rhsExpr, bool isCompAssign) { - if (!isCompAssign) - UsualUnaryConversions(lhsExpr); + if (!isCompAssign) { + lhsExpr = UsualUnaryConversions(lhsExpr.take()); + if (lhsExpr.isInvalid()) + return QualType(); + } - UsualUnaryConversions(rhsExpr); + rhsExpr = UsualUnaryConversions(rhsExpr.take()); + if (rhsExpr.isInvalid()) + return QualType(); // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. QualType lhs = - Context.getCanonicalType(lhsExpr->getType()).getUnqualifiedType(); + Context.getCanonicalType(lhsExpr.get()->getType()).getUnqualifiedType(); QualType rhs = - Context.getCanonicalType(rhsExpr->getType()).getUnqualifiedType(); + Context.getCanonicalType(rhsExpr.get()->getType()).getUnqualifiedType(); // If both types are identical, no conversion is needed. if (lhs == rhs) @@ -434,11 +502,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, QualType lhs_unpromoted = lhs; if (lhs->isPromotableIntegerType()) lhs = Context.getPromotedIntegerType(lhs); - QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr); + QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr.get()); if (!LHSBitfieldPromoteTy.isNull()) lhs = LHSBitfieldPromoteTy; if (lhs != lhs_unpromoted && !isCompAssign) - ImpCastExprToType(lhsExpr, lhs, CK_IntegralCast); + lhsExpr = ImpCastExprToType(lhsExpr.take(), lhs, CK_IntegralCast); // If both types are identical, no conversion is needed. if (lhs == rhs) @@ -455,11 +523,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, if (!RHSComplexFloat && !rhs->isRealFloatingType()) { if (rhs->isIntegerType()) { QualType fp = cast<ComplexType>(lhs)->getElementType(); - ImpCastExprToType(rhsExpr, fp, CK_IntegralToFloating); - ImpCastExprToType(rhsExpr, lhs, CK_FloatingRealToComplex); + rhsExpr = ImpCastExprToType(rhsExpr.take(), fp, CK_IntegralToFloating); + rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingRealToComplex); } else { assert(rhs->isComplexIntegerType()); - ImpCastExprToType(rhsExpr, lhs, CK_IntegralComplexToFloatingComplex); + rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralComplexToFloatingComplex); } return lhs; } @@ -469,11 +537,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, // int -> float -> _Complex float if (lhs->isIntegerType()) { QualType fp = cast<ComplexType>(rhs)->getElementType(); - ImpCastExprToType(lhsExpr, fp, CK_IntegralToFloating); - ImpCastExprToType(lhsExpr, rhs, CK_FloatingRealToComplex); + lhsExpr = ImpCastExprToType(lhsExpr.take(), fp, CK_IntegralToFloating); + lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingRealToComplex); } else { assert(lhs->isComplexIntegerType()); - ImpCastExprToType(lhsExpr, rhs, CK_IntegralComplexToFloatingComplex); + lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralComplexToFloatingComplex); } } return rhs; @@ -495,13 +563,13 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, if (LHSComplexFloat && RHSComplexFloat) { if (order > 0) { // _Complex float -> _Complex double - ImpCastExprToType(rhsExpr, lhs, CK_FloatingComplexCast); + rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingComplexCast); return lhs; } else if (order < 0) { // _Complex float -> _Complex double if (!isCompAssign) - ImpCastExprToType(lhsExpr, rhs, CK_FloatingComplexCast); + lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingComplexCast); return rhs; } return lhs; @@ -513,8 +581,8 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, if (order > 0) { // LHS is wider // float -> _Complex double QualType fp = cast<ComplexType>(lhs)->getElementType(); - ImpCastExprToType(rhsExpr, fp, CK_FloatingCast); - ImpCastExprToType(rhsExpr, lhs, CK_FloatingRealToComplex); + rhsExpr = ImpCastExprToType(rhsExpr.take(), fp, CK_FloatingCast); + rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingRealToComplex); return lhs; } @@ -522,11 +590,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, QualType result = (order == 0 ? lhs : Context.getComplexType(rhs)); // double -> _Complex double - ImpCastExprToType(rhsExpr, result, CK_FloatingRealToComplex); + rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingRealToComplex); // _Complex float -> _Complex double if (!isCompAssign && order < 0) - ImpCastExprToType(lhsExpr, result, CK_FloatingComplexCast); + lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingComplexCast); return result; } @@ -539,8 +607,8 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, // float -> _Complex double if (!isCompAssign) { QualType fp = cast<ComplexType>(rhs)->getElementType(); - ImpCastExprToType(lhsExpr, fp, CK_FloatingCast); - ImpCastExprToType(lhsExpr, rhs, CK_FloatingRealToComplex); + lhsExpr = ImpCastExprToType(lhsExpr.take(), fp, CK_FloatingCast); + lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingRealToComplex); } return rhs; } @@ -550,11 +618,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, // double -> _Complex double if (!isCompAssign) - ImpCastExprToType(lhsExpr, result, CK_FloatingRealToComplex); + lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingRealToComplex); // _Complex float -> _Complex double if (order > 0) - ImpCastExprToType(rhsExpr, result, CK_FloatingComplexCast); + rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingComplexCast); return result; } @@ -568,13 +636,13 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, if (LHSFloat && RHSFloat) { int order = Context.getFloatingTypeOrder(lhs, rhs); if (order > 0) { - ImpCastExprToType(rhsExpr, lhs, CK_FloatingCast); + rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_FloatingCast); return lhs; } assert(order < 0 && "illegal float comparison"); if (!isCompAssign) - ImpCastExprToType(lhsExpr, rhs, CK_FloatingCast); + lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_FloatingCast); return rhs; } @@ -582,7 +650,7 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, if (LHSFloat) { if (rhs->isIntegerType()) { // Convert rhs to the lhs floating point type. - ImpCastExprToType(rhsExpr, lhs, CK_IntegralToFloating); + rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralToFloating); return lhs; } @@ -591,11 +659,11 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, QualType result = Context.getComplexType(lhs); // _Complex int -> _Complex float - ImpCastExprToType(rhsExpr, result, CK_IntegralComplexToFloatingComplex); + rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_IntegralComplexToFloatingComplex); // float -> _Complex float if (!isCompAssign) - ImpCastExprToType(lhsExpr, result, CK_FloatingRealToComplex); + lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_FloatingRealToComplex); return result; } @@ -604,7 +672,7 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, if (lhs->isIntegerType()) { // Convert lhs to the rhs floating point type. if (!isCompAssign) - ImpCastExprToType(lhsExpr, rhs, CK_IntegralToFloating); + lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralToFloating); return rhs; } @@ -614,10 +682,10 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, // _Complex int -> _Complex float if (!isCompAssign) - ImpCastExprToType(lhsExpr, result, CK_IntegralComplexToFloatingComplex); + lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_IntegralComplexToFloatingComplex); // float -> _Complex float - ImpCastExprToType(rhsExpr, result, CK_FloatingRealToComplex); + rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_FloatingRealToComplex); return result; } @@ -633,21 +701,21 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, assert(order && "inequal types with equal element ordering"); if (order > 0) { // _Complex int -> _Complex long - ImpCastExprToType(rhsExpr, lhs, CK_IntegralComplexCast); + rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralComplexCast); return lhs; } if (!isCompAssign) - ImpCastExprToType(lhsExpr, rhs, CK_IntegralComplexCast); + lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralComplexCast); return rhs; } else if (lhsComplexInt) { // int -> _Complex int - ImpCastExprToType(rhsExpr, lhs, CK_IntegralRealToComplex); + rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralRealToComplex); return lhs; } else if (rhsComplexInt) { // int -> _Complex int if (!isCompAssign) - ImpCastExprToType(lhsExpr, rhs, CK_IntegralRealToComplex); + lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralRealToComplex); return rhs; } @@ -659,29 +727,29 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, if (lhsSigned == rhsSigned) { // Same signedness; use the higher-ranked type if (compare >= 0) { - ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast); + rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast); return lhs; } else if (!isCompAssign) - ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast); + lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast); return rhs; } else if (compare != (lhsSigned ? 1 : -1)) { // The unsigned type has greater than or equal rank to the // signed type, so use the unsigned type if (rhsSigned) { - ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast); + rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast); return lhs; } else if (!isCompAssign) - ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast); + lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast); return rhs; } else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) { // The two types are different widths; if we are here, that // means the signed type is larger than the unsigned type, so // use the signed type. if (lhsSigned) { - ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast); + rhsExpr = ImpCastExprToType(rhsExpr.take(), lhs, CK_IntegralCast); return lhs; } else if (!isCompAssign) - ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast); + lhsExpr = ImpCastExprToType(lhsExpr.take(), rhs, CK_IntegralCast); return rhs; } else { // The signed type is higher-ranked than the unsigned type, @@ -690,9 +758,9 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, // to the signed type. QualType result = Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs); - ImpCastExprToType(rhsExpr, result, CK_IntegralCast); + rhsExpr = ImpCastExprToType(rhsExpr.take(), result, CK_IntegralCast); if (!isCompAssign) - ImpCastExprToType(lhsExpr, result, CK_IntegralCast); + lhsExpr = ImpCastExprToType(lhsExpr.take(), result, CK_IntegralCast); return result; } } @@ -702,6 +770,163 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, //===----------------------------------------------------------------------===// +ExprResult +Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, + SourceLocation DefaultLoc, + SourceLocation RParenLoc, + Expr *ControllingExpr, + MultiTypeArg types, + MultiExprArg exprs) { + unsigned NumAssocs = types.size(); + assert(NumAssocs == exprs.size()); + + ParsedType *ParsedTypes = types.release(); + Expr **Exprs = exprs.release(); + + TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs]; + for (unsigned i = 0; i < NumAssocs; ++i) { + if (ParsedTypes[i]) + (void) GetTypeFromParser(ParsedTypes[i], &Types[i]); + else + Types[i] = 0; + } + + ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, + ControllingExpr, Types, Exprs, + NumAssocs); + delete [] Types; + return ER; +} + +ExprResult +Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, + SourceLocation DefaultLoc, + SourceLocation RParenLoc, + Expr *ControllingExpr, + TypeSourceInfo **Types, + Expr **Exprs, + unsigned NumAssocs) { + bool TypeErrorFound = false, + IsResultDependent = ControllingExpr->isTypeDependent(), + ContainsUnexpandedParameterPack + = ControllingExpr->containsUnexpandedParameterPack(); + + for (unsigned i = 0; i < NumAssocs; ++i) { + if (Exprs[i]->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + + if (Types[i]) { + if (Types[i]->getType()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + + if (Types[i]->getType()->isDependentType()) { + IsResultDependent = true; + } else { + // C1X 6.5.1.1p2 "The type name in a generic association shall specify a + // complete object type other than a variably modified type." + unsigned D = 0; + if (Types[i]->getType()->isIncompleteType()) + D = diag::err_assoc_type_incomplete; + else if (!Types[i]->getType()->isObjectType()) + D = diag::err_assoc_type_nonobject; + else if (Types[i]->getType()->isVariablyModifiedType()) + D = diag::err_assoc_type_variably_modified; + + if (D != 0) { + Diag(Types[i]->getTypeLoc().getBeginLoc(), D) + << Types[i]->getTypeLoc().getSourceRange() + << Types[i]->getType(); + TypeErrorFound = true; + } + + // C1X 6.5.1.1p2 "No two generic associations in the same generic + // selection shall specify compatible types." + for (unsigned j = i+1; j < NumAssocs; ++j) + if (Types[j] && !Types[j]->getType()->isDependentType() && + Context.typesAreCompatible(Types[i]->getType(), + Types[j]->getType())) { + Diag(Types[j]->getTypeLoc().getBeginLoc(), + diag::err_assoc_compatible_types) + << Types[j]->getTypeLoc().getSourceRange() + << Types[j]->getType() + << Types[i]->getType(); + Diag(Types[i]->getTypeLoc().getBeginLoc(), + diag::note_compat_assoc) + << Types[i]->getTypeLoc().getSourceRange() + << Types[i]->getType(); + TypeErrorFound = true; + } + } + } + } + if (TypeErrorFound) + return ExprError(); + + // If we determined that the generic selection is result-dependent, don't + // try to compute the result expression. + if (IsResultDependent) + return Owned(new (Context) GenericSelectionExpr( + Context, KeyLoc, ControllingExpr, + Types, Exprs, NumAssocs, DefaultLoc, + RParenLoc, ContainsUnexpandedParameterPack)); + + llvm::SmallVector<unsigned, 1> CompatIndices; + unsigned DefaultIndex = -1U; + for (unsigned i = 0; i < NumAssocs; ++i) { + if (!Types[i]) + DefaultIndex = i; + else if (Context.typesAreCompatible(ControllingExpr->getType(), + Types[i]->getType())) + CompatIndices.push_back(i); + } + + // C1X 6.5.1.1p2 "The controlling expression of a generic selection shall have + // type compatible with at most one of the types named in its generic + // association list." + if (CompatIndices.size() > 1) { + // We strip parens here because the controlling expression is typically + // parenthesized in macro definitions. + ControllingExpr = ControllingExpr->IgnoreParens(); + Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_multi_match) + << ControllingExpr->getSourceRange() << ControllingExpr->getType() + << (unsigned) CompatIndices.size(); + for (llvm::SmallVector<unsigned, 1>::iterator I = CompatIndices.begin(), + E = CompatIndices.end(); I != E; ++I) { + Diag(Types[*I]->getTypeLoc().getBeginLoc(), + diag::note_compat_assoc) + << Types[*I]->getTypeLoc().getSourceRange() + << Types[*I]->getType(); + } + return ExprError(); + } + + // C1X 6.5.1.1p2 "If a generic selection has no default generic association, + // its controlling expression shall have type compatible with exactly one of + // the types named in its generic association list." + if (DefaultIndex == -1U && CompatIndices.size() == 0) { + // We strip parens here because the controlling expression is typically + // parenthesized in macro definitions. + ControllingExpr = ControllingExpr->IgnoreParens(); + Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_no_match) + << ControllingExpr->getSourceRange() << ControllingExpr->getType(); + return ExprError(); + } + + // C1X 6.5.1.1p3 "If a generic selection has a generic association with a + // type name that is compatible with the type of the controlling expression, + // then the result expression of the generic selection is the expression + // in that generic association. Otherwise, the result expression of the + // generic selection is the expression in the default generic association." + unsigned ResultIndex = + CompatIndices.size() ? CompatIndices[0] : DefaultIndex; + + return Owned(new (Context) GenericSelectionExpr( + Context, KeyLoc, ControllingExpr, + Types, Exprs, NumAssocs, DefaultLoc, + RParenLoc, ContainsUnexpandedParameterPack, + ResultIndex)); +} + /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string /// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from @@ -721,8 +946,10 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { StringTokLocs.push_back(StringToks[i].getLocation()); QualType StrTy = Context.CharTy; - if (Literal.AnyWide) StrTy = Context.getWCharType(); - if (Literal.Pascal) StrTy = Context.UnsignedCharTy; + if (Literal.AnyWide) + StrTy = Context.getWCharType(); + else if (Literal.Pascal) + StrTy = Context.UnsignedCharTy; // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). if (getLangOptions().CPlusPlus || getLangOptions().ConstStrings) @@ -738,7 +965,7 @@ Sema::ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks) { // Pass &StringTokLocs[0], StringTokLocs.size() to factory! return Owned(StringLiteral::Create(Context, Literal.GetString(), Literal.GetStringLength(), - Literal.AnyWide, StrTy, + Literal.AnyWide, Literal.Pascal, StrTy, &StringTokLocs[0], StringTokLocs.size())); } @@ -783,11 +1010,20 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, // diagnose this. if (!S.CurContext->isFunctionOrMethod()) return CR_NoCapture; - // This particular madness can happen in ill-formed default - // arguments; claim it's okay and let downstream code handle it. - if (isa<ParmVarDecl>(var) && - S.CurContext == var->getDeclContext()->getParent()) - return CR_NoCapture; + // Certain madnesses can happen with parameter declarations, which + // we want to ignore. + if (isa<ParmVarDecl>(var)) { + // - If the parameter still belongs to the translation unit, then + // we're actually just using one parameter in the declaration of + // the next. This is useful in e.g. VLAs. + if (isa<TranslationUnitDecl>(var->getDeclContext())) + return CR_NoCapture; + + // - This particular madness can happen in ill-formed default + // arguments; claim it's okay and let downstream code handle it. + if (S.CurContext == var->getDeclContext()->getParent()) + return CR_NoCapture; + } DeclarationName functionName; if (FunctionDecl *fn = dyn_cast<FunctionDecl>(var->getDeclContext())) @@ -889,8 +1125,18 @@ static CaptureResult shouldCaptureValueReference(Sema &S, SourceLocation loc, // Build a copy expression. Expr *copyExpr = 0; - if (!byRef && S.getLangOptions().CPlusPlus && - !type->isDependentType() && type->isStructureOrClassType()) { + const RecordType *rtype; + if (!byRef && S.getLangOptions().CPlusPlus && !type->isDependentType() && + (rtype = type->getAs<RecordType>())) { + + // The capture logic needs the destructor, so make sure we mark it. + // Usually this is unnecessary because most local variables have + // their destructors marked at declaration time, but parameters are + // an exception because it's technically only the call site that + // actually requires the destructor. + if (isa<ParmVarDecl>(var)) + S.FinalizeVarWithDestructor(var, rtype); + // According to the blocks spec, the capture of a variable from // the stack requires a const copy constructor. This is not true // of the copy/move done to move a __block variable to the heap. @@ -974,8 +1220,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, MarkDeclarationReferenced(NameInfo.getLoc(), D); Expr *E = DeclRefExpr::Create(Context, - SS? (NestedNameSpecifier *)SS->getScopeRep() : 0, - SS? SS->getRange() : SourceRange(), + SS? SS->getWithLocInContext(Context) + : NestedNameSpecifierLoc(), D, NameInfo, Ty, VK); // Just in case we're building an illegal pointer-to-member. @@ -1261,12 +1507,24 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, return IMA_Error_StaticContext; } + CXXRecordDecl * + contextClass = cast<CXXMethodDecl>(DC)->getParent()->getCanonicalDecl(); + + // [class.mfct.non-static]p3: + // ...is used in the body of a non-static member function of class X, + // if name lookup (3.4.1) resolves the name in the id-expression to a + // non-static non-type member of some class C [...] + // ...if C is not X or a base class of X, the class member access expression + // is ill-formed. + if (R.getNamingClass() && + contextClass != R.getNamingClass()->getCanonicalDecl() && + contextClass->isProvablyNotDerivedFrom(R.getNamingClass())) + return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); + // If we can prove that the current context is unrelated to all the // declaring classes, it can't be an implicit member reference (in // which case it's an error if any of those members are selected). - if (IsProvablyNotDerivedFrom(SemaRef, - cast<CXXMethodDecl>(DC)->getParent(), - Classes)) + if (IsProvablyNotDerivedFrom(SemaRef, contextClass, Classes)) return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated); return (hasNonInstance ? IMA_Mixed : IMA_Instance); @@ -1350,10 +1608,13 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, TemplateArgumentListInfo TList; if (ULE->hasExplicitTemplateArgs()) ULE->copyTemplateArgumentsInto(TList); + + CXXScopeSpec SS; + SS.Adopt(ULE->getQualifierLoc()); CXXDependentScopeMemberExpr *DepExpr = CXXDependentScopeMemberExpr::Create( Context, DepThis, DepThisType, true, SourceLocation(), - ULE->getQualifier(), ULE->getQualifierRange(), NULL, + SS.getWithLocInContext(Context), NULL, R.getLookupNameInfo(), &TList); CallsUndergoingInstantiation.back()->setCallee(DepExpr); } else { @@ -1479,11 +1740,10 @@ bool Sema::canSynthesizeProvisionalIvar(ObjCPropertyDecl *Property) { return true; } -static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef, - LookupResult &Lookup, - IdentifierInfo *II, - SourceLocation NameLoc) { - ObjCMethodDecl *CurMeth = SemaRef.getCurMethodDecl(); +ObjCIvarDecl *Sema::SynthesizeProvisionalIvar(LookupResult &Lookup, + IdentifierInfo *II, + SourceLocation NameLoc) { + ObjCMethodDecl *CurMeth = getCurMethodDecl(); bool LookForIvars; if (Lookup.empty()) LookForIvars = true; @@ -1503,7 +1763,7 @@ static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef, if (!ClassImpDecl) return 0; bool DynamicImplSeen = false; - ObjCPropertyDecl *property = SemaRef.LookupPropertyDecl(IDecl, II); + ObjCPropertyDecl *property = LookupPropertyDecl(IDecl, II); if (!property) return 0; if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) { @@ -1515,9 +1775,9 @@ static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef, return 0; } if (!DynamicImplSeen) { - QualType PropType = SemaRef.Context.getCanonicalType(property->getType()); - ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(SemaRef.Context, ClassImpDecl, - NameLoc, + QualType PropType = Context.getCanonicalType(property->getType()); + ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, + NameLoc, NameLoc, II, PropType, /*Dinfo=*/0, ObjCIvarDecl::Private, (Expr *)0, true); @@ -1619,7 +1879,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // Synthesize ivars lazily. if (getLangOptions().ObjCDefaultSynthProperties && getLangOptions().ObjCNonFragileABI2) { - if (SynthesizeProvisionalIvar(*this, R, II, NameLoc)) { + if (SynthesizeProvisionalIvar(R, II, NameLoc)) { if (const ObjCPropertyDecl *Property = canSynthesizeProvisionalIvar(II)) { Diag(NameLoc, diag::warn_synthesized_ivar_access) << II; @@ -1850,13 +2110,35 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, if (SelfExpr.isInvalid()) return ExprError(); - Expr *SelfE = SelfExpr.take(); - DefaultLvalueConversion(SelfE); + SelfExpr = DefaultLvalueConversion(SelfExpr.take()); + if (SelfExpr.isInvalid()) + return ExprError(); MarkDeclarationReferenced(Loc, IV); + Expr *base = SelfExpr.take(); + base = base->IgnoreParenImpCasts(); + if (const DeclRefExpr *DE = dyn_cast<DeclRefExpr>(base)) { + const NamedDecl *ND = DE->getDecl(); + if (!isa<ImplicitParamDecl>(ND)) { + // relax the rule such that it is allowed to have a shadow 'self' + // where stand-alone ivar can be found in this 'self' object. + // This is to match gcc's behavior. + ObjCInterfaceDecl *selfIFace = 0; + if (const ObjCObjectPointerType *OPT = + base->getType()->getAsObjCInterfacePointerType()) + selfIFace = OPT->getInterfaceDecl(); + if (!selfIFace || + !selfIFace->lookupInstanceVariable(IV->getIdentifier())) { + Diag(Loc, diag::error_implicit_ivar_access) + << IV->getDeclName(); + Diag(ND->getLocation(), diag::note_declared_at); + return ExprError(); + } + } + } return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), Loc, - SelfE, true, true)); + SelfExpr.take(), true, true)); } } else if (CurMethod->isInstanceMethod()) { // We should warn if a local variable hides an ivar. @@ -1902,14 +2184,14 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, /// * Finally we cast from the declaring class to the "true" /// declaring class of the member. This conversion does not /// obey access control. -bool -Sema::PerformObjectMemberConversion(Expr *&From, +ExprResult +Sema::PerformObjectMemberConversion(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, NamedDecl *Member) { CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Member->getDeclContext()); if (!RD) - return false; + return Owned(From); QualType DestRecordType; QualType DestType; @@ -1929,7 +2211,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, } } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) { if (Method->isStatic()) - return false; + return Owned(From); DestType = Method->getThisType(Context); DestRecordType = DestType->getPointeeType(); @@ -1943,15 +2225,15 @@ Sema::PerformObjectMemberConversion(Expr *&From, } } else { // No conversion necessary. - return false; + return Owned(From); } if (DestType->isDependentType() || FromType->isDependentType()) - return false; + return Owned(From); // If the unqualified types are the same, no conversion is necessary. if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) - return false; + return Owned(From); SourceRange FromRange = From->getSourceRange(); SourceLocation FromLoc = FromRange.getBegin(); @@ -1990,12 +2272,12 @@ Sema::PerformObjectMemberConversion(Expr *&From, CXXCastPath BasePath; if (CheckDerivedToBaseConversion(FromRecordType, QRecordType, FromLoc, FromRange, &BasePath)) - return true; + return ExprError(); if (PointerConversions) QType = Context.getPointerType(QType); - ImpCastExprToType(From, QType, CK_UncheckedDerivedToBase, - VK, &BasePath); + From = ImpCastExprToType(From, QType, CK_UncheckedDerivedToBase, + VK, &BasePath).take(); FromType = QType; FromRecordType = QRecordType; @@ -2003,7 +2285,7 @@ Sema::PerformObjectMemberConversion(Expr *&From, // If the qualifier type was the same as the destination type, // we're done. if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) - return false; + return Owned(From); } } @@ -2026,13 +2308,13 @@ Sema::PerformObjectMemberConversion(Expr *&From, CXXCastPath BasePath; if (CheckDerivedToBaseConversion(FromRecordType, URecordType, FromLoc, FromRange, &BasePath)) - return true; + return ExprError(); QualType UType = URecordType; if (PointerConversions) UType = Context.getPointerType(UType); - ImpCastExprToType(From, UType, CK_UncheckedDerivedToBase, - VK, &BasePath); + From = ImpCastExprToType(From, UType, CK_UncheckedDerivedToBase, + VK, &BasePath).take(); FromType = UType; FromRecordType = URecordType; } @@ -2046,11 +2328,10 @@ Sema::PerformObjectMemberConversion(Expr *&From, if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType, FromLoc, FromRange, &BasePath, IgnoreAccess)) - return true; + return ExprError(); - ImpCastExprToType(From, DestType, CK_UncheckedDerivedToBase, - VK, &BasePath); - return false; + return ImpCastExprToType(From, DestType, CK_UncheckedDerivedToBase, + VK, &BasePath); } /// \brief Build a MemberExpr AST node. @@ -2061,14 +2342,7 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, QualType Ty, ExprValueKind VK, ExprObjectKind OK, const TemplateArgumentListInfo *TemplateArgs = 0) { - NestedNameSpecifier *Qualifier = 0; - SourceRange QualifierRange; - if (SS.isSet()) { - Qualifier = (NestedNameSpecifier *) SS.getScopeRep(); - QualifierRange = SS.getRange(); - } - - return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange, + return MemberExpr::Create(C, Base, isArrow, SS.getWithLocInContext(C), Member, FoundDecl, MemberNameInfo, TemplateArgs, Ty, VK, OK); } @@ -2123,10 +2397,12 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, } S.MarkDeclarationReferenced(MemberNameInfo.getLoc(), Field); - if (S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), - FoundDecl, Field)) + ExprResult Base = + S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), + FoundDecl, Field); + if (Base.isInvalid()) return ExprError(); - return S.Owned(BuildMemberExpr(S.Context, BaseExpr, IsArrow, SS, + return S.Owned(BuildMemberExpr(S.Context, Base.take(), IsArrow, SS, Field, FoundDecl, MemberNameInfo, MemberType, VK, OK)); } @@ -2234,7 +2510,7 @@ bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS, /// were not overloaded, and it doesn't promise that the declaration /// will in fact be used. static bool CheckDeclInExpr(Sema &S, SourceLocation Loc, NamedDecl *D) { - if (isa<TypedefDecl>(D)) { + if (isa<TypedefNameDecl>(D)) { S.Diag(Loc, diag::err_unexpected_typedef) << D->getDeclName(); return true; } @@ -2276,8 +2552,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(Context, R.getNamingClass(), - (NestedNameSpecifier*) SS.getScopeRep(), - SS.getRange(), R.getLookupNameInfo(), + SS.getWithLocInContext(Context), + R.getLookupNameInfo(), NeedsADL, R.isOverloadedResult(), R.begin(), R.end()); @@ -2433,6 +2709,16 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, break; case Decl::Function: { + const FunctionType *fty = type->castAs<FunctionType>(); + + // If we're referring to a function with an __unknown_anytype + // result type, make the entire expression __unknown_anytype. + if (fty->getResultType() == Context.UnknownAnyTy) { + type = Context.UnknownAnyTy; + valueKind = VK_RValue; + break; + } + // Functions are l-values in C++. if (getLangOptions().CPlusPlus) { valueKind = VK_LValue; @@ -2444,10 +2730,10 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, // used for checking compatibility. Therefore, when referencing // the function, we pretend that we don't have the full function // type. - if (!cast<FunctionDecl>(VD)->hasPrototype()) - if (const FunctionProtoType *proto = type->getAs<FunctionProtoType>()) - type = Context.getFunctionNoProtoType(proto->getResultType(), - proto->getExtInfo()); + if (!cast<FunctionDecl>(VD)->hasPrototype() && + isa<FunctionProtoType>(fty)) + type = Context.getFunctionNoProtoType(fty->getResultType(), + fty->getExtInfo()); // Functions are r-values in C. valueKind = VK_RValue; @@ -2455,6 +2741,16 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, } case Decl::CXXMethod: + // If we're referring to a method with an __unknown_anytype + // result type, make the entire expression __unknown_anytype. + // This should only be possible with a type written directly. + if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(VD->getType())) + if (proto->getResultType() == Context.UnknownAnyTy) { + type = Context.UnknownAnyTy; + valueKind = VK_RValue; + break; + } + // C++ methods are l-values if static, r-values if non-static. if (cast<CXXMethodDecl>(VD)->isStatic()) { valueKind = VK_LValue; @@ -2478,8 +2774,7 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return ExprError(); } -ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, - tok::TokenKind Kind) { +ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { PredefinedExpr::IdentType IT; switch (Kind) { @@ -2606,9 +2901,14 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { bool isExact = (result == APFloat::opOK); Res = FloatingLiteral::Create(Context, Val, isExact, Ty, Tok.getLocation()); - if (getLangOptions().SinglePrecisionConstants && Ty == Context.DoubleTy) - ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast); - + if (Ty == Context.DoubleTy) { + if (getLangOptions().SinglePrecisionConstants) { + Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).take(); + } else if (getLangOptions().OpenCL && !getOpenCLOptions().cl_khr_fp64) { + Diag(Tok.getLocation(), diag::warn_double_const_requires_fp64); + Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).take(); + } + } } else if (!Literal.isIntegerLiteral()) { return ExprError(); } else { @@ -2716,10 +3016,10 @@ ExprResult Sema::ActOnParenExpr(SourceLocation L, /// The UsualUnaryConversions() function is *not* called by this routine. /// See C99 6.3.2.1p[2-4] for more details. -bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, - SourceLocation OpLoc, - SourceRange ExprRange, - bool isSizeof) { +bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType exprType, + SourceLocation OpLoc, + SourceRange ExprRange, + UnaryExprOrTypeTrait ExprKind) { if (exprType->isDependentType()) return false; @@ -2730,30 +3030,47 @@ bool Sema::CheckSizeOfAlignOfOperand(QualType exprType, if (const ReferenceType *Ref = exprType->getAs<ReferenceType>()) exprType = Ref->getPointeeType(); + // [OpenCL 1.1 6.11.12] "The vec_step built-in function takes a built-in + // scalar or vector data type argument..." + // Every built-in scalar type (OpenCL 1.1 6.1.1) is either an arithmetic + // type (C99 6.2.5p18) or void. + if (ExprKind == UETT_VecStep) { + if (!(exprType->isArithmeticType() || exprType->isVoidType() || + exprType->isVectorType())) { + Diag(OpLoc, diag::err_vecstep_non_scalar_vector_type) + << exprType << ExprRange; + return true; + } + } + // C99 6.5.3.4p1: if (exprType->isFunctionType()) { // alignof(function) is allowed as an extension. - if (isSizeof) - Diag(OpLoc, diag::ext_sizeof_function_type) << ExprRange; + if (ExprKind == UETT_SizeOf) + Diag(OpLoc, diag::ext_sizeof_function_type) + << ExprRange; return false; } - // Allow sizeof(void)/alignof(void) as an extension. + // Allow sizeof(void)/alignof(void) as an extension. vec_step(void) is not + // an extension, as void is a built-in scalar type (OpenCL 1.1 6.1.1). if (exprType->isVoidType()) { - Diag(OpLoc, diag::ext_sizeof_void_type) - << (isSizeof ? "sizeof" : "__alignof") << ExprRange; + if (ExprKind != UETT_VecStep) + Diag(OpLoc, diag::ext_sizeof_void_type) + << ExprKind << ExprRange; return false; } if (RequireCompleteType(OpLoc, exprType, PDiag(diag::err_sizeof_alignof_incomplete_type) - << int(!isSizeof) << ExprRange)) + << ExprKind << ExprRange)) return true; // Reject sizeof(interface) and sizeof(interface<proto>) in 64-bit mode. if (LangOpts.ObjCNonFragileABI && exprType->isObjCObjectType()) { Diag(OpLoc, diag::err_sizeof_nonfragile_interface) - << exprType << isSizeof << ExprRange; + << exprType << (ExprKind == UETT_SizeOf) + << ExprRange; return true; } @@ -2783,109 +3100,132 @@ static bool CheckAlignOfExpr(Sema &S, Expr *E, SourceLocation OpLoc, if (isa<FieldDecl>(ME->getMemberDecl())) return false; - return S.CheckSizeOfAlignOfOperand(E->getType(), OpLoc, ExprRange, false); + return S.CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange, + UETT_AlignOf); +} + +bool Sema::CheckVecStepExpr(Expr *E, SourceLocation OpLoc, + SourceRange ExprRange) { + E = E->IgnoreParens(); + + // Cannot know anything else if the expression is dependent. + if (E->isTypeDependent()) + return false; + + return CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, ExprRange, + UETT_VecStep); } /// \brief Build a sizeof or alignof expression given a type operand. ExprResult -Sema::CreateSizeOfAlignOfExpr(TypeSourceInfo *TInfo, - SourceLocation OpLoc, - bool isSizeOf, SourceRange R) { +Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, + SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R) { if (!TInfo) return ExprError(); QualType T = TInfo->getType(); if (!T->isDependentType() && - CheckSizeOfAlignOfOperand(T, OpLoc, R, isSizeOf)) + CheckUnaryExprOrTypeTraitOperand(T, OpLoc, R, ExprKind)) return ExprError(); // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. - return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, TInfo, - Context.getSizeType(), OpLoc, - R.getEnd())); + return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, TInfo, + Context.getSizeType(), + OpLoc, R.getEnd())); } /// \brief Build a sizeof or alignof expression given an expression /// operand. ExprResult -Sema::CreateSizeOfAlignOfExpr(Expr *E, SourceLocation OpLoc, - bool isSizeOf, SourceRange R) { +Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R) { // Verify that the operand is valid. bool isInvalid = false; if (E->isTypeDependent()) { // Delay type-checking for type-dependent expressions. - } else if (!isSizeOf) { + } else if (ExprKind == UETT_AlignOf) { isInvalid = CheckAlignOfExpr(*this, E, OpLoc, R); + } else if (ExprKind == UETT_VecStep) { + isInvalid = CheckVecStepExpr(E, OpLoc, R); } else if (E->getBitField()) { // C99 6.5.3.4p1. Diag(OpLoc, diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; } else if (E->getType()->isPlaceholderType()) { - ExprResult PE = CheckPlaceholderExpr(E, OpLoc); + ExprResult PE = CheckPlaceholderExpr(E); if (PE.isInvalid()) return ExprError(); - return CreateSizeOfAlignOfExpr(PE.take(), OpLoc, isSizeOf, R); + return CreateUnaryExprOrTypeTraitExpr(PE.take(), OpLoc, ExprKind, R); } else { - isInvalid = CheckSizeOfAlignOfOperand(E->getType(), OpLoc, R, true); + isInvalid = CheckUnaryExprOrTypeTraitOperand(E->getType(), OpLoc, R, + UETT_SizeOf); } if (isInvalid) return ExprError(); // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. - return Owned(new (Context) SizeOfAlignOfExpr(isSizeOf, E, - Context.getSizeType(), OpLoc, - R.getEnd())); + return Owned(new (Context) UnaryExprOrTypeTraitExpr(ExprKind, E, + Context.getSizeType(), + OpLoc, R.getEnd())); } -/// ActOnSizeOfAlignOfExpr - Handle @c sizeof(type) and @c sizeof @c expr and -/// the same for @c alignof and @c __alignof +/// ActOnUnaryExprOrTypeTraitExpr - Handle @c sizeof(type) and @c sizeof @c +/// expr and the same for @c alignof and @c __alignof /// Note that the ArgRange is invalid if isType is false. ExprResult -Sema::ActOnSizeOfAlignOfExpr(SourceLocation OpLoc, bool isSizeof, bool isType, - void *TyOrEx, const SourceRange &ArgRange) { +Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, bool isType, + void *TyOrEx, const SourceRange &ArgRange) { // If error parsing type, ignore. if (TyOrEx == 0) return ExprError(); if (isType) { TypeSourceInfo *TInfo; (void) GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrEx), &TInfo); - return CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeof, ArgRange); + return CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, ArgRange); } Expr *ArgEx = (Expr *)TyOrEx; ExprResult Result - = CreateSizeOfAlignOfExpr(ArgEx, OpLoc, isSizeof, ArgEx->getSourceRange()); + = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind, + ArgEx->getSourceRange()); return move(Result); } -static QualType CheckRealImagOperand(Sema &S, Expr *&V, SourceLocation Loc, +static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc, bool isReal) { - if (V->isTypeDependent()) + if (V.get()->isTypeDependent()) return S.Context.DependentTy; // _Real and _Imag are only l-values for normal l-values. - if (V->getObjectKind() != OK_Ordinary) - S.DefaultLvalueConversion(V); + if (V.get()->getObjectKind() != OK_Ordinary) { + V = S.DefaultLvalueConversion(V.take()); + if (V.isInvalid()) + return QualType(); + } // These operators return the element type of a complex type. - if (const ComplexType *CT = V->getType()->getAs<ComplexType>()) + if (const ComplexType *CT = V.get()->getType()->getAs<ComplexType>()) return CT->getElementType(); // Otherwise they pass through real integer and floating point types here. - if (V->getType()->isArithmeticType()) - return V->getType(); + if (V.get()->getType()->isArithmeticType()) + return V.get()->getType(); // Test for placeholders. - ExprResult PR = S.CheckPlaceholderExpr(V, Loc); + ExprResult PR = S.CheckPlaceholderExpr(V.get()); if (PR.isInvalid()) return QualType(); - if (PR.take() != V) { - V = PR.take(); + if (PR.get() != V.get()) { + V = move(PR); return CheckRealImagOperand(S, V, Loc, isReal); } // Reject anything else. - S.Diag(Loc, diag::err_realimag_invalid_type) << V->getType() + S.Diag(Loc, diag::err_realimag_invalid_type) << V.get()->getType() << (isReal ? "__real" : "__imag"); return QualType(); } @@ -2955,9 +3295,16 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *RHSExp = Idx; // Perform default conversions. - if (!LHSExp->getType()->getAs<VectorType>()) - DefaultFunctionArrayLvalueConversion(LHSExp); - DefaultFunctionArrayLvalueConversion(RHSExp); + if (!LHSExp->getType()->getAs<VectorType>()) { + ExprResult Result = DefaultFunctionArrayLvalueConversion(LHSExp); + if (Result.isInvalid()) + return ExprError(); + LHSExp = Result.take(); + } + ExprResult Result = DefaultFunctionArrayLvalueConversion(RHSExp); + if (Result.isInvalid()) + return ExprError(); + RHSExp = Result.take(); QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType(); ExprValueKind VK = VK_LValue; @@ -3010,8 +3357,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, // force the promotion here. Diag(LHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << LHSExp->getSourceRange(); - ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy), - CK_ArrayToPointerDecay); + LHSExp = ImpCastExprToType(LHSExp, Context.getArrayDecayedType(LHSTy), + CK_ArrayToPointerDecay).take(); LHSTy = LHSExp->getType(); BaseExpr = LHSExp; @@ -3021,8 +3368,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, // Same as previous, except for 123[f().a] case Diag(RHSExp->getLocStart(), diag::ext_subscript_non_lvalue) << RHSExp->getSourceRange(); - ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy), - CK_ArrayToPointerDecay); + RHSExp = ImpCastExprToType(RHSExp, Context.getArrayDecayedType(RHSTy), + CK_ArrayToPointerDecay).take(); RHSTy = RHSExp->getType(); BaseExpr = RHSExp; @@ -3269,8 +3616,7 @@ Sema::ActOnDependentMemberExpr(Expr *BaseExpr, QualType BaseType, // must have pointer type, and the accessed type is the pointee. return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType, IsArrow, OpLoc, - SS.getScopeRep(), - SS.getRange(), + SS.getWithLocInContext(Context), FirstQualifierInScope, NameInfo, TemplateArgs)); } @@ -3441,10 +3787,15 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, // Explicit member accesses. } else { + ExprResult BaseResult = Owned(Base); ExprResult Result = - LookupMemberExpr(R, Base, IsArrow, OpLoc, + LookupMemberExpr(R, BaseResult, IsArrow, OpLoc, SS, /*ObjCImpDecl*/ 0, TemplateArgs != 0); + if (BaseResult.isInvalid()) + return ExprError(); + Base = BaseResult.take(); + if (Result.isInvalid()) { Owned(Base); return ExprError(); @@ -3477,7 +3828,6 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } R.setBaseObjectType(BaseType); - NestedNameSpecifier *Qualifier = SS.getScopeRep(); const DeclarationNameInfo &MemberNameInfo = R.getLookupNameInfo(); DeclarationName MemberName = MemberNameInfo.getName(); SourceLocation MemberLoc = MemberNameInfo.getLoc(); @@ -3522,7 +3872,7 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, = UnresolvedMemberExpr::Create(Context, R.isUnresolvableResult(), BaseExpr, BaseExprType, IsArrow, OpLoc, - Qualifier, SS.getRange(), + SS.getWithLocInContext(Context), MemberNameInfo, TemplateArgs, R.begin(), R.end()); @@ -3569,8 +3919,12 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, // Perform a property load on the base regardless of whether we // actually need it for the declaration. - if (BaseExpr->getObjectKind() == OK_ObjCProperty) - ConvertPropertyForRValue(BaseExpr); + if (BaseExpr->getObjectKind() == OK_ObjCProperty) { + ExprResult Result = ConvertPropertyForRValue(BaseExpr); + if (Result.isInvalid()) + return ExprError(); + BaseExpr = Result.take(); + } if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, @@ -3591,12 +3945,20 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, } if (CXXMethodDecl *MemberFn = dyn_cast<CXXMethodDecl>(MemberDecl)) { + ExprValueKind valueKind; + QualType type; + if (MemberFn->isInstance()) { + valueKind = VK_RValue; + type = Context.BoundMemberTy; + } else { + valueKind = VK_LValue; + type = MemberFn->getType(); + } + MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, MemberFn, FoundDecl, MemberNameInfo, - MemberFn->getType(), - MemberFn->isInstance() ? VK_RValue : VK_LValue, - OK_Ordinary)); + type, valueKind, OK_Ordinary)); } assert(!isa<FunctionDecl>(MemberDecl) && "member function not C++ method?"); @@ -3629,9 +3991,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, /// types would be profitable. The redefinition type is whatever /// this translation unit tried to typedef to id/Class; we store /// it to the side and then re-use it in places like this. -static bool ShouldTryAgainWithRedefinitionType(Sema &S, Expr *&base) { +static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) { const ObjCObjectPointerType *opty - = base->getType()->getAs<ObjCObjectPointerType>(); + = base.get()->getType()->getAs<ObjCObjectPointerType>(); if (!opty) return false; const ObjCObjectType *ty = opty->getObjectType(); @@ -3651,7 +4013,7 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, Expr *&base) { if (opty && !opty->getObjectType()->getInterface() != 0) return false; - S.ImpCastExprToType(base, redef, CK_BitCast); + base = S.ImpCastExprToType(base.take(), redef, CK_BitCast); return true; } @@ -3666,17 +4028,22 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, Expr *&base) { /// The ObjCImpDecl bit is a gross hack that will need to be properly /// fixed for ObjC++. ExprResult -Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, +Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, bool &IsArrow, SourceLocation OpLoc, CXXScopeSpec &SS, Decl *ObjCImpDecl, bool HasTemplateArgs) { - assert(BaseExpr && "no base expression"); + assert(BaseExpr.get() && "no base expression"); // Perform default conversions. - DefaultFunctionArrayConversion(BaseExpr); - if (IsArrow) DefaultLvalueConversion(BaseExpr); + BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); - QualType BaseType = BaseExpr->getType(); + if (IsArrow) { + BaseExpr = DefaultLvalueConversion(BaseExpr.take()); + if (BaseExpr.isInvalid()) + return ExprError(); + } + + QualType BaseType = BaseExpr.get()->getType(); assert(!BaseType->isDependentType()); DeclarationName MemberName = R.getLookupName(); @@ -3700,19 +4067,21 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // overloaded operator->, but that should have been dealt with // by now. Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << BaseType << int(IsArrow) << BaseExpr->getSourceRange() + << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() << FixItHint::CreateReplacement(OpLoc, "."); IsArrow = false; + } else if (BaseType == Context.BoundMemberTy) { + goto fail; } else { Diag(MemberLoc, diag::err_typecheck_member_reference_arrow) - << BaseType << BaseExpr->getSourceRange(); + << BaseType << BaseExpr.get()->getSourceRange(); return ExprError(); } } // Handle field access to simple records. if (const RecordType *RTy = BaseType->getAs<RecordType>()) { - if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(), + if (LookupMemberExprInRecord(*this, R, BaseExpr.get()->getSourceRange(), RTy, OpLoc, SS, HasTemplateArgs)) return ExprError(); @@ -3735,7 +4104,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // But we only actually find it this way on objects of type 'id', // apparently. if (OTy->isObjCId() && Member->isStr("isa")) - return Owned(new (Context) ObjCIsaExpr(BaseExpr, IsArrow, MemberLoc, + return Owned(new (Context) ObjCIsaExpr(BaseExpr.take(), IsArrow, MemberLoc, Context.getObjCClassType())); if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) @@ -3768,7 +4137,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, Diag(MemberLoc, diag::err_typecheck_member_reference_ivar) << IDecl->getDeclName() << MemberName - << BaseExpr->getSourceRange(); + << BaseExpr.get()->getSourceRange(); return ExprError(); } } @@ -3814,7 +4183,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, } return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), - MemberLoc, BaseExpr, + MemberLoc, BaseExpr.take(), IsArrow)); } @@ -3822,8 +4191,11 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, const ObjCObjectPointerType *OPT; if (!IsArrow && (OPT = BaseType->getAs<ObjCObjectPointerType>())) { // This actually uses the base as an r-value. - DefaultLvalueConversion(BaseExpr); - assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr->getType())); + BaseExpr = DefaultLvalueConversion(BaseExpr.take()); + if (BaseExpr.isInvalid()) + return ExprError(); + + assert(Context.hasSameUnqualifiedType(BaseType, BaseExpr.get()->getType())); IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); @@ -3843,7 +4215,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, VK_LValue, OK_ObjCProperty, MemberLoc, - BaseExpr)); + BaseExpr.take())); } if (ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(PMDecl)) { @@ -3867,11 +4239,12 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, return Owned(new (Context) ObjCPropertyRefExpr(OMD, SMD, PType, VK, OK, - MemberLoc, BaseExpr)); + MemberLoc, BaseExpr.take())); } } - - if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) + // Use of id.member can only be for a property reference. Do not + // use the 'id' redefinition in this case. + if (IsArrow && ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, ObjCImpDecl, HasTemplateArgs); @@ -3937,7 +4310,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // FIXME: we must check that the setter has property type. return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter, PType, VK, OK, - MemberLoc, BaseExpr)); + MemberLoc, BaseExpr.take())); } if (ShouldTryAgainWithRedefinitionType(*this, BaseExpr)) @@ -3949,7 +4322,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, } // Normal property access. - return HandleExprPropertyRefExpr(OPT, BaseExpr, MemberName, MemberLoc, + return HandleExprPropertyRefExpr(OPT, BaseExpr.get(), MemberName, MemberLoc, SourceLocation(), QualType(), false); } @@ -3957,13 +4330,13 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (BaseType->isExtVectorType()) { // FIXME: this expr should store IsArrow. IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); - ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr->getValueKind()); + ExprValueKind VK = (IsArrow ? VK_LValue : BaseExpr.get()->getValueKind()); QualType ret = CheckExtVectorComponent(*this, BaseType, VK, OpLoc, Member, MemberLoc); if (ret.isNull()) return ExprError(); - return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr, + return Owned(new (Context) ExtVectorElementExpr(ret, VK, BaseExpr.take(), *Member, MemberLoc)); } @@ -3972,7 +4345,8 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (IsArrow && BaseType->isSpecificBuiltinType(BuiltinType::ObjCSel) && !Context.ObjCSelRedefinitionType->isObjCSelType()) { - ImpCastExprToType(BaseExpr, Context.ObjCSelRedefinitionType, CK_BitCast); + BaseExpr = ImpCastExprToType(BaseExpr.take(), Context.ObjCSelRedefinitionType, + CK_BitCast); return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, ObjCImpDecl, HasTemplateArgs); } @@ -3991,7 +4365,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, if (!IsArrow && Ptr->getPointeeType()->isRecordType() && MemberName.getNameKind() != DeclarationName::CXXDestructorName) { Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) - << BaseType << int(IsArrow) << BaseExpr->getSourceRange() + << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() << FixItHint::CreateReplacement(OpLoc, "->"); // Recurse as an -> access. @@ -4006,11 +4380,11 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, bool TryCall = false; bool Overloaded = false; UnresolvedSet<8> AllOverloads; - if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr)) { + if (const OverloadExpr *Overloads = dyn_cast<OverloadExpr>(BaseExpr.get())) { AllOverloads.append(Overloads->decls_begin(), Overloads->decls_end()); TryCall = true; Overloaded = true; - } else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr)) { + } else if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(BaseExpr.get())) { if (FunctionDecl* Fun = dyn_cast<FunctionDecl>(DeclRef->getDecl())) { AllOverloads.addDecl(Fun); TryCall = true; @@ -4024,22 +4398,25 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, bool HasViableZeroArgOverload = false; for (OverloadExpr::decls_iterator it = AllOverloads.begin(), DeclsEnd = AllOverloads.end(); it != DeclsEnd; ++it) { - const FunctionDecl *OverloadDecl = cast<FunctionDecl>(*it); - QualType ResultTy = OverloadDecl->getResultType(); - if ((!IsArrow && ResultTy->isRecordType()) || - (IsArrow && ResultTy->isPointerType() && - ResultTy->getPointeeType()->isRecordType())) { - ViableOverloads.addDecl(*it); - if (OverloadDecl->getMinRequiredArguments() == 0) { - HasViableZeroArgOverload = true; + // Our overload set may include TemplateDecls, which we'll ignore for the + // purposes of determining whether we can issue a '()' fixit. + if (const FunctionDecl *OverloadDecl = dyn_cast<FunctionDecl>(*it)) { + QualType ResultTy = OverloadDecl->getResultType(); + if ((!IsArrow && ResultTy->isRecordType()) || + (IsArrow && ResultTy->isPointerType() && + ResultTy->getPointeeType()->isRecordType())) { + ViableOverloads.addDecl(*it); + if (OverloadDecl->getMinRequiredArguments() == 0) { + HasViableZeroArgOverload = true; + } } } } if (!HasViableZeroArgOverload || ViableOverloads.size() != 1) { - Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call) - << 1 << 0 - << BaseExpr->getSourceRange(); + Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) + << (AllOverloads.size() > 1) << 0 + << BaseExpr.get()->getSourceRange(); int ViableOverloadCount = ViableOverloads.size(); int I; for (I = 0; I < ViableOverloadCount; ++I) { @@ -4052,7 +4429,7 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, diag::note_member_ref_possible_intended_overload); } if (I != ViableOverloadCount) { - Diag(BaseExpr->getExprLoc(), diag::note_ovl_too_many_candidates) + Diag(BaseExpr.get()->getExprLoc(), diag::note_ovl_too_many_candidates) << int(ViableOverloadCount - I); } return ExprError(); @@ -4068,6 +4445,16 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, } } else if ((Fun = BaseType->getAs<FunctionType>())) { TryCall = true; + } else if (BaseType == Context.BoundMemberTy) { + // Look for the bound-member type. If it's still overloaded, + // give up, although we probably should have fallen into the + // OverloadExpr case above if we actually have an overloaded + // bound member. + QualType fnType = Expr::findBoundMemberType(BaseExpr.get()); + if (!fnType.isNull()) { + TryCall = true; + Fun = fnType->castAs<FunctionType>(); + } } if (TryCall) { @@ -4088,24 +4475,24 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr, // can emit a fixit and carry on pretending that BaseExpr was actually a // CallExpr. SourceLocation ParenInsertionLoc = - PP.getLocForEndOfToken(BaseExpr->getLocEnd()); - Diag(BaseExpr->getExprLoc(), diag::err_member_reference_needs_call) + PP.getLocForEndOfToken(BaseExpr.get()->getLocEnd()); + Diag(BaseExpr.get()->getExprLoc(), diag::err_member_reference_needs_call) << int(Overloaded) << 1 - << BaseExpr->getSourceRange() + << BaseExpr.get()->getSourceRange() << FixItHint::CreateInsertion(ParenInsertionLoc, "()"); - ExprResult NewBase = ActOnCallExpr(0, BaseExpr, ParenInsertionLoc, + ExprResult NewBase = ActOnCallExpr(0, BaseExpr.take(), ParenInsertionLoc, MultiExprArg(*this, 0, 0), ParenInsertionLoc); if (NewBase.isInvalid()) return ExprError(); - BaseExpr = NewBase.takeAs<Expr>(); - DefaultFunctionArrayConversion(BaseExpr); + BaseExpr = NewBase; + BaseExpr = DefaultFunctionArrayConversion(BaseExpr.take()); return LookupMemberExpr(R, BaseExpr, IsArrow, OpLoc, SS, ObjCImpDecl, HasTemplateArgs); } Diag(MemberLoc, diag::err_typecheck_member_reference_struct_union) - << BaseType << BaseExpr->getSourceRange(); + << BaseType << BaseExpr.get()->getSourceRange(); return ExprError(); } @@ -4167,8 +4554,12 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, NameInfo, TemplateArgs); } else { LookupResult R(*this, NameInfo, LookupMemberName); - Result = LookupMemberExpr(R, Base, IsArrow, OpLoc, + ExprResult BaseResult = Owned(Base); + Result = LookupMemberExpr(R, BaseResult, IsArrow, OpLoc, SS, ObjCImpDecl, TemplateArgs != 0); + if (BaseResult.isInvalid()) + return ExprError(); + Base = BaseResult.take(); if (Result.isInvalid()) { Owned(Base); @@ -4313,6 +4704,13 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, << NumArgsInProto << NumArgs << Fn->getSourceRange() << SourceRange(Args[NumArgsInProto]->getLocStart(), Args[NumArgs-1]->getLocEnd()); + + // Emit the location of the prototype. + if (FDecl && !FDecl->getBuiltinID()) + Diag(FDecl->getLocStart(), + diag::note_typecheck_call_too_many_args) + << FDecl; + // This deletes the extra arguments. Call->setNumArgs(Context, NumArgsInProto); return true; @@ -4394,16 +4792,37 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, // If this is a variadic call, handle args passed through "...". if (CallType != VariadicDoesNotApply) { - // Promote the arguments (C99 6.5.2.2p7). - for (unsigned i = ArgIx; i != NumArgs; ++i) { - Expr *Arg = Args[i]; - Invalid |= DefaultVariadicArgumentPromotion(Arg, CallType, FDecl); - AllArgs.push_back(Arg); + + // Assume that extern "C" functions with variadic arguments that + // return __unknown_anytype aren't *really* variadic. + if (Proto->getResultType() == Context.UnknownAnyTy && + FDecl && FDecl->isExternC()) { + for (unsigned i = ArgIx; i != NumArgs; ++i) { + ExprResult arg; + if (isa<ExplicitCastExpr>(Args[i]->IgnoreParens())) + arg = DefaultFunctionArrayLvalueConversion(Args[i]); + else + arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl); + Invalid |= arg.isInvalid(); + AllArgs.push_back(arg.take()); + } + + // Otherwise do argument promotion, (C99 6.5.2.2p7). + } else { + for (unsigned i = ArgIx; i != NumArgs; ++i) { + ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], CallType, FDecl); + Invalid |= Arg.isInvalid(); + AllArgs.push_back(Arg.take()); + } } } return Invalid; } +/// Given a function expression of unknown-any type, try to rebuild it +/// to have a function type. +static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn); + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. @@ -4464,94 +4883,39 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs, RParenLoc)); - Expr *NakedFn = Fn->IgnoreParens(); - - // Determine whether this is a call to an unresolved member function. - if (UnresolvedMemberExpr *MemE = dyn_cast<UnresolvedMemberExpr>(NakedFn)) { - // If lookup was unresolved but not dependent (i.e. didn't find - // an unresolved using declaration), it has to be an overloaded - // function set, which means it must contain either multiple - // declarations (all methods or method templates) or a single - // method template. - assert((MemE->getNumDecls() > 1) || - isa<FunctionTemplateDecl>( - (*MemE->decls_begin())->getUnderlyingDecl())); - (void)MemE; + if (Fn->getType() == Context.UnknownAnyTy) { + ExprResult result = rebuildUnknownAnyFunction(*this, Fn); + if (result.isInvalid()) return ExprError(); + Fn = result.take(); + } + if (Fn->getType() == Context.BoundMemberTy) { return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, RParenLoc); } + } - // Determine whether this is a call to a member function. - if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(NakedFn)) { - NamedDecl *MemDecl = MemExpr->getMemberDecl(); - if (isa<CXXMethodDecl>(MemDecl)) + // Check for overloaded calls. This can happen even in C due to extensions. + if (Fn->getType() == Context.OverloadTy) { + OverloadExpr::FindResult find = OverloadExpr::find(Fn); + + // We aren't supposed to apply this logic if there's an '&' involved. + if (!find.IsAddressOfOperand) { + OverloadExpr *ovl = find.Expression; + if (isa<UnresolvedLookupExpr>(ovl)) { + UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(ovl); + return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs, + RParenLoc, ExecConfig); + } else { return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, RParenLoc); - } - - // Determine whether this is a call to a pointer-to-member function. - if (BinaryOperator *BO = dyn_cast<BinaryOperator>(NakedFn)) { - if (BO->getOpcode() == BO_PtrMemD || - BO->getOpcode() == BO_PtrMemI) { - if (const FunctionProtoType *FPT - = BO->getType()->getAs<FunctionProtoType>()) { - QualType ResultTy = FPT->getCallResultType(Context); - ExprValueKind VK = Expr::getValueKindForType(FPT->getResultType()); - - // Check that the object type isn't more qualified than the - // member function we're calling. - Qualifiers FuncQuals = Qualifiers::fromCVRMask(FPT->getTypeQuals()); - Qualifiers ObjectQuals - = BO->getOpcode() == BO_PtrMemD - ? BO->getLHS()->getType().getQualifiers() - : BO->getLHS()->getType()->getAs<PointerType>() - ->getPointeeType().getQualifiers(); - - Qualifiers Difference = ObjectQuals - FuncQuals; - Difference.removeObjCGCAttr(); - Difference.removeAddressSpace(); - if (Difference) { - std::string QualsString = Difference.getAsString(); - Diag(LParenLoc, diag::err_pointer_to_member_call_drops_quals) - << BO->getType().getUnqualifiedType() - << QualsString - << (QualsString.find(' ') == std::string::npos? 1 : 2); - } - - CXXMemberCallExpr *TheCall - = new (Context) CXXMemberCallExpr(Context, Fn, Args, - NumArgs, ResultTy, VK, - RParenLoc); - - if (CheckCallReturnType(FPT->getResultType(), - BO->getRHS()->getSourceRange().getBegin(), - TheCall, 0)) - return ExprError(); - - if (ConvertArgumentsForCall(TheCall, BO, 0, FPT, Args, NumArgs, - RParenLoc)) - return ExprError(); - - return MaybeBindToTemporary(TheCall); - } - return ExprError(Diag(Fn->getLocStart(), - diag::err_typecheck_call_not_function) - << Fn->getType() << Fn->getSourceRange()); } } } // If we're directly calling a function, get the appropriate declaration. - // Also, in C++, keep track of whether we should perform argument-dependent - // lookup and whether there were any explicitly-specified template arguments. Expr *NakedFn = Fn->IgnoreParens(); - if (isa<UnresolvedLookupExpr>(NakedFn)) { - UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(NakedFn); - return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs, - RParenLoc, ExecConfig); - } NamedDecl *NDecl = 0; if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(NakedFn)) @@ -4560,6 +4924,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (isa<DeclRefExpr>(NakedFn)) NDecl = cast<DeclRefExpr>(NakedFn)->getDecl(); + else if (isa<MemberExpr>(NakedFn)) + NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl(); return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc, ExecConfig); @@ -4595,7 +4961,10 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl); // Promote the function operand. - UsualUnaryConversions(Fn); + ExprResult Result = UsualUnaryConversions(Fn); + if (Result.isInvalid()) + return ExprError(); + Fn = Result.take(); // Make the call expr early, before semantic checks. This guarantees cleanup // of arguments and function on error. @@ -4621,6 +4990,7 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) return CheckBuiltinFunctionCall(BuiltinID, TheCall); + retry: const FunctionType *FuncT; if (const PointerType *PT = Fn->getType()->getAs<PointerType>()) { // C99 6.5.2.2p1 - "The expression that denotes the called function shall @@ -4633,6 +5003,15 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, Fn->getType()->getAs<BlockPointerType>()) { FuncT = BPT->getPointeeType()->castAs<FunctionType>(); } else { + // Handle calls to expressions of unknown-any type. + if (Fn->getType() == Context.UnknownAnyTy) { + ExprResult rewrite = rebuildUnknownAnyFunction(*this, Fn); + if (rewrite.isInvalid()) return ExprError(); + Fn = rewrite.take(); + TheCall->setCallee(Fn); + goto retry; + } + return ExprError(Diag(LParenLoc, diag::err_typecheck_call_not_function) << Fn->getType() << Fn->getSourceRange()); } @@ -4703,7 +5082,12 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, Arg = ArgE.takeAs<Expr>(); } else { - DefaultArgumentPromotion(Arg); + ExprResult ArgE = DefaultArgumentPromotion(Arg); + + if (ArgE.isInvalid()) + return true; + + Arg = ArgE.takeAs<Expr>(); } if (RequireCompleteType(Arg->getSourceRange().getBegin(), @@ -4819,12 +5203,12 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg initlist, /// Prepares for a scalar cast, performing all the necessary stages /// except the final cast and returning the kind required. -static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) { +static CastKind PrepareScalarCast(Sema &S, ExprResult &Src, QualType DestTy) { // Both Src and Dest are scalar types, i.e. arithmetic or pointer. // Also, callers should have filtered out the invalid cases with // pointers. Everything else should be possible. - QualType SrcTy = Src->getType(); + QualType SrcTy = Src.get()->getType(); if (S.Context.hasSameUnqualifiedType(SrcTy, DestTy)) return CK_NoOp; @@ -4854,7 +5238,7 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) { case Type::STK_Integral: switch (DestTy->getScalarTypeKind()) { case Type::STK_Pointer: - if (Src->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) + if (Src.get()->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNull)) return CK_NullToPointer; return CK_IntegralToPointer; case Type::STK_Bool: @@ -4864,12 +5248,12 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) { case Type::STK_Floating: return CK_IntegralToFloating; case Type::STK_IntegralComplex: - S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(), - CK_IntegralCast); + Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), + CK_IntegralCast); return CK_IntegralRealToComplex; case Type::STK_FloatingComplex: - S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(), - CK_IntegralToFloating); + Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), + CK_IntegralToFloating); return CK_FloatingRealToComplex; case Type::STK_MemberPointer: llvm_unreachable("member pointer type in C"); @@ -4885,12 +5269,12 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) { case Type::STK_Integral: return CK_FloatingToIntegral; case Type::STK_FloatingComplex: - S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(), - CK_FloatingCast); + Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), + CK_FloatingCast); return CK_FloatingRealToComplex; case Type::STK_IntegralComplex: - S.ImpCastExprToType(Src, DestTy->getAs<ComplexType>()->getElementType(), - CK_FloatingToIntegral); + Src = S.ImpCastExprToType(Src.take(), DestTy->getAs<ComplexType>()->getElementType(), + CK_FloatingToIntegral); return CK_IntegralRealToComplex; case Type::STK_Pointer: llvm_unreachable("valid float->pointer cast?"); @@ -4909,14 +5293,14 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) { QualType ET = SrcTy->getAs<ComplexType>()->getElementType(); if (S.Context.hasSameType(ET, DestTy)) return CK_FloatingComplexToReal; - S.ImpCastExprToType(Src, ET, CK_FloatingComplexToReal); + Src = S.ImpCastExprToType(Src.take(), ET, CK_FloatingComplexToReal); return CK_FloatingCast; } case Type::STK_Bool: return CK_FloatingComplexToBoolean; case Type::STK_Integral: - S.ImpCastExprToType(Src, SrcTy->getAs<ComplexType>()->getElementType(), - CK_FloatingComplexToReal); + Src = S.ImpCastExprToType(Src.take(), SrcTy->getAs<ComplexType>()->getElementType(), + CK_FloatingComplexToReal); return CK_FloatingToIntegral; case Type::STK_Pointer: llvm_unreachable("valid complex float->pointer cast?"); @@ -4935,14 +5319,14 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) { QualType ET = SrcTy->getAs<ComplexType>()->getElementType(); if (S.Context.hasSameType(ET, DestTy)) return CK_IntegralComplexToReal; - S.ImpCastExprToType(Src, ET, CK_IntegralComplexToReal); + Src = S.ImpCastExprToType(Src.take(), ET, CK_IntegralComplexToReal); return CK_IntegralCast; } case Type::STK_Bool: return CK_IntegralComplexToBoolean; case Type::STK_Floating: - S.ImpCastExprToType(Src, SrcTy->getAs<ComplexType>()->getElementType(), - CK_IntegralComplexToReal); + Src = S.ImpCastExprToType(Src.take(), SrcTy->getAs<ComplexType>()->getElementType(), + CK_IntegralComplexToReal); return CK_IntegralToFloating; case Type::STK_Pointer: llvm_unreachable("valid complex int->pointer cast?"); @@ -4957,15 +5341,20 @@ static CastKind PrepareScalarCast(Sema &S, Expr *&Src, QualType DestTy) { } /// CheckCastTypes - Check type constraints for casting between types. -bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, - Expr *&castExpr, CastKind& Kind, ExprValueKind &VK, - CXXCastPath &BasePath, bool FunctionalStyle) { +ExprResult Sema::CheckCastTypes(SourceRange TyR, QualType castType, + Expr *castExpr, CastKind& Kind, ExprValueKind &VK, + CXXCastPath &BasePath, bool FunctionalStyle) { + if (castExpr->getType() == Context.UnknownAnyTy) + return checkUnknownAnyCast(TyR, castType, castExpr, Kind, VK, BasePath); + if (getLangOptions().CPlusPlus) return CXXCheckCStyleCast(SourceRange(TyR.getBegin(), castExpr->getLocEnd()), castType, VK, castExpr, Kind, BasePath, FunctionalStyle); + assert(!castExpr->getType()->isPlaceholderType()); + // We only support r-value casts in C. VK = VK_RValue; @@ -4973,18 +5362,24 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, // type needs to be scalar. if (castType->isVoidType()) { // We don't necessarily do lvalue-to-rvalue conversions on this. - IgnoredValueConversions(castExpr); + ExprResult castExprRes = IgnoredValueConversions(castExpr); + if (castExprRes.isInvalid()) + return ExprError(); + castExpr = castExprRes.take(); // Cast to void allows any expr type. Kind = CK_ToVoid; - return false; + return Owned(castExpr); } - DefaultFunctionArrayLvalueConversion(castExpr); + ExprResult castExprRes = DefaultFunctionArrayLvalueConversion(castExpr); + if (castExprRes.isInvalid()) + return ExprError(); + castExpr = castExprRes.take(); if (RequireCompleteType(TyR.getBegin(), castType, diag::err_typecheck_cast_to_incomplete)) - return true; + return ExprError(); if (!castType->isScalarType() && !castType->isVectorType()) { if (Context.hasSameUnqualifiedType(castType, castExpr->getType()) && @@ -4994,7 +5389,7 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, Diag(TyR.getBegin(), diag::ext_typecheck_cast_nonscalar) << castType << castExpr->getSourceRange(); Kind = CK_NoOp; - return false; + return Owned(castExpr); } if (castType->isUnionType()) { @@ -5011,16 +5406,19 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, break; } } - if (Field == FieldEnd) - return Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type) + if (Field == FieldEnd) { + Diag(TyR.getBegin(), diag::err_typecheck_cast_to_union_no_type) << castExpr->getType() << castExpr->getSourceRange(); + return ExprError(); + } Kind = CK_ToUnion; - return false; + return Owned(castExpr); } // Reject any other conversions to non-scalar types. - return Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) + Diag(TyR.getBegin(), diag::err_typecheck_cond_expect_scalar) << castType << castExpr->getSourceRange(); + return ExprError(); } // The type we're casting to is known to be a scalar or vector. @@ -5028,49 +5426,73 @@ bool Sema::CheckCastTypes(SourceRange TyR, QualType castType, // Require the operand to be a scalar or vector. if (!castExpr->getType()->isScalarType() && !castExpr->getType()->isVectorType()) { - return Diag(castExpr->getLocStart(), + Diag(castExpr->getLocStart(), diag::err_typecheck_expect_scalar_operand) << castExpr->getType() << castExpr->getSourceRange(); + return ExprError(); } if (castType->isExtVectorType()) return CheckExtVectorCast(TyR, castType, castExpr, Kind); - if (castType->isVectorType()) - return CheckVectorCast(TyR, castType, castExpr->getType(), Kind); - if (castExpr->getType()->isVectorType()) - return CheckVectorCast(TyR, castExpr->getType(), castType, Kind); + if (castType->isVectorType()) { + if (castType->getAs<VectorType>()->getVectorKind() == + VectorType::AltiVecVector && + (castExpr->getType()->isIntegerType() || + castExpr->getType()->isFloatingType())) { + Kind = CK_VectorSplat; + return Owned(castExpr); + } else if (CheckVectorCast(TyR, castType, castExpr->getType(), Kind)) { + return ExprError(); + } else + return Owned(castExpr); + } + if (castExpr->getType()->isVectorType()) { + if (CheckVectorCast(TyR, castExpr->getType(), castType, Kind)) + return ExprError(); + else + return Owned(castExpr); + } // The source and target types are both scalars, i.e. // - arithmetic types (fundamental, enum, and complex) // - all kinds of pointers // Note that member pointers were filtered out with C++, above. - if (isa<ObjCSelectorExpr>(castExpr)) - return Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); + if (isa<ObjCSelectorExpr>(castExpr)) { + Diag(castExpr->getLocStart(), diag::err_cast_selector_expr); + return ExprError(); + } // If either type is a pointer, the other type has to be either an // integer or a pointer. if (!castType->isArithmeticType()) { QualType castExprType = castExpr->getType(); if (!castExprType->isIntegralType(Context) && - castExprType->isArithmeticType()) - return Diag(castExpr->getLocStart(), - diag::err_cast_pointer_from_non_pointer_int) + castExprType->isArithmeticType()) { + Diag(castExpr->getLocStart(), + diag::err_cast_pointer_from_non_pointer_int) << castExprType << castExpr->getSourceRange(); + return ExprError(); + } } else if (!castExpr->getType()->isArithmeticType()) { - if (!castType->isIntegralType(Context) && castType->isArithmeticType()) - return Diag(castExpr->getLocStart(), - diag::err_cast_pointer_to_non_pointer_int) + if (!castType->isIntegralType(Context) && castType->isArithmeticType()) { + Diag(castExpr->getLocStart(), diag::err_cast_pointer_to_non_pointer_int) << castType << castExpr->getSourceRange(); + return ExprError(); + } } - Kind = PrepareScalarCast(*this, castExpr, castType); + castExprRes = Owned(castExpr); + Kind = PrepareScalarCast(*this, castExprRes, castType); + if (castExprRes.isInvalid()) + return ExprError(); + castExpr = castExprRes.take(); if (Kind == CK_BitCast) CheckCastAlign(castExpr, castType, TyR); - return false; + return Owned(castExpr); } bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, @@ -5093,8 +5515,8 @@ bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, return false; } -bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, - CastKind &Kind) { +ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, + Expr *CastExpr, CastKind &Kind) { assert(DestTy->isExtVectorType() && "Not an extended vector type!"); QualType SrcTy = CastExpr->getType(); @@ -5102,11 +5524,13 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, // If SrcTy is a VectorType, the total size must match to explicitly cast to // an ExtVectorType. if (SrcTy->isVectorType()) { - if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)) - return Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) + if (Context.getTypeSize(DestTy) != Context.getTypeSize(SrcTy)) { + Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) << DestTy << SrcTy << R; + return ExprError(); + } Kind = CK_BitCast; - return false; + return Owned(CastExpr); } // All non-pointer scalars can be cast to ExtVector type. The appropriate @@ -5118,11 +5542,14 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr, << DestTy << SrcTy << R; QualType DestElemTy = DestTy->getAs<ExtVectorType>()->getElementType(); - ImpCastExprToType(CastExpr, DestElemTy, - PrepareScalarCast(*this, CastExpr, DestElemTy)); + ExprResult CastExprRes = Owned(CastExpr); + CastKind CK = PrepareScalarCast(*this, CastExprRes, DestElemTy); + if (CastExprRes.isInvalid()) + return ExprError(); + CastExpr = ImpCastExprToType(CastExprRes.take(), DestElemTy, CK).take(); Kind = CK_VectorSplat; - return false; + return Owned(CastExpr); } ExprResult @@ -5150,12 +5577,15 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, CastKind Kind = CK_Invalid; ExprValueKind VK = VK_RValue; CXXCastPath BasePath; - if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr, - Kind, VK, BasePath)) + ExprResult CastResult = + CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr, + Kind, VK, BasePath); + if (CastResult.isInvalid()) return ExprError(); + castExpr = CastResult.take(); return Owned(CStyleCastExpr::Create(Context, - Ty->getType().getNonLValueExprType(Context), + Ty->getType().getNonLValueExprType(Context), VK, Kind, castExpr, &BasePath, Ty, LParenLoc, RParenLoc)); } @@ -5185,9 +5615,9 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, TypeSourceInfo *TInfo) { ParenListExpr *PE = cast<ParenListExpr>(Op); QualType Ty = TInfo->getType(); - bool isAltiVecLiteral = false; + bool isVectorLiteral = false; - // Check for an altivec literal, + // Check for an altivec or OpenCL literal, // i.e. all the elements are integer constants. if (getLangOptions().AltiVec && Ty->isVectorType()) { if (PE->getNumExprs() == 0) { @@ -5196,18 +5626,45 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc, } if (PE->getNumExprs() == 1) { if (!PE->getExpr(0)->getType()->isVectorType()) - isAltiVecLiteral = true; + isVectorLiteral = true; } else - isAltiVecLiteral = true; + isVectorLiteral = true; } - // If this is an altivec initializer, '(' type ')' '(' init, ..., init ')' + // If this is a vector initializer, '(' type ')' '(' init, ..., init ')' // then handle it as such. - if (isAltiVecLiteral) { + if (isVectorLiteral) { llvm::SmallVector<Expr *, 8> initExprs; - for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i) - initExprs.push_back(PE->getExpr(i)); + // '(...)' form of vector initialization in AltiVec: the number of + // initializers must be one or must match the size of the vector. + // If a single value is specified in the initializer then it will be + // replicated to all the components of the vector + if (Ty->getAs<VectorType>()->getVectorKind() == + VectorType::AltiVecVector) { + unsigned numElems = Ty->getAs<VectorType>()->getNumElements(); + // The number of initializers must be one or must match the size of the + // vector. If a single value is specified in the initializer then it will + // be replicated to all the components of the vector + if (PE->getNumExprs() == 1) { + QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); + ExprResult Literal = Owned(PE->getExpr(0)); + Literal = ImpCastExprToType(Literal.take(), ElemTy, + PrepareScalarCast(*this, Literal, ElemTy)); + return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, Literal.take()); + } + else if (PE->getNumExprs() < numElems) { + Diag(PE->getExprLoc(), + diag::err_incorrect_number_of_vector_initializers); + return ExprError(); + } + else + for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i) + initExprs.push_back(PE->getExpr(i)); + } + else + for (unsigned i = 0, e = PE->getNumExprs(); i != e; ++i) + initExprs.push_back(PE->getExpr(i)); // FIXME: This means that pretty-printing the final AST will produce curly // braces instead of the original commas. @@ -5265,11 +5722,8 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS, // In this case, check to make sure that we got here from a "NULL" // string in the source code. NullExpr = NullExpr->IgnoreParenImpCasts(); - SourceManager& SM = Context.getSourceManager(); - SourceLocation Loc = SM.getInstantiationLoc(NullExpr->getExprLoc()); - unsigned Len = - Lexer::MeasureTokenLength(Loc, SM, Context.getLangOptions()); - if (Len != 4 || memcmp(SM.getCharacterData(Loc), "NULL", 4)) + SourceLocation loc = NullExpr->getExprLoc(); + if (!findMacroSpelling(loc, "NULL")) return false; } @@ -5283,23 +5737,17 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS, /// Note that lhs is not null here, even if this is the gnu "x ?: y" extension. /// In that case, lhs = cond. /// C99 6.5.15 -QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, +QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc) { - // If both LHS and RHS are overloaded functions, try to resolve them. - if (Context.hasSameType(LHS->getType(), RHS->getType()) && - LHS->getType()->isSpecificBuiltinType(BuiltinType::Overload)) { - ExprResult LHSResult = CheckPlaceholderExpr(LHS, QuestionLoc); - if (LHSResult.isInvalid()) - return QualType(); - ExprResult RHSResult = CheckPlaceholderExpr(RHS, QuestionLoc); - if (RHSResult.isInvalid()) - return QualType(); + ExprResult lhsResult = CheckPlaceholderExpr(LHS.get()); + if (!lhsResult.isUsable()) return QualType(); + LHS = move(lhsResult); - LHS = LHSResult.take(); - RHS = RHSResult.take(); - } + ExprResult rhsResult = CheckPlaceholderExpr(RHS.get()); + if (!rhsResult.isUsable()) return QualType(); + RHS = move(rhsResult); // C++ is sufficiently different to merit its own checker. if (getLangOptions().CPlusPlus) @@ -5308,12 +5756,19 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, VK = VK_RValue; OK = OK_Ordinary; - UsualUnaryConversions(Cond); - UsualUnaryConversions(LHS); - UsualUnaryConversions(RHS); - QualType CondTy = Cond->getType(); - QualType LHSTy = LHS->getType(); - QualType RHSTy = RHS->getType(); + Cond = UsualUnaryConversions(Cond.take()); + if (Cond.isInvalid()) + return QualType(); + LHS = UsualUnaryConversions(LHS.take()); + if (LHS.isInvalid()) + return QualType(); + RHS = UsualUnaryConversions(RHS.take()); + if (RHS.isInvalid()) + return QualType(); + + QualType CondTy = Cond.get()->getType(); + QualType LHSTy = LHS.get()->getType(); + QualType RHSTy = RHS.get()->getType(); // first, check the condition. if (!CondTy->isScalarType()) { // C99 6.5.15p2 @@ -5321,14 +5776,14 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // Throw an error if its not either. if (getLangOptions().OpenCL) { if (!CondTy->isVectorType()) { - Diag(Cond->getLocStart(), + Diag(Cond.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar_or_vector) << CondTy; return QualType(); } } else { - Diag(Cond->getLocStart(), diag::err_typecheck_cond_expect_scalar) + Diag(Cond.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) << CondTy; return QualType(); } @@ -5344,25 +5799,27 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (getLangOptions().OpenCL && CondTy->isVectorType()) { // Both operands should be of scalar type. if (!LHSTy->isScalarType()) { - Diag(LHS->getLocStart(), diag::err_typecheck_cond_expect_scalar) + Diag(LHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) << CondTy; return QualType(); } if (!RHSTy->isScalarType()) { - Diag(RHS->getLocStart(), diag::err_typecheck_cond_expect_scalar) + Diag(RHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar) << CondTy; return QualType(); } // Implicity convert these scalars to the type of the condition. - ImpCastExprToType(LHS, CondTy, CK_IntegralCast); - ImpCastExprToType(RHS, CondTy, CK_IntegralCast); + LHS = ImpCastExprToType(LHS.take(), CondTy, CK_IntegralCast); + RHS = ImpCastExprToType(RHS.take(), CondTy, CK_IntegralCast); } // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) { UsualArithmeticConversions(LHS, RHS); - return LHS->getType(); + if (LHS.isInvalid() || RHS.isInvalid()) + return QualType(); + return LHS.get()->getType(); } // If both operands are the same structure or union type, the result is that @@ -5380,32 +5837,34 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // The following || allows only one side to be void (a GCC-ism). if (LHSTy->isVoidType() || RHSTy->isVoidType()) { if (!LHSTy->isVoidType()) - Diag(RHS->getLocStart(), diag::ext_typecheck_cond_one_void) - << RHS->getSourceRange(); + Diag(RHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void) + << RHS.get()->getSourceRange(); if (!RHSTy->isVoidType()) - Diag(LHS->getLocStart(), diag::ext_typecheck_cond_one_void) - << LHS->getSourceRange(); - ImpCastExprToType(LHS, Context.VoidTy, CK_ToVoid); - ImpCastExprToType(RHS, Context.VoidTy, CK_ToVoid); + Diag(LHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void) + << LHS.get()->getSourceRange(); + LHS = ImpCastExprToType(LHS.take(), Context.VoidTy, CK_ToVoid); + RHS = ImpCastExprToType(RHS.take(), Context.VoidTy, CK_ToVoid); return Context.VoidTy; } // C99 6.5.15p6 - "if one operand is a null pointer constant, the result has // the type of the other operand." if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) && - RHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { + RHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { // promote the null to a pointer. - ImpCastExprToType(RHS, LHSTy, CK_NullToPointer); + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_NullToPointer); return LHSTy; } if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) && - LHS->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(LHS, RHSTy, CK_NullToPointer); + LHS.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { + LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_NullToPointer); return RHSTy; } // All objective-c pointer type analysis is done here. QualType compositeType = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); + if (LHS.isInvalid() || RHS.isInvalid()) + return QualType(); if (!compositeType.isNull()) return compositeType; @@ -5415,12 +5874,12 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) { if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) { QualType destType = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, destType, CK_BitCast); - ImpCastExprToType(RHS, destType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast); return destType; } Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) - << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } // We have 2 block pointer types. @@ -5435,18 +5894,18 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), rhptee.getUnqualifiedType())) { Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); // In this situation, we assume void* type. No especially good // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. QualType incompatTy = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, incompatTy, CK_BitCast); - ImpCastExprToType(RHS, incompatTy, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast); return incompatTy; } // The block pointer types are compatible. - ImpCastExprToType(LHS, LHSTy, CK_BitCast); - ImpCastExprToType(RHS, LHSTy, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); return LHSTy; } @@ -5463,9 +5922,9 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); // Add qualifiers if necessary. - ImpCastExprToType(LHS, destType, CK_NoOp); + LHS = ImpCastExprToType(LHS.take(), destType, CK_NoOp); // Promote to void*. - ImpCastExprToType(RHS, destType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast); return destType; } if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) { @@ -5473,9 +5932,9 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); // Add qualifiers if necessary. - ImpCastExprToType(RHS, destType, CK_NoOp); + RHS = ImpCastExprToType(RHS.take(), destType, CK_NoOp); // Promote to void*. - ImpCastExprToType(LHS, destType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast); return destType; } @@ -5486,13 +5945,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(), rhptee.getUnqualifiedType())) { Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); // In this situation, we assume void* type. No especially good // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. QualType incompatTy = Context.getPointerType(Context.VoidTy); - ImpCastExprToType(LHS, incompatTy, CK_BitCast); - ImpCastExprToType(RHS, incompatTy, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast); return incompatTy; } // The pointer types are compatible. @@ -5502,8 +5961,8 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // type. // FIXME: Need to calculate the composite type. // FIXME: Need to add qualifiers - ImpCastExprToType(LHS, LHSTy, CK_BitCast); - ImpCastExprToType(RHS, LHSTy, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); return LHSTy; } @@ -5511,69 +5970,69 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // null pointers have been filtered out by this point. if (RHSTy->isPointerType() && LHSTy->isIntegerType()) { Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) - << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); - ImpCastExprToType(LHS, RHSTy, CK_IntegralToPointer); + << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_IntegralToPointer); return RHSTy; } if (LHSTy->isPointerType() && RHSTy->isIntegerType()) { Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch) - << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); - ImpCastExprToType(RHS, LHSTy, CK_IntegralToPointer); + << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_IntegralToPointer); return LHSTy; } // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is not a pointer type. In this case, the user most // likely forgot to take the address of the other expression. - if (DiagnoseConditionalForNull(LHS, RHS, QuestionLoc)) + if (DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc)) return QualType(); // Otherwise, the operands are not compatible. Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) - << LHSTy << RHSTy << LHS->getSourceRange() << RHS->getSourceRange(); + << LHSTy << RHSTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } /// FindCompositeObjCPointerType - Helper method to find composite type of /// two objective-c pointer types of the two input expressions. -QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, +QualType Sema::FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc) { - QualType LHSTy = LHS->getType(); - QualType RHSTy = RHS->getType(); + QualType LHSTy = LHS.get()->getType(); + QualType RHSTy = RHS.get()->getType(); // Handle things like Class and struct objc_class*. Here we case the result // to the pseudo-builtin, because that will be implicitly cast back to the // redefinition type if an attempt is made to access its fields. if (LHSTy->isObjCClassType() && (Context.hasSameType(RHSTy, Context.ObjCClassRedefinitionType))) { - ImpCastExprToType(RHS, LHSTy, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); return LHSTy; } if (RHSTy->isObjCClassType() && (Context.hasSameType(LHSTy, Context.ObjCClassRedefinitionType))) { - ImpCastExprToType(LHS, RHSTy, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast); return RHSTy; } // And the same for struct objc_object* / id if (LHSTy->isObjCIdType() && (Context.hasSameType(RHSTy, Context.ObjCIdRedefinitionType))) { - ImpCastExprToType(RHS, LHSTy, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); return LHSTy; } if (RHSTy->isObjCIdType() && (Context.hasSameType(LHSTy, Context.ObjCIdRedefinitionType))) { - ImpCastExprToType(LHS, RHSTy, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast); return RHSTy; } // And the same for struct objc_selector* / SEL if (Context.isObjCSelType(LHSTy) && (Context.hasSameType(RHSTy, Context.ObjCSelRedefinitionType))) { - ImpCastExprToType(RHS, LHSTy, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast); return LHSTy; } if (Context.isObjCSelType(RHSTy) && (Context.hasSameType(LHSTy, Context.ObjCSelRedefinitionType))) { - ImpCastExprToType(LHS, RHSTy, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_BitCast); return RHSTy; } // Check constraints for Objective-C object pointers types. @@ -5620,15 +6079,15 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, else { Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands) << LHSTy << RHSTy - << LHS->getSourceRange() << RHS->getSourceRange(); + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); QualType incompatTy = Context.getObjCIdType(); - ImpCastExprToType(LHS, incompatTy, CK_BitCast); - ImpCastExprToType(RHS, incompatTy, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast); return incompatTy; } // The object pointer types are compatible. - ImpCastExprToType(LHS, compositeType, CK_BitCast); - ImpCastExprToType(RHS, compositeType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), compositeType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), compositeType, CK_BitCast); return compositeType; } // Check Objective-C object pointer types and 'void *' @@ -5639,9 +6098,9 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, = Context.getQualifiedType(lhptee, rhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); // Add qualifiers if necessary. - ImpCastExprToType(LHS, destType, CK_NoOp); + LHS = ImpCastExprToType(LHS.take(), destType, CK_NoOp); // Promote to void*. - ImpCastExprToType(RHS, destType, CK_BitCast); + RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast); return destType; } if (LHSTy->isObjCObjectPointerType() && RHSTy->isVoidPointerType()) { @@ -5651,9 +6110,9 @@ QualType Sema::FindCompositeObjCPointerType(Expr *&LHS, Expr *&RHS, = Context.getQualifiedType(rhptee, lhptee.getQualifiers()); QualType destType = Context.getPointerType(destPointee); // Add qualifiers if necessary. - ImpCastExprToType(RHS, destType, CK_NoOp); + RHS = ImpCastExprToType(RHS.take(), destType, CK_NoOp); // Promote to void*. - ImpCastExprToType(LHS, destType, CK_BitCast); + LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast); return destType; } return QualType(); @@ -5681,7 +6140,10 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, && commonExpr->isOrdinaryOrBitFieldObject() && RHSExpr->isOrdinaryOrBitFieldObject() && Context.hasSameType(commonExpr->getType(), RHSExpr->getType()))) { - UsualUnaryConversions(commonExpr); + ExprResult commonRes = UsualUnaryConversions(commonExpr); + if (commonRes.isInvalid()) + return ExprError(); + commonExpr = commonRes.take(); } opaqueValue = new (Context) OpaqueValueExpr(commonExpr->getExprLoc(), @@ -5693,19 +6155,21 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; - QualType result = CheckConditionalOperands(CondExpr, LHSExpr, RHSExpr, + ExprResult Cond = Owned(CondExpr), LHS = Owned(LHSExpr), RHS = Owned(RHSExpr); + QualType result = CheckConditionalOperands(Cond, LHS, RHS, VK, OK, QuestionLoc); - if (result.isNull()) + if (result.isNull() || Cond.isInvalid() || LHS.isInvalid() || + RHS.isInvalid()) return ExprError(); if (!commonExpr) - return Owned(new (Context) ConditionalOperator(CondExpr, QuestionLoc, - LHSExpr, ColonLoc, - RHSExpr, result, VK, OK)); + return Owned(new (Context) ConditionalOperator(Cond.take(), QuestionLoc, + LHS.take(), ColonLoc, + RHS.take(), result, VK, OK)); return Owned(new (Context) - BinaryConditionalOperator(commonExpr, opaqueValue, CondExpr, LHSExpr, - RHSExpr, QuestionLoc, ColonLoc, result, VK, OK)); + BinaryConditionalOperator(commonExpr, opaqueValue, Cond.take(), LHS.take(), + RHS.take(), QuestionLoc, ColonLoc, result, VK, OK)); } // checkPointerTypesForAssignment - This is a very tricky routine (despite @@ -5736,6 +6200,12 @@ checkPointerTypesForAssignment(Sema &S, QualType lhsType, QualType rhsType) { if (lhq.getAddressSpace() != rhq.getAddressSpace()) ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; + // It's okay to add or remove GC qualifiers when converting to + // and from void*. + else if (lhq.withoutObjCGCAttr().compatiblyIncludes(rhq.withoutObjCGCAttr()) + && (lhptee->isVoidType() || rhptee->isVoidType())) + ; // keep old + // For GCC compatibility, other qualifier mismatches are treated // as still compatible in C. else ConvTy = Sema::CompatiblePointerDiscardsQualifiers; @@ -5885,7 +6355,7 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc, // adds casts to this they'll be wasted, but fortunately that doesn't // usually happen on valid code. OpaqueValueExpr rhs(Loc, rhsType, VK_RValue); - Expr *rhsPtr = &rhs; + ExprResult rhsPtr = &rhs; CastKind K = CK_Invalid; return CheckAssignmentConstraints(lhsType, rhsPtr, K); @@ -5909,9 +6379,9 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc, /// /// Sets 'Kind' for any result kind except Incompatible. Sema::AssignConvertType -Sema::CheckAssignmentConstraints(QualType lhsType, Expr *&rhs, +Sema::CheckAssignmentConstraints(QualType lhsType, ExprResult &rhs, CastKind &Kind) { - QualType rhsType = rhs->getType(); + QualType rhsType = rhs.get()->getType(); // Get canonical types. We're not formatting these types, just comparing // them. @@ -5950,7 +6420,7 @@ Sema::CheckAssignmentConstraints(QualType lhsType, Expr *&rhs, QualType elType = cast<ExtVectorType>(lhsType)->getElementType(); if (elType != rhsType) { Kind = PrepareScalarCast(*this, rhs, elType); - ImpCastExprToType(rhs, elType, Kind); + rhs = ImpCastExprToType(rhs.take(), elType, Kind); } Kind = CK_VectorSplat; return Compatible; @@ -6151,10 +6621,11 @@ Sema::CheckAssignmentConstraints(QualType lhsType, Expr *&rhs, /// \brief Constructs a transparent union from an expression that is /// used to initialize the transparent union. -static void ConstructTransparentUnion(ASTContext &C, Expr *&E, +static void ConstructTransparentUnion(Sema &S, ASTContext &C, ExprResult &EResult, QualType UnionType, FieldDecl *Field) { // Build an initializer list that designates the appropriate member // of the transparent union. + Expr *E = EResult.take(); InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(), &E, 1, SourceLocation()); @@ -6164,13 +6635,14 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E, // Build a compound literal constructing a value of the transparent // union type from this initializer list. TypeSourceInfo *unionTInfo = C.getTrivialTypeSourceInfo(UnionType); - E = new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType, - VK_RValue, Initializer, false); + EResult = S.Owned( + new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType, + VK_RValue, Initializer, false)); } Sema::AssignConvertType -Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { - QualType FromType = rExpr->getType(); +Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &rExpr) { + QualType FromType = rExpr.get()->getType(); // If the ArgType is a Union type, we want to handle a potential // transparent_union GCC extension. @@ -6191,25 +6663,23 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { // 2) null pointer constant if (FromType->isPointerType()) if (FromType->getAs<PointerType>()->getPointeeType()->isVoidType()) { - ImpCastExprToType(rExpr, it->getType(), CK_BitCast); + rExpr = ImpCastExprToType(rExpr.take(), it->getType(), CK_BitCast); InitField = *it; break; } - if (rExpr->isNullPointerConstant(Context, + if (rExpr.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(rExpr, it->getType(), CK_NullToPointer); + rExpr = ImpCastExprToType(rExpr.take(), it->getType(), CK_NullToPointer); InitField = *it; break; } } - Expr *rhs = rExpr; CastKind Kind = CK_Invalid; - if (CheckAssignmentConstraints(it->getType(), rhs, Kind) + if (CheckAssignmentConstraints(it->getType(), rExpr, Kind) == Compatible) { - ImpCastExprToType(rhs, it->getType(), Kind); - rExpr = rhs; + rExpr = ImpCastExprToType(rExpr.take(), it->getType(), Kind); InitField = *it; break; } @@ -6218,20 +6688,23 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType, Expr *&rExpr) { if (!InitField) return Incompatible; - ConstructTransparentUnion(Context, rExpr, ArgType, InitField); + ConstructTransparentUnion(*this, Context, rExpr, ArgType, InitField); return Compatible; } Sema::AssignConvertType -Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { +Sema::CheckSingleAssignmentConstraints(QualType lhsType, ExprResult &rExpr) { if (getLangOptions().CPlusPlus) { if (!lhsType->isRecordType()) { // C++ 5.17p3: If the left operand is not of class type, the // expression is implicitly converted (C++ 4) to the // cv-unqualified type of the left operand. - if (PerformImplicitConversion(rExpr, lhsType.getUnqualifiedType(), - AA_Assigning)) + ExprResult Res = PerformImplicitConversion(rExpr.get(), + lhsType.getUnqualifiedType(), + AA_Assigning); + if (Res.isInvalid()) return Incompatible; + rExpr = move(Res); return Compatible; } @@ -6244,9 +6717,9 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { if ((lhsType->isPointerType() || lhsType->isObjCObjectPointerType() || lhsType->isBlockPointerType()) - && rExpr->isNullPointerConstant(Context, + && rExpr.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - ImpCastExprToType(rExpr, lhsType, CK_NullToPointer); + rExpr = ImpCastExprToType(rExpr.take(), lhsType, CK_NullToPointer); return Compatible; } @@ -6256,8 +6729,11 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // expressions that suppress this implicit conversion (&, sizeof). // // Suppress this for references: C++ 8.5.3p5. - if (!lhsType->isReferenceType()) - DefaultFunctionArrayLvalueConversion(rExpr); + if (!lhsType->isReferenceType()) { + rExpr = DefaultFunctionArrayLvalueConversion(rExpr.take()); + if (rExpr.isInvalid()) + return Incompatible; + } CastKind Kind = CK_Invalid; Sema::AssignConvertType result = @@ -6269,25 +6745,25 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) { // so that we can use references in built-in functions even in C. // The getNonReferenceType() call makes sure that the resulting expression // does not have reference type. - if (result != Incompatible && rExpr->getType() != lhsType) - ImpCastExprToType(rExpr, lhsType.getNonLValueExprType(Context), Kind); + if (result != Incompatible && rExpr.get()->getType() != lhsType) + rExpr = ImpCastExprToType(rExpr.take(), lhsType.getNonLValueExprType(Context), Kind); return result; } -QualType Sema::InvalidOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { +QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) { Diag(Loc, diag::err_typecheck_invalid_operands) - << lex->getType() << rex->getType() - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getType() << rex.get()->getType() + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return QualType(); } -QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { +QualType Sema::CheckVectorOperands(SourceLocation Loc, ExprResult &lex, ExprResult &rex) { // For conversion purposes, we ignore any qualifiers. // For example, "const float" and "float" are equivalent. QualType lhsType = - Context.getCanonicalType(lex->getType()).getUnqualifiedType(); + Context.getCanonicalType(lex.get()->getType()).getUnqualifiedType(); QualType rhsType = - Context.getCanonicalType(rex->getType()).getUnqualifiedType(); + Context.getCanonicalType(rex.get()->getType()).getUnqualifiedType(); // If the vector types are identical, return. if (lhsType == rhsType) @@ -6301,17 +6777,17 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { if (LV->getElementType() == RV->getElementType() && LV->getNumElements() == RV->getNumElements()) { if (lhsType->isExtVectorType()) { - ImpCastExprToType(rex, lhsType, CK_BitCast); + rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); return lhsType; } - ImpCastExprToType(lex, rhsType, CK_BitCast); + lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast); return rhsType; } else if (Context.getTypeSize(lhsType) ==Context.getTypeSize(rhsType)){ // If we are allowing lax vector conversions, and LHS and RHS are both // vectors, the total size only needs to be the same. This is a // bitcast; no bits are changed but the result type is different. - ImpCastExprToType(rex, lhsType, CK_BitCast); + rex = ImpCastExprToType(rex.take(), lhsType, CK_BitCast); return lhsType; } } @@ -6321,7 +6797,7 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { // Handle the case of equivalent AltiVec and GCC vector types if (lhsType->isVectorType() && rhsType->isVectorType() && Context.areCompatibleVectorTypes(lhsType, rhsType)) { - ImpCastExprToType(lex, rhsType, CK_BitCast); + lex = ImpCastExprToType(lex.take(), rhsType, CK_BitCast); return rhsType; } @@ -6340,9 +6816,9 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { if (EltTy->isIntegralType(Context) && rhsType->isIntegralType(Context)) { int order = Context.getIntegerTypeOrder(EltTy, rhsType); if (order > 0) - ImpCastExprToType(rex, EltTy, CK_IntegralCast); + rex = ImpCastExprToType(rex.take(), EltTy, CK_IntegralCast); if (order >= 0) { - ImpCastExprToType(rex, lhsType, CK_VectorSplat); + rex = ImpCastExprToType(rex.take(), lhsType, CK_VectorSplat); if (swapped) std::swap(rex, lex); return lhsType; } @@ -6351,9 +6827,9 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { rhsType->isRealFloatingType()) { int order = Context.getFloatingTypeOrder(EltTy, rhsType); if (order > 0) - ImpCastExprToType(rex, EltTy, CK_FloatingCast); + rex = ImpCastExprToType(rex.take(), EltTy, CK_FloatingCast); if (order >= 0) { - ImpCastExprToType(rex, lhsType, CK_VectorSplat); + rex = ImpCastExprToType(rex.take(), lhsType, CK_VectorSplat); if (swapped) std::swap(rex, lex); return lhsType; } @@ -6362,72 +6838,78 @@ QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, Expr *&rex) { // Vectors of different size or scalar and non-ext-vector are errors. Diag(Loc, diag::err_typecheck_vector_not_convertable) - << lex->getType() << rex->getType() - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getType() << rex.get()->getType() + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return QualType(); } QualType Sema::CheckMultiplyDivideOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign, bool isDiv) { - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) + ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign, bool isDiv) { + if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) return CheckVectorOperands(Loc, lex, rex); QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); + if (lex.isInvalid() || rex.isInvalid()) + return QualType(); - if (!lex->getType()->isArithmeticType() || - !rex->getType()->isArithmeticType()) + if (!lex.get()->getType()->isArithmeticType() || + !rex.get()->getType()->isArithmeticType()) return InvalidOperands(Loc, lex, rex); // Check for division by zero. if (isDiv && - rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) - DiagRuntimeBehavior(Loc, rex, PDiag(diag::warn_division_by_zero) - << rex->getSourceRange()); + rex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) + DiagRuntimeBehavior(Loc, rex.get(), PDiag(diag::warn_division_by_zero) + << rex.get()->getSourceRange()); return compType; } QualType Sema::CheckRemainderOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { - if (lex->getType()->hasIntegerRepresentation() && - rex->getType()->hasIntegerRepresentation()) + ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign) { + if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { + if (lex.get()->getType()->hasIntegerRepresentation() && + rex.get()->getType()->hasIntegerRepresentation()) return CheckVectorOperands(Loc, lex, rex); return InvalidOperands(Loc, lex, rex); } QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); + if (lex.isInvalid() || rex.isInvalid()) + return QualType(); - if (!lex->getType()->isIntegerType() || !rex->getType()->isIntegerType()) + if (!lex.get()->getType()->isIntegerType() || !rex.get()->getType()->isIntegerType()) return InvalidOperands(Loc, lex, rex); // Check for remainder by zero. - if (rex->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) - DiagRuntimeBehavior(Loc, rex, PDiag(diag::warn_remainder_by_zero) - << rex->getSourceRange()); + if (rex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) + DiagRuntimeBehavior(Loc, rex.get(), PDiag(diag::warn_remainder_by_zero) + << rex.get()->getSourceRange()); return compType; } QualType Sema::CheckAdditionOperands( // C99 6.5.6 - Expr *&lex, Expr *&rex, SourceLocation Loc, QualType* CompLHSTy) { - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { + ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) { + if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { QualType compType = CheckVectorOperands(Loc, lex, rex); if (CompLHSTy) *CompLHSTy = compType; return compType; } QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy); + if (lex.isInvalid() || rex.isInvalid()) + return QualType(); // handle the common case first (both operands are arithmetic). - if (lex->getType()->isArithmeticType() && - rex->getType()->isArithmeticType()) { + if (lex.get()->getType()->isArithmeticType() && + rex.get()->getType()->isArithmeticType()) { if (CompLHSTy) *CompLHSTy = compType; return compType; } // Put any potential pointer into PExp - Expr* PExp = lex, *IExp = rex; + Expr* PExp = lex.get(), *IExp = rex.get(); if (IExp->getType()->isAnyPointerType()) std::swap(PExp, IExp); @@ -6440,23 +6922,23 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6 if (PointeeTy->isVoidType()) { if (getLangOptions().CPlusPlus) { Diag(Loc, diag::err_typecheck_pointer_arith_void_type) - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return QualType(); } // GNU extension: arithmetic on pointer to void Diag(Loc, diag::ext_gnu_void_ptr) - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } else if (PointeeTy->isFunctionType()) { if (getLangOptions().CPlusPlus) { Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << lex->getType() << lex->getSourceRange(); + << lex.get()->getType() << lex.get()->getSourceRange(); return QualType(); } // GNU extension: arithmetic on pointer to function Diag(Loc, diag::ext_gnu_ptr_func_arith) - << lex->getType() << lex->getSourceRange(); + << lex.get()->getType() << lex.get()->getSourceRange(); } else { // Check if we require a complete type. if (((PExp->getType()->isPointerType() && @@ -6476,9 +6958,9 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6 } if (CompLHSTy) { - QualType LHSTy = Context.isPromotableBitField(lex); + QualType LHSTy = Context.isPromotableBitField(lex.get()); if (LHSTy.isNull()) { - LHSTy = lex->getType(); + LHSTy = lex.get()->getType(); if (LHSTy->isPromotableIntegerType()) LHSTy = Context.getPromotedIntegerType(LHSTy); } @@ -6492,28 +6974,30 @@ QualType Sema::CheckAdditionOperands( // C99 6.5.6 } // C99 6.5.6 -QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, +QualType Sema::CheckSubtractionOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc, QualType* CompLHSTy) { - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { + if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { QualType compType = CheckVectorOperands(Loc, lex, rex); if (CompLHSTy) *CompLHSTy = compType; return compType; } QualType compType = UsualArithmeticConversions(lex, rex, CompLHSTy); + if (lex.isInvalid() || rex.isInvalid()) + return QualType(); // Enforce type constraints: C99 6.5.6p3. // Handle the common case first (both operands are arithmetic). - if (lex->getType()->isArithmeticType() - && rex->getType()->isArithmeticType()) { + if (lex.get()->getType()->isArithmeticType() && + rex.get()->getType()->isArithmeticType()) { if (CompLHSTy) *CompLHSTy = compType; return compType; } // Either ptr - int or ptr - ptr. - if (lex->getType()->isAnyPointerType()) { - QualType lpointee = lex->getType()->getPointeeType(); + if (lex.get()->getType()->isAnyPointerType()) { + QualType lpointee = lex.get()->getType()->getPointeeType(); // The LHS must be an completely-defined object type. @@ -6522,7 +7006,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, if (lpointee->isVoidType()) { if (getLangOptions().CPlusPlus) { Diag(Loc, diag::err_typecheck_pointer_arith_void_type) - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return QualType(); } @@ -6531,42 +7015,42 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, } else if (lpointee->isFunctionType()) { if (getLangOptions().CPlusPlus) { Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << lex->getType() << lex->getSourceRange(); + << lex.get()->getType() << lex.get()->getSourceRange(); return QualType(); } // GNU C extension: arithmetic on pointer to function - ComplainAboutFunc = lex; + ComplainAboutFunc = lex.get(); } else if (!lpointee->isDependentType() && RequireCompleteType(Loc, lpointee, PDiag(diag::err_typecheck_sub_ptr_object) - << lex->getSourceRange() - << lex->getType())) + << lex.get()->getSourceRange() + << lex.get()->getType())) return QualType(); // Diagnose bad cases where we step over interface counts. if (lpointee->isObjCObjectType() && LangOpts.ObjCNonFragileABI) { Diag(Loc, diag::err_arithmetic_nonfragile_interface) - << lpointee << lex->getSourceRange(); + << lpointee << lex.get()->getSourceRange(); return QualType(); } // The result type of a pointer-int computation is the pointer type. - if (rex->getType()->isIntegerType()) { + if (rex.get()->getType()->isIntegerType()) { if (ComplainAboutVoid) Diag(Loc, diag::ext_gnu_void_ptr) - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); if (ComplainAboutFunc) Diag(Loc, diag::ext_gnu_ptr_func_arith) << ComplainAboutFunc->getType() << ComplainAboutFunc->getSourceRange(); - if (CompLHSTy) *CompLHSTy = lex->getType(); - return lex->getType(); + if (CompLHSTy) *CompLHSTy = lex.get()->getType(); + return lex.get()->getType(); } // Handle pointer-pointer subtractions. - if (const PointerType *RHSPTy = rex->getType()->getAs<PointerType>()) { + if (const PointerType *RHSPTy = rex.get()->getType()->getAs<PointerType>()) { QualType rpointee = RHSPTy->getPointeeType(); // RHS must be a completely-type object type. @@ -6574,7 +7058,7 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, if (rpointee->isVoidType()) { if (getLangOptions().CPlusPlus) { Diag(Loc, diag::err_typecheck_pointer_arith_void_type) - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return QualType(); } @@ -6582,26 +7066,26 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, } else if (rpointee->isFunctionType()) { if (getLangOptions().CPlusPlus) { Diag(Loc, diag::err_typecheck_pointer_arith_function_type) - << rex->getType() << rex->getSourceRange(); + << rex.get()->getType() << rex.get()->getSourceRange(); return QualType(); } // GNU extension: arithmetic on pointer to function if (!ComplainAboutFunc) - ComplainAboutFunc = rex; + ComplainAboutFunc = rex.get(); } else if (!rpointee->isDependentType() && RequireCompleteType(Loc, rpointee, PDiag(diag::err_typecheck_sub_ptr_object) - << rex->getSourceRange() - << rex->getType())) + << rex.get()->getSourceRange() + << rex.get()->getType())) return QualType(); if (getLangOptions().CPlusPlus) { // Pointee types must be the same: C++ [expr.add] if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) { Diag(Loc, diag::err_typecheck_sub_ptr_compatible) - << lex->getType() << rex->getType() - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getType() << rex.get()->getType() + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return QualType(); } } else { @@ -6610,21 +7094,21 @@ QualType Sema::CheckSubtractionOperands(Expr *&lex, Expr *&rex, Context.getCanonicalType(lpointee).getUnqualifiedType(), Context.getCanonicalType(rpointee).getUnqualifiedType())) { Diag(Loc, diag::err_typecheck_sub_ptr_compatible) - << lex->getType() << rex->getType() - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getType() << rex.get()->getType() + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return QualType(); } } if (ComplainAboutVoid) Diag(Loc, diag::ext_gnu_void_ptr) - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); if (ComplainAboutFunc) Diag(Loc, diag::ext_gnu_ptr_func_arith) << ComplainAboutFunc->getType() << ComplainAboutFunc->getSourceRange(); - if (CompLHSTy) *CompLHSTy = lex->getType(); + if (CompLHSTy) *CompLHSTy = lex.get()->getType(); return Context.getPointerDiffType(); } } @@ -6638,22 +7122,26 @@ static bool isScopedEnumerationType(QualType T) { return false; } -static void DiagnoseBadShiftValues(Sema& S, Expr *&lex, Expr *&rex, +static void DiagnoseBadShiftValues(Sema& S, ExprResult &lex, ExprResult &rex, SourceLocation Loc, unsigned Opc, QualType LHSTy) { llvm::APSInt Right; // Check right/shifter operand - if (rex->isValueDependent() || !rex->isIntegerConstantExpr(Right, S.Context)) + if (rex.get()->isValueDependent() || !rex.get()->isIntegerConstantExpr(Right, S.Context)) return; if (Right.isNegative()) { - S.Diag(Loc, diag::warn_shift_negative) << rex->getSourceRange(); + S.DiagRuntimeBehavior(Loc, rex.get(), + S.PDiag(diag::warn_shift_negative) + << rex.get()->getSourceRange()); return; } llvm::APInt LeftBits(Right.getBitWidth(), - S.Context.getTypeSize(lex->getType())); + S.Context.getTypeSize(lex.get()->getType())); if (Right.uge(LeftBits)) { - S.Diag(Loc, diag::warn_shift_gt_typewidth) << rex->getSourceRange(); + S.DiagRuntimeBehavior(Loc, rex.get(), + S.PDiag(diag::warn_shift_gt_typewidth) + << rex.get()->getSourceRange()); return; } if (Opc != BO_Shl) @@ -6664,7 +7152,7 @@ static void DiagnoseBadShiftValues(Sema& S, Expr *&lex, Expr *&rex, // integers have defined behavior modulo one more than the maximum value // representable in the result type, so never warn for those. llvm::APSInt Left; - if (lex->isValueDependent() || !lex->isIntegerConstantExpr(Left, S.Context) || + if (lex.get()->isValueDependent() || !lex.get()->isIntegerConstantExpr(Left, S.Context) || LHSTy->hasUnsignedIntegerRepresentation()) return; llvm::APInt ResultBits = @@ -6681,32 +7169,32 @@ static void DiagnoseBadShiftValues(Sema& S, Expr *&lex, Expr *&rex, if (LeftBits == ResultBits - 1) { S.Diag(Loc, diag::warn_shift_result_overrides_sign_bit) << Result.toString(10) << LHSTy - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return; } S.Diag(Loc, diag::warn_shift_result_gt_typewidth) << Result.toString(10) << Result.getMinSignedBits() << LHSTy - << Left.getBitWidth() << lex->getSourceRange() << rex->getSourceRange(); + << Left.getBitWidth() << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } // C99 6.5.7 -QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, +QualType Sema::CheckShiftOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc, unsigned Opc, bool isCompAssign) { // C99 6.5.7p2: Each of the operands shall have integer type. - if (!lex->getType()->hasIntegerRepresentation() || - !rex->getType()->hasIntegerRepresentation()) + if (!lex.get()->getType()->hasIntegerRepresentation() || + !rex.get()->getType()->hasIntegerRepresentation()) return InvalidOperands(Loc, lex, rex); // C++0x: Don't allow scoped enums. FIXME: Use something better than // hasIntegerRepresentation() above instead of this. - if (isScopedEnumerationType(lex->getType()) || - isScopedEnumerationType(rex->getType())) { + if (isScopedEnumerationType(lex.get()->getType()) || + isScopedEnumerationType(rex.get()->getType())) { return InvalidOperands(Loc, lex, rex); } // Vector shifts promote their scalar inputs to vector type. - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) + if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) return CheckVectorOperands(Loc, lex, rex); // Shifts don't perform usual arithmetic conversions, they just do integer @@ -6714,13 +7202,17 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // For the LHS, do usual unary conversions, but then reset them away // if this is a compound assignment. - Expr *old_lex = lex; - UsualUnaryConversions(lex); - QualType LHSTy = lex->getType(); + ExprResult old_lex = lex; + lex = UsualUnaryConversions(lex.take()); + if (lex.isInvalid()) + return QualType(); + QualType LHSTy = lex.get()->getType(); if (isCompAssign) lex = old_lex; // The RHS is simpler. - UsualUnaryConversions(rex); + rex = UsualUnaryConversions(rex.take()); + if (rex.isInvalid()) + return QualType(); // Sanity-check shift operands DiagnoseBadShiftValues(*this, lex, rex, Loc, Opc, LHSTy); @@ -6740,22 +7232,24 @@ static bool IsWithinTemplateSpecialization(Decl *D) { } // C99 6.5.8, C++ [expr.rel] -QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, +QualType Sema::CheckCompareOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc, unsigned OpaqueOpc, bool isRelational) { BinaryOperatorKind Opc = (BinaryOperatorKind) OpaqueOpc; // Handle vector comparisons separately. - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) + if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) return CheckVectorCompareOperands(lex, rex, Loc, isRelational); - QualType lType = lex->getType(); - QualType rType = rex->getType(); - - Expr *LHSStripped = lex->IgnoreParenImpCasts(); - Expr *RHSStripped = rex->IgnoreParenImpCasts(); + QualType lType = lex.get()->getType(); + QualType rType = rex.get()->getType(); + + Expr *LHSStripped = lex.get()->IgnoreParenImpCasts(); + Expr *RHSStripped = rex.get()->IgnoreParenImpCasts(); QualType LHSStrippedType = LHSStripped->getType(); QualType RHSStrippedType = RHSStripped->getType(); + + // Two different enums will raise a warning when compared. if (const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>()) { if (const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>()) { @@ -6764,15 +7258,15 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, !Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) { Diag(Loc, diag::warn_comparison_of_mixed_enum_types) << LHSStrippedType << RHSStrippedType - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } } } if (!lType->hasFloatingRepresentation() && !(lType->isBlockPointerType() && isRelational) && - !lex->getLocStart().isMacroID() && - !rex->getLocStart().isMacroID()) { + !lex.get()->getLocStart().isMacroID() && + !rex.get()->getLocStart().isMacroID()) { // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. @@ -6828,13 +7322,13 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) && !RHSStripped->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - literalString = lex; + literalString = lex.get(); literalStringStripped = LHSStripped; } else if ((isa<StringLiteral>(RHSStripped) || isa<ObjCEncodeExpr>(RHSStripped)) && !LHSStripped->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - literalString = rex; + literalString = rex.get(); literalStringStripped = RHSStripped; } @@ -6858,15 +7352,23 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, } // C99 6.5.8p3 / C99 6.5.9p4 - if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) + if (lex.get()->getType()->isArithmeticType() && rex.get()->getType()->isArithmeticType()) { UsualArithmeticConversions(lex, rex); + if (lex.isInvalid() || rex.isInvalid()) + return QualType(); + } else { - UsualUnaryConversions(lex); - UsualUnaryConversions(rex); + lex = UsualUnaryConversions(lex.take()); + if (lex.isInvalid()) + return QualType(); + + rex = UsualUnaryConversions(rex.take()); + if (rex.isInvalid()) + return QualType(); } - lType = lex->getType(); - rType = rex->getType(); + lType = lex.get()->getType(); + rType = rex.get()->getType(); // The result of comparisons is 'bool' in C++, 'int' in C. QualType ResultTy = Context.getLogicalOperationType(); @@ -6877,15 +7379,15 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, } else { // Check for comparisons of floating point operands using != and ==. if (lType->hasFloatingRepresentation()) - CheckFloatComparison(Loc,lex,rex); + CheckFloatComparison(Loc, lex.get(), rex.get()); if (lType->isArithmeticType() && rType->isArithmeticType()) return ResultTy; } - bool LHSIsNull = lex->isNullPointerConstant(Context, + bool LHSIsNull = lex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); - bool RHSIsNull = rex->isNullPointerConstant(Context, + bool RHSIsNull = rex.get()->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); // All of the following pointer-related warnings are GCC extensions, except @@ -6911,12 +7413,12 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, isSFINAEContext()? diag::err_typecheck_comparison_of_fptr_to_void : diag::ext_typecheck_comparison_of_fptr_to_void) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); if (isSFINAEContext()) return QualType(); - ImpCastExprToType(rex, lType, CK_BitCast); + rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); return ResultTy; } } @@ -6934,17 +7436,17 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, isSFINAEContext()? 0 : &NonStandardCompositeType); if (T.isNull()) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return QualType(); } else if (NonStandardCompositeType) { Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) << lType << rType << T - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } - ImpCastExprToType(lex, T, CK_BitCast); - ImpCastExprToType(rex, T, CK_BitCast); + lex = ImpCastExprToType(lex.take(), T, CK_BitCast); + rex = ImpCastExprToType(rex.take(), T, CK_BitCast); return ResultTy; } // C99 6.5.9p2 and C99 6.5.8p2 @@ -6953,7 +7455,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // Valid unless a relational comparison of function pointers if (isRelational && LCanPointeeTy->isFunctionType()) { Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } } else if (!isRelational && (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) { @@ -6961,15 +7463,19 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType()) && !LHSIsNull && !RHSIsNull) { Diag(Loc, diag::ext_typecheck_comparison_of_fptr_to_void) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } } else { // Invalid Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + } + if (LCanPointeeTy != RCanPointeeTy) { + if (LHSIsNull && !RHSIsNull) + lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + else + rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); } - if (LCanPointeeTy != RCanPointeeTy) - ImpCastExprToType(rex, lType, CK_BitCast); return ResultTy; } @@ -6983,7 +7489,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (RHSIsNull && ((lType->isPointerType() || lType->isNullPtrType()) || (!isRelational && lType->isMemberPointerType()))) { - ImpCastExprToType(rex, lType, + rex = ImpCastExprToType(rex.take(), lType, lType->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer); @@ -6992,7 +7498,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (LHSIsNull && ((rType->isPointerType() || rType->isNullPtrType()) || (!isRelational && rType->isMemberPointerType()))) { - ImpCastExprToType(lex, rType, + lex = ImpCastExprToType(lex.take(), rType, rType->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer); @@ -7017,19 +7523,25 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, isSFINAEContext()? 0 : &NonStandardCompositeType); if (T.isNull()) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); return QualType(); } else if (NonStandardCompositeType) { Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) << lType << rType << T - << lex->getSourceRange() << rex->getSourceRange(); + << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } - ImpCastExprToType(lex, T, CK_BitCast); - ImpCastExprToType(rex, T, CK_BitCast); + lex = ImpCastExprToType(lex.take(), T, CK_BitCast); + rex = ImpCastExprToType(rex.take(), T, CK_BitCast); return ResultTy; } + + // Handle scoped enumeration types specifically, since they don't promote + // to integers. + if (lex.get()->getType()->isEnumeralType() && + Context.hasSameUnqualifiedType(lex.get()->getType(), rex.get()->getType())) + return ResultTy; } // Handle block pointer types. @@ -7040,49 +7552,57 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (!LHSIsNull && !RHSIsNull && !Context.typesAreCompatible(lpointee, rpointee)) { Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } - ImpCastExprToType(rex, lType, CK_BitCast); + rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); return ResultTy; } + // Allow block pointers to be compared with null pointer constants. if (!isRelational && ((lType->isBlockPointerType() && rType->isPointerType()) || (lType->isPointerType() && rType->isBlockPointerType()))) { if (!LHSIsNull && !RHSIsNull) { - if (!((rType->isPointerType() && rType->getAs<PointerType>() + if (!((rType->isPointerType() && rType->castAs<PointerType>() ->getPointeeType()->isVoidType()) - || (lType->isPointerType() && lType->getAs<PointerType>() + || (lType->isPointerType() && lType->castAs<PointerType>() ->getPointeeType()->isVoidType()))) Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } - ImpCastExprToType(rex, lType, CK_BitCast); + if (LHSIsNull && !RHSIsNull) + lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + else + rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); return ResultTy; } - if ((lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType())) { - if (lType->isPointerType() || rType->isPointerType()) { - const PointerType *LPT = lType->getAs<PointerType>(); - const PointerType *RPT = rType->getAs<PointerType>(); - bool LPtrToVoid = LPT ? - Context.getCanonicalType(LPT->getPointeeType())->isVoidType() : false; - bool RPtrToVoid = RPT ? - Context.getCanonicalType(RPT->getPointeeType())->isVoidType() : false; + if (lType->isObjCObjectPointerType() || rType->isObjCObjectPointerType()) { + const PointerType *LPT = lType->getAs<PointerType>(); + const PointerType *RPT = rType->getAs<PointerType>(); + if (LPT || RPT) { + bool LPtrToVoid = LPT ? LPT->getPointeeType()->isVoidType() : false; + bool RPtrToVoid = RPT ? RPT->getPointeeType()->isVoidType() : false; if (!LPtrToVoid && !RPtrToVoid && !Context.typesAreCompatible(lType, rType)) { Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); } - ImpCastExprToType(rex, lType, CK_BitCast); + if (LHSIsNull && !RHSIsNull) + lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + else + rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); return ResultTy; } if (lType->isObjCObjectPointerType() && rType->isObjCObjectPointerType()) { if (!Context.areComparableObjCPointerTypes(lType, rType)) Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); - ImpCastExprToType(rex, lType, CK_BitCast); + << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); + if (LHSIsNull && !RHSIsNull) + lex = ImpCastExprToType(lex.take(), rType, CK_BitCast); + else + rex = ImpCastExprToType(rex.take(), lType, CK_BitCast); return ResultTy; } } @@ -7104,16 +7624,16 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (DiagID) { Diag(Loc, DiagID) - << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + << lType << rType << lex.get()->getSourceRange() << rex.get()->getSourceRange(); if (isError) return QualType(); } if (lType->isIntegerType()) - ImpCastExprToType(lex, rType, + lex = ImpCastExprToType(lex.take(), rType, LHSIsNull ? CK_NullToPointer : CK_IntegralToPointer); else - ImpCastExprToType(rex, lType, + rex = ImpCastExprToType(rex.take(), lType, RHSIsNull ? CK_NullToPointer : CK_IntegralToPointer); return ResultTy; } @@ -7121,14 +7641,15 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // Handle block pointers. if (!isRelational && RHSIsNull && lType->isBlockPointerType() && rType->isIntegerType()) { - ImpCastExprToType(rex, lType, CK_NullToPointer); + rex = ImpCastExprToType(rex.take(), lType, CK_NullToPointer); return ResultTy; } if (!isRelational && LHSIsNull && lType->isIntegerType() && rType->isBlockPointerType()) { - ImpCastExprToType(lex, rType, CK_NullToPointer); + lex = ImpCastExprToType(lex.take(), rType, CK_NullToPointer); return ResultTy; } + return InvalidOperands(Loc, lex, rex); } @@ -7136,7 +7657,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, /// operates on extended vector types. Instead of producing an IntTy result, /// like a scalar comparison, a vector comparison produces a vector of integer /// types. -QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, +QualType Sema::CheckVectorCompareOperands(ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isRelational) { // Check to make sure we're operating on vectors of the same type and width, @@ -7145,20 +7666,20 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, if (vType.isNull()) return vType; + QualType lType = lex.get()->getType(); + QualType rType = rex.get()->getType(); + // If AltiVec, the comparison results in a numeric type, i.e. // bool for C++, int for C - if (getLangOptions().AltiVec) + if (vType->getAs<VectorType>()->getVectorKind() == VectorType::AltiVecVector) return Context.getLogicalOperationType(); - QualType lType = lex->getType(); - QualType rType = rex->getType(); - // For non-floating point types, check for self-comparisons of the form // x == x, x != x, x < x, etc. These always evaluate to a constant, and // often indicate logic errors in the program. if (!lType->hasFloatingRepresentation()) { - if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex->IgnoreParens())) - if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex->IgnoreParens())) + if (DeclRefExpr* DRL = dyn_cast<DeclRefExpr>(lex.get()->IgnoreParens())) + if (DeclRefExpr* DRR = dyn_cast<DeclRefExpr>(rex.get()->IgnoreParens())) if (DRL->getDecl() == DRR->getDecl()) DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always) @@ -7170,7 +7691,7 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, // Check for comparisons of floating point operands using != and ==. if (!isRelational && lType->hasFloatingRepresentation()) { assert (rType->hasFloatingRepresentation()); - CheckFloatComparison(Loc,lex,rex); + CheckFloatComparison(Loc, lex.get(), rex.get()); } // Return the type for the comparison, which is the same as vector type for @@ -7192,51 +7713,61 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, } inline QualType Sema::CheckBitwiseOperands( - Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) { - if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) { - if (lex->getType()->hasIntegerRepresentation() && - rex->getType()->hasIntegerRepresentation()) + ExprResult &lex, ExprResult &rex, SourceLocation Loc, bool isCompAssign) { + if (lex.get()->getType()->isVectorType() || rex.get()->getType()->isVectorType()) { + if (lex.get()->getType()->hasIntegerRepresentation() && + rex.get()->getType()->hasIntegerRepresentation()) return CheckVectorOperands(Loc, lex, rex); return InvalidOperands(Loc, lex, rex); } - QualType compType = UsualArithmeticConversions(lex, rex, isCompAssign); + ExprResult lexResult = Owned(lex), rexResult = Owned(rex); + QualType compType = UsualArithmeticConversions(lexResult, rexResult, isCompAssign); + if (lexResult.isInvalid() || rexResult.isInvalid()) + return QualType(); + lex = lexResult.take(); + rex = rexResult.take(); - if (lex->getType()->isIntegralOrUnscopedEnumerationType() && - rex->getType()->isIntegralOrUnscopedEnumerationType()) + if (lex.get()->getType()->isIntegralOrUnscopedEnumerationType() && + rex.get()->getType()->isIntegralOrUnscopedEnumerationType()) return compType; return InvalidOperands(Loc, lex, rex); } inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] - Expr *&lex, Expr *&rex, SourceLocation Loc, unsigned Opc) { + ExprResult &lex, ExprResult &rex, SourceLocation Loc, unsigned Opc) { // Diagnose cases where the user write a logical and/or but probably meant a // bitwise one. We do this when the LHS is a non-bool integer and the RHS // is a constant. - if (lex->getType()->isIntegerType() && !lex->getType()->isBooleanType() && - rex->getType()->isIntegerType() && !rex->isValueDependent() && + if (lex.get()->getType()->isIntegerType() && !lex.get()->getType()->isBooleanType() && + rex.get()->getType()->isIntegerType() && !rex.get()->isValueDependent() && // Don't warn in macros. !Loc.isMacroID()) { // If the RHS can be constant folded, and if it constant folds to something // that isn't 0 or 1 (which indicate a potential logical operation that // happened to fold to true/false) then warn. Expr::EvalResult Result; - if (rex->Evaluate(Result, Context) && !Result.HasSideEffects && + if (rex.get()->Evaluate(Result, Context) && !Result.HasSideEffects && Result.Val.getInt() != 0 && Result.Val.getInt() != 1) { Diag(Loc, diag::warn_logical_instead_of_bitwise) - << rex->getSourceRange() + << rex.get()->getSourceRange() << (Opc == BO_LAnd ? "&&" : "||") << (Opc == BO_LAnd ? "&" : "|"); } } if (!Context.getLangOptions().CPlusPlus) { - UsualUnaryConversions(lex); - UsualUnaryConversions(rex); + lex = UsualUnaryConversions(lex.take()); + if (lex.isInvalid()) + return QualType(); + + rex = UsualUnaryConversions(rex.take()); + if (rex.isInvalid()) + return QualType(); - if (!lex->getType()->isScalarType() || !rex->getType()->isScalarType()) + if (!lex.get()->getType()->isScalarType() || !rex.get()->getType()->isScalarType()) return InvalidOperands(Loc, lex, rex); return Context.IntTy; @@ -7248,9 +7779,15 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] // C++ [expr.log.and]p1 // C++ [expr.log.or]p1 // The operands are both contextually converted to type bool. - if (PerformContextuallyConvertToBool(lex) || - PerformContextuallyConvertToBool(rex)) + ExprResult lexRes = PerformContextuallyConvertToBool(lex.get()); + if (lexRes.isInvalid()) + return InvalidOperands(Loc, lex, rex); + lex = move(lexRes); + + ExprResult rexRes = PerformContextuallyConvertToBool(rex.get()); + if (rexRes.isInvalid()) return InvalidOperands(Loc, lex, rex); + rex = move(rexRes); // C++ [expr.log.and]p2 // C++ [expr.log.or]p2 @@ -7281,6 +7818,35 @@ static bool IsReadonlyProperty(Expr *E, Sema &S) { return false; } +static bool IsConstProperty(Expr *E, Sema &S) { + if (E->getStmtClass() == Expr::ObjCPropertyRefExprClass) { + const ObjCPropertyRefExpr* PropExpr = cast<ObjCPropertyRefExpr>(E); + if (PropExpr->isImplicitProperty()) return false; + + ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty(); + QualType T = PDecl->getType(); + if (T->isReferenceType()) + T = T->getAs<ReferenceType>()->getPointeeType(); + CanQualType CT = S.Context.getCanonicalType(T); + return CT.isConstQualified(); + } + return false; +} + +static bool IsReadonlyMessage(Expr *E, Sema &S) { + if (E->getStmtClass() != Expr::MemberExprClass) + return false; + const MemberExpr *ME = cast<MemberExpr>(E); + NamedDecl *Member = ME->getMemberDecl(); + if (isa<FieldDecl>(Member)) { + Expr *Base = ME->getBase()->IgnoreParenImpCasts(); + if (Base->getStmtClass() != Expr::ObjCMessageExprClass) + return false; + return cast<ObjCMessageExpr>(Base)->getMethodDecl() != 0; + } + return false; +} + /// CheckForModifiableLvalue - Verify that E is a modifiable lvalue. If not, /// emit an error and return true. If so, return false. static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { @@ -7289,6 +7855,10 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { &Loc); if (IsLV == Expr::MLV_Valid && IsReadonlyProperty(E, S)) IsLV = Expr::MLV_ReadonlyProperty; + else if (Expr::MLV_ConstQualified && IsConstProperty(E, S)) + IsLV = Expr::MLV_Valid; + else if (IsLV == Expr::MLV_ClassTemporary && IsReadonlyMessage(E, S)) + IsLV = Expr::MLV_InvalidMessageExpression; if (IsLV == Expr::MLV_Valid) return false; @@ -7331,6 +7901,9 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_NoSetterProperty: Diag = diag::error_nosetter_property_assignment; break; + case Expr::MLV_InvalidMessageExpression: + Diag = diag::error_readonly_message_assignment; + break; case Expr::MLV_SubObjCPropertySetting: Diag = diag::error_no_subobject_property_setting; break; @@ -7349,7 +7922,7 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { // C99 6.5.16.1 -QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, +QualType Sema::CheckAssignmentOperands(Expr *LHS, ExprResult &RHS, SourceLocation Loc, QualType CompoundType) { // Verify that LHS is a modifiable lvalue, and emit error if not. @@ -7357,14 +7930,21 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, return QualType(); QualType LHSType = LHS->getType(); - QualType RHSType = CompoundType.isNull() ? RHS->getType() : CompoundType; + QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() : CompoundType; AssignConvertType ConvTy; if (CompoundType.isNull()) { QualType LHSTy(LHSType); // Simple assignment "x = y". - if (LHS->getObjectKind() == OK_ObjCProperty) - ConvertPropertyForLValue(LHS, RHS, LHSTy); + if (LHS->getObjectKind() == OK_ObjCProperty) { + ExprResult LHSResult = Owned(LHS); + ConvertPropertyForLValue(LHSResult, RHS, LHSTy); + if (LHSResult.isInvalid()) + return QualType(); + LHS = LHSResult.take(); + } ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS); + if (RHS.isInvalid()) + return QualType(); // Special case of NSObject attributes on c-style pointer types. if (ConvTy == IncompatiblePointer && ((Context.isObjCNSObjectType(LHSType) && @@ -7382,7 +7962,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, // If the RHS is a unary plus or minus, check to see if they = and + are // right next to each other. If so, the user may have typo'd "x =+ 4" // instead of "x += 4". - Expr *RHSCheck = RHS; + Expr *RHSCheck = RHS.get(); if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RHSCheck)) RHSCheck = ICE->getSubExpr(); if (UnaryOperator *UO = dyn_cast<UnaryOperator>(RHSCheck)) { @@ -7406,32 +7986,12 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, } if (DiagnoseAssignmentResult(ConvTy, Loc, LHSType, RHSType, - RHS, AA_Assigning)) + RHS.get(), AA_Assigning)) return QualType(); - - // Check to see if the destination operand is a dereferenced null pointer. If - // so, and if not volatile-qualified, this is undefined behavior that the - // optimizer will delete, so warn about it. People sometimes try to use this - // to get a deterministic trap and are surprised by clang's behavior. This - // only handles the pattern "*null = whatever", which is a very syntactic - // check. - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(LHS->IgnoreParenCasts())) - if (UO->getOpcode() == UO_Deref && - UO->getSubExpr()->IgnoreParenCasts()-> - isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull) && - !UO->getType().isVolatileQualified()) { - DiagRuntimeBehavior(UO->getOperatorLoc(), UO, - PDiag(diag::warn_indirection_through_null) - << UO->getSubExpr()->getSourceRange()); - DiagRuntimeBehavior(UO->getOperatorLoc(), UO, - PDiag(diag::note_indirection_through_null)); - } - + CheckForNullPointerDereference(*this, LHS); // Check for trivial buffer overflows. - if (const ArraySubscriptExpr *ae - = dyn_cast<ArraySubscriptExpr>(LHS->IgnoreParenCasts())) - CheckArrayAccess(ae); + CheckArrayAccess(LHS->IgnoreParenCasts()); // C99 6.5.16p3: The type of an assignment expression is the type of the // left operand unless the left operand has qualified type, in which case @@ -7445,34 +8005,34 @@ QualType Sema::CheckAssignmentOperands(Expr *LHS, Expr *&RHS, } // C99 6.5.17 -static QualType CheckCommaOperands(Sema &S, Expr *&LHS, Expr *&RHS, +static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { - S.DiagnoseUnusedExprResult(LHS); + S.DiagnoseUnusedExprResult(LHS.get()); - ExprResult LHSResult = S.CheckPlaceholderExpr(LHS, Loc); - if (LHSResult.isInvalid()) + LHS = S.CheckPlaceholderExpr(LHS.take()); + RHS = S.CheckPlaceholderExpr(RHS.take()); + if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); - ExprResult RHSResult = S.CheckPlaceholderExpr(RHS, Loc); - if (RHSResult.isInvalid()) - return QualType(); - RHS = RHSResult.take(); - // C's comma performs lvalue conversion (C99 6.3.2.1) on both its // operands, but not unary promotions. // C++'s comma does not do any conversions at all (C++ [expr.comma]p1). // So we treat the LHS as a ignored value, and in C++ we allow the // containing site to determine what should be done with the RHS. - S.IgnoredValueConversions(LHS); + LHS = S.IgnoredValueConversions(LHS.take()); + if (LHS.isInvalid()) + return QualType(); if (!S.getLangOptions().CPlusPlus) { - S.DefaultFunctionArrayLvalueConversion(RHS); - if (!RHS->getType()->isVoidType()) - S.RequireCompleteType(Loc, RHS->getType(), diag::err_incomplete_type); + RHS = S.DefaultFunctionArrayLvalueConversion(RHS.take()); + if (RHS.isInvalid()) + return QualType(); + if (!RHS.get()->getType()->isVoidType()) + S.RequireCompleteType(Loc, RHS.get()->getType(), diag::err_incomplete_type); } - return RHS->getType(); + return RHS.get()->getType(); } /// CheckIncrementDecrementOperand - unlike most "Check" methods, this routine @@ -7535,7 +8095,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, S.Diag(OpLoc, diag::ext_integer_increment_complex) << ResType << Op->getSourceRange(); } else if (ResType->isPlaceholderType()) { - ExprResult PR = S.CheckPlaceholderExpr(Op, OpLoc); + ExprResult PR = S.CheckPlaceholderExpr(Op); if (PR.isInvalid()) return QualType(); return CheckIncrementDecrementOperand(S, PR.take(), VK, OpLoc, isInc, isPrefix); @@ -7562,7 +8122,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, } } -void Sema::ConvertPropertyForRValue(Expr *&E) { +ExprResult Sema::ConvertPropertyForRValue(Expr *E) { assert(E->getValueKind() == VK_LValue && E->getObjectKind() == OK_ObjCProperty); const ObjCPropertyRefExpr *PRE = E->getObjCProperty(); @@ -7586,28 +8146,30 @@ void Sema::ConvertPropertyForRValue(Expr *&E) { ExprResult Result = MaybeBindToTemporary(E); if (!Result.isInvalid()) E = Result.take(); + + return Owned(E); } -void Sema::ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType &LHSTy) { - assert(LHS->getValueKind() == VK_LValue && - LHS->getObjectKind() == OK_ObjCProperty); - const ObjCPropertyRefExpr *PRE = LHS->getObjCProperty(); +void Sema::ConvertPropertyForLValue(ExprResult &LHS, ExprResult &RHS, QualType &LHSTy) { + assert(LHS.get()->getValueKind() == VK_LValue && + LHS.get()->getObjectKind() == OK_ObjCProperty); + const ObjCPropertyRefExpr *PropRef = LHS.get()->getObjCProperty(); - if (PRE->isImplicitProperty()) { + if (PropRef->isImplicitProperty()) { // If using property-dot syntax notation for assignment, and there is a // setter, RHS expression is being passed to the setter argument. So, // type conversion (and comparison) is RHS to setter's argument type. - if (const ObjCMethodDecl *SetterMD = PRE->getImplicitPropertySetter()) { + if (const ObjCMethodDecl *SetterMD = PropRef->getImplicitPropertySetter()) { ObjCMethodDecl::param_iterator P = SetterMD->param_begin(); LHSTy = (*P)->getType(); // Otherwise, if the getter returns an l-value, just call that. } else { - QualType Result = PRE->getImplicitPropertyGetter()->getResultType(); + QualType Result = PropRef->getImplicitPropertyGetter()->getResultType(); ExprValueKind VK = Expr::getValueKindForType(Result); if (VK == VK_LValue) { - LHS = ImplicitCastExpr::Create(Context, LHS->getType(), - CK_GetObjCProperty, LHS, 0, VK); + LHS = ImplicitCastExpr::Create(Context, LHS.get()->getType(), + CK_GetObjCProperty, LHS.take(), 0, VK); return; } } @@ -7616,11 +8178,9 @@ void Sema::ConvertPropertyForLValue(Expr *&LHS, Expr *&RHS, QualType &LHSTy) { if (getLangOptions().CPlusPlus && LHSTy->isRecordType()) { InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, LHSTy); - Expr *Arg = RHS; - ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), - Owned(Arg)); + ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), RHS); if (!ArgE.isInvalid()) - RHS = ArgE.takeAs<Expr>(); + RHS = ArgE; } } @@ -7695,10 +8255,15 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, return S.Context.DependentTy; if (OrigOp->getType() == S.Context.OverloadTy) return S.Context.OverloadTy; + if (OrigOp->getType() == S.Context.UnknownAnyTy) + return S.Context.UnknownAnyTy; + if (OrigOp->getType() == S.Context.BoundMemberTy) { + S.Diag(OpLoc, diag::err_invalid_form_pointer_member_function) + << OrigOp->getSourceRange(); + return QualType(); + } - ExprResult PR = S.CheckPlaceholderExpr(OrigOp, OpLoc); - if (PR.isInvalid()) return QualType(); - OrigOp = PR.take(); + assert(!OrigOp->getType()->isPlaceholderType()); // Make sure to ignore parentheses in subsequent checks Expr *op = OrigOp->IgnoreParens(); @@ -7717,7 +8282,7 @@ static QualType CheckAddressOfOperand(Sema &S, Expr *OrigOp, ValueDecl *dcl = getPrimaryDecl(op); Expr::LValueClassification lval = op->ClassifyLValue(S.Context); - if (lval == Expr::LV_ClassTemporary) { + if (lval == Expr::LV_ClassTemporary) { bool sfinae = S.isSFINAEContext(); S.Diag(OpLoc, sfinae ? diag::err_typecheck_addrof_class_temporary : diag::ext_typecheck_addrof_class_temporary) @@ -7833,7 +8398,10 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, if (Op->isTypeDependent()) return S.Context.DependentTy; - S.UsualUnaryConversions(Op); + ExprResult ConvResult = S.UsualUnaryConversions(Op); + if (ConvResult.isInvalid()) + return QualType(); + Op = ConvResult.take(); QualType OpTy = Op->getType(); QualType Result; @@ -7847,7 +8415,7 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, OpTy->getAs<ObjCObjectPointerType>()) Result = OPT->getPointeeType(); else { - ExprResult PR = S.CheckPlaceholderExpr(Op, OpLoc); + ExprResult PR = S.CheckPlaceholderExpr(Op); if (PR.isInvalid()) return QualType(); if (PR.take() != Op) return CheckIndirectionOperand(S, PR.take(), VK, OpLoc); @@ -7970,7 +8538,8 @@ static void DiagnoseSelfAssignment(Sema &S, Expr *lhs, Expr *rhs, /// built-in operations; ActOnBinOp handles overloaded operators. ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, - Expr *lhs, Expr *rhs) { + Expr *lhsExpr, Expr *rhsExpr) { + ExprResult lhs = Owned(lhsExpr), rhs = Owned(rhsExpr); QualType ResultTy; // Result type of the binary operator. // The following two variables are used for compound assignment operators QualType CompLHSTy; // Type of LHS after promotions for computation @@ -7978,16 +8547,33 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; + // Check if a 'foo<int>' involved in a binary op, identifies a single + // function unambiguously (i.e. an lvalue ala 13.4) + // But since an assignment can trigger target based overload, exclude it in + // our blind search. i.e: + // template<class T> void f(); template<class T, class U> void f(U); + // f<int> == 0; // resolve f<int> blindly + // void (*p)(int); p = f<int>; // resolve f<int> using target + if (Opc != BO_Assign) { + ExprResult resolvedLHS = CheckPlaceholderExpr(lhs.get()); + if (!resolvedLHS.isUsable()) return ExprError(); + lhs = move(resolvedLHS); + + ExprResult resolvedRHS = CheckPlaceholderExpr(rhs.get()); + if (!resolvedRHS.isUsable()) return ExprError(); + rhs = move(resolvedRHS); + } + switch (Opc) { case BO_Assign: - ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType()); + ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, QualType()); if (getLangOptions().CPlusPlus && - lhs->getObjectKind() != OK_ObjCProperty) { - VK = lhs->getValueKind(); - OK = lhs->getObjectKind(); + lhs.get()->getObjectKind() != OK_ObjCProperty) { + VK = lhs.get()->getValueKind(); + OK = lhs.get()->getObjectKind(); } if (!ResultTy.isNull()) - DiagnoseSelfAssignment(*this, lhs, rhs, OpLoc); + DiagnoseSelfAssignment(*this, lhs.get(), rhs.get(), OpLoc); break; case BO_PtrMemD: case BO_PtrMemI: @@ -8036,60 +8622,59 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, CompResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc, true, Opc == BO_DivAssign); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) + ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); break; case BO_RemAssign: CompResultTy = CheckRemainderOperands(lhs, rhs, OpLoc, true); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) + ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); break; case BO_AddAssign: CompResultTy = CheckAdditionOperands(lhs, rhs, OpLoc, &CompLHSTy); - if (!CompResultTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) + ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); break; case BO_SubAssign: CompResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc, &CompLHSTy); - if (!CompResultTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) + ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); break; case BO_ShlAssign: case BO_ShrAssign: CompResultTy = CheckShiftOperands(lhs, rhs, OpLoc, Opc, true); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) + ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); break; case BO_AndAssign: case BO_XorAssign: case BO_OrAssign: CompResultTy = CheckBitwiseOperands(lhs, rhs, OpLoc, true); CompLHSTy = CompResultTy; - if (!CompResultTy.isNull()) - ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, CompResultTy); + if (!CompResultTy.isNull() && !lhs.isInvalid() && !rhs.isInvalid()) + ResultTy = CheckAssignmentOperands(lhs.get(), rhs, OpLoc, CompResultTy); break; case BO_Comma: ResultTy = CheckCommaOperands(*this, lhs, rhs, OpLoc); - if (getLangOptions().CPlusPlus) { - VK = rhs->getValueKind(); - OK = rhs->getObjectKind(); + if (getLangOptions().CPlusPlus && !rhs.isInvalid()) { + VK = rhs.get()->getValueKind(); + OK = rhs.get()->getObjectKind(); } break; } - if (ResultTy.isNull()) + if (ResultTy.isNull() || lhs.isInvalid() || rhs.isInvalid()) return ExprError(); if (CompResultTy.isNull()) - return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, ResultTy, - VK, OK, OpLoc)); - - if (getLangOptions().CPlusPlus && lhs->getObjectKind() != OK_ObjCProperty) { + return Owned(new (Context) BinaryOperator(lhs.take(), rhs.take(), Opc, + ResultTy, VK, OK, OpLoc)); + if (getLangOptions().CPlusPlus && lhs.get()->getObjectKind() != OK_ObjCProperty) { VK = VK_LValue; - OK = lhs->getObjectKind(); + OK = lhs.get()->getObjectKind(); } - return Owned(new (Context) CompoundAssignOperator(lhs, rhs, Opc, ResultTy, - VK, OK, CompLHSTy, + return Owned(new (Context) CompoundAssignOperator(lhs.take(), rhs.take(), Opc, + ResultTy, VK, OK, CompLHSTy, CompResultTy, OpLoc)); } @@ -8161,23 +8746,23 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, Self.PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(lhs->getLocStart(), OpLoc) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(lhsopc), - Self.PDiag(diag::note_precedence_bitwise_first) - << BinOp::getOpcodeStr(Opc), - SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd()), Self.PDiag(diag::note_precedence_bitwise_silence) << BinOp::getOpcodeStr(lhsopc), - lhs->getSourceRange()); + lhs->getSourceRange(), + Self.PDiag(diag::note_precedence_bitwise_first) + << BinOp::getOpcodeStr(Opc), + SourceRange(cast<BinOp>(lhs)->getRHS()->getLocStart(), rhs->getLocEnd())); else if (BinOp::isComparisonOp(rhsopc)) SuggestParentheses(Self, OpLoc, Self.PDiag(diag::warn_precedence_bitwise_rel) << SourceRange(OpLoc, rhs->getLocEnd()) << BinOp::getOpcodeStr(Opc) << BinOp::getOpcodeStr(rhsopc), + Self.PDiag(diag::note_precedence_bitwise_silence) + << BinOp::getOpcodeStr(rhsopc), + rhs->getSourceRange(), Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), - SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart()), - Self.PDiag(diag::note_precedence_bitwise_silence) - << BinOp::getOpcodeStr(rhsopc), - rhs->getSourceRange()); + SourceRange(lhs->getLocEnd(), cast<BinOp>(rhs)->getLHS()->getLocStart())); } /// \brief It accepts a '&&' expr that is inside a '||' one. @@ -8185,14 +8770,13 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, /// in parentheses. static void EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc, - Expr *E) { - assert(isa<BinaryOperator>(E) && - cast<BinaryOperator>(E)->getOpcode() == BO_LAnd); - SuggestParentheses(Self, OpLoc, + BinaryOperator *Bop) { + assert(Bop->getOpcode() == BO_LAnd); + SuggestParentheses(Self, Bop->getOperatorLoc(), Self.PDiag(diag::warn_logical_and_in_logical_or) - << E->getSourceRange(), + << Bop->getSourceRange() << OpLoc, Self.PDiag(diag::note_logical_and_in_logical_or_silence), - E->getSourceRange(), + Bop->getSourceRange(), Self.PDiag(0), SourceRange()); } @@ -8316,7 +8900,8 @@ ExprResult Sema::BuildBinOp(Scope *S, SourceLocation OpLoc, ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, - Expr *Input) { + Expr *InputExpr) { + ExprResult Input = Owned(InputExpr); ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; QualType resultType; @@ -8325,23 +8910,28 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UO_PreDec: case UO_PostInc: case UO_PostDec: - resultType = CheckIncrementDecrementOperand(*this, Input, VK, OpLoc, + resultType = CheckIncrementDecrementOperand(*this, Input.get(), VK, OpLoc, Opc == UO_PreInc || Opc == UO_PostInc, Opc == UO_PreInc || Opc == UO_PreDec); break; case UO_AddrOf: - resultType = CheckAddressOfOperand(*this, Input, OpLoc); + resultType = CheckAddressOfOperand(*this, Input.get(), OpLoc); break; - case UO_Deref: - DefaultFunctionArrayLvalueConversion(Input); - resultType = CheckIndirectionOperand(*this, Input, VK, OpLoc); + case UO_Deref: { + ExprResult resolved = CheckPlaceholderExpr(Input.get()); + if (!resolved.isUsable()) return ExprError(); + Input = move(resolved); + Input = DefaultFunctionArrayLvalueConversion(Input.take()); + resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc); break; + } case UO_Plus: case UO_Minus: - UsualUnaryConversions(Input); - resultType = Input->getType(); + Input = UsualUnaryConversions(Input.take()); + if (Input.isInvalid()) return ExprError(); + resultType = Input.get()->getType(); if (resultType->isDependentType()) break; if (resultType->isArithmeticType() || // C99 6.5.3.3p1 @@ -8355,49 +8945,59 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType->isPointerType()) break; else if (resultType->isPlaceholderType()) { - ExprResult PR = CheckPlaceholderExpr(Input, OpLoc); - if (PR.isInvalid()) return ExprError(); - return CreateBuiltinUnaryOp(OpLoc, Opc, PR.take()); + Input = CheckPlaceholderExpr(Input.take()); + if (Input.isInvalid()) return ExprError(); + return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take()); } return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) - << resultType << Input->getSourceRange()); + << resultType << Input.get()->getSourceRange()); + case UO_Not: // bitwise complement - UsualUnaryConversions(Input); - resultType = Input->getType(); + Input = UsualUnaryConversions(Input.take()); + if (Input.isInvalid()) return ExprError(); + resultType = Input.get()->getType(); if (resultType->isDependentType()) break; // C99 6.5.3.3p1. We allow complex int and float as a GCC extension. if (resultType->isComplexType() || resultType->isComplexIntegerType()) // C99 does not support '~' for complex conjugation. Diag(OpLoc, diag::ext_integer_complement_complex) - << resultType << Input->getSourceRange(); + << resultType << Input.get()->getSourceRange(); else if (resultType->hasIntegerRepresentation()) break; else if (resultType->isPlaceholderType()) { - ExprResult PR = CheckPlaceholderExpr(Input, OpLoc); - if (PR.isInvalid()) return ExprError(); - return CreateBuiltinUnaryOp(OpLoc, Opc, PR.take()); + Input = CheckPlaceholderExpr(Input.take()); + if (Input.isInvalid()) return ExprError(); + return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take()); } else { return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) - << resultType << Input->getSourceRange()); + << resultType << Input.get()->getSourceRange()); } break; + case UO_LNot: // logical negation // Unlike +/-/~, integer promotions aren't done here (C99 6.5.3.3p5). - DefaultFunctionArrayLvalueConversion(Input); - resultType = Input->getType(); + Input = DefaultFunctionArrayLvalueConversion(Input.take()); + if (Input.isInvalid()) return ExprError(); + resultType = Input.get()->getType(); if (resultType->isDependentType()) break; - if (resultType->isScalarType()) { // C99 6.5.3.3p1 - // ok, fallthrough + if (resultType->isScalarType()) { + // C99 6.5.3.3p1: ok, fallthrough; + if (Context.getLangOptions().CPlusPlus) { + // C++03 [expr.unary.op]p8, C++0x [expr.unary.op]p9: + // operand contextually converted to bool. + Input = ImpCastExprToType(Input.take(), Context.BoolTy, + ScalarTypeToBooleanCastKind(resultType)); + } } else if (resultType->isPlaceholderType()) { - ExprResult PR = CheckPlaceholderExpr(Input, OpLoc); - if (PR.isInvalid()) return ExprError(); - return CreateBuiltinUnaryOp(OpLoc, Opc, PR.take()); + Input = CheckPlaceholderExpr(Input.take()); + if (Input.isInvalid()) return ExprError(); + return CreateBuiltinUnaryOp(OpLoc, Opc, Input.take()); } else { return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) - << resultType << Input->getSourceRange()); + << resultType << Input.get()->getSourceRange()); } // LNot always has type int. C99 6.5.3.3p5. @@ -8408,20 +9008,21 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, case UO_Imag: resultType = CheckRealImagOperand(*this, Input, OpLoc, Opc == UO_Real); // _Real and _Imag map ordinary l-values into ordinary l-values. - if (Input->getValueKind() != VK_RValue && - Input->getObjectKind() == OK_Ordinary) - VK = Input->getValueKind(); + if (Input.isInvalid()) return ExprError(); + if (Input.get()->getValueKind() != VK_RValue && + Input.get()->getObjectKind() == OK_Ordinary) + VK = Input.get()->getValueKind(); break; case UO_Extension: - resultType = Input->getType(); - VK = Input->getValueKind(); - OK = Input->getObjectKind(); + resultType = Input.get()->getType(); + VK = Input.get()->getValueKind(); + OK = Input.get()->getObjectKind(); break; } - if (resultType.isNull()) + if (resultType.isNull() || Input.isInvalid()) return ExprError(); - return Owned(new (Context) UnaryOperator(Input, Opc, resultType, + return Owned(new (Context) UnaryOperator(Input.take(), Opc, resultType, VK, OK, OpLoc)); } @@ -8488,26 +9089,28 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, LastLabelStmt = Label; LastStmt = Label->getSubStmt(); } - if (Expr *LastExpr = dyn_cast<Expr>(LastStmt)) { + if (Expr *LastE = dyn_cast<Expr>(LastStmt)) { // Do function/array conversion on the last expression, but not // lvalue-to-rvalue. However, initialize an unqualified type. - DefaultFunctionArrayConversion(LastExpr); - Ty = LastExpr->getType().getUnqualifiedType(); + ExprResult LastExpr = DefaultFunctionArrayConversion(LastE); + if (LastExpr.isInvalid()) + return ExprError(); + Ty = LastExpr.get()->getType().getUnqualifiedType(); - if (!Ty->isDependentType() && !LastExpr->isTypeDependent()) { - ExprResult Res = PerformCopyInitialization( + if (!Ty->isDependentType() && !LastExpr.get()->isTypeDependent()) { + LastExpr = PerformCopyInitialization( InitializedEntity::InitializeResult(LPLoc, Ty, false), SourceLocation(), - Owned(LastExpr)); - if (Res.isInvalid()) + LastExpr); + if (LastExpr.isInvalid()) return ExprError(); - if ((LastExpr = Res.takeAs<Expr>())) { + if (LastExpr.get() != 0) { if (!LastLabelStmt) - Compound->setLastStmt(LastExpr); + Compound->setLastStmt(LastExpr.take()); else - LastLabelStmt->setSubStmt(LastExpr); + LastLabelStmt->setSubStmt(LastExpr.take()); StmtExprMayBindToTemp = true; } } @@ -8779,8 +9382,8 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) { // Check whether that explicit signature was synthesized by // GetTypeForDeclarator. If so, don't save that as part of the // written signature. - if (ExplicitSignature.getLParenLoc() == - ExplicitSignature.getRParenLoc()) { + if (ExplicitSignature.getLocalRangeBegin() == + ExplicitSignature.getLocalRangeEnd()) { // This would be much cheaper if we stored TypeLocs instead of // TypeSourceInfos. TypeLoc Result = ExplicitSignature.getResultLoc(); @@ -8942,7 +9545,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, // If we don't have a function type, just build one from nothing. } else { FunctionProtoType::ExtProtoInfo EPI; - EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, 0, CC_Default); + EPI.ExtInfo = FunctionType::ExtInfo(NoReturn, false, 0, CC_Default); BlockTy = Context.getFunctionType(RetTy, 0, 0, EPI); } @@ -8984,7 +9587,10 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, // a pointer for va_arg. VaListType = Context.getArrayDecayedType(VaListType); // Make sure the input expression also decays appropriately. - UsualUnaryConversions(E); + ExprResult Result = UsualUnaryConversions(E); + if (Result.isInvalid()) + return ExprError(); + E = Result.take(); } else { // Otherwise, the va_list argument must be an l-value because // it is modified by va_arg. @@ -9260,6 +9866,8 @@ Sema::PopExpressionEvaluationContext() { void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { assert(D && "No declaration?"); + D->setReferenced(); + if (D->isUsed(false)) return; @@ -9393,6 +10001,9 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) { if (MSInfo->getPointOfInstantiation().isInvalid() && MSInfo->getTemplateSpecializationKind()== TSK_ImplicitInstantiation) { MSInfo->setPointOfInstantiation(Loc); + // This is a modification of an existing AST node. Notify listeners. + if (ASTMutationListener *L = getASTMutationListener()) + L->StaticDataMemberInstantiated(Var); PendingInstantiations.push_back(std::make_pair(Var, Loc)); } } @@ -9624,10 +10235,13 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { return; } + Diag(Loc, diagnostic) << E->getSourceRange(); + SourceLocation Open = E->getSourceRange().getBegin(); SourceLocation Close = PP.getLocForEndOfToken(E->getSourceRange().getEnd()); - - Diag(Loc, diagnostic) << E->getSourceRange(); + Diag(Loc, diag::note_condition_assign_silence) + << FixItHint::CreateInsertion(Open, "(") + << FixItHint::CreateInsertion(Close, ")"); if (IsOrAssign) Diag(Loc, diag::note_condition_or_assign_to_comparison) @@ -9635,10 +10249,6 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { else Diag(Loc, diag::note_condition_assign_to_comparison) << FixItHint::CreateReplacement(Loc, "=="); - - Diag(Loc, diag::note_condition_assign_silence) - << FixItHint::CreateInsertion(Open, "(") - << FixItHint::CreateInsertion(Close, ")"); } /// \brief Redundant parentheses over an equality comparison can indicate @@ -9648,6 +10258,9 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *parenE) { SourceLocation parenLoc = parenE->getLocStart(); if (parenLoc.isInvalid() || parenLoc.isMacroID()) return; + // Don't warn for dependent expressions. + if (parenE->isTypeDependent()) + return; Expr *E = parenE->IgnoreParens(); @@ -9658,68 +10271,467 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *parenE) { SourceLocation Loc = opE->getOperatorLoc(); Diag(Loc, diag::warn_equality_with_extra_parens) << E->getSourceRange(); - Diag(Loc, diag::note_equality_comparison_to_assign) - << FixItHint::CreateReplacement(Loc, "="); Diag(Loc, diag::note_equality_comparison_silence) << FixItHint::CreateRemoval(parenE->getSourceRange().getBegin()) << FixItHint::CreateRemoval(parenE->getSourceRange().getEnd()); + Diag(Loc, diag::note_equality_comparison_to_assign) + << FixItHint::CreateReplacement(Loc, "="); } } -bool Sema::CheckBooleanCondition(Expr *&E, SourceLocation Loc) { +ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) { DiagnoseAssignmentAsCondition(E); if (ParenExpr *parenE = dyn_cast<ParenExpr>(E)) DiagnoseEqualityWithExtraParens(parenE); - if (!E->isTypeDependent()) { - if (E->isBoundMemberFunction(Context)) - return Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func) - << E->getSourceRange(); + ExprResult result = CheckPlaceholderExpr(E); + if (result.isInvalid()) return ExprError(); + E = result.take(); + if (!E->isTypeDependent()) { if (getLangOptions().CPlusPlus) return CheckCXXBooleanCondition(E); // C++ 6.4p4 - DefaultFunctionArrayLvalueConversion(E); + ExprResult ERes = DefaultFunctionArrayLvalueConversion(E); + if (ERes.isInvalid()) + return ExprError(); + E = ERes.take(); QualType T = E->getType(); - if (!T->isScalarType()) // C99 6.8.4.1p1 - return Diag(Loc, diag::err_typecheck_statement_requires_scalar) - << T << E->getSourceRange(); + if (!T->isScalarType()) { // C99 6.8.4.1p1 + Diag(Loc, diag::err_typecheck_statement_requires_scalar) + << T << E->getSourceRange(); + return ExprError(); + } } - return false; + return Owned(E); } ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, Expr *Sub) { if (!Sub) return ExprError(); - - if (CheckBooleanCondition(Sub, Loc)) + + return CheckBooleanCondition(Sub, Loc); +} + +namespace { + /// A visitor for rebuilding a call to an __unknown_any expression + /// to have an appropriate type. + struct RebuildUnknownAnyFunction + : StmtVisitor<RebuildUnknownAnyFunction, ExprResult> { + + Sema &S; + + RebuildUnknownAnyFunction(Sema &S) : S(S) {} + + ExprResult VisitStmt(Stmt *S) { + llvm_unreachable("unexpected statement!"); + return ExprError(); + } + + ExprResult VisitExpr(Expr *expr) { + S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_call) + << expr->getSourceRange(); + return ExprError(); + } + + /// Rebuild an expression which simply semantically wraps another + /// expression which it shares the type and value kind of. + template <class T> ExprResult rebuildSugarExpr(T *expr) { + ExprResult subResult = Visit(expr->getSubExpr()); + if (subResult.isInvalid()) return ExprError(); + + Expr *subExpr = subResult.take(); + expr->setSubExpr(subExpr); + expr->setType(subExpr->getType()); + expr->setValueKind(subExpr->getValueKind()); + assert(expr->getObjectKind() == OK_Ordinary); + return expr; + } + + ExprResult VisitParenExpr(ParenExpr *paren) { + return rebuildSugarExpr(paren); + } + + ExprResult VisitUnaryExtension(UnaryOperator *op) { + return rebuildSugarExpr(op); + } + + ExprResult VisitUnaryAddrOf(UnaryOperator *op) { + ExprResult subResult = Visit(op->getSubExpr()); + if (subResult.isInvalid()) return ExprError(); + + Expr *subExpr = subResult.take(); + op->setSubExpr(subExpr); + op->setType(S.Context.getPointerType(subExpr->getType())); + assert(op->getValueKind() == VK_RValue); + assert(op->getObjectKind() == OK_Ordinary); + return op; + } + + ExprResult resolveDecl(Expr *expr, ValueDecl *decl) { + if (!isa<FunctionDecl>(decl)) return VisitExpr(expr); + + expr->setType(decl->getType()); + + assert(expr->getValueKind() == VK_RValue); + if (S.getLangOptions().CPlusPlus && + !(isa<CXXMethodDecl>(decl) && + cast<CXXMethodDecl>(decl)->isInstance())) + expr->setValueKind(VK_LValue); + + return expr; + } + + ExprResult VisitMemberExpr(MemberExpr *mem) { + return resolveDecl(mem, mem->getMemberDecl()); + } + + ExprResult VisitDeclRefExpr(DeclRefExpr *ref) { + return resolveDecl(ref, ref->getDecl()); + } + }; +} + +/// Given a function expression of unknown-any type, try to rebuild it +/// to have a function type. +static ExprResult rebuildUnknownAnyFunction(Sema &S, Expr *fn) { + ExprResult result = RebuildUnknownAnyFunction(S).Visit(fn); + if (result.isInvalid()) return ExprError(); + return S.DefaultFunctionArrayConversion(result.take()); +} + +namespace { + /// A visitor for rebuilding an expression of type __unknown_anytype + /// into one which resolves the type directly on the referring + /// expression. Strict preservation of the original source + /// structure is not a goal. + struct RebuildUnknownAnyExpr + : StmtVisitor<RebuildUnknownAnyExpr, ExprResult> { + + Sema &S; + + /// The current destination type. + QualType DestType; + + RebuildUnknownAnyExpr(Sema &S, QualType castType) + : S(S), DestType(castType) {} + + ExprResult VisitStmt(Stmt *S) { + llvm_unreachable("unexpected statement!"); + return ExprError(); + } + + ExprResult VisitExpr(Expr *expr) { + S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_expr) + << expr->getSourceRange(); + return ExprError(); + } + + ExprResult VisitCallExpr(CallExpr *call); + ExprResult VisitObjCMessageExpr(ObjCMessageExpr *message); + + /// Rebuild an expression which simply semantically wraps another + /// expression which it shares the type and value kind of. + template <class T> ExprResult rebuildSugarExpr(T *expr) { + ExprResult subResult = Visit(expr->getSubExpr()); + if (subResult.isInvalid()) return ExprError(); + Expr *subExpr = subResult.take(); + expr->setSubExpr(subExpr); + expr->setType(subExpr->getType()); + expr->setValueKind(subExpr->getValueKind()); + assert(expr->getObjectKind() == OK_Ordinary); + return expr; + } + + ExprResult VisitParenExpr(ParenExpr *paren) { + return rebuildSugarExpr(paren); + } + + ExprResult VisitUnaryExtension(UnaryOperator *op) { + return rebuildSugarExpr(op); + } + + ExprResult VisitUnaryAddrOf(UnaryOperator *op) { + const PointerType *ptr = DestType->getAs<PointerType>(); + if (!ptr) { + S.Diag(op->getOperatorLoc(), diag::err_unknown_any_addrof) + << op->getSourceRange(); + return ExprError(); + } + assert(op->getValueKind() == VK_RValue); + assert(op->getObjectKind() == OK_Ordinary); + op->setType(DestType); + + // Build the sub-expression as if it were an object of the pointee type. + DestType = ptr->getPointeeType(); + ExprResult subResult = Visit(op->getSubExpr()); + if (subResult.isInvalid()) return ExprError(); + op->setSubExpr(subResult.take()); + return op; + } + + ExprResult VisitImplicitCastExpr(ImplicitCastExpr *ice); + + ExprResult resolveDecl(Expr *expr, ValueDecl *decl); + + ExprResult VisitMemberExpr(MemberExpr *mem) { + return resolveDecl(mem, mem->getMemberDecl()); + } + + ExprResult VisitDeclRefExpr(DeclRefExpr *ref) { + return resolveDecl(ref, ref->getDecl()); + } + }; +} + +/// Rebuilds a call expression which yielded __unknown_anytype. +ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *call) { + Expr *callee = call->getCallee(); + + enum FnKind { + FK_MemberFunction, + FK_FunctionPointer, + FK_BlockPointer + }; + + FnKind kind; + QualType type = callee->getType(); + if (type == S.Context.BoundMemberTy) { + assert(isa<CXXMemberCallExpr>(call) || isa<CXXOperatorCallExpr>(call)); + kind = FK_MemberFunction; + type = Expr::findBoundMemberType(callee); + } else if (const PointerType *ptr = type->getAs<PointerType>()) { + type = ptr->getPointeeType(); + kind = FK_FunctionPointer; + } else { + type = type->castAs<BlockPointerType>()->getPointeeType(); + kind = FK_BlockPointer; + } + const FunctionType *fnType = type->castAs<FunctionType>(); + + // Verify that this is a legal result type of a function. + if (DestType->isArrayType() || DestType->isFunctionType()) { + unsigned diagID = diag::err_func_returning_array_function; + if (kind == FK_BlockPointer) + diagID = diag::err_block_returning_array_function; + + S.Diag(call->getExprLoc(), diagID) + << DestType->isFunctionType() << DestType; return ExprError(); - - return Owned(Sub); + } + + // Otherwise, go ahead and set DestType as the call's result. + call->setType(DestType.getNonLValueExprType(S.Context)); + call->setValueKind(Expr::getValueKindForType(DestType)); + assert(call->getObjectKind() == OK_Ordinary); + + // Rebuild the function type, replacing the result type with DestType. + if (const FunctionProtoType *proto = dyn_cast<FunctionProtoType>(fnType)) + DestType = S.Context.getFunctionType(DestType, + proto->arg_type_begin(), + proto->getNumArgs(), + proto->getExtProtoInfo()); + else + DestType = S.Context.getFunctionNoProtoType(DestType, + fnType->getExtInfo()); + + // Rebuild the appropriate pointer-to-function type. + switch (kind) { + case FK_MemberFunction: + // Nothing to do. + break; + + case FK_FunctionPointer: + DestType = S.Context.getPointerType(DestType); + break; + + case FK_BlockPointer: + DestType = S.Context.getBlockPointerType(DestType); + break; + } + + // Finally, we can recurse. + ExprResult calleeResult = Visit(callee); + if (!calleeResult.isUsable()) return ExprError(); + call->setCallee(calleeResult.take()); + + // Bind a temporary if necessary. + return S.MaybeBindToTemporary(call); } -/// Check for operands with placeholder types and complain if found. -/// Returns true if there was an error and no recovery was possible. -ExprResult Sema::CheckPlaceholderExpr(Expr *E, SourceLocation Loc) { - const BuiltinType *BT = E->getType()->getAs<BuiltinType>(); - if (!BT || !BT->isPlaceholderType()) return Owned(E); - - // If this is overload, check for a single overload. - assert(BT->getKind() == BuiltinType::Overload); - - if (FunctionDecl *Specialization - = ResolveSingleFunctionTemplateSpecialization(E)) { - // The access doesn't really matter in this case. - DeclAccessPair Found = DeclAccessPair::make(Specialization, - Specialization->getAccess()); - E = FixOverloadedFunctionReference(E, Found, Specialization); - if (!E) return ExprError(); - return Owned(E); +ExprResult RebuildUnknownAnyExpr::VisitObjCMessageExpr(ObjCMessageExpr *msg) { + ObjCMethodDecl *method = msg->getMethodDecl(); + assert(method && "__unknown_anytype message without result type?"); + + // Verify that this is a legal result type of a call. + if (DestType->isArrayType() || DestType->isFunctionType()) { + S.Diag(msg->getExprLoc(), diag::err_func_returning_array_function) + << DestType->isFunctionType() << DestType; + return ExprError(); } - Diag(Loc, diag::err_ovl_unresolvable) << E->getSourceRange(); + assert(method->getResultType() == S.Context.UnknownAnyTy); + method->setResultType(DestType); + + // Change the type of the message. + msg->setType(DestType.getNonReferenceType()); + msg->setValueKind(Expr::getValueKindForType(DestType)); + + return S.MaybeBindToTemporary(msg); +} + +ExprResult RebuildUnknownAnyExpr::VisitImplicitCastExpr(ImplicitCastExpr *ice) { + // The only case we should ever see here is a function-to-pointer decay. + assert(ice->getCastKind() == CK_FunctionToPointerDecay); + assert(ice->getValueKind() == VK_RValue); + assert(ice->getObjectKind() == OK_Ordinary); + + ice->setType(DestType); + + // Rebuild the sub-expression as the pointee (function) type. + DestType = DestType->castAs<PointerType>()->getPointeeType(); + + ExprResult result = Visit(ice->getSubExpr()); + if (!result.isUsable()) return ExprError(); + + ice->setSubExpr(result.take()); + return S.Owned(ice); +} + +ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *expr, ValueDecl *decl) { + ExprValueKind valueKind = VK_LValue; + QualType type = DestType; + + // We know how to make this work for certain kinds of decls: + + // - functions + if (FunctionDecl *fn = dyn_cast<FunctionDecl>(decl)) { + // This is true because FunctionDecls must always have function + // type, so we can't be resolving the entire thing at once. + assert(type->isFunctionType()); + + if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(fn)) + if (method->isInstance()) { + valueKind = VK_RValue; + type = S.Context.BoundMemberTy; + } + + // Function references aren't l-values in C. + if (!S.getLangOptions().CPlusPlus) + valueKind = VK_RValue; + + // - variables + } else if (isa<VarDecl>(decl)) { + if (const ReferenceType *refTy = type->getAs<ReferenceType>()) { + type = refTy->getPointeeType(); + } else if (type->isFunctionType()) { + S.Diag(expr->getExprLoc(), diag::err_unknown_any_var_function_type) + << decl << expr->getSourceRange(); + return ExprError(); + } + + // - nothing else + } else { + S.Diag(expr->getExprLoc(), diag::err_unsupported_unknown_any_decl) + << decl << expr->getSourceRange(); + return ExprError(); + } + + decl->setType(DestType); + expr->setType(type); + expr->setValueKind(valueKind); + return S.Owned(expr); +} + +/// Check a cast of an unknown-any type. We intentionally only +/// trigger this for C-style casts. +ExprResult Sema::checkUnknownAnyCast(SourceRange typeRange, QualType castType, + Expr *castExpr, CastKind &castKind, + ExprValueKind &VK, CXXCastPath &path) { + // Rewrite the casted expression from scratch. + ExprResult result = RebuildUnknownAnyExpr(*this, castType).Visit(castExpr); + if (!result.isUsable()) return ExprError(); + + castExpr = result.take(); + VK = castExpr->getValueKind(); + castKind = CK_NoOp; + + return castExpr; +} + +static ExprResult diagnoseUnknownAnyExpr(Sema &S, Expr *e) { + Expr *orig = e; + unsigned diagID = diag::err_uncasted_use_of_unknown_any; + while (true) { + e = e->IgnoreParenImpCasts(); + if (CallExpr *call = dyn_cast<CallExpr>(e)) { + e = call->getCallee(); + diagID = diag::err_uncasted_call_of_unknown_any; + } else { + break; + } + } + + SourceLocation loc; + NamedDecl *d; + if (DeclRefExpr *ref = dyn_cast<DeclRefExpr>(e)) { + loc = ref->getLocation(); + d = ref->getDecl(); + } else if (MemberExpr *mem = dyn_cast<MemberExpr>(e)) { + loc = mem->getMemberLoc(); + d = mem->getMemberDecl(); + } else if (ObjCMessageExpr *msg = dyn_cast<ObjCMessageExpr>(e)) { + diagID = diag::err_uncasted_call_of_unknown_any; + loc = msg->getSelectorLoc(); + d = msg->getMethodDecl(); + assert(d && "unknown method returning __unknown_any?"); + } else { + S.Diag(e->getExprLoc(), diag::err_unsupported_unknown_any_expr) + << e->getSourceRange(); + return ExprError(); + } + + S.Diag(loc, diagID) << d << orig->getSourceRange(); + + // Never recoverable. return ExprError(); } + +/// Check for operands with placeholder types and complain if found. +/// Returns true if there was an error and no recovery was possible. +ExprResult Sema::CheckPlaceholderExpr(Expr *E) { + // Placeholder types are always *exactly* the appropriate builtin type. + QualType type = E->getType(); + + // Overloaded expressions. + if (type == Context.OverloadTy) + return ResolveAndFixSingleFunctionTemplateSpecialization(E, false, true, + E->getSourceRange(), + QualType(), + diag::err_ovl_unresolvable); + + // Bound member functions. + if (type == Context.BoundMemberTy) { + Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func) + << E->getSourceRange(); + return ExprError(); + } + + // Expressions of unknown type. + if (type == Context.UnknownAnyTy) + return diagnoseUnknownAnyExpr(*this, E); + + assert(!type->isPlaceholderType()); + return Owned(E); +} + +bool Sema::CheckCaseExpression(Expr *expr) { + if (expr->isTypeDependent()) + return true; + if (expr->isValueDependent() || expr->isIntegerConstantExpr(Context)) + return expr->getType()->isIntegralOrEnumerationType(); + return false; +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index 6dd7aab..7f1bf59 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -28,6 +28,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace sema; @@ -138,10 +139,11 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, LookInScope = true; } + TypeDecl *NonMatchingTypeDecl = 0; LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); for (unsigned Step = 0; Step != 2; ++Step) { // Look for the name first in the computed lookup context (if we - // have one) and, if that fails to find a match, in the sope (if + // have one) and, if that fails to find a match, in the scope (if // we're allowed to look there). Found.clear(); if (Step == 0 && LookupCtx) @@ -164,6 +166,9 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, return ParsedType::make(T); } + + if (!SearchType.isNull()) + NonMatchingTypeDecl = Type; } // If the name that we found is a class template name, and it is @@ -236,24 +241,22 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, if (isDependent) { // We didn't find our type, but that's okay: it's dependent // anyway. - NestedNameSpecifier *NNS = 0; - SourceRange Range; - if (SS.isSet()) { - NNS = (NestedNameSpecifier *)SS.getScopeRep(); - Range = SourceRange(SS.getRange().getBegin(), NameLoc); - } else { - NNS = NestedNameSpecifier::Create(Context, &II); - Range = SourceRange(NameLoc); - } - - QualType T = CheckTypenameType(ETK_None, NNS, II, - SourceLocation(), - Range, NameLoc); + + // FIXME: What if we have no nested-name-specifier? + QualType T = CheckTypenameType(ETK_None, SourceLocation(), + SS.getWithLocInContext(Context), + II, NameLoc); return ParsedType::make(T); } - if (ObjectTypePtr) - Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) + if (NonMatchingTypeDecl) { + QualType T = Context.getTypeDeclType(NonMatchingTypeDecl); + Diag(NameLoc, diag::err_destructor_expr_type_mismatch) + << T << SearchType; + Diag(NonMatchingTypeDecl->getLocation(), diag::note_destructor_type_here) + << T; + } else if (ObjectTypePtr) + Diag(NameLoc, diag::err_ident_in_dtor_not_a_type) << &II; else Diag(NameLoc, diag::err_destructor_class_name); @@ -321,7 +324,7 @@ ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals); if (!Context.hasSameType(T, UnqualT)) { T = UnqualT; - ImpCastExprToType(E, UnqualT, CK_NoOp, CastCategory(E)); + E = ImpCastExprToType(E, UnqualT, CK_NoOp, CastCategory(E)).take(); } } @@ -341,7 +344,7 @@ ExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { // Find the std::type_info type. - if (!StdNamespace) + if (!getStdNamespace()) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); if (!CXXTypeInfoDecl) { @@ -477,17 +480,21 @@ Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) { ExprResult Sema::ActOnCXXThrow(SourceLocation OpLoc, Expr *Ex) { // Don't report an error if 'throw' is used in system headers. - if (!getLangOptions().Exceptions && + if (!getLangOptions().CXXExceptions && !getSourceManager().isInSystemHeader(OpLoc)) Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; - if (Ex && !Ex->isTypeDependent() && CheckCXXThrowOperand(OpLoc, Ex)) - return ExprError(); + if (Ex && !Ex->isTypeDependent()) { + ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex); + if (ExRes.isInvalid()) + return ExprError(); + Ex = ExRes.take(); + } return Owned(new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc)); } /// CheckCXXThrowOperand - Validate the operand of a throw. -bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { +ExprResult Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E) { // C++ [except.throw]p3: // A throw-expression initializes a temporary object, called the exception // object, the type of which is determined by removing any top-level @@ -495,10 +502,13 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // the type from "array of T" or "function returning T" to "pointer to T" // or "pointer to function returning T", [...] if (E->getType().hasQualifiers()) - ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp, - CastCategory(E)); + E = ImpCastExprToType(E, E->getType().getUnqualifiedType(), CK_NoOp, + CastCategory(E)).take(); - DefaultFunctionArrayConversion(E); + ExprResult Res = DefaultFunctionArrayConversion(E); + if (Res.isInvalid()) + return ExprError(); + E = Res.take(); // If the type of the exception would be an incomplete type or a pointer // to an incomplete type other than (cv) void the program is ill-formed. @@ -513,12 +523,12 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { PDiag(isPointer ? diag::err_throw_incomplete_ptr : diag::err_throw_incomplete) << E->getSourceRange())) - return true; + return ExprError(); if (RequireNonAbstractType(ThrowLoc, E->getType(), PDiag(diag::err_throw_abstract_type) << E->getSourceRange())) - return true; + return ExprError(); } // Initialize the exception result. This implicitly weeds out @@ -529,16 +539,16 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { InitializedEntity Entity = InitializedEntity::InitializeException(ThrowLoc, E->getType(), /*NRVO=*/false); - ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable, - QualType(), E); + Res = PerformMoveOrCopyInitialization(Entity, NRVOVariable, + QualType(), E); if (Res.isInvalid()) - return true; - E = Res.takeAs<Expr>(); + return ExprError(); + E = Res.take(); // If the exception has class type, we need additional handling. const RecordType *RecordTy = Ty->getAs<RecordType>(); if (!RecordTy) - return false; + return Owned(E); CXXRecordDecl *RD = cast<CXXRecordDecl>(RecordTy->getDecl()); // If we are throwing a polymorphic class type or pointer thereof, @@ -547,21 +557,21 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *&E) { // If a pointer is thrown, the referenced object will not be destroyed. if (isPointer) - return false; + return Owned(E); // If the class has a non-trivial destructor, we must be able to call it. if (RD->hasTrivialDestructor()) - return false; + return Owned(E); CXXDestructorDecl *Destructor = const_cast<CXXDestructorDecl*>(LookupDestructor(RD)); if (!Destructor) - return false; + return Owned(E); MarkDeclarationReferenced(E->getExprLoc(), Destructor); CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_exception) << Ty); - return false; + return Owned(E); } CXXMethodDecl *Sema::tryCaptureCXXThis() { @@ -666,10 +676,13 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, CastKind Kind = CK_Invalid; ExprValueKind VK = VK_RValue; CXXCastPath BasePath; - if (CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0], - Kind, VK, BasePath, - /*FunctionalStyle=*/true)) + ExprResult CastExpr = + CheckCastTypes(TInfo->getTypeLoc().getSourceRange(), Ty, Exprs[0], + Kind, VK, BasePath, + /*FunctionalStyle=*/true); + if (CastExpr.isInvalid()) return ExprError(); + Exprs[0] = CastExpr.take(); exprs.release(); @@ -846,16 +859,18 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, diag::err_auto_new_ctor_multiple_expressions) << AllocType << TypeRange); } - QualType DeducedType; - if (!DeduceAutoType(AllocType, ConstructorArgs.get()[0], DeducedType)) + TypeSourceInfo *DeducedType = 0; + if (!DeduceAutoType(AllocTypeInfo, ConstructorArgs.get()[0], DeducedType)) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) << AllocType << ConstructorArgs.get()[0]->getType() << TypeRange << ConstructorArgs.get()[0]->getSourceRange()); + if (!DeducedType) + return ExprError(); - AllocType = DeducedType; - AllocTypeInfo = Context.getTrivialTypeSourceInfo(AllocType, StartLoc); + AllocTypeInfo = DeducedType; + AllocType = AllocTypeInfo->getType(); } // Per C++0x [expr.new]p5, the type being constructed may be a @@ -935,8 +950,8 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - ImpCastExprToType(ArraySize, Context.getSizeType(), - CK_IntegralCast); + ArraySize = ImpCastExprToType(ArraySize, Context.getSizeType(), + CK_IntegralCast).take(); } FunctionDecl *OperatorNew = 0; @@ -1090,7 +1105,10 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, else if (AllocType->isVariablyModifiedType()) return Diag(Loc, diag::err_variably_modified_new_type) << AllocType; - + else if (unsigned AddressSpace = AllocType.getAddressSpace()) + return Diag(Loc, diag::err_address_space_qualified_new) + << AllocType.getUnqualifiedType() << AddressSpace; + return false; } @@ -1384,16 +1402,16 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs); return true; - case OR_Deleted: + case OR_Deleted: { Diag(StartLoc, diag::err_ovl_deleted_call) << Best->Function->isDeleted() << Name - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Range; Candidates.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); return true; } + } assert(false && "Unreachable, bad result from BestViableFunction"); return true; } @@ -1402,11 +1420,18 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, /// DeclareGlobalNewDelete - Declare the global forms of operator new and /// delete. These are: /// @code +/// // C++03: /// void* operator new(std::size_t) throw(std::bad_alloc); /// void* operator new[](std::size_t) throw(std::bad_alloc); /// void operator delete(void *) throw(); /// void operator delete[](void *) throw(); +/// // C++0x: +/// void* operator new(std::size_t); +/// void* operator new[](std::size_t); +/// void operator delete(void *); +/// void operator delete[](void *); /// @endcode +/// C++0x operator delete is implicitly noexcept. /// Note that the placement and nothrow forms of new are *not* implicitly /// declared. Their use requires including \<new\>. void Sema::DeclareGlobalNewDelete() { @@ -1418,10 +1443,16 @@ void Sema::DeclareGlobalNewDelete() { // implicitly declared in global scope in each translation unit of a // program // + // C++03: // void* operator new(std::size_t) throw(std::bad_alloc); // void* operator new[](std::size_t) throw(std::bad_alloc); // void operator delete(void*) throw(); // void operator delete[](void*) throw(); + // C++0x: + // void* operator new(std::size_t); + // void* operator new[](std::size_t); + // void operator delete(void*); + // void operator delete[](void*); // // These implicit declarations introduce only the function names operator // new, operator new[], operator delete, operator delete[]. @@ -1430,14 +1461,16 @@ void Sema::DeclareGlobalNewDelete() { // "std" or "bad_alloc" as necessary to form the exception specification. // However, we do not make these implicit declarations visible to name // lookup. - if (!StdBadAlloc) { + // Note that the C++0x versions of operator delete are deallocation functions, + // and thus are implicitly noexcept. + if (!StdBadAlloc && !getLangOptions().CPlusPlus0x) { // The "std::bad_alloc" class has not yet been declared, so build it // implicitly. StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, getOrCreateStdNamespace(), - SourceLocation(), + SourceLocation(), SourceLocation(), &PP.getIdentifierTable().get("bad_alloc"), - SourceLocation(), 0); + 0); getStdBadAlloc()->setImplicit(true); } @@ -1493,21 +1526,27 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, bool HasBadAllocExceptionSpec = (Name.getCXXOverloadedOperator() == OO_New || Name.getCXXOverloadedOperator() == OO_Array_New); - if (HasBadAllocExceptionSpec) { + if (HasBadAllocExceptionSpec && !getLangOptions().CPlusPlus0x) { assert(StdBadAlloc && "Must have std::bad_alloc declared"); BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); } FunctionProtoType::ExtProtoInfo EPI; - EPI.HasExceptionSpec = true; if (HasBadAllocExceptionSpec) { - EPI.NumExceptions = 1; - EPI.Exceptions = &BadAllocType; + if (!getLangOptions().CPlusPlus0x) { + EPI.ExceptionSpecType = EST_Dynamic; + EPI.NumExceptions = 1; + EPI.Exceptions = &BadAllocType; + } + } else { + EPI.ExceptionSpecType = getLangOptions().CPlusPlus0x ? + EST_BasicNoexcept : EST_DynamicNone; } QualType FnType = Context.getFunctionType(Return, &Argument, 1, EPI); FunctionDecl *Alloc = - FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), Name, + FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), + SourceLocation(), Name, FnType, /*TInfo=*/0, SC_None, SC_None, false, true); Alloc->setImplicit(); @@ -1516,9 +1555,9 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, Alloc->addAttr(::new (Context) MallocAttr(SourceLocation(), Context)); ParmVarDecl *Param = ParmVarDecl::Create(Context, Alloc, SourceLocation(), - 0, Argument, /*TInfo=*/0, - SC_None, - SC_None, 0); + SourceLocation(), 0, + Argument, /*TInfo=*/0, + SC_None, SC_None, 0); Alloc->setParams(&Param, 1); // FIXME: Also add this declaration to the IdentifierResolver, but @@ -1608,19 +1647,20 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, /// @code delete [] ptr; @endcode ExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, - bool ArrayForm, Expr *Ex) { + bool ArrayForm, Expr *ExE) { // C++ [expr.delete]p1: // The operand shall have a pointer type, or a class type having a single // conversion function to a pointer type. The result has type void. // // DR599 amends "pointer type" to "pointer to object type" in both cases. + ExprResult Ex = Owned(ExE); FunctionDecl *OperatorDelete = 0; bool ArrayFormAsWritten = ArrayForm; bool UsualArrayDeleteWantsSize = false; - if (!Ex->isTypeDependent()) { - QualType Type = Ex->getType(); + if (!Ex.get()->isTypeDependent()) { + QualType Type = Ex.get()->getType(); if (const RecordType *Record = Type->getAs<RecordType>()) { if (RequireCompleteType(StartLoc, Type, @@ -1652,15 +1692,18 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // We have a single conversion to a pointer-to-object type. Perform // that conversion. // TODO: don't redo the conversion calculation. - if (!PerformImplicitConversion(Ex, + ExprResult Res = + PerformImplicitConversion(Ex.get(), ObjectPtrConversions.front()->getConversionType(), - AA_Converting)) { - Type = Ex->getType(); + AA_Converting); + if (Res.isUsable()) { + Ex = move(Res); + Type = Ex.get()->getType(); } } else if (ObjectPtrConversions.size() > 1) { Diag(StartLoc, diag::err_ambiguous_delete_operand) - << Type << Ex->getSourceRange(); + << Type << Ex.get()->getSourceRange(); for (unsigned i= 0; i < ObjectPtrConversions.size(); i++) NoteOverloadCandidate(ObjectPtrConversions[i]); return ExprError(); @@ -1669,7 +1712,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (!Type->isPointerType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) - << Type << Ex->getSourceRange()); + << Type << Ex.get()->getSourceRange()); QualType Pointee = Type->getAs<PointerType>()->getPointeeType(); if (Pointee->isVoidType() && !isSFINAEContext()) { @@ -1677,27 +1720,30 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // effectively bans deletion of "void*". However, most compilers support // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) - << Type << Ex->getSourceRange(); + << Type << Ex.get()->getSourceRange(); } else if (Pointee->isFunctionType() || Pointee->isVoidType()) return ExprError(Diag(StartLoc, diag::err_delete_operand) - << Type << Ex->getSourceRange()); + << Type << Ex.get()->getSourceRange()); else if (!Pointee->isDependentType() && RequireCompleteType(StartLoc, Pointee, PDiag(diag::warn_delete_incomplete) - << Ex->getSourceRange())) + << Ex.get()->getSourceRange())) return ExprError(); - + else if (unsigned AddressSpace = Pointee.getAddressSpace()) + return Diag(Ex.get()->getLocStart(), + diag::err_address_space_qualified_delete) + << Pointee.getUnqualifiedType() << AddressSpace; // C++ [expr.delete]p2: // [Note: a pointer to a const type can be the operand of a // delete-expression; it is not necessary to cast away the constness // (5.2.11) of the pointer expression before it is used as the operand // of the delete-expression. ] - ImpCastExprToType(Ex, Context.getPointerType(Context.VoidTy), + Ex = ImpCastExprToType(Ex.take(), Context.getPointerType(Context.VoidTy), CK_NoOp); if (Pointee->isArrayType() && !ArrayForm) { Diag(StartLoc, diag::warn_delete_array_type) - << Type << Ex->getSourceRange() + << Type << Ex.get()->getSourceRange() << FixItHint::CreateInsertion(PP.getLocForEndOfToken(StartLoc), "[]"); ArrayForm = true; } @@ -1740,8 +1786,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // Look for a global declaration. DeclareGlobalNewDelete(); DeclContext *TUDecl = Context.getTranslationUnitDecl(); + Expr *Arg = Ex.get(); if (FindAllocationOverload(StartLoc, SourceRange(), DeleteName, - &Ex, 1, TUDecl, /*AllowMissing=*/false, + &Arg, 1, TUDecl, /*AllowMissing=*/false, OperatorDelete)) return ExprError(); } @@ -1752,7 +1799,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (const RecordType *RT = PointeeElem->getAs<RecordType>()) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); if (CXXDestructorDecl *Dtor = LookupDestructor(RD)) { - CheckDestructorAccess(Ex->getExprLoc(), Dtor, + CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, PDiag(diag::err_access_dtor) << PointeeElem); } } @@ -1762,7 +1809,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, return Owned(new (Context) CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, ArrayFormAsWritten, UsualArrayDeleteWantsSize, - OperatorDelete, Ex, StartLoc)); + OperatorDelete, Ex.take(), StartLoc)); } /// \brief Check the use of the given variable as a C++ condition in an if, @@ -1783,18 +1830,23 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, diag::err_invalid_use_of_array_type) << ConditionVar->getSourceRange()); - Expr *Condition = DeclRefExpr::Create(Context, 0, SourceRange(), ConditionVar, + ExprResult Condition = + Owned(DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), + ConditionVar, ConditionVar->getLocation(), ConditionVar->getType().getNonReferenceType(), - VK_LValue); - if (ConvertToBoolean && CheckBooleanCondition(Condition, StmtLoc)) - return ExprError(); + VK_LValue)); + if (ConvertToBoolean) { + Condition = CheckBooleanCondition(Condition.take(), StmtLoc); + if (Condition.isInvalid()) + return ExprError(); + } - return Owned(Condition); + return move(Condition); } /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid. -bool Sema::CheckCXXBooleanCondition(Expr *&CondExpr) { +ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr) { // C++ 6.4p4: // The value of a condition that is an initialized declaration in a statement // other than a switch statement is the value of the declared variable @@ -1880,20 +1932,22 @@ static ExprResult BuildCXXCastArgument(Sema &S, /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit -/// conversion sequence ICS. Returns true if there was an error, false -/// otherwise. The expression From is replaced with the converted +/// conversion sequence ICS. Returns the converted /// expression. Action is the kind of conversion we're performing, /// used in the error message. -bool -Sema::PerformImplicitConversion(Expr *&From, QualType ToType, +ExprResult +Sema::PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence &ICS, AssignmentAction Action, bool CStyle) { switch (ICS.getKind()) { - case ImplicitConversionSequence::StandardConversion: - if (PerformImplicitConversion(From, ToType, ICS.Standard, Action, - CStyle)) - return true; + case ImplicitConversionSequence::StandardConversion: { + ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard, + Action, CStyle); + if (Res.isInvalid()) + return ExprError(); + From = Res.take(); break; + } case ImplicitConversionSequence::UserDefinedConversion: { @@ -1920,10 +1974,13 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, } // Watch out for elipsis conversion. if (!ICS.UserDefined.EllipsisConversion) { - if (PerformImplicitConversion(From, BeforeToType, - ICS.UserDefined.Before, AA_Converting, - CStyle)) - return true; + ExprResult Res = + PerformImplicitConversion(From, BeforeToType, + ICS.UserDefined.Before, AA_Converting, + CStyle); + if (Res.isInvalid()) + return ExprError(); + From = Res.take(); } ExprResult CastArg @@ -1935,9 +1992,9 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, From); if (CastArg.isInvalid()) - return true; + return ExprError(); - From = CastArg.takeAs<Expr>(); + From = CastArg.take(); return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, AA_Converting, CStyle); @@ -1947,28 +2004,27 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(), PDiag(diag::err_typecheck_ambiguous_condition) << From->getSourceRange()); - return true; + return ExprError(); case ImplicitConversionSequence::EllipsisConversion: assert(false && "Cannot perform an ellipsis conversion"); - return false; + return Owned(From); case ImplicitConversionSequence::BadConversion: - return true; + return ExprError(); } // Everything went well. - return false; + return Owned(From); } /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType by following the standard -/// conversion sequence SCS. Returns true if there was an error, false -/// otherwise. The expression From is replaced with the converted +/// conversion sequence SCS. Returns the converted /// expression. Flavor is the context in which we're performing this /// conversion, for use in error messages. -bool -Sema::PerformImplicitConversion(Expr *&From, QualType ToType, +ExprResult +Sema::PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, AssignmentAction Action, bool CStyle) { // Overall FIXME: we are recomputing too many types here and doing far too @@ -1986,32 +2042,20 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, MultiExprArg(*this, &From, 1), /*FIXME:ConstructLoc*/SourceLocation(), ConstructorArgs)) - return true; - ExprResult FromResult = - BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), - ToType, SCS.CopyConstructor, - move_arg(ConstructorArgs), - /*ZeroInit*/ false, - CXXConstructExpr::CK_Complete, - SourceRange()); - if (FromResult.isInvalid()) - return true; - From = FromResult.takeAs<Expr>(); - return false; + return ExprError(); + return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), + ToType, SCS.CopyConstructor, + move_arg(ConstructorArgs), + /*ZeroInit*/ false, + CXXConstructExpr::CK_Complete, + SourceRange()); } - ExprResult FromResult = - BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), - ToType, SCS.CopyConstructor, - MultiExprArg(*this, &From, 1), - /*ZeroInit*/ false, - CXXConstructExpr::CK_Complete, - SourceRange()); - - if (FromResult.isInvalid()) - return true; - - From = FromResult.takeAs<Expr>(); - return false; + return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), + ToType, SCS.CopyConstructor, + MultiExprArg(*this, &From, 1), + /*ZeroInit*/ false, + CXXConstructExpr::CK_Complete, + SourceRange()); } // Resolve overloaded function references. @@ -2020,10 +2064,10 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true, Found); if (!Fn) - return true; + return ExprError(); if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) - return true; + return ExprError(); From = FixOverloadedFunctionReference(From, Found, Fn); FromType = From->getType(); @@ -2038,13 +2082,15 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Lvalue_To_Rvalue: // Should this get its own ICK? if (From->getObjectKind() == OK_ObjCProperty) { - ConvertPropertyForRValue(From); + ExprResult FromRes = ConvertPropertyForRValue(From); + if (FromRes.isInvalid()) + return ExprError(); + From = FromRes.take(); if (!From->isGLValue()) break; } // Check for trivial buffer overflows. - if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(From)) - CheckArrayAccess(AE); + CheckArrayAccess(From); FromType = FromType.getUnqualifiedType(); From = ImplicitCastExpr::Create(Context, FromType, CK_LValueToRValue, @@ -2053,12 +2099,12 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); - ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay); + From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay).take(); break; case ICK_Function_To_Pointer: FromType = Context.getPointerType(FromType); - ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay); + From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay).take(); break; default: @@ -2072,7 +2118,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // If both sides are functions (or pointers/references to them), there could // be incompatible exception declarations. if (CheckExceptionSpecCompatibility(From, ToType)) - return true; + return ExprError(); // Nothing else to do. break; @@ -2080,19 +2126,19 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // If both sides are functions (or pointers/references to them), there could // be incompatible exception declarations. if (CheckExceptionSpecCompatibility(From, ToType)) - return true; + return ExprError(); - ImpCastExprToType(From, ToType, CK_NoOp); + From = ImpCastExprToType(From, ToType, CK_NoOp).take(); break; case ICK_Integral_Promotion: case ICK_Integral_Conversion: - ImpCastExprToType(From, ToType, CK_IntegralCast); + From = ImpCastExprToType(From, ToType, CK_IntegralCast).take(); break; case ICK_Floating_Promotion: case ICK_Floating_Conversion: - ImpCastExprToType(From, ToType, CK_FloatingCast); + From = ImpCastExprToType(From, ToType, CK_FloatingCast).take(); break; case ICK_Complex_Promotion: @@ -2110,35 +2156,41 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, } else { CK = CK_IntegralComplexCast; } - ImpCastExprToType(From, ToType, CK); + From = ImpCastExprToType(From, ToType, CK).take(); break; } case ICK_Floating_Integral: if (ToType->isRealFloatingType()) - ImpCastExprToType(From, ToType, CK_IntegralToFloating); + From = ImpCastExprToType(From, ToType, CK_IntegralToFloating).take(); else - ImpCastExprToType(From, ToType, CK_FloatingToIntegral); + From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral).take(); break; case ICK_Compatible_Conversion: - ImpCastExprToType(From, ToType, CK_NoOp); + From = ImpCastExprToType(From, ToType, CK_NoOp).take(); break; case ICK_Pointer_Conversion: { if (SCS.IncompatibleObjC && Action != AA_Casting) { // Diagnose incompatible Objective-C conversions - Diag(From->getSourceRange().getBegin(), - diag::ext_typecheck_convert_incompatible_pointer) - << From->getType() << ToType << Action - << From->getSourceRange(); + if (Action == AA_Initializing) + Diag(From->getSourceRange().getBegin(), + diag::ext_typecheck_convert_incompatible_pointer) + << ToType << From->getType() << Action + << From->getSourceRange(); + else + Diag(From->getSourceRange().getBegin(), + diag::ext_typecheck_convert_incompatible_pointer) + << From->getType() << ToType << Action + << From->getSourceRange(); } CastKind Kind = CK_Invalid; CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) - return true; - ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath); + return ExprError(); + From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take(); break; } @@ -2146,27 +2198,17 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, CastKind Kind = CK_Invalid; CXXCastPath BasePath; if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle)) - return true; + return ExprError(); if (CheckExceptionSpecCompatibility(From, ToType)) - return true; - ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath); + return ExprError(); + From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath).take(); break; } - case ICK_Boolean_Conversion: { - CastKind Kind = CK_Invalid; - switch (FromType->getScalarTypeKind()) { - case Type::STK_Pointer: Kind = CK_PointerToBoolean; break; - case Type::STK_MemberPointer: Kind = CK_MemberPointerToBoolean; break; - case Type::STK_Bool: llvm_unreachable("bool -> bool conversion?"); - case Type::STK_Integral: Kind = CK_IntegralToBoolean; break; - case Type::STK_Floating: Kind = CK_FloatingToBoolean; break; - case Type::STK_IntegralComplex: Kind = CK_IntegralComplexToBoolean; break; - case Type::STK_FloatingComplex: Kind = CK_FloatingComplexToBoolean; break; - } - ImpCastExprToType(From, Context.BoolTy, Kind); + case ICK_Boolean_Conversion: + From = ImpCastExprToType(From, Context.BoolTy, + ScalarTypeToBooleanCastKind(FromType)).take(); break; - } case ICK_Derived_To_Base: { CXXCastPath BasePath; @@ -2176,20 +2218,20 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, From->getSourceRange(), &BasePath, CStyle)) - return true; + return ExprError(); - ImpCastExprToType(From, ToType.getNonReferenceType(), + From = ImpCastExprToType(From, ToType.getNonReferenceType(), CK_DerivedToBase, CastCategory(From), - &BasePath); + &BasePath).take(); break; } case ICK_Vector_Conversion: - ImpCastExprToType(From, ToType, CK_BitCast); + From = ImpCastExprToType(From, ToType, CK_BitCast).take(); break; case ICK_Vector_Splat: - ImpCastExprToType(From, ToType, CK_VectorSplat); + From = ImpCastExprToType(From, ToType, CK_VectorSplat).take(); break; case ICK_Complex_Real: @@ -2202,17 +2244,17 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, if (Context.hasSameUnqualifiedType(ElType, From->getType())) { // do nothing } else if (From->getType()->isRealFloatingType()) { - ImpCastExprToType(From, ElType, - isFloatingComplex ? CK_FloatingCast : CK_FloatingToIntegral); + From = ImpCastExprToType(From, ElType, + isFloatingComplex ? CK_FloatingCast : CK_FloatingToIntegral).take(); } else { assert(From->getType()->isIntegerType()); - ImpCastExprToType(From, ElType, - isFloatingComplex ? CK_IntegralToFloating : CK_IntegralCast); + From = ImpCastExprToType(From, ElType, + isFloatingComplex ? CK_IntegralToFloating : CK_IntegralCast).take(); } // y -> _Complex y - ImpCastExprToType(From, ToType, + From = ImpCastExprToType(From, ToType, isFloatingComplex ? CK_FloatingRealToComplex - : CK_IntegralRealToComplex); + : CK_IntegralRealToComplex).take(); // Case 2. _Complex x -> y } else { @@ -2223,29 +2265,43 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, bool isFloatingComplex = ElType->isRealFloatingType(); // _Complex x -> x - ImpCastExprToType(From, ElType, + From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_FloatingComplexToReal - : CK_IntegralComplexToReal); + : CK_IntegralComplexToReal).take(); // x -> y if (Context.hasSameUnqualifiedType(ElType, ToType)) { // do nothing } else if (ToType->isRealFloatingType()) { - ImpCastExprToType(From, ToType, - isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating); + From = ImpCastExprToType(From, ToType, + isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating).take(); } else { assert(ToType->isIntegerType()); - ImpCastExprToType(From, ToType, - isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast); + From = ImpCastExprToType(From, ToType, + isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast).take(); } } break; case ICK_Block_Pointer_Conversion: { - ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, VK_RValue); + From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, + VK_RValue).take(); break; } + case ICK_TransparentUnionConversion: { + ExprResult FromRes = Owned(From); + Sema::AssignConvertType ConvTy = + CheckTransparentUnionArgumentConstraints(ToType, FromRes); + if (FromRes.isInvalid()) + return ExprError(); + From = FromRes.take(); + assert ((ConvTy == Sema::Compatible) && + "Improper transparent union conversion"); + (void)ConvTy; + break; + } + case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: @@ -2265,10 +2321,11 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, // target type isn't a reference. ExprValueKind VK = ToType->isReferenceType() ? CastCategory(From) : VK_RValue; - ImpCastExprToType(From, ToType.getNonLValueExprType(Context), - CK_NoOp, VK); + From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context), + CK_NoOp, VK).take(); - if (SCS.DeprecatedStringLiteralToCharPtr) + if (SCS.DeprecatedStringLiteralToCharPtr && + !getLangOptions().WritableStrings) Diag(From->getLocStart(), diag::warn_deprecated_string_literal_conversion) << ToType.getNonReferenceType(); @@ -2280,7 +2337,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, break; } - return false; + return Owned(From); } ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait UTT, @@ -2295,41 +2352,197 @@ ExprResult Sema::ActOnUnaryTypeTrait(UnaryTypeTrait UTT, return BuildUnaryTypeTrait(UTT, KWLoc, TSInfo, RParen); } -static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T, - SourceLocation KeyLoc) { - // FIXME: For many of these traits, we need a complete type before we can - // check these properties. - assert(!T->isDependentType() && - "Cannot evaluate traits for dependent types."); +/// \brief Check the completeness of a type in a unary type trait. +/// +/// If the particular type trait requires a complete type, tries to complete +/// it. If completing the type fails, a diagnostic is emitted and false +/// returned. If completing the type succeeds or no completion was required, +/// returns true. +static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, + UnaryTypeTrait UTT, + SourceLocation Loc, + QualType ArgTy) { + // C++0x [meta.unary.prop]p3: + // For all of the class templates X declared in this Clause, instantiating + // that template with a template argument that is a class template + // specialization may result in the implicit instantiation of the template + // argument if and only if the semantics of X require that the argument + // must be a complete type. + // We apply this rule to all the type trait expressions used to implement + // these class templates. We also try to follow any GCC documented behavior + // in these expressions to ensure portability of standard libraries. + switch (UTT) { + // is_complete_type somewhat obviously cannot require a complete type. + case UTT_IsCompleteType: + // Fall-through + + // These traits are modeled on the type predicates in C++0x + // [meta.unary.cat] and [meta.unary.comp]. They are not specified as + // requiring a complete type, as whether or not they return true cannot be + // impacted by the completeness of the type. + case UTT_IsVoid: + case UTT_IsIntegral: + case UTT_IsFloatingPoint: + case UTT_IsArray: + case UTT_IsPointer: + case UTT_IsLvalueReference: + case UTT_IsRvalueReference: + case UTT_IsMemberFunctionPointer: + case UTT_IsMemberObjectPointer: + case UTT_IsEnum: + case UTT_IsUnion: + case UTT_IsClass: + case UTT_IsFunction: + case UTT_IsReference: + case UTT_IsArithmetic: + case UTT_IsFundamental: + case UTT_IsObject: + case UTT_IsScalar: + case UTT_IsCompound: + case UTT_IsMemberPointer: + // Fall-through + + // These traits are modeled on type predicates in C++0x [meta.unary.prop] + // which requires some of its traits to have the complete type. However, + // the completeness of the type cannot impact these traits' semantics, and + // so they don't require it. This matches the comments on these traits in + // Table 49. + case UTT_IsConst: + case UTT_IsVolatile: + case UTT_IsSigned: + case UTT_IsUnsigned: + return true; + + // C++0x [meta.unary.prop] Table 49 requires the following traits to be + // applied to a complete type. + case UTT_IsTrivial: + case UTT_IsStandardLayout: + case UTT_IsPOD: + case UTT_IsLiteral: + case UTT_IsEmpty: + case UTT_IsPolymorphic: + case UTT_IsAbstract: + // Fall-through + + // These trait expressions are designed to help implement predicates in + // [meta.unary.prop] despite not being named the same. They are specified + // by both GCC and the Embarcadero C++ compiler, and require the complete + // type due to the overarching C++0x type predicates being implemented + // requiring the complete type. + case UTT_HasNothrowAssign: + case UTT_HasNothrowConstructor: + case UTT_HasNothrowCopy: + case UTT_HasTrivialAssign: + case UTT_HasTrivialConstructor: + case UTT_HasTrivialCopy: + case UTT_HasTrivialDestructor: + case UTT_HasVirtualDestructor: + // Arrays of unknown bound are expressly allowed. + QualType ElTy = ArgTy; + if (ArgTy->isIncompleteArrayType()) + ElTy = S.Context.getAsArrayType(ArgTy)->getElementType(); + + // The void type is expressly allowed. + if (ElTy->isVoidType()) + return true; + + return !S.RequireCompleteType( + Loc, ElTy, diag::err_incomplete_type_used_in_type_trait_expr); + } + llvm_unreachable("Type trait not handled by switch"); +} + +static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, + SourceLocation KeyLoc, QualType T) { + assert(!T->isDependentType() && "Cannot evaluate traits of dependent type"); + ASTContext &C = Self.Context; switch(UTT) { - default: assert(false && "Unknown type trait or not implemented"); - case UTT_IsPOD: return T->isPODType(); - case UTT_IsLiteral: return T->isLiteralType(); - case UTT_IsClass: // Fallthrough + // Type trait expressions corresponding to the primary type category + // predicates in C++0x [meta.unary.cat]. + case UTT_IsVoid: + return T->isVoidType(); + case UTT_IsIntegral: + return T->isIntegralType(C); + case UTT_IsFloatingPoint: + return T->isFloatingType(); + case UTT_IsArray: + return T->isArrayType(); + case UTT_IsPointer: + return T->isPointerType(); + case UTT_IsLvalueReference: + return T->isLValueReferenceType(); + case UTT_IsRvalueReference: + return T->isRValueReferenceType(); + case UTT_IsMemberFunctionPointer: + return T->isMemberFunctionPointerType(); + case UTT_IsMemberObjectPointer: + return T->isMemberDataPointerType(); + case UTT_IsEnum: + return T->isEnumeralType(); case UTT_IsUnion: - if (const RecordType *Record = T->getAs<RecordType>()) { - bool Union = Record->getDecl()->isUnion(); - return UTT == UTT_IsUnion ? Union : !Union; - } + return T->isUnionType(); + case UTT_IsClass: + return T->isClassType() || T->isStructureType(); + case UTT_IsFunction: + return T->isFunctionType(); + + // Type trait expressions which correspond to the convenient composition + // predicates in C++0x [meta.unary.comp]. + case UTT_IsReference: + return T->isReferenceType(); + case UTT_IsArithmetic: + return T->isArithmeticType() && !T->isEnumeralType(); + case UTT_IsFundamental: + return T->isFundamentalType(); + case UTT_IsObject: + return T->isObjectType(); + case UTT_IsScalar: + return T->isScalarType(); + case UTT_IsCompound: + return T->isCompoundType(); + case UTT_IsMemberPointer: + return T->isMemberPointerType(); + + // Type trait expressions which correspond to the type property predicates + // in C++0x [meta.unary.prop]. + case UTT_IsConst: + return T.isConstQualified(); + case UTT_IsVolatile: + return T.isVolatileQualified(); + case UTT_IsTrivial: + return T->isTrivialType(); + case UTT_IsStandardLayout: + return T->isStandardLayoutType(); + case UTT_IsPOD: + return T->isPODType(); + case UTT_IsLiteral: + return T->isLiteralType(); + case UTT_IsEmpty: + if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + return !RD->isUnion() && RD->isEmpty(); return false; - case UTT_IsEnum: return T->isEnumeralType(); case UTT_IsPolymorphic: - if (const RecordType *Record = T->getAs<RecordType>()) { - // Type traits are only parsed in C++, so we've got CXXRecords. - return cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic(); - } + if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + return RD->isPolymorphic(); return false; case UTT_IsAbstract: - if (const RecordType *RT = T->getAs<RecordType>()) - return cast<CXXRecordDecl>(RT->getDecl())->isAbstract(); - return false; - case UTT_IsEmpty: - if (const RecordType *Record = T->getAs<RecordType>()) { - return !Record->getDecl()->isUnion() - && cast<CXXRecordDecl>(Record->getDecl())->isEmpty(); - } + if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + return RD->isAbstract(); return false; + case UTT_IsSigned: + return T->isSignedIntegerType(); + case UTT_IsUnsigned: + return T->isUnsignedIntegerType(); + + // Type trait expressions which query classes regarding their construction, + // destruction, and copying. Rather than being based directly on the + // related type predicates in the standard, they are specified by both + // GCC[1] and the Embarcadero C++ compiler[2], and Clang implements those + // specifications. + // + // 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html + // 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index case UTT_HasTrivialConstructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true then the trait is true, else if type is @@ -2418,7 +2631,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T, FoundAssign = true; const FunctionProtoType *CPT = Operator->getType()->getAs<FunctionProtoType>(); - if (!CPT->hasEmptyExceptionSpec()) { + if (!CPT->isNothrow(Self.Context)) { AllNoThrow = false; break; } @@ -2458,9 +2671,9 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T, FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs<FunctionProtoType>(); - // TODO: check whether evaluating default arguments can throw. + // FIXME: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. - if (!CPT->hasEmptyExceptionSpec() || CPT->getNumArgs() > 1) { + if (!CPT->isNothrow(Self.Context) || CPT->getNumArgs() > 1) { AllNoThrow = false; break; } @@ -2495,7 +2708,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T, = Constructor->getType()->getAs<FunctionProtoType>(); // TODO: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. - return CPT->hasEmptyExceptionSpec() && CPT->getNumArgs() == 0; + return CPT->isNothrow(Self.Context) && CPT->getNumArgs() == 0; } } } @@ -2510,7 +2723,17 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, QualType T, return Destructor->isVirtual(); } return false; + + // These type trait expressions are modeled on the specifications for the + // Embarcadero C++0x type trait functions: + // http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index + case UTT_IsCompleteType: + // http://docwiki.embarcadero.com/RADStudio/XE/en/Is_complete_type_(typename_T_): + // Returns True if and only if T is a complete type at the point of the + // function call. + return !T->isIncompleteType(); } + llvm_unreachable("Type trait not covered by switch"); } ExprResult Sema::BuildUnaryTypeTrait(UnaryTypeTrait UTT, @@ -2518,23 +2741,12 @@ ExprResult Sema::BuildUnaryTypeTrait(UnaryTypeTrait UTT, TypeSourceInfo *TSInfo, SourceLocation RParen) { QualType T = TSInfo->getType(); - - // According to http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html - // all traits except __is_class, __is_enum and __is_union require a the type - // to be complete, an array of unknown bound, or void. - if (UTT != UTT_IsClass && UTT != UTT_IsEnum && UTT != UTT_IsUnion) { - QualType E = T; - if (T->isIncompleteArrayType()) - E = Context.getAsArrayType(T)->getElementType(); - if (!T->isVoidType() && - RequireCompleteType(KWLoc, E, - diag::err_incomplete_type_used_in_type_trait_expr)) - return ExprError(); - } + if (!CheckUnaryTypeTraitTypeCompleteness(*this, UTT, KWLoc, T)) + return ExprError(); bool Value = false; if (!T->isDependentType()) - Value = EvaluateUnaryTypeTrait(*this, UTT, T, KWLoc); + Value = EvaluateUnaryTypeTrait(*this, UTT, KWLoc, T); return Owned(new (Context) UnaryTypeTraitExpr(KWLoc, UTT, TSInfo, Value, RParen, Context.BoolTy)); @@ -2561,8 +2773,8 @@ ExprResult Sema::ActOnBinaryTypeTrait(BinaryTypeTrait BTT, static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, QualType LhsT, QualType RhsT, SourceLocation KeyLoc) { - assert((!LhsT->isDependentType() || RhsT->isDependentType()) && - "Cannot evaluate traits for dependent types."); + assert(!LhsT->isDependentType() && !RhsT->isDependentType() && + "Cannot evaluate traits of dependent types"); switch(BTT) { case BTT_IsBaseOf: { @@ -2594,11 +2806,12 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, return cast<CXXRecordDecl>(rhsRecord->getDecl()) ->isDerivedFrom(cast<CXXRecordDecl>(lhsRecord->getDecl())); } - + case BTT_IsSame: + return Self.Context.hasSameType(LhsT, RhsT); case BTT_TypeCompatible: return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(), RhsT.getUnqualifiedType()); - + case BTT_IsConvertible: case BTT_IsConvertibleTo: { // C++0x [meta.rel]p4: // Given the following function prototype: @@ -2673,6 +2886,8 @@ ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT, QualType ResultType; switch (BTT) { case BTT_IsBaseOf: ResultType = Context.BoolTy; break; + case BTT_IsConvertible: ResultType = Context.BoolTy; break; + case BTT_IsSame: ResultType = Context.BoolTy; break; case BTT_TypeCompatible: ResultType = Context.IntTy; break; case BTT_IsConvertibleTo: ResultType = Context.BoolTy; break; } @@ -2682,7 +2897,138 @@ ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT, ResultType)); } -QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex, +ExprResult Sema::ActOnArrayTypeTrait(ArrayTypeTrait ATT, + SourceLocation KWLoc, + ParsedType Ty, + Expr* DimExpr, + SourceLocation RParen) { + TypeSourceInfo *TSInfo; + QualType T = GetTypeFromParser(Ty, &TSInfo); + if (!TSInfo) + TSInfo = Context.getTrivialTypeSourceInfo(T); + + return BuildArrayTypeTrait(ATT, KWLoc, TSInfo, DimExpr, RParen); +} + +static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT, + QualType T, Expr *DimExpr, + SourceLocation KeyLoc) { + assert(!T->isDependentType() && "Cannot evaluate traits of dependent type"); + + switch(ATT) { + case ATT_ArrayRank: + if (T->isArrayType()) { + unsigned Dim = 0; + while (const ArrayType *AT = Self.Context.getAsArrayType(T)) { + ++Dim; + T = AT->getElementType(); + } + return Dim; + } + return 0; + + case ATT_ArrayExtent: { + llvm::APSInt Value; + uint64_t Dim; + if (DimExpr->isIntegerConstantExpr(Value, Self.Context, 0, false)) { + if (Value < llvm::APSInt(Value.getBitWidth(), Value.isUnsigned())) { + Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer) << + DimExpr->getSourceRange(); + return false; + } + Dim = Value.getLimitedValue(); + } else { + Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer) << + DimExpr->getSourceRange(); + return false; + } + + if (T->isArrayType()) { + unsigned D = 0; + bool Matched = false; + while (const ArrayType *AT = Self.Context.getAsArrayType(T)) { + if (Dim == D) { + Matched = true; + break; + } + ++D; + T = AT->getElementType(); + } + + if (Matched && T->isArrayType()) { + if (const ConstantArrayType *CAT = Self.Context.getAsConstantArrayType(T)) + return CAT->getSize().getLimitedValue(); + } + } + return 0; + } + } + llvm_unreachable("Unknown type trait or not implemented"); +} + +ExprResult Sema::BuildArrayTypeTrait(ArrayTypeTrait ATT, + SourceLocation KWLoc, + TypeSourceInfo *TSInfo, + Expr* DimExpr, + SourceLocation RParen) { + QualType T = TSInfo->getType(); + + // FIXME: This should likely be tracked as an APInt to remove any host + // assumptions about the width of size_t on the target. + uint64_t Value = 0; + if (!T->isDependentType()) + Value = EvaluateArrayTypeTrait(*this, ATT, T, DimExpr, KWLoc); + + // While the specification for these traits from the Embarcadero C++ + // compiler's documentation says the return type is 'unsigned int', Clang + // returns 'size_t'. On Windows, the primary platform for the Embarcadero + // compiler, there is no difference. On several other platforms this is an + // important distinction. + return Owned(new (Context) ArrayTypeTraitExpr(KWLoc, ATT, TSInfo, Value, + DimExpr, RParen, + Context.getSizeType())); +} + +ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET, + SourceLocation KWLoc, + Expr *Queried, + SourceLocation RParen) { + // If error parsing the expression, ignore. + if (!Queried) + return ExprError(); + + ExprResult Result = BuildExpressionTrait(ET, KWLoc, Queried, RParen); + + return move(Result); +} + +static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) { + switch (ET) { + case ET_IsLValueExpr: return E->isLValue(); + case ET_IsRValueExpr: return E->isRValue(); + } + llvm_unreachable("Expression trait not covered by switch"); +} + +ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET, + SourceLocation KWLoc, + Expr *Queried, + SourceLocation RParen) { + if (Queried->isTypeDependent()) { + // Delay type-checking for type-dependent expressions. + } else if (Queried->getType()->isPlaceholderType()) { + ExprResult PE = CheckPlaceholderExpr(Queried); + if (PE.isInvalid()) return ExprError(); + return BuildExpressionTrait(ET, KWLoc, PE.take(), RParen); + } + + bool Value = EvaluateExpressionTrait(ET, Queried); + + return Owned(new (Context) ExpressionTraitExpr(KWLoc, ET, Queried, Value, + RParen, Context.BoolTy)); +} + +QualType Sema::CheckPointerToMemberOperands(ExprResult &lex, ExprResult &rex, ExprValueKind &VK, SourceLocation Loc, bool isIndirect) { @@ -2691,11 +3037,11 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex, // The binary operator .* [p3: ->*] binds its second operand, which shall // be of type "pointer to member of T" (where T is a completely-defined // class type) [...] - QualType RType = rex->getType(); + QualType RType = rex.get()->getType(); const MemberPointerType *MemPtr = RType->getAs<MemberPointerType>(); if (!MemPtr) { Diag(Loc, diag::err_bad_memptr_rhs) - << OpSpelling << RType << rex->getSourceRange(); + << OpSpelling << RType << rex.get()->getSourceRange(); return QualType(); } @@ -2711,7 +3057,7 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex, // [...] to its first operand, which shall be of class T or of a class of // which T is an unambiguous and accessible base class. [p3: a pointer to // such a class] - QualType LType = lex->getType(); + QualType LType = lex.get()->getType(); if (isIndirect) { if (const PointerType *Ptr = LType->getAs<PointerType>()) LType = Ptr->getPointeeType(); @@ -2736,20 +3082,20 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex, if (!IsDerivedFrom(LType, Class, Paths) || Paths.isAmbiguous(Context.getCanonicalType(Class))) { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling - << (int)isIndirect << lex->getType(); + << (int)isIndirect << lex.get()->getType(); return QualType(); } // Cast LHS to type of use. QualType UseType = isIndirect ? Context.getPointerType(Class) : Class; ExprValueKind VK = - isIndirect ? VK_RValue : CastCategory(lex); + isIndirect ? VK_RValue : CastCategory(lex.get()); CXXCastPath BasePath; BuildBasePathArray(Paths, BasePath); - ImpCastExprToType(lex, UseType, CK_DerivedToBase, VK, &BasePath); + lex = ImpCastExprToType(lex.take(), UseType, CK_DerivedToBase, VK, &BasePath); } - if (isa<CXXScalarValueInitExpr>(rex->IgnoreParens())) { + if (isa<CXXScalarValueInitExpr>(rex.get()->IgnoreParens())) { // Diagnose use of pointer-to-member type which when used as // the functional cast in a pointer-to-member expression. Diag(Loc, diag::err_pointer_to_member_type) << isIndirect; @@ -2761,13 +3107,6 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex, // second operand. // The cv qualifiers are the union of those in the pointer and the left side, // in accordance with 5.5p5 and 5.2.5. - // FIXME: This returns a dereferenced member function pointer as a normal - // function type. However, the only operation valid on such functions is - // calling them. There's also a GCC extension to get a function pointer to the - // thing, which is another complication, because this type - unlike the type - // that is the result of this expression - takes the class as the first - // argument. - // We probably need a "MemberFunctionClosureType" or something like that. QualType Result = MemPtr->getPointeeType(); Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers()); @@ -2784,15 +3123,15 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex, break; case RQ_LValue: - if (!isIndirect && !lex->Classify(Context).isLValue()) + if (!isIndirect && !lex.get()->Classify(Context).isLValue()) Diag(Loc, diag::err_pointer_to_member_oper_value_classify) - << RType << 1 << lex->getSourceRange(); + << RType << 1 << lex.get()->getSourceRange(); break; case RQ_RValue: - if (isIndirect || !lex->Classify(Context).isRValue()) + if (isIndirect || !lex.get()->Classify(Context).isRValue()) Diag(Loc, diag::err_pointer_to_member_oper_value_classify) - << RType << 0 << lex->getSourceRange(); + << RType << 0 << lex.get()->getSourceRange(); break; } } @@ -2804,12 +3143,14 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex, // operand is a pointer to a member function is a prvalue. The // result of an ->* expression is an lvalue if its second operand // is a pointer to data member and a prvalue otherwise. - if (Result->isFunctionType()) + if (Result->isFunctionType()) { VK = VK_RValue; - else if (isIndirect) + return Context.BoundMemberTy; + } else if (isIndirect) { VK = VK_LValue; - else - VK = lex->getValueKind(); + } else { + VK = lex.get()->getValueKind(); + } return Result; } @@ -2910,43 +3251,52 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, overload resolution is used to find a /// conversion to a common type. -static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, +static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc) { - Expr *Args[2] = { LHS, RHS }; + Expr *Args[2] = { LHS.get(), RHS.get() }; OverloadCandidateSet CandidateSet(QuestionLoc); Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args, 2, CandidateSet); OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(Self, QuestionLoc, Best)) { - case OR_Success: + case OR_Success: { // We found a match. Perform the conversions on the arguments and move on. - if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0], - Best->Conversions[0], Sema::AA_Converting) || - Self.PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1], - Best->Conversions[1], Sema::AA_Converting)) + ExprResult LHSRes = + Self.PerformImplicitConversion(LHS.get(), Best->BuiltinTypes.ParamTypes[0], + Best->Conversions[0], Sema::AA_Converting); + if (LHSRes.isInvalid()) + break; + LHS = move(LHSRes); + + ExprResult RHSRes = + Self.PerformImplicitConversion(RHS.get(), Best->BuiltinTypes.ParamTypes[1], + Best->Conversions[1], Sema::AA_Converting); + if (RHSRes.isInvalid()) break; + RHS = move(RHSRes); if (Best->Function) Self.MarkDeclarationReferenced(QuestionLoc, Best->Function); return false; - + } + case OR_No_Viable_Function: // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is a pointer type. In this case, the user most // likely forgot to take the address of the other expression. - if (Self.DiagnoseConditionalForNull(LHS, RHS, QuestionLoc)) + if (Self.DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc)) return true; Self.Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) - << LHS->getType() << RHS->getType() - << LHS->getSourceRange() << RHS->getSourceRange(); + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return true; case OR_Ambiguous: Self.Diag(QuestionLoc, diag::err_conditional_ambiguous_ovl) - << LHS->getType() << RHS->getType() - << LHS->getSourceRange() << RHS->getSourceRange(); + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); // FIXME: Print the possible common types by printing the return types of // the viable candidates. break; @@ -2960,16 +3310,17 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS, /// \brief Perform an "extended" implicit conversion as returned by /// TryClassUnification. -static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) { +static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); - InitializationKind Kind = InitializationKind::CreateCopy(E->getLocStart(), + InitializationKind Kind = InitializationKind::CreateCopy(E.get()->getLocStart(), SourceLocation()); - InitializationSequence InitSeq(Self, Entity, Kind, &E, 1); - ExprResult Result = InitSeq.Perform(Self, Entity, Kind, MultiExprArg(&E, 1)); + Expr *Arg = E.take(); + InitializationSequence InitSeq(Self, Entity, Kind, &Arg, 1); + ExprResult Result = InitSeq.Perform(Self, Entity, Kind, MultiExprArg(&Arg, 1)); if (Result.isInvalid()) return true; - E = Result.takeAs<Expr>(); + E = Result; return false; } @@ -2977,7 +3328,7 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, QualType T) { /// /// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y /// extension. In this case, LHS == Cond. (But they're not aliases.) -QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, +QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc) { // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++ @@ -2985,9 +3336,11 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // C++0x 5.16p1 // The first expression is contextually converted to bool. - if (!Cond->isTypeDependent()) { - if (CheckCXXBooleanCondition(Cond)) + if (!Cond.get()->isTypeDependent()) { + ExprResult CondRes = CheckCXXBooleanCondition(Cond.take()); + if (CondRes.isInvalid()) return QualType(); + Cond = move(CondRes); } // Assume r-value. @@ -2995,28 +3348,30 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, OK = OK_Ordinary; // Either of the arguments dependent? - if (LHS->isTypeDependent() || RHS->isTypeDependent()) + if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent()) return Context.DependentTy; // C++0x 5.16p2 // If either the second or the third operand has type (cv) void, ... - QualType LTy = LHS->getType(); - QualType RTy = RHS->getType(); + QualType LTy = LHS.get()->getType(); + QualType RTy = RHS.get()->getType(); bool LVoid = LTy->isVoidType(); bool RVoid = RTy->isVoidType(); if (LVoid || RVoid) { // ... then the [l2r] conversions are performed on the second and third // operands ... - DefaultFunctionArrayLvalueConversion(LHS); - DefaultFunctionArrayLvalueConversion(RHS); - LTy = LHS->getType(); - RTy = RHS->getType(); + LHS = DefaultFunctionArrayLvalueConversion(LHS.take()); + RHS = DefaultFunctionArrayLvalueConversion(RHS.take()); + if (LHS.isInvalid() || RHS.isInvalid()) + return QualType(); + LTy = LHS.get()->getType(); + RTy = RHS.get()->getType(); // ... and one of the following shall hold: // -- The second or the third operand (but not both) is a throw- // expression; the result is of the type of the other and is an rvalue. - bool LThrow = isa<CXXThrowExpr>(LHS); - bool RThrow = isa<CXXThrowExpr>(RHS); + bool LThrow = isa<CXXThrowExpr>(LHS.get()); + bool RThrow = isa<CXXThrowExpr>(RHS.get()); if (LThrow && !RThrow) return RTy; if (RThrow && !LThrow) @@ -3030,7 +3385,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // Neither holds, error. Diag(QuestionLoc, diag::err_conditional_void_nonvoid) << (LVoid ? RTy : LTy) << (LVoid ? 0 : 1) - << LHS->getSourceRange() << RHS->getSourceRange(); + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } @@ -3046,15 +3401,15 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // These return true if a single direction is already ambiguous. QualType L2RType, R2LType; bool HaveL2R, HaveR2L; - if (TryClassUnification(*this, LHS, RHS, QuestionLoc, HaveL2R, L2RType)) + if (TryClassUnification(*this, LHS.get(), RHS.get(), QuestionLoc, HaveL2R, L2RType)) return QualType(); - if (TryClassUnification(*this, RHS, LHS, QuestionLoc, HaveR2L, R2LType)) + if (TryClassUnification(*this, RHS.get(), LHS.get(), QuestionLoc, HaveR2L, R2LType)) return QualType(); // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) - << LTy << RTy << LHS->getSourceRange() << RHS->getSourceRange(); + << LTy << RTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } @@ -3062,13 +3417,13 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // the chosen operand and the converted operands are used in place of the // original operands for the remainder of this section. if (HaveL2R) { - if (ConvertForConditional(*this, LHS, L2RType)) + if (ConvertForConditional(*this, LHS, L2RType) || LHS.isInvalid()) return QualType(); - LTy = LHS->getType(); + LTy = LHS.get()->getType(); } else if (HaveR2L) { - if (ConvertForConditional(*this, RHS, R2LType)) + if (ConvertForConditional(*this, RHS, R2LType) || RHS.isInvalid()) return QualType(); - RTy = RHS->getType(); + RTy = RHS.get()->getType(); } } @@ -3081,13 +3436,13 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // l-values. bool Same = Context.hasSameType(LTy, RTy); if (Same && - LHS->isGLValue() && - LHS->getValueKind() == RHS->getValueKind() && - LHS->isOrdinaryOrBitFieldObject() && - RHS->isOrdinaryOrBitFieldObject()) { - VK = LHS->getValueKind(); - if (LHS->getObjectKind() == OK_BitField || - RHS->getObjectKind() == OK_BitField) + LHS.get()->isGLValue() && + LHS.get()->getValueKind() == RHS.get()->getValueKind() && + LHS.get()->isOrdinaryOrBitFieldObject() && + RHS.get()->isOrdinaryOrBitFieldObject()) { + VK = LHS.get()->getValueKind(); + if (LHS.get()->getObjectKind() == OK_BitField || + RHS.get()->getObjectKind() == OK_BitField) OK = OK_BitField; return LTy; } @@ -3106,10 +3461,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // C++0x 5.16p6 // LValue-to-rvalue, array-to-pointer, and function-to-pointer standard // conversions are performed on the second and third operands. - DefaultFunctionArrayLvalueConversion(LHS); - DefaultFunctionArrayLvalueConversion(RHS); - LTy = LHS->getType(); - RTy = RHS->getType(); + LHS = DefaultFunctionArrayLvalueConversion(LHS.take()); + RHS = DefaultFunctionArrayLvalueConversion(RHS.take()); + if (LHS.isInvalid() || RHS.isInvalid()) + return QualType(); + LTy = LHS.get()->getType(); + RTy = RHS.get()->getType(); // After those conversions, one of the following shall hold: // -- The second and third operands have the same type; the result @@ -3123,18 +3480,18 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); ExprResult LHSCopy = PerformCopyInitialization(Entity, SourceLocation(), - Owned(LHS)); + LHS); if (LHSCopy.isInvalid()) return QualType(); ExprResult RHSCopy = PerformCopyInitialization(Entity, SourceLocation(), - Owned(RHS)); + RHS); if (RHSCopy.isInvalid()) return QualType(); - LHS = LHSCopy.takeAs<Expr>(); - RHS = RHSCopy.takeAs<Expr>(); + LHS = LHSCopy; + RHS = RHSCopy; } return LTy; @@ -3149,7 +3506,9 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // common type, and the result is of that type. if (LTy->isArithmeticType() && RTy->isArithmeticType()) { UsualArithmeticConversions(LHS, RHS); - return LHS->getType(); + if (LHS.isInvalid() || RHS.isInvalid()) + return QualType(); + return LHS.get()->getType(); } // -- The second and third operands have pointer type, or one has pointer @@ -3170,7 +3529,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands_nonstandard) << LTy << RTy << Composite - << LHS->getSourceRange() << RHS->getSourceRange(); + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return Composite; } @@ -3181,12 +3540,12 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, return Composite; // Check if we are using a null with a non-pointer type. - if (DiagnoseConditionalForNull(LHS, RHS, QuestionLoc)) + if (DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc)) return QualType(); Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) - << LHS->getType() << RHS->getType() - << LHS->getSourceRange() << RHS->getSourceRange(); + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } @@ -3224,16 +3583,16 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // the type of the other operand. if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (T2->isMemberPointerType()) - ImpCastExprToType(E1, T2, CK_NullToMemberPointer); + E1 = ImpCastExprToType(E1, T2, CK_NullToMemberPointer).take(); else - ImpCastExprToType(E1, T2, CK_NullToPointer); + E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).take(); return T2; } if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (T1->isMemberPointerType()) - ImpCastExprToType(E2, T1, CK_NullToMemberPointer); + E2 = ImpCastExprToType(E2, T1, CK_NullToMemberPointer).take(); else - ImpCastExprToType(E2, T1, CK_NullToPointer); + E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).take(); return T1; } @@ -3763,7 +4122,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->NumArgs); - TypeResult T = ActOnTemplateIdType(TemplateId->Template, + TypeResult T = ActOnTemplateIdType(TemplateId->SS, + TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, @@ -3811,7 +4171,8 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, ASTTemplateArgsPtr TemplateArgsPtr(*this, TemplateId->getTemplateArgs(), TemplateId->NumArgs); - TypeResult T = ActOnTemplateIdType(TemplateId->Template, + TypeResult T = ActOnTemplateIdType(TemplateId->SS, + TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, @@ -3834,24 +4195,25 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, Destructed, HasTrailingLParen); } -ExprResult Sema::BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, +ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, CXXMethodDecl *Method) { - if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0, - FoundDecl, Method)) + ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/0, + FoundDecl, Method); + if (Exp.isInvalid()) return true; MemberExpr *ME = - new (Context) MemberExpr(Exp, /*IsArrow=*/false, Method, + new (Context) MemberExpr(Exp.take(), /*IsArrow=*/false, Method, SourceLocation(), Method->getType(), VK_RValue, OK_Ordinary); QualType ResultType = Method->getResultType(); ExprValueKind VK = Expr::getValueKindForType(ResultType); ResultType = ResultType.getNonLValueExprType(Context); - MarkDeclarationReferenced(Exp->getLocStart(), Method); + MarkDeclarationReferenced(Exp.get()->getLocStart(), Method); CXXMemberCallExpr *CE = new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, VK, - Exp->getLocEnd()); + Exp.get()->getLocEnd()); return CE; } @@ -3869,46 +4231,62 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation, /// Perform the conversions required for an expression used in a /// context that ignores the result. -void Sema::IgnoredValueConversions(Expr *&E) { +ExprResult Sema::IgnoredValueConversions(Expr *E) { // C99 6.3.2.1: // [Except in specific positions,] an lvalue that does not have // array type is converted to the value stored in the // designated object (and is no longer an lvalue). - if (E->isRValue()) return; + if (E->isRValue()) return Owned(E); // We always want to do this on ObjC property references. if (E->getObjectKind() == OK_ObjCProperty) { - ConvertPropertyForRValue(E); - if (E->isRValue()) return; + ExprResult Res = ConvertPropertyForRValue(E); + if (Res.isInvalid()) return Owned(E); + E = Res.take(); + if (E->isRValue()) return Owned(E); } // Otherwise, this rule does not apply in C++, at least not for the moment. - if (getLangOptions().CPlusPlus) return; + if (getLangOptions().CPlusPlus) return Owned(E); // GCC seems to also exclude expressions of incomplete enum type. if (const EnumType *T = E->getType()->getAs<EnumType>()) { if (!T->getDecl()->isComplete()) { // FIXME: stupid workaround for a codegen bug! - ImpCastExprToType(E, Context.VoidTy, CK_ToVoid); - return; + E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).take(); + return Owned(E); } } - DefaultFunctionArrayLvalueConversion(E); + ExprResult Res = DefaultFunctionArrayLvalueConversion(E); + if (Res.isInvalid()) + return Owned(E); + E = Res.take(); + if (!E->getType()->isVoidType()) RequireCompleteType(E->getExprLoc(), E->getType(), diag::err_incomplete_type); + return Owned(E); } -ExprResult Sema::ActOnFinishFullExpr(Expr *FullExpr) { - if (!FullExpr) +ExprResult Sema::ActOnFinishFullExpr(Expr *FE) { + ExprResult FullExpr = Owned(FE); + + if (!FullExpr.get()) + return ExprError(); + + if (DiagnoseUnexpandedParameterPack(FullExpr.get())) + return ExprError(); + + FullExpr = CheckPlaceholderExpr(FullExpr.take()); + if (FullExpr.isInvalid()) return ExprError(); - if (DiagnoseUnexpandedParameterPack(FullExpr)) + FullExpr = IgnoredValueConversions(FullExpr.take()); + if (FullExpr.isInvalid()) return ExprError(); - IgnoredValueConversions(FullExpr); - CheckImplicitConversions(FullExpr); + CheckImplicitConversions(FullExpr.get()); return MaybeCreateExprWithCleanups(FullExpr); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp index 4d03b06..2a262f0 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp @@ -62,7 +62,8 @@ ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, // Create the aggregate string with the appropriate content and location // information. - S = StringLiteral::Create(Context, &StrBuf[0], StrBuf.size(), false, + S = StringLiteral::Create(Context, &StrBuf[0], StrBuf.size(), + /*Wide=*/false, /*Pascal=*/false, Context.getPointerType(Context.CharTy), &StrLocs[0], StrLocs.size()); } @@ -246,7 +247,10 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, if (Args[i]->isTypeDependent()) continue; - DefaultArgumentPromotion(Args[i]); + ExprResult Result = DefaultArgumentPromotion(Args[i]); + if (Result.isInvalid()) + return true; + Args[i] = Result.take(); } unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found : @@ -305,7 +309,9 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, if (Args[i]->isTypeDependent()) continue; - IsError |= DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0); + ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0); + IsError |= Arg.isInvalid(); + Args[i] = Arg.take(); } } else { // Check for extra arguments to non-variadic methods. @@ -318,12 +324,24 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Args[NumArgs-1]->getLocEnd()); } } + // diagnose nonnull arguments. + for (specific_attr_iterator<NonNullAttr> + i = Method->specific_attr_begin<NonNullAttr>(), + e = Method->specific_attr_end<NonNullAttr>(); i != e; ++i) { + CheckNonNullArguments(*i, Args, lbrac); + } DiagnoseSentinelCalls(Method, lbrac, Args, NumArgs); return IsError; } bool Sema::isSelfExpr(Expr *RExpr) { + // 'self' is objc 'self' in an objc method only. + DeclContext *DC = CurContext; + while (isa<BlockDecl>(DC)) + DC = DC->getParent(); + if (DC && !isa<ObjCMethodDecl>(DC)) + return false; if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(RExpr)) if (ICE->getCastKind() == CK_LValueToRValue) RExpr = ICE->getSubExpr(); @@ -381,6 +399,23 @@ ObjCMethodDecl *Sema::LookupPrivateInstanceMethod(Selector Sel, return Method; } +/// LookupMethodInQualifiedType - Lookups up a method in protocol qualifier +/// list of a qualified objective pointer type. +ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel, + const ObjCObjectPointerType *OPT, + bool Instance) +{ + ObjCMethodDecl *MD = 0; + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) { + ObjCProtocolDecl *PROTO = (*I); + if ((MD = PROTO->lookupMethod(Sel, Instance))) { + return MD; + } + } + return 0; +} + /// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an /// objective C interface. This is a property reference expression. ExprResult Sema:: @@ -391,6 +426,13 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, bool Super) { const ObjCInterfaceType *IFaceT = OPT->getInterfaceType(); ObjCInterfaceDecl *IFace = IFaceT->getDecl(); + + if (MemberName.getNameKind() != DeclarationName::Identifier) { + Diag(MemberLoc, diag::err_invalid_property_name) + << MemberName << QualType(OPT, 0); + return ExprError(); + } + IdentifierInfo *Member = MemberName.getAsIdentifierInfo(); if (IFace->isForwardDecl()) { @@ -405,6 +447,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); QualType ResTy = PD->getType(); + ResTy = ResTy.getNonLValueExprType(Context); Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)) @@ -448,6 +491,10 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); + + // May be founf in property's qualified list. + if (!Getter) + Getter = LookupMethodInQualifiedType(Sel, OPT, true); // If this reference is in an @implementation, check for 'private' methods. if (!Getter) @@ -467,6 +514,11 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, SelectorTable::constructSetterName(PP.getIdentifierTable(), PP.getSelectorTable(), Member); ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); + + // May be founf in property's qualified list. + if (!Setter) + Setter = LookupMethodInQualifiedType(SetterSel, OPT, true); + if (!Setter) { // If this reference is in an @implementation, also check for 'private' // methods. @@ -475,7 +527,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // Look through local category implementations associated with the class. if (!Setter) Setter = IFace->getCategoryInstanceMethod(SetterSel); - + if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc)) return ExprError(); @@ -868,7 +920,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, return ExprError(); } assert(Class && "We don't know which class we're messaging?"); - + (void)DiagnoseUseOfDecl(Class, Loc); // Find the method we are messaging. if (!Method) { if (Class->isForwardDecl()) { @@ -1007,7 +1059,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // If necessary, apply function/array conversion to the receiver. // C99 6.7.5.3p[7,8]. - DefaultFunctionArrayLvalueConversion(Receiver); + ExprResult Result = DefaultFunctionArrayLvalueConversion(Receiver); + if (Result.isInvalid()) + return ExprError(); + Receiver = Result.take(); ReceiverType = Receiver->getType(); } @@ -1026,39 +1081,53 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } else if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { // Handle messages to Class. - if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { - if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { - // First check the public methods in the class interface. - Method = ClassDecl->lookupClassMethod(Sel); - - if (!Method) - Method = LookupPrivateClassMethod(Sel, ClassDecl); + // We allow sending a message to a qualified Class ("Class<foo>"), which + // is ok as long as one of the protocols implements the selector (if not, warn). + if (const ObjCObjectPointerType *QClassTy + = ReceiverType->getAsObjCQualifiedClassType()) { + // Search protocols for class methods. + Method = LookupMethodInQualifiedType(Sel, QClassTy, false); + if (!Method) { + Method = LookupMethodInQualifiedType(Sel, QClassTy, true); + // warn if instance method found for a Class message. + if (Method) { + Diag(Loc, diag::warn_instance_method_on_class_found) + << Method->getSelector() << Sel; + Diag(Method->getLocation(), diag::note_method_declared_at); + } + } + } else { + if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { + if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) { + // First check the public methods in the class interface. + Method = ClassDecl->lookupClassMethod(Sel); - // FIXME: if we still haven't found a method, we need to look in - // protocols (if we have qualifiers). + if (!Method) + Method = LookupPrivateClassMethod(Sel, ClassDecl); + } + if (Method && DiagnoseUseOfDecl(Method, Loc)) + return ExprError(); } - if (Method && DiagnoseUseOfDecl(Method, Loc)) - return ExprError(); - } - if (!Method) { - // If not messaging 'self', look for any factory method named 'Sel'. - if (!Receiver || !isSelfExpr(Receiver)) { - Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc), - true); - if (!Method) { - // If no class (factory) method was found, check if an _instance_ - // method of the same name exists in the root class only. - Method = LookupInstanceMethodInGlobalPool(Sel, + if (!Method) { + // If not messaging 'self', look for any factory method named 'Sel'. + if (!Receiver || !isSelfExpr(Receiver)) { + Method = LookupFactoryMethodInGlobalPool(Sel, + SourceRange(LBracLoc, RBracLoc), + true); + if (!Method) { + // If no class (factory) method was found, check if an _instance_ + // method of the same name exists in the root class only. + Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc), - true); - if (Method) - if (const ObjCInterfaceDecl *ID = - dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { - if (ID->getSuperClass()) - Diag(Loc, diag::warn_root_inst_method_not_found) - << Sel << SourceRange(LBracLoc, RBracLoc); - } + true); + if (Method) + if (const ObjCInterfaceDecl *ID = + dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { + if (ID->getSuperClass()) + Diag(Loc, diag::warn_root_inst_method_not_found) + << Sel << SourceRange(LBracLoc, RBracLoc); + } + } } } } @@ -1070,15 +1139,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (const ObjCObjectPointerType *QIdTy = ReceiverType->getAsObjCQualifiedIdType()) { // Search protocols for instance methods. - for (ObjCObjectPointerType::qual_iterator I = QIdTy->qual_begin(), - E = QIdTy->qual_end(); I != E; ++I) { - ObjCProtocolDecl *PDecl = *I; - if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) - break; - // Since we aren't supporting "Class<foo>", look for a class method. - if (PDecl && (Method = PDecl->lookupClassMethod(Sel))) - break; - } + Method = LookupMethodInQualifiedType(Sel, QIdTy, true); + if (!Method) + Method = LookupMethodInQualifiedType(Sel, QIdTy, false); } else if (const ObjCObjectPointerType *OCIType = ReceiverType->getAsObjCInterfacePointerType()) { // We allow sending a message to a pointer to an interface (an object). @@ -1088,15 +1151,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // The idea is to add class info to MethodPool. Method = ClassDecl->lookupInstanceMethod(Sel); - if (!Method) { + if (!Method) // Search protocol qualifiers. - for (ObjCObjectPointerType::qual_iterator QI = OCIType->qual_begin(), - E = OCIType->qual_end(); QI != E; ++QI) { - if ((Method = (*QI)->lookupInstanceMethod(Sel))) - break; - } - } - bool forwardClass = false; + Method = LookupMethodInQualifiedType(Sel, OCIType, true); + + const ObjCInterfaceDecl *forwardClass = 0; if (!Method) { // If we have implementations in scope, check "private" methods. Method = LookupPrivateInstanceMethod(Sel, ClassDecl); @@ -1108,7 +1167,8 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc)); - forwardClass = OCIType->getInterfaceDecl()->isForwardDecl(); + if (OCIType->getInterfaceDecl()->isForwardDecl()) + forwardClass = OCIType->getInterfaceDecl(); if (Method && !forwardClass) Diag(Loc, diag::warn_maynot_respond) << OCIType->getInterfaceDecl()->getIdentifier() << Sel; @@ -1125,37 +1185,42 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, << ReceiverType << Receiver->getSourceRange(); if (ReceiverType->isPointerType()) - ImpCastExprToType(Receiver, Context.getObjCIdType(), - CK_BitCast); + Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), + CK_BitCast).take(); else { // TODO: specialized warning on null receivers? bool IsNull = Receiver->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull); - ImpCastExprToType(Receiver, Context.getObjCIdType(), - IsNull ? CK_NullToPointer : CK_IntegralToPointer); + Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), + IsNull ? CK_NullToPointer : CK_IntegralToPointer).take(); } ReceiverType = Receiver->getType(); } - else if (getLangOptions().CPlusPlus && - !PerformContextuallyConvertToObjCId(Receiver)) { - if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) { - Receiver = ICE->getSubExpr(); - ReceiverType = Receiver->getType(); + else { + ExprResult ReceiverRes; + if (getLangOptions().CPlusPlus) + ReceiverRes = PerformContextuallyConvertToObjCId(Receiver); + if (ReceiverRes.isUsable()) { + Receiver = ReceiverRes.take(); + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Receiver)) { + Receiver = ICE->getSubExpr(); + ReceiverType = Receiver->getType(); + } + return BuildInstanceMessage(Receiver, + ReceiverType, + SuperLoc, + Sel, + Method, + LBracLoc, + SelectorLoc, + RBracLoc, + move(ArgsIn)); + } else { + // Reject other random receiver types (e.g. structs). + Diag(Loc, diag::err_bad_receiver_type) + << ReceiverType << Receiver->getSourceRange(); + return ExprError(); } - return BuildInstanceMessage(Receiver, - ReceiverType, - SuperLoc, - Sel, - Method, - LBracLoc, - SelectorLoc, - RBracLoc, - move(ArgsIn)); - } else { - // Reject other random receiver types (e.g. structs). - Diag(Loc, diag::err_bad_receiver_type) - << ReceiverType << Receiver->getSourceRange(); - return ExprError(); } } } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp index 5882da0..ca3fd6d 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp @@ -92,13 +92,31 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, const ConstantArrayType *CAT = cast<ConstantArrayType>(AT); - // C99 6.7.8p14. We have an array of character type with known size. However, + // We have an array of character type with known size. However, // the size may be smaller or larger than the string we are initializing. // FIXME: Avoid truncation for 64-bit length strings. - if (StrLength-1 > CAT->getSize().getZExtValue()) - S.Diag(Str->getSourceRange().getBegin(), - diag::warn_initializer_string_for_char_array_too_long) - << Str->getSourceRange(); + if (S.getLangOptions().CPlusPlus) { + if (StringLiteral *SL = dyn_cast<StringLiteral>(Str)) { + // For Pascal strings it's OK to strip off the terminating null character, + // so the example below is valid: + // + // unsigned char a[2] = "\pa"; + if (SL->isPascal()) + StrLength--; + } + + // [dcl.init.string]p2 + if (StrLength > CAT->getSize().getZExtValue()) + S.Diag(Str->getSourceRange().getBegin(), + diag::err_initializer_string_for_char_array_too_long) + << Str->getSourceRange(); + } else { + // C99 6.7.8p14. + if (StrLength-1 > CAT->getSize().getZExtValue()) + S.Diag(Str->getSourceRange().getBegin(), + diag::warn_initializer_string_for_char_array_too_long) + << Str->getSourceRange(); + } // Set the type to the actual size that we are initializing. If we have // something like: @@ -386,15 +404,29 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity, if (hadError) { // Do nothing } else if (Init < NumInits) { - ILE->setInit(Init, ElementInit.takeAs<Expr>()); - } else if (InitSeq.getKind() + // For arrays, just set the expression used for value-initialization + // of the "holes" in the array. + if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) + ILE->setArrayFiller(ElementInit.takeAs<Expr>()); + else + ILE->setInit(Init, ElementInit.takeAs<Expr>()); + } else { + // For arrays, just set the expression used for value-initialization + // of the rest of elements and exit. + if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement) { + ILE->setArrayFiller(ElementInit.takeAs<Expr>()); + return; + } + + if (InitSeq.getKind() == InitializationSequence::ConstructorInitialization) { - // Value-initialization requires a constructor call, so - // extend the initializer list to include the constructor - // call and make a note that we'll need to take another pass - // through the initializer list. - ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>()); - RequiresSecondPass = true; + // Value-initialization requires a constructor call, so + // extend the initializer list to include the constructor + // call and make a note that we'll need to take another pass + // through the initializer list. + ILE->updateInit(SemaRef.Context, Init, ElementInit.takeAs<Expr>()); + RequiresSecondPass = true; + } } } else if (InitListExpr *InnerILE = dyn_cast<InitListExpr>(ILE->getInit(Init))) @@ -713,15 +745,23 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // compatible structure or union type. In the latter case, the // initial value of the object, including unnamed members, is // that of the expression. + ExprResult ExprRes = SemaRef.Owned(expr); if ((ElemType->isRecordType() || ElemType->isVectorType()) && - SemaRef.CheckSingleAssignmentConstraints(ElemType, expr) + SemaRef.CheckSingleAssignmentConstraints(ElemType, ExprRes) == Sema::Compatible) { - SemaRef.DefaultFunctionArrayLvalueConversion(expr); - UpdateStructuredListElement(StructuredList, StructuredIndex, expr); + if (ExprRes.isInvalid()) + hadError = true; + else { + ExprRes = SemaRef.DefaultFunctionArrayLvalueConversion(ExprRes.take()); + if (ExprRes.isInvalid()) + hadError = true; + } + UpdateStructuredListElement(StructuredList, StructuredIndex, + ExprRes.takeAs<Expr>()); ++Index; return; } - + ExprRes.release(); // Fall through for subaggregate initialization } @@ -1755,11 +1795,15 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, // Pre-allocate storage for the structured initializer list. unsigned NumElements = 0; unsigned NumInits = 0; - if (!StructuredList) + bool GotNumInits = false; + if (!StructuredList) { NumInits = IList->getNumInits(); - else if (Index < IList->getNumInits()) { - if (InitListExpr *SubList = dyn_cast<InitListExpr>(IList->getInit(Index))) + GotNumInits = true; + } else if (Index < IList->getNumInits()) { + if (InitListExpr *SubList = dyn_cast<InitListExpr>(IList->getInit(Index))) { NumInits = SubList->getNumInits(); + GotNumInits = true; + } } if (const ArrayType *AType @@ -1768,7 +1812,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, NumElements = CAType->getSize().getZExtValue(); // Simple heuristic so that we don't allocate a very large // initializer with many empty entries at the end. - if (NumInits && NumElements > NumInits) + if (GotNumInits && NumElements > NumInits) NumElements = 0; } } else if (const VectorType *VType = CurrentObjectType->getAs<VectorType>()) @@ -1936,6 +1980,9 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, Loc, GNUSyntax, Init.takeAs<Expr>()); if (getLangOptions().CPlusPlus) + Diag(DIE->getLocStart(), diag::ext_designated_init_cxx) + << DIE->getSourceRange(); + else if (!getLangOptions().C99) Diag(DIE->getLocStart(), diag::ext_designated_init) << DIE->getSourceRange(); @@ -1998,6 +2045,7 @@ DeclarationName InitializedEntity::getName() const { case EK_New: case EK_Temporary: case EK_Base: + case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: case EK_BlockElement: @@ -2020,6 +2068,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const { case EK_New: case EK_Temporary: case EK_Base: + case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: case EK_BlockElement: @@ -2042,6 +2091,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_New: case EK_Temporary: case EK_Base: + case EK_Delegating: case EK_ArrayElement: case EK_VectorElement: case EK_BlockElement: @@ -2101,6 +2151,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_ReferenceInitDropsQualifiers: case FK_ReferenceInitFailed: case FK_ConversionFailed: + case FK_ConversionFromPropertyFailed: case FK_TooManyInitsForScalar: case FK_ReferenceBindingToInitList: case FK_InitListBadDestinationType: @@ -3126,8 +3177,14 @@ InitializationSequence::InitializationSequence(Sema &S, } for (unsigned I = 0; I != NumArgs; ++I) - if (Args[I]->getObjectKind() == OK_ObjCProperty) - S.ConvertPropertyForRValue(Args[I]); + if (Args[I]->getObjectKind() == OK_ObjCProperty) { + ExprResult Result = S.ConvertPropertyForRValue(Args[I]); + if (Result.isInvalid()) { + SetFailed(FK_ConversionFromPropertyFailed); + return; + } + Args[I] = Result.take(); + } QualType SourceType; Expr *Initializer = 0; @@ -3289,6 +3346,7 @@ getAssignmentAction(const InitializedEntity &Entity) { case InitializedEntity::EK_New: case InitializedEntity::EK_Exception: case InitializedEntity::EK_Base: + case InitializedEntity::EK_Delegating: return Sema::AA_Initializing; case InitializedEntity::EK_Parameter: @@ -3325,6 +3383,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_New: case InitializedEntity::EK_Variable: case InitializedEntity::EK_Base: + case InitializedEntity::EK_Delegating: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_Exception: case InitializedEntity::EK_BlockElement: @@ -3346,6 +3405,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Result: case InitializedEntity::EK_New: case InitializedEntity::EK_Base: + case InitializedEntity::EK_Delegating: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_BlockElement: return false; @@ -3430,6 +3490,7 @@ static ExprResult CopyObject(Sema &S, case InitializedEntity::EK_Temporary: case InitializedEntity::EK_New: case InitializedEntity::EK_Base: + case InitializedEntity::EK_Delegating: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_BlockElement: Loc = CurInitExpr->getLocStart(); @@ -3686,14 +3747,15 @@ InitializationSequence::Perform(Sema &S, case SK_ObjCObjectConversion: case SK_ArrayInit: { assert(Args.size() == 1); - Expr *CurInitExpr = Args.get()[0]; - if (!CurInitExpr) return ExprError(); + CurInit = Args.get()[0]; + if (!CurInit.get()) return ExprError(); // Read from a property when initializing something with it. - if (CurInitExpr->getObjectKind() == OK_ObjCProperty) - S.ConvertPropertyForRValue(CurInitExpr); - - CurInit = ExprResult(CurInitExpr); + if (CurInit.get()->getObjectKind() == OK_ObjCProperty) { + CurInit = S.ConvertPropertyForRValue(CurInit.take()); + if (CurInit.isInvalid()) + return ExprError(); + } break; } @@ -3710,14 +3772,13 @@ InitializationSequence::Perform(Sema &S, if (CurInit.isInvalid()) return ExprError(); - Expr *CurInitExpr = CurInit.get(); - QualType SourceType = CurInitExpr? CurInitExpr->getType() : QualType(); + QualType SourceType = CurInit.get() ? CurInit.get()->getType() : QualType(); switch (Step->Kind) { case SK_ResolveAddressOfOverloadedFunction: // Overload resolution determined which function invoke; update the // initializer to reflect that choice. - S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl); + S.CheckAddressOfMemberAccess(CurInit.get(), Step->Function.FoundDecl); S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation()); CurInit = S.FixOverloadedFunctionReference(move(CurInit), Step->Function.FoundDecl, @@ -3735,8 +3796,8 @@ InitializationSequence::Perform(Sema &S, // Casts to inaccessible base classes are allowed with C-style casts. bool IgnoreBaseAccess = Kind.isCStyleOrFunctionalCast(); if (S.CheckDerivedToBaseConversion(SourceType, Step->Type, - CurInitExpr->getLocStart(), - CurInitExpr->getSourceRange(), + CurInit.get()->getLocStart(), + CurInit.get()->getSourceRange(), &BasePath, IgnoreBaseAccess)) return ExprError(); @@ -3745,7 +3806,7 @@ InitializationSequence::Perform(Sema &S, if (const PointerType *Pointer = T->getAs<PointerType>()) T = Pointer->getPointeeType(); if (const RecordType *RecordTy = T->getAs<RecordType>()) - S.MarkVTableUsed(CurInitExpr->getLocStart(), + S.MarkVTableUsed(CurInit.get()->getLocStart(), cast<CXXRecordDecl>(RecordTy->getDecl())); } @@ -3764,21 +3825,21 @@ InitializationSequence::Perform(Sema &S, } case SK_BindReference: - if (FieldDecl *BitField = CurInitExpr->getBitField()) { + if (FieldDecl *BitField = CurInit.get()->getBitField()) { // References cannot bind to bit fields (C++ [dcl.init.ref]p5). S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield) << Entity.getType().isVolatileQualified() << BitField->getDeclName() - << CurInitExpr->getSourceRange(); + << CurInit.get()->getSourceRange(); S.Diag(BitField->getLocation(), diag::note_bitfield_decl); return ExprError(); } - if (CurInitExpr->refersToVectorElement()) { + if (CurInit.get()->refersToVectorElement()) { // References cannot bind to vector elements. S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element) << Entity.getType().isVolatileQualified() - << CurInitExpr->getSourceRange(); + << CurInit.get()->getSourceRange(); PrintInitLocationNote(S, Entity); return ExprError(); } @@ -3786,7 +3847,7 @@ InitializationSequence::Perform(Sema &S, // Reference binding does not have any corresponding ASTs. // Check exception specifications - if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) + if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType)) return ExprError(); break; @@ -3795,7 +3856,7 @@ InitializationSequence::Perform(Sema &S, // Reference binding does not have any corresponding ASTs. // Check exception specifications - if (S.CheckExceptionSpecCompatibility(CurInitExpr, DestType)) + if (S.CheckExceptionSpecCompatibility(CurInit.get(), DestType)) return ExprError(); break; @@ -3817,13 +3878,14 @@ InitializationSequence::Perform(Sema &S, if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) { // Build a call to the selected constructor. ASTOwningVector<Expr*> ConstructorArgs(S); - SourceLocation Loc = CurInitExpr->getLocStart(); + SourceLocation Loc = CurInit.get()->getLocStart(); CurInit.release(); // Ownership transferred into MultiExprArg, below. // Determine the arguments required to actually perform the constructor // call. + Expr *Arg = CurInit.get(); if (S.CompleteConstructorCall(Constructor, - MultiExprArg(&CurInitExpr, 1), + MultiExprArg(&Arg, 1), Loc, ConstructorArgs)) return ExprError(); @@ -3851,23 +3913,22 @@ InitializationSequence::Perform(Sema &S, // Build a call to the conversion function. CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn); IsLvalue = Conversion->getResultType()->isLValueReferenceType(); - S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0, + S.CheckMemberOperatorAccess(Kind.getLocation(), CurInit.get(), 0, FoundFn); S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()); // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because // we don't want to turn off access control here for c-style casts. - if (S.PerformObjectArgumentInitialization(CurInitExpr, /*Qualifier=*/0, - FoundFn, Conversion)) + ExprResult CurInitExprRes = + S.PerformObjectArgumentInitialization(CurInit.take(), /*Qualifier=*/0, + FoundFn, Conversion); + if(CurInitExprRes.isInvalid()) return ExprError(); - - // Do a little dance to make sure that CurInit has the proper - // pointer. - CurInit.release(); + CurInit = move(CurInitExprRes); // Build the actual call to the conversion function. - CurInit = S.BuildCXXMemberCallExpr(CurInitExpr, FoundFn, Conversion); + CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion); if (CurInit.isInvalid() || !CurInit.get()) return ExprError(); @@ -3881,23 +3942,21 @@ InitializationSequence::Perform(Sema &S, if (RequiresCopy || shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); else if (CreatedObject && shouldDestroyTemporary(Entity)) { - CurInitExpr = static_cast<Expr *>(CurInit.get()); - QualType T = CurInitExpr->getType(); + QualType T = CurInit.get()->getType(); if (const RecordType *Record = T->getAs<RecordType>()) { CXXDestructorDecl *Destructor = S.LookupDestructor(cast<CXXRecordDecl>(Record->getDecl())); - S.CheckDestructorAccess(CurInitExpr->getLocStart(), Destructor, + S.CheckDestructorAccess(CurInit.get()->getLocStart(), Destructor, S.PDiag(diag::err_access_dtor_temp) << T); - S.MarkDeclarationReferenced(CurInitExpr->getLocStart(), Destructor); - S.DiagnoseUseOfDecl(Destructor, CurInitExpr->getLocStart()); + S.MarkDeclarationReferenced(CurInit.get()->getLocStart(), Destructor); + S.DiagnoseUseOfDecl(Destructor, CurInit.get()->getLocStart()); } } - CurInitExpr = CurInit.takeAs<Expr>(); // FIXME: xvalues CurInit = S.Owned(ImplicitCastExpr::Create(S.Context, - CurInitExpr->getType(), - CastKind, CurInitExpr, 0, + CurInit.get()->getType(), + CastKind, CurInit.get(), 0, IsLvalue ? VK_LValue : VK_RValue)); if (RequiresCopy) @@ -3917,25 +3976,23 @@ InitializationSequence::Perform(Sema &S, (Step->Kind == SK_QualificationConversionXValue ? VK_XValue : VK_RValue); - S.ImpCastExprToType(CurInitExpr, Step->Type, CK_NoOp, VK); - CurInit.release(); - CurInit = S.Owned(CurInitExpr); + CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type, CK_NoOp, VK); break; } case SK_ConversionSequence: { - if (S.PerformImplicitConversion(CurInitExpr, Step->Type, *Step->ICS, - getAssignmentAction(Entity), - Kind.isCStyleOrFunctionalCast())) + ExprResult CurInitExprRes = + S.PerformImplicitConversion(CurInit.get(), Step->Type, *Step->ICS, + getAssignmentAction(Entity), + Kind.isCStyleOrFunctionalCast()); + if (CurInitExprRes.isInvalid()) return ExprError(); - - CurInit.release(); - CurInit = S.Owned(CurInitExpr); + CurInit = move(CurInitExprRes); break; } case SK_ListInitialization: { - InitListExpr *InitList = cast<InitListExpr>(CurInitExpr); + InitListExpr *InitList = cast<InitListExpr>(CurInit.get()); QualType Ty = Step->Type; if (S.CheckInitList(Entity, InitList, ResultType? *ResultType : Ty)) return ExprError(); @@ -4004,6 +4061,9 @@ InitializationSequence::Perform(Sema &S, CXXConstructExpr::CK_VirtualBase : CXXConstructExpr::CK_NonVirtualBase; } + if (Entity.getKind() == InitializedEntity::EK_Delegating) { + ConstructKind = CXXConstructExpr::CK_Delegating; + } // Only get the parenthesis range if it is a direct construction. SourceRange parenRange = @@ -4068,54 +4128,57 @@ InitializationSequence::Perform(Sema &S, } case SK_CAssignment: { - QualType SourceType = CurInitExpr->getType(); + QualType SourceType = CurInit.get()->getType(); + ExprResult Result = move(CurInit); Sema::AssignConvertType ConvTy = - S.CheckSingleAssignmentConstraints(Step->Type, CurInitExpr); + S.CheckSingleAssignmentConstraints(Step->Type, Result); + if (Result.isInvalid()) + return ExprError(); + CurInit = move(Result); // If this is a call, allow conversion to a transparent union. + ExprResult CurInitExprRes = move(CurInit); if (ConvTy != Sema::Compatible && Entity.getKind() == InitializedEntity::EK_Parameter && - S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExpr) + S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExprRes) == Sema::Compatible) ConvTy = Sema::Compatible; + if (CurInitExprRes.isInvalid()) + return ExprError(); + CurInit = move(CurInitExprRes); bool Complained; if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(), Step->Type, SourceType, - CurInitExpr, + CurInit.get(), getAssignmentAction(Entity), &Complained)) { PrintInitLocationNote(S, Entity); return ExprError(); } else if (Complained) PrintInitLocationNote(S, Entity); - - CurInit.release(); - CurInit = S.Owned(CurInitExpr); break; } case SK_StringInit: { QualType Ty = Step->Type; - CheckStringInit(CurInitExpr, ResultType ? *ResultType : Ty, + CheckStringInit(CurInit.get(), ResultType ? *ResultType : Ty, S.Context.getAsArrayType(Ty), S); break; } case SK_ObjCObjectConversion: - S.ImpCastExprToType(CurInitExpr, Step->Type, + CurInit = S.ImpCastExprToType(CurInit.take(), Step->Type, CK_ObjCObjectLValueCast, - S.CastCategory(CurInitExpr)); - CurInit.release(); - CurInit = S.Owned(CurInitExpr); + S.CastCategory(CurInit.get())); break; case SK_ArrayInit: // Okay: we checked everything before creating this step. Note that // this is a GNU extension. S.Diag(Kind.getLocation(), diag::ext_array_init_copy) - << Step->Type << CurInitExpr->getType() - << CurInitExpr->getSourceRange(); + << Step->Type << CurInit.get()->getType() + << CurInit.get()->getSourceRange(); // If the destination type is an incomplete array type, update the // type accordingly. @@ -4123,7 +4186,7 @@ InitializationSequence::Perform(Sema &S, if (const IncompleteArrayType *IncompleteDest = S.Context.getAsIncompleteArrayType(Step->Type)) { if (const ConstantArrayType *ConstantSource - = S.Context.getAsConstantArrayType(CurInitExpr->getType())) { + = S.Context.getAsConstantArrayType(CurInit.get()->getType())) { *ResultType = S.Context.getConstantArrayType( IncompleteDest->getElementType(), ConstantSource->getSize(), @@ -4283,6 +4346,11 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->getSourceRange(); break; } + + case FK_ConversionFromPropertyFailed: + // No-op. This error has already been reported. + break; + case FK_TooManyInitsForScalar: { SourceRange R; @@ -4482,6 +4550,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const { OS << "conversion failed"; break; + case FK_ConversionFromPropertyFailed: + OS << "conversion from property failed"; + break; + case FK_TooManyInitsForScalar: OS << "too many initializers for scalar"; break; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp index 3deb403..309c771 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp @@ -686,8 +686,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // FIXME: Calling convention! FunctionProtoType::ExtProtoInfo EPI = ConvProto->getExtProtoInfo(); EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC_Default); - EPI.HasExceptionSpec = false; - EPI.HasAnyExceptionSpec = false; + EPI.ExceptionSpecType = EST_None; EPI.NumExceptions = 0; QualType ExpectedType = R.getSema().Context.getFunctionType(R.getLookupName().getCXXNameType(), @@ -1130,8 +1129,8 @@ bool Sema::LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation) { // If we didn't find a use of this identifier, and if the identifier // corresponds to a compiler builtin, create the decl object for the builtin // now, injecting it into translation unit scope, and return it. - if (AllowBuiltinCreation) - return LookupBuiltin(*this, R); + if (AllowBuiltinCreation && LookupBuiltin(*this, R)) + return true; // If we didn't find a use of this identifier, the ExternalSource // may be able to handle the situation. @@ -1964,10 +1963,13 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { case Type::Complex: break; - // These are ignored by ADL. + // If T is an Objective-C object or interface type, or a pointer to an + // object or interface type, the associated namespace is the global + // namespace. case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: + Result.Namespaces.insert(Result.S.Context.getTranslationUnitDecl()); break; } @@ -2203,7 +2205,8 @@ void ADLResult::insert(NamedDecl *New) { void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, - ADLResult &Result) { + ADLResult &Result, + bool StdNamespaceIsAssociated) { // Find all of the associated namespaces and classes based on the // arguments we have. AssociatedNamespaceSet AssociatedNamespaces; @@ -2211,6 +2214,8 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, FindAssociatedClassesAndNamespaces(Args, NumArgs, AssociatedNamespaces, AssociatedClasses); + if (StdNamespaceIsAssociated && StdNamespace) + AssociatedNamespaces.insert(getStdNamespace()); QualType T1, T2; if (Operator) { @@ -2766,30 +2771,35 @@ void Sema::LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, } /// LookupOrCreateLabel - Do a name lookup of a label with the specified name. -/// If isLocalLabel is true, then this is a definition of an __label__ label -/// name, otherwise it is a normal label definition or use. +/// If GnuLabelLoc is a valid source location, then this is a definition +/// of an __label__ label name, otherwise it is a normal label definition +/// or use. LabelDecl *Sema::LookupOrCreateLabel(IdentifierInfo *II, SourceLocation Loc, - bool isLocalLabel) { + SourceLocation GnuLabelLoc) { // Do a lookup to see if we have a label with this name already. NamedDecl *Res = 0; - - // Local label definitions always shadow existing labels. - if (!isLocalLabel) - Res = LookupSingleName(CurScope, II, Loc, LookupLabel, NotForRedeclaration); - - // If we found a label, check to see if it is in the same context as us. When - // in a Block, we don't want to reuse a label in an enclosing function. + + if (GnuLabelLoc.isValid()) { + // Local label definitions always shadow existing labels. + Res = LabelDecl::Create(Context, CurContext, Loc, II, GnuLabelLoc); + Scope *S = CurScope; + PushOnScopeChains(Res, S, true); + return cast<LabelDecl>(Res); + } + + // Not a GNU local label. + Res = LookupSingleName(CurScope, II, Loc, LookupLabel, NotForRedeclaration); + // If we found a label, check to see if it is in the same context as us. + // When in a Block, we don't want to reuse a label in an enclosing function. if (Res && Res->getDeclContext() != CurContext) Res = 0; - if (Res == 0) { // If not forward referenced or defined already, create the backing decl. Res = LabelDecl::Create(Context, CurContext, Loc, II); - Scope *S = isLocalLabel ? CurScope : CurScope->getFnParent(); + Scope *S = CurScope->getFnParent(); assert(S && "Not in a function?"); PushOnScopeChains(Res, S, true); } - return cast<LabelDecl>(Res); } @@ -2853,8 +2863,6 @@ void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, } void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) { - using namespace std; - // Use a simple length-based heuristic to determine the minimum possible // edit distance. If the minimum isn't good enough, bail out early. unsigned MinED = abs((int)Name.size() - (int)Typo.size()); @@ -2863,7 +2871,8 @@ void TypoCorrectionConsumer::FoundName(llvm::StringRef Name) { // Compute an upper bound on the allowable edit distance, so that the // edit-distance algorithm can short-circuit. - unsigned UpperBound = min(unsigned((Typo.size() + 2) / 3), BestEditDistance); + unsigned UpperBound = + std::min(unsigned((Typo.size() + 2) / 3), BestEditDistance); // Compute the edit distance between the typo and the name of this // entity. If this edit distance is not worse than the best edit diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp index b086ca7..6c4469c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp @@ -45,11 +45,7 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, !(Attributes & ObjCDeclSpec::DQ_PR_copy))); TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); - QualType T = TSI->getType(); - if (T->isReferenceType()) { - Diag(AtLoc, diag::error_reference_property); - return 0; - } + // Proceed with constructing the ObjCPropertDecls. ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(ClassCategory); @@ -404,12 +400,16 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (!PropertyIvar) PropertyIvar = PropertyId; QualType PropType = Context.getCanonicalType(property->getType()); + QualType PropertyIvarType = PropType; + if (PropType->isReferenceType()) + PropertyIvarType = cast<ReferenceType>(PropType)->getPointeeType(); // Check that this is a previously declared 'ivar' in 'IDecl' interface ObjCInterfaceDecl *ClassDeclared; Ivar = IDecl->lookupInstanceVariable(PropertyIvar, ClassDeclared); if (!Ivar) { - Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyLoc, - PropertyIvar, PropType, /*Dinfo=*/0, + Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, + PropertyLoc, PropertyLoc, PropertyIvar, + PropertyIvarType, /*Dinfo=*/0, ObjCIvarDecl::Private, (Expr *)0, true); ClassImpDecl->addDecl(Ivar); @@ -432,19 +432,19 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, QualType IvarType = Context.getCanonicalType(Ivar->getType()); // Check that type of property and its ivar are type compatible. - if (PropType != IvarType) { + if (PropertyIvarType != IvarType) { bool compat = false; - if (isa<ObjCObjectPointerType>(PropType) + if (isa<ObjCObjectPointerType>(PropertyIvarType) && isa<ObjCObjectPointerType>(IvarType)) compat = Context.canAssignObjCInterfaces( - PropType->getAs<ObjCObjectPointerType>(), + PropertyIvarType->getAs<ObjCObjectPointerType>(), IvarType->getAs<ObjCObjectPointerType>()); else { SourceLocation Loc = PropertyIvarLoc; if (Loc.isInvalid()) Loc = PropertyLoc; - compat = (CheckAssignmentConstraints(Loc, PropType, IvarType) + compat = (CheckAssignmentConstraints(Loc, PropertyIvarType, IvarType) == Compatible); } if (!compat) { @@ -459,7 +459,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // FIXME! Rules for properties are somewhat different that those // for assignments. Use a new routine to consolidate all cases; // specifically for property redeclarations as well as for ivars. - QualType lhsType =Context.getCanonicalType(PropType).getUnqualifiedType(); + QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType(); QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType(); if (lhsType != rhsType && lhsType->isArithmeticType()) { @@ -538,7 +538,10 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, SelfExpr, true, true); ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); ParmVarDecl *Param = (*P); - Expr *rhs = new (Context) DeclRefExpr(Param, Param->getType(), + QualType T = Param->getType(); + if (T->isReferenceType()) + T = T->getAs<ReferenceType>()->getPointeeType(); + Expr *rhs = new (Context) DeclRefExpr(Param, T, VK_LValue, SourceLocation()); ExprResult Res = BuildBinOp(S, lhs->getLocEnd(), BO_Assign, lhs, rhs); @@ -682,7 +685,7 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, /// ComparePropertiesInBaseAndSuper - This routine compares property /// declarations in base and its super class, if any, and issues -/// diagnostics in a variety of inconsistant situations. +/// diagnostics in a variety of inconsistent situations. /// void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) { ObjCInterfaceDecl *SDecl = IDecl->getSuperClass(); @@ -1137,10 +1140,14 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, static void AddPropertyAttrs(Sema &S, ObjCMethodDecl *PropertyMethod, ObjCPropertyDecl *Property) { // Should we just clone all attributes over? - if (DeprecatedAttr *A = Property->getAttr<DeprecatedAttr>()) - PropertyMethod->addAttr(A->clone(S.Context)); - if (UnavailableAttr *A = Property->getAttr<UnavailableAttr>()) - PropertyMethod->addAttr(A->clone(S.Context)); + for (Decl::attr_iterator A = Property->attr_begin(), + AEnd = Property->attr_end(); + A != AEnd; ++A) { + if (isa<DeprecatedAttr>(*A) || + isa<UnavailableAttr>(*A) || + isa<AvailabilityAttr>(*A)) + PropertyMethod->addAttr((*A)->clone(S.Context)); + } } /// ProcessPropertyDecl - Make sure that any user-defined setter/getter methods @@ -1235,7 +1242,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, // Invent the arguments for the setter. We don't bother making a // nice name for the argument. - ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, Loc, + ParmVarDecl *Argument = ParmVarDecl::Create(Context, SetterMethod, + Loc, Loc, property->getIdentifier(), property->getType(), /*TInfo=*/0, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp index 8d03285..3f3ed0e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp @@ -36,18 +36,26 @@ using namespace sema; /// A convenience routine for creating a decayed reference to a /// function. -static Expr * +static ExprResult CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, SourceLocation Loc = SourceLocation()) { - Expr *E = new (S.Context) DeclRefExpr(Fn, Fn->getType(), VK_LValue, Loc); - S.DefaultFunctionArrayConversion(E); - return E; + ExprResult E = S.Owned(new (S.Context) DeclRefExpr(Fn, Fn->getType(), VK_LValue, Loc)); + E = S.DefaultFunctionArrayConversion(E.take()); + if (E.isInvalid()) + return ExprError(); + return move(E); } static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, bool InOverloadResolution, StandardConversionSequence &SCS, bool CStyle); + +static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From, + QualType &ToType, + bool InOverloadResolution, + StandardConversionSequence &SCS, + bool CStyle); static OverloadingResult IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, UserDefinedConversionSequence& User, @@ -128,7 +136,9 @@ ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind) { ICR_Conversion, ICR_Conversion, ICR_Conversion, - ICR_Complex_Real_Conversion + ICR_Complex_Real_Conversion, + ICR_Conversion, + ICR_Conversion }; return Rank[(int)Kind]; } @@ -157,7 +167,9 @@ const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Derived-to-base conversion", "Vector conversion", "Vector splat", - "Complex-real conversion" + "Complex-real conversion", + "Block Pointer conversion", + "Transparent Union Conversion" }; return Name[Kind]; } @@ -228,7 +240,7 @@ isPointerConversionToVoidPointer(ASTContext& Context) const { if (First == ICK_Array_To_Pointer) FromType = Context.getArrayDecayedType(FromType); - if (Second == ICK_Pointer_Conversion && FromType->isPointerType()) + if (Second == ICK_Pointer_Conversion && FromType->isAnyPointerType()) if (const PointerType* ToPtrType = ToType->getAs<PointerType>()) return ToPtrType->getPointeeType()->isVoidType(); @@ -876,20 +888,19 @@ bool Sema::TryImplicitConversion(InitializationSequence &Sequence, } /// PerformImplicitConversion - Perform an implicit conversion of the -/// expression From to the type ToType. Returns true if there was an -/// error, false otherwise. The expression From is replaced with the +/// expression From to the type ToType. Returns the /// converted expression. Flavor is the kind of conversion we're /// performing, used in the error message. If @p AllowExplicit, /// explicit user-defined conversions are permitted. -bool -Sema::PerformImplicitConversion(Expr *&From, QualType ToType, +ExprResult +Sema::PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit) { ImplicitConversionSequence ICS; return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS); } -bool -Sema::PerformImplicitConversion(Expr *&From, QualType ToType, +ExprResult +Sema::PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit, ImplicitConversionSequence& ICS) { ICS = clang::TryImplicitConversion(*this, From, ToType, @@ -1048,27 +1059,33 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // otherwise, only a boolean conversion is standard if (!ToType->isBooleanType()) return false; - - } - - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) { - if (!Method->isStatic()) { - const Type *ClassType - = S.Context.getTypeDeclType(Method->getParent()).getTypePtr(); - FromType = S.Context.getMemberPointerType(FromType, ClassType); - } } - // If the "from" expression takes the address of the overloaded - // function, update the type of the resulting expression accordingly. - if (FromType->getAs<FunctionType>()) - if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(From->IgnoreParens())) - if (UnOp->getOpcode() == UO_AddrOf) - FromType = S.Context.getPointerType(FromType); + // Check if the "from" expression is taking the address of an overloaded + // function and recompute the FromType accordingly. Take advantage of the + // fact that non-static member functions *must* have such an address-of + // expression. + CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn); + if (Method && !Method->isStatic()) { + assert(isa<UnaryOperator>(From->IgnoreParens()) && + "Non-unary operator on non-static member address"); + assert(cast<UnaryOperator>(From->IgnoreParens())->getOpcode() + == UO_AddrOf && + "Non-address-of operator on non-static member address"); + const Type *ClassType + = S.Context.getTypeDeclType(Method->getParent()).getTypePtr(); + FromType = S.Context.getMemberPointerType(FromType, ClassType); + } else if (isa<UnaryOperator>(From->IgnoreParens())) { + assert(cast<UnaryOperator>(From->IgnoreParens())->getOpcode() == + UO_AddrOf && + "Non-address-of operator for overloaded function expression"); + FromType = S.Context.getPointerType(FromType); + } // Check that we've computed the proper type after overload resolution. - assert(S.Context.hasSameType(FromType, - S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType())); + assert(S.Context.hasSameType( + FromType, + S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType())); } else { return false; } @@ -1188,6 +1205,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // Pointer conversions (C++ 4.10). SCS.Second = ICK_Pointer_Conversion; SCS.IncompatibleObjC = IncompatibleObjC; + FromType = FromType.getUnqualifiedType(); } else if (S.IsMemberPointerConversion(From, FromType, ToType, InOverloadResolution, FromType)) { // Pointer to member conversions (4.11). @@ -1203,6 +1221,11 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, } else if (IsNoReturnConversion(S.Context, FromType, ToType, FromType)) { // Treat a conversion that strips "noreturn" as an identity conversion. SCS.Second = ICK_NoReturn_Adjustment; + } else if (IsTransparentUnionStandardConversion(S, From, ToType, + InOverloadResolution, + SCS, CStyle)) { + SCS.Second = ICK_TransparentUnionConversion; + FromType = ToType; } else { // No second conversion required. SCS.Second = ICK_Identity; @@ -1244,6 +1267,30 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, return true; } + +static bool +IsTransparentUnionStandardConversion(Sema &S, Expr* From, + QualType &ToType, + bool InOverloadResolution, + StandardConversionSequence &SCS, + bool CStyle) { + + const RecordType *UT = ToType->getAsUnionType(); + if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>()) + return false; + // The field to initialize within the transparent union. + RecordDecl *UD = UT->getDecl(); + // It's compatible if the expression matches any of the fields. + for (RecordDecl::field_iterator it = UD->field_begin(), + itend = UD->field_end(); + it != itend; ++it) { + if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS, CStyle)) { + ToType = it->getType(); + return true; + } + } + return false; +} /// IsIntegralPromotion - Determines whether the conversion from the /// expression From (whose potentially-adjusted type is FromType) to @@ -1615,8 +1662,30 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType, return true; } + if (FromPointeeType->isVectorType() && ToPointeeType->isVectorType() && + Context.areCompatibleVectorTypes(FromPointeeType, ToPointeeType)) { + ConvertedType = BuildSimilarlyQualifiedPointerType(FromTypePtr, + ToPointeeType, + ToType, Context); + return true; + } + return false; } + +/// \brief Adopt the given qualifiers for the given type. +static QualType AdoptQualifiers(ASTContext &Context, QualType T, Qualifiers Qs){ + Qualifiers TQs = T.getQualifiers(); + + // Check whether qualifiers already match. + if (TQs == Qs) + return T; + + if (Qs.compatiblyIncludes(TQs)) + return Context.getQualifiedType(T, Qs); + + return Context.getQualifiedType(T.getUnqualifiedType(), Qs); +} /// isObjCPointerConversion - Determines whether this is an /// Objective-C pointer conversion. Subroutine of IsPointerConversion, @@ -1627,6 +1696,9 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, if (!getLangOptions().ObjC1) return false; + // The set of qualifiers on the type we're converting from. + Qualifiers FromQualifiers = FromType.getQualifiers(); + // First, we handle all conversions on ObjC object pointer types. const ObjCObjectPointerType* ToObjCPtr = ToType->getAs<ObjCObjectPointerType>(); @@ -1640,10 +1712,11 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, FromObjCPtr->getPointeeType())) return false; + // Check for compatible // Objective C++: We're able to convert between "id" or "Class" and a // pointer to any interface (in both directions). if (ToObjCPtr->isObjCBuiltinType() && FromObjCPtr->isObjCBuiltinType()) { - ConvertedType = ToType; + ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); return true; } // Conversions with Objective-C's id<...>. @@ -1651,7 +1724,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ToObjCPtr->isObjCQualifiedIdType()) && Context.ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) { - ConvertedType = ToType; + ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); return true; } // Objective C++: We're able to convert from a pointer to an @@ -1666,6 +1739,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, ToObjCPtr->getPointeeType(), ToType, Context); + ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers); return true; } @@ -1677,6 +1751,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr, ToObjCPtr->getPointeeType(), ToType, Context); + ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers); return true; } } @@ -1689,7 +1764,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, // Objective C++: We're able to convert from a pointer to any object // to a block pointer type. if (FromObjCPtr && FromObjCPtr->isObjCBuiltinType()) { - ConvertedType = ToType; + ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); return true; } ToPointeeType = ToBlockPtr->getPointeeType(); @@ -1698,7 +1773,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, ToObjCPtr && ToObjCPtr->isObjCBuiltinType()) { // Objective C++: We're able to convert from a block pointer type to a // pointer to any object. - ConvertedType = ToType; + ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); return true; } else @@ -1721,6 +1796,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, // We always complain about this conversion. IncompatibleObjC = true; ConvertedType = Context.getPointerType(ConvertedType); + ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers); return true; } // Allow conversion of pointee being objective-c pointer to another one; @@ -1730,6 +1806,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType, IncompatibleObjC)) { ConvertedType = Context.getPointerType(ConvertedType); + ConvertedType = AdoptQualifiers(Context, ConvertedType, FromQualifiers); return true; } @@ -1790,7 +1867,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, if (HasObjCConversion) { // We had an Objective-C conversion. Allow this pointer // conversion, but complain about it. - ConvertedType = ToType; + ConvertedType = AdoptQualifiers(Context, ToType, FromQualifiers); IncompatibleObjC = true; return true; } @@ -1936,11 +2013,12 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, Kind = CK_BitCast; - if (CXXBoolLiteralExpr* LitBool - = dyn_cast<CXXBoolLiteralExpr>(From->IgnoreParens())) - if (!IsCStyleOrFunctionalCast && LitBool->getValue() == false) - Diag(LitBool->getExprLoc(), diag::warn_init_pointer_from_false) - << ToType; + if (!IsCStyleOrFunctionalCast && + Context.hasSameUnqualifiedType(From->getType(), Context.BoolTy) && + From->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) + DiagRuntimeBehavior(From->getExprLoc(), From, + PDiag(diag::warn_impcast_bool_to_null_pointer) + << ToType << From->getSourceRange()); if (const PointerType *FromPtrType = FromType->getAs<PointerType>()) if (const PointerType *ToPtrType = ToType->getAs<PointerType>()) { @@ -2116,21 +2194,24 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, // unwrap. UnwrappedAnyPointer = true; + Qualifiers FromQuals = FromType.getQualifiers(); + Qualifiers ToQuals = ToType.getQualifiers(); + // -- for every j > 0, if const is in cv 1,j then const is in cv // 2,j, and similarly for volatile. - if (!CStyle && !ToType.isAtLeastAsQualifiedAs(FromType)) + if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals)) return false; // -- if the cv 1,j and cv 2,j are different, then const is in // every cv for 0 < k < j. - if (!CStyle && FromType.getCVRQualifiers() != ToType.getCVRQualifiers() + if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers() && !PreviousToQualsIncludeConst) return false; // Keep track of whether all prior cv-qualifiers in the "to" type // include const. PreviousToQualsIncludeConst - = PreviousToQualsIncludeConst && ToType.isConstQualified(); + = PreviousToQualsIncludeConst && ToQuals.hasConst(); } // We are left with FromType and ToType being the pointee types @@ -2175,7 +2256,11 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, S.IsDerivedFrom(From->getType(), ToType))) ConstructorsOnly = true; - if (S.RequireCompleteType(From->getLocStart(), ToType, S.PDiag())) { + S.RequireCompleteType(From->getLocStart(), ToType, S.PDiag()); + // RequireCompleteType may have returned true due to some invalid decl + // during template instantiation, but ToType may be complete enough now + // to try to recover. + if (ToType->isIncompleteType()) { // We're not going to find any constructors. } else if (CXXRecordDecl *ToRecordDecl = dyn_cast<CXXRecordDecl>(ToRecordType->getDecl())) { @@ -2546,7 +2631,8 @@ CompareStandardConversionSequences(Sema &S, if (ImplicitConversionSequence::CompareKind DerivedCK = CompareDerivedToBaseConversions(S, SCS1, SCS2)) return DerivedCK; - } else if (SCS1ConvertsToVoid && SCS2ConvertsToVoid) { + } else if (SCS1ConvertsToVoid && SCS2ConvertsToVoid && + !S.Context.hasSameType(SCS1.getFromType(), SCS2.getFromType())) { // Both conversion sequences are conversions to void // pointers. Compare the source types to determine if there's an // inheritance relationship in their sources. @@ -2560,10 +2646,8 @@ CompareStandardConversionSequences(Sema &S, if (SCS2.First == ICK_Array_To_Pointer) FromType2 = S.Context.getArrayDecayedType(FromType2); - QualType FromPointee1 - = FromType1->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); - QualType FromPointee2 - = FromType2->getAs<PointerType>()->getPointeeType().getUnqualifiedType(); + QualType FromPointee1 = FromType1->getPointeeType().getUnqualifiedType(); + QualType FromPointee2 = FromType2->getPointeeType().getUnqualifiedType(); if (S.IsDerivedFrom(FromPointee2, FromPointee1)) return ImplicitConversionSequence::Better; @@ -2572,13 +2656,19 @@ CompareStandardConversionSequences(Sema &S, // Objective-C++: If one interface is more specific than the // other, it is the better one. - const ObjCObjectType* FromIface1 = FromPointee1->getAs<ObjCObjectType>(); - const ObjCObjectType* FromIface2 = FromPointee2->getAs<ObjCObjectType>(); - if (FromIface1 && FromIface1) { - if (S.Context.canAssignObjCInterfaces(FromIface2, FromIface1)) - return ImplicitConversionSequence::Better; - else if (S.Context.canAssignObjCInterfaces(FromIface1, FromIface2)) - return ImplicitConversionSequence::Worse; + const ObjCObjectPointerType* FromObjCPtr1 + = FromType1->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType* FromObjCPtr2 + = FromType2->getAs<ObjCObjectPointerType>(); + if (FromObjCPtr1 && FromObjCPtr2) { + bool AssignLeft = S.Context.canAssignObjCInterfaces(FromObjCPtr1, + FromObjCPtr2); + bool AssignRight = S.Context.canAssignObjCInterfaces(FromObjCPtr2, + FromObjCPtr1); + if (AssignLeft != AssignRight) { + return AssignLeft? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + } } } @@ -2981,7 +3071,12 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, // overload resolution, cases for which cv1 is greater // cv-qualification than cv2 are identified as // reference-compatible with added qualification (see 13.3.3.2). - if (T1Quals.getCVRQualifiers() == T2Quals.getCVRQualifiers()) + // + // Note that we also require equivalence of Objective-C GC and address-space + // qualifiers when performing these computations, so that e.g., an int in + // address space 1 is not reference-compatible with an int in address + // space 2. + if (T1Quals == T2Quals) return Ref_Compatible; else if (T1.isMoreQualifiedThan(T2)) return Ref_Compatible_With_Added_Qualification; @@ -3480,8 +3575,8 @@ TryObjectArgumentInitialization(Sema &S, QualType OrigFromType, /// PerformObjectArgumentInitialization - Perform initialization of /// the implicit object parameter for the given Method with the given /// expression. -bool -Sema::PerformObjectArgumentInitialization(Expr *&From, +ExprResult +Sema::PerformObjectArgumentInitialization(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method) { @@ -3517,7 +3612,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, << From->getSourceRange(); Diag(Method->getLocation(), diag::note_previous_decl) << Method->getDeclName(); - return true; + return ExprError(); } } @@ -3526,13 +3621,18 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, << ImplicitParamRecordType << FromRecordType << From->getSourceRange(); } - if (ICS.Standard.Second == ICK_Derived_To_Base) - return PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method); + if (ICS.Standard.Second == ICK_Derived_To_Base) { + ExprResult FromRes = + PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method); + if (FromRes.isInvalid()) + return ExprError(); + From = FromRes.take(); + } if (!Context.hasSameType(From->getType(), DestType)) - ImpCastExprToType(From, DestType, CK_NoOp, - From->getType()->isPointerType() ? VK_RValue : VK_LValue); - return false; + From = ImpCastExprToType(From, DestType, CK_NoOp, + From->getType()->isPointerType() ? VK_RValue : VK_LValue).take(); + return Owned(From); } /// TryContextuallyConvertToBool - Attempt to contextually convert the @@ -3550,16 +3650,16 @@ TryContextuallyConvertToBool(Sema &S, Expr *From) { /// PerformContextuallyConvertToBool - Perform a contextual conversion /// of the expression From to bool (C++0x [conv]p3). -bool Sema::PerformContextuallyConvertToBool(Expr *&From) { +ExprResult Sema::PerformContextuallyConvertToBool(Expr *From) { ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From); if (!ICS.isBad()) return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting); if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy)) - return Diag(From->getSourceRange().getBegin(), - diag::err_typecheck_bool_condition) + return Diag(From->getSourceRange().getBegin(), + diag::err_typecheck_bool_condition) << From->getType() << From->getSourceRange(); - return true; + return ExprError(); } /// TryContextuallyConvertToObjCId - Attempt to contextually convert the @@ -3577,12 +3677,12 @@ TryContextuallyConvertToObjCId(Sema &S, Expr *From) { /// PerformContextuallyConvertToObjCId - Perform a contextual conversion /// of the expression From to 'id'. -bool Sema::PerformContextuallyConvertToObjCId(Expr *&From) { +ExprResult Sema::PerformContextuallyConvertToObjCId(Expr *From) { QualType Ty = Context.getObjCIdType(); ImplicitConversionSequence ICS = TryContextuallyConvertToObjCId(*this, From); if (!ICS.isBad()) return PerformImplicitConversion(From, Ty, ICS, AA_Converting); - return true; + return ExprError(); } /// \brief Attempt to convert the given expression to an integral or @@ -4061,7 +4161,7 @@ void Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, Expr::Classification ObjectClassification, Expr **Args, unsigned NumArgs, @@ -4114,7 +4214,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, void Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions) { @@ -6090,9 +6190,10 @@ void Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, bool Operator, Expr **Args, unsigned NumArgs, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, - bool PartialOverloading) { + bool PartialOverloading, + bool StdNamespaceIsAssociated) { ADLResult Fns; // FIXME: This approach for uniquing ADL results (and removing @@ -6103,7 +6204,8 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, // we supposed to consider on ADL candidates, anyway? // FIXME: Pass in the explicit template arguments? - ArgumentDependentLookup(Name, Operator, Args, NumArgs, Fns); + ArgumentDependentLookup(Name, Operator, Args, NumArgs, Fns, + StdNamespaceIsAssociated); // Erase all of the candidates we already knew about. for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), @@ -6282,8 +6384,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, // Best is the best viable function. if (Best->Function && - (Best->Function->isDeleted() || - Best->Function->getAttr<UnavailableAttr>())) + (Best->Function->isDeleted() || Best->Function->isUnavailable())) return OR_Deleted; return OR_Success; @@ -6473,6 +6574,17 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) { return; } + if (FromQs.getObjCGCAttr() != ToQs.getObjCGCAttr()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_gc) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy + << FromQs.getObjCGCAttr() << ToQs.getObjCGCAttr() + << (unsigned) isObjectArgument << I+1; + MaybeEmitInheritedConstructorNote(S, Fn); + return; + } + unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers(); assert(CVR && "unexpected qualifiers mismatch"); @@ -6735,7 +6847,7 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, FunctionDecl *Fn = Cand->Function; // Note deleted candidates, but only if they're viable. - if (Cand->Viable && (Fn->isDeleted() || Fn->hasAttr<UnavailableAttr>())) { + if (Cand->Viable && (Fn->isDeleted() || Fn->isUnavailable())) { std::string FnDesc; OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc); @@ -7134,8 +7246,23 @@ public: if (!TargetFunctionType->isFunctionType()) { if (OvlExpr->hasExplicitTemplateArgs()) { DeclAccessPair dap; - if( FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization( + if (FunctionDecl* Fn = S.ResolveSingleFunctionTemplateSpecialization( OvlExpr, false, &dap) ) { + + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Fn)) { + if (!Method->isStatic()) { + // If the target type is a non-function type and the function + // found is a non-static member function, pretend as if that was + // the target, it's the only possible type to end up with. + TargetTypeIsNonStaticMemberFunction = true; + + // And skip adding the function if its not in the proper form. + // We'll diagnose this due to an empty set of functions. + if (!OvlExprInfo.HasFormOfMemberPointer) + return; + } + } + Matches.push_back(std::make_pair(dap,Fn)); } } @@ -7419,32 +7546,29 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetTyp /// template, where that template-id refers to a single template whose template /// arguments are either provided by the template-id or have defaults, /// as described in C++0x [temp.arg.explicit]p3. -FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From, - bool Complain, - DeclAccessPair* FoundResult) { +FunctionDecl * +Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, + bool Complain, + DeclAccessPair *FoundResult) { // C++ [over.over]p1: // [...] [Note: any redundant set of parentheses surrounding the // overloaded function name is ignored (5.1). ] // C++ [over.over]p1: // [...] The overloaded function name can be preceded by the & // operator. - if (From->getType() != Context.OverloadTy) - return 0; - - OverloadExpr *OvlExpr = OverloadExpr::find(From).Expression; // If we didn't actually find any template-ids, we're done. - if (!OvlExpr->hasExplicitTemplateArgs()) + if (!ovl->hasExplicitTemplateArgs()) return 0; TemplateArgumentListInfo ExplicitTemplateArgs; - OvlExpr->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs); + ovl->getExplicitTemplateArgs().copyInto(ExplicitTemplateArgs); // Look through all of the overloaded functions, searching for one // whose type matches exactly. FunctionDecl *Matched = 0; - for (UnresolvedSetIterator I = OvlExpr->decls_begin(), - E = OvlExpr->decls_end(); I != E; ++I) { + for (UnresolvedSetIterator I = ovl->decls_begin(), + E = ovl->decls_end(); I != E; ++I) { // C++0x [temp.arg.explicit]p3: // [...] In contexts where deduction is done and fails, or in contexts // where deduction is not done, if a template argument list is @@ -7461,7 +7585,7 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From, // function template specialization, which is added to the set of // overloaded functions considered. FunctionDecl *Specialization = 0; - TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc()); + TemplateDeductionInfo Info(Context, ovl->getNameLoc()); if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs, Specialization, Info)) { @@ -7470,30 +7594,98 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From, continue; } + assert(Specialization && "no specialization and no error?"); + // Multiple matches; we can't resolve to a single declaration. if (Matched) { - if (FoundResult) - *FoundResult = DeclAccessPair(); - if (Complain) { - Diag(From->getLocStart(), diag::err_addr_ovl_ambiguous) - << OvlExpr->getName(); - NoteAllOverloadCandidates(OvlExpr); + Diag(ovl->getExprLoc(), diag::err_addr_ovl_ambiguous) + << ovl->getName(); + NoteAllOverloadCandidates(ovl); } return 0; - } + } - if ((Matched = Specialization) && FoundResult) - *FoundResult = I.getPair(); + Matched = Specialization; + if (FoundResult) *FoundResult = I.getPair(); } return Matched; } + + + +// Resolve and fix an overloaded expression that +// can be resolved because it identifies a single function +// template specialization +// Last three arguments should only be supplied if Complain = true +ExprResult Sema::ResolveAndFixSingleFunctionTemplateSpecialization( + Expr *SrcExpr, bool doFunctionPointerConverion, bool complain, + const SourceRange& OpRangeForComplaining, + QualType DestTypeForComplaining, + unsigned DiagIDForComplaining) { + assert(SrcExpr->getType() == Context.OverloadTy); + + OverloadExpr::FindResult ovl = OverloadExpr::find(SrcExpr); + + DeclAccessPair found; + ExprResult SingleFunctionExpression; + if (FunctionDecl *fn = ResolveSingleFunctionTemplateSpecialization( + ovl.Expression, /*complain*/ false, &found)) { + if (DiagnoseUseOfDecl(fn, SrcExpr->getSourceRange().getBegin())) + return ExprError(); + + // It is only correct to resolve to an instance method if we're + // resolving a form that's permitted to be a pointer to member. + // Otherwise we'll end up making a bound member expression, which + // is illegal in all the contexts we resolve like this. + if (!ovl.HasFormOfMemberPointer && + isa<CXXMethodDecl>(fn) && + cast<CXXMethodDecl>(fn)->isInstance()) { + if (complain) { + Diag(ovl.Expression->getExprLoc(), + diag::err_invalid_use_of_bound_member_func) + << ovl.Expression->getSourceRange(); + // TODO: I believe we only end up here if there's a mix of + // static and non-static candidates (otherwise the expression + // would have 'bound member' type, not 'overload' type). + // Ideally we would note which candidate was chosen and why + // the static candidates were rejected. + } + + return ExprError(); + } + + // Fix the expresion to refer to 'fn'. + SingleFunctionExpression = + Owned(FixOverloadedFunctionReference(SrcExpr, found, fn)); + + // If desired, do function-to-pointer decay. + if (doFunctionPointerConverion) + SingleFunctionExpression = + DefaultFunctionArrayLvalueConversion(SingleFunctionExpression.take()); + } + + if (!SingleFunctionExpression.isUsable()) { + if (complain) { + Diag(OpRangeForComplaining.getBegin(), DiagIDForComplaining) + << ovl.Expression->getName() + << DestTypeForComplaining + << OpRangeForComplaining + << ovl.Expression->getQualifierLoc().getSourceRange(); + NoteAllOverloadCandidates(SrcExpr); + } + return ExprError(); + } + + return SingleFunctionExpression; +} + /// \brief Add a single candidate to the overload set. static void AddOverloadedCallCandidate(Sema &S, DeclAccessPair FoundDecl, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, OverloadCandidateSet &CandidateSet, bool PartialOverloading) { @@ -7559,7 +7751,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, // It would be nice to avoid this copy. TemplateArgumentListInfo TABuffer; - const TemplateArgumentListInfo *ExplicitTemplateArgs = 0; + TemplateArgumentListInfo *ExplicitTemplateArgs = 0; if (ULE->hasExplicitTemplateArgs()) { ULE->copyTemplateArgumentsInto(TABuffer); ExplicitTemplateArgs = &TABuffer; @@ -7576,7 +7768,8 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, Args, NumArgs, ExplicitTemplateArgs, CandidateSet, - PartialOverloading); + PartialOverloading, + ULE->isStdAssociatedNamespace()); } /// Attempts to recover from a call where no functions were found. @@ -7590,9 +7783,7 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, SourceLocation RParenLoc) { CXXScopeSpec SS; - if (ULE->getQualifier()) - SS.MakeTrivial(SemaRef.Context, - ULE->getQualifier(), ULE->getQualifierRange()); + SS.Adopt(ULE->getQualifierLoc()); TemplateArgumentListInfo TABuffer; const TemplateArgumentListInfo *ExplicitTemplateArgs = 0; @@ -7657,7 +7848,9 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, // We don't perform ADL in C. assert(getLangOptions().CPlusPlus && "ADL enabled in C"); - } + } else + assert(!ULE->isStdAssociatedNamespace() && + "std is associated namespace but not doing ADL"); #endif OverloadCandidateSet CandidateSet(Fn->getExprLoc()); @@ -7704,8 +7897,7 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, Diag(Fn->getSourceRange().getBegin(), diag::err_ovl_deleted_call) << Best->Function->isDeleted() << ULE->getName() - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Fn->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); } @@ -7749,8 +7941,12 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // TODO: provide better source location info. DeclarationNameInfo OpNameInfo(OpName, OpLoc); - if (Input->getObjectKind() == OK_ObjCProperty) - ConvertPropertyForRValue(Input); + if (Input->getObjectKind() == OK_ObjCProperty) { + ExprResult Result = ConvertPropertyForRValue(Input); + if (Result.isInvalid()) + return ExprError(); + Input = Result.take(); + } Expr *Args[2] = { Input, 0 }; unsigned NumArgs = 1; @@ -7776,11 +7972,11 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, CXXRecordDecl *NamingClass = 0; // because lookup ignores member operators UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, NamingClass, - 0, SourceRange(), OpNameInfo, + NestedNameSpecifierLoc(), OpNameInfo, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, - &Args[0], NumArgs, + &Args[0], NumArgs, Context.DependentTy, VK_RValue, OpLoc)); @@ -7821,9 +8017,12 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) { CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl); - if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, - Best->FoundDecl, Method)) + ExprResult InputRes = + PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, + Best->FoundDecl, Method); + if (InputRes.isInvalid()) return ExprError(); + Input = InputRes.take(); } else { // Convert the arguments. ExprResult InputInit @@ -7845,11 +8044,13 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, ResultTy = ResultTy.getNonLValueExprType(Context); // Build the actual expression node. - Expr *FnExpr = CreateFunctionRefExpr(*this, FnDecl); + ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl); + if (FnExpr.isInvalid()) + return ExprError(); Args[0] = Input; CallExpr *TheCall = - new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, + new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(), Args, NumArgs, ResultTy, VK, OpLoc); if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, @@ -7861,39 +8062,40 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in // operator node. - if (PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0], - Best->Conversions[0], AA_Passing)) - return ExprError(); - - break; - } - } - - case OR_No_Viable_Function: - // No viable function; fall through to handling this as a - // built-in operator, which will produce an error message for us. + ExprResult InputRes = + PerformImplicitConversion(Input, Best->BuiltinTypes.ParamTypes[0], + Best->Conversions[0], AA_Passing); + if (InputRes.isInvalid()) + return ExprError(); + Input = InputRes.take(); break; + } + } - case OR_Ambiguous: - Diag(OpLoc, diag::err_ovl_ambiguous_oper_unary) - << UnaryOperator::getOpcodeStr(Opc) - << Input->getType() - << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, - Args, NumArgs, - UnaryOperator::getOpcodeStr(Opc), OpLoc); - return ExprError(); + case OR_No_Viable_Function: + // No viable function; fall through to handling this as a + // built-in operator, which will produce an error message for us. + break; - case OR_Deleted: - Diag(OpLoc, diag::err_ovl_deleted_oper) - << Best->Function->isDeleted() + case OR_Ambiguous: + Diag(OpLoc, diag::err_ovl_ambiguous_oper_unary) << UnaryOperator::getOpcodeStr(Opc) - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << Input->getType() << Input->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); - return ExprError(); - } + CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, + Args, NumArgs, + UnaryOperator::getOpcodeStr(Opc), OpLoc); + return ExprError(); + + case OR_Deleted: + Diag(OpLoc, diag::err_ovl_deleted_oper) + << Best->Function->isDeleted() + << UnaryOperator::getOpcodeStr(Opc) + << getDeletedOrUnavailableSuffix(Best->Function) + << Input->getSourceRange(); + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); + return ExprError(); + } // Either we found no viable overloaded operator or we matched a // built-in operator. In either case, fall through to trying to @@ -7956,8 +8158,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // TODO: provide better source location info in DNLoc component. DeclarationNameInfo OpNameInfo(OpName, OpLoc); UnresolvedLookupExpr *Fn - = UnresolvedLookupExpr::Create(Context, NamingClass, 0, SourceRange(), - OpNameInfo, /*ADL*/ true, IsOverloaded(Fns), + = UnresolvedLookupExpr::Create(Context, NamingClass, + NestedNameSpecifierLoc(), OpNameInfo, + /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args, 2, @@ -7967,8 +8170,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, } // Always do property rvalue conversions on the RHS. - if (Args[1]->getObjectKind() == OK_ObjCProperty) - ConvertPropertyForRValue(Args[1]); + if (Args[1]->getObjectKind() == OK_ObjCProperty) { + ExprResult Result = ConvertPropertyForRValue(Args[1]); + if (Result.isInvalid()) + return ExprError(); + Args[1] = Result.take(); + } // The LHS is more complicated. if (Args[0]->getObjectKind() == OK_ObjCProperty) { @@ -7996,7 +8203,10 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); } - ConvertPropertyForRValue(Args[0]); + ExprResult Result = ConvertPropertyForRValue(Args[0]); + if (Result.isInvalid()) + return ExprError(); + Args[0] = Result.take(); } // If this is the assignment operator, we only perform overload resolution @@ -8057,10 +8267,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (Arg1.isInvalid()) return ExprError(); - if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, - Best->FoundDecl, Method)) + ExprResult Arg0 = + PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, + Best->FoundDecl, Method); + if (Arg0.isInvalid()) return ExprError(); - + Args[0] = Arg0.takeAs<Expr>(); Args[1] = RHS = Arg1.takeAs<Expr>(); } else { // Convert the arguments. @@ -8090,10 +8302,12 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, ResultTy = ResultTy.getNonLValueExprType(Context); // Build the actual expression node. - Expr *FnExpr = CreateFunctionRefExpr(*this, FnDecl, OpLoc); + ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, OpLoc); + if (FnExpr.isInvalid()) + return ExprError(); CXXOperatorCallExpr *TheCall = - new (Context) CXXOperatorCallExpr(Context, Op, FnExpr, + new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(), Args, 2, ResultTy, VK, OpLoc); if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, @@ -8105,12 +8319,19 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in // operator node. - if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0], - Best->Conversions[0], AA_Passing) || - PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1], - Best->Conversions[1], AA_Passing)) + ExprResult ArgsRes0 = + PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0], + Best->Conversions[0], AA_Passing); + if (ArgsRes0.isInvalid()) return ExprError(); + Args[0] = ArgsRes0.take(); + ExprResult ArgsRes1 = + PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1], + Best->Conversions[1], AA_Passing); + if (ArgsRes1.isInvalid()) + return ExprError(); + Args[1] = ArgsRes1.take(); break; } } @@ -8158,8 +8379,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Diag(OpLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << BinaryOperator::getOpcodeStr(Opc) - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2); return ExprError(); @@ -8187,7 +8407,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, OpNameInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc)); UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create(Context, NamingClass, - 0, SourceRange(), OpNameInfo, + NestedNameSpecifierLoc(), OpNameInfo, /*ADL*/ true, /*Overloaded*/ false, UnresolvedSetIterator(), UnresolvedSetIterator()); @@ -8200,10 +8420,18 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, RLoc)); } - if (Args[0]->getObjectKind() == OK_ObjCProperty) - ConvertPropertyForRValue(Args[0]); - if (Args[1]->getObjectKind() == OK_ObjCProperty) - ConvertPropertyForRValue(Args[1]); + if (Args[0]->getObjectKind() == OK_ObjCProperty) { + ExprResult Result = ConvertPropertyForRValue(Args[0]); + if (Result.isInvalid()) + return ExprError(); + Args[0] = Result.take(); + } + if (Args[1]->getObjectKind() == OK_ObjCProperty) { + ExprResult Result = ConvertPropertyForRValue(Args[1]); + if (Result.isInvalid()) + return ExprError(); + Args[1] = Result.take(); + } // Build an empty overload set. OverloadCandidateSet CandidateSet(LLoc); @@ -8234,9 +8462,12 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Convert the arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl); - if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, - Best->FoundDecl, Method)) + ExprResult Arg0 = + PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, + Best->FoundDecl, Method); + if (Arg0.isInvalid()) return ExprError(); + Args[0] = Arg0.take(); // Convert the arguments. ExprResult InputInit @@ -8256,11 +8487,13 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, ResultTy = ResultTy.getNonLValueExprType(Context); // Build the actual expression node. - Expr *FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc); + ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, LLoc); + if (FnExpr.isInvalid()) + return ExprError(); CXXOperatorCallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, OO_Subscript, - FnExpr, Args, 2, + FnExpr.take(), Args, 2, ResultTy, VK, RLoc); if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall, @@ -8272,11 +8505,19 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in // operator node. - if (PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0], - Best->Conversions[0], AA_Passing) || - PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1], - Best->Conversions[1], AA_Passing)) + ExprResult ArgsRes0 = + PerformImplicitConversion(Args[0], Best->BuiltinTypes.ParamTypes[0], + Best->Conversions[0], AA_Passing); + if (ArgsRes0.isInvalid()) return ExprError(); + Args[0] = ArgsRes0.take(); + + ExprResult ArgsRes1 = + PerformImplicitConversion(Args[1], Best->BuiltinTypes.ParamTypes[1], + Best->Conversions[1], AA_Passing); + if (ArgsRes1.isInvalid()) + return ExprError(); + Args[1] = ArgsRes1.take(); break; } @@ -8308,8 +8549,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, case OR_Deleted: Diag(LLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << "[]" - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, 2, "[]", LLoc); @@ -8325,16 +8565,66 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, /// function (and includes the object parameter), Args/NumArgs are the /// arguments to the function call (not including the object /// parameter). The caller needs to validate that the member -/// expression refers to a member function or an overloaded member -/// function. +/// expression refers to a non-static member function or an overloaded +/// member function. ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc) { + assert(MemExprE->getType() == Context.BoundMemberTy || + MemExprE->getType() == Context.OverloadTy); + // Dig out the member expression. This holds both the object // argument and the member function we're referring to. Expr *NakedMemExpr = MemExprE->IgnoreParens(); + // Determine whether this is a call to a pointer-to-member function. + if (BinaryOperator *op = dyn_cast<BinaryOperator>(NakedMemExpr)) { + assert(op->getType() == Context.BoundMemberTy); + assert(op->getOpcode() == BO_PtrMemD || op->getOpcode() == BO_PtrMemI); + + QualType fnType = + op->getRHS()->getType()->castAs<MemberPointerType>()->getPointeeType(); + + const FunctionProtoType *proto = fnType->castAs<FunctionProtoType>(); + QualType resultType = proto->getCallResultType(Context); + ExprValueKind valueKind = Expr::getValueKindForType(proto->getResultType()); + + // Check that the object type isn't more qualified than the + // member function we're calling. + Qualifiers funcQuals = Qualifiers::fromCVRMask(proto->getTypeQuals()); + + QualType objectType = op->getLHS()->getType(); + if (op->getOpcode() == BO_PtrMemI) + objectType = objectType->castAs<PointerType>()->getPointeeType(); + Qualifiers objectQuals = objectType.getQualifiers(); + + Qualifiers difference = objectQuals - funcQuals; + difference.removeObjCGCAttr(); + difference.removeAddressSpace(); + if (difference) { + std::string qualsString = difference.getAsString(); + Diag(LParenLoc, diag::err_pointer_to_member_call_drops_quals) + << fnType.getUnqualifiedType() + << qualsString + << (qualsString.find(' ') == std::string::npos ? 1 : 2); + } + + CXXMemberCallExpr *call + = new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs, + resultType, valueKind, RParenLoc); + + if (CheckCallReturnType(proto->getResultType(), + op->getRHS()->getSourceRange().getBegin(), + call, 0)) + return ExprError(); + + if (ConvertArgumentsForCall(call, op, 0, proto, Args, NumArgs, RParenLoc)) + return ExprError(); + + return MaybeBindToTemporary(call); + } + MemberExpr *MemExpr; CXXMethodDecl *Method = 0; DeclAccessPair FoundDecl = DeclAccessPair::make(0, AS_public); @@ -8427,8 +8717,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call) << Best->Function->isDeleted() << DeclName - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << MemExprE->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); // FIXME: Leaking incoming expressions! @@ -8464,12 +8753,14 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // Convert the object argument (for a non-static member function call). // We only need to do this if there was actually an overload; otherwise // it was done at lookup. - Expr *ObjectArg = MemExpr->getBase(); - if (!Method->isStatic() && - PerformObjectArgumentInitialization(ObjectArg, Qualifier, - FoundDecl, Method)) - return ExprError(); - MemExpr->setBase(ObjectArg); + if (!Method->isStatic()) { + ExprResult ObjectArg = + PerformObjectArgumentInitialization(MemExpr->getBase(), Qualifier, + FoundDecl, Method); + if (ObjectArg.isInvalid()) + return ExprError(); + MemExpr->setBase(ObjectArg.take()); + } // Convert the rest of the arguments const FunctionProtoType *Proto = @@ -8489,15 +8780,19 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, /// overloaded function call operator (@c operator()) or performing a /// user-defined conversion on the object argument. ExprResult -Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, +Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, SourceLocation LParenLoc, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc) { - if (Object->getObjectKind() == OK_ObjCProperty) - ConvertPropertyForRValue(Object); + ExprResult Object = Owned(Obj); + if (Object.get()->getObjectKind() == OK_ObjCProperty) { + Object = ConvertPropertyForRValue(Object.take()); + if (Object.isInvalid()) + return ExprError(); + } - assert(Object->getType()->isRecordType() && "Requires object type argument"); - const RecordType *Record = Object->getType()->getAs<RecordType>(); + assert(Object.get()->getType()->isRecordType() && "Requires object type argument"); + const RecordType *Record = Object.get()->getType()->getAs<RecordType>(); // C++ [over.call.object]p1: // If the primary-expression E in the function call syntax @@ -8509,9 +8804,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, OverloadCandidateSet CandidateSet(LParenLoc); DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call); - if (RequireCompleteType(LParenLoc, Object->getType(), + if (RequireCompleteType(LParenLoc, Object.get()->getType(), PDiag(diag::err_incomplete_object_call) - << Object->getSourceRange())) + << Object.get()->getSourceRange())) return true; LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName); @@ -8520,8 +8815,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); Oper != OperEnd; ++Oper) { - AddMethodCandidate(Oper.getPair(), Object->getType(), - Object->Classify(Context), Args, NumArgs, CandidateSet, + AddMethodCandidate(Oper.getPair(), Object.get()->getType(), + Object.get()->Classify(Context), Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/ false); } @@ -8566,12 +8861,12 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, if (const FunctionProtoType *Proto = ConvType->getAs<FunctionProtoType>()) AddSurrogateCandidate(Conv, I.getPair(), ActingContext, Proto, - Object, Args, NumArgs, CandidateSet); + Object.get(), Args, NumArgs, CandidateSet); } // Perform overload resolution. OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(*this, Object->getLocStart(), + switch (CandidateSet.BestViableFunction(*this, Object.get()->getLocStart(), Best)) { case OR_Success: // Overload resolution succeeded; we'll build the appropriate call @@ -8580,31 +8875,30 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, case OR_No_Viable_Function: if (CandidateSet.empty()) - Diag(Object->getSourceRange().getBegin(), diag::err_ovl_no_oper) - << Object->getType() << /*call*/ 1 - << Object->getSourceRange(); + Diag(Object.get()->getSourceRange().getBegin(), diag::err_ovl_no_oper) + << Object.get()->getType() << /*call*/ 1 + << Object.get()->getSourceRange(); else - Diag(Object->getSourceRange().getBegin(), + Diag(Object.get()->getSourceRange().getBegin(), diag::err_ovl_no_viable_object_call) - << Object->getType() << Object->getSourceRange(); + << Object.get()->getType() << Object.get()->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); break; case OR_Ambiguous: - Diag(Object->getSourceRange().getBegin(), + Diag(Object.get()->getSourceRange().getBegin(), diag::err_ovl_ambiguous_object_call) - << Object->getType() << Object->getSourceRange(); + << Object.get()->getType() << Object.get()->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, Args, NumArgs); break; case OR_Deleted: - Diag(Object->getSourceRange().getBegin(), + Diag(Object.get()->getSourceRange().getBegin(), diag::err_ovl_deleted_object_call) << Best->Function->isDeleted() - << Object->getType() - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) - << Object->getSourceRange(); + << Object.get()->getType() + << getDeletedOrUnavailableSuffix(Best->Function) + << Object.get()->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, NumArgs); break; } @@ -8619,7 +8913,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, = cast<CXXConversionDecl>( Best->Conversions[0].UserDefined.ConversionFunction); - CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); + CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl); DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc); // We selected one of the surrogate functions that converts the @@ -8628,7 +8922,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Create an implicit member expr to refer to the conversion operator. // and then call it. - ExprResult Call = BuildCXXMemberCallExpr(Object, Best->FoundDecl, Conv); + ExprResult Call = BuildCXXMemberCallExpr(Object.get(), Best->FoundDecl, Conv); if (Call.isInvalid()) return ExprError(); @@ -8637,7 +8931,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, } MarkDeclarationReferenced(LParenLoc, Best->Function); - CheckMemberOperatorAccess(LParenLoc, Object, 0, Best->FoundDecl); + CheckMemberOperatorAccess(LParenLoc, Object.get(), 0, Best->FoundDecl); DiagnoseUseOfDecl(Best->FoundDecl, LParenLoc); // We found an overloaded operator(). Build a CXXOperatorCallExpr @@ -8660,11 +8954,13 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, } else { MethodArgs = new Expr*[NumArgs + 1]; } - MethodArgs[0] = Object; + MethodArgs[0] = Object.get(); for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) MethodArgs[ArgIdx + 1] = Args[ArgIdx]; - Expr *NewFn = CreateFunctionRefExpr(*this, Method); + ExprResult NewFn = CreateFunctionRefExpr(*this, Method); + if (NewFn.isInvalid()) + return true; // Once we've built TheCall, all of the expressions are properly // owned. @@ -8673,7 +8969,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, ResultTy = ResultTy.getNonLValueExprType(Context); CXXOperatorCallExpr *TheCall = - new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn, + new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn.take(), MethodArgs, NumArgs + 1, ResultTy, VK, RParenLoc); delete [] MethodArgs; @@ -8692,10 +8988,14 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, bool IsError = false; // Initialize the implicit object parameter. - IsError |= PerformObjectArgumentInitialization(Object, /*Qualifier=*/0, - Best->FoundDecl, Method); - TheCall->setArg(0, Object); - + ExprResult ObjRes = + PerformObjectArgumentInitialization(Object.get(), /*Qualifier=*/0, + Best->FoundDecl, Method); + if (ObjRes.isInvalid()) + IsError = true; + else + Object = move(ObjRes); + TheCall->setArg(0, Object.take()); // Check the argument types. for (unsigned i = 0; i != NumArgsToCheck; i++) { @@ -8731,9 +9031,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, if (Proto->isVariadic()) { // Promote the arguments (C99 6.5.2.2p7). for (unsigned i = NumArgsInProto; i != NumArgs; i++) { - Expr *Arg = Args[i]; - IsError |= DefaultVariadicArgumentPromotion(Arg, VariadicMethod, 0); - TheCall->setArg(i + 1, Arg); + ExprResult Arg = DefaultVariadicArgumentPromotion(Args[i], VariadicMethod, 0); + IsError |= Arg.isInvalid(); + TheCall->setArg(i + 1, Arg.take()); } } @@ -8753,8 +9053,12 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { assert(Base->getType()->isRecordType() && "left-hand side must have class type"); - if (Base->getObjectKind() == OK_ObjCProperty) - ConvertPropertyForRValue(Base); + if (Base->getObjectKind() == OK_ObjCProperty) { + ExprResult Result = ConvertPropertyForRValue(Base); + if (Result.isInvalid()) + return ExprError(); + Base = Result.take(); + } SourceLocation Loc = Base->getExprLoc(); @@ -8811,8 +9115,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { Diag(OpLoc, diag::err_ovl_deleted_oper) << Best->Function->isDeleted() << "->" - << Best->Function->getMessageUnavailableAttr( - !Best->Function->isDeleted()) + << getDeletedOrUnavailableSuffix(Best->Function) << Base->getSourceRange(); CandidateSet.NoteCandidates(*this, OCD_AllCandidates, &Base, 1); return ExprError(); @@ -8824,24 +9127,30 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { // Convert the object parameter. CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); - if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, - Best->FoundDecl, Method)) + ExprResult BaseResult = + PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, + Best->FoundDecl, Method); + if (BaseResult.isInvalid()) return ExprError(); + Base = BaseResult.take(); // Build the operator call. - Expr *FnExpr = CreateFunctionRefExpr(*this, Method); + ExprResult FnExpr = CreateFunctionRefExpr(*this, Method); + if (FnExpr.isInvalid()) + return ExprError(); QualType ResultTy = Method->getResultType(); ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); CXXOperatorCallExpr *TheCall = - new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, + new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr.take(), &Base, 1, ResultTy, VK, OpLoc); if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall, Method)) return ExprError(); - return Owned(TheCall); + + return MaybeBindToTemporary(TheCall); } /// FixOverloadedFunctionReference - E is an expression that refers to @@ -8930,12 +9239,12 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, } return DeclRefExpr::Create(Context, - ULE->getQualifier(), - ULE->getQualifierRange(), + ULE->getQualifierLoc(), Fn, ULE->getNameLoc(), Fn->getType(), VK_LValue, + Found.getDecl(), TemplateArgs); } @@ -8954,17 +9263,17 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, if (MemExpr->isImplicitAccess()) { if (cast<CXXMethodDecl>(Fn)->isStatic()) { return DeclRefExpr::Create(Context, - MemExpr->getQualifier(), - MemExpr->getQualifierRange(), + MemExpr->getQualifierLoc(), Fn, MemExpr->getMemberLoc(), Fn->getType(), VK_LValue, + Found.getDecl(), TemplateArgs); } else { SourceLocation Loc = MemExpr->getMemberLoc(); if (MemExpr->getQualifier()) - Loc = MemExpr->getQualifierRange().getBegin(); + Loc = MemExpr->getQualifierLoc().getBeginLoc(); Base = new (Context) CXXThisExpr(Loc, MemExpr->getBaseType(), /*isImplicit=*/true); @@ -8972,18 +9281,24 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, } else Base = MemExpr->getBase(); + ExprValueKind valueKind; + QualType type; + if (cast<CXXMethodDecl>(Fn)->isStatic()) { + valueKind = VK_LValue; + type = Fn->getType(); + } else { + valueKind = VK_RValue; + type = Context.BoundMemberTy; + } + return MemberExpr::Create(Context, Base, MemExpr->isArrow(), - MemExpr->getQualifier(), - MemExpr->getQualifierRange(), + MemExpr->getQualifierLoc(), Fn, Found, MemExpr->getMemberNameInfo(), TemplateArgs, - Fn->getType(), - cast<CXXMethodDecl>(Fn)->isStatic() - ? VK_LValue : VK_RValue, - OK_Ordinary); + type, valueKind, OK_Ordinary); } llvm_unreachable("Invalid reference to overloaded function"); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp index 89957e6..65cea7a 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Initialization.h" +#include "clang/Sema/Lookup.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -45,8 +46,9 @@ StmtResult Sema::ActOnExprStmt(FullExprArg expr) { } -StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc, bool LeadingEmptyMacro) { - return Owned(new (Context) NullStmt(SemiLoc, LeadingEmptyMacro)); +StmtResult Sema::ActOnNullStmt(SourceLocation SemiLoc, + SourceLocation LeadingEmptyMacroLoc) { + return Owned(new (Context) NullStmt(SemiLoc, LeadingEmptyMacroLoc)); } StmtResult Sema::ActOnDeclStmt(DeclGroupPtrTy dg, SourceLocation StartLoc, @@ -76,12 +78,6 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (!E) return; - if (E->isBoundMemberFunction(Context)) { - Diag(E->getLocStart(), diag::err_invalid_use_of_bound_member_func) - << E->getSourceRange(); - return; - } - SourceLocation Loc; SourceRange R1, R2; if (!E->isUnusedResultAWarning(Loc, R1, R2, Context)) @@ -245,11 +241,10 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, } // Otherwise, things are good. Fill in the declaration and return it. - TheDecl->setLocation(IdentLoc); - LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt); TheDecl->setStmt(LS); - TheDecl->setLocation(IdentLoc); + if (!TheDecl->isGnuLocal()) + TheDecl->setLocation(IdentLoc); return Owned(LS); } @@ -470,7 +465,10 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, GetTypeBeforeIntegralPromotion(CondExpr); // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. - UsualUnaryConversions(CondExpr); + ExprResult CondResult = UsualUnaryConversions(CondExpr); + if (CondResult.isInvalid()) + return StmtError(); + CondExpr = CondResult.take(); QualType CondType = CondExpr->getType(); SS->setCond(CondExpr); @@ -556,7 +554,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // If the LHS is not the same type as the condition, insert an implicit // cast. - ImpCastExprToType(Lo, CondType, CK_IntegralCast); + Lo = ImpCastExprToType(Lo, CondType, CK_IntegralCast).take(); CS->setLHS(Lo); // If this is a case range, remember it in CaseRanges, otherwise CaseVals. @@ -635,7 +633,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, // If the LHS is not the same type as the condition, insert an implicit // cast. - ImpCastExprToType(Hi, CondType, CK_IntegralCast); + Hi = ImpCastExprToType(Hi, CondType, CK_IntegralCast).take(); CR->setRHS(Hi); // If the low value is bigger than the high value, the case is empty. @@ -869,11 +867,13 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, Expr *Cond, SourceLocation CondRParen) { assert(Cond && "ActOnDoStmt(): missing expression"); - if (CheckBooleanCondition(Cond, DoLoc)) + ExprResult CondResult = CheckBooleanCondition(Cond, DoLoc); + if (CondResult.isInvalid() || CondResult.isInvalid()) return StmtError(); + Cond = CondResult.take(); CheckImplicitConversions(Cond, DoLoc); - ExprResult CondResult = MaybeCreateExprWithCleanups(Cond); + CondResult = MaybeCreateExprWithCleanups(Cond); if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.take(); @@ -974,7 +974,10 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, << FirstType << First->getSourceRange(); } if (Second && !Second->isTypeDependent()) { - DefaultFunctionArrayLvalueConversion(Second); + ExprResult Result = DefaultFunctionArrayLvalueConversion(Second); + if (Result.isInvalid()) + return StmtError(); + Second = Result.take(); QualType SecondType = Second->getType(); if (!SecondType->isObjCObjectPointerType()) Diag(ForLoc, diag::err_collection_expr_type) @@ -992,7 +995,8 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, Selector CSelector = Context.Selectors.getSelector(3, &KeyIdents[0]); if (ObjCInterfaceDecl *IDecl = OPT->getInterfaceDecl()) { if (!IDecl->isForwardDecl() && - !IDecl->lookupInstanceMethod(CSelector)) { + !IDecl->lookupInstanceMethod(CSelector) && + !LookupMethodInQualifiedType(CSelector, OPT, true)) { // Must further look into private implementation methods. if (!LookupPrivateInstanceMethod(CSelector, IDecl)) Diag(ForLoc, diag::warn_collection_expr_type) @@ -1005,6 +1009,389 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, ForLoc, RParenLoc)); } +namespace { + +enum BeginEndFunction { + BEF_begin, + BEF_end +}; + +/// Build a variable declaration for a for-range statement. +static VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, + QualType Type, const char *Name) { + DeclContext *DC = SemaRef.CurContext; + IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); + TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); + VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, + TInfo, SC_Auto, SC_None); + Decl->setImplicit(); + return Decl; +} + +/// Finish building a variable declaration for a for-range statement. +/// \return true if an error occurs. +static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, + SourceLocation Loc, int diag) { + // Deduce the type for the iterator variable now rather than leaving it to + // AddInitializerToDecl, so we can produce a more suitable diagnostic. + TypeSourceInfo *InitTSI = 0; + if (Init->getType()->isVoidType() || + !SemaRef.DeduceAutoType(Decl->getTypeSourceInfo(), Init, InitTSI)) + SemaRef.Diag(Loc, diag) << Init->getType(); + if (!InitTSI) { + Decl->setInvalidDecl(); + return true; + } + Decl->setTypeSourceInfo(InitTSI); + Decl->setType(InitTSI->getType()); + + SemaRef.AddInitializerToDecl(Decl, Init, /*DirectInit=*/false, + /*TypeMayContainAuto=*/false); + SemaRef.FinalizeDeclaration(Decl); + SemaRef.CurContext->addHiddenDecl(Decl); + return false; +} + +/// Produce a note indicating which begin/end function was implicitly called +/// by a C++0x for-range statement. This is often not obvious from the code, +/// nor from the diagnostics produced when analysing the implicit expressions +/// required in a for-range statement. +void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E, + BeginEndFunction BEF) { + CallExpr *CE = dyn_cast<CallExpr>(E); + if (!CE) + return; + FunctionDecl *D = dyn_cast<FunctionDecl>(CE->getCalleeDecl()); + if (!D) + return; + SourceLocation Loc = D->getLocation(); + + std::string Description; + bool IsTemplate = false; + if (FunctionTemplateDecl *FunTmpl = D->getPrimaryTemplate()) { + Description = SemaRef.getTemplateArgumentBindingsText( + FunTmpl->getTemplateParameters(), *D->getTemplateSpecializationArgs()); + IsTemplate = true; + } + + SemaRef.Diag(Loc, diag::note_for_range_begin_end) + << BEF << IsTemplate << Description << E->getType(); +} + +/// Build a call to 'begin' or 'end' for a C++0x for-range statement. If the +/// given LookupResult is non-empty, it is assumed to describe a member which +/// will be invoked. Otherwise, the function will be found via argument +/// dependent lookup. +static ExprResult BuildForRangeBeginEndCall(Sema &SemaRef, Scope *S, + SourceLocation Loc, + VarDecl *Decl, + BeginEndFunction BEF, + const DeclarationNameInfo &NameInfo, + LookupResult &MemberLookup, + Expr *Range) { + ExprResult CallExpr; + if (!MemberLookup.empty()) { + ExprResult MemberRef = + SemaRef.BuildMemberReferenceExpr(Range, Range->getType(), Loc, + /*IsPtr=*/false, CXXScopeSpec(), + /*Qualifier=*/0, MemberLookup, + /*TemplateArgs=*/0); + if (MemberRef.isInvalid()) + return ExprError(); + CallExpr = SemaRef.ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(), + Loc, 0); + if (CallExpr.isInvalid()) + return ExprError(); + } else { + UnresolvedSet<0> FoundNames; + // C++0x [stmt.ranged]p1: For the purposes of this name lookup, namespace + // std is an associated namespace. + UnresolvedLookupExpr *Fn = + UnresolvedLookupExpr::Create(SemaRef.Context, /*NamingClass=*/0, + NestedNameSpecifierLoc(), NameInfo, + /*NeedsADL=*/true, /*Overloaded=*/false, + FoundNames.begin(), FoundNames.end(), + /*LookInStdNamespace=*/true); + CallExpr = SemaRef.BuildOverloadedCallExpr(S, Fn, Fn, Loc, &Range, 1, Loc, + 0); + if (CallExpr.isInvalid()) { + SemaRef.Diag(Range->getLocStart(), diag::note_for_range_type) + << Range->getType(); + return ExprError(); + } + } + if (FinishForRangeVarDecl(SemaRef, Decl, CallExpr.get(), Loc, + diag::err_for_range_iter_deduction_failure)) { + NoteForRangeBeginEndFunction(SemaRef, CallExpr.get(), BEF); + return ExprError(); + } + return CallExpr; +} + +} + +/// ActOnCXXForRangeStmt - Check and build a C++0x for-range statement. +/// +/// C++0x [stmt.ranged]: +/// A range-based for statement is equivalent to +/// +/// { +/// auto && __range = range-init; +/// for ( auto __begin = begin-expr, +/// __end = end-expr; +/// __begin != __end; +/// ++__begin ) { +/// for-range-declaration = *__begin; +/// statement +/// } +/// } +/// +/// The body of the loop is not available yet, since it cannot be analysed until +/// we have determined the type of the for-range-declaration. +StmtResult +Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, SourceLocation LParenLoc, + Stmt *First, SourceLocation ColonLoc, Expr *Range, + SourceLocation RParenLoc) { + if (!First || !Range) + return StmtError(); + + DeclStmt *DS = dyn_cast<DeclStmt>(First); + assert(DS && "first part of for range not a decl stmt"); + + if (!DS->isSingleDecl()) { + Diag(DS->getStartLoc(), diag::err_type_defined_in_for_range); + return StmtError(); + } + if (DS->getSingleDecl()->isInvalidDecl()) + return StmtError(); + + if (DiagnoseUnexpandedParameterPack(Range, UPPC_Expression)) + return StmtError(); + + // Build auto && __range = range-init + SourceLocation RangeLoc = Range->getLocStart(); + VarDecl *RangeVar = BuildForRangeVarDecl(*this, RangeLoc, + Context.getAutoRRefDeductType(), + "__range"); + if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc, + diag::err_for_range_deduction_failure)) + return StmtError(); + + // Claim the type doesn't contain auto: we've already done the checking. + DeclGroupPtrTy RangeGroup = + BuildDeclaratorGroup((Decl**)&RangeVar, 1, /*TypeMayContainAuto=*/false); + StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc); + if (RangeDecl.isInvalid()) + return StmtError(); + + return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(), + /*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS, + RParenLoc); +} + +/// BuildCXXForRangeStmt - Build or instantiate a C++0x for-range statement. +StmtResult +Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, + Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond, + Expr *Inc, Stmt *LoopVarDecl, + SourceLocation RParenLoc) { + Scope *S = getCurScope(); + + DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl); + VarDecl *RangeVar = cast<VarDecl>(RangeDS->getSingleDecl()); + QualType RangeVarType = RangeVar->getType(); + + DeclStmt *LoopVarDS = cast<DeclStmt>(LoopVarDecl); + VarDecl *LoopVar = cast<VarDecl>(LoopVarDS->getSingleDecl()); + + StmtResult BeginEndDecl = BeginEnd; + ExprResult NotEqExpr = Cond, IncrExpr = Inc; + + if (!BeginEndDecl.get() && !RangeVarType->isDependentType()) { + SourceLocation RangeLoc = RangeVar->getLocation(); + + ExprResult RangeRef = BuildDeclRefExpr(RangeVar, + RangeVarType.getNonReferenceType(), + VK_LValue, ColonLoc); + if (RangeRef.isInvalid()) + return StmtError(); + + QualType AutoType = Context.getAutoDeductType(); + Expr *Range = RangeVar->getInit(); + if (!Range) + return StmtError(); + QualType RangeType = Range->getType(); + + if (RequireCompleteType(RangeLoc, RangeType, + PDiag(diag::err_for_range_incomplete_type))) + return StmtError(); + + // Build auto __begin = begin-expr, __end = end-expr. + VarDecl *BeginVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType, + "__begin"); + VarDecl *EndVar = BuildForRangeVarDecl(*this, ColonLoc, AutoType, + "__end"); + + // Build begin-expr and end-expr and attach to __begin and __end variables. + ExprResult BeginExpr, EndExpr; + if (const ArrayType *UnqAT = RangeType->getAsArrayTypeUnsafe()) { + // - if _RangeT is an array type, begin-expr and end-expr are __range and + // __range + __bound, respectively, where __bound is the array bound. If + // _RangeT is an array of unknown size or an array of incomplete type, + // the program is ill-formed; + + // begin-expr is __range. + BeginExpr = RangeRef; + if (FinishForRangeVarDecl(*this, BeginVar, RangeRef.get(), ColonLoc, + diag::err_for_range_iter_deduction_failure)) { + NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); + return StmtError(); + } + + // Find the array bound. + ExprResult BoundExpr; + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(UnqAT)) + BoundExpr = Owned(IntegerLiteral::Create(Context, CAT->getSize(), + Context.IntTy, RangeLoc)); + else if (const VariableArrayType *VAT = + dyn_cast<VariableArrayType>(UnqAT)) + BoundExpr = VAT->getSizeExpr(); + else { + // Can't be a DependentSizedArrayType or an IncompleteArrayType since + // UnqAT is not incomplete and Range is not type-dependent. + assert(0 && "Unexpected array type in for-range"); + return StmtError(); + } + + // end-expr is __range + __bound. + EndExpr = ActOnBinOp(S, ColonLoc, tok::plus, RangeRef.get(), + BoundExpr.get()); + if (EndExpr.isInvalid()) + return StmtError(); + if (FinishForRangeVarDecl(*this, EndVar, EndExpr.get(), ColonLoc, + diag::err_for_range_iter_deduction_failure)) { + NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end); + return StmtError(); + } + } else { + DeclarationNameInfo BeginNameInfo(&PP.getIdentifierTable().get("begin"), + ColonLoc); + DeclarationNameInfo EndNameInfo(&PP.getIdentifierTable().get("end"), + ColonLoc); + + LookupResult BeginMemberLookup(*this, BeginNameInfo, LookupMemberName); + LookupResult EndMemberLookup(*this, EndNameInfo, LookupMemberName); + + if (CXXRecordDecl *D = RangeType->getAsCXXRecordDecl()) { + // - if _RangeT is a class type, the unqualified-ids begin and end are + // looked up in the scope of class _RangeT as if by class member access + // lookup (3.4.5), and if either (or both) finds at least one + // declaration, begin-expr and end-expr are __range.begin() and + // __range.end(), respectively; + LookupQualifiedName(BeginMemberLookup, D); + LookupQualifiedName(EndMemberLookup, D); + + if (BeginMemberLookup.empty() != EndMemberLookup.empty()) { + Diag(ColonLoc, diag::err_for_range_member_begin_end_mismatch) + << RangeType << BeginMemberLookup.empty(); + return StmtError(); + } + } else { + // - otherwise, begin-expr and end-expr are begin(__range) and + // end(__range), respectively, where begin and end are looked up with + // argument-dependent lookup (3.4.2). For the purposes of this name + // lookup, namespace std is an associated namespace. + } + + BeginExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, BeginVar, + BEF_begin, BeginNameInfo, + BeginMemberLookup, RangeRef.get()); + if (BeginExpr.isInvalid()) + return StmtError(); + + EndExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, EndVar, + BEF_end, EndNameInfo, + EndMemberLookup, RangeRef.get()); + if (EndExpr.isInvalid()) + return StmtError(); + } + + // C++0x [decl.spec.auto]p6: BeginType and EndType must be the same. + QualType BeginType = BeginVar->getType(), EndType = EndVar->getType(); + if (!Context.hasSameType(BeginType, EndType)) { + Diag(RangeLoc, diag::err_for_range_begin_end_types_differ) + << BeginType << EndType; + NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); + NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end); + } + + Decl *BeginEndDecls[] = { BeginVar, EndVar }; + // Claim the type doesn't contain auto: we've already done the checking. + DeclGroupPtrTy BeginEndGroup = + BuildDeclaratorGroup(BeginEndDecls, 2, /*TypeMayContainAuto=*/false); + BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc); + + ExprResult BeginRef = BuildDeclRefExpr(BeginVar, + BeginType.getNonReferenceType(), + VK_LValue, ColonLoc); + ExprResult EndRef = BuildDeclRefExpr(EndVar, EndType.getNonReferenceType(), + VK_LValue, ColonLoc); + + // Build and check __begin != __end expression. + NotEqExpr = ActOnBinOp(S, ColonLoc, tok::exclaimequal, + BeginRef.get(), EndRef.get()); + NotEqExpr = ActOnBooleanCondition(S, ColonLoc, NotEqExpr.get()); + NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get()); + if (NotEqExpr.isInvalid()) { + NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); + if (!Context.hasSameType(BeginType, EndType)) + NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end); + return StmtError(); + } + + // Build and check ++__begin expression. + IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get()); + IncrExpr = ActOnFinishFullExpr(IncrExpr.get()); + if (IncrExpr.isInvalid()) { + NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); + return StmtError(); + } + + // Build and check *__begin expression. + ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get()); + if (DerefExpr.isInvalid()) { + NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); + return StmtError(); + } + + // Attach *__begin as initializer for VD. + if (!LoopVar->isInvalidDecl()) { + AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false, + /*TypeMayContainAuto=*/true); + if (LoopVar->isInvalidDecl()) + NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); + } + } + + return Owned(new (Context) CXXForRangeStmt(RangeDS, + cast_or_null<DeclStmt>(BeginEndDecl.get()), + NotEqExpr.take(), IncrExpr.take(), + LoopVarDS, /*Body=*/0, ForLoc, + ColonLoc, RParenLoc)); +} + +/// FinishCXXForRangeStmt - Attach the body to a C++0x for-range statement. +/// This is a separate step from ActOnCXXForRangeStmt because analysis of the +/// body cannot be performed until after the type of the range variable is +/// determined. +StmtResult Sema::FinishCXXForRangeStmt(Stmt *S, Stmt *B) { + if (!S || !B) + return StmtError(); + + cast<CXXForRangeStmt>(S)->setBody(B); + return S; +} + StmtResult Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, LabelDecl *TheDecl) { @@ -1020,8 +1407,12 @@ Sema::ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, if (!E->isTypeDependent()) { QualType ETy = E->getType(); QualType DestTy = Context.getPointerType(Context.VoidTy.withConst()); + ExprResult ExprRes = Owned(E); AssignConvertType ConvTy = - CheckSingleAssignmentConstraints(DestTy, E); + CheckSingleAssignmentConstraints(DestTy, ExprRes); + if (ExprRes.isInvalid()) + return StmtError(); + E = ExprRes.take(); if (DiagnoseAssignmentResult(ConvTy, StarLoc, DestTy, ETy, E, AA_Passing)) return StmtError(); } @@ -1188,7 +1579,10 @@ Sema::ActOnBlockReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (RetValExp) { // Don't call UsualUnaryConversions(), since we don't want to do // integer promotions here. - DefaultFunctionArrayLvalueConversion(RetValExp); + ExprResult Result = DefaultFunctionArrayLvalueConversion(RetValExp); + if (Result.isInvalid()) + return StmtError(); + RetValExp = Result.take(); CurBlock->ReturnType = RetValExp->getType(); if (BlockDeclRefExpr *CDRE = dyn_cast<BlockDeclRefExpr>(RetValExp)) { // We have to remove a 'const' added to copied-in variable which was @@ -1290,8 +1684,12 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (RetValExp->getType()->isVoidType()) D = diag::ext_return_has_void_expr; else { - IgnoredValueConversions(RetValExp); - ImpCastExprToType(RetValExp, Context.VoidTy, CK_ToVoid); + ExprResult Result = Owned(RetValExp); + Result = IgnoredValueConversions(Result.take()); + if (Result.isInvalid()) + return StmtError(); + RetValExp = Result.take(); + RetValExp = ImpCastExprToType(RetValExp, Context.VoidTy, CK_ToVoid).take(); } // return (some void expression); is legal in C++. @@ -1498,8 +1896,11 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, } } - DefaultFunctionArrayLvalueConversion(Exprs[i]); + ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); + if (Result.isInvalid()) + return StmtError(); + Exprs[i] = Result.take(); InputConstraintInfos.push_back(Info); } @@ -1614,7 +2015,7 @@ StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, if (InputDomain == AD_Int && OutputDomain == AD_Int && !isOperandMentioned(InputOpNo, Pieces) && InputExpr->isEvaluatable(Context)) { - ImpCastExprToType(InputExpr, OutTy, CK_IntegralCast); + InputExpr = ImpCastExprToType(InputExpr, OutTy, CK_IntegralCast).take(); Exprs[InputOpNo] = InputExpr; NS->setInputExpr(i, InputExpr); continue; @@ -1663,8 +2064,11 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) { if (Throw) { - DefaultLvalueConversion(Throw); + ExprResult Result = DefaultLvalueConversion(Throw); + if (Result.isInvalid()) + return StmtError(); + Throw = Result.take(); QualType ThrowType = Throw->getType(); // Make sure the expression type is an ObjC pointer or "void *". if (!ThrowType->isDependentType() && @@ -1703,8 +2107,11 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SyncExpr, Stmt *SyncBody) { getCurFunction()->setHasBranchProtectedScope(); - DefaultLvalueConversion(SyncExpr); + ExprResult Result = DefaultLvalueConversion(SyncExpr); + if (Result.isInvalid()) + return StmtError(); + SyncExpr = Result.take(); // Make sure the expression type is an ObjC pointer or "void *". if (!SyncExpr->getType()->isDependentType() && !SyncExpr->getType()->isObjCObjectPointerType()) { @@ -1766,7 +2173,7 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, MultiStmtArg RawHandlers) { // Don't report an error if 'try' is used in system headers. - if (!getLangOptions().Exceptions && + if (!getLangOptions().CXXExceptions && !getSourceManager().isInSystemHeader(TryLoc)) Diag(TryLoc, diag::err_exceptions_disabled) << "try"; @@ -1824,3 +2231,36 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, return Owned(CXXTryStmt::Create(Context, TryLoc, TryBlock, Handlers, NumHandlers)); } + +StmtResult +Sema::ActOnSEHTryBlock(bool IsCXXTry, + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler) { + assert(TryBlock && Handler); + + getCurFunction()->setHasBranchProtectedScope(); + + return Owned(SEHTryStmt::Create(Context,IsCXXTry,TryLoc,TryBlock,Handler)); +} + +StmtResult +Sema::ActOnSEHExceptBlock(SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block) { + assert(FilterExpr && Block); + + if(!FilterExpr->getType()->isIntegerType()) { + return StmtError(Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) << FilterExpr->getType()); + } + + return Owned(SEHExceptStmt::Create(Context,Loc,FilterExpr,Block)); +} + +StmtResult +Sema::ActOnSEHFinallyBlock(SourceLocation Loc, + Stmt *Block) { + assert(Block); + return Owned(SEHFinallyStmt::Create(Context,Loc,Block)); +} + diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp index f02dd25..ef09124 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp @@ -76,13 +76,13 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, return 0; } -static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) { +void Sema::FilterAcceptableTemplateNames(LookupResult &R) { // The set of class templates we've already seen. llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates; LookupResult::Filter filter = R.makeFilter(); while (filter.hasNext()) { NamedDecl *Orig = filter.next(); - NamedDecl *Repl = isAcceptableTemplateName(C, Orig); + NamedDecl *Repl = isAcceptableTemplateName(Context, Orig); if (!Repl) filter.erase(); else if (Repl != Orig) { @@ -114,6 +114,14 @@ static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) { filter.done(); } +bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R) { + for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) + if (isAcceptableTemplateName(Context, *I)) + return true; + + return false; +} + TemplateNameKind Sema::isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, @@ -289,7 +297,7 @@ void Sema::LookupTemplateName(LookupResult &Found, DeclarationName Name = Found.getLookupName(); if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx, false, CTC_CXXCasts)) { - FilterAcceptableTemplateNames(Context, Found); + FilterAcceptableTemplateNames(Found); if (!Found.empty()) { if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_template_suggest) @@ -311,7 +319,7 @@ void Sema::LookupTemplateName(LookupResult &Found, } } - FilterAcceptableTemplateNames(Context, Found); + FilterAcceptableTemplateNames(Found); if (Found.empty()) { if (isDependent) MemberOfUnknownSpecialization = true; @@ -327,7 +335,7 @@ void Sema::LookupTemplateName(LookupResult &Found, LookupResult FoundOuter(*this, Found.getLookupName(), Found.getNameLoc(), LookupOrdinaryName); LookupName(FoundOuter, S); - FilterAcceptableTemplateNames(Context, FoundOuter); + FilterAcceptableTemplateNames(FoundOuter); if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the @@ -368,9 +376,6 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs) { - NestedNameSpecifier *Qualifier - = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); - DeclContext *DC = getFunctionLevelDeclContext(); if (!isAddressOfOperand && @@ -386,7 +391,7 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, /*This*/ 0, ThisType, /*IsArrow*/ true, /*Op*/ SourceLocation(), - Qualifier, SS.getRange(), + SS.getWithLocInContext(Context), FirstQualifierInScope, NameInfo, TemplateArgs)); @@ -472,7 +477,8 @@ static TemplateArgumentLoc translateTemplateArgument(Sema &SemaRef, else TArg = Template; return TemplateArgumentLoc(TArg, - Arg.getScopeSpec().getRange(), + Arg.getScopeSpec().getWithLocInContext( + SemaRef.Context), Arg.getLocation(), Arg.getEllipsisLoc()); } @@ -497,7 +503,7 @@ void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn, /// (otherwise, "class" was used), and KeyLoc is the location of the /// "class" or "typename" keyword. ParamName is the name of the /// parameter (NULL indicates an unnamed template parameter) and -/// ParamName is the location of the parameter name (if any). +/// ParamNameLoc is the location of the parameter name (if any). /// If the type parameter has a default argument, it will be added /// later via ActOnTypeParameterDefault. Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, @@ -527,8 +533,9 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), - Loc, Depth, Position, ParamName, Typename, - Ellipsis); + KeyLoc, Loc, Depth, Position, ParamName, + Typename, Ellipsis); + Param->setAccess(AS_public); if (Invalid) Param->setInvalidDecl(); @@ -651,9 +658,12 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, bool IsParameterPack = D.hasEllipsis(); NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), + D.getSourceRange().getBegin(), D.getIdentifierLoc(), Depth, Position, ParamName, T, IsParameterPack, TInfo); + Param->setAccess(AS_public); + if (Invalid) Param->setInvalidDecl(); @@ -678,10 +688,12 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, return Param; TemplateArgument Converted; - if (CheckTemplateArgument(Param, Param->getType(), Default, Converted)) { + ExprResult DefaultRes = CheckTemplateArgument(Param, Param->getType(), Default, Converted); + if (DefaultRes.isInvalid()) { Param->setInvalidDecl(); return Param; } + Default = DefaultRes.take(); Param->setDefaultArgument(Default, false); } @@ -707,13 +719,13 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, // Construct the parameter object. bool IsParameterPack = EllipsisLoc.isValid(); - // FIXME: Pack-ness is dropped TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), NameLoc.isInvalid()? TmpLoc : NameLoc, Depth, Position, IsParameterPack, Name, Params); - + Param->setAccess(AS_public); + // If the template template parameter has a name, then link the identifier // into the scope and lookup mechanisms. if (Name) { @@ -791,7 +803,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, TemplateParameterList *TemplateParams, - AccessSpecifier AS) { + AccessSpecifier AS, + unsigned NumOuterTemplateParamLists, + TemplateParameterList** OuterTemplateParamLists) { assert(TemplateParams && TemplateParams->size() > 0 && "No template parameters"); assert(TUK != TUK_Reference && "Can only declare or define class templates"); @@ -961,11 +975,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } CXXRecordDecl *NewClass = - CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc, + CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name, PrevClassTemplate? PrevClassTemplate->getTemplatedDecl() : 0, /*DelayTypeCreation=*/true); SetNestedNameSpecifier(NewClass, SS); + if (NumOuterTemplateParamLists > 0) + NewClass->setTemplateParameterListsInfo(Context, + NumOuterTemplateParamLists, + OuterTemplateParamLists); ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, @@ -1089,7 +1107,8 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, /// \brief Check for unexpanded parameter packs within the template parameters /// of a template template parameter, recursively. -bool DiagnoseUnexpandedParameterPacks(Sema &S, TemplateTemplateParmDecl *TTP){ +static bool DiagnoseUnexpandedParameterPacks(Sema &S, + TemplateTemplateParmDecl *TTP) { TemplateParameterList *Params = TTP->getTemplateParameters(); for (unsigned I = 0, N = Params->size(); I != N; ++I) { NamedDecl *P = Params->getParam(I); @@ -1448,9 +1467,9 @@ DependsOnTemplateParameters(const TemplateSpecializationType *TemplateId, /// /// \returns the template parameter list, if any, that corresponds to the /// name that is preceded by the scope specifier @p SS. This template -/// parameter list may be have template parameters (if we're declaring a +/// parameter list may have template parameters (if we're declaring a /// template) or may have no template parameters (if we're declaring a -/// template specialization), or may be NULL (if we were's declaring isn't +/// template specialization), or may be NULL (if what we're declaring isn't /// itself a template). TemplateParameterList * Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, @@ -1631,14 +1650,42 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, return ParamLists[NumParamLists - 1]; } +void Sema::NoteAllFoundTemplates(TemplateName Name) { + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + Diag(Template->getLocation(), diag::note_template_declared_here) + << (isa<FunctionTemplateDecl>(Template)? 0 + : isa<ClassTemplateDecl>(Template)? 1 + : 2) + << Template->getDeclName(); + return; + } + + if (OverloadedTemplateStorage *OST = Name.getAsOverloadedTemplate()) { + for (OverloadedTemplateStorage::iterator I = OST->begin(), + IEnd = OST->end(); + I != IEnd; ++I) + Diag((*I)->getLocation(), diag::note_template_declared_here) + << 0 << (*I)->getDeclName(); + + return; + } +} + + QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, - const TemplateArgumentListInfo &TemplateArgs) { + TemplateArgumentListInfo &TemplateArgs) { TemplateDecl *Template = Name.getAsTemplateDecl(); - if (!Template) { - // The template name does not resolve to a template, so we just - // build a dependent template-id type. - return Context.getTemplateSpecializationType(Name, TemplateArgs); + if (!Template || isa<FunctionTemplateDecl>(Template)) { + // We might have a substituted template template parameter pack. If so, + // build a template specialization type for it. + if (Name.getAsSubstTemplateTemplateParmPack()) + return Context.getTemplateSpecializationType(Name, TemplateArgs); + + Diag(TemplateLoc, diag::err_template_id_not_a_type) + << Name; + NoteAllFoundTemplates(Name); + return QualType(); } // Check that the template argument list is well-formed for this @@ -1727,6 +1774,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, ClassTemplate->getTemplatedDecl()->getTagKind(), ClassTemplate->getDeclContext(), ClassTemplate->getLocation(), + ClassTemplate->getLocation(), ClassTemplate, Converted.data(), Converted.size(), 0); @@ -1746,77 +1794,148 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, } TypeResult -Sema::ActOnTemplateIdType(TemplateTy TemplateD, SourceLocation TemplateLoc, +Sema::ActOnTemplateIdType(CXXScopeSpec &SS, + TemplateTy TemplateD, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc) { + if (SS.isInvalid()) + return true; + TemplateName Template = TemplateD.getAsVal<TemplateName>(); // Translate the parser's template argument list in our AST format. TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { + QualType T = Context.getDependentTemplateSpecializationType(ETK_None, + DTN->getQualifier(), + DTN->getIdentifier(), + TemplateArgs); + + // Build type-source information. + TypeLocBuilder TLB; + DependentTemplateSpecializationTypeLoc SpecTL + = TLB.push<DependentTemplateSpecializationTypeLoc>(T); + SpecTL.setKeywordLoc(SourceLocation()); + SpecTL.setNameLoc(TemplateLoc); + SpecTL.setLAngleLoc(LAngleLoc); + SpecTL.setRAngleLoc(RAngleLoc); + SpecTL.setQualifierLoc(SS.getWithLocInContext(Context)); + for (unsigned I = 0, N = SpecTL.getNumArgs(); I != N; ++I) + SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); + return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); + } + QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); TemplateArgsIn.release(); if (Result.isNull()) return true; - TypeSourceInfo *DI = Context.CreateTypeSourceInfo(Result); - TemplateSpecializationTypeLoc TL - = cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc()); - TL.setTemplateNameLoc(TemplateLoc); - TL.setLAngleLoc(LAngleLoc); - TL.setRAngleLoc(RAngleLoc); - for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) - TL.setArgLocInfo(i, TemplateArgs[i].getLocInfo()); - - return CreateParsedType(Result, DI); + // Build type-source information. + TypeLocBuilder TLB; + TemplateSpecializationTypeLoc SpecTL + = TLB.push<TemplateSpecializationTypeLoc>(Result); + SpecTL.setTemplateNameLoc(TemplateLoc); + SpecTL.setLAngleLoc(LAngleLoc); + SpecTL.setRAngleLoc(RAngleLoc); + for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i) + SpecTL.setArgLocInfo(i, TemplateArgs[i].getLocInfo()); + + if (SS.isNotEmpty()) { + // Create an elaborated-type-specifier containing the nested-name-specifier. + Result = Context.getElaboratedType(ETK_None, SS.getScopeRep(), Result); + ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(Result); + ElabTL.setKeywordLoc(SourceLocation()); + ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); + } + + return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } -TypeResult Sema::ActOnTagTemplateIdType(CXXScopeSpec &SS, - TypeResult TypeResult, - TagUseKind TUK, +TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, TypeSpecifierType TagSpec, - SourceLocation TagLoc) { - if (TypeResult.isInvalid()) - return ::TypeResult(); - - TypeSourceInfo *DI; - QualType Type = GetTypeFromParser(TypeResult.get(), &DI); - - // Verify the tag specifier. + SourceLocation TagLoc, + CXXScopeSpec &SS, + TemplateTy TemplateD, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation RAngleLoc) { + TemplateName Template = TemplateD.getAsVal<TemplateName>(); + + // Translate the parser's template argument list in our AST format. + TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); + translateTemplateArguments(TemplateArgsIn, TemplateArgs); + + // Determine the tag kind TagTypeKind TagKind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); + ElaboratedTypeKeyword Keyword + = TypeWithKeyword::getKeywordForTagTypeKind(TagKind); - if (const RecordType *RT = Type->getAs<RecordType>()) { + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { + QualType T = Context.getDependentTemplateSpecializationType(Keyword, + DTN->getQualifier(), + DTN->getIdentifier(), + TemplateArgs); + + // Build type-source information. + TypeLocBuilder TLB; + DependentTemplateSpecializationTypeLoc SpecTL + = TLB.push<DependentTemplateSpecializationTypeLoc>(T); + SpecTL.setKeywordLoc(TagLoc); + SpecTL.setNameLoc(TemplateLoc); + SpecTL.setLAngleLoc(LAngleLoc); + SpecTL.setRAngleLoc(RAngleLoc); + SpecTL.setQualifierLoc(SS.getWithLocInContext(Context)); + for (unsigned I = 0, N = SpecTL.getNumArgs(); I != N; ++I) + SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); + return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); + } + + QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); + if (Result.isNull()) + return TypeResult(); + + // Check the tag kind + if (const RecordType *RT = Result->getAs<RecordType>()) { RecordDecl *D = RT->getDecl(); - + IdentifierInfo *Id = D->getIdentifier(); assert(Id && "templated class must have an identifier"); - + if (!isAcceptableTagRedeclaration(D, TagKind, TagLoc, *Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) - << Type + << Result << FixItHint::CreateReplacement(SourceRange(TagLoc), D->getKindName()); Diag(D->getLocation(), diag::note_previous_use); } } - - ElaboratedTypeKeyword Keyword - = TypeWithKeyword::getKeywordForTagTypeKind(TagKind); - QualType ElabType = Context.getElaboratedType(Keyword, /*NNS=*/0, Type); - - TypeSourceInfo *ElabDI = Context.CreateTypeSourceInfo(ElabType); - ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(ElabDI->getTypeLoc()); - TL.setKeywordLoc(TagLoc); - TL.setQualifierRange(SS.getRange()); - TL.getNamedTypeLoc().initializeFullCopy(DI->getTypeLoc()); - return CreateParsedType(ElabType, ElabDI); + + // Provide source-location information for the template specialization. + TypeLocBuilder TLB; + TemplateSpecializationTypeLoc SpecTL + = TLB.push<TemplateSpecializationTypeLoc>(Result); + SpecTL.setTemplateNameLoc(TemplateLoc); + SpecTL.setLAngleLoc(LAngleLoc); + SpecTL.setRAngleLoc(RAngleLoc); + for (unsigned i = 0, e = SpecTL.getNumArgs(); i != e; ++i) + SpecTL.setArgLocInfo(i, TemplateArgs[i].getLocInfo()); + + // Construct an elaborated type containing the nested-name-specifier (if any) + // and keyword. + Result = Context.getElaboratedType(Keyword, SS.getScopeRep(), Result); + ElaboratedTypeLoc ElabTL = TLB.push<ElaboratedTypeLoc>(Result); + ElabTL.setKeywordLoc(TagLoc); + ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); + return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, - LookupResult &R, - bool RequiresADL, + LookupResult &R, + bool RequiresADL, const TemplateArgumentListInfo &TemplateArgs) { // FIXME: Can we do any checking at this point? I guess we could check the // template arguments that we have against the template name, if the template @@ -1832,19 +1951,12 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, assert(!R.empty() && "empty lookup results when building templateid"); assert(!R.isAmbiguous() && "ambiguous lookup when building templateid"); - NestedNameSpecifier *Qualifier = 0; - SourceRange QualifierRange; - if (SS.isSet()) { - Qualifier = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); - QualifierRange = SS.getRange(); - } - // We don't want lookup warnings at this point. R.suppressDiagnostics(); UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(Context, R.getNamingClass(), - Qualifier, QualifierRange, + SS.getWithLocInContext(Context), R.getLookupNameInfo(), RequiresADL, TemplateArgs, R.begin(), R.end()); @@ -1935,7 +2047,8 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, MemberOfUnknownSpecialization); if (TNK == TNK_Non_template && LookupCtx->isDependentContext() && isa<CXXRecordDecl>(LookupCtx) && - cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) { + (!cast<CXXRecordDecl>(LookupCtx)->hasDefinition() || + cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases())) { // This is a dependent template. Handle it below. } else if (TNK == TNK_Non_template) { Diag(Name.getSourceRange().getBegin(), @@ -2043,7 +2156,6 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, /// /// \param Converted the list of template arguments provided for template /// parameters that precede \p Param in the template parameter list. -/// /// \returns the substituted template argument, or NULL if an error occurred. static TypeSourceInfo * SubstDefaultTemplateArgument(Sema &SemaRef, @@ -2140,6 +2252,9 @@ SubstDefaultTemplateArgument(Sema &SemaRef, /// \param Converted the list of template arguments provided for template /// parameters that precede \p Param in the template parameter list. /// +/// \param QualifierLoc Will be set to the nested-name-specifier (with +/// source-location information) that precedes the template name. +/// /// \returns the substituted template argument, or NULL if an error occurred. static TemplateName SubstDefaultTemplateArgument(Sema &SemaRef, @@ -2147,7 +2262,8 @@ SubstDefaultTemplateArgument(Sema &SemaRef, SourceLocation TemplateLoc, SourceLocation RAngleLoc, TemplateTemplateParmDecl *Param, - llvm::SmallVectorImpl<TemplateArgument> &Converted) { + llvm::SmallVectorImpl<TemplateArgument> &Converted, + NestedNameSpecifierLoc &QualifierLoc) { TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted.data(), Converted.size()); @@ -2159,7 +2275,16 @@ SubstDefaultTemplateArgument(Sema &SemaRef, Converted.size(), SourceRange(TemplateLoc, RAngleLoc)); - return SemaRef.SubstTemplateName( + // Substitute into the nested-name-specifier first, + QualifierLoc = Param->getDefaultArgument().getTemplateQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, + AllTemplateArgs); + if (!QualifierLoc) + return TemplateName(); + } + + return SemaRef.SubstTemplateName(QualifierLoc, Param->getDefaultArgument().getArgument().getAsTemplate(), Param->getDefaultArgument().getTemplateNameLoc(), AllTemplateArgs); @@ -2195,10 +2320,10 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, return TemplateArgumentLoc(); ExprResult Arg = SubstDefaultTemplateArgument(*this, Template, - TemplateLoc, - RAngleLoc, - NonTypeParm, - Converted); + TemplateLoc, + RAngleLoc, + NonTypeParm, + Converted); if (Arg.isInvalid()) return TemplateArgumentLoc(); @@ -2211,16 +2336,19 @@ Sema::SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, if (!TempTempParm->hasDefaultArgument()) return TemplateArgumentLoc(); + + NestedNameSpecifierLoc QualifierLoc; TemplateName TName = SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, TempTempParm, - Converted); + Converted, + QualifierLoc); if (TName.isNull()) return TemplateArgumentLoc(); return TemplateArgumentLoc(TemplateArgument(TName), - TempTempParm->getDefaultArgument().getTemplateQualifierRange(), + TempTempParm->getDefaultArgument().getTemplateQualifierLoc(), TempTempParm->getDefaultArgument().getTemplateNameLoc()); } @@ -2300,9 +2428,11 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return true; case TemplateArgument::Expression: { - Expr *E = Arg.getArgument().getAsExpr(); TemplateArgument Result; - if (CheckTemplateArgument(NTTP, NTTPType, E, Result, CTAK)) + ExprResult Res = + CheckTemplateArgument(NTTP, NTTPType, Arg.getArgument().getAsExpr(), + Result, CTAK); + if (Res.isInvalid()) return true; Converted.push_back(Result); @@ -2331,28 +2461,23 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, DeclarationNameInfo NameInfo(DTN->getIdentifier(), Arg.getTemplateNameLoc()); - // FIXME: TemplateArgumentLoc should store a NestedNameSpecifierLoc - // for the template name. CXXScopeSpec SS; - SS.MakeTrivial(Context, DTN->getQualifier(), - Arg.getTemplateQualifierRange()); - Expr *E = DependentScopeDeclRefExpr::Create(Context, + SS.Adopt(Arg.getTemplateQualifierLoc()); + ExprResult E = Owned(DependentScopeDeclRefExpr::Create(Context, SS.getWithLocInContext(Context), - NameInfo); + NameInfo)); // If we parsed the template argument as a pack expansion, create a // pack expansion expression. if (Arg.getArgument().getKind() == TemplateArgument::TemplateExpansion){ - ExprResult Expansion = ActOnPackExpansion(E, - Arg.getTemplateEllipsisLoc()); - if (Expansion.isInvalid()) + E = ActOnPackExpansion(E.take(), Arg.getTemplateEllipsisLoc()); + if (E.isInvalid()) return true; - - E = Expansion.get(); } TemplateArgument Result; - if (CheckTemplateArgument(NTTP, NTTPType, E, Result)) + E = CheckTemplateArgument(NTTP, NTTPType, E.take(), Result); + if (E.isInvalid()) return true; Converted.push_back(Result); @@ -2461,7 +2586,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, /// for specializing the given template. bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, - const TemplateArgumentListInfo &TemplateArgs, + TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, llvm::SmallVectorImpl<TemplateArgument> &Converted) { TemplateParameterList *Params = Template->getTemplateParameters(); @@ -2499,6 +2624,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // a template-id shall match the type and form specified for the // corresponding parameter declared by the template in its // template-parameter-list. + bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template); llvm::SmallVector<TemplateArgument, 2> ArgumentPack; TemplateParameterList::iterator Param = Params->begin(), ParamEnd = Params->end(); @@ -2604,17 +2730,18 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, break; } + NestedNameSpecifierLoc QualifierLoc; TemplateName Name = SubstDefaultTemplateArgument(*this, Template, TemplateLoc, RAngleLoc, TempParm, - Converted); + Converted, + QualifierLoc); if (Name.isNull()) return true; - Arg = TemplateArgumentLoc(TemplateArgument(Name), - TempParm->getDefaultArgument().getTemplateQualifierRange(), - TempParm->getDefaultArgument().getTemplateNameLoc()); + Arg = TemplateArgumentLoc(TemplateArgument(Name), QualifierLoc, + TempParm->getDefaultArgument().getTemplateNameLoc()); } // Introduce an instantiation record that describes where we are using @@ -2628,6 +2755,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, RAngleLoc, 0, Converted)) return true; + // Core issue 150 (assumed resolution): if this is a template template + // parameter, keep track of the default template arguments from the + // template definition. + if (isTemplateTemplateParameter) + TemplateArgs.addArgument(Arg); + // Move to the next template parameter and argument. ++Param; ++ArgIdx; @@ -2853,7 +2986,7 @@ bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { return true; } - if (!Tag->getDeclName() && !Tag->getTypedefForAnonDecl()) { + if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl()) { S.Diag(SR.getBegin(), diag::ext_template_arg_unnamed_type) << SR; S.Diag(Tag->getLocation(), diag::note_template_unnamed_type_here); return true; @@ -2961,13 +3094,25 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, SourceLocation AddrOpLoc; if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(Arg)) { if (UnOp->getOpcode() == UO_AddrOf) { + // Support &__uuidof(class_with_uuid) as a non-type template argument. + // Very common in Microsoft COM headers. + if (S.getLangOptions().Microsoft && + isa<CXXUuidofExpr>(UnOp->getSubExpr())) { + Converted = TemplateArgument(ArgIn); + return false; + } + DRE = dyn_cast<DeclRefExpr>(UnOp->getSubExpr()); AddressTaken = true; AddrOpLoc = UnOp->getOperatorLoc(); } - } else + } else { + if (S.getLangOptions().Microsoft && isa<CXXUuidofExpr>(Arg)) { + Converted = TemplateArgument(ArgIn); + return false; + } DRE = dyn_cast<DeclRefExpr>(Arg); - + } if (!DRE) { S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) << Arg->getSourceRange(); @@ -3266,15 +3411,14 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, /// non-type template parameter. /// /// This routine implements the semantics of C++ [temp.arg.nontype]. -/// It returns true if an error occurred, and false otherwise. \p +/// If an error occurred, it returns ExprError(); otherwise, it +/// returns the converted template argument. \p /// InstantiatedParamType is the type of the non-type template /// parameter after it has been instantiated. -/// -/// If no error was detected, Converted receives the converted template argument. -bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, - QualType InstantiatedParamType, Expr *&Arg, - TemplateArgument &Converted, - CheckTemplateArgumentKind CTAK) { +ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, + QualType InstantiatedParamType, Expr *Arg, + TemplateArgument &Converted, + CheckTemplateArgumentKind CTAK) { SourceLocation StartLoc = Arg->getSourceRange().getBegin(); // If either the parameter has a dependent type or the argument is @@ -3282,7 +3426,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) { // FIXME: Produce a cloned, canonical expression? Converted = TemplateArgument(Arg); - return false; + return Owned(Arg); } // C++ [temp.arg.nontype]p5: @@ -3312,12 +3456,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, diag::err_template_arg_not_integral_or_enumeral) << ArgType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); - return true; + return ExprError(); } else if (!Arg->isValueDependent() && !Arg->isIntegerConstantExpr(Value, Context, &NonConstantLoc)) { Diag(NonConstantLoc, diag::err_template_arg_not_ice) << ArgType << Arg->getSourceRange(); - return true; + return ExprError(); } // From here on out, all we care about are the unqualified forms @@ -3340,21 +3484,21 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch) << ArgType << ParamType; Diag(Param->getLocation(), diag::note_template_param_here); - return true; + return ExprError(); } else if (ParamType->isBooleanType()) { // This is an integral-to-boolean conversion. - ImpCastExprToType(Arg, ParamType, CK_IntegralToBoolean); + Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralToBoolean).take(); } else if (IsIntegralPromotion(Arg, ArgType, ParamType) || !ParamType->isEnumeralType()) { // This is an integral promotion or conversion. - ImpCastExprToType(Arg, ParamType, CK_IntegralCast); + Arg = ImpCastExprToType(Arg, ParamType, CK_IntegralCast).take(); } else { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); - return true; + return ExprError(); } QualType IntegerType = Context.getCanonicalType(ParamType); @@ -3404,13 +3548,13 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // The argument is value-dependent. Create a new // TemplateArgument with the converted expression. Converted = TemplateArgument(Arg); - return false; + return Owned(Arg); } Converted = TemplateArgument(Value, ParamType->isEnumeralType() ? ParamType : IntegerType); - return false; + return Owned(Arg); } DeclAccessPair FoundResult; // temporary for ResolveOverloadedFunction @@ -3422,7 +3566,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (ArgType->isNullPtrType() && (ParamType->isPointerType() || ParamType->isMemberPointerType())) { Converted = TemplateArgument((NamedDecl *)0); - return false; + return Owned(Arg); } // Handle pointer-to-function, reference-to-function, and @@ -3454,22 +3598,25 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, true, FoundResult)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) - return true; + return ExprError(); Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); ArgType = Arg->getType(); } else - return true; + return ExprError(); } - if (!ParamType->isMemberPointerType()) - return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, - Arg, Converted); + if (!ParamType->isMemberPointerType()) { + if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + ParamType, + Arg, Converted)) + return ExprError(); + return Owned(Arg); + } if (IsQualificationConversion(ArgType, ParamType.getNonReferenceType(), false)) { - ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)); + Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take(); } else if (!Context.hasSameUnqualifiedType(ArgType, ParamType.getNonReferenceType())) { // We can't perform this conversion. @@ -3477,10 +3624,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, diag::err_template_arg_not_convertible) << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); - return true; + return ExprError(); } - return CheckTemplateArgumentPointerToMember(Arg, Converted); + if (CheckTemplateArgumentPointerToMember(Arg, Converted)) + return ExprError(); + return Owned(Arg); } if (ParamType->isPointerType()) { @@ -3491,9 +3640,11 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamType->getPointeeType()->isIncompleteOrObjectType() && "Only object pointers allowed here"); - return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, - Arg, Converted); + if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + ParamType, + Arg, Converted)) + return ExprError(); + return Owned(Arg); } if (const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>()) { @@ -3512,17 +3663,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, true, FoundResult)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) - return true; + return ExprError(); Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); ArgType = Arg->getType(); } else - return true; + return ExprError(); } - return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, - ParamType, - Arg, Converted); + if (CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, + ParamType, + Arg, Converted)) + return ExprError(); + return Owned(Arg); } // -- For a non-type template-parameter of type pointer to data @@ -3532,17 +3685,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (Context.hasSameUnqualifiedType(ParamType, ArgType)) { // Types match exactly: nothing more to do here. } else if (IsQualificationConversion(ArgType, ParamType, false)) { - ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)); + Arg = ImpCastExprToType(Arg, ParamType, CK_NoOp, CastCategory(Arg)).take(); } else { // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); - return true; + return ExprError(); } - return CheckTemplateArgumentPointerToMember(Arg, Converted); + if (CheckTemplateArgumentPointerToMember(Arg, Converted)) + return ExprError(); + return Owned(Arg); } /// \brief Check a template argument against its corresponding @@ -3636,11 +3791,8 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, // the element type on the parameter could be more qualified than the // element type in the expression we constructed. if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(), - ParamType.getUnqualifiedType(), false)) { - Expr *RefE = RefExpr.takeAs<Expr>(); - ImpCastExprToType(RefE, ParamType.getUnqualifiedType(), CK_NoOp); - RefExpr = Owned(RefE); - } + ParamType.getUnqualifiedType(), false)) + RefExpr = ImpCastExprToType(RefExpr.take(), ParamType.getUnqualifiedType(), CK_NoOp); assert(!RefExpr.isInvalid() && Context.hasSameType(((Expr*) RefExpr.get())->getType(), @@ -3659,12 +3811,9 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, if (T->isFunctionType() || T->isArrayType()) { // Decay functions and arrays. - Expr *RefE = (Expr *)RefExpr.get(); - DefaultFunctionArrayConversion(RefE); - if (RefE != RefExpr.get()) { - RefExpr.release(); - RefExpr = Owned(RefE); - } + RefExpr = DefaultFunctionArrayConversion(RefExpr.take()); + if (RefExpr.isInvalid()) + return ExprError(); return move(RefExpr); } @@ -3703,18 +3852,18 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, if (T->isCharType() || T->isWideCharType()) return Owned(new (Context) CharacterLiteral( Arg.getAsIntegral()->getZExtValue(), - T->isWideCharType(), - T, - Loc)); + T->isWideCharType(), T, Loc)); if (T->isBooleanType()) return Owned(new (Context) CXXBoolLiteralExpr( Arg.getAsIntegral()->getBoolValue(), - T, - Loc)); + T, Loc)); + // If this is an enum type that we're instantiating, we need to use an integer + // type the same size as the enumerator. We don't want to build an + // IntegerLiteral with enum type. QualType BT; if (const EnumType *ET = T->getAs<EnumType>()) - BT = ET->getDecl()->getPromotionType(); + BT = ET->getDecl()->getIntegerType(); else BT = T; @@ -3722,10 +3871,9 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, if (T->isEnumeralType()) { // FIXME: This is a hack. We need a better way to handle substituted // non-type template parameters. - E = CStyleCastExpr::Create(Context, T, VK_RValue, CK_IntegralCast, - E, 0, - Context.getTrivialTypeSourceInfo(T, Loc), - Loc, Loc); + E = CStyleCastExpr::Create(Context, T, VK_RValue, CK_IntegralCast, E, 0, + Context.getTrivialTypeSourceInfo(T, Loc), + Loc, Loc); } return Owned(E); @@ -4245,7 +4393,7 @@ static NamedDecl *getPreviousDecl(NamedDecl *ND) { return FD->getPreviousDeclaration(); if (TagDecl *TD = dyn_cast<TagDecl>(ND)) return TD->getPreviousDeclaration(); - if (TypedefDecl *TD = dyn_cast<TypedefDecl>(ND)) + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(ND)) return TD->getPreviousDeclaration(); if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(ND)) return FTD->getPreviousDeclaration(); @@ -4268,6 +4416,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, MultiTemplateParamsArg TemplateParameterLists) { assert(TUK != TUK_Reference && "References are not specializations"); + // NOTE: KWLoc is the location of the tag keyword. This will instead + // store the location of the outermost template keyword in the declaration. + SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0 + ? TemplateParameterLists.get()[0]->getTemplateLoc() : SourceLocation(); + // Find the class template we're specializing TemplateName Name = TemplateD.getAsVal<TemplateName>(); ClassTemplateDecl *ClassTemplate @@ -4298,10 +4451,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (Invalid) return true; - unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size(); - if (TemplateParams) - --NumMatchedTemplateParamLists; - if (TemplateParams && TemplateParams->size() > 0) { isPartialSpecialization = true; @@ -4443,10 +4592,15 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Since the only prior class template specialization with these // arguments was referenced but not declared, or we're only // referencing this specialization as a friend, reuse that - // declaration node as our own, updating its source location to - // reflect our new declaration. + // declaration node as our own, updating its source location and + // the list of outer template parameters to reflect our new declaration. Specialization = PrevDecl; Specialization->setLocation(TemplateNameLoc); + if (TemplateParameterLists.size() > 0) { + Specialization->setTemplateParameterListsInfo(Context, + TemplateParameterLists.size(), + (TemplateParameterList**) TemplateParameterLists.release()); + } PrevDecl = 0; CanonType = Context.getTypeDeclType(Specialization); } else if (isPartialSpecialization) { @@ -4471,7 +4625,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateNameLoc, Attr, TemplateParams, - AS_none); + AS_none, + TemplateParameterLists.size() - 1, + (TemplateParameterList**) TemplateParameterLists.release()); } // Create a new class template partial specialization declaration node. @@ -4482,7 +4638,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, ClassTemplatePartialSpecializationDecl *Partial = ClassTemplatePartialSpecializationDecl::Create(Context, Kind, ClassTemplate->getDeclContext(), - TemplateNameLoc, + KWLoc, TemplateNameLoc, TemplateParams, ClassTemplate, Converted.data(), @@ -4492,9 +4648,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, PrevPartial, SequenceNumber); SetNestedNameSpecifier(Partial, SS); - if (NumMatchedTemplateParamLists > 0 && SS.isSet()) { + if (TemplateParameterLists.size() > 1 && SS.isSet()) { Partial->setTemplateParameterListsInfo(Context, - NumMatchedTemplateParamLists, + TemplateParameterLists.size() - 1, (TemplateParameterList**) TemplateParameterLists.release()); } @@ -4545,15 +4701,15 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Specialization = ClassTemplateSpecializationDecl::Create(Context, Kind, ClassTemplate->getDeclContext(), - TemplateNameLoc, + KWLoc, TemplateNameLoc, ClassTemplate, Converted.data(), Converted.size(), PrevDecl); SetNestedNameSpecifier(Specialization, SS); - if (NumMatchedTemplateParamLists > 0 && SS.isSet()) { + if (TemplateParameterLists.size() > 0) { Specialization->setTemplateParameterListsInfo(Context, - NumMatchedTemplateParamLists, + TemplateParameterLists.size(), (TemplateParameterList**) TemplateParameterLists.release()); } @@ -4623,8 +4779,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateArgs, CanonType); if (TUK != TUK_Friend) { Specialization->setTypeAsWritten(WrittenTy); - if (TemplateParams) - Specialization->setTemplateKeywordLoc(TemplateParams->getTemplateLoc()); + Specialization->setTemplateKeywordLoc(TemplateKWLoc); } TemplateArgsIn.release(); @@ -4927,7 +5082,7 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, /// this function specialization. bool Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous) { // The set of function template specializations that could match this // explicit function template specialization. @@ -4983,7 +5138,17 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Ignore access information; it doesn't figure into redeclaration checking. FunctionDecl *Specialization = cast<FunctionDecl>(*Result); - Specialization->setLocation(FD->getLocation()); + + FunctionTemplateSpecializationInfo *SpecInfo + = Specialization->getTemplateSpecializationInfo(); + assert(SpecInfo && "Function template specialization info missing?"); + { + // Note: do not overwrite location info if previous template + // specialization kind was explicit. + TemplateSpecializationKind TSK = SpecInfo->getTemplateSpecializationKind(); + if (TSK == TSK_Undeclared || TSK == TSK_ImplicitInstantiation) + Specialization->setLocation(FD->getLocation()); + } // FIXME: Check if the prior specialization has a point of instantiation. // If so, we have run afoul of . @@ -5006,10 +5171,6 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // before the first use of that specialization that would cause an implicit // instantiation to take place, in every translation unit in which such a // use occurs; no diagnostic is required. - FunctionTemplateSpecializationInfo *SpecInfo - = Specialization->getTemplateSpecializationInfo(); - assert(SpecInfo && "Function template specialization info missing?"); - bool HasNoEffect = false; if (!isFriend && CheckSpecializationInstantiationRedecl(FD->getLocation(), @@ -5402,7 +5563,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization = ClassTemplateSpecializationDecl::Create(Context, Kind, ClassTemplate->getDeclContext(), - TemplateNameLoc, + KWLoc, TemplateNameLoc, ClassTemplate, Converted.data(), Converted.size(), @@ -5883,26 +6044,34 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, return true; } + // Create the resulting type. ElaboratedTypeKeyword Kwd = TypeWithKeyword::getKeywordForTagTypeKind(Kind); - return ParsedType::make(Context.getDependentNameType(Kwd, NNS, Name)); + QualType Result = Context.getDependentNameType(Kwd, NNS, Name); + + // Create type-source location information for this type. + TypeLocBuilder TLB; + DependentNameTypeLoc TL = TLB.push<DependentNameTypeLoc>(Result); + TL.setKeywordLoc(TagLoc); + TL.setQualifierLoc(SS.getWithLocInContext(Context)); + TL.setNameLoc(NameLoc); + return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } TypeResult Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc) { - NestedNameSpecifier *NNS - = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - if (!NNS) + if (SS.isInvalid()) return true; - + if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() && !getLangOptions().CPlusPlus0x) Diag(TypenameLoc, diag::ext_typename_outside_of_template) << FixItHint::CreateRemoval(TypenameLoc); - QualType T = CheckTypenameType(ETK_Typename, NNS, II, - TypenameLoc, SS.getRange(), IdLoc); + NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); + QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None, + TypenameLoc, QualifierLoc, II, IdLoc); if (T.isNull()) return true; @@ -5910,12 +6079,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, if (isa<DependentNameType>(T)) { DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); TL.setKeywordLoc(TypenameLoc); - TL.setQualifierRange(SS.getRange()); + TL.setQualifierLoc(QualifierLoc); TL.setNameLoc(IdLoc); } else { ElaboratedTypeLoc TL = cast<ElaboratedTypeLoc>(TSI->getTypeLoc()); TL.setKeywordLoc(TypenameLoc); - TL.setQualifierRange(SS.getRange()); + TL.setQualifierLoc(QualifierLoc); cast<TypeSpecTypeLoc>(TL.getNamedTypeLoc()).setNameLoc(IdLoc); } @@ -5923,91 +6092,94 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, } TypeResult -Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, - const CXXScopeSpec &SS, SourceLocation TemplateLoc, - ParsedType Ty) { +Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, + SourceLocation TemplateLoc, + TemplateTy TemplateIn, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation RAngleLoc) { if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() && !getLangOptions().CPlusPlus0x) Diag(TypenameLoc, diag::ext_typename_outside_of_template) - << FixItHint::CreateRemoval(TypenameLoc); - - TypeSourceInfo *InnerTSI = 0; - QualType T = GetTypeFromParser(Ty, &InnerTSI); - - assert(isa<TemplateSpecializationType>(T) && - "Expected a template specialization type"); - - if (computeDeclContext(SS, false)) { - // If we can compute a declaration context, then the "typename" - // keyword was superfluous. Just build an ElaboratedType to keep - // track of the nested-name-specifier. - - // Push the inner type, preserving its source locations if possible. + << FixItHint::CreateRemoval(TypenameLoc); + + // Translate the parser's template argument list in our AST format. + TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); + translateTemplateArguments(TemplateArgsIn, TemplateArgs); + + TemplateName Template = TemplateIn.get(); + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { + // Construct a dependent template specialization type. + assert(DTN && "dependent template has non-dependent name?"); + assert(DTN->getQualifier() + == static_cast<NestedNameSpecifier*>(SS.getScopeRep())); + QualType T = Context.getDependentTemplateSpecializationType(ETK_Typename, + DTN->getQualifier(), + DTN->getIdentifier(), + TemplateArgs); + + // Create source-location information for this type. TypeLocBuilder Builder; - if (InnerTSI) - Builder.pushFullCopy(InnerTSI->getTypeLoc()); - else - Builder.push<TemplateSpecializationTypeLoc>(T).initialize(Context, - TemplateLoc); - - /* Note: NNS already embedded in template specialization type T. */ - T = Context.getElaboratedType(ETK_Typename, /*NNS=*/0, T); - ElaboratedTypeLoc TL = Builder.push<ElaboratedTypeLoc>(T); - TL.setKeywordLoc(TypenameLoc); - TL.setQualifierRange(SS.getRange()); - - TypeSourceInfo *TSI = Builder.getTypeSourceInfo(Context, T); - return CreateParsedType(T, TSI); - } - - // TODO: it's really silly that we make a template specialization - // type earlier only to drop it again here. - const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T); - DependentTemplateName *DTN = - TST->getTemplateName().getAsDependentTemplateName(); - assert(DTN && "dependent template has non-dependent name?"); - assert(DTN->getQualifier() - == static_cast<NestedNameSpecifier*>(SS.getScopeRep())); - T = Context.getDependentTemplateSpecializationType(ETK_Typename, - DTN->getQualifier(), - DTN->getIdentifier(), - TST->getNumArgs(), - TST->getArgs()); - TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); - DependentTemplateSpecializationTypeLoc TL = - cast<DependentTemplateSpecializationTypeLoc>(TSI->getTypeLoc()); - if (InnerTSI) { - TemplateSpecializationTypeLoc TSTL = - cast<TemplateSpecializationTypeLoc>(InnerTSI->getTypeLoc()); - TL.setLAngleLoc(TSTL.getLAngleLoc()); - TL.setRAngleLoc(TSTL.getRAngleLoc()); - for (unsigned I = 0, E = TST->getNumArgs(); I != E; ++I) - TL.setArgLocInfo(I, TSTL.getArgLocInfo(I)); - } else { - // FIXME: Poor source-location information here. - TL.initializeLocal(Context, TemplateLoc); + DependentTemplateSpecializationTypeLoc SpecTL + = Builder.push<DependentTemplateSpecializationTypeLoc>(T); + SpecTL.setLAngleLoc(LAngleLoc); + SpecTL.setRAngleLoc(RAngleLoc); + SpecTL.setKeywordLoc(TypenameLoc); + SpecTL.setQualifierLoc(SS.getWithLocInContext(Context)); + SpecTL.setNameLoc(TemplateNameLoc); + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) + SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); + return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } + + QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); + if (T.isNull()) + return true; + + // Provide source-location information for the template specialization + // type. + TypeLocBuilder Builder; + TemplateSpecializationTypeLoc SpecTL + = Builder.push<TemplateSpecializationTypeLoc>(T); + + // FIXME: No place to set the location of the 'template' keyword! + SpecTL.setLAngleLoc(LAngleLoc); + SpecTL.setRAngleLoc(RAngleLoc); + SpecTL.setTemplateNameLoc(TemplateNameLoc); + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) + SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); + + T = Context.getElaboratedType(ETK_Typename, SS.getScopeRep(), T); + ElaboratedTypeLoc TL = Builder.push<ElaboratedTypeLoc>(T); TL.setKeywordLoc(TypenameLoc); - TL.setQualifierRange(SS.getRange()); + TL.setQualifierLoc(SS.getWithLocInContext(Context)); + + TypeSourceInfo *TSI = Builder.getTypeSourceInfo(Context, T); return CreateParsedType(T, TSI); } + /// \brief Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType -Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, const IdentifierInfo &II, - SourceLocation KeywordLoc, SourceRange NNSRange, +Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, + SourceLocation KeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo &II, SourceLocation IILoc) { CXXScopeSpec SS; - SS.MakeTrivial(Context, NNS, NNSRange); + SS.Adopt(QualifierLoc); DeclContext *Ctx = computeDeclContext(SS); if (!Ctx) { // If the nested-name-specifier is dependent and couldn't be // resolved to a type, build a typename type. - assert(NNS->isDependent()); - return Context.getDependentNameType(Keyword, NNS, &II); + assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); + return Context.getDependentNameType(Keyword, + QualifierLoc.getNestedNameSpecifier(), + &II); } // If the nested-name-specifier refers to the current instantiation, @@ -6032,7 +6204,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, case LookupResult::FoundUnresolvedValue: { // We found a using declaration that is a value. Most likely, the using // declaration itself is meant to have the 'typename' keyword. - SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : NNSRange.getBegin(), + SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : SS.getBeginLoc(), IILoc); Diag(IILoc, diag::err_typename_refers_to_using_value_decl) << Name << Ctx << FullRange; @@ -6048,13 +6220,16 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, case LookupResult::NotFoundInCurrentInstantiation: // Okay, it's a member of an unknown instantiation. - return Context.getDependentNameType(Keyword, NNS, &II); + return Context.getDependentNameType(Keyword, + QualifierLoc.getNestedNameSpecifier(), + &II); case LookupResult::Found: if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { // We found a type. Build an ElaboratedType, since the // typename-specifier was just sugar. - return Context.getElaboratedType(ETK_Typename, NNS, + return Context.getElaboratedType(ETK_Typename, + QualifierLoc.getNestedNameSpecifier(), Context.getTypeDeclType(Type)); } @@ -6077,7 +6252,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // If we get here, it's because name lookup did not find a // type. Emit an appropriate diagnostic and return an error. - SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : NNSRange.getBegin(), + SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : SS.getBeginLoc(), IILoc); Diag(IILoc, DiagID) << FullRange << Name << Ctx; if (Referenced) @@ -6225,3 +6400,24 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, Out << ']'; return Out.str(); } + +void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, bool Flag) { + if (!FD) + return; + FD->setLateTemplateParsed(Flag); +} + +bool Sema::IsInsideALocalClassWithinATemplateFunction() { + DeclContext *DC = CurContext; + + while (DC) { + if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) { + const FunctionDecl *FD = RD->isLocalClass(); + return (FD && FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate); + } else if (DC->isTranslationUnit() || DC->isNamespace()) + return false; + + DC = DC->getParent(); + } + return false; +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp index 139fafb..235af04 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -800,6 +800,32 @@ DeduceTemplateArguments(Sema &S, return Sema::TDK_Success; } +/// \brief Determine whether the parameter has qualifiers that are either +/// inconsistent with or a superset of the argument's qualifiers. +static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType, + QualType ArgType) { + Qualifiers ParamQs = ParamType.getQualifiers(); + Qualifiers ArgQs = ArgType.getQualifiers(); + + if (ParamQs == ArgQs) + return false; + + // Mismatched (but not missing) Objective-C GC attributes. + if (ParamQs.getObjCGCAttr() != ArgQs.getObjCGCAttr() && + ParamQs.hasObjCGCAttr()) + return true; + + // Mismatched (but not missing) address spaces. + if (ParamQs.getAddressSpace() != ArgQs.getAddressSpace() && + ParamQs.hasAddressSpace()) + return true; + + // CVR qualifier superset. + return (ParamQs.getCVRQualifiers() != ArgQs.getCVRQualifiers()) && + ((ParamQs.getCVRQualifiers() | ArgQs.getCVRQualifiers()) + == ParamQs.getCVRQualifiers()); +} + /// \brief Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -875,9 +901,12 @@ DeduceTemplateArguments(Sema &S, Comparison.ParamIsRvalueRef = ParamRef->getAs<RValueReferenceType>(); Comparison.ArgIsRvalueRef = ArgRef->getAs<RValueReferenceType>(); Comparison.Qualifiers = NeitherMoreQualified; - if (Param.isMoreQualifiedThan(Arg)) + + Qualifiers ParamQuals = Param.getQualifiers(); + Qualifiers ArgQuals = Arg.getQualifiers(); + if (ParamQuals.isStrictSupersetOf(ArgQuals)) Comparison.Qualifiers = ParamMoreQualified; - else if (Arg.isMoreQualifiedThan(Param)) + else if (ArgQuals.isStrictSupersetOf(ParamQuals)) Comparison.Qualifiers = ArgMoreQualified; RefParamComparisons->push_back(Comparison); } @@ -949,7 +978,6 @@ DeduceTemplateArguments(Sema &S, // If the argument type is an array type, move the qualifiers up to the // top level, so they can be matched with the qualifiers on the parameter. - // FIXME: address spaces, ObjC GC qualifiers if (isa<ArrayType>(Arg)) { Qualifiers Quals; Arg = S.Context.getUnqualifiedArrayType(Arg, Quals); @@ -961,7 +989,8 @@ DeduceTemplateArguments(Sema &S, // The argument type can not be less qualified than the parameter // type. - if (Param.isMoreQualifiedThan(Arg) && !(TDF & TDF_IgnoreQualifiers)) { + if (!(TDF & TDF_IgnoreQualifiers) && + hasInconsistentOrSupersetQualifiersOf(Param, Arg)) { Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); Info.FirstArg = TemplateArgument(Param); Info.SecondArg = TemplateArgument(Arg); @@ -972,8 +1001,18 @@ DeduceTemplateArguments(Sema &S, assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function"); QualType DeducedType = Arg; - // local manipulation is okay because it's canonical - DeducedType.removeLocalCVRQualifiers(Param.getCVRQualifiers()); + // Remove any qualifiers on the parameter from the deduced type. + // We checked the qualifiers for consistency above. + Qualifiers DeducedQs = DeducedType.getQualifiers(); + Qualifiers ParamQs = Param.getQualifiers(); + DeducedQs.removeCVRQualifiers(ParamQs.getCVRQualifiers()); + if (ParamQs.hasObjCGCAttr()) + DeducedQs.removeObjCGCAttr(); + if (ParamQs.hasAddressSpace()) + DeducedQs.removeAddressSpace(); + DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), + DeducedQs); + if (RecanonicalizeArg) DeducedType = S.Context.getCanonicalType(DeducedType); @@ -1006,7 +1045,7 @@ DeduceTemplateArguments(Sema &S, // Check the cv-qualifiers on the parameter and argument types. if (!(TDF & TDF_IgnoreQualifiers)) { if (TDF & TDF_ParamWithReferenceType) { - if (Param.isMoreQualifiedThan(Arg)) + if (hasInconsistentOrSupersetQualifiersOf(Param, Arg)) return Sema::TDK_NonDeducedMismatch; } else if (!IsPossiblyOpaquelyQualifiedType(Param)) { if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) @@ -1728,11 +1767,24 @@ getTrivialTemplateArgumentLoc(Sema &S, return TemplateArgumentLoc(TemplateArgument(E), E); } - case TemplateArgument::Template: - return TemplateArgumentLoc(Arg, SourceRange(), Loc); - - case TemplateArgument::TemplateExpansion: - return TemplateArgumentLoc(Arg, SourceRange(), Loc, Loc); + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { + NestedNameSpecifierLocBuilder Builder; + TemplateName Template = Arg.getAsTemplate(); + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) + Builder.MakeTrivial(S.Context, DTN->getQualifier(), Loc); + else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + Builder.MakeTrivial(S.Context, QTN->getQualifier(), Loc); + + if (Arg.getKind() == TemplateArgument::Template) + return TemplateArgumentLoc(Arg, + Builder.getWithLocInContext(S.Context), + Loc); + + + return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(S.Context), + Loc, Loc); + } case TemplateArgument::Expression: return TemplateArgumentLoc(Arg, Arg.getAsExpr()); @@ -1996,7 +2048,7 @@ static bool isSimpleTemplateIdType(QualType T) { Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentListInfo &ExplicitTemplateArgs, + TemplateArgumentListInfo &ExplicitTemplateArgs, llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced, llvm::SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType, @@ -2442,8 +2494,8 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, // C++0x [temp.deduct.call]p3: // If P is a cv-qualified type, the top level cv-qualifiers of P's type // are ignored for type deduction. - if (ParamType.getCVRQualifiers()) - ParamType = ParamType.getLocalUnqualifiedType(); + if (ParamType.hasQualifiers()) + ParamType = ParamType.getUnqualifiedType(); const ReferenceType *ParamRefType = ParamType->getAs<ReferenceType>(); if (ParamRefType) { QualType PointeeType = ParamRefType->getPointeeType(); @@ -2499,8 +2551,7 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, else { // - If A is a cv-qualified type, the top level cv-qualifiers of A's // type are ignored for type deduction. - if (ArgType.getCVRQualifiers()) - ArgType = ArgType.getUnqualifiedType(); + ArgType = ArgType.getUnqualifiedType(); } } @@ -2563,7 +2614,7 @@ static bool AdjustFunctionParmAndArgTypesForDeduction(Sema &S, /// \returns the result of template argument deduction. Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + TemplateArgumentListInfo *ExplicitTemplateArgs, Expr **Args, unsigned NumArgs, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { @@ -2761,7 +2812,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, /// \returns the result of template argument deduction. Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { @@ -2832,18 +2883,18 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType P = Context.getCanonicalType(FromType); QualType A = Context.getCanonicalType(ToType); - // C++0x [temp.deduct.conv]p3: + // C++0x [temp.deduct.conv]p2: // If P is a reference type, the type referred to by P is used for // type deduction. if (const ReferenceType *PRef = P->getAs<ReferenceType>()) P = PRef->getPointeeType(); - // C++0x [temp.deduct.conv]p3: - // If A is a reference type, the type referred to by A is used + // C++0x [temp.deduct.conv]p4: + // [...] If A is a reference type, the type referred to by A is used // for type deduction. if (const ReferenceType *ARef = A->getAs<ReferenceType>()) - A = ARef->getPointeeType(); - // C++ [temp.deduct.conv]p2: + A = ARef->getPointeeType().getUnqualifiedType(); + // C++ [temp.deduct.conv]p3: // // If A is not a reference type: else { @@ -2864,9 +2915,10 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, else P = P.getUnqualifiedType(); - // C++0x [temp.deduct.conv]p3: + // C++0x [temp.deduct.conv]p4: // If A is a cv-qualified type, the top level cv-qualifiers of A's - // type are ignored for type deduction. + // type are ignored for type deduction. If A is a reference type, the type + // referred to by A is used for type deduction. A = A.getUnqualifiedType(); } @@ -2941,7 +2993,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, /// \returns the result of template argument deduction. Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - const TemplateArgumentListInfo *ExplicitTemplateArgs, + TemplateArgumentListInfo *ExplicitTemplateArgs, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, @@ -2989,11 +3041,14 @@ namespace { /// /// \param Result if type deduction was successful, this will be set to the /// deduced type. This may still contain undeduced autos if the type is -/// dependent. +/// dependent. This will be set to null if deduction succeeded, but auto +/// substitution failed; the appropriate diagnostic will already have been +/// produced in that case. /// /// \returns true if deduction succeeded, false if it failed. bool -Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) { +Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *Init, + TypeSourceInfo *&Result) { if (Init->isTypeDependent()) { Result = Type; return true; @@ -3004,14 +3059,18 @@ Sema::DeduceAutoType(QualType Type, Expr *Init, QualType &Result) { LocalInstantiationScope InstScope(*this); // Build template<class TemplParam> void Func(FuncParam); - QualType TemplArg = Context.getTemplateTypeParmType(0, 0, false); - TemplateTypeParmDecl TemplParam(0, Loc, 0, false, TemplArg, false); - NamedDecl *TemplParamPtr = &TemplParam; + TemplateTypeParmDecl *TemplParam = + TemplateTypeParmDecl::Create(Context, 0, SourceLocation(), Loc, 0, 0, 0, + false, false); + QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0); + NamedDecl *TemplParamPtr = TemplParam; FixedSizeTemplateParameterList<1> TemplateParams(Loc, Loc, &TemplParamPtr, Loc); - QualType FuncParam = + TypeSourceInfo *FuncParamInfo = SubstituteAutoTransform(*this, TemplArg).TransformType(Type); + assert(FuncParamInfo && "substituting template parameter for 'auto' failed"); + QualType FuncParam = FuncParamInfo->getType(); // Deduce type of TemplParam in Func(Init) llvm::SmallVector<DeducedTemplateArgument, 1> Deduced; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp index ae0ac9c..92ba095 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -95,6 +95,12 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, assert(Function->getPrimaryTemplate() && "No function template?"); if (Function->getPrimaryTemplate()->isMemberSpecialization()) break; + } else if (FunctionTemplateDecl *FunTmpl + = Function->getDescribedFunctionTemplate()) { + // Add the "injected" template arguments. + std::pair<const TemplateArgument *, unsigned> + Injected = FunTmpl->getInjectedTemplateArgs(); + Result.addOuterTemplateArguments(Injected.first, Injected.second); } // If this is a friend declaration and it declares an entity at @@ -718,8 +724,9 @@ namespace { /// as an instantiated local. VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, TypeSourceInfo *Declarator, - IdentifierInfo *Name, - SourceLocation Loc); + SourceLocation StartLoc, + SourceLocation NameLoc, + IdentifierInfo *Name); /// \brief Rebuild the Objective-C exception declaration and register the /// declaration as an instantiated local. @@ -730,9 +737,12 @@ namespace { /// elaborated type. QualType RebuildElaboratedType(SourceLocation KeywordLoc, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, QualType T); + NestedNameSpecifierLoc QualifierLoc, + QualType T); - TemplateName TransformTemplateName(TemplateName Name, + TemplateName TransformTemplateName(CXXScopeSpec &SS, + TemplateName Name, + SourceLocation NameLoc, QualType ObjectType = QualType(), NamedDecl *FirstQualifierInScope = 0); @@ -747,6 +757,7 @@ namespace { QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL); ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, + int indexAdjustment, llvm::Optional<unsigned> NumExpansions); /// \brief Transforms a template type parameter type by performing @@ -871,10 +882,11 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D, VarDecl * TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl, TypeSourceInfo *Declarator, - IdentifierInfo *Name, - SourceLocation Loc) { + SourceLocation StartLoc, + SourceLocation NameLoc, + IdentifierInfo *Name) { VarDecl *Var = inherited::RebuildExceptionDecl(ExceptionDecl, Declarator, - Name, Loc); + StartLoc, NameLoc, Name); if (Var) getSema().CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); return Var; @@ -892,7 +904,7 @@ VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, QualType TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, + NestedNameSpecifierLoc QualifierLoc, QualType T) { if (const TagType *TT = T->getAs<TagType>()) { TagDecl* TD = TT->getDecl(); @@ -918,10 +930,13 @@ TemplateInstantiator::RebuildElaboratedType(SourceLocation KeywordLoc, return TreeTransform<TemplateInstantiator>::RebuildElaboratedType(KeywordLoc, Keyword, - NNS, T); + QualifierLoc, + T); } -TemplateName TemplateInstantiator::TransformTemplateName(TemplateName Name, +TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS, + TemplateName Name, + SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope) { if (TemplateTemplateParmDecl *TTP @@ -955,24 +970,31 @@ TemplateName TemplateInstantiator::TransformTemplateName(TemplateName Name, TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && Template.getAsTemplateDecl() && "Wrong kind of template template argument"); + + // We don't ever want to substitute for a qualified template name, since + // the qualifier is handled separately. So, look through the qualified + // template name to its underlying declaration. + if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + Template = TemplateName(QTN->getTemplateDecl()); + return Template; } } if (SubstTemplateTemplateParmPackStorage *SubstPack - = Name.getAsSubstTemplateTemplateParmPack()) { + = Name.getAsSubstTemplateTemplateParmPack()) { if (getSema().ArgumentPackSubstitutionIndex == -1) return Name; - + const TemplateArgument &ArgPack = SubstPack->getArgumentPack(); assert(getSema().ArgumentPackSubstitutionIndex < (int)ArgPack.pack_size() && "Pack substitution index out-of-range"); return ArgPack.pack_begin()[getSema().ArgumentPackSubstitutionIndex] - .getAsTemplate(); + .getAsTemplate(); } - return inherited::TransformTemplateName(Name, ObjectType, - FirstQualifierInScope); + return inherited::TransformTemplateName(SS, Name, NameLoc, ObjectType, + FirstQualifierInScope); } ExprResult @@ -1153,8 +1175,9 @@ QualType TemplateInstantiator::TransformFunctionProtoType(TypeLocBuilder &TLB, ParmVarDecl * TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm, + int indexAdjustment, llvm::Optional<unsigned> NumExpansions) { - return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, + return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment, NumExpansions); } @@ -1217,12 +1240,17 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, // the template parameter list of a member template inside the // template we are instantiating). Create a new template type // parameter with the template "level" reduced by one. + TemplateTypeParmDecl *NewTTPDecl = 0; + if (TemplateTypeParmDecl *OldTTPDecl = T->getDecl()) + NewTTPDecl = cast_or_null<TemplateTypeParmDecl>( + TransformDecl(TL.getNameLoc(), OldTTPDecl)); + QualType Result = getSema().Context.getTemplateTypeParmType(T->getDepth() - TemplateArgs.getNumLevels(), T->getIndex(), T->isParameterPack(), - T->getName()); + NewTTPDecl); TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; @@ -1396,6 +1424,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs, + int indexAdjustment, llvm::Optional<unsigned> NumExpansions) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); TypeSourceInfo *NewDI = 0; @@ -1432,9 +1461,10 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, } ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(), - NewDI, NewDI->getType(), - OldParm->getIdentifier(), + OldParm->getInnerLocStart(), OldParm->getLocation(), + OldParm->getIdentifier(), + NewDI->getType(), NewDI, OldParm->getStorageClass(), OldParm->getStorageClassAsWritten()); if (!NewParm) @@ -1465,6 +1495,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, // FIXME: OldParm may come from a FunctionProtoType, in which case CurContext // can be anything, is this right ? NewParm->setDeclContext(CurContext); + + NewParm->setScopeInfo(OldParm->getFunctionScopeDepth(), + OldParm->getFunctionScopeIndex() + indexAdjustment); return NewParm; } @@ -1508,6 +1541,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, } SourceLocation EllipsisLoc; + TypeSourceInfo *BaseTypeLoc; if (Base->isPackExpansion()) { // This is a pack expansion. See whether we should expand it now, or // wait until later. @@ -1558,13 +1592,18 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, // The resulting base specifier will (still) be a pack expansion. EllipsisLoc = Base->getEllipsisLoc(); + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, -1); + BaseTypeLoc = SubstType(Base->getTypeSourceInfo(), + TemplateArgs, + Base->getSourceRange().getBegin(), + DeclarationName()); + } else { + BaseTypeLoc = SubstType(Base->getTypeSourceInfo(), + TemplateArgs, + Base->getSourceRange().getBegin(), + DeclarationName()); } - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, -1); - TypeSourceInfo *BaseTypeLoc = SubstType(Base->getTypeSourceInfo(), - TemplateArgs, - Base->getSourceRange().getBegin(), - DeclarationName()); if (!BaseTypeLoc) { Invalid = true; continue; @@ -1622,9 +1661,18 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *PatternDef = cast_or_null<CXXRecordDecl>(Pattern->getDefinition()); - if (!PatternDef) { - if (!Complain) { + if (!PatternDef || PatternDef->isBeingDefined()) { + if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) { // Say nothing + } else if (PatternDef) { + assert(PatternDef->isBeingDefined()); + Diag(PointOfInstantiation, + diag::err_template_instantiate_within_definition) + << (TSK != TSK_ImplicitInstantiation) + << Context.getTypeDeclType(Instantiation); + // Not much point in noting the template declaration here, since + // we're lexically inside it. + Instantiation->setInvalidDecl(); } else if (Pattern == Instantiation->getInstantiatedFromMemberClass()) { Diag(PointOfInstantiation, diag::err_implicit_instantiate_member_undefined) @@ -2130,16 +2178,6 @@ bool Sema::SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall, return Instantiator.TransformExprs(Exprs, NumExprs, IsCall, Outputs); } -/// \brief Do template substitution on a nested-name-specifier. -NestedNameSpecifier * -Sema::SubstNestedNameSpecifier(NestedNameSpecifier *NNS, - SourceRange Range, - const MultiLevelTemplateArgumentList &TemplateArgs) { - TemplateInstantiator Instantiator(*this, TemplateArgs, Range.getBegin(), - DeclarationName()); - return Instantiator.TransformNestedNameSpecifier(NNS, Range); -} - NestedNameSpecifierLoc Sema::SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, const MultiLevelTemplateArgumentList &TemplateArgs) { @@ -2161,11 +2199,14 @@ Sema::SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, } TemplateName -Sema::SubstTemplateName(TemplateName Name, SourceLocation Loc, +Sema::SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, + TemplateName Name, SourceLocation Loc, const MultiLevelTemplateArgumentList &TemplateArgs) { TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, DeclarationName()); - return Instantiator.TransformTemplateName(Name); + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + return Instantiator.TransformTemplateName(SS, Name, Loc); } bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 3a40b6f..6e11ef5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -128,7 +128,8 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { return Inst; } -Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { +Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D, + bool IsTypeAlias) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI->getType()->isDependentType() || @@ -144,9 +145,13 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { } // Create the new typedef - TypedefDecl *Typedef - = TypedefDecl::Create(SemaRef.Context, Owner, D->getLocation(), - D->getIdentifier(), DI); + TypedefNameDecl *Typedef; + if (IsTypeAlias) + Typedef = TypeAliasDecl::Create(SemaRef.Context, Owner, D->getLocStart(), + D->getLocation(), D->getIdentifier(), DI); + else + Typedef = TypedefDecl::Create(SemaRef.Context, Owner, D->getLocStart(), + D->getLocation(), D->getIdentifier(), DI); if (Invalid) Typedef->setInvalidDecl(); @@ -154,17 +159,20 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { // tag decl, re-establish that relationship for the new typedef. if (const TagType *oldTagType = D->getUnderlyingType()->getAs<TagType>()) { TagDecl *oldTag = oldTagType->getDecl(); - if (oldTag->getTypedefForAnonDecl() == D) { + if (oldTag->getTypedefNameForAnonDecl() == D) { TagDecl *newTag = DI->getType()->castAs<TagType>()->getDecl(); - assert(!newTag->getIdentifier() && !newTag->getTypedefForAnonDecl()); - newTag->setTypedefForAnonDecl(Typedef); + assert(!newTag->getIdentifier() && !newTag->getTypedefNameForAnonDecl()); + newTag->setTypedefNameForAnonDecl(Typedef); } } - if (TypedefDecl *Prev = D->getPreviousDeclaration()) { + if (TypedefNameDecl *Prev = D->getPreviousDeclaration()) { NamedDecl *InstPrev = SemaRef.FindInstantiatedDecl(D->getLocation(), Prev, TemplateArgs); - Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev)); + if (!InstPrev) + return 0; + + Typedef->setPreviousDeclaration(cast<TypedefNameDecl>(InstPrev)); } SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef); @@ -175,6 +183,14 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { return Typedef; } +Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { + return VisitTypedefNameDecl(D, /*IsTypeAlias=*/false); +} + +Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) { + return VisitTypedefNameDecl(D, /*IsTypeAlias=*/true); +} + /// \brief Instantiate an initializer, breaking it into separate /// initialization arguments. /// @@ -261,12 +277,14 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { // Build the instantiated declaration VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, + D->getInnerLocStart(), D->getLocation(), D->getIdentifier(), DI->getType(), DI, D->getStorageClass(), D->getStorageClassAsWritten()); Var->setThreadSpecified(D->isThreadSpecified()); Var->setCXXDirectInitializer(D->hasCXXDirectInitializer()); + Var->setCXXForRangeDecl(D->isCXXForRangeDecl()); // Substitute the nested name specifier, if any. if (SubstQualifier(D, Var)) @@ -280,8 +298,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Var->setAccess(D->getAccess()); - if (!D->isStaticDataMember()) + if (!D->isStaticDataMember()) { Var->setUsed(D->isUsed(false)); + Var->setReferenced(D->isReferenced()); + } // FIXME: In theory, we could have a previous declaration for variables that // are not static data members. @@ -346,7 +366,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { } SemaRef.PopExpressionEvaluationContext(); - } else if (!Var->isStaticDataMember() || Var->isOutOfLine()) + } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) && + !Var->isCXXForRangeDecl()) SemaRef.ActOnUninitializedDecl(Var, false); // Diagnose unused local variables. @@ -448,9 +469,14 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) { int i = 0; for (IndirectFieldDecl::chain_iterator PI = D->chain_begin(), PE = D->chain_end(); - PI != PE; ++PI) - NamedChain[i++] = (SemaRef.FindInstantiatedDecl(D->getLocation(), - *PI, TemplateArgs)); + PI != PE; ++PI) { + NamedDecl *Next = SemaRef.FindInstantiatedDecl(D->getLocation(), *PI, + TemplateArgs); + if (!Next) + return 0; + + NamedChain[i++] = Next; + } QualType T = cast<FieldDecl>(NamedChain[i-1])->getType(); IndirectFieldDecl* IndirectField @@ -469,10 +495,18 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { // Handle friend type expressions by simply substituting template // parameters into the pattern type and checking the result. if (TypeSourceInfo *Ty = D->getFriendType()) { - TypeSourceInfo *InstTy = - SemaRef.SubstType(Ty, TemplateArgs, - D->getLocation(), DeclarationName()); - if (!InstTy) + TypeSourceInfo *InstTy; + // If this is an unsupported friend, don't bother substituting template + // arguments into it. The actual type referred to won't be used by any + // parts of Clang, and may not be valid for instantiating. Just use the + // same info for the instantiated friend. + if (D->isUnsupportedFriend()) { + InstTy = Ty; + } else { + InstTy = SemaRef.SubstType(Ty, TemplateArgs, + D->getLocation(), DeclarationName()); + } + if (!InstTy) return 0; FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getFriendLoc(), InstTy); @@ -519,13 +553,13 @@ Decl *TemplateDeclInstantiator::VisitStaticAssertDecl(StaticAssertDecl *D) { D->getMessage(); return SemaRef.ActOnStaticAssertDeclaration(D->getLocation(), InstantiatedAssertExpr.get(), - Message.get()); + Message.get(), + D->getRParenLoc()); } Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { - EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner, + EnumDecl *Enum = EnumDecl::Create(SemaRef.Context, Owner, D->getLocStart(), D->getLocation(), D->getIdentifier(), - D->getTagKeywordLoc(), /*PrevDecl=*/0, D->isScoped(), D->isScopedUsingClassTag(), D->isFixed()); if (D->isFixed()) { @@ -750,8 +784,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { CXXRecordDecl *RecordInst = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), DC, - Pattern->getLocation(), Pattern->getIdentifier(), - Pattern->getTagKeywordLoc(), PrevDecl, + Pattern->getLocStart(), Pattern->getLocation(), + Pattern->getIdentifier(), PrevDecl, /*DelayTypeCreation=*/true); if (QualifierLoc) @@ -892,8 +926,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { CXXRecordDecl *Record = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner, - D->getLocation(), D->getIdentifier(), - D->getTagKeywordLoc(), PrevDecl); + D->getLocStart(), D->getLocation(), + D->getIdentifier(), PrevDecl); // Substitute the nested name specifier, if any. if (SubstQualifier(D, Record)) @@ -991,8 +1025,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } FunctionDecl *Function = - FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(), - D->getDeclName(), T, TInfo, + FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), + D->getLocation(), D->getDeclName(), T, TInfo, D->getStorageClass(), D->getStorageClassAsWritten(), D->isInlineSpecified(), D->hasWrittenPrototype()); @@ -1288,30 +1322,33 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); CXXMethodDecl *Method = 0; + SourceLocation StartLoc = D->getInnerLocStart(); DeclarationNameInfo NameInfo = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { Method = CXXConstructorDecl::Create(SemaRef.Context, Record, - NameInfo, T, TInfo, + StartLoc, NameInfo, T, TInfo, Constructor->isExplicit(), Constructor->isInlineSpecified(), false); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, - NameInfo, T, TInfo, + StartLoc, NameInfo, T, TInfo, Destructor->isInlineSpecified(), false); } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { Method = CXXConversionDecl::Create(SemaRef.Context, Record, - NameInfo, T, TInfo, + StartLoc, NameInfo, T, TInfo, Conversion->isInlineSpecified(), - Conversion->isExplicit()); + Conversion->isExplicit(), + Conversion->getLocEnd()); } else { Method = CXXMethodDecl::Create(SemaRef.Context, Record, - NameInfo, T, TInfo, + StartLoc, NameInfo, T, TInfo, D->isStatic(), D->getStorageClassAsWritten(), - D->isInlineSpecified()); + D->isInlineSpecified(), + D->getLocEnd()); } if (QualifierLoc) @@ -1431,23 +1468,24 @@ Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) { } ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) { - return SemaRef.SubstParmVarDecl(D, TemplateArgs, llvm::Optional<unsigned>()); + return SemaRef.SubstParmVarDecl(D, TemplateArgs, /*indexAdjustment*/ 0, + llvm::Optional<unsigned>()); } Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( TemplateTypeParmDecl *D) { // TODO: don't always clone when decls are refcounted. - const Type* T = D->getTypeForDecl(); - assert(T->isTemplateTypeParmType()); - const TemplateTypeParmType *TTPT = T->getAs<TemplateTypeParmType>(); + assert(D->getTypeForDecl()->isTemplateTypeParmType()); TemplateTypeParmDecl *Inst = - TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), - TTPT->getDepth() - TemplateArgs.getNumLevels(), - TTPT->getIndex(), D->getIdentifier(), + TemplateTypeParmDecl::Create(SemaRef.Context, Owner, + D->getLocStart(), D->getLocation(), + D->getDepth() - TemplateArgs.getNumLevels(), + D->getIndex(), D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack()); - + Inst->setAccess(AS_public); + if (D->hasDefaultArgument()) Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false); @@ -1567,7 +1605,6 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( return 0; // Check that this type is acceptable for a non-type template parameter. - bool Invalid = false; T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(), D->getLocation()); if (T.isNull()) { @@ -1579,7 +1616,8 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( NonTypeTemplateParmDecl *Param; if (IsExpandedParameterPack) Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, - D->getLocation(), + D->getInnerLocStart(), + D->getLocation(), D->getDepth() - TemplateArgs.getNumLevels(), D->getPosition(), D->getIdentifier(), T, @@ -1589,12 +1627,14 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( ExpandedParameterPackTypesAsWritten.data()); else Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, + D->getInnerLocStart(), D->getLocation(), D->getDepth() - TemplateArgs.getNumLevels(), D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI); + Param->setAccess(AS_public); if (Invalid) Param->setInvalidDecl(); @@ -1628,6 +1668,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams); Param->setDefaultArgument(D->getDefaultArgument(), false); + Param->setAccess(AS_public); // Introduce this template parameter's instantiation into the instantiation // scope. @@ -1719,9 +1760,12 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { I != E; ++I) { UsingShadowDecl *Shadow = *I; NamedDecl *InstTarget = - cast<NamedDecl>(SemaRef.FindInstantiatedDecl(Shadow->getLocation(), - Shadow->getTargetDecl(), - TemplateArgs)); + cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl( + Shadow->getLocation(), + Shadow->getTargetDecl(), + TemplateArgs)); + if (!InstTarget) + return 0; if (CheckRedeclaration && SemaRef.CheckUsingShadowDecl(NewUD, InstTarget, Prev)) @@ -1936,7 +1980,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( = ClassTemplatePartialSpecializationDecl::Create(SemaRef.Context, PartialSpec->getTagKind(), Owner, - PartialSpec->getLocation(), + PartialSpec->getLocStart(), + PartialSpec->getLocation(), InstParams, ClassTemplate, Converted.data(), @@ -2063,8 +2108,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, const FunctionProtoType *Proto = Tmpl->getType()->getAs<FunctionProtoType>(); assert(Proto && "Function template without prototype?"); - if (Proto->hasExceptionSpec() || Proto->hasAnyExceptionSpec() || - Proto->getNoReturnAttr()) { + if (Proto->hasExceptionSpec() || Proto->getNoReturnAttr()) { // The function has an exception specification or a "noreturn" // attribute. Substitute into each of the exception types. llvm::SmallVector<QualType, 4> Exceptions; @@ -2078,7 +2122,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, Unexpanded); assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); - + bool Expand = false; bool RetainExpansion = false; llvm::Optional<unsigned> NumExpansions @@ -2092,7 +2136,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, RetainExpansion, NumExpansions)) break; - + if (!Expand) { // We can't expand this pack expansion into separate arguments yet; // just substitute into the pattern and create a new pack expansion @@ -2108,7 +2152,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, Exceptions.push_back(T); continue; } - + // Substitute into the pack expansion pattern for each template bool Invalid = false; for (unsigned ArgIdx = 0; ArgIdx != *NumExpansions; ++ArgIdx) { @@ -2121,13 +2165,13 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, Invalid = true; break; } - + Exceptions.push_back(T); } - + if (Invalid) break; - + continue; } @@ -2140,14 +2184,20 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, Exceptions.push_back(T); } + Expr *NoexceptExpr = 0; + if (Expr *OldNoexceptExpr = Proto->getNoexceptExpr()) { + ExprResult E = SemaRef.SubstExpr(OldNoexceptExpr, TemplateArgs); + if (E.isUsable()) + NoexceptExpr = E.take(); + } // Rebuild the function type FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); - EPI.HasExceptionSpec = Proto->hasExceptionSpec(); - EPI.HasAnyExceptionSpec = Proto->hasAnyExceptionSpec(); + EPI.ExceptionSpecType = Proto->getExceptionSpecType(); EPI.NumExceptions = Exceptions.size(); EPI.Exceptions = Exceptions.data(); + EPI.NoexceptExpr = NoexceptExpr; EPI.ExtInfo = Proto->getExtInfo(); const FunctionProtoType *NewProto @@ -2218,6 +2268,21 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (PatternDecl) Pattern = PatternDecl->getBody(PatternDecl); + // Postpone late parsed template instantiations. + if (PatternDecl->isLateTemplateParsed() && !LateTemplateParser) { + PendingInstantiations.push_back( + std::make_pair(Function, PointOfInstantiation)); + return; + } + + // Call the LateTemplateParser callback if there a need to late parse + // a templated function definition. + if (!Pattern && PatternDecl && PatternDecl->isLateTemplateParsed() && + LateTemplateParser) { + LateTemplateParser(OpaqueParser, PatternDecl); + Pattern = PatternDecl->getBody(PatternDecl); + } + if (!Pattern) { if (DefinitionRequired) { if (Function->getPrimaryTemplate()) @@ -2573,10 +2638,15 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, New->getParent(), EllipsisLoc); } else if (Init->isMemberInitializer()) { - FieldDecl *Member = cast<FieldDecl>(FindInstantiatedDecl( + FieldDecl *Member = cast_or_null<FieldDecl>(FindInstantiatedDecl( Init->getMemberLocation(), Init->getMember(), TemplateArgs)); + if (!Member) { + AnyErrors = true; + New->setInvalidDecl(); + continue; + } NewInit = BuildMemberInitializer(Member, (Expr **)NewArgs.data(), NewArgs.size(), @@ -2585,10 +2655,16 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, Init->getRParenLoc()); } else if (Init->isIndirectMemberInitializer()) { IndirectFieldDecl *IndirectMember = - cast<IndirectFieldDecl>(FindInstantiatedDecl( + cast_or_null<IndirectFieldDecl>(FindInstantiatedDecl( Init->getMemberLocation(), Init->getIndirectMember(), TemplateArgs)); + if (!IndirectMember) { + AnyErrors = true; + New->setInvalidDecl(); + continue; + } + NewInit = BuildMemberInitializer(IndirectMember, (Expr **)NewArgs.data(), NewArgs.size(), Init->getSourceLocation(), @@ -2917,7 +2993,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // FIXME: Can we use the CurrentInstantiationScope to avoid this // extra instantiation in the common case? - T = SubstType(T, TemplateArgs, SourceLocation(), DeclarationName()); + T = SubstType(T, TemplateArgs, Loc, DeclarationName()); assert(!T.isNull() && "Instantiation of injected-class-name cannot fail."); if (!T->isDependentType()) { @@ -2974,11 +3050,14 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // If our context used to be dependent, we may need to instantiate // it before performing lookup into that context. + bool IsBeingInstantiated = false; if (CXXRecordDecl *Spec = dyn_cast<CXXRecordDecl>(ParentDC)) { if (!Spec->isDependentContext()) { QualType T = Context.getTypeDeclType(Spec); const RecordType *Tag = T->getAs<RecordType>(); assert(Tag && "type of non-dependent record is not a RecordType"); + if (Tag->isBeingDefined()) + IsBeingInstantiated = true; if (!Tag->isBeingDefined() && RequireCompleteType(Loc, T, diag::err_incomplete_type)) return 0; @@ -3005,11 +3084,29 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, ParentDC->decls_end()); } - // UsingShadowDecls can instantiate to nothing because of using hiding. - assert((Result || isa<UsingShadowDecl>(D) || D->isInvalidDecl() || - cast<Decl>(ParentDC)->isInvalidDecl()) - && "Unable to find instantiation of declaration!"); - + if (!Result) { + if (isa<UsingShadowDecl>(D)) { + // UsingShadowDecls can instantiate to nothing because of using hiding. + } else if (Diags.hasErrorOccurred()) { + // We've already complained about something, so most likely this + // declaration failed to instantiate. There's no point in complaining + // further, since this is normal in invalid code. + } else if (IsBeingInstantiated) { + // The class in which this member exists is currently being + // instantiated, and we haven't gotten around to instantiating this + // member yet. This can happen when the code uses forward declarations + // of member classes, and introduces ordering dependencies via + // template instantiation. + Diag(Loc, diag::err_member_not_yet_instantiated) + << D->getDeclName() + << Context.getTypeDeclType(cast<CXXRecordDecl>(ParentDC)); + Diag(D->getLocation(), diag::note_non_instantiated_member_here); + } else { + // We should have found something, but didn't. + llvm_unreachable("Unable to find instantiation of declaration!"); + } + } + D = Result; } @@ -3018,7 +3115,10 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, /// \brief Performs template instantiation for all implicit template /// instantiations we have seen until this point. -void Sema::PerformPendingInstantiations(bool LocalOnly) { +/// +/// \returns true if anything was instantiated. +bool Sema::PerformPendingInstantiations(bool LocalOnly) { + bool InstantiatedAnything = false; while (!PendingLocalImplicitInstantiations.empty() || (!LocalOnly && !PendingInstantiations.empty())) { PendingImplicitInstantiation Inst; @@ -3039,6 +3139,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { TSK_ExplicitInstantiationDefinition; InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true, DefinitionRequired); + InstantiatedAnything = true; continue; } @@ -3075,7 +3176,10 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { TSK_ExplicitInstantiationDefinition; InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true, DefinitionRequired); + InstantiatedAnything = true; } + + return InstantiatedAnything; } void Sema::PerformDependentDiagnostics(const DeclContext *Pattern, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp index 0da801c..096d353 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -167,7 +167,7 @@ DiagnoseUnexpandedParameterPacks(Sema &S, SourceLocation Loc, IdentifierInfo *Name = 0; if (const TemplateTypeParmType *TTP = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) - Name = TTP->getName(); + Name = TTP->getIdentifier(); else Name = Unexpanded[I].first.get<NamedDecl *>()->getIdentifier(); @@ -483,7 +483,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { Depth = TTP->getDepth(); Index = TTP->getIndex(); - Name = TTP->getName(); + Name = TTP->getIdentifier(); } else { NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>(); if (isa<ParmVarDecl>(ND)) @@ -649,6 +649,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_struct: case TST_class: case TST_auto: + case TST_unknown_anytype: case TST_error: break; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp index ba80076..00ac1d6 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp @@ -13,6 +13,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" +#include "clang/Basic/OpenCL.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" @@ -22,6 +23,7 @@ #include "clang/AST/Expr.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ErrorHandling.h" @@ -70,6 +72,40 @@ static bool isOmittedBlockReturnType(const Declarator &D) { return false; } +/// diagnoseBadTypeAttribute - Diagnoses a type attribute which +/// doesn't apply to the given type. +static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, + QualType type) { + bool useInstantiationLoc = false; + + unsigned diagID = 0; + switch (attr.getKind()) { + case AttributeList::AT_objc_gc: + diagID = diag::warn_pointer_attribute_wrong_type; + useInstantiationLoc = true; + break; + + default: + // Assume everything else was a function attribute. + diagID = diag::warn_function_attribute_wrong_type; + break; + } + + SourceLocation loc = attr.getLoc(); + llvm::StringRef name = attr.getName()->getName(); + + // The GC attributes are usually written with macros; special-case them. + if (useInstantiationLoc && loc.isMacroID() && attr.getParameterName()) { + if (attr.getParameterName()->isStr("strong")) { + if (S.findMacroSpelling(loc, "__strong")) name = "__strong"; + } else if (attr.getParameterName()->isStr("weak")) { + if (S.findMacroSpelling(loc, "__weak")) name = "__weak"; + } + } + + S.Diag(loc, diagID) << name << type; +} + // objc_gc applies to Objective-C pointers or, otherwise, to the // smallest available pointer type (i.e. 'void*' in 'void**'). #define OBJC_POINTER_TYPE_ATTRS_CASELIST \ @@ -83,7 +119,8 @@ static bool isOmittedBlockReturnType(const Declarator &D) { case AttributeList::AT_stdcall: \ case AttributeList::AT_thiscall: \ case AttributeList::AT_pascal: \ - case AttributeList::AT_regparm + case AttributeList::AT_regparm: \ + case AttributeList::AT_pcs \ namespace { /// An object which stores processing state for the entire @@ -102,6 +139,9 @@ namespace { /// Whether there are non-trivial modifications to the decl spec. bool trivial; + /// Whether we saved the attributes in the decl spec. + bool hasSavedAttrs; + /// The original set of attributes on the DeclSpec. llvm::SmallVector<AttributeList*, 2> savedAttrs; @@ -113,7 +153,7 @@ namespace { TypeProcessingState(Sema &sema, Declarator &declarator) : sema(sema), declarator(declarator), chunkIndex(declarator.getNumTypeObjects()), - trivial(true) {} + trivial(true), hasSavedAttrs(false) {} Sema &getSema() const { return sema; @@ -142,13 +182,14 @@ namespace { /// Save the current set of attributes on the DeclSpec. void saveDeclSpecAttrs() { // Don't try to save them multiple times. - if (!savedAttrs.empty()) return; + if (hasSavedAttrs) return; DeclSpec &spec = getMutableDeclSpec(); for (AttributeList *attr = spec.getAttributes().getList(); attr; attr = attr->getNext()) savedAttrs.push_back(attr); trivial &= savedAttrs.empty(); + hasSavedAttrs = true; } /// Record that we had nowhere to put the given type attribute. @@ -162,11 +203,8 @@ namespace { void diagnoseIgnoredTypeAttrs(QualType type) const { for (llvm::SmallVectorImpl<AttributeList*>::const_iterator i = ignoredTypeAttrs.begin(), e = ignoredTypeAttrs.end(); - i != e; ++i) { - AttributeList &attr = **i; - getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type) - << attr.getName() << type; - } + i != e; ++i) + diagnoseBadTypeAttribute(getSema(), **i, type); } ~TypeProcessingState() { @@ -181,7 +219,13 @@ namespace { } void restoreDeclSpecAttrs() { - assert(!savedAttrs.empty()); + assert(hasSavedAttrs); + + if (savedAttrs.empty()) { + getMutableDeclSpec().getAttributes().set(0); + return; + } + getMutableDeclSpec().getAttributes().set(savedAttrs[0]); for (unsigned i = 0, e = savedAttrs.size() - 1; i != e; ++i) savedAttrs[i]->setNext(savedAttrs[i+1]); @@ -287,9 +331,8 @@ static void distributeObjCPointerTypeAttr(TypeProcessingState &state, } } error: - - state.getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type) - << attr.getName() << type; + + diagnoseBadTypeAttribute(state.getSema(), attr, type); } /// Distribute an objc_gc type attribute that was written on the @@ -328,8 +371,15 @@ distributeObjCPointerTypeAttrFromDeclarator(TypeProcessingState &state, // That might actually be the decl spec if we weren't blocked by // anything in the declarator. if (considerDeclSpec) { - if (handleObjCPointerTypeAttr(state, attr, declSpecType)) + if (handleObjCPointerTypeAttr(state, attr, declSpecType)) { + // Splice the attribute into the decl spec. Prevents the + // attribute from being applied multiple times and gives + // the source-location-filler something to work with. + state.saveDeclSpecAttrs(); + moveAttrFromListToList(attr, declarator.getAttrListRef(), + declarator.getMutableDeclSpec().getAttributes().getListRef()); return; + } } // Otherwise, if we found an appropriate chunk, splice the attribute @@ -374,8 +424,7 @@ static void distributeFunctionTypeAttr(TypeProcessingState &state, } } - state.getSema().Diag(attr.getLoc(), diag::warn_function_attribute_wrong_type) - << attr.getName() << type; + diagnoseBadTypeAttribute(state.getSema(), attr, type); } /// Try to distribute a function type attribute to the innermost @@ -505,13 +554,12 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, // ...and *prepend* it to the declarator. declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction( - ParsedAttributes(), /*proto*/ true, /*variadic*/ false, SourceLocation(), /*args*/ 0, 0, /*type quals*/ 0, /*ref-qualifier*/true, SourceLocation(), - /*EH*/ false, SourceLocation(), false, 0, 0, 0, + /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0, /*parens*/ loc, loc, declarator)); @@ -698,7 +746,7 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) { } // If the type is deprecated or unavailable, diagnose it. - S.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeLoc()); + S.DiagnoseUseOfDecl(D, DS.getTypeSpecTypeNameLoc()); assert(DS.getTypeSpecWidth() == 0 && DS.getTypeSpecComplex() == 0 && DS.getTypeSpecSign() == 0 && "No qualifiers on tag names!"); @@ -706,12 +754,11 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) { // TypeQuals handled by caller. Result = Context.getTypeDeclType(D); - // In C++, make an ElaboratedType. - if (S.getLangOptions().CPlusPlus) { - ElaboratedTypeKeyword Keyword - = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); - Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result); - } + // In both C and C++, make an ElaboratedType. + ElaboratedTypeKeyword Keyword + = ElaboratedType::getKeywordForTypeSpec(DS.getTypeSpecType()); + Result = S.getElaboratedType(Keyword, DS.getTypeSpecScope(), Result); + if (D->isInvalidDecl()) declarator.setInvalidType(true); break; @@ -795,6 +842,10 @@ static QualType ConvertDeclSpecToType(Sema &S, TypeProcessingState &state) { break; } + case DeclSpec::TST_unknown_anytype: + Result = Context.UnknownAnyTy; + break; + case DeclSpec::TST_error: Result = Context.IntTy; declarator.setInvalidType(true); @@ -1108,8 +1159,13 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } // Do lvalue-to-rvalue conversions on the array size expression. - if (ArraySize && !ArraySize->isRValue()) - DefaultLvalueConversion(ArraySize); + if (ArraySize && !ArraySize->isRValue()) { + ExprResult Result = DefaultLvalueConversion(ArraySize); + if (Result.isInvalid()) + return QualType(); + + ArraySize = Result.take(); + } // C99 6.7.5.2p1: The size expression shall have integer type. // TODO: in theory, if we were insane, we could allow contextual @@ -1464,19 +1520,27 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, TypeProcessingState state(*this, D); + // In C++0x, deallocation functions (normal and array operator delete) + // are implicitly noexcept. + bool ImplicitlyNoexcept = false; + switch (D.getName().getKind()) { - case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_OperatorFunctionId: + if (getLangOptions().CPlusPlus0x) { + OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator; + if (OO == OO_Delete || OO == OO_Array_Delete) + ImplicitlyNoexcept = true; + } + // Intentional fall-through. + case UnqualifiedId::IK_Identifier: case UnqualifiedId::IK_LiteralOperatorId: case UnqualifiedId::IK_TemplateId: T = ConvertDeclSpecToType(*this, state); if (!D.isInvalidType() && D.getDeclSpec().isTypeSpecOwned()) { TagDecl* Owned = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); - // Owned is embedded if it was defined here, or if it is the - // very first (i.e., canonical) declaration of this tag type. - Owned->setEmbeddedInDeclarator(Owned->isDefinition() || - Owned->isCanonicalDecl()); + // Owned declaration is embedded in declarator. + Owned->setEmbeddedInDeclarator(true); if (OwnedDecl) *OwnedDecl = Owned; } break; @@ -1512,6 +1576,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case Declarator::KNRTypeListContext: assert(0 && "K&R type lists aren't allowed in C++"); break; + case Declarator::ObjCPrototypeContext: case Declarator::PrototypeContext: Error = 0; // Function prototype break; @@ -1535,9 +1600,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case Declarator::TemplateTypeArgContext: Error = 7; // Template type argument break; + case Declarator::AliasDeclContext: + Error = 9; // Type alias + break; case Declarator::TypeNameContext: if (!AutoAllowedInTypeName) - Error = 10; // Generic + Error = 11; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: @@ -1551,7 +1619,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // In Objective-C it is an error to use 'auto' on a function declarator. if (D.isFunctionDeclarator()) - Error = 9; + Error = 10; // C++0x [dcl.spec.auto]p2: 'auto' is always fine if the declarator // contains a trailing return type. That is only legal at the outermost @@ -1588,6 +1656,11 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, if (D.getIdentifier()) Name = D.getIdentifier(); + // Does this declaration declare a typedef-name? + bool IsTypedefName = + D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef || + D.getContext() == Declarator::AliasDeclContext; + // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is // opposite of what we want :). @@ -1660,8 +1733,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, ASM = ArrayType::Static; else ASM = ArrayType::Normal; - if (ASM == ArrayType::Star && - D.getContext() != Declarator::PrototypeContext) { + if (ASM == ArrayType::Star && !D.isPrototypeContext()) { // FIXME: This check isn't quite right: it allows star in prototypes // for function definitions, and disallows some edge cases detailed // in http://gcc.gnu.org/ml/gcc-patches/2009-02/msg00133.html @@ -1728,7 +1800,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // cv-qualifiers on return types are pointless except when the type is a // class type in C++. - if (T->isPointerType() && T.getCVRQualifiers() && + if (isa<PointerType>(T) && T.getLocalCVRQualifiers() && + (D.getName().getKind() != UnqualifiedId::IK_ConversionFunctionId) && (!getLangOptions().CPlusPlus || !T->isDependentType())) { assert(chunkIndex + 1 < e && "No DeclaratorChunk for the return type?"); DeclaratorChunk ReturnTypeChunk = D.getTypeObject(chunkIndex + 1); @@ -1764,9 +1837,9 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Exception specs are not allowed in typedefs. Complain, but add it // anyway. - if (FTI.hasExceptionSpec && - D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) - Diag(FTI.getThrowLoc(), diag::err_exception_spec_in_typedef); + if (IsTypedefName && FTI.getExceptionSpecType()) + Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef) + << (D.getContext() == Declarator::AliasDeclContext); if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) { // Simple void foo(), where the incoming T is the result type. @@ -1845,9 +1918,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } else if (!FTI.hasPrototype) { if (ArgTy->isPromotableIntegerType()) { ArgTy = Context.getPromotedIntegerType(ArgTy); + Param->setKNRPromoted(true); } else if (const BuiltinType* BTy = ArgTy->getAs<BuiltinType>()) { - if (BTy->getKind() == BuiltinType::Float) + if (BTy->getKind() == BuiltinType::Float) { ArgTy = Context.DoubleTy; + Param->setKNRPromoted(true); + } } } @@ -1855,9 +1931,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } llvm::SmallVector<QualType, 4> Exceptions; - if (FTI.hasExceptionSpec) { - EPI.HasExceptionSpec = FTI.hasExceptionSpec; - EPI.HasAnyExceptionSpec = FTI.hasAnyExceptionSpec; + EPI.ExceptionSpecType = FTI.getExceptionSpecType(); + if (FTI.getExceptionSpecType() == EST_Dynamic) { Exceptions.reserve(FTI.NumExceptions); for (unsigned ei = 0, ee = FTI.NumExceptions; ei != ee; ++ei) { // FIXME: Preserve type source info. @@ -1869,6 +1944,27 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, } EPI.NumExceptions = Exceptions.size(); EPI.Exceptions = Exceptions.data(); + } else if (FTI.getExceptionSpecType() == EST_ComputedNoexcept) { + // If an error occurred, there's no expression here. + if (Expr *NoexceptExpr = FTI.NoexceptExpr) { + assert((NoexceptExpr->isTypeDependent() || + NoexceptExpr->getType()->getCanonicalTypeUnqualified() == + Context.BoolTy) && + "Parser should have made sure that the expression is boolean"); + SourceLocation ErrLoc; + llvm::APSInt Dummy; + if (!NoexceptExpr->isValueDependent() && + !NoexceptExpr->isIntegerConstantExpr(Dummy, Context, &ErrLoc, + /*evaluated*/false)) + Diag(ErrLoc, diag::err_noexcept_needs_constant_expression) + << NoexceptExpr->getSourceRange(); + else + EPI.NoexceptExpr = NoexceptExpr; + } + } else if (FTI.getExceptionSpecType() == EST_None && + ImplicitlyNoexcept && chunkIndex == 0) { + // Only the outermost chunk is marked noexcept, of course. + EPI.ExceptionSpecType = EST_BasicNoexcept; } T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI); @@ -1903,11 +1999,12 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: ClsType = QualType(NNS->getAsType(), 0); - // Note: if NNS is dependent, then its prefix (if any) is already - // included in ClsType; this does not hold if the NNS is - // nondependent: in this case (if there is indeed a prefix) - // ClsType needs to be wrapped into an elaborated type. - if (NNSPrefix && !NNS->isDependent()) + // Note: if the NNS has a prefix and ClsType is a nondependent + // TemplateSpecializationType, then the NNS prefix is NOT included + // in ClsType; hence we wrap ClsType into an ElaboratedType. + // NOTE: in particular, no wrap occurs if ClsType already is an + // Elaborated, DependentName, or DependentTemplateSpecialization. + if (NNSPrefix && isa<TemplateSpecializationType>(NNS->getAsType())) ClsType = Context.getElaboratedType(ETK_None, NNSPrefix, ClsType); break; } @@ -1968,8 +2065,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // declaration. if ((FnTy->getTypeQuals() != 0 || FnTy->getRefQualifier()) && !(D.getContext() == Declarator::TemplateTypeArgContext && - !D.isFunctionDeclarator()) && - D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && + !D.isFunctionDeclarator()) && !IsTypedefName && (FreeFunction || D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static)) { if (D.getContext() == Declarator::TemplateTypeArgContext) { @@ -2053,8 +2149,10 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Diagnose any ignored type attributes. if (!T.isNull()) state.diagnoseIgnoredTypeAttrs(T); - // If there's a constexpr specifier, treat it as a top-level const. - if (D.getDeclSpec().isConstexprSpecified()) { + // C++0x [dcl.constexpr]p9: + // A constexpr specifier used in an object declaration declares the object + // as const. + if (D.getDeclSpec().isConstexprSpecified() && T->isObjectType()) { T.addConst(); } @@ -2103,7 +2201,9 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case Declarator::FileContext: case Declarator::KNRTypeListContext: + case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here? case Declarator::TypeNameContext: + case Declarator::AliasDeclContext: case Declarator::MemberContext: case Declarator::BlockContext: case Declarator::ForContext: @@ -2126,6 +2226,62 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, return GetTypeSourceInfoForDeclarator(D, T, ReturnTypeInfo); } +/// Map an AttributedType::Kind to an AttributeList::Kind. +static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { + switch (kind) { + case AttributedType::attr_address_space: + return AttributeList::AT_address_space; + case AttributedType::attr_regparm: + return AttributeList::AT_regparm; + case AttributedType::attr_vector_size: + return AttributeList::AT_vector_size; + case AttributedType::attr_neon_vector_type: + return AttributeList::AT_neon_vector_type; + case AttributedType::attr_neon_polyvector_type: + return AttributeList::AT_neon_polyvector_type; + case AttributedType::attr_objc_gc: + return AttributeList::AT_objc_gc; + case AttributedType::attr_noreturn: + return AttributeList::AT_noreturn; + case AttributedType::attr_cdecl: + return AttributeList::AT_cdecl; + case AttributedType::attr_fastcall: + return AttributeList::AT_fastcall; + case AttributedType::attr_stdcall: + return AttributeList::AT_stdcall; + case AttributedType::attr_thiscall: + return AttributeList::AT_thiscall; + case AttributedType::attr_pascal: + return AttributeList::AT_pascal; + case AttributedType::attr_pcs: + return AttributeList::AT_pcs; + } + llvm_unreachable("unexpected attribute kind!"); + return AttributeList::Kind(); +} + +static void fillAttributedTypeLoc(AttributedTypeLoc TL, + const AttributeList *attrs) { + AttributedType::Kind kind = TL.getAttrKind(); + + assert(attrs && "no type attributes in the expected location!"); + AttributeList::Kind parsedKind = getAttrListKind(kind); + while (attrs->getKind() != parsedKind) { + attrs = attrs->getNext(); + assert(attrs && "no matching attribute in expected location!"); + } + + TL.setAttrNameLoc(attrs->getLoc()); + if (TL.hasAttrExprOperand()) + TL.setAttrExprOperand(attrs->getArg(0)); + else if (TL.hasAttrEnumOperand()) + TL.setAttrEnumOperandLoc(attrs->getParameterLoc()); + + // FIXME: preserve this information to here. + if (TL.hasAttrOperand()) + TL.setAttrOperandParensRange(SourceRange()); +} + namespace { class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> { ASTContext &Context; @@ -2135,6 +2291,10 @@ namespace { TypeSpecLocFiller(ASTContext &Context, const DeclSpec &DS) : Context(Context), DS(DS) {} + void VisitAttributedTypeLoc(AttributedTypeLoc TL) { + fillAttributedTypeLoc(TL, DS.getAttributes().getList()); + Visit(TL.getModifiedLoc()); + } void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { Visit(TL.getUnqualifiedLoc()); } @@ -2179,7 +2339,7 @@ namespace { // If we got no declarator info from previous Sema routines, // just fill with the typespec loc. if (!TInfo) { - TL.initialize(Context, DS.getTypeSpecTypeLoc()); + TL.initialize(Context, DS.getTypeSpecTypeNameLoc()); return; } @@ -2237,7 +2397,7 @@ namespace { ? DS.getTypeSpecTypeLoc() : SourceLocation()); const CXXScopeSpec& SS = DS.getTypeSpecScope(); - TL.setQualifierRange(SS.isEmpty() ? SourceRange(): SS.getRange()); + TL.setQualifierLoc(SS.getWithLocInContext(Context)); Visit(TL.getNextTypeLoc().getUnqualifiedLoc()); } void VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { @@ -2255,9 +2415,8 @@ namespace { ? DS.getTypeSpecTypeLoc() : SourceLocation()); const CXXScopeSpec& SS = DS.getTypeSpecScope(); - TL.setQualifierRange(SS.isEmpty() ? SourceRange() : SS.getRange()); - // FIXME: load appropriate source location. - TL.setNameLoc(DS.getTypeSpecTypeLoc()); + TL.setQualifierLoc(SS.getWithLocInContext(Context)); + TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } void VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL) { @@ -2277,9 +2436,11 @@ namespace { ? DS.getTypeSpecTypeLoc() : SourceLocation()); const CXXScopeSpec& SS = DS.getTypeSpecScope(); - TL.setQualifierRange(SS.isEmpty() ? SourceRange() : SS.getRange()); - // FIXME: load appropriate source location. - TL.setNameLoc(DS.getTypeSpecTypeLoc()); + TL.setQualifierLoc(SS.getWithLocInContext(Context)); + TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); + } + void VisitTagTypeLoc(TagTypeLoc TL) { + TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } void VisitTypeLoc(TypeLoc TL) { @@ -2289,10 +2450,12 @@ namespace { }; class DeclaratorLocFiller : public TypeLocVisitor<DeclaratorLocFiller> { + ASTContext &Context; const DeclaratorChunk &Chunk; public: - DeclaratorLocFiller(const DeclaratorChunk &Chunk) : Chunk(Chunk) {} + DeclaratorLocFiller(ASTContext &Context, const DeclaratorChunk &Chunk) + : Context(Context), Chunk(Chunk) {} void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { llvm_unreachable("qualified type locs not expected here!"); @@ -2312,8 +2475,48 @@ namespace { } void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::MemberPointer); + const CXXScopeSpec& SS = Chunk.Mem.Scope(); + NestedNameSpecifierLoc NNSLoc = SS.getWithLocInContext(Context); + + const Type* ClsTy = TL.getClass(); + QualType ClsQT = QualType(ClsTy, 0); + TypeSourceInfo *ClsTInfo = Context.CreateTypeSourceInfo(ClsQT, 0); + // Now copy source location info into the type loc component. + TypeLoc ClsTL = ClsTInfo->getTypeLoc(); + switch (NNSLoc.getNestedNameSpecifier()->getKind()) { + case NestedNameSpecifier::Identifier: + assert(isa<DependentNameType>(ClsTy) && "Unexpected TypeLoc"); + { + DependentNameTypeLoc DNTLoc = cast<DependentNameTypeLoc>(ClsTL); + DNTLoc.setKeywordLoc(SourceLocation()); + DNTLoc.setQualifierLoc(NNSLoc.getPrefix()); + DNTLoc.setNameLoc(NNSLoc.getLocalBeginLoc()); + } + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + if (isa<ElaboratedType>(ClsTy)) { + ElaboratedTypeLoc ETLoc = *cast<ElaboratedTypeLoc>(&ClsTL); + ETLoc.setKeywordLoc(SourceLocation()); + ETLoc.setQualifierLoc(NNSLoc.getPrefix()); + TypeLoc NamedTL = ETLoc.getNamedTypeLoc(); + NamedTL.initializeFullCopy(NNSLoc.getTypeLoc()); + } else { + ClsTL.initializeFullCopy(NNSLoc.getTypeLoc()); + } + break; + + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Global: + llvm_unreachable("Nested-name-specifier must name a type"); + break; + } + + // Finally fill in MemberPointerLocInfo fields. TL.setStarLoc(Chunk.Loc); - // FIXME: nested name specifier + TL.setClassTInfo(ClsTInfo); } void VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Reference); @@ -2334,8 +2537,8 @@ namespace { } void VisitFunctionTypeLoc(FunctionTypeLoc TL) { assert(Chunk.Kind == DeclaratorChunk::Function); - TL.setLParenLoc(Chunk.Loc); - TL.setRParenLoc(Chunk.EndLoc); + TL.setLocalRangeBegin(Chunk.Loc); + TL.setLocalRangeEnd(Chunk.EndLoc); TL.setTrailingReturn(!!Chunk.Fun.TrailingReturnType); const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun; @@ -2378,7 +2581,13 @@ Sema::GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, } for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { - DeclaratorLocFiller(D.getTypeObject(i)).Visit(CurrTL); + while (isa<AttributedTypeLoc>(CurrTL)) { + AttributedTypeLoc TL = cast<AttributedTypeLoc>(CurrTL); + fillAttributedTypeLoc(TL, D.getTypeObject(i).getAttrs()); + CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); + } + + DeclaratorLocFiller(Context, D.getTypeObject(i)).Visit(CurrTL); CurrTL = CurrTL.getNextTypeLoc().getUnqualifiedLoc(); } @@ -2434,7 +2643,8 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { // A type-specifier-seq shall not define a class or enumeration // unless it appears in the type-id of an alias-declaration // (7.1.3). - if (OwnedTag && OwnedTag->isDefinition()) + if (OwnedTag && OwnedTag->isDefinition() && + D.getContext() != Declarator::AliasDeclContext) Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier) << Context.getTypeDeclType(OwnedTag); } @@ -2547,7 +2757,14 @@ static bool handleObjCGCTypeAttr(TypeProcessingState &state, return true; } - type = S.Context.getObjCGCQualType(type, GCAttr); + QualType origType = type; + type = S.Context.getObjCGCQualType(origType, GCAttr); + + // Make an attributed type to preserve the source information. + if (attr.getLoc().isValid()) + type = S.Context.getAttributedType(AttributedType::attr_objc_gc, + origType, type); + return true; } @@ -2775,7 +2992,7 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, } // Also diagnose fastcall with regparm. - if (fn->getRegParmType()) { + if (fn->getHasRegParm()) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) << "regparm" << FunctionType::getNameForCallConv(CC); @@ -2789,6 +3006,41 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, return true; } +/// Handle OpenCL image access qualifiers: read_only, write_only, read_write +static void HandleOpenCLImageAccessAttribute(QualType& CurType, + const AttributeList &Attr, + Sema &S) { + // Check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + Attr.setInvalid(); + return; + } + Expr *sizeExpr = static_cast<Expr *>(Attr.getArg(0)); + llvm::APSInt arg(32); + if (sizeExpr->isTypeDependent() || sizeExpr->isValueDependent() || + !sizeExpr->isIntegerConstantExpr(arg, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "opencl_image_access" << sizeExpr->getSourceRange(); + Attr.setInvalid(); + return; + } + unsigned iarg = static_cast<unsigned>(arg.getZExtValue()); + switch (iarg) { + case CLIA_read_only: + case CLIA_write_only: + case CLIA_read_write: + // Implemented in a separate patch + break; + default: + // Implemented in a separate patch + S.Diag(Attr.getLoc(), diag::err_attribute_invalid_size) + << sizeExpr->getSourceRange(); + Attr.setInvalid(); + break; + } +} + /// HandleVectorSizeAttribute - this attribute is only applicable to integral /// and float scalars, although arrays, pointers, and function return values are /// allowed in conjunction with this construct. Aggregates with this attribute @@ -2943,6 +3195,10 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, "neon_polyvector_type"); break; + case AttributeList::AT_opencl_image_access: + HandleOpenCLImageAccessAttribute(type, attr, state.getSema()); + break; + FUNCTION_TYPE_ATTRS_CASELIST: // Never process function type attributes as part of the // declaration-specifiers. @@ -3088,7 +3344,7 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, } QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { - ExprResult ER = CheckPlaceholderExpr(E, Loc); + ExprResult ER = CheckPlaceholderExpr(E); if (ER.isInvalid()) return QualType(); E = ER.take(); @@ -3101,7 +3357,7 @@ QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { } QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc) { - ExprResult ER = CheckPlaceholderExpr(E, Loc); + ExprResult ER = CheckPlaceholderExpr(E); if (ER.isInvalid()) return QualType(); E = ER.take(); diff --git a/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp b/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp index c3415cb..ab697ee 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/TargetAttributesSema.cpp @@ -136,7 +136,7 @@ static void HandleX86ForceAlignArgPointerAttr(Decl *D, if (VD && VD->getType()->isFunctionPointerType()) return; // Also don't warn on function pointer typedefs. - TypedefDecl *TD = dyn_cast<TypedefDecl>(D); + TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D); if (TD && (TD->getUnderlyingType()->isFunctionPointerType() || TD->getUnderlyingType()->isFunctionType())) return; diff --git a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h index 57a44ad..2a71e14 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h +++ b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h @@ -67,7 +67,7 @@ using namespace sema; /// /// Subclasses can customize the transformation at various levels. The /// most coarse-grained transformations involve replacing TransformType(), -/// TransformExpr(), TransformDecl(), TransformNestedNameSpecifier(), +/// TransformExpr(), TransformDecl(), TransformNestedNameSpecifierLoc(), /// TransformTemplateName(), or TransformTemplateArgument() with entirely /// new implementations. /// @@ -375,16 +375,6 @@ public: return cast_or_null<NamedDecl>(getDerived().TransformDecl(Loc, D)); } - /// \brief Transform the given nested-name-specifier. - /// - /// By default, transforms all of the types and declarations within the - /// nested-name-specifier. Subclasses may override this function to provide - /// alternate behavior. - NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS, - SourceRange Range, - QualType ObjectType = QualType(), - NamedDecl *FirstQualifierInScope = 0); - /// \brief Transform the given nested-name-specifier with source-location /// information. /// @@ -407,10 +397,27 @@ public: /// \brief Transform the given template name. /// + /// \param SS The nested-name-specifier that qualifies the template + /// name. This nested-name-specifier must already have been transformed. + /// + /// \param Name The template name to transform. + /// + /// \param NameLoc The source location of the template name. + /// + /// \param ObjectType If we're translating a template name within a member + /// access expression, this is the type of the object whose member template + /// is being referenced. + /// + /// \param FirstQualifierInScope If the first part of a nested-name-specifier + /// also refers to a name within the current (lexical) scope, this is the + /// declaration it refers to. + /// /// By default, transforms the template name by transforming the declarations /// and nested-name-specifiers that occur within the template name. /// Subclasses may override this function to provide alternate behavior. - TemplateName TransformTemplateName(TemplateName Name, + TemplateName TransformTemplateName(CXXScopeSpec &SS, + TemplateName Name, + SourceLocation NameLoc, QualType ObjectType = QualType(), NamedDecl *FirstQualifierInScope = 0); @@ -483,6 +490,9 @@ public: QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); #include "clang/AST/TypeLocNodes.def" + StmtResult + TransformSEHHandler(Stmt *Handler); + QualType TransformTemplateSpecializationType(TypeLocBuilder &TLB, TemplateSpecializationTypeLoc TL, @@ -491,7 +501,13 @@ public: QualType TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, - NestedNameSpecifier *Prefix); + TemplateName Template, + CXXScopeSpec &SS); + + QualType + TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, + DependentTemplateSpecializationTypeLoc TL, + NestedNameSpecifierLoc QualifierLoc); /// \brief Transforms the parameters of a function type into the /// given vectors. @@ -508,7 +524,11 @@ public: /// \brief Transforms a single function-type parameter. Return null /// on error. + /// + /// \param indexAdjustment - A number to add to the parameter's + /// scope index; can be negative ParmVarDecl *TransformFunctionTypeParam(ParmVarDecl *OldParm, + int indexAdjustment, llvm::Optional<unsigned> NumExpansions); QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL); @@ -656,7 +676,7 @@ public: QualType RebuildUnresolvedUsingType(Decl *D); /// \brief Build a new typedef type. - QualType RebuildTypedefType(TypedefDecl *Typedef) { + QualType RebuildTypedefType(TypedefNameDecl *Typedef) { return SemaRef.Context.getTypeDeclType(Typedef); } @@ -701,7 +721,7 @@ public: /// different behavior. QualType RebuildTemplateSpecializationType(TemplateName Template, SourceLocation TemplateLoc, - const TemplateArgumentListInfo &Args); + TemplateArgumentListInfo &Args); /// \brief Build a new parenthesized type. /// @@ -718,8 +738,11 @@ public: /// Subclasses may override this routine to provide different behavior. QualType RebuildElaboratedType(SourceLocation KeywordLoc, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, QualType Named) { - return SemaRef.Context.getElaboratedType(Keyword, NNS, Named); + NestedNameSpecifierLoc QualifierLoc, + QualType Named) { + return SemaRef.Context.getElaboratedType(Keyword, + QualifierLoc.getNestedNameSpecifier(), + Named); } /// \brief Build a new typename type that refers to a template-id. @@ -728,34 +751,40 @@ public: /// nested-name-specifier and the given type. Subclasses may override /// this routine to provide different behavior. QualType RebuildDependentTemplateSpecializationType( - ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - const IdentifierInfo *Name, - SourceLocation NameLoc, - const TemplateArgumentListInfo &Args) { + ElaboratedTypeKeyword Keyword, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo *Name, + SourceLocation NameLoc, + TemplateArgumentListInfo &Args) { // Rebuild the template name. // TODO: avoid TemplateName abstraction - TemplateName InstName = - getDerived().RebuildTemplateName(Qualifier, QualifierRange, *Name, - QualType(), 0); + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + TemplateName InstName + = getDerived().RebuildTemplateName(SS, *Name, NameLoc, QualType(), 0); if (InstName.isNull()) return QualType(); - + // If it's still dependent, make a dependent specialization. if (InstName.getAsDependentTemplateName()) - return SemaRef.Context.getDependentTemplateSpecializationType( - Keyword, Qualifier, Name, Args); - + return SemaRef.Context.getDependentTemplateSpecializationType(Keyword, + QualifierLoc.getNestedNameSpecifier(), + Name, + Args); + // Otherwise, make an elaborated type wrapping a non-dependent // specialization. QualType T = - getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args); + getDerived().RebuildTemplateSpecializationType(InstName, NameLoc, Args); if (T.isNull()) return QualType(); - - // NOTE: NNS is already recorded in template specialization type T. - return SemaRef.Context.getElaboratedType(Keyword, /*NNS=*/0, T); + + if (Keyword == ETK_None && QualifierLoc.getNestedNameSpecifier() == 0) + return T; + + return SemaRef.Context.getElaboratedType(Keyword, + QualifierLoc.getNestedNameSpecifier(), + T); } /// \brief Build a new typename type that refers to an identifier. @@ -764,23 +793,24 @@ public: /// (or elaborated type). Subclasses may override this routine to provide /// different behavior. QualType RebuildDependentNameType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, - const IdentifierInfo *Id, SourceLocation KeywordLoc, - SourceRange NNSRange, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo *Id, SourceLocation IdLoc) { CXXScopeSpec SS; - SS.MakeTrivial(SemaRef.Context, NNS, NNSRange); + SS.Adopt(QualifierLoc); - if (NNS->isDependent()) { + if (QualifierLoc.getNestedNameSpecifier()->isDependent()) { // If the name is still dependent, just build a new dependent name type. if (!SemaRef.computeDeclContext(SS)) - return SemaRef.Context.getDependentNameType(Keyword, NNS, Id); + return SemaRef.Context.getDependentNameType(Keyword, + QualifierLoc.getNestedNameSpecifier(), + Id); } if (Keyword == ETK_None || Keyword == ETK_Typename) - return SemaRef.CheckTypenameType(Keyword, NNS, *Id, - KeywordLoc, NNSRange, IdLoc); + return SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, + *Id, IdLoc); TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); @@ -828,7 +858,8 @@ public: NamedDecl *SomeDecl = Result.getRepresentativeDecl(); unsigned Kind = 0; if (isa<TypedefDecl>(SomeDecl)) Kind = 1; - else if (isa<ClassTemplateDecl>(SomeDecl)) Kind = 2; + else if (isa<TypeAliasDecl>(SomeDecl)) Kind = 2; + else if (isa<ClassTemplateDecl>(SomeDecl)) Kind = 3; SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind; SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at); break; @@ -850,7 +881,9 @@ public: // Build the elaborated-type-specifier type. QualType T = SemaRef.Context.getTypeDeclType(Tag); - return SemaRef.Context.getElaboratedType(Keyword, NNS, T); + return SemaRef.Context.getElaboratedType(Keyword, + QualifierLoc.getNestedNameSpecifier(), + T); } /// \brief Build a new pack expansion type. @@ -865,56 +898,13 @@ public: NumExpansions); } - /// \brief Build a new nested-name-specifier given the prefix and an - /// identifier that names the next step in the nested-name-specifier. - /// - /// By default, performs semantic analysis when building the new - /// nested-name-specifier. Subclasses may override this routine to provide - /// different behavior. - NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, - SourceRange Range, - IdentifierInfo &II, - QualType ObjectType, - NamedDecl *FirstQualifierInScope); - - /// \brief Build a new nested-name-specifier given the prefix and the - /// namespace named in the next step in the nested-name-specifier. - /// - /// By default, performs semantic analysis when building the new - /// nested-name-specifier. Subclasses may override this routine to provide - /// different behavior. - NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, - SourceRange Range, - NamespaceDecl *NS); - - /// \brief Build a new nested-name-specifier given the prefix and the - /// namespace alias named in the next step in the nested-name-specifier. - /// - /// By default, performs semantic analysis when building the new - /// nested-name-specifier. Subclasses may override this routine to provide - /// different behavior. - NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, - SourceRange Range, - NamespaceAliasDecl *Alias); - - /// \brief Build a new nested-name-specifier given the prefix and the - /// type named in the next step in the nested-name-specifier. - /// - /// By default, performs semantic analysis when building the new - /// nested-name-specifier. Subclasses may override this routine to provide - /// different behavior. - NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, - SourceRange Range, - bool TemplateKW, - QualType T); - /// \brief Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template /// that the template name refers to. /// /// By default, builds the new template name directly. Subclasses may override /// this routine to provide different behavior. - TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, + TemplateName RebuildTemplateName(CXXScopeSpec &SS, bool TemplateKW, TemplateDecl *Template); @@ -925,9 +915,9 @@ public: /// be resolved to a specific template, then builds the appropriate kind of /// template name. Subclasses may override this routine to provide different /// behavior. - TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - const IdentifierInfo &II, + TemplateName RebuildTemplateName(CXXScopeSpec &SS, + const IdentifierInfo &Name, + SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope); @@ -938,8 +928,9 @@ public: /// be resolved to a specific template, then builds the appropriate kind of /// template name. Subclasses may override this routine to provide different /// behavior. - TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier, + TemplateName RebuildTemplateName(CXXScopeSpec &SS, OverloadedOperatorKind Operator, + SourceLocation NameLoc, QualType ObjectType); /// \brief Build a new template name given a template template parameter pack @@ -1147,9 +1138,10 @@ public: /// Subclasses may override this routine to provide different behavior. VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, TypeSourceInfo *TInfo, QualType T) { - return getSema().BuildObjCExceptionDecl(TInfo, T, - ExceptionDecl->getIdentifier(), - ExceptionDecl->getLocation()); + return getSema().BuildObjCExceptionDecl(TInfo, T, + ExceptionDecl->getInnerLocStart(), + ExceptionDecl->getLocation(), + ExceptionDecl->getIdentifier()); } /// \brief Build a new Objective-C @catch statement. @@ -1214,11 +1206,16 @@ public: /// /// By default, performs semantic analysis to build the new decaration. /// Subclasses may override this routine to provide different behavior. - VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, + VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, TypeSourceInfo *Declarator, - IdentifierInfo *Name, - SourceLocation Loc) { - return getSema().BuildExceptionDeclaration(0, Declarator, Name, Loc); + SourceLocation StartLoc, + SourceLocation IdLoc, + IdentifierInfo *Id) { + VarDecl *Var = getSema().BuildExceptionDeclaration(0, Declarator, + StartLoc, IdLoc, Id); + if (Var) + getSema().CurContext->addDecl(Var); + return Var; } /// \brief Build a new C++ catch statement. @@ -1242,6 +1239,46 @@ public: return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, move(Handlers)); } + /// \brief Build a new C++0x range-based for statement. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc, + SourceLocation ColonLoc, + Stmt *Range, Stmt *BeginEnd, + Expr *Cond, Expr *Inc, + Stmt *LoopVar, + SourceLocation RParenLoc) { + return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd, + Cond, Inc, LoopVar, RParenLoc); + } + + /// \brief Attach body to a C++0x range-based for statement. + /// + /// By default, performs semantic analysis to finish the new statement. + /// Subclasses may override this routine to provide different behavior. + StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body) { + return getSema().FinishCXXForRangeStmt(ForRange, Body); + } + + StmtResult RebuildSEHTryStmt(bool IsCXXTry, + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler) { + return getSema().ActOnSEHTryBlock(IsCXXTry,TryLoc,TryBlock,Handler); + } + + StmtResult RebuildSEHExceptStmt(SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block) { + return getSema().ActOnSEHExceptBlock(Loc,FilterExpr,Block); + } + + StmtResult RebuildSEHFinallyStmt(SourceLocation Loc, + Stmt *Block) { + return getSema().ActOnSEHFinallyBlock(Loc,Block); + } + /// \brief Build a new expression that references a declaration. /// /// By default, performs semantic analysis to build the new expression. @@ -1257,13 +1294,12 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildDeclRefExpr(NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + ExprResult RebuildDeclRefExpr(NestedNameSpecifierLoc QualifierLoc, ValueDecl *VD, const DeclarationNameInfo &NameInfo, TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; - SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange); + SS.Adopt(QualifierLoc); // FIXME: loses template args. @@ -1315,25 +1351,28 @@ public: NumComponents, RParenLoc); } - /// \brief Build a new sizeof or alignof expression with a type argument. + /// \brief Build a new sizeof, alignof or vec_step expression with a + /// type argument. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildSizeOfAlignOf(TypeSourceInfo *TInfo, - SourceLocation OpLoc, - bool isSizeOf, SourceRange R) { - return getSema().CreateSizeOfAlignOfExpr(TInfo, OpLoc, isSizeOf, R); + ExprResult RebuildUnaryExprOrTypeTrait(TypeSourceInfo *TInfo, + SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R) { + return getSema().CreateUnaryExprOrTypeTraitExpr(TInfo, OpLoc, ExprKind, R); } - /// \brief Build a new sizeof or alignof expression with an expression - /// argument. + /// \brief Build a new sizeof, alignof or vec step expression with an + /// expression argument. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildSizeOfAlignOf(Expr *SubExpr, SourceLocation OpLoc, - bool isSizeOf, SourceRange R) { + ExprResult RebuildUnaryExprOrTypeTrait(Expr *SubExpr, SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R) { ExprResult Result - = getSema().CreateSizeOfAlignOfExpr(SubExpr, OpLoc, isSizeOf, R); + = getSema().CreateUnaryExprOrTypeTraitExpr(SubExpr, OpLoc, ExprKind, R); if (Result.isInvalid()) return ExprError(); @@ -1371,8 +1410,7 @@ public: /// Subclasses may override this routine to provide different behavior. ExprResult RebuildMemberExpr(Expr *Base, SourceLocation OpLoc, bool isArrow, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &MemberNameInfo, ValueDecl *Member, NamedDecl *FoundDecl, @@ -1382,14 +1420,17 @@ public: // We have a reference to an unnamed field. This is always the // base of an anonymous struct/union member access, i.e. the // field is always of record type. - assert(!Qualifier && "Can't have an unnamed field with a qualifier!"); + assert(!QualifierLoc && "Can't have an unnamed field with a qualifier!"); assert(Member->getType()->isRecordType() && "unnamed member not of record type?"); - if (getSema().PerformObjectMemberConversion(Base, Qualifier, - FoundDecl, Member)) + ExprResult BaseResult = + getSema().PerformObjectMemberConversion(Base, + QualifierLoc.getNestedNameSpecifier(), + FoundDecl, Member); + if (BaseResult.isInvalid()) return ExprError(); - + Base = BaseResult.take(); ExprValueKind VK = isArrow ? VK_LValue : Base->getValueKind(); MemberExpr *ME = new (getSema().Context) MemberExpr(Base, isArrow, @@ -1400,11 +1441,12 @@ public: } CXXScopeSpec SS; - if (Qualifier) { - SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange); - } + SS.Adopt(QualifierLoc); - getSema().DefaultFunctionArrayConversion(Base); + ExprResult BaseResult = getSema().DefaultFunctionArrayConversion(Base); + if (BaseResult.isInvalid()) + return ExprError(); + Base = BaseResult.take(); QualType BaseType = Base->getType(); // FIXME: this involves duplicating earlier analysis in a lot of @@ -1586,6 +1628,22 @@ public: RParenLoc); } + /// \brief Build a new generic selection expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildGenericSelectionExpr(SourceLocation KeyLoc, + SourceLocation DefaultLoc, + SourceLocation RParenLoc, + Expr *ControllingExpr, + TypeSourceInfo **Types, + Expr **Exprs, + unsigned NumAssocs) { + return getSema().CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc, + ControllingExpr, Types, Exprs, + NumAssocs); + } + /// \brief Build a new overloaded operator call expression. /// /// By default, performs semantic analysis to build the new expression. @@ -1882,6 +1940,29 @@ public: return getSema().BuildBinaryTypeTrait(Trait, StartLoc, LhsT, RhsT, RParenLoc); } + /// \brief Build a new array type trait expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildArrayTypeTrait(ArrayTypeTrait Trait, + SourceLocation StartLoc, + TypeSourceInfo *TSInfo, + Expr *DimExpr, + SourceLocation RParenLoc) { + return getSema().BuildArrayTypeTrait(Trait, StartLoc, TSInfo, DimExpr, RParenLoc); + } + + /// \brief Build a new expression trait expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildExpressionTrait(ExpressionTrait Trait, + SourceLocation StartLoc, + Expr *Queried, + SourceLocation RParenLoc) { + return getSema().BuildExpressionTrait(Trait, StartLoc, Queried, RParenLoc); + } + /// \brief Build a new (previously unresolved) declaration reference /// expression. /// @@ -1968,16 +2049,15 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildCXXDependentScopeMemberExpr(Expr *BaseE, - QualType BaseType, - bool IsArrow, - SourceLocation OperatorLoc, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + QualType BaseType, + bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &MemberNameInfo, const TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; - SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange); + SS.Adopt(QualifierLoc); return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType, OperatorLoc, IsArrow, @@ -1994,13 +2074,12 @@ public: QualType BaseType, SourceLocation OperatorLoc, bool IsArrow, - NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, + NestedNameSpecifierLoc QualifierLoc, NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs) { CXXScopeSpec SS; - SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange); + SS.Adopt(QualifierLoc); return SemaRef.BuildMemberReferenceExpr(BaseE, BaseType, OperatorLoc, IsArrow, @@ -2076,20 +2155,20 @@ public: bool IsArrow, bool IsFreeIvar) { // FIXME: We lose track of the IsFreeIvar bit. CXXScopeSpec SS; - Expr *Base = BaseArg; + ExprResult Base = getSema().Owned(BaseArg); LookupResult R(getSema(), Ivar->getDeclName(), IvarLoc, Sema::LookupMemberName); ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, /*FIME:*/IvarLoc, SS, 0, false); - if (Result.isInvalid()) + if (Result.isInvalid() || Base.isInvalid()) return ExprError(); if (Result.get()) return move(Result); - return getSema().BuildMemberReferenceExpr(Base, Base->getType(), + return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(), /*FIXME:*/IvarLoc, IsArrow, SS, /*FirstQualifierInScope=*/0, R, @@ -2104,20 +2183,20 @@ public: ObjCPropertyDecl *Property, SourceLocation PropertyLoc) { CXXScopeSpec SS; - Expr *Base = BaseArg; + ExprResult Base = getSema().Owned(BaseArg); LookupResult R(getSema(), Property->getDeclName(), PropertyLoc, Sema::LookupMemberName); bool IsArrow = false; ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, /*FIME:*/PropertyLoc, SS, 0, false); - if (Result.isInvalid()) + if (Result.isInvalid() || Base.isInvalid()) return ExprError(); if (Result.get()) return move(Result); - return getSema().BuildMemberReferenceExpr(Base, Base->getType(), + return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(), /*FIXME:*/PropertyLoc, IsArrow, SS, /*FirstQualifierInScope=*/0, @@ -2148,19 +2227,19 @@ public: ExprResult RebuildObjCIsaExpr(Expr *BaseArg, SourceLocation IsaLoc, bool IsArrow) { CXXScopeSpec SS; - Expr *Base = BaseArg; + ExprResult Base = getSema().Owned(BaseArg); LookupResult R(getSema(), &getSema().Context.Idents.get("isa"), IsaLoc, Sema::LookupMemberName); ExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, /*FIME:*/IsaLoc, SS, 0, false); - if (Result.isInvalid()) + if (Result.isInvalid() || Base.isInvalid()) return ExprError(); if (Result.get()) return move(Result); - return getSema().BuildMemberReferenceExpr(Base, Base->getType(), + return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(), /*FIXME:*/IsaLoc, IsArrow, SS, /*FirstQualifierInScope=*/0, R, @@ -2183,28 +2262,25 @@ public: // Build a reference to the __builtin_shufflevector builtin FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first); - Expr *Callee - = new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(), - VK_LValue, BuiltinLoc); - SemaRef.UsualUnaryConversions(Callee); + ExprResult Callee + = SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Builtin, Builtin->getType(), + VK_LValue, BuiltinLoc)); + Callee = SemaRef.UsualUnaryConversions(Callee.take()); + if (Callee.isInvalid()) + return ExprError(); // Build the CallExpr unsigned NumSubExprs = SubExprs.size(); Expr **Subs = (Expr **)SubExprs.release(); - CallExpr *TheCall = new (SemaRef.Context) CallExpr(SemaRef.Context, Callee, + ExprResult TheCall = SemaRef.Owned( + new (SemaRef.Context) CallExpr(SemaRef.Context, Callee.take(), Subs, NumSubExprs, Builtin->getCallResultType(), Expr::getValueKindForType(Builtin->getResultType()), - RParenLoc); - ExprResult OwnedCall(SemaRef.Owned(TheCall)); + RParenLoc)); // Type-check the __builtin_shufflevector expression. - ExprResult Result = SemaRef.SemaBuiltinShuffleVector(TheCall); - if (Result.isInvalid()) - return ExprError(); - - OwnedCall.release(); - return move(Result); + return SemaRef.SemaBuiltinShuffleVector(cast<CallExpr>(TheCall.take())); } /// \brief Build a new template argument pack expansion. @@ -2230,7 +2306,7 @@ public: return TemplateArgumentLoc(TemplateArgument( Pattern.getArgument().getAsTemplate(), NumExpansions), - Pattern.getTemplateQualifierRange(), + Pattern.getTemplateQualifierLoc(), Pattern.getTemplateNameLoc(), EllipsisLoc); @@ -2265,20 +2341,15 @@ public: } private: - QualType TransformTypeInObjectScope(QualType T, - QualType ObjectType, - NamedDecl *FirstQualifierInScope, - NestedNameSpecifier *Prefix); - - TypeSourceInfo *TransformTypeInObjectScope(TypeSourceInfo *T, - QualType ObjectType, - NamedDecl *FirstQualifierInScope, - NestedNameSpecifier *Prefix); - TypeLoc TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType, NamedDecl *FirstQualifierInScope, CXXScopeSpec &SS); + + TypeSourceInfo *TransformTypeInObjectScope(TypeSourceInfo *TSInfo, + QualType ObjectType, + NamedDecl *FirstQualifierInScope, + CXXScopeSpec &SS); }; template<typename Derived> @@ -2426,99 +2497,6 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs, } template<typename Derived> -NestedNameSpecifier * -TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, - SourceRange Range, - QualType ObjectType, - NamedDecl *FirstQualifierInScope) { - NestedNameSpecifier *Prefix = NNS->getPrefix(); - - // Transform the prefix of this nested name specifier. - if (Prefix) { - Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range, - ObjectType, - FirstQualifierInScope); - if (!Prefix) - return 0; - } - - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - if (Prefix) { - // The object type and qualifier-in-scope really apply to the - // leftmost entity. - ObjectType = QualType(); - FirstQualifierInScope = 0; - } - - assert((Prefix || !ObjectType.isNull()) && - "Identifier nested-name-specifier with no prefix or object type"); - if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix() && - ObjectType.isNull()) - return NNS; - - return getDerived().RebuildNestedNameSpecifier(Prefix, Range, - *NNS->getAsIdentifier(), - ObjectType, - FirstQualifierInScope); - - case NestedNameSpecifier::Namespace: { - NamespaceDecl *NS - = cast_or_null<NamespaceDecl>( - getDerived().TransformDecl(Range.getBegin(), - NNS->getAsNamespace())); - if (!getDerived().AlwaysRebuild() && - Prefix == NNS->getPrefix() && - NS == NNS->getAsNamespace()) - return NNS; - - return getDerived().RebuildNestedNameSpecifier(Prefix, Range, NS); - } - - case NestedNameSpecifier::NamespaceAlias: { - NamespaceAliasDecl *Alias - = cast_or_null<NamespaceAliasDecl>( - getDerived().TransformDecl(Range.getBegin(), - NNS->getAsNamespaceAlias())); - if (!getDerived().AlwaysRebuild() && - Prefix == NNS->getPrefix() && - Alias == NNS->getAsNamespaceAlias()) - return NNS; - - return getDerived().RebuildNestedNameSpecifier(Prefix, Range, Alias); - } - - case NestedNameSpecifier::Global: - // There is no meaningful transformation that one could perform on the - // global scope. - return NNS; - - case NestedNameSpecifier::TypeSpecWithTemplate: - case NestedNameSpecifier::TypeSpec: { - TemporaryBase Rebase(*this, Range.getBegin(), DeclarationName()); - QualType T = TransformTypeInObjectScope(QualType(NNS->getAsType(), 0), - ObjectType, - FirstQualifierInScope, - Prefix); - if (T.isNull()) - return 0; - - if (!getDerived().AlwaysRebuild() && - Prefix == NNS->getPrefix() && - T == QualType(NNS->getAsType(), 0)) - return NNS; - - return getDerived().RebuildNestedNameSpecifier(Prefix, Range, - NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, - T); - } - } - - // Required to silence a GCC warning - return 0; -} - -template<typename Derived> NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc( NestedNameSpecifierLoc NNS, @@ -2594,10 +2572,11 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc( << TL.getType() << SS.getRange(); return NestedNameSpecifierLoc(); } - } + } - // The qualifier-in-scope only applies to the leftmost entity. + // The qualifier-in-scope and object type only apply to the leftmost entity. FirstQualifierInScope = 0; + ObjectType = QualType(); } // Don't rebuild the nested-name-specifier if we don't have to. @@ -2669,89 +2648,73 @@ TreeTransform<Derived> template<typename Derived> TemplateName -TreeTransform<Derived>::TransformTemplateName(TemplateName Name, +TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS, + TemplateName Name, + SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope) { - SourceLocation Loc = getDerived().getBaseLocation(); - if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { - NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(), - /*FIXME*/ SourceRange(Loc), - ObjectType, - FirstQualifierInScope); - if (!NNS) + TemplateDecl *Template = QTN->getTemplateDecl(); + assert(Template && "qualified template name must refer to a template"); + + TemplateDecl *TransTemplate + = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc, + Template)); + if (!TransTemplate) return TemplateName(); - - if (TemplateDecl *Template = QTN->getTemplateDecl()) { - TemplateDecl *TransTemplate - = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Loc, Template)); - if (!TransTemplate) - return TemplateName(); - - if (!getDerived().AlwaysRebuild() && - NNS == QTN->getQualifier() && - TransTemplate == Template) - return Name; - - return getDerived().RebuildTemplateName(NNS, QTN->hasTemplateKeyword(), - TransTemplate); - } - - // These should be getting filtered out before they make it into the AST. - llvm_unreachable("overloaded template name survived to here"); + + if (!getDerived().AlwaysRebuild() && + SS.getScopeRep() == QTN->getQualifier() && + TransTemplate == Template) + return Name; + + return getDerived().RebuildTemplateName(SS, QTN->hasTemplateKeyword(), + TransTemplate); } - + if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { - NestedNameSpecifier *NNS = DTN->getQualifier(); - if (NNS) { - NNS = getDerived().TransformNestedNameSpecifier(NNS, - /*FIXME:*/SourceRange(Loc), - ObjectType, - FirstQualifierInScope); - if (!NNS) return TemplateName(); - + if (SS.getScopeRep()) { // These apply to the scope specifier, not the template. ObjectType = QualType(); FirstQualifierInScope = 0; - } - + } + if (!getDerived().AlwaysRebuild() && - NNS == DTN->getQualifier() && + SS.getScopeRep() == DTN->getQualifier() && ObjectType.isNull()) return Name; - + if (DTN->isIdentifier()) { - // FIXME: Bad range - SourceRange QualifierRange(getDerived().getBaseLocation()); - return getDerived().RebuildTemplateName(NNS, QualifierRange, + return getDerived().RebuildTemplateName(SS, *DTN->getIdentifier(), + NameLoc, ObjectType, FirstQualifierInScope); } - return getDerived().RebuildTemplateName(NNS, DTN->getOperator(), + return getDerived().RebuildTemplateName(SS, DTN->getOperator(), NameLoc, ObjectType); } - + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { TemplateDecl *TransTemplate - = cast_or_null<TemplateDecl>(getDerived().TransformDecl(Loc, Template)); + = cast_or_null<TemplateDecl>(getDerived().TransformDecl(NameLoc, + Template)); if (!TransTemplate) return TemplateName(); - + if (!getDerived().AlwaysRebuild() && TransTemplate == Template) return Name; - + return TemplateName(TransTemplate); } - + if (SubstTemplateTemplateParmPackStorage *SubstPack - = Name.getAsSubstTemplateTemplateParmPack()) { + = Name.getAsSubstTemplateTemplateParmPack()) { TemplateTemplateParmDecl *TransParam - = cast_or_null<TemplateTemplateParmDecl>( - getDerived().TransformDecl(Loc, SubstPack->getParameterPack())); + = cast_or_null<TemplateTemplateParmDecl>( + getDerived().TransformDecl(NameLoc, SubstPack->getParameterPack())); if (!TransParam) return TemplateName(); @@ -2785,12 +2748,25 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc( break; case TemplateArgument::Template: - Output = TemplateArgumentLoc(Arg, SourceRange(), Loc); - break; - - case TemplateArgument::TemplateExpansion: - Output = TemplateArgumentLoc(Arg, SourceRange(), Loc, Loc); + case TemplateArgument::TemplateExpansion: { + NestedNameSpecifierLocBuilder Builder; + TemplateName Template = Arg.getAsTemplate(); + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) + Builder.MakeTrivial(SemaRef.Context, DTN->getQualifier(), Loc); + else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + Builder.MakeTrivial(SemaRef.Context, QTN->getQualifier(), Loc); + + if (Arg.getKind() == TemplateArgument::Template) + Output = TemplateArgumentLoc(Arg, + Builder.getWithLocInContext(SemaRef.Context), + Loc); + else + Output = TemplateArgumentLoc(Arg, + Builder.getWithLocInContext(SemaRef.Context), + Loc, Loc); + break; + } case TemplateArgument::Expression: Output = TemplateArgumentLoc(Arg, Arg.getAsExpr()); @@ -2849,14 +2825,22 @@ bool TreeTransform<Derived>::TransformTemplateArgument( } case TemplateArgument::Template: { - TemporaryBase Rebase(*this, Input.getLocation(), DeclarationName()); + NestedNameSpecifierLoc QualifierLoc = Input.getTemplateQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); + if (!QualifierLoc) + return true; + } + + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); TemplateName Template - = getDerived().TransformTemplateName(Arg.getAsTemplate()); + = getDerived().TransformTemplateName(SS, Arg.getAsTemplate(), + Input.getTemplateNameLoc()); if (Template.isNull()) return true; - Output = TemplateArgumentLoc(TemplateArgument(Template), - Input.getTemplateQualifierRange(), + Output = TemplateArgumentLoc(TemplateArgument(Template), QualifierLoc, Input.getTemplateNameLoc()); return false; } @@ -2872,8 +2856,7 @@ bool TreeTransform<Derived>::TransformTemplateArgument( Expr *InputExpr = Input.getSourceExpression(); if (!InputExpr) InputExpr = Input.getArgument().getAsExpr(); - ExprResult E - = getDerived().TransformExpr(InputExpr); + ExprResult E = getDerived().TransformExpr(InputExpr); if (E.isInvalid()) return true; Output = TemplateArgumentLoc(TemplateArgument(E.take()), E.take()); return false; @@ -3177,112 +3160,87 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, return Result; } -/// \brief Transforms a type that was written in a scope specifier, -/// given an object type, the results of unqualified lookup, and -/// an already-instantiated prefix. -/// -/// The object type is provided iff the scope specifier qualifies the -/// member of a dependent member-access expression. The prefix is -/// provided iff the the scope specifier in which this appears has a -/// prefix. -/// -/// This is private to TreeTransform. template<typename Derived> -QualType -TreeTransform<Derived>::TransformTypeInObjectScope(QualType T, - QualType ObjectType, - NamedDecl *UnqualLookup, - NestedNameSpecifier *Prefix) { - if (getDerived().AlreadyTransformed(T)) - return T; - - TypeSourceInfo *TSI = - SemaRef.Context.getTrivialTypeSourceInfo(T, getDerived().getBaseLocation()); - - TSI = getDerived().TransformTypeInObjectScope(TSI, ObjectType, - UnqualLookup, Prefix); - if (!TSI) return QualType(); - return TSI->getType(); -} - -template<typename Derived> -TypeSourceInfo * -TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSI, +TypeLoc +TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType, NamedDecl *UnqualLookup, - NestedNameSpecifier *Prefix) { - // TODO: in some cases, we might have some verification to do here. - if (ObjectType.isNull()) - return getDerived().TransformType(TSI); - - QualType T = TSI->getType(); + CXXScopeSpec &SS) { + QualType T = TL.getType(); if (getDerived().AlreadyTransformed(T)) - return TSI; - + return TL; + TypeLocBuilder TLB; QualType Result; - + if (isa<TemplateSpecializationType>(T)) { - TemplateSpecializationTypeLoc TL - = cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc()); - + TemplateSpecializationTypeLoc SpecTL + = cast<TemplateSpecializationTypeLoc>(TL); + TemplateName Template = - getDerived().TransformTemplateName(TL.getTypePtr()->getTemplateName(), + getDerived().TransformTemplateName(SS, + SpecTL.getTypePtr()->getTemplateName(), + SpecTL.getTemplateNameLoc(), ObjectType, UnqualLookup); - if (Template.isNull()) return 0; - - Result = getDerived() - .TransformTemplateSpecializationType(TLB, TL, Template); + if (Template.isNull()) + return TypeLoc(); + + Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL, + Template); } else if (isa<DependentTemplateSpecializationType>(T)) { - DependentTemplateSpecializationTypeLoc TL - = cast<DependentTemplateSpecializationTypeLoc>(TSI->getTypeLoc()); - - Result = getDerived() - .TransformDependentTemplateSpecializationType(TLB, TL, Prefix); + DependentTemplateSpecializationTypeLoc SpecTL + = cast<DependentTemplateSpecializationTypeLoc>(TL); + + TemplateName Template + = getDerived().RebuildTemplateName(SS, + *SpecTL.getTypePtr()->getIdentifier(), + SpecTL.getNameLoc(), + ObjectType, UnqualLookup); + if (Template.isNull()) + return TypeLoc(); + + Result = getDerived().TransformDependentTemplateSpecializationType(TLB, + SpecTL, + Template, + SS); } else { // Nothing special needs to be done for these. - Result = getDerived().TransformType(TLB, TSI->getTypeLoc()); + Result = getDerived().TransformType(TLB, TL); } - - if (Result.isNull()) return 0; - return TLB.getTypeSourceInfo(SemaRef.Context, Result); + + if (Result.isNull()) + return TypeLoc(); + + return TLB.getTypeSourceInfo(SemaRef.Context, Result)->getTypeLoc(); } template<typename Derived> -TypeLoc -TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL, +TypeSourceInfo * +TreeTransform<Derived>::TransformTypeInObjectScope(TypeSourceInfo *TSInfo, QualType ObjectType, NamedDecl *UnqualLookup, CXXScopeSpec &SS) { // FIXME: Painfully copy-paste from the above! - // TODO: in some cases, we might have some verification to do here. - if (ObjectType.isNull()) { - TypeLocBuilder TLB; - TLB.reserve(TL.getFullDataSize()); - QualType Result = getDerived().TransformType(TLB, TL); - if (Result.isNull()) - return TypeLoc(); - - return TLB.getTypeSourceInfo(SemaRef.Context, Result)->getTypeLoc(); - } - - QualType T = TL.getType(); + QualType T = TSInfo->getType(); if (getDerived().AlreadyTransformed(T)) - return TL; + return TSInfo; TypeLocBuilder TLB; QualType Result; + TypeLoc TL = TSInfo->getTypeLoc(); if (isa<TemplateSpecializationType>(T)) { TemplateSpecializationTypeLoc SpecTL = cast<TemplateSpecializationTypeLoc>(TL); - TemplateName Template = - getDerived().TransformTemplateName(SpecTL.getTypePtr()->getTemplateName(), + TemplateName Template + = getDerived().TransformTemplateName(SS, + SpecTL.getTypePtr()->getTemplateName(), + SpecTL.getTemplateNameLoc(), ObjectType, UnqualLookup); if (Template.isNull()) - return TypeLoc(); + return 0; Result = getDerived().TransformTemplateSpecializationType(TLB, SpecTL, Template); @@ -3290,18 +3248,27 @@ TreeTransform<Derived>::TransformTypeInObjectScope(TypeLoc TL, DependentTemplateSpecializationTypeLoc SpecTL = cast<DependentTemplateSpecializationTypeLoc>(TL); + TemplateName Template + = getDerived().RebuildTemplateName(SS, + *SpecTL.getTypePtr()->getIdentifier(), + SpecTL.getNameLoc(), + ObjectType, UnqualLookup); + if (Template.isNull()) + return 0; + Result = getDerived().TransformDependentTemplateSpecializationType(TLB, - SpecTL, - SS.getScopeRep()); + SpecTL, + Template, + SS); } else { // Nothing special needs to be done for these. Result = getDerived().TransformType(TLB, TL); } if (Result.isNull()) - return TypeLoc(); + return 0; - return TLB.getTypeSourceInfo(SemaRef.Context, Result)->getTypeLoc(); + return TLB.getTypeSourceInfo(SemaRef.Context, Result); } template <class TyLoc> static inline @@ -3438,23 +3405,34 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB, MemberPointerTypeLoc TL) { - const MemberPointerType *T = TL.getTypePtr(); - QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); if (PointeeType.isNull()) return QualType(); - // TODO: preserve source information for this. - QualType ClassType - = getDerived().TransformType(QualType(T->getClass(), 0)); - if (ClassType.isNull()) - return QualType(); + TypeSourceInfo* OldClsTInfo = TL.getClassTInfo(); + TypeSourceInfo* NewClsTInfo = 0; + if (OldClsTInfo) { + NewClsTInfo = getDerived().TransformType(OldClsTInfo); + if (!NewClsTInfo) + return QualType(); + } + + const MemberPointerType *T = TL.getTypePtr(); + QualType OldClsType = QualType(T->getClass(), 0); + QualType NewClsType; + if (NewClsTInfo) + NewClsType = NewClsTInfo->getType(); + else { + NewClsType = getDerived().TransformType(OldClsType); + if (NewClsType.isNull()) + return QualType(); + } QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || PointeeType != T->getPointeeType() || - ClassType != QualType(T->getClass(), 0)) { - Result = getDerived().RebuildMemberPointerType(PointeeType, ClassType, + NewClsType != OldClsType) { + Result = getDerived().RebuildMemberPointerType(PointeeType, NewClsType, TL.getStarLoc()); if (Result.isNull()) return QualType(); @@ -3462,6 +3440,7 @@ TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB, MemberPointerTypeLoc NewTL = TLB.push<MemberPointerTypeLoc>(Result); NewTL.setSigilLoc(TL.getSigilLoc()); + NewTL.setClassTInfo(NewClsTInfo); return Result; } @@ -3707,6 +3686,7 @@ QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB, template<typename Derived> ParmVarDecl * TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm, + int indexAdjustment, llvm::Optional<unsigned> NumExpansions) { TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo(); TypeSourceInfo *NewDI = 0; @@ -3741,18 +3721,22 @@ TreeTransform<Derived>::TransformFunctionTypeParam(ParmVarDecl *OldParm, if (!NewDI) return 0; - if (NewDI == OldDI) + if (NewDI == OldDI && indexAdjustment == 0) return OldParm; - else - return ParmVarDecl::Create(SemaRef.Context, - OldParm->getDeclContext(), - OldParm->getLocation(), - OldParm->getIdentifier(), - NewDI->getType(), - NewDI, - OldParm->getStorageClass(), - OldParm->getStorageClassAsWritten(), - /* DefArg */ NULL); + + ParmVarDecl *newParm = ParmVarDecl::Create(SemaRef.Context, + OldParm->getDeclContext(), + OldParm->getInnerLocStart(), + OldParm->getLocation(), + OldParm->getIdentifier(), + NewDI->getType(), + NewDI, + OldParm->getStorageClass(), + OldParm->getStorageClassAsWritten(), + /* DefArg */ NULL); + newParm->setScopeInfo(OldParm->getFunctionScopeDepth(), + OldParm->getFunctionScopeIndex() + indexAdjustment); + return newParm; } template<typename Derived> @@ -3762,9 +3746,14 @@ bool TreeTransform<Derived>:: const QualType *ParamTypes, llvm::SmallVectorImpl<QualType> &OutParamTypes, llvm::SmallVectorImpl<ParmVarDecl*> *PVars) { + int indexAdjustment = 0; + for (unsigned i = 0; i != NumParams; ++i) { if (ParmVarDecl *OldParm = Params[i]) { + assert(OldParm->getFunctionScopeIndex() == i); + llvm::Optional<unsigned> NumExpansions; + ParmVarDecl *NewParm = 0; if (OldParm->isParameterPack()) { // We have a function parameter pack that may need to be expanded. llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; @@ -3774,7 +3763,8 @@ bool TreeTransform<Derived>:: PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(TL); TypeLoc Pattern = ExpansionTL.getPatternLoc(); SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded); - + assert(Unexpanded.size() > 0 && "Could not find parameter packs!"); + // Determine whether we should expand the parameter packs. bool ShouldExpand = false; bool RetainExpansion = false; @@ -3799,6 +3789,7 @@ bool TreeTransform<Derived>:: Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm, + indexAdjustment++, OrigNumExpansions); if (!NewParm) return true; @@ -3814,6 +3805,7 @@ bool TreeTransform<Derived>:: ForgetPartiallySubstitutedPackRAII Forget(getDerived()); ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm, + indexAdjustment++, OrigNumExpansions); if (!NewParm) return true; @@ -3823,17 +3815,28 @@ bool TreeTransform<Derived>:: PVars->push_back(NewParm); } + // The next parameter should have the same adjustment as the + // last thing we pushed, but we post-incremented indexAdjustment + // on every push. Also, if we push nothing, the adjustment should + // go down by one. + indexAdjustment--; + // We're done with the pack expansion. continue; } // We'll substitute the parameter now without expanding the pack // expansion. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + NewParm = getDerived().TransformFunctionTypeParam(OldParm, + indexAdjustment, + NumExpansions); + } else { + NewParm = getDerived().TransformFunctionTypeParam(OldParm, + indexAdjustment, + llvm::Optional<unsigned>()); } - - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); - ParmVarDecl *NewParm = getDerived().TransformFunctionTypeParam(OldParm, - NumExpansions); + if (!NewParm) return true; @@ -3848,6 +3851,7 @@ bool TreeTransform<Derived>:: QualType OldType = ParamTypes[i]; bool IsPackExpansion = false; llvm::Optional<unsigned> NumExpansions; + QualType NewType; if (const PackExpansionType *Expansion = dyn_cast<PackExpansionType>(OldType)) { // We have a function parameter pack that may need to be expanded. @@ -3902,10 +3906,12 @@ bool TreeTransform<Derived>:: // expansion. OldType = Expansion->getPattern(); IsPackExpansion = true; + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + NewType = getDerived().TransformType(OldType); + } else { + NewType = getDerived().TransformType(OldType); } - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); - QualType NewType = getDerived().TransformType(OldType); if (NewType.isNull()) return true; @@ -3918,8 +3924,16 @@ bool TreeTransform<Derived>:: PVars->push_back(0); } - return false; +#ifndef NDEBUG + if (PVars) { + for (unsigned i = 0, e = PVars->size(); i != e; ++i) + if (ParmVarDecl *parm = (*PVars)[i]) + assert(parm->getFunctionScopeIndex() == i); } +#endif + + return false; +} template<typename Derived> QualType @@ -3983,8 +3997,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, } FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result); - NewTL.setLParenLoc(TL.getLParenLoc()); - NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); + NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); NewTL.setTrailingReturn(TL.getTrailingReturn()); for (unsigned i = 0, e = NewTL.getNumArgs(); i != e; ++i) NewTL.setArg(i, ParamDecls[i]); @@ -4007,8 +4021,8 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType( Result = getDerived().RebuildFunctionNoProtoType(ResultType); FunctionNoProtoTypeLoc NewTL = TLB.push<FunctionNoProtoTypeLoc>(Result); - NewTL.setLParenLoc(TL.getLParenLoc()); - NewTL.setRParenLoc(TL.getRParenLoc()); + NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); + NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); NewTL.setTrailingReturn(false); return Result; @@ -4041,9 +4055,9 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { const TypedefType *T = TL.getTypePtr(); - TypedefDecl *Typedef - = cast_or_null<TypedefDecl>(getDerived().TransformDecl(TL.getNameLoc(), - T->getDecl())); + TypedefNameDecl *Typedef + = cast_or_null<TypedefNameDecl>(getDerived().TransformDecl(TL.getNameLoc(), + T->getDecl())); if (!Typedef) return QualType(); @@ -4236,7 +4250,28 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType( TypeLocBuilder &TLB, SubstTemplateTypeParmTypeLoc TL) { - return TransformTypeSpecType(TLB, TL); + const SubstTemplateTypeParmType *T = TL.getTypePtr(); + + // Substitute into the replacement type, which itself might involve something + // that needs to be transformed. This only tends to occur with default + // template arguments of template template parameters. + TemporaryBase Rebase(*this, TL.getNameLoc(), DeclarationName()); + QualType Replacement = getDerived().TransformType(T->getReplacementType()); + if (Replacement.isNull()) + return QualType(); + + // Always canonicalize the replacement type. + Replacement = SemaRef.Context.getCanonicalType(Replacement); + QualType Result + = SemaRef.Context.getSubstTemplateTypeParmType(T->getReplacedParameter(), + Replacement); + + // Propagate type-source information. + SubstTemplateTypeParmTypeLoc NewTL + = TLB.push<SubstTemplateTypeParmTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } template<typename Derived> @@ -4252,8 +4287,12 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( TemplateSpecializationTypeLoc TL) { const TemplateSpecializationType *T = TL.getTypePtr(); + // The nested-name-specifier never matters in a TemplateSpecializationType, + // because we can't have a dependent nested-name-specifier anyway. + CXXScopeSpec SS; TemplateName Template - = getDerived().TransformTemplateName(T->getTemplateName()); + = getDerived().TransformTemplateName(SS, T->getTemplateName(), + TL.getTemplateNameLoc()); if (Template.isNull()) return QualType(); @@ -4362,18 +4401,76 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( return Result; } +template <typename Derived> +QualType TreeTransform<Derived>::TransformDependentTemplateSpecializationType( + TypeLocBuilder &TLB, + DependentTemplateSpecializationTypeLoc TL, + TemplateName Template, + CXXScopeSpec &SS) { + TemplateArgumentListInfo NewTemplateArgs; + NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); + NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); + typedef TemplateArgumentLocContainerIterator< + DependentTemplateSpecializationTypeLoc> ArgIterator; + if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), + ArgIterator(TL, TL.getNumArgs()), + NewTemplateArgs)) + return QualType(); + + // FIXME: maybe don't rebuild if all the template arguments are the same. + + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { + QualType Result + = getSema().Context.getDependentTemplateSpecializationType( + TL.getTypePtr()->getKeyword(), + DTN->getQualifier(), + DTN->getIdentifier(), + NewTemplateArgs); + + DependentTemplateSpecializationTypeLoc NewTL + = TLB.push<DependentTemplateSpecializationTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getKeywordLoc()); + + NewTL.setQualifierLoc(SS.getWithLocInContext(SemaRef.Context)); + NewTL.setNameLoc(TL.getNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) + NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); + return Result; + } + + QualType Result + = getDerived().RebuildTemplateSpecializationType(Template, + TL.getNameLoc(), + NewTemplateArgs); + + if (!Result.isNull()) { + /// FIXME: Wrap this in an elaborated-type-specifier? + TemplateSpecializationTypeLoc NewTL + = TLB.push<TemplateSpecializationTypeLoc>(Result); + NewTL.setTemplateNameLoc(TL.getNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) + NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); + } + + return Result; +} + template<typename Derived> QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, ElaboratedTypeLoc TL) { const ElaboratedType *T = TL.getTypePtr(); - NestedNameSpecifier *NNS = 0; + NestedNameSpecifierLoc QualifierLoc; // NOTE: the qualifier in an ElaboratedType is optional. - if (T->getQualifier() != 0) { - NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - TL.getQualifierRange()); - if (!NNS) + if (TL.getQualifierLoc()) { + QualifierLoc + = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); + if (!QualifierLoc) return QualType(); } @@ -4383,18 +4480,18 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || - NNS != T->getQualifier() || + QualifierLoc != TL.getQualifierLoc() || NamedT != T->getNamedType()) { Result = getDerived().RebuildElaboratedType(TL.getKeywordLoc(), - T->getKeyword(), NNS, NamedT); + T->getKeyword(), + QualifierLoc, NamedT); if (Result.isNull()) return QualType(); } ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); NewTL.setKeywordLoc(TL.getKeywordLoc()); - NewTL.setQualifierRange(TL.getQualifierRange()); - + NewTL.setQualifierLoc(QualifierLoc); return Result; } @@ -4462,17 +4559,16 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB, DependentNameTypeLoc TL) { const DependentNameType *T = TL.getTypePtr(); - NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - TL.getQualifierRange()); - if (!NNS) + NestedNameSpecifierLoc QualifierLoc + = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); + if (!QualifierLoc) return QualType(); QualType Result - = getDerived().RebuildDependentNameType(T->getKeyword(), NNS, - T->getIdentifier(), + = getDerived().RebuildDependentNameType(T->getKeyword(), TL.getKeywordLoc(), - TL.getQualifierRange(), + QualifierLoc, + T->getIdentifier(), TL.getNameLoc()); if (Result.isNull()) return QualType(); @@ -4483,11 +4579,11 @@ QualType TreeTransform<Derived>::TransformDependentNameType(TypeLocBuilder &TLB, ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); NewTL.setKeywordLoc(TL.getKeywordLoc()); - NewTL.setQualifierRange(TL.getQualifierRange()); + NewTL.setQualifierLoc(QualifierLoc); } else { DependentNameTypeLoc NewTL = TLB.push<DependentNameTypeLoc>(Result); NewTL.setKeywordLoc(TL.getKeywordLoc()); - NewTL.setQualifierRange(TL.getQualifierRange()); + NewTL.setQualifierLoc(QualifierLoc); NewTL.setNameLoc(TL.getNameLoc()); } return Result; @@ -4497,65 +4593,79 @@ template<typename Derived> QualType TreeTransform<Derived>:: TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL) { - const DependentTemplateSpecializationType *T = TL.getTypePtr(); - - NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - TL.getQualifierRange()); - if (!NNS) - return QualType(); - + NestedNameSpecifierLoc QualifierLoc; + if (TL.getQualifierLoc()) { + QualifierLoc + = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); + if (!QualifierLoc) + return QualType(); + } + return getDerived() - .TransformDependentTemplateSpecializationType(TLB, TL, NNS); + .TransformDependentTemplateSpecializationType(TLB, TL, QualifierLoc); } template<typename Derived> QualType TreeTransform<Derived>:: - TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, - DependentTemplateSpecializationTypeLoc TL, - NestedNameSpecifier *NNS) { +TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, + DependentTemplateSpecializationTypeLoc TL, + NestedNameSpecifierLoc QualifierLoc) { const DependentTemplateSpecializationType *T = TL.getTypePtr(); - + TemplateArgumentListInfo NewTemplateArgs; NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); - - // FIXME: Nested-name-specifier source location info! + typedef TemplateArgumentLocContainerIterator< - DependentTemplateSpecializationTypeLoc> ArgIterator; + DependentTemplateSpecializationTypeLoc> ArgIterator; if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), ArgIterator(TL, TL.getNumArgs()), NewTemplateArgs)) return QualType(); - + QualType Result = getDerived().RebuildDependentTemplateSpecializationType(T->getKeyword(), - NNS, - TL.getQualifierRange(), + QualifierLoc, T->getIdentifier(), - TL.getNameLoc(), - NewTemplateArgs); + TL.getNameLoc(), + NewTemplateArgs); if (Result.isNull()) return QualType(); - + if (const ElaboratedType *ElabT = dyn_cast<ElaboratedType>(Result)) { QualType NamedT = ElabT->getNamedType(); - + // Copy information relevant to the template specialization. TemplateSpecializationTypeLoc NamedTL = TLB.push<TemplateSpecializationTypeLoc>(NamedT); + NamedTL.setTemplateNameLoc(TL.getNameLoc()); NamedTL.setLAngleLoc(TL.getLAngleLoc()); NamedTL.setRAngleLoc(TL.getRAngleLoc()); - for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) - NamedTL.setArgLocInfo(I, TL.getArgLocInfo(I)); - + for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I) + NamedTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo()); + // Copy information relevant to the elaborated type. ElaboratedTypeLoc NewTL = TLB.push<ElaboratedTypeLoc>(Result); NewTL.setKeywordLoc(TL.getKeywordLoc()); - NewTL.setQualifierRange(TL.getQualifierRange()); + NewTL.setQualifierLoc(QualifierLoc); + } else if (isa<DependentTemplateSpecializationType>(Result)) { + DependentTemplateSpecializationTypeLoc SpecTL + = TLB.push<DependentTemplateSpecializationTypeLoc>(Result); + SpecTL.setKeywordLoc(TL.getKeywordLoc()); + SpecTL.setQualifierLoc(QualifierLoc); + SpecTL.setNameLoc(TL.getNameLoc()); + SpecTL.setLAngleLoc(TL.getLAngleLoc()); + SpecTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I) + SpecTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo()); } else { - TypeLoc NewTL(Result, TL.getOpaqueData()); - TLB.pushFullCopy(NewTL); + TemplateSpecializationTypeLoc SpecTL + = TLB.push<TemplateSpecializationTypeLoc>(Result); + SpecTL.setTemplateNameLoc(TL.getNameLoc()); + SpecTL.setLAngleLoc(TL.getLAngleLoc()); + SpecTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I) + SpecTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo()); } return Result; } @@ -5304,8 +5414,9 @@ TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) { return StmtError(); Var = getDerived().RebuildExceptionDecl(ExceptionDecl, T, - ExceptionDecl->getIdentifier(), - ExceptionDecl->getLocation()); + ExceptionDecl->getInnerLocStart(), + ExceptionDecl->getLocation(), + ExceptionDecl->getIdentifier()); if (!Var || Var->isInvalidDecl()) return StmtError(); } @@ -5356,6 +5467,112 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) { move_arg(Handlers)); } +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { + StmtResult Range = getDerived().TransformStmt(S->getRangeStmt()); + if (Range.isInvalid()) + return StmtError(); + + StmtResult BeginEnd = getDerived().TransformStmt(S->getBeginEndStmt()); + if (BeginEnd.isInvalid()) + return StmtError(); + + ExprResult Cond = getDerived().TransformExpr(S->getCond()); + if (Cond.isInvalid()) + return StmtError(); + + ExprResult Inc = getDerived().TransformExpr(S->getInc()); + if (Inc.isInvalid()) + return StmtError(); + + StmtResult LoopVar = getDerived().TransformStmt(S->getLoopVarStmt()); + if (LoopVar.isInvalid()) + return StmtError(); + + StmtResult NewStmt = S; + if (getDerived().AlwaysRebuild() || + Range.get() != S->getRangeStmt() || + BeginEnd.get() != S->getBeginEndStmt() || + Cond.get() != S->getCond() || + Inc.get() != S->getInc() || + LoopVar.get() != S->getLoopVarStmt()) + NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), + S->getColonLoc(), Range.get(), + BeginEnd.get(), Cond.get(), + Inc.get(), LoopVar.get(), + S->getRParenLoc()); + + StmtResult Body = getDerived().TransformStmt(S->getBody()); + if (Body.isInvalid()) + return StmtError(); + + // Body has changed but we didn't rebuild the for-range statement. Rebuild + // it now so we have a new statement to attach the body to. + if (Body.get() != S->getBody() && NewStmt.get() == S) + NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), + S->getColonLoc(), Range.get(), + BeginEnd.get(), Cond.get(), + Inc.get(), LoopVar.get(), + S->getRParenLoc()); + + if (NewStmt.get() == S) + return SemaRef.Owned(S); + + return FinishCXXForRangeStmt(NewStmt.get(), Body.get()); +} + +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformSEHTryStmt(SEHTryStmt *S) { + StmtResult TryBlock; // = getDerived().TransformCompoundStmt(S->getTryBlock()); + if(TryBlock.isInvalid()) return StmtError(); + + StmtResult Handler = getDerived().TransformSEHHandler(S->getHandler()); + if(!getDerived().AlwaysRebuild() && + TryBlock.get() == S->getTryBlock() && + Handler.get() == S->getHandler()) + return SemaRef.Owned(S); + + return getDerived().RebuildSEHTryStmt(S->getIsCXXTry(), + S->getTryLoc(), + TryBlock.take(), + Handler.take()); +} + +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformSEHFinallyStmt(SEHFinallyStmt *S) { + StmtResult Block; // = getDerived().TransformCompoundStatement(S->getBlock()); + if(Block.isInvalid()) return StmtError(); + + return getDerived().RebuildSEHFinallyStmt(S->getFinallyLoc(), + Block.take()); +} + +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformSEHExceptStmt(SEHExceptStmt *S) { + ExprResult FilterExpr = getDerived().TransformExpr(S->getFilterExpr()); + if(FilterExpr.isInvalid()) return StmtError(); + + StmtResult Block; // = getDerived().TransformCompoundStatement(S->getBlock()); + if(Block.isInvalid()) return StmtError(); + + return getDerived().RebuildSEHExceptStmt(S->getExceptLoc(), + FilterExpr.take(), + Block.take()); +} + +template<typename Derived> +StmtResult +TreeTransform<Derived>::TransformSEHHandler(Stmt *Handler) { + if(isa<SEHFinallyStmt>(Handler)) + return getDerived().TransformSEHFinallyStmt(cast<SEHFinallyStmt>(Handler)); + else + return getDerived().TransformSEHExceptStmt(cast<SEHExceptStmt>(Handler)); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// @@ -5368,11 +5585,11 @@ TreeTransform<Derived>::TransformPredefinedExpr(PredefinedExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { - NestedNameSpecifier *Qualifier = 0; - if (E->getQualifier()) { - Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); - if (!Qualifier) + NestedNameSpecifierLoc QualifierLoc; + if (E->getQualifierLoc()) { + QualifierLoc + = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); + if (!QualifierLoc) return ExprError(); } @@ -5390,7 +5607,7 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { } if (!getDerived().AlwaysRebuild() && - Qualifier == E->getQualifier() && + QualifierLoc == E->getQualifierLoc() && ND == E->getDecl() && NameInfo.getName() == E->getDecl()->getDeclName() && !E->hasExplicitTemplateArgs()) { @@ -5413,8 +5630,8 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) { return ExprError(); } - return getDerived().RebuildDeclRefExpr(Qualifier, E->getQualifierRange(), - ND, NameInfo, TemplateArgs); + return getDerived().RebuildDeclRefExpr(QualifierLoc, ND, NameInfo, + TemplateArgs); } template<typename Derived> @@ -5449,6 +5666,42 @@ TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) { + ExprResult ControllingExpr = + getDerived().TransformExpr(E->getControllingExpr()); + if (ControllingExpr.isInvalid()) + return ExprError(); + + llvm::SmallVector<Expr *, 4> AssocExprs; + llvm::SmallVector<TypeSourceInfo *, 4> AssocTypes; + for (unsigned i = 0; i != E->getNumAssocs(); ++i) { + TypeSourceInfo *TS = E->getAssocTypeSourceInfo(i); + if (TS) { + TypeSourceInfo *AssocType = getDerived().TransformType(TS); + if (!AssocType) + return ExprError(); + AssocTypes.push_back(AssocType); + } else { + AssocTypes.push_back(0); + } + + ExprResult AssocExpr = getDerived().TransformExpr(E->getAssocExpr(i)); + if (AssocExpr.isInvalid()) + return ExprError(); + AssocExprs.push_back(AssocExpr.release()); + } + + return getDerived().RebuildGenericSelectionExpr(E->getGenericLoc(), + E->getDefaultLoc(), + E->getRParenLoc(), + ControllingExpr.release(), + AssocTypes.data(), + AssocExprs.data(), + E->getNumAssocs()); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) { ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); if (SubExpr.isInvalid()) @@ -5498,8 +5751,8 @@ TreeTransform<Derived>::TransformOffsetOfExpr(OffsetOfExpr *E) { const Node &ON = E->getComponent(I); Component Comp; Comp.isBrackets = true; - Comp.LocStart = ON.getRange().getBegin(); - Comp.LocEnd = ON.getRange().getEnd(); + Comp.LocStart = ON.getSourceRange().getBegin(); + Comp.LocEnd = ON.getSourceRange().getEnd(); switch (ON.getKind()) { case Node::Array: { Expr *FromIndex = E->getIndexExpr(ON.getArrayExprIndex()); @@ -5552,7 +5805,8 @@ TreeTransform<Derived>::TransformOpaqueValueExpr(OpaqueValueExpr *E) { template<typename Derived> ExprResult -TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *E) { if (E->isArgumentType()) { TypeSourceInfo *OldT = E->getArgumentTypeInfo(); @@ -5563,9 +5817,9 @@ TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { if (!getDerived().AlwaysRebuild() && OldT == NewT) return SemaRef.Owned(E); - return getDerived().RebuildSizeOfAlignOf(NewT, E->getOperatorLoc(), - E->isSizeOf(), - E->getSourceRange()); + return getDerived().RebuildUnaryExprOrTypeTrait(NewT, E->getOperatorLoc(), + E->getKind(), + E->getSourceRange()); } ExprResult SubExpr; @@ -5583,9 +5837,10 @@ TreeTransform<Derived>::TransformSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { return SemaRef.Owned(E); } - return getDerived().RebuildSizeOfAlignOf(SubExpr.get(), E->getOperatorLoc(), - E->isSizeOf(), - E->getSourceRange()); + return getDerived().RebuildUnaryExprOrTypeTrait(SubExpr.get(), + E->getOperatorLoc(), + E->getKind(), + E->getSourceRange()); } template<typename Derived> @@ -5646,12 +5901,12 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { if (Base.isInvalid()) return ExprError(); - NestedNameSpecifier *Qualifier = 0; + NestedNameSpecifierLoc QualifierLoc; if (E->hasQualifier()) { - Qualifier - = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); - if (Qualifier == 0) + QualifierLoc + = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); + + if (!QualifierLoc) return ExprError(); } @@ -5673,7 +5928,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && - Qualifier == E->getQualifier() && + QualifierLoc == E->getQualifierLoc() && Member == E->getMemberDecl() && FoundDecl == E->getFoundDecl() && !E->hasExplicitTemplateArgs()) { @@ -5706,8 +5961,7 @@ TreeTransform<Derived>::TransformMemberExpr(MemberExpr *E) { return getDerived().RebuildMemberExpr(Base.get(), FakeOperatorLoc, E->isArrow(), - Qualifier, - E->getQualifierRange(), + QualifierLoc, E->getMemberNameInfo(), Member, FoundDecl, @@ -6333,7 +6587,7 @@ TreeTransform<Derived>::TransformCXXUuidofExpr(CXXUuidofExpr *E) { TInfo == E->getTypeOperandSourceInfo()) return SemaRef.Owned(E); - return getDerived().RebuildCXXTypeidExpr(E->getType(), + return getDerived().RebuildCXXUuidofExpr(E->getType(), E->getLocStart(), TInfo, E->getLocEnd()); @@ -6623,8 +6877,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( if (E->getDestroyedTypeInfo()) { TypeSourceInfo *DestroyedTypeInfo = getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(), - ObjectType, 0, - QualifierLoc.getNestedNameSpecifier()); + ObjectType, 0, SS); if (!DestroyedTypeInfo) return ExprError(); Destroyed = DestroyedTypeInfo; @@ -6670,8 +6923,6 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformUnresolvedLookupExpr( UnresolvedLookupExpr *Old) { - TemporaryBase Rebase(*this, Old->getNameLoc(), DeclarationName()); - LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(), Sema::LookupOrdinaryName); @@ -6708,14 +6959,13 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr( // Rebuild the nested-name qualifier, if present. CXXScopeSpec SS; - NestedNameSpecifier *Qualifier = 0; - if (Old->getQualifier()) { - Qualifier = getDerived().TransformNestedNameSpecifier(Old->getQualifier(), - Old->getQualifierRange()); - if (!Qualifier) + if (Old->getQualifierLoc()) { + NestedNameSpecifierLoc QualifierLoc + = getDerived().TransformNestedNameSpecifierLoc(Old->getQualifierLoc()); + if (!QualifierLoc) return ExprError(); - SS.MakeTrivial(SemaRef.Context, Qualifier, Old->getQualifierRange()); + SS.Adopt(QualifierLoc); } if (Old->getNamingClass()) { @@ -6785,6 +7035,53 @@ TreeTransform<Derived>::TransformBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { + TypeSourceInfo *T = getDerived().TransformType(E->getQueriedTypeSourceInfo()); + if (!T) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + T == E->getQueriedTypeSourceInfo()) + return SemaRef.Owned(E); + + ExprResult SubExpr; + { + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); + SubExpr = getDerived().TransformExpr(E->getDimensionExpression()); + if (SubExpr.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getDimensionExpression()) + return SemaRef.Owned(E); + } + + return getDerived().RebuildArrayTypeTrait(E->getTrait(), + E->getLocStart(), + T, + SubExpr.get(), + E->getLocEnd()); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformExpressionTraitExpr(ExpressionTraitExpr *E) { + ExprResult SubExpr; + { + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); + SubExpr = getDerived().TransformExpr(E->getQueriedExpression()); + if (SubExpr.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && SubExpr.get() == E->getQueriedExpression()) + return SemaRef.Owned(E); + } + + return getDerived().RebuildExpressionTrait( + E->getTrait(), E->getLocStart(), SubExpr.get(), E->getLocEnd()); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *E) { NestedNameSpecifierLoc QualifierLoc @@ -6994,16 +7291,16 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( // the member name. NamedDecl *FirstQualifierInScope = getDerived().TransformFirstQualifierInScope( - E->getFirstQualifierFoundInScope(), - E->getQualifierRange().getBegin()); + E->getFirstQualifierFoundInScope(), + E->getQualifierLoc().getBeginLoc()); - NestedNameSpecifier *Qualifier = 0; + NestedNameSpecifierLoc QualifierLoc; if (E->getQualifier()) { - Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange(), - ObjectType, - FirstQualifierInScope); - if (!Qualifier) + QualifierLoc + = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc(), + ObjectType, + FirstQualifierInScope); + if (!QualifierLoc) return ExprError(); } @@ -7022,7 +7319,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( if (!getDerived().AlwaysRebuild() && Base.get() == OldBase && BaseType == E->getBaseType() && - Qualifier == E->getQualifier() && + QualifierLoc == E->getQualifierLoc() && NameInfo.getName() == E->getMember() && FirstQualifierInScope == E->getFirstQualifierFoundInScope()) return SemaRef.Owned(E); @@ -7031,8 +7328,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( BaseType, E->isArrow(), E->getOperatorLoc(), - Qualifier, - E->getQualifierRange(), + QualifierLoc, FirstQualifierInScope, NameInfo, /*TemplateArgs*/ 0); @@ -7048,8 +7344,7 @@ TreeTransform<Derived>::TransformCXXDependentScopeMemberExpr( BaseType, E->isArrow(), E->getOperatorLoc(), - Qualifier, - E->getQualifierRange(), + QualifierLoc, FirstQualifierInScope, NameInfo, &TransArgs); @@ -7070,12 +7365,11 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) BaseType = getDerived().TransformType(Old->getBaseType()); } - NestedNameSpecifier *Qualifier = 0; - if (Old->getQualifier()) { - Qualifier - = getDerived().TransformNestedNameSpecifier(Old->getQualifier(), - Old->getQualifierRange()); - if (Qualifier == 0) + NestedNameSpecifierLoc QualifierLoc; + if (Old->getQualifierLoc()) { + QualifierLoc + = getDerived().TransformNestedNameSpecifierLoc(Old->getQualifierLoc()); + if (!QualifierLoc) return ExprError(); } @@ -7093,8 +7387,10 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) // This can happen because of dependent hiding. if (isa<UsingShadowDecl>(*I)) continue; - else + else { + R.clear(); return ExprError(); + } } // Expand using declarations. @@ -7143,8 +7439,7 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) BaseType, Old->getOperatorLoc(), Old->isArrow(), - Qualifier, - Old->getQualifierRange(), + QualifierLoc, FirstQualifierInScope, R, (Old->hasExplicitTemplateArgs() @@ -7490,8 +7785,6 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { template<typename Derived> ExprResult TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { - NestedNameSpecifier *Qualifier = 0; - ValueDecl *ND = cast_or_null<ValueDecl>(getDerived().TransformDecl(E->getLocation(), E->getDecl())); @@ -7508,7 +7801,7 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { } DeclarationNameInfo NameInfo(E->getDecl()->getDeclName(), E->getLocation()); - return getDerived().RebuildDeclRefExpr(Qualifier, SourceLocation(), + return getDerived().RebuildDeclRefExpr(NestedNameSpecifierLoc(), ND, NameInfo, 0); } @@ -7720,88 +8013,33 @@ template<typename Derived> QualType TreeTransform<Derived>::RebuildTemplateSpecializationType( TemplateName Template, SourceLocation TemplateNameLoc, - const TemplateArgumentListInfo &TemplateArgs) { + TemplateArgumentListInfo &TemplateArgs) { return SemaRef.CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); } template<typename Derived> -NestedNameSpecifier * -TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, - SourceRange Range, - IdentifierInfo &II, - QualType ObjectType, - NamedDecl *FirstQualifierInScope) { - CXXScopeSpec SS; - // FIXME: The source location information is all wrong. - SS.MakeTrivial(SemaRef.Context, Prefix, Range); - if (SemaRef.BuildCXXNestedNameSpecifier(0, II, /*FIXME:*/Range.getBegin(), - /*FIXME:*/Range.getEnd(), - ObjectType, false, - SS, FirstQualifierInScope, - false)) - return 0; - - return SS.getScopeRep(); -} - -template<typename Derived> -NestedNameSpecifier * -TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, - SourceRange Range, - NamespaceDecl *NS) { - return NestedNameSpecifier::Create(SemaRef.Context, Prefix, NS); -} - -template<typename Derived> -NestedNameSpecifier * -TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, - SourceRange Range, - NamespaceAliasDecl *Alias) { - return NestedNameSpecifier::Create(SemaRef.Context, Prefix, Alias); -} - -template<typename Derived> -NestedNameSpecifier * -TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, - SourceRange Range, - bool TemplateKW, - QualType T) { - if (T->isDependentType() || T->isRecordType() || - (SemaRef.getLangOptions().CPlusPlus0x && T->isEnumeralType())) { - assert(!T.hasLocalQualifiers() && "Can't get cv-qualifiers here"); - return NestedNameSpecifier::Create(SemaRef.Context, Prefix, TemplateKW, - T.getTypePtr()); - } - - SemaRef.Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T; - return 0; -} - -template<typename Derived> TemplateName -TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, +TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, bool TemplateKW, TemplateDecl *Template) { - return SemaRef.Context.getQualifiedTemplateName(Qualifier, TemplateKW, + return SemaRef.Context.getQualifiedTemplateName(SS.getScopeRep(), TemplateKW, Template); } template<typename Derived> TemplateName -TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, - SourceRange QualifierRange, - const IdentifierInfo &II, +TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, + const IdentifierInfo &Name, + SourceLocation NameLoc, QualType ObjectType, NamedDecl *FirstQualifierInScope) { - CXXScopeSpec SS; - SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange); - UnqualifiedId Name; - Name.setIdentifier(&II, /*FIXME:*/getDerived().getBaseLocation()); + UnqualifiedId TemplateName; + TemplateName.setIdentifier(&Name, NameLoc); Sema::TemplateTy Template; getSema().ActOnDependentTemplateName(/*Scope=*/0, - /*FIXME:*/getDerived().getBaseLocation(), + /*FIXME:*/SourceLocation(), SS, - Name, + TemplateName, ParsedType::make(ObjectType), /*EnteringContext=*/false, Template); @@ -7810,18 +8048,17 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, template<typename Derived> TemplateName -TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, +TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, OverloadedOperatorKind Operator, + SourceLocation NameLoc, QualType ObjectType) { - CXXScopeSpec SS; - SS.MakeTrivial(SemaRef.Context, Qualifier, SourceRange(getDerived().getBaseLocation())); UnqualifiedId Name; - SourceLocation SymbolLocations[3]; // FIXME: Bogus location information. - Name.setOperatorFunctionId(/*FIXME:*/getDerived().getBaseLocation(), - Operator, SymbolLocations); + // FIXME: Bogus location information. + SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc }; + Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations); Sema::TemplateTy Template; getSema().ActOnDependentTemplateName(/*Scope=*/0, - /*FIXME:*/getDerived().getBaseLocation(), + /*FIXME:*/SourceLocation(), SS, Name, ParsedType::make(ObjectType), diff --git a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h index 1e0a7c4..3570737 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h +++ b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h @@ -44,8 +44,7 @@ class TypeLocBuilder { public: TypeLocBuilder() - : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) - {} + : Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) {} ~TypeLocBuilder() { if (Buffer != InlineBuffer) diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp index 5e94f59..782e5c6 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.cpp @@ -50,7 +50,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::Char16: ID = PREDEF_TYPE_CHAR16_ID; break; case BuiltinType::Char32: ID = PREDEF_TYPE_CHAR32_ID; break; case BuiltinType::Overload: ID = PREDEF_TYPE_OVERLOAD_ID; break; + case BuiltinType::BoundMember:ID = PREDEF_TYPE_BOUND_MEMBER; break; case BuiltinType::Dependent: ID = PREDEF_TYPE_DEPENDENT_ID; break; + case BuiltinType::UnknownAny: ID = PREDEF_TYPE_UNKNOWN_ANY; break; case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break; case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break; case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break; diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h index d416699..838df13 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTCommon.h @@ -23,7 +23,9 @@ namespace serialization { enum DeclUpdateKind { UPD_CXX_SET_DEFINITIONDATA, UPD_CXX_ADDED_IMPLICIT_MEMBER, - UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION + UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION, + UPD_CXX_ADDED_ANONYMOUS_NAMESPACE, + UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER }; TypeIdx TypeIdxFromBuiltin(const BuiltinType *BT); diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp index c3953ba..d2e41a9 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReader.cpp @@ -23,6 +23,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Lex/MacroInfo.h" @@ -36,6 +37,7 @@ #include "clang/Basic/FileSystemStatCache.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VersionTuple.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Bitcode/BitstreamReader.h" #include "llvm/Support/MemoryBuffer.h" @@ -77,6 +79,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { PARSE_LANGOPT_BENIGN(Digraphs); PARSE_LANGOPT_BENIGN(HexFloats); PARSE_LANGOPT_IMPORTANT(C99, diag::warn_pch_c99); + PARSE_LANGOPT_IMPORTANT(C1X, diag::warn_pch_c1x); PARSE_LANGOPT_IMPORTANT(Microsoft, diag::warn_pch_microsoft_extensions); PARSE_LANGOPT_BENIGN(MSCVersion); PARSE_LANGOPT_IMPORTANT(CPlusPlus, diag::warn_pch_cplusplus); @@ -126,6 +129,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { PARSE_LANGOPT_IMPORTANT(PICLevel, diag::warn_pch_pic_level); PARSE_LANGOPT_IMPORTANT(GNUInline, diag::warn_pch_gnu_inline); PARSE_LANGOPT_IMPORTANT(NoInline, diag::warn_pch_no_inline); + PARSE_LANGOPT_IMPORTANT(Deprecated, diag::warn_pch_deprecated); PARSE_LANGOPT_IMPORTANT(AccessControl, diag::warn_pch_access_control); PARSE_LANGOPT_IMPORTANT(CharIsSigned, diag::warn_pch_char_signed); PARSE_LANGOPT_IMPORTANT(ShortWChar, diag::warn_pch_short_wchar); @@ -953,8 +957,16 @@ bool ASTReader::ReadDeclContextStorage(llvm::BitstreamCursor &Cursor, return false; } -void ASTReader::Error(const char *Msg) { - Diag(diag::err_fe_pch_malformed) << Msg; +void ASTReader::Error(llvm::StringRef Msg) { + Error(diag::err_fe_pch_malformed, Msg); +} + +void ASTReader::Error(unsigned DiagID, + llvm::StringRef Arg1, llvm::StringRef Arg2) { + if (Diags.isDiagnosticInFlight()) + Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2); + else + Diag(DiagID) << Arg1 << Arg2; } /// \brief Tell the AST listener about the predefines buffers in the chain. @@ -1306,8 +1318,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(unsigned ID) { || (time_t)Record[5] != File->getModificationTime() #endif )) { - Diag(diag::err_fe_pch_file_modified) - << Filename; + Error(diag::err_fe_pch_file_modified, Filename); return Failure; } @@ -2460,20 +2471,26 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(llvm::StringRef FileName, if (CurrentDir.empty()) CurrentDir = "."; } - // Open the AST file. - // - // FIXME: This shouldn't be here, we should just take a raw_ostream. - std::string ErrStr; - llvm::error_code ec; - if (FileName == "-") { - ec = llvm::MemoryBuffer::getSTDIN(F.Buffer); - if (ec) - ErrStr = ec.message(); - } else - F.Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrStr)); - if (!F.Buffer) { - Error(ErrStr.c_str()); - return IgnorePCH; + if (!ASTBuffers.empty()) { + F.Buffer.reset(ASTBuffers.back()); + ASTBuffers.pop_back(); + assert(F.Buffer && "Passed null buffer"); + } else { + // Open the AST file. + // + // FIXME: This shouldn't be here, we should just take a raw_ostream. + std::string ErrStr; + llvm::error_code ec; + if (FileName == "-") { + ec = llvm::MemoryBuffer::getSTDIN(F.Buffer); + if (ec) + ErrStr = ec.message(); + } else + F.Buffer.reset(FileMgr.getBufferForFile(FileName, &ErrStr)); + if (!F.Buffer) { + Error(ErrStr.c_str()); + return IgnorePCH; + } } // Initialize the stream @@ -2668,6 +2685,11 @@ void ASTReader::InitializeContext(ASTContext &Ctx) { if (SpecialTypes[SPECIAL_TYPE_INT128_INSTALLED]) Context->setInt128Installed(); + if (unsigned AutoDeduct = SpecialTypes[SPECIAL_TYPE_AUTO_DEDUCT]) + Context->AutoDeductTy = GetType(AutoDeduct); + if (unsigned AutoRRefDeduct = SpecialTypes[SPECIAL_TYPE_AUTO_RREF_DEDUCT]) + Context->AutoRRefDeductTy = GetType(AutoRRefDeduct); + ReadPragmaDiagnosticMappings(Context->getDiagnostics()); // If there were any CUDA special declarations, deserialize them. @@ -2786,6 +2808,7 @@ bool ASTReader::ParseLanguageOptions( PARSE_LANGOPT(Digraphs); PARSE_LANGOPT(HexFloats); PARSE_LANGOPT(C99); + PARSE_LANGOPT(C1X); PARSE_LANGOPT(Microsoft); PARSE_LANGOPT(CPlusPlus); PARSE_LANGOPT(CPlusPlus0x); @@ -2823,6 +2846,7 @@ bool ASTReader::ParseLanguageOptions( PARSE_LANGOPT(PICLevel); PARSE_LANGOPT(GNUInline); PARSE_LANGOPT(NoInline); + PARSE_LANGOPT(Deprecated); PARSE_LANGOPT(AccessControl); PARSE_LANGOPT(CharIsSigned); PARSE_LANGOPT(ShortWChar); @@ -2836,7 +2860,9 @@ bool ASTReader::ParseLanguageOptions( PARSE_LANGOPT(CUDA); PARSE_LANGOPT(CatchUndefined); PARSE_LANGOPT(DefaultFPContract); - // FIXME: Missing ElideConstructors?! + PARSE_LANGOPT(ElideConstructors); + PARSE_LANGOPT(SpellChecking); + PARSE_LANGOPT(MRTD); #undef PARSE_LANGOPT return Listener->ReadLanguageOptions(LangOpts); @@ -2999,12 +3025,12 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { } case TYPE_LVALUE_REFERENCE: { - if (Record.size() != 1) { + if (Record.size() != 2) { Error("Incorrect encoding of lvalue reference type"); return QualType(); } QualType PointeeType = GetType(Record[0]); - return Context->getLValueReferenceType(PointeeType); + return Context->getLValueReferenceType(PointeeType, Record[1]); } case TYPE_RVALUE_REFERENCE: { @@ -3082,12 +3108,12 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { } case TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 4) { + if (Record.size() != 5) { Error("incorrect encoding of no-proto function type"); return QualType(); } QualType ResultType = GetType(Record[0]); - FunctionType::ExtInfo Info(Record[1], Record[2], (CallingConv)Record[3]); + FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], (CallingConv)Record[4]); return Context->getFunctionNoProtoType(ResultType, Info); } @@ -3096,10 +3122,11 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1], - /*regparm*/ Record[2], - static_cast<CallingConv>(Record[3])); + /*hasregparm*/ Record[2], + /*regparm*/ Record[3], + static_cast<CallingConv>(Record[4])); - unsigned Idx = 4; + unsigned Idx = 5; unsigned NumParams = Record[Idx++]; llvm::SmallVector<QualType, 16> ParamTypes; for (unsigned I = 0; I != NumParams; ++I) @@ -3108,13 +3135,18 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { EPI.Variadic = Record[Idx++]; EPI.TypeQuals = Record[Idx++]; EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]); - EPI.HasExceptionSpec = Record[Idx++]; - EPI.HasAnyExceptionSpec = Record[Idx++]; - EPI.NumExceptions = Record[Idx++]; - llvm::SmallVector<QualType, 2> Exceptions; - for (unsigned I = 0; I != EPI.NumExceptions; ++I) - Exceptions.push_back(GetType(Record[Idx++])); - EPI.Exceptions = Exceptions.data(); + ExceptionSpecificationType EST = + static_cast<ExceptionSpecificationType>(Record[Idx++]); + EPI.ExceptionSpecType = EST; + if (EST == EST_Dynamic) { + EPI.NumExceptions = Record[Idx++]; + llvm::SmallVector<QualType, 2> Exceptions; + for (unsigned I = 0; I != EPI.NumExceptions; ++I) + Exceptions.push_back(GetType(Record[Idx++])); + EPI.Exceptions = Exceptions.data(); + } else if (EST == EST_ComputedNoexcept) { + EPI.NoexceptExpr = ReadExpr(*Loc.F); + } return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams, EPI); } @@ -3128,7 +3160,7 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Error("incorrect encoding of typedef type"); return QualType(); } - TypedefDecl *Decl = cast<TypedefDecl>(GetDecl(Record[0])); + TypedefNameDecl *Decl = cast<TypedefNameDecl>(GetDecl(Record[0])); QualType Canonical = GetType(Record[1]); if (!Canonical.isNull()) Canonical = Context->getCanonicalType(Canonical); @@ -3271,8 +3303,9 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { unsigned Depth = Record[Idx++]; unsigned Index = Record[Idx++]; bool Pack = Record[Idx++]; - IdentifierInfo *Name = GetIdentifierInfo(Record, Idx); - return Context->getTemplateTypeParmType(Depth, Index, Pack, Name); + TemplateTypeParmDecl *D = + cast_or_null<TemplateTypeParmDecl>(GetDecl(Record[Idx++])); + return Context->getTemplateTypeParmType(Depth, Index, Pack, D); } case TYPE_DEPENDENT_NAME: { @@ -3398,6 +3431,7 @@ void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { } void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { TL.setStarLoc(ReadSourceLocation(Record, Idx)); + TL.setClassTInfo(Reader.GetTypeSourceInfo(F, Record, Idx)); } void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { TL.setLBracketLoc(ReadSourceLocation(Record, Idx)); @@ -3431,8 +3465,8 @@ void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { - TL.setLParenLoc(ReadSourceLocation(Record, Idx)); - TL.setRParenLoc(ReadSourceLocation(Record, Idx)); + TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx)); + TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx)); TL.setTrailingReturn(Record[Idx++]); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { TL.setArg(i, cast_or_null<ParmVarDecl>(Reader.GetDecl(Record[Idx++]))); @@ -3517,20 +3551,20 @@ void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) { } void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { TL.setKeywordLoc(ReadSourceLocation(Record, Idx)); - TL.setQualifierRange(Reader.ReadSourceRange(F, Record, Idx)); + TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); } void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { TL.setKeywordLoc(ReadSourceLocation(Record, Idx)); - TL.setQualifierRange(Reader.ReadSourceRange(F, Record, Idx)); + TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); TL.setNameLoc(ReadSourceLocation(Record, Idx)); } void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL) { TL.setKeywordLoc(ReadSourceLocation(Record, Idx)); - TL.setQualifierRange(Reader.ReadSourceRange(F, Record, Idx)); + TL.setQualifierLoc(Reader.ReadNestedNameSpecifierLoc(F, Record, Idx)); TL.setNameLoc(ReadSourceLocation(Record, Idx)); TL.setLAngleLoc(ReadSourceLocation(Record, Idx)); TL.setRAngleLoc(ReadSourceLocation(Record, Idx)); @@ -3605,7 +3639,9 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_DOUBLE_ID: T = Context->DoubleTy; break; case PREDEF_TYPE_LONGDOUBLE_ID: T = Context->LongDoubleTy; break; case PREDEF_TYPE_OVERLOAD_ID: T = Context->OverloadTy; break; + case PREDEF_TYPE_BOUND_MEMBER: T = Context->BoundMemberTy; break; case PREDEF_TYPE_DEPENDENT_ID: T = Context->DependentTy; break; + case PREDEF_TYPE_UNKNOWN_ANY: T = Context->UnknownAnyTy; break; case PREDEF_TYPE_NULLPTR_ID: T = Context->NullPtrTy; break; case PREDEF_TYPE_CHAR16_ID: T = Context->Char16Ty; break; case PREDEF_TYPE_CHAR32_ID: T = Context->Char32Ty; break; @@ -3675,16 +3711,18 @@ ASTReader::GetTemplateArgumentLocInfo(PerFileData &F, case TemplateArgument::Type: return GetTypeSourceInfo(F, Record, Index); case TemplateArgument::Template: { - SourceRange QualifierRange = ReadSourceRange(F, Record, Index); + NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, + Index); SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index); - return TemplateArgumentLocInfo(QualifierRange, TemplateNameLoc, + return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc, SourceLocation()); } case TemplateArgument::TemplateExpansion: { - SourceRange QualifierRange = ReadSourceRange(F, Record, Index); + NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, + Index); SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index); SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index); - return TemplateArgumentLocInfo(QualifierRange, TemplateNameLoc, + return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc, EllipsisLoc); } case TemplateArgument::Null: @@ -3722,11 +3760,13 @@ ASTReader::GetCXXBaseSpecifiersOffset(serialization::CXXBaseSpecifiersID ID) { --ID; uint64_t Offset = 0; for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - if (ID < Chain[I]->LocalNumCXXBaseSpecifiers) - return Offset + Chain[I]->CXXBaseSpecifiersOffsets[ID]; + PerFileData &F = *Chain[N - I - 1]; + + if (ID < F.LocalNumCXXBaseSpecifiers) + return Offset + F.CXXBaseSpecifiersOffsets[ID]; - ID -= Chain[I]->LocalNumCXXBaseSpecifiers; - Offset += Chain[I]->SizeInBits; + ID -= F.LocalNumCXXBaseSpecifiers; + Offset += F.SizeInBits; } assert(false && "CXXBaseSpecifiers not found"); @@ -3737,14 +3777,14 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { // Figure out which AST file contains this offset. PerFileData *F = 0; for (unsigned I = 0, N = Chain.size(); I != N; ++I) { - if (Offset < Chain[I]->SizeInBits) { - F = Chain[I]; + if (Offset < Chain[N - I - 1]->SizeInBits) { + F = Chain[N - I - 1]; break; } - Offset -= Chain[I]->SizeInBits; + Offset -= Chain[N - I - 1]->SizeInBits; } - + if (!F) { Error("Malformed AST file: C++ base specifiers at impossible offset"); return 0; @@ -4014,6 +4054,23 @@ void ASTReader::PrintStats() { std::fprintf(stderr, "\n"); } +/// Return the amount of memory used by memory buffers, breaking down +/// by heap-backed versus mmap'ed memory. +void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { + for (unsigned i = 0, e = Chain.size(); i != e; ++i) + if (llvm::MemoryBuffer *buf = Chain[i]->Buffer.get()) { + size_t bytes = buf->getBufferSize(); + switch (buf->getBufferKind()) { + case llvm::MemoryBuffer::MemoryBuffer_Malloc: + sizes.malloc_bytes += bytes; + break; + case llvm::MemoryBuffer::MemoryBuffer_MMap: + sizes.mmap_bytes += bytes; + break; + } + } +} + void ASTReader::InitializeSema(Sema &S) { SemaObj = &S; S.ExternalSource = this; @@ -4054,7 +4111,7 @@ void ASTReader::InitializeSema(Sema &S) { // and add them to Sema's vector of such declarations. for (unsigned I = 0, N = ExtVectorDecls.size(); I != N; ++I) SemaObj->ExtVectorDecls.push_back( - cast<TypedefDecl>(GetDecl(ExtVectorDecls[I]))); + cast<TypedefNameDecl>(GetDecl(ExtVectorDecls[I]))); // FIXME: Do VTable uses and dynamic classes deserialize too much ? // Can we cut them down before writing them ? @@ -4087,22 +4144,22 @@ void ASTReader::InitializeSema(Sema &S) { SemaObj->ReferencedSelectors.insert(std::make_pair(Sel, SelLoc)); } } - - // If there were any pending implicit instantiations, deserialize them - // and add them to Sema's queue of such instantiations. - assert(F->PendingInstantiations.size() % 2 == 0 && - "Expected pairs of entries"); - for (unsigned Idx = 0, N = F->PendingInstantiations.size(); Idx < N;) { - ValueDecl *D=cast<ValueDecl>(GetDecl(F->PendingInstantiations[Idx++])); - SourceLocation Loc = ReadSourceLocation(*F, F->PendingInstantiations,Idx); - SemaObj->PendingInstantiations.push_back(std::make_pair(D, Loc)); - } } - // The two special data sets below always come from the most recent PCH, + // The special data sets below always come from the most recent PCH, // which is at the front of the chain. PerFileData &F = *Chain.front(); + // If there were any pending implicit instantiations, deserialize them + // and add them to Sema's queue of such instantiations. + assert(F.PendingInstantiations.size() % 2 == 0 && + "Expected pairs of entries"); + for (unsigned Idx = 0, N = F.PendingInstantiations.size(); Idx < N;) { + ValueDecl *D=cast<ValueDecl>(GetDecl(F.PendingInstantiations[Idx++])); + SourceLocation Loc = ReadSourceLocation(F, F.PendingInstantiations,Idx); + SemaObj->PendingInstantiations.push_back(std::make_pair(D, Loc)); + } + // If there were any weak undeclared identifiers, deserialize them and add to // Sema's list of weak undeclared identifiers. if (!WeakUndeclaredIdentifiers.empty()) { @@ -4354,8 +4411,8 @@ IdentifierInfo *ASTReader::DecodeIdentifierInfo(unsigned ID) { return IdentifiersLoaded[ID]; } -void ASTReader::ReadSLocEntry(unsigned ID) { - ReadSLocEntryRecord(ID); +bool ASTReader::ReadSLocEntry(unsigned ID) { + return ReadSLocEntryRecord(ID) != Success; } Selector ASTReader::DecodeSelector(unsigned ID) { @@ -4762,103 +4819,57 @@ NestedNameSpecifierLoc ASTReader::ReadNestedNameSpecifierLoc(PerFileData &F, const RecordData &Record, unsigned &Idx) { unsigned N = Record[Idx++]; - NestedNameSpecifier *NNS = 0, *Prev = 0; - llvm::SmallVector<char, 32> LocationData; + NestedNameSpecifierLocBuilder Builder; for (unsigned I = 0; I != N; ++I) { NestedNameSpecifier::SpecifierKind Kind = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; switch (Kind) { case NestedNameSpecifier::Identifier: { - // Nested-name-specifier - IdentifierInfo *II = GetIdentifierInfo(Record, Idx); - NNS = NestedNameSpecifier::Create(*Context, Prev, II); - - // Location information + IdentifierInfo *II = GetIdentifierInfo(Record, Idx); SourceRange Range = ReadSourceRange(F, Record, Idx); - unsigned RawStart = Range.getBegin().getRawEncoding(); - unsigned RawEnd = Range.getEnd().getRawEncoding(); - LocationData.append(reinterpret_cast<char*>(&RawStart), - reinterpret_cast<char*>(&RawStart) +sizeof(unsigned)); - LocationData.append(reinterpret_cast<char*>(&RawEnd), - reinterpret_cast<char*>(&RawEnd) + sizeof(unsigned)); + Builder.Extend(*Context, II, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::Namespace: { - // Nested-name-specifier NamespaceDecl *NS = cast<NamespaceDecl>(GetDecl(Record[Idx++])); - NNS = NestedNameSpecifier::Create(*Context, Prev, NS); - - // Location information SourceRange Range = ReadSourceRange(F, Record, Idx); - unsigned RawStart = Range.getBegin().getRawEncoding(); - unsigned RawEnd = Range.getEnd().getRawEncoding(); - LocationData.append(reinterpret_cast<char*>(&RawStart), - reinterpret_cast<char*>(&RawStart) +sizeof(unsigned)); - LocationData.append(reinterpret_cast<char*>(&RawEnd), - reinterpret_cast<char*>(&RawEnd) + sizeof(unsigned)); + Builder.Extend(*Context, NS, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::NamespaceAlias: { - // Nested-name-specifier NamespaceAliasDecl *Alias = cast<NamespaceAliasDecl>(GetDecl(Record[Idx++])); - NNS = NestedNameSpecifier::Create(*Context, Prev, Alias); - - // Location information SourceRange Range = ReadSourceRange(F, Record, Idx); - unsigned RawStart = Range.getBegin().getRawEncoding(); - unsigned RawEnd = Range.getEnd().getRawEncoding(); - LocationData.append(reinterpret_cast<char*>(&RawStart), - reinterpret_cast<char*>(&RawStart) +sizeof(unsigned)); - LocationData.append(reinterpret_cast<char*>(&RawEnd), - reinterpret_cast<char*>(&RawEnd) + sizeof(unsigned)); - + Builder.Extend(*Context, Alias, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { - // Nested-name-specifier bool Template = Record[Idx++]; TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx); if (!T) return NestedNameSpecifierLoc(); - NNS = NestedNameSpecifier::Create(*Context, Prev, Template, - T->getType().getTypePtr()); - - // Location information. SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); - unsigned RawLocation = ColonColonLoc.getRawEncoding(); - void *OpaqueTypeData = T->getTypeLoc().getOpaqueData(); - LocationData.append(reinterpret_cast<char*>(&OpaqueTypeData), - (reinterpret_cast<char*>(&OpaqueTypeData) - + sizeof(void *))); - LocationData.append(reinterpret_cast<char*>(&RawLocation), - (reinterpret_cast<char*>(&RawLocation) + - sizeof(unsigned))); + + // FIXME: 'template' keyword location not saved anywhere, so we fake it. + Builder.Extend(*Context, + Template? T->getTypeLoc().getBeginLoc() : SourceLocation(), + T->getTypeLoc(), ColonColonLoc); break; } case NestedNameSpecifier::Global: { - // Nested-name-specifier - NNS = NestedNameSpecifier::GlobalSpecifier(*Context); - SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); - unsigned RawLocation = ColonColonLoc.getRawEncoding(); - LocationData.append(reinterpret_cast<char*>(&RawLocation), - (reinterpret_cast<char*>(&RawLocation) + - sizeof(unsigned))); + Builder.MakeGlobal(*Context, ColonColonLoc); break; } } - Prev = NNS; } - void *Mem = Context->Allocate(LocationData.size(), llvm::alignOf<void*>()); - memcpy(Mem, LocationData.data(), LocationData.size()); - return NestedNameSpecifierLoc(NNS, Mem); + return Builder.getWithLocInContext(*Context); } SourceRange @@ -4897,6 +4908,18 @@ std::string ASTReader::ReadString(const RecordData &Record, unsigned &Idx) { return Result; } +VersionTuple ASTReader::ReadVersionTuple(const RecordData &Record, + unsigned &Idx) { + unsigned Major = Record[Idx++]; + unsigned Minor = Record[Idx++]; + unsigned Subminor = Record[Idx++]; + if (Minor == 0) + return VersionTuple(Major); + if (Subminor == 0) + return VersionTuple(Major, Minor - 1); + return VersionTuple(Major, Minor - 1, Subminor - 1); +} + CXXTemporary *ASTReader::ReadCXXTemporary(const RecordData &Record, unsigned &Idx) { CXXDestructorDecl *Decl = cast<CXXDestructorDecl>(GetDecl(Record[Idx++])); diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp index 493ccba..3a825de 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderDecl.cpp @@ -38,6 +38,9 @@ namespace clang { const RecordData &Record; unsigned &Idx; TypeID TypeIDForTypeDecl; + + DeclID DeclContextIDForTemplateParmDecl; + DeclID LexicalDeclContextIDForTemplateParmDecl; uint64_t GetCurrentCursorOffset(); SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) { @@ -79,7 +82,8 @@ namespace clang { void Visit(Decl *D); - void UpdateDecl(Decl *D, const RecordData &Record); + void UpdateDecl(Decl *D, ASTReader::PerFileData &Module, + const RecordData &Record); void VisitDecl(Decl *D); void VisitTranslationUnitDecl(TranslationUnitDecl *TU); @@ -90,6 +94,7 @@ namespace clang { void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); void VisitTypeDecl(TypeDecl *TD); void VisitTypedefDecl(TypedefDecl *TD); + void VisitTypeAliasDecl(TypeAliasDecl *TD); void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); void VisitTagDecl(TagDecl *TD); void VisitEnumDecl(EnumDecl *ED); @@ -175,13 +180,32 @@ void ASTDeclReader::Visit(Decl *D) { // FunctionDecl's body was written last after all other Stmts/Exprs. if (Record[Idx++]) FD->setLazyBody(GetCurrentCursorOffset()); + } else if (D->isTemplateParameter()) { + // If we have a fully initialized template parameter, we can now + // set its DeclContext. + D->setDeclContext( + cast_or_null<DeclContext>( + Reader.GetDecl(DeclContextIDForTemplateParmDecl))); + D->setLexicalDeclContext( + cast_or_null<DeclContext>( + Reader.GetDecl(LexicalDeclContextIDForTemplateParmDecl))); } } void ASTDeclReader::VisitDecl(Decl *D) { - D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]))); - D->setLexicalDeclContext( + if (D->isTemplateParameter()) { + // We don't want to deserialize the DeclContext of a template + // parameter immediately, because the template parameter might be + // used in the formulation of its DeclContext. Use the translation + // unit DeclContext as a placeholder. + DeclContextIDForTemplateParmDecl = Record[Idx++]; + LexicalDeclContextIDForTemplateParmDecl = Record[Idx++]; + D->setDeclContext(Reader.getContext()->getTranslationUnitDecl()); + } else { + D->setDeclContext(cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]))); + D->setLexicalDeclContext( cast_or_null<DeclContext>(Reader.GetDecl(Record[Idx++]))); + } D->setLocation(ReadSourceLocation(Record, Idx)); D->setInvalidDecl(Record[Idx++]); if (Record[Idx++]) { // hasAttrs @@ -191,6 +215,7 @@ void ASTDeclReader::VisitDecl(Decl *D) { } D->setImplicit(Record[Idx++]); D->setUsed(Record[Idx++]); + D->setReferenced(Record[Idx++]); D->setAccess((AccessSpecifier)Record[Idx++]); D->setPCHLevel(Record[Idx++] + (F.Type <= ASTReader::PCH)); } @@ -208,6 +233,7 @@ void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) { void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) { VisitNamedDecl(TD); + TD->setLocStart(ReadSourceLocation(Record, Idx)); // Delay type reading until after we have fully initialized the decl. TypeIDForTypeDecl = Record[Idx++]; } @@ -217,6 +243,11 @@ void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) { TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx)); } +void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) { + VisitTypeDecl(TD); + TD->setTypeSourceInfo(GetTypeSourceInfo(Record, Idx)); +} + void ASTDeclReader::VisitTagDecl(TagDecl *TD) { VisitTypeDecl(TD); VisitRedeclarable(TD); @@ -225,14 +256,13 @@ void ASTDeclReader::VisitTagDecl(TagDecl *TD) { TD->setDefinition(Record[Idx++]); TD->setEmbeddedInDeclarator(Record[Idx++]); TD->setRBraceLoc(ReadSourceLocation(Record, Idx)); - TD->setTagKeywordLoc(ReadSourceLocation(Record, Idx)); if (Record[Idx++]) { // hasExtInfo TagDecl::ExtInfo *Info = new (*Reader.getContext()) TagDecl::ExtInfo(); ReadQualifierInfo(*Info, Record, Idx); - TD->TypedefDeclOrQualifier = Info; + TD->TypedefNameDeclOrQualifier = Info; } else - TD->setTypedefForAnonDecl( - cast_or_null<TypedefDecl>(Reader.GetDecl(Record[Idx++]))); + TD->setTypedefNameForAnonDecl( + cast_or_null<TypedefNameDecl>(Reader.GetDecl(Record[Idx++]))); } void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) { @@ -272,6 +302,7 @@ void ASTDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { VisitValueDecl(DD); + DD->setInnerLocStart(ReadSourceLocation(Record, Idx)); if (Record[Idx++]) { // hasExtInfo DeclaratorDecl::ExtInfo *Info = new (*Reader.getContext()) DeclaratorDecl::ExtInfo(); @@ -655,12 +686,13 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { void ASTDeclReader::VisitVarDecl(VarDecl *VD) { VisitDeclaratorDecl(VD); VisitRedeclarable(VD); - VD->SClass = (StorageClass)Record[Idx++]; - VD->setStorageClassAsWritten((StorageClass)Record[Idx++]); - VD->setThreadSpecified(Record[Idx++]); - VD->setCXXDirectInitializer(Record[Idx++]); - VD->setExceptionVariable(Record[Idx++]); - VD->setNRVOVariable(Record[Idx++]); + VD->VarDeclBits.SClass = (StorageClass)Record[Idx++]; + VD->VarDeclBits.SClassAsWritten = (StorageClass)Record[Idx++]; + VD->VarDeclBits.ThreadSpecified = Record[Idx++]; + VD->VarDeclBits.HasCXXDirectInit = Record[Idx++]; + VD->VarDeclBits.ExceptionVar = Record[Idx++]; + VD->VarDeclBits.NRVOVariable = Record[Idx++]; + VD->VarDeclBits.CXXForRangeDecl = Record[Idx++]; if (Record[Idx++]) VD->setInit(Reader.ReadExpr(F)); @@ -678,8 +710,19 @@ void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) { void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { VisitVarDecl(PD); - PD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]); - PD->setHasInheritedDefaultArg(Record[Idx++]); + unsigned isObjCMethodParam = Record[Idx++]; + unsigned scopeDepth = Record[Idx++]; + unsigned scopeIndex = Record[Idx++]; + unsigned declQualifier = Record[Idx++]; + if (isObjCMethodParam) { + assert(scopeDepth == 0); + PD->setObjCMethodScopeInfo(scopeIndex); + PD->ParmVarDeclBits.ScopeDepthOrObjCQuals = declQualifier; + } else { + PD->setScopeInfo(scopeDepth, scopeIndex); + } + PD->ParmVarDeclBits.IsKNRPromoted = Record[Idx++]; + PD->ParmVarDeclBits.HasInheritedDefaultArg = Record[Idx++]; if (Record[Idx++]) // hasUninstantiatedDefaultArg. PD->setUninstantiatedDefaultArg(Reader.ReadExpr(F)); } @@ -687,6 +730,7 @@ void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) { void ASTDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { VisitDecl(AD); AD->setAsmString(cast<StringLiteral>(Reader.ReadExpr(F))); + AD->setRParenLoc(ReadSourceLocation(Record, Idx)); } void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { @@ -720,19 +764,21 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) { VisitDecl(D); D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]); - D->setHasBraces(Record[Idx++]); + D->setExternLoc(ReadSourceLocation(Record, Idx)); + D->setRBraceLoc(ReadSourceLocation(Record, Idx)); } void ASTDeclReader::VisitLabelDecl(LabelDecl *D) { VisitNamedDecl(D); + D->setLocStart(ReadSourceLocation(Record, Idx)); } void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { VisitNamedDecl(D); D->IsInline = Record[Idx++]; - D->LBracLoc = ReadSourceLocation(Record, Idx); - D->RBracLoc = ReadSourceLocation(Record, Idx); + D->LocStart = ReadSourceLocation(Record, Idx); + D->RBraceLoc = ReadSourceLocation(Record, Idx); D->NextNamespace = Record[Idx++]; bool IsOriginal = Record[Idx++]; @@ -790,7 +836,6 @@ void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { void ASTDeclReader::VisitUnresolvedUsingTypenameDecl( UnresolvedUsingTypenameDecl *D) { VisitTypeDecl(D); - D->UsingLocation = ReadSourceLocation(Record, Idx); D->TypenameLocation = ReadSourceLocation(Record, Idx); D->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); } @@ -807,10 +852,19 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.Empty = Record[Idx++]; Data.Polymorphic = Record[Idx++]; Data.Abstract = Record[Idx++]; + Data.IsStandardLayout = Record[Idx++]; + Data.HasNoNonEmptyBases = Record[Idx++]; + Data.HasPrivateFields = Record[Idx++]; + Data.HasProtectedFields = Record[Idx++]; + Data.HasPublicFields = Record[Idx++]; Data.HasTrivialConstructor = Record[Idx++]; + Data.HasConstExprNonCopyMoveConstructor = Record[Idx++]; Data.HasTrivialCopyConstructor = Record[Idx++]; + Data.HasTrivialMoveConstructor = Record[Idx++]; Data.HasTrivialCopyAssignment = Record[Idx++]; + Data.HasTrivialMoveAssignment = Record[Idx++]; Data.HasTrivialDestructor = Record[Idx++]; + Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++]; Data.ComputedVisibleConversions = Record[Idx++]; Data.DeclaredDefaultConstructor = Record[Idx++]; Data.DeclaredCopyConstructor = Record[Idx++]; @@ -1172,7 +1226,6 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { VisitTypeDecl(D); D->setDeclaredWithTypename(Record[Idx++]); - D->setParameterPack(Record[Idx++]); bool Inherited = Record[Idx++]; TypeSourceInfo *DefArg = GetTypeSourceInfo(Record, Idx); @@ -1217,6 +1270,7 @@ void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) { VisitDecl(D); D->AssertExpr = Reader.ReadExpr(F); D->Message = cast<StringLiteral>(Reader.ReadExpr(F)); + D->RParenLoc = ReadSourceLocation(Record, Idx); } std::pair<uint64_t, uint64_t> @@ -1398,7 +1452,12 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { D = Context->getTranslationUnitDecl(); break; case DECL_TYPEDEF: - D = TypedefDecl::Create(*Context, 0, SourceLocation(), 0, 0); + D = TypedefDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), + 0, 0); + break; + case DECL_TYPEALIAS: + D = TypeAliasDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), + 0, 0); break; case DECL_ENUM: D = EnumDecl::Create(*Context, Decl::EmptyShell()); @@ -1411,19 +1470,20 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { 0, llvm::APSInt()); break; case DECL_FUNCTION: - D = FunctionDecl::Create(*Context, 0, SourceLocation(), DeclarationName(), - QualType(), 0); + D = FunctionDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), + DeclarationName(), QualType(), 0); break; case DECL_LINKAGE_SPEC: - D = LinkageSpecDecl::Create(*Context, 0, SourceLocation(), + D = LinkageSpecDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), (LinkageSpecDecl::LanguageIDs)0, - false); + SourceLocation()); break; case DECL_LABEL: D = LabelDecl::Create(*Context, 0, SourceLocation(), 0); break; case DECL_NAMESPACE: - D = NamespaceDecl::Create(*Context, 0, SourceLocation(), 0); + D = NamespaceDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), 0); break; case DECL_NAMESPACE_ALIAS: D = NamespaceAliasDecl::Create(*Context, 0, SourceLocation(), @@ -1460,8 +1520,9 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { D = CXXRecordDecl::Create(*Context, Decl::EmptyShell()); break; case DECL_CXX_METHOD: - D = CXXMethodDecl::Create(*Context, 0, DeclarationNameInfo(), - QualType(), 0); + D = CXXMethodDecl::Create(*Context, 0, SourceLocation(), + DeclarationNameInfo(), QualType(), 0, + false, SC_None, false, SourceLocation()); break; case DECL_CXX_CONSTRUCTOR: D = CXXConstructorDecl::Create(*Context, Decl::EmptyShell()); @@ -1482,38 +1543,38 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { D = FriendTemplateDecl::Create(*Context, Decl::EmptyShell()); break; case DECL_CLASS_TEMPLATE: - D = ClassTemplateDecl::Create(*Context, 0, SourceLocation(), - DeclarationName(), 0, 0, 0); + D = ClassTemplateDecl::Create(*Context, Decl::EmptyShell()); break; case DECL_CLASS_TEMPLATE_SPECIALIZATION: D = ClassTemplateSpecializationDecl::Create(*Context, Decl::EmptyShell()); break; case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION: D = ClassTemplatePartialSpecializationDecl::Create(*Context, - Decl::EmptyShell()); + Decl::EmptyShell()); break; case DECL_FUNCTION_TEMPLATE: - D = FunctionTemplateDecl::Create(*Context, 0, SourceLocation(), - DeclarationName(), 0, 0); + D = FunctionTemplateDecl::Create(*Context, Decl::EmptyShell()); break; case DECL_TEMPLATE_TYPE_PARM: D = TemplateTypeParmDecl::Create(*Context, Decl::EmptyShell()); break; case DECL_NON_TYPE_TEMPLATE_PARM: - D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0,0,0, - QualType(), false, 0); + D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), 0, 0, 0, QualType(), + false, 0); break; case DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK: - D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0, - 0, QualType(), 0, 0, Record[Idx++], - 0); + D = NonTypeTemplateParmDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), 0, 0, 0, QualType(), + 0, 0, Record[Idx++], 0); break; case DECL_TEMPLATE_TEMPLATE_PARM: D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0, false, 0, 0); break; case DECL_STATIC_ASSERT: - D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0); + D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0, + SourceLocation()); break; case DECL_OBJC_METHOD: @@ -1524,15 +1585,15 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { D = ObjCInterfaceDecl::Create(*Context, 0, SourceLocation(), 0); break; case DECL_OBJC_IVAR: - D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, - ObjCIvarDecl::None); + D = ObjCIvarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), + 0, QualType(), 0, ObjCIvarDecl::None); break; case DECL_OBJC_PROTOCOL: D = ObjCProtocolDecl::Create(*Context, 0, SourceLocation(), 0); break; case DECL_OBJC_AT_DEFS_FIELD: - D = ObjCAtDefsFieldDecl::Create(*Context, 0, SourceLocation(), 0, - QualType(), 0); + D = ObjCAtDefsFieldDecl::Create(*Context, 0, SourceLocation(), + SourceLocation(), 0, QualType(), 0); break; case DECL_OBJC_CLASS: D = ObjCClassDecl::Create(*Context, 0, SourceLocation()); @@ -1564,16 +1625,16 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { SourceLocation()); break; case DECL_FIELD: - D = FieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, 0, - false); + D = FieldDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0, + QualType(), 0, 0, false); break; case DECL_INDIRECTFIELD: D = IndirectFieldDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, 0); break; case DECL_VAR: - D = VarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, - SC_None, SC_None); + D = VarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0, + QualType(), 0, SC_None, SC_None); break; case DECL_IMPLICIT_PARAM: @@ -1581,11 +1642,12 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { break; case DECL_PARM_VAR: - D = ParmVarDecl::Create(*Context, 0, SourceLocation(), 0, QualType(), 0, - SC_None, SC_None, 0); + D = ParmVarDecl::Create(*Context, 0, SourceLocation(), SourceLocation(), 0, + QualType(), 0, SC_None, SC_None, 0); break; case DECL_FILE_SCOPE_ASM: - D = FileScopeAsmDecl::Create(*Context, 0, SourceLocation(), 0); + D = FileScopeAsmDecl::Create(*Context, 0, 0, SourceLocation(), + SourceLocation()); break; case DECL_BLOCK: D = BlockDecl::Create(*Context, 0, SourceLocation()); @@ -1614,22 +1676,26 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { // so we need to make sure we insert in front. For all other contexts, // the vector is empty here anyway, so there's no loss in efficiency. Infos.insert(Infos.begin(), Info); + } - // Now add the pending visible updates for this decl context, if it has - // any. - DeclContextVisibleUpdatesPending::iterator I = - PendingVisibleUpdates.find(ID); - if (I != PendingVisibleUpdates.end()) { - DeclContextVisibleUpdates &U = I->second; - Info.LexicalDecls = 0; - Info.NumLexicalDecls = 0; - for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end(); - UI != UE; ++UI) { - Info.NameLookupTableData = *UI; - Infos.push_back(Info); - } - PendingVisibleUpdates.erase(I); + // Now add the pending visible updates for this decl context, if it has any. + DeclContextVisibleUpdatesPending::iterator I = + PendingVisibleUpdates.find(ID); + if (I != PendingVisibleUpdates.end()) { + // There are updates. This means the context has external visible + // storage, even if the original stored version didn't. + DC->setHasExternalVisibleStorage(true); + DeclContextVisibleUpdates &U = I->second; + DeclContextInfos &Infos = DeclContextOffsets[DC]; + DeclContextInfo Info; + Info.LexicalDecls = 0; + Info.NumLexicalDecls = 0; + for (DeclContextVisibleUpdates::iterator UI = U.begin(), UE = U.end(); + UI != UE; ++UI) { + Info.NameLookupTableData = *UI; + Infos.push_back(Info); } + PendingVisibleUpdates.erase(I); } } assert(Idx == Record.size()); @@ -1652,7 +1718,7 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { unsigned RecCode = Cursor.ReadRecord(Code, Record); (void)RecCode; assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!"); - Reader.UpdateDecl(D, Record); + Reader.UpdateDecl(D, *F, Record); } } @@ -1666,7 +1732,8 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { return D; } -void ASTDeclReader::UpdateDecl(Decl *D, const RecordData &Record) { +void ASTDeclReader::UpdateDecl(Decl *D, ASTReader::PerFileData &Module, + const RecordData &Record) { unsigned Idx = 0; while (Idx < Record.size()) { switch ((DeclUpdateKind)Record[Idx++]) { @@ -1686,6 +1753,26 @@ void ASTDeclReader::UpdateDecl(Decl *D, const RecordData &Record) { case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: // It will be added to the template's specializations set when loaded. Reader.GetDecl(Record[Idx++]); + break; + + case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { + NamespaceDecl *Anon = cast<NamespaceDecl>(Reader.GetDecl(Record[Idx++])); + // Guard against these being loaded out of original order. Don't use + // getNextNamespace(), since it tries to access the context and can't in + // the middle of deserialization. + if (!Anon->NextNamespace) { + if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(D)) + TU->setAnonymousNamespace(Anon); + else + cast<NamespaceDecl>(D)->OrigOrAnonNamespace.setPointer(Anon); + } + break; + } + + case UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER: + cast<VarDecl>(D)->getMemberSpecializationInfo()->setPointOfInstantiation( + Reader.ReadSourceLocation(Module, Record, Idx)); + break; } } } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp index 42f0b1a..918db7e 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTReaderStmt.cpp @@ -97,7 +97,7 @@ namespace clang { void VisitParenListExpr(ParenListExpr *E); void VisitUnaryOperator(UnaryOperator *E); void VisitOffsetOfExpr(OffsetOfExpr *E); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); void VisitArraySubscriptExpr(ArraySubscriptExpr *E); void VisitCallExpr(CallExpr *E); void VisitMemberExpr(MemberExpr *E); @@ -122,6 +122,7 @@ namespace clang { void VisitShuffleVectorExpr(ShuffleVectorExpr *E); void VisitBlockExpr(BlockExpr *E); void VisitBlockDeclRefExpr(BlockDeclRefExpr *E); + void VisitGenericSelectionExpr(GenericSelectionExpr *E); void VisitObjCStringLiteral(ObjCStringLiteral *E); void VisitObjCEncodeExpr(ObjCEncodeExpr *E); void VisitObjCSelectorExpr(ObjCSelectorExpr *E); @@ -141,6 +142,7 @@ namespace clang { // C++ Statements void VisitCXXCatchStmt(CXXCatchStmt *S); void VisitCXXTryStmt(CXXTryStmt *S); + void VisitCXXForRangeStmt(CXXForRangeStmt *); void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); void VisitCXXConstructExpr(CXXConstructExpr *E); @@ -177,6 +179,8 @@ namespace clang { void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E); void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E); + void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E); + void VisitExpressionTraitExpr(ExpressionTraitExpr *E); void VisitCXXNoexceptExpr(CXXNoexceptExpr *E); void VisitPackExpansionExpr(PackExpansionExpr *E); void VisitSizeOfPackExpr(SizeOfPackExpr *E); @@ -208,7 +212,7 @@ void ASTStmtReader::VisitStmt(Stmt *S) { void ASTStmtReader::VisitNullStmt(NullStmt *S) { VisitStmt(S); S->setSemiLoc(ReadSourceLocation(Record, Idx)); - S->LeadingEmptyMacro = Record[Idx++]; + S->LeadingEmptyMacro = ReadSourceLocation(Record, Idx); } void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) { @@ -421,23 +425,23 @@ void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { VisitExpr(E); - bool HasQualifier = Record[Idx++]; - bool HasExplicitTemplateArgs = Record[Idx++]; - - E->DecoratedD.setInt((HasQualifier? DeclRefExpr::HasQualifierFlag : 0) | - (HasExplicitTemplateArgs - ? DeclRefExpr::HasExplicitTemplateArgumentListFlag : 0)); - - if (HasQualifier) { - E->getNameQualifier()->NNS = Reader.ReadNestedNameSpecifier(Record, Idx); - E->getNameQualifier()->Range = ReadSourceRange(Record, Idx); - } + E->DeclRefExprBits.HasQualifier = Record[Idx++]; + E->DeclRefExprBits.HasFoundDecl = Record[Idx++]; + E->DeclRefExprBits.HasExplicitTemplateArgs = Record[Idx++]; + unsigned NumTemplateArgs = 0; + if (E->hasExplicitTemplateArgs()) + NumTemplateArgs = Record[Idx++]; + + if (E->hasQualifier()) + E->getInternalQualifierLoc() + = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); + + if (E->hasFoundDecl()) + E->getInternalFoundDecl() = cast<NamedDecl>(Reader.GetDecl(Record[Idx++])); - if (HasExplicitTemplateArgs) { - unsigned NumTemplateArgs = Record[Idx++]; + if (E->hasExplicitTemplateArgs()) ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(), NumTemplateArgs); - } E->setDecl(cast<ValueDecl>(Reader.GetDecl(Record[Idx++]))); E->setLocation(ReadSourceLocation(Record, Idx)); @@ -468,7 +472,8 @@ void ASTStmtReader::VisitStringLiteral(StringLiteral *E) { assert(Record[Idx] == E->getNumConcatenated() && "Wrong number of concatenated tokens!"); ++Idx; - E->setWide(Record[Idx++]); + E->IsWide = Record[Idx++]; + E->IsPascal = Record[Idx++]; // Read string data llvm::SmallString<16> Str(&Record[Idx], &Record[Idx] + Len); @@ -555,9 +560,9 @@ void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { E->setIndexExpr(I, Reader.ReadSubExpr()); } -void ASTStmtReader::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { VisitExpr(E); - E->setSizeof(Record[Idx++]); + E->setKind(static_cast<UnaryExprOrTypeTrait>(Record[Idx++])); if (Record[Idx] == 0) { E->setArgument(Reader.ReadSubExpr()); ++Idx; @@ -680,16 +685,29 @@ void ASTStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { void ASTStmtReader::VisitInitListExpr(InitListExpr *E) { VisitExpr(E); - unsigned NumInits = Record[Idx++]; - E->reserveInits(*Reader.getContext(), NumInits); - for (unsigned I = 0; I != NumInits; ++I) - E->updateInit(*Reader.getContext(), I, Reader.ReadSubExpr()); E->setSyntacticForm(cast_or_null<InitListExpr>(Reader.ReadSubStmt())); E->setLBraceLoc(ReadSourceLocation(Record, Idx)); E->setRBraceLoc(ReadSourceLocation(Record, Idx)); - E->setInitializedFieldInUnion( - cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++]))); + bool isArrayFiller = Record[Idx++]; + Expr *filler = 0; + if (isArrayFiller) { + filler = Reader.ReadSubExpr(); + E->ArrayFillerOrUnionFieldInit = filler; + } else + E->ArrayFillerOrUnionFieldInit + = cast_or_null<FieldDecl>(Reader.GetDecl(Record[Idx++])); E->sawArrayRangeDesignator(Record[Idx++]); + unsigned NumInits = Record[Idx++]; + E->reserveInits(*Reader.getContext(), NumInits); + if (isArrayFiller) { + for (unsigned I = 0; I != NumInits; ++I) { + Expr *init = Reader.ReadSubExpr(); + E->updateInit(*Reader.getContext(), I, init ? init : filler); + } + } else { + for (unsigned I = 0; I != NumInits; ++I) + E->updateInit(*Reader.getContext(), I, Reader.ReadSubExpr()); + } } void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) { @@ -820,6 +838,25 @@ void ASTStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { E->setConstQualAdded(Record[Idx++]); } +void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) { + VisitExpr(E); + E->NumAssocs = Record[Idx++]; + E->AssocTypes = new (*Reader.getContext()) TypeSourceInfo*[E->NumAssocs]; + E->SubExprs = + new(*Reader.getContext()) Stmt*[GenericSelectionExpr::END_EXPR+E->NumAssocs]; + + E->SubExprs[GenericSelectionExpr::CONTROLLING] = Reader.ReadSubExpr(); + for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) { + E->AssocTypes[I] = GetTypeSourceInfo(Record, Idx); + E->SubExprs[GenericSelectionExpr::END_EXPR+I] = Reader.ReadSubExpr(); + } + E->ResultIndex = Record[Idx++]; + + E->GenericLoc = ReadSourceLocation(Record, Idx); + E->DefaultLoc = ReadSourceLocation(Record, Idx); + E->RParenLoc = ReadSourceLocation(Record, Idx); +} + //===----------------------------------------------------------------------===// // Objective-C Expressions and Statements @@ -998,6 +1035,19 @@ void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) { S->getStmts()[i + 1] = Reader.ReadSubStmt(); } +void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) { + VisitStmt(S); + S->setForLoc(ReadSourceLocation(Record, Idx)); + S->setColonLoc(ReadSourceLocation(Record, Idx)); + S->setRParenLoc(ReadSourceLocation(Record, Idx)); + S->setRangeStmt(Reader.ReadSubStmt()); + S->setBeginEndStmt(Reader.ReadSubStmt()); + S->setCond(Reader.ReadSubExpr()); + S->setInc(Reader.ReadSubExpr()); + S->setLoopVarStmt(Reader.ReadSubStmt()); + S->setBody(Reader.ReadSubStmt()); +} + void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { VisitCallExpr(E); E->setOperator((OverloadedOperatorKind)Record[Idx++]); @@ -1201,14 +1251,13 @@ ASTStmtReader::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(), Record[Idx++]); - E->setBase(Reader.ReadSubExpr()); - E->setBaseType(Reader.GetType(Record[Idx++])); - E->setArrow(Record[Idx++]); - E->setOperatorLoc(ReadSourceLocation(Record, Idx)); - E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); - E->setQualifierRange(ReadSourceRange(Record, Idx)); - E->setFirstQualifierFoundInScope( - cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++]))); + E->Base = Reader.ReadSubExpr(); + E->BaseType = Reader.GetType(Record[Idx++]); + E->IsArrow = Record[Idx++]; + E->OperatorLoc = ReadSourceLocation(Record, Idx); + E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); + E->FirstQualifierFoundInScope + = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++])); ReadDeclarationNameInfo(E->MemberNameInfo, Record, Idx); } @@ -1254,24 +1303,25 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) { E->initializeResults(*Reader.getContext(), Decls.begin(), Decls.end()); ReadDeclarationNameInfo(E->NameInfo, Record, Idx); - E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx)); - E->setQualifierRange(ReadSourceRange(Record, Idx)); + E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx); } void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { VisitOverloadExpr(E); - E->setArrow(Record[Idx++]); - E->setHasUnresolvedUsing(Record[Idx++]); - E->setBase(Reader.ReadSubExpr()); - E->setBaseType(Reader.GetType(Record[Idx++])); - E->setOperatorLoc(ReadSourceLocation(Record, Idx)); + E->IsArrow = Record[Idx++]; + E->HasUnresolvedUsing = Record[Idx++]; + E->Base = Reader.ReadSubExpr(); + E->BaseType = Reader.GetType(Record[Idx++]); + E->OperatorLoc = ReadSourceLocation(Record, Idx); } void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { VisitOverloadExpr(E); - E->setRequiresADL(Record[Idx++]); - E->setOverloaded(Record[Idx++]); - E->setNamingClass(cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++]))); + E->RequiresADL = Record[Idx++]; + if (E->RequiresADL) + E->StdIsAssociatedNamespace = Record[Idx++]; + E->Overloaded = Record[Idx++]; + E->NamingClass = cast_or_null<CXXRecordDecl>(Reader.GetDecl(Record[Idx++])); } void ASTStmtReader::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { @@ -1295,6 +1345,26 @@ void ASTStmtReader::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { E->RhsType = GetTypeSourceInfo(Record, Idx); } +void ASTStmtReader::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { + VisitExpr(E); + E->ATT = (ArrayTypeTrait)Record[Idx++]; + E->Value = (unsigned int)Record[Idx++]; + SourceRange Range = ReadSourceRange(Record, Idx); + E->Loc = Range.getBegin(); + E->RParen = Range.getEnd(); + E->QueriedType = GetTypeSourceInfo(Record, Idx); +} + +void ASTStmtReader::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { + VisitExpr(E); + E->ET = (ExpressionTrait)Record[Idx++]; + E->Value = (bool)Record[Idx++]; + SourceRange Range = ReadSourceRange(Record, Idx); + E->QueriedExpression = Reader.ReadSubExpr(); + E->Loc = Range.getBegin(); + E->RParen = Range.getEnd(); +} + void ASTStmtReader::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { VisitExpr(E); E->Value = (bool)Record[Idx++]; @@ -1500,12 +1570,13 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_DECL_REF: - S = DeclRefExpr::CreateEmpty(*Context, - /*HasQualifier=*/Record[ASTStmtReader::NumExprFields], - /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1], - /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1] - ? Record[ASTStmtReader::NumExprFields + 2] - : 0); + S = DeclRefExpr::CreateEmpty( + *Context, + /*HasQualifier=*/Record[ASTStmtReader::NumExprFields], + /*HasFoundDecl=*/Record[ASTStmtReader::NumExprFields + 1], + /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2], + /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2] ? + Record[ASTStmtReader::NumExprFields + 3] : 0); break; case EXPR_INTEGER_LITERAL: @@ -1548,7 +1619,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { break; case EXPR_SIZEOF_ALIGN_OF: - S = new (Context) SizeOfAlignOfExpr(Empty); + S = new (Context) UnaryExprOrTypeTraitExpr(Empty); break; case EXPR_ARRAY_SUBSCRIPT: @@ -1565,11 +1636,9 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { // logic with a MemberExpr::CreateEmpty. assert(Idx == 0); - NestedNameSpecifier *NNS = 0; - SourceRange QualifierRange; + NestedNameSpecifierLoc QualifierLoc; if (Record[Idx++]) { // HasQualifier. - NNS = ReadNestedNameSpecifier(Record, Idx); - QualifierRange = ReadSourceRange(F, Record, Idx); + QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx); } TemplateArgumentListInfo ArgInfo; @@ -1595,7 +1664,7 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { DeclarationNameInfo MemberNameInfo(MemberD->getDeclName(), MemberLoc); bool IsArrow = Record[Idx++]; - S = MemberExpr::Create(*Context, Base, IsArrow, NNS, QualifierRange, + S = MemberExpr::Create(*Context, Base, IsArrow, QualifierLoc, MemberD, FoundDecl, MemberNameInfo, HasExplicitTemplateArgs ? &ArgInfo : 0, T, VK, OK); ReadDeclarationNameLoc(F, cast<MemberExpr>(S)->MemberDNLoc, @@ -1683,6 +1752,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { S = new (Context) BlockDeclRefExpr(Empty); break; + case EXPR_GENERIC_SELECTION: + S = new (Context) GenericSelectionExpr(Empty); + break; + case EXPR_OBJC_STRING_LITERAL: S = new (Context) ObjCStringLiteral(Empty); break; @@ -1741,6 +1814,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { /*NumHandlers=*/Record[ASTStmtReader::NumStmtFields]); break; + case STMT_CXX_FOR_RANGE: + S = new (Context) CXXForRangeStmt(Empty); + break; + case EXPR_CXX_OPERATOR_CALL: S = new (Context) CXXOperatorCallExpr(*Context, Empty); break; @@ -1881,6 +1958,14 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { S = new (Context) BinaryTypeTraitExpr(Empty); break; + case EXPR_ARRAY_TYPE_TRAIT: + S = new (Context) ArrayTypeTraitExpr(Empty); + break; + + case EXPR_CXX_EXPRESSION_TRAIT: + S = new (Context) ExpressionTraitExpr(Empty); + break; + case EXPR_CXX_NOEXCEPT: S = new (Context) CXXNoexceptExpr(Empty); break; diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp index 383ca3d..6d44fb6 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriter.cpp @@ -37,6 +37,7 @@ #include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VersionTuple.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/StringExtras.h" @@ -50,12 +51,16 @@ using namespace clang; using namespace clang::serialization; template <typename T, typename Allocator> -T *data(std::vector<T, Allocator> &v) { - return v.empty() ? 0 : &v.front(); +static llvm::StringRef data(const std::vector<T, Allocator> &v) { + if (v.empty()) return llvm::StringRef(); + return llvm::StringRef(reinterpret_cast<const char*>(&v[0]), + sizeof(T) * v.size()); } -template <typename T, typename Allocator> -const T *data(const std::vector<T, Allocator> &v) { - return v.empty() ? 0 : &v.front(); + +template <typename T> +static llvm::StringRef data(const llvm::SmallVectorImpl<T> &v) { + return llvm::StringRef(reinterpret_cast<const char*>(v.data()), + sizeof(T) * v.size()); } //===----------------------------------------------------------------------===// @@ -104,12 +109,13 @@ void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) { } void ASTTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) { - Writer.AddTypeRef(T->getPointeeType(), Record); + Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record); + Record.push_back(T->isSpelledAsLValue()); Code = TYPE_LVALUE_REFERENCE; } void ASTTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) { - Writer.AddTypeRef(T->getPointeeType(), Record); + Writer.AddTypeRef(T->getPointeeTypeAsWritten(), Record); Code = TYPE_RVALUE_REFERENCE; } @@ -160,6 +166,7 @@ void ASTTypeWriter::VisitFunctionType(const FunctionType *T) { Writer.AddTypeRef(T->getResultType(), Record); FunctionType::ExtInfo C = T->getExtInfo(); Record.push_back(C.getNoReturn()); + Record.push_back(C.getHasRegParm()); Record.push_back(C.getRegParm()); // FIXME: need to stabilize encoding of calling convention... Record.push_back(C.getCC()); @@ -178,11 +185,14 @@ void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { Record.push_back(T->isVariadic()); Record.push_back(T->getTypeQuals()); Record.push_back(static_cast<unsigned>(T->getRefQualifier())); - Record.push_back(T->hasExceptionSpec()); - Record.push_back(T->hasAnyExceptionSpec()); - Record.push_back(T->getNumExceptions()); - for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) - Writer.AddTypeRef(T->getExceptionType(I), Record); + Record.push_back(T->getExceptionSpecType()); + if (T->getExceptionSpecType() == EST_Dynamic) { + Record.push_back(T->getNumExceptions()); + for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) + Writer.AddTypeRef(T->getExceptionType(I), Record); + } else if (T->getExceptionSpecType() == EST_ComputedNoexcept) { + Writer.AddStmt(T->getNoexceptExpr()); + } Code = TYPE_FUNCTION_PROTO; } @@ -293,7 +303,7 @@ ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) { Record.push_back(T->getDepth()); Record.push_back(T->getIndex()); Record.push_back(T->isParameterPack()); - Writer.AddIdentifierRef(T->getName(), Record); + Writer.AddDeclRef(T->getDecl(), Record); Code = TYPE_TEMPLATE_TYPE_PARM; } @@ -418,6 +428,7 @@ void TypeLocWriter::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { } void TypeLocWriter::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { Writer.AddSourceLocation(TL.getStarLoc(), Record); + Writer.AddTypeSourceInfo(TL.getClassTInfo(), Record); } void TypeLocWriter::VisitArrayTypeLoc(ArrayTypeLoc TL) { Writer.AddSourceLocation(TL.getLBracketLoc(), Record); @@ -450,8 +461,8 @@ void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { - Writer.AddSourceLocation(TL.getLParenLoc(), Record); - Writer.AddSourceLocation(TL.getRParenLoc(), Record); + Writer.AddSourceLocation(TL.getLocalRangeBegin(), Record); + Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record); Record.push_back(TL.getTrailingReturn()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) Writer.AddDeclRef(TL.getArg(i), Record); @@ -532,20 +543,20 @@ void TypeLocWriter::VisitParenTypeLoc(ParenTypeLoc TL) { } void TypeLocWriter::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { Writer.AddSourceLocation(TL.getKeywordLoc(), Record); - Writer.AddSourceRange(TL.getQualifierRange(), Record); + Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record); } void TypeLocWriter::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { Writer.AddSourceLocation(TL.getKeywordLoc(), Record); - Writer.AddSourceRange(TL.getQualifierRange(), Record); + Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record); Writer.AddSourceLocation(TL.getNameLoc(), Record); } void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL) { Writer.AddSourceLocation(TL.getKeywordLoc(), Record); - Writer.AddSourceRange(TL.getQualifierRange(), Record); + Writer.AddNestedNameSpecifierLoc(TL.getQualifierLoc(), Record); Writer.AddSourceLocation(TL.getNameLoc(), Record); Writer.AddSourceLocation(TL.getLAngleLoc(), Record); Writer.AddSourceLocation(TL.getRAngleLoc(), Record); @@ -652,6 +663,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream, RECORD(EXPR_SHUFFLE_VECTOR); RECORD(EXPR_BLOCK); RECORD(EXPR_BLOCK_DECL_REF); + RECORD(EXPR_GENERIC_SELECTION); RECORD(EXPR_OBJC_STRING_LITERAL); RECORD(EXPR_OBJC_ENCODE); RECORD(EXPR_OBJC_SELECTOR_EXPR); @@ -1000,6 +1012,7 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.Digraphs); // C94, C99 and C++ Record.push_back(LangOpts.HexFloats); // C99 Hexadecimal float constants. Record.push_back(LangOpts.C99); // C99 Support + Record.push_back(LangOpts.C1X); // C1X Support Record.push_back(LangOpts.Microsoft); // Microsoft extensions. // LangOpts.MSCVersion is ignored because all it does it set a macro, which is // already saved elsewhere. @@ -1054,6 +1067,7 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.GNUInline); // Should GNU inline semantics be // used (instead of C99 semantics). Record.push_back(LangOpts.NoInline); // Should __NO_INLINE__ be defined. + Record.push_back(LangOpts.Deprecated); // Should __DEPRECATED be defined. Record.push_back(LangOpts.AccessControl); // Whether C++ access control should // be enabled. Record.push_back(LangOpts.CharIsSigned); // Whether char is a signed or @@ -1072,6 +1086,7 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) { Record.push_back(LangOpts.DefaultFPContract); Record.push_back(LangOpts.ElideConstructors); Record.push_back(LangOpts.SpellChecking); + Record.push_back(LangOpts.MRTD); Stream.EmitRecord(LANGUAGE_OPTIONS, Record); } @@ -1427,7 +1442,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Figure out which record code to use. unsigned Code; if (SLoc->isFile()) { - if (SLoc->getFile().getContentCache()->Entry) + if (SLoc->getFile().getContentCache()->OrigEntry) Code = SM_SLOC_FILE_ENTRY; else Code = SM_SLOC_BUFFER_ENTRY; @@ -1444,17 +1459,27 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Record.push_back(File.hasLineDirectives()); const SrcMgr::ContentCache *Content = File.getContentCache(); - if (Content->Entry) { + if (Content->OrigEntry) { + assert(Content->OrigEntry == Content->ContentsEntry && + "Writing to AST an overriden file is not supported"); + // The source location entry is a file. The blob associated // with this entry is the file name. // Emit size/modification time for this file. - Record.push_back(Content->Entry->getSize()); - Record.push_back(Content->Entry->getModificationTime()); + Record.push_back(Content->OrigEntry->getSize()); + Record.push_back(Content->OrigEntry->getModificationTime()); // Turn the file name into an absolute path, if it isn't already. - const char *Filename = Content->Entry->getName(); + const char *Filename = Content->OrigEntry->getName(); llvm::SmallString<128> FilePath(Filename); + + // Ask the file manager to fixup the relative path for us. This will + // honor the working directory. + SourceMgr.getFileManager().FixupRelativePath(FilePath); + + // FIXME: This call to make_absolute shouldn't be necessary, the + // call to FixupRelativePath should always return an absolute path. llvm::sys::fs::make_absolute(FilePath); Filename = FilePath.c_str(); @@ -1517,9 +1542,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Record.push_back(SLocEntryOffsets.size()); unsigned BaseOffset = Chain ? Chain->getNextSLocOffset() : 0; Record.push_back(SourceMgr.getNextOffset() - BaseOffset); - Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, - (const char *)data(SLocEntryOffsets), - SLocEntryOffsets.size()*sizeof(SLocEntryOffsets[0])); + Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets)); // Write the source location entry preloads array, telling the AST // reader which source locations entries it should load eagerly. @@ -1778,8 +1801,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { Record.push_back(NumPreprocessingRecords); Record.push_back(MacroDefinitionOffsets.size()); Stream.EmitRecordWithBlob(MacroDefOffsetAbbrev, Record, - (const char *)data(MacroDefinitionOffsets), - MacroDefinitionOffsets.size() * sizeof(uint32_t)); + data(MacroDefinitionOffsets)); } } @@ -1809,6 +1831,29 @@ void ASTWriter::WritePragmaDiagnosticMappings(const Diagnostic &Diag) { Stream.EmitRecord(DIAG_PRAGMA_MAPPINGS, Record); } +void ASTWriter::WriteCXXBaseSpecifiersOffsets() { + if (CXXBaseSpecifiersOffsets.empty()) + return; + + RecordData Record; + + // Create a blob abbreviation for the C++ base specifiers offsets. + using namespace llvm; + + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(CXX_BASE_SPECIFIER_OFFSETS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev); + + // Write the selector offsets table. + Record.clear(); + Record.push_back(CXX_BASE_SPECIFIER_OFFSETS); + Record.push_back(CXXBaseSpecifiersOffsets.size()); + Stream.EmitRecordWithBlob(BaseSpecifierOffsetAbbrev, Record, + data(CXXBaseSpecifiersOffsets)); +} + //===----------------------------------------------------------------------===// // Type Serialization //===----------------------------------------------------------------------===// @@ -1881,9 +1926,7 @@ uint64_t ASTWriter::WriteDeclContextLexicalBlock(ASTContext &Context, Decls.push_back(std::make_pair((*D)->getKind(), GetDeclRef(*D))); ++NumLexicalDeclContexts; - Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, - reinterpret_cast<char*>(Decls.data()), - Decls.size() * sizeof(KindDeclIDPair)); + Stream.EmitRecordWithBlob(DeclContextLexicalAbbrev, Record, data(Decls)); return Offset; } @@ -1900,9 +1943,7 @@ void ASTWriter::WriteTypeDeclOffsets() { Record.clear(); Record.push_back(TYPE_OFFSET); Record.push_back(TypeOffsets.size()); - Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, - (const char *)data(TypeOffsets), - TypeOffsets.size() * sizeof(TypeOffsets[0])); + Stream.EmitRecordWithBlob(TypeOffsetAbbrev, Record, data(TypeOffsets)); // Write the declaration offsets array Abbrev = new BitCodeAbbrev(); @@ -1913,9 +1954,7 @@ void ASTWriter::WriteTypeDeclOffsets() { Record.clear(); Record.push_back(DECL_OFFSET); Record.push_back(DeclOffsets.size()); - Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, - (const char *)data(DeclOffsets), - DeclOffsets.size() * sizeof(DeclOffsets[0])); + Stream.EmitRecordWithBlob(DeclOffsetAbbrev, Record, data(DeclOffsets)); } //===----------------------------------------------------------------------===// @@ -2102,8 +2141,7 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { Record.push_back(SELECTOR_OFFSETS); Record.push_back(SelectorOffsets.size()); Stream.EmitRecordWithBlob(SelectorOffsetAbbrev, Record, - (const char *)data(SelectorOffsets), - SelectorOffsets.size() * 4); + data(SelectorOffsets)); } } @@ -2305,8 +2343,7 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP) { Record.push_back(IDENTIFIER_OFFSET); Record.push_back(IdentifierOffsets.size()); Stream.EmitRecordWithBlob(IdentifierOffsetAbbrev, Record, - (const char *)data(IdentifierOffsets), - IdentifierOffsets.size() * sizeof(uint32_t)); + data(IdentifierOffsets)); } //===----------------------------------------------------------------------===// @@ -2583,6 +2620,19 @@ void ASTWriter::AddString(llvm::StringRef Str, RecordDataImpl &Record) { Record.insert(Record.end(), Str.begin(), Str.end()); } +void ASTWriter::AddVersionTuple(const VersionTuple &Version, + RecordDataImpl &Record) { + Record.push_back(Version.getMajor()); + if (llvm::Optional<unsigned> Minor = Version.getMinor()) + Record.push_back(*Minor + 1); + else + Record.push_back(0); + if (llvm::Optional<unsigned> Subminor = Version.getSubminor()) + Record.push_back(*Subminor + 1); + else + Record.push_back(0); +} + /// \brief Note that the identifier II occurs at the given offset /// within the identifier table. void ASTWriter::SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset) { @@ -2770,6 +2820,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, AddTypeRef(Context.ObjCSelRedefinitionType, Record); AddTypeRef(Context.getRawNSConstantStringType(), Record); Record.push_back(Context.isInt128Installed()); + AddTypeRef(Context.AutoDeductTy, Record); + AddTypeRef(Context.AutoRRefDeductTy, Record); Stream.EmitRecord(SPECIAL_TYPES, Record); // Keep writing types and declarations until all types and @@ -2797,25 +2849,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, WriteTypeDeclOffsets(); WritePragmaDiagnosticMappings(Context.getDiagnostics()); - // Write the C++ base-specifier set offsets. - if (!CXXBaseSpecifiersOffsets.empty()) { - // Create a blob abbreviation for the C++ base specifiers offsets. - using namespace llvm; - - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(CXX_BASE_SPECIFIER_OFFSETS)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // size - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned BaseSpecifierOffsetAbbrev = Stream.EmitAbbrev(Abbrev); - - // Write the selector offsets table. - Record.clear(); - Record.push_back(CXX_BASE_SPECIFIER_OFFSETS); - Record.push_back(CXXBaseSpecifiersOffsets.size()); - Stream.EmitRecordWithBlob(BaseSpecifierOffsetAbbrev, Record, - (const char *)CXXBaseSpecifiersOffsets.data(), - CXXBaseSpecifiersOffsets.size() * sizeof(uint32_t)); - } + WriteCXXBaseSpecifiersOffsets(); // Write the record containing external, unnamed definitions. if (!ExternalDefinitions.empty()) @@ -2911,8 +2945,7 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, Record.clear(); Record.push_back(TU_UPDATE_LEXICAL); Stream.EmitRecordWithBlob(TuUpdateLexicalAbbrev, Record, - reinterpret_cast<const char*>(NewGlobalDecls.data()), - NewGlobalDecls.size() * sizeof(KindDeclIDPair)); + data(NewGlobalDecls)); // And a visible updates block for the DeclContexts. Abv = new llvm::BitCodeAbbrev(); Abv->Add(llvm::BitCodeAbbrevOp(UPDATE_VISIBLE)); @@ -2997,10 +3030,8 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, for (std::deque<Sema::PendingImplicitInstantiation>::iterator I = SemaRef.PendingInstantiations.begin(), N = SemaRef.PendingInstantiations.end(); I != N; ++I) { - if (I->first->getPCHLevel() == 0) { - AddDeclRef(I->first, PendingInstantiations); - AddSourceLocation(I->second, PendingInstantiations); - } + AddDeclRef(I->first, PendingInstantiations); + AddSourceLocation(I->second, PendingInstantiations); } assert(SemaRef.PendingLocalImplicitInstantiations.empty() && "There are local ones at end of translation unit!"); @@ -3040,6 +3071,8 @@ void ASTWriter::WriteASTChain(Sema &SemaRef, MemorizeStatCalls *StatCalls, // write all of them again). WritePragmaDiagnosticMappings(Context.getDiagnostics()); + WriteCXXBaseSpecifiersOffsets(); + /// Build a record containing first declarations from a chained PCH and the /// most recent declarations in this AST that they point to. RecordData FirstLatestDeclIDs; @@ -3245,11 +3278,11 @@ void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, AddTypeSourceInfo(Arg.getAsTypeSourceInfo(), Record); break; case TemplateArgument::Template: - AddSourceRange(Arg.getTemplateQualifierRange(), Record); + AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc(), Record); AddSourceLocation(Arg.getTemplateNameLoc(), Record); break; case TemplateArgument::TemplateExpansion: - AddSourceRange(Arg.getTemplateQualifierRange(), Record); + AddNestedNameSpecifierLoc(Arg.getTemplateQualifierLoc(), Record); AddSourceLocation(Arg.getTemplateNameLoc(), Record); AddSourceLocation(Arg.getTemplateEllipsisLoc(), Record); break; @@ -3452,7 +3485,7 @@ void ASTWriter::AddQualifierInfo(const QualifierInfo &Info, void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS, RecordDataImpl &Record) { // Nested name specifiers usually aren't too long. I think that 8 would - // typically accomodate the vast majority. + // typically accommodate the vast majority. llvm::SmallVector<NestedNameSpecifier *, 8> NestedNames; // Push each of the NNS's onto a stack for serialization in reverse order. @@ -3495,7 +3528,7 @@ void ASTWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS, void ASTWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, RecordDataImpl &Record) { // Nested name specifiers usually aren't too long. I think that 8 would - // typically accomodate the vast majority. + // typically accommodate the vast majority. llvm::SmallVector<NestedNameSpecifierLoc , 8> NestedNames; // Push each of the nested-name-specifiers's onto a stack for @@ -3749,10 +3782,19 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Data.Empty); Record.push_back(Data.Polymorphic); Record.push_back(Data.Abstract); + Record.push_back(Data.IsStandardLayout); + Record.push_back(Data.HasNoNonEmptyBases); + Record.push_back(Data.HasPrivateFields); + Record.push_back(Data.HasProtectedFields); + Record.push_back(Data.HasPublicFields); Record.push_back(Data.HasTrivialConstructor); + Record.push_back(Data.HasConstExprNonCopyMoveConstructor); Record.push_back(Data.HasTrivialCopyConstructor); + Record.push_back(Data.HasTrivialMoveConstructor); Record.push_back(Data.HasTrivialCopyAssignment); + Record.push_back(Data.HasTrivialMoveAssignment); Record.push_back(Data.HasTrivialDestructor); + Record.push_back(Data.HasNonLiteralTypeFieldsOrBases); Record.push_back(Data.ComputedVisibleConversions); Record.push_back(Data.DeclaredDefaultConstructor); Record.push_back(Data.DeclaredCopyConstructor); @@ -3897,4 +3939,37 @@ void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, AddDeclRef(D, Record); } +void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D) { + // The specializations set is kept in the canonical template. + TD = TD->getCanonicalDecl(); + if (!(D->getPCHLevel() == 0 && TD->getPCHLevel() > 0)) + return; // Not a source specialization added to a template from PCH. + + UpdateRecord &Record = DeclUpdates[TD]; + Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); + AddDeclRef(D, Record); +} + +void ASTWriter::CompletedImplicitDefinition(const FunctionDecl *D) { + if (D->getPCHLevel() == 0) + return; // Declaration not imported from PCH. + + // Implicit decl from a PCH was defined. + // FIXME: Should implicit definition be a separate FunctionDecl? + RewriteDecl(D); +} + +void ASTWriter::StaticDataMemberInstantiated(const VarDecl *D) { + if (D->getPCHLevel() == 0) + return; + + // Since the actual instantiation is delayed, this really means that we need + // to update the instantiation location. + UpdateRecord &Record = DeclUpdates[D]; + Record.push_back(UPD_CXX_INSTANTIATED_STATIC_DATA_MEMBER); + AddSourceLocation( + D->getMemberSpecializationInfo()->getPointOfInstantiation(), Record); +} + ASTSerializationListener::~ASTSerializationListener() { } diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp index 12d1226..1ca00a3 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterDecl.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Serialization/ASTWriter.h" +#include "ASTCommon.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" @@ -21,6 +22,7 @@ #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; +using namespace serialization; //===----------------------------------------------------------------------===// // Declaration serialization @@ -53,6 +55,7 @@ namespace clang { void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); void VisitTypeDecl(TypeDecl *D); void VisitTypedefDecl(TypedefDecl *D); + void VisitTypeAliasDecl(TypeAliasDecl *D); void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); void VisitTagDecl(TagDecl *D); void VisitEnumDecl(EnumDecl *D); @@ -140,6 +143,7 @@ void ASTDeclWriter::VisitDecl(Decl *D) { Writer.WriteAttributes(D->getAttrs(), Record); Record.push_back(D->isImplicit()); Record.push_back(D->isUsed(false)); + Record.push_back(D->isReferenced()); Record.push_back(D->getAccess()); Record.push_back(D->getPCHLevel()); } @@ -157,6 +161,7 @@ void ASTDeclWriter::VisitNamedDecl(NamedDecl *D) { void ASTDeclWriter::VisitTypeDecl(TypeDecl *D) { VisitNamedDecl(D); + Writer.AddSourceLocation(D->getLocStart(), Record); Writer.AddTypeRef(QualType(D->getTypeForDecl(), 0), Record); } @@ -166,6 +171,12 @@ void ASTDeclWriter::VisitTypedefDecl(TypedefDecl *D) { Code = serialization::DECL_TYPEDEF; } +void ASTDeclWriter::VisitTypeAliasDecl(TypeAliasDecl *D) { + VisitTypeDecl(D); + Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record); + Code = serialization::DECL_TYPEALIAS; +} + void ASTDeclWriter::VisitTagDecl(TagDecl *D) { VisitTypeDecl(D); VisitRedeclarable(D); @@ -174,12 +185,11 @@ void ASTDeclWriter::VisitTagDecl(TagDecl *D) { Record.push_back(D->isDefinition()); Record.push_back(D->isEmbeddedInDeclarator()); Writer.AddSourceLocation(D->getRBraceLoc(), Record); - Writer.AddSourceLocation(D->getTagKeywordLoc(), Record); Record.push_back(D->hasExtInfo()); if (D->hasExtInfo()) Writer.AddQualifierInfo(*D->getExtInfo(), Record); else - Writer.AddDeclRef(D->getTypedefForAnonDecl(), Record); + Writer.AddDeclRef(D->getTypedefNameForAnonDecl(), Record); } void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) { @@ -221,6 +231,7 @@ void ASTDeclWriter::VisitEnumConstantDecl(EnumConstantDecl *D) { void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { VisitValueDecl(D); + Writer.AddSourceLocation(D->getInnerLocStart(), Record); Record.push_back(D->hasExtInfo()); if (D->hasExtInfo()) Writer.AddQualifierInfo(*D->getExtInfo(), Record); @@ -552,6 +563,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { Record.push_back(D->hasCXXDirectInitializer()); Record.push_back(D->isExceptionVariable()); Record.push_back(D->isNRVOVariable()); + Record.push_back(D->isCXXForRangeDecl()); Record.push_back(D->getInit() ? 1 : 0); if (D->getInit()) Writer.AddStmt(D->getInit()); @@ -575,7 +587,11 @@ void ASTDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) { void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { VisitVarDecl(D); + Record.push_back(D->isObjCMethodParameter()); + Record.push_back(D->getFunctionScopeDepth()); + Record.push_back(D->getFunctionScopeIndex()); Record.push_back(D->getObjCDeclQualifier()); // FIXME: stable encoding + Record.push_back(D->isKNRPromoted()); Record.push_back(D->hasInheritedDefaultArg()); Record.push_back(D->hasUninstantiatedDefaultArg()); if (D->hasUninstantiatedDefaultArg()) @@ -593,7 +609,9 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { D->getPCHLevel() == 0 && D->getStorageClass() == 0 && !D->hasCXXDirectInitializer() && // Can params have this ever? + D->getFunctionScopeDepth() == 0 && D->getObjCDeclQualifier() == 0 && + !D->isKNRPromoted() && !D->hasInheritedDefaultArg() && D->getInit() == 0 && !D->hasUninstantiatedDefaultArg()) // No default expr. @@ -613,6 +631,7 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) { void ASTDeclWriter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { VisitDecl(D); Writer.AddStmt(D->getAsmString()); + Writer.AddSourceLocation(D->getRParenLoc(), Record); Code = serialization::DECL_FILE_SCOPE_ASM; } @@ -645,15 +664,15 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) { void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { VisitDecl(D); - // FIXME: It might be nice to serialize the brace locations for this - // declaration, which don't seem to be readily available in the AST. Record.push_back(D->getLanguage()); - Record.push_back(D->hasBraces()); + Writer.AddSourceLocation(D->getExternLoc(), Record); + Writer.AddSourceLocation(D->getRBraceLoc(), Record); Code = serialization::DECL_LINKAGE_SPEC; } void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) { VisitNamedDecl(D); + Writer.AddSourceLocation(D->getLocStart(), Record); Code = serialization::DECL_LABEL; } @@ -661,8 +680,8 @@ void ASTDeclWriter::VisitLabelDecl(LabelDecl *D) { void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { VisitNamedDecl(D); Record.push_back(D->isInline()); - Writer.AddSourceLocation(D->getLBracLoc(), Record); - Writer.AddSourceLocation(D->getRBracLoc(), Record); + Writer.AddSourceLocation(D->getLocStart(), Record); + Writer.AddSourceLocation(D->getRBraceLoc(), Record); Writer.AddDeclRef(D->getNextNamespace(), Record); // Only write one reference--original or anonymous @@ -692,6 +711,20 @@ void ASTDeclWriter::VisitNamespaceDecl(NamespaceDecl *D) { } } } + + if (Writer.hasChain() && D->isAnonymousNamespace() && !D->getNextNamespace()){ + // This is a most recent reopening of the anonymous namespace. If its parent + // is in a previous PCH (or is the TU), mark that parent for update, because + // the original namespace always points to the latest re-opening of its + // anonymous namespace. + Decl *Parent = cast<Decl>( + D->getParent()->getRedeclContext()->getPrimaryContext()); + if (Parent->getPCHLevel() > 0) { + ASTWriter::UpdateRecord &Record = Writer.DeclUpdates[Parent]; + Record.push_back(UPD_CXX_ADDED_ANONYMOUS_NAMESPACE); + Writer.AddDeclRef(D, Record); + } + } } void ASTDeclWriter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { @@ -743,7 +776,6 @@ void ASTDeclWriter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { void ASTDeclWriter::VisitUnresolvedUsingTypenameDecl( UnresolvedUsingTypenameDecl *D) { VisitTypeDecl(D); - Writer.AddSourceLocation(D->getUsingLoc(), Record); Writer.AddSourceLocation(D->getTypenameLoc(), Record); Writer.AddNestedNameSpecifierLoc(D->getQualifierLoc(), Record); Code = serialization::DECL_UNRESOLVED_USING_TYPENAME; @@ -1001,7 +1033,6 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { VisitTypeDecl(D); Record.push_back(D->wasDeclaredWithTypename()); - Record.push_back(D->isParameterPack()); Record.push_back(D->defaultArgumentWasInherited()); Writer.AddTypeSourceInfo(D->getDefaultArgumentInfo(), Record); @@ -1054,6 +1085,7 @@ void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) { VisitDecl(D); Writer.AddStmt(D->getAssertExpr()); Writer.AddStmt(D->getMessage()); + Writer.AddSourceLocation(D->getRParenLoc(), Record); Code = serialization::DECL_STATIC_ASSERT; } @@ -1121,6 +1153,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs Abv->Add(BitCodeAbbrevOp(0)); // isImplicit Abv->Add(BitCodeAbbrevOp(0)); // isUsed + Abv->Add(BitCodeAbbrevOp(0)); // isReferenced Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier Abv->Add(BitCodeAbbrevOp(0)); // PCH level @@ -1130,6 +1163,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { // ValueDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type // DeclaratorDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerStartLoc Abv->Add(BitCodeAbbrevOp(0)); // hasExtInfo Abv->Add(BitCodeAbbrevOp(serialization::PREDEF_TYPE_NULL_ID)); // InfoType // VarDecl @@ -1140,10 +1174,15 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // hasCXXDirectInitializer Abv->Add(BitCodeAbbrevOp(0)); // isExceptionVariable Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable + Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl Abv->Add(BitCodeAbbrevOp(0)); // HasInit Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo // ParmVarDecl + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsObjCMethodParameter + Abv->Add(BitCodeAbbrevOp(0)); // ScopeDepth + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ScopeIndex Abv->Add(BitCodeAbbrevOp(0)); // ObjCDeclQualifier + Abv->Add(BitCodeAbbrevOp(0)); // KNRPromoted Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedDefaultArg Abv->Add(BitCodeAbbrevOp(0)); // HasUninstantiatedDefaultArg diff --git a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp index af846a9..bd5889a 100644 --- a/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Serialization/ASTWriterStmt.cpp @@ -68,7 +68,7 @@ namespace clang { void VisitParenListExpr(ParenListExpr *E); void VisitUnaryOperator(UnaryOperator *E); void VisitOffsetOfExpr(OffsetOfExpr *E); - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); void VisitArraySubscriptExpr(ArraySubscriptExpr *E); void VisitCallExpr(CallExpr *E); void VisitMemberExpr(MemberExpr *E); @@ -93,6 +93,7 @@ namespace clang { void VisitShuffleVectorExpr(ShuffleVectorExpr *E); void VisitBlockExpr(BlockExpr *E); void VisitBlockDeclRefExpr(BlockDeclRefExpr *E); + void VisitGenericSelectionExpr(GenericSelectionExpr *E); // Objective-C Expressions void VisitObjCStringLiteral(ObjCStringLiteral *E); @@ -115,6 +116,7 @@ namespace clang { // C++ Statements void VisitCXXCatchStmt(CXXCatchStmt *S); void VisitCXXTryStmt(CXXTryStmt *S); + void VisitCXXForRangeStmt(CXXForRangeStmt *); void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E); void VisitCXXMemberCallExpr(CXXMemberCallExpr *E); @@ -151,6 +153,8 @@ namespace clang { void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E); void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E); + void VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E); + void VisitExpressionTraitExpr(ExpressionTraitExpr *E); void VisitCXXNoexceptExpr(CXXNoexceptExpr *E); void VisitPackExpansionExpr(PackExpansionExpr *E); void VisitSizeOfPackExpr(SizeOfPackExpr *E); @@ -177,7 +181,7 @@ void ASTStmtWriter::VisitStmt(Stmt *S) { void ASTStmtWriter::VisitNullStmt(NullStmt *S) { VisitStmt(S); Writer.AddSourceLocation(S->getSemiLoc(), Record); - Record.push_back(S->LeadingEmptyMacro); + Writer.AddSourceLocation(S->LeadingEmptyMacro, Record); Code = serialization::STMT_NULL; } @@ -380,19 +384,23 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) { VisitExpr(E); Record.push_back(E->hasQualifier()); + Record.push_back(E->getDecl() != E->getFoundDecl()); Record.push_back(E->hasExplicitTemplateArgs()); - if (E->hasQualifier()) { - Writer.AddNestedNameSpecifier(E->getQualifier(), Record); - Writer.AddSourceRange(E->getQualifierRange(), Record); - } - if (E->hasExplicitTemplateArgs()) { unsigned NumTemplateArgs = E->getNumTemplateArgs(); Record.push_back(NumTemplateArgs); - AddExplicitTemplateArgumentList(E->getExplicitTemplateArgs()); } + if (E->hasQualifier()) + Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record); + + if (E->getDecl() != E->getFoundDecl()) + Writer.AddDeclRef(E->getFoundDecl(), Record); + + if (E->hasExplicitTemplateArgs()) + AddExplicitTemplateArgumentList(E->getExplicitTemplateArgs()); + Writer.AddDeclRef(E->getDecl(), Record); Writer.AddSourceLocation(E->getLocation(), Record); Writer.AddDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName(), Record); @@ -425,6 +433,7 @@ void ASTStmtWriter::VisitStringLiteral(StringLiteral *E) { Record.push_back(E->getByteLength()); Record.push_back(E->getNumConcatenated()); Record.push_back(E->isWide()); + Record.push_back(E->isPascal()); // FIXME: String data should be stored as a blob at the end of the // StringLiteral. However, we can't do so now because we have no // provision for coping with abbreviations when we're jumping around @@ -479,8 +488,8 @@ void ASTStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) { for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { const OffsetOfExpr::OffsetOfNode &ON = E->getComponent(I); Record.push_back(ON.getKind()); // FIXME: Stable encoding - Writer.AddSourceLocation(ON.getRange().getBegin(), Record); - Writer.AddSourceLocation(ON.getRange().getEnd(), Record); + Writer.AddSourceLocation(ON.getSourceRange().getBegin(), Record); + Writer.AddSourceLocation(ON.getSourceRange().getEnd(), Record); switch (ON.getKind()) { case OffsetOfExpr::OffsetOfNode::Array: Record.push_back(ON.getArrayExprIndex()); @@ -504,9 +513,9 @@ void ASTStmtWriter::VisitOffsetOfExpr(OffsetOfExpr *E) { Code = serialization::EXPR_OFFSETOF; } -void ASTStmtWriter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { +void ASTStmtWriter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { VisitExpr(E); - Record.push_back(E->isSizeOf()); + Record.push_back(E->getKind()); if (E->isArgumentType()) Writer.AddTypeSourceInfo(E->getArgumentTypeInfo(), Record); else { @@ -541,10 +550,8 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) { // Don't call VisitExpr, we'll write everything here. Record.push_back(E->hasQualifier()); - if (E->hasQualifier()) { - Writer.AddNestedNameSpecifier(E->getQualifier(), Record); - Writer.AddSourceRange(E->getQualifierRange(), Record); - } + if (E->hasQualifier()) + Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record); Record.push_back(E->hasExplicitTemplateArgs()); if (E->hasExplicitTemplateArgs()) { @@ -666,14 +673,27 @@ void ASTStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) { VisitExpr(E); - Record.push_back(E->getNumInits()); - for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) - Writer.AddStmt(E->getInit(I)); Writer.AddStmt(E->getSyntacticForm()); Writer.AddSourceLocation(E->getLBraceLoc(), Record); Writer.AddSourceLocation(E->getRBraceLoc(), Record); - Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record); + bool isArrayFiller = E->ArrayFillerOrUnionFieldInit.is<Expr*>(); + Record.push_back(isArrayFiller); + if (isArrayFiller) + Writer.AddStmt(E->getArrayFiller()); + else + Writer.AddDeclRef(E->getInitializedFieldInUnion(), Record); Record.push_back(E->hadArrayRangeDesignator()); + Record.push_back(E->getNumInits()); + if (isArrayFiller) { + // ArrayFiller may have filled "holes" due to designated initializer. + // Replace them by 0 to indicate that the filler goes in that place. + Expr *filler = E->getArrayFiller(); + for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) + Writer.AddStmt(E->getInit(I) != filler ? E->getInit(I) : 0); + } else { + for (unsigned I = 0, N = E->getNumInits(); I != N; ++I) + Writer.AddStmt(E->getInit(I)); + } Code = serialization::EXPR_INIT_LIST; } @@ -785,6 +805,23 @@ void ASTStmtWriter::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) { Code = serialization::EXPR_BLOCK_DECL_REF; } +void ASTStmtWriter::VisitGenericSelectionExpr(GenericSelectionExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumAssocs()); + + Writer.AddStmt(E->getControllingExpr()); + for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) { + Writer.AddTypeSourceInfo(E->getAssocTypeSourceInfo(I), Record); + Writer.AddStmt(E->getAssocExpr(I)); + } + Record.push_back(E->isResultDependent() ? -1U : E->getResultIndex()); + + Writer.AddSourceLocation(E->getGenericLoc(), Record); + Writer.AddSourceLocation(E->getDefaultLoc(), Record); + Writer.AddSourceLocation(E->getRParenLoc(), Record); + Code = serialization::EXPR_GENERIC_SELECTION; +} + //===----------------------------------------------------------------------===// // Objective-C Expressions and Statements. //===----------------------------------------------------------------------===// @@ -964,6 +1001,20 @@ void ASTStmtWriter::VisitCXXTryStmt(CXXTryStmt *S) { Code = serialization::STMT_CXX_TRY; } +void ASTStmtWriter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { + VisitStmt(S); + Writer.AddSourceLocation(S->getForLoc(), Record); + Writer.AddSourceLocation(S->getColonLoc(), Record); + Writer.AddSourceLocation(S->getRParenLoc(), Record); + Writer.AddStmt(S->getRangeStmt()); + Writer.AddStmt(S->getBeginEndStmt()); + Writer.AddStmt(S->getCond()); + Writer.AddStmt(S->getInc()); + Writer.AddStmt(S->getLoopVarStmt()); + Writer.AddStmt(S->getBody()); + Code = serialization::STMT_CXX_FOR_RANGE; +} + void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { VisitCallExpr(E); Record.push_back(E->getOperator()); @@ -1196,8 +1247,7 @@ ASTStmtWriter::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E){ Writer.AddTypeRef(E->getBaseType(), Record); Record.push_back(E->isArrow()); Writer.AddSourceLocation(E->getOperatorLoc(), Record); - Writer.AddNestedNameSpecifier(E->getQualifier(), Record); - Writer.AddSourceRange(E->getQualifierRange(), Record); + Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record); Writer.AddDeclRef(E->getFirstQualifierFoundInScope(), Record); Writer.AddDeclarationNameInfo(E->MemberNameInfo, Record); Code = serialization::EXPR_CXX_DEPENDENT_SCOPE_MEMBER; @@ -1253,8 +1303,7 @@ void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) { } Writer.AddDeclarationNameInfo(E->NameInfo, Record); - Writer.AddNestedNameSpecifier(E->getQualifier(), Record); - Writer.AddSourceRange(E->getQualifierRange(), Record); + Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record); } void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { @@ -1270,6 +1319,8 @@ void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { VisitOverloadExpr(E); Record.push_back(E->requiresADL()); + if (E->requiresADL()) + Record.push_back(E->isStdAssociatedNamespace()); Record.push_back(E->isOverloaded()); Writer.AddDeclRef(E->getNamingClass(), Record); Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP; @@ -1294,6 +1345,24 @@ void ASTStmtWriter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { Code = serialization::EXPR_BINARY_TYPE_TRAIT; } +void ASTStmtWriter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { + VisitExpr(E); + Record.push_back(E->getTrait()); + Record.push_back(E->getValue()); + Writer.AddSourceRange(E->getSourceRange(), Record); + Writer.AddTypeSourceInfo(E->getQueriedTypeSourceInfo(), Record); + Code = serialization::EXPR_ARRAY_TYPE_TRAIT; +} + +void ASTStmtWriter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { + VisitExpr(E); + Record.push_back(E->getTrait()); + Record.push_back(E->getValue()); + Writer.AddSourceRange(E->getSourceRange(), Record); + Writer.AddStmt(E->getQueriedExpression()); + Code = serialization::EXPR_CXX_EXPRESSION_TRAIT; +} + void ASTStmtWriter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { VisitExpr(E); Record.push_back(E->getValue()); @@ -1424,7 +1493,7 @@ void ASTWriter::FlushStmts() { WriteSubStmt(StmtsToEmit[I]); assert(N == StmtsToEmit.size() && - "Substatement writen via AddStmt rather than WriteSubStmt!"); + "Substatement written via AddStmt rather than WriteSubStmt!"); // Note that we are at the end of a full expression. Any // expression records that follow this one are part of a different diff --git a/contrib/llvm/tools/clang/lib/Serialization/ChainedIncludesSource.cpp b/contrib/llvm/tools/clang/lib/Serialization/ChainedIncludesSource.cpp new file mode 100644 index 0000000..da5be95 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Serialization/ChainedIncludesSource.cpp @@ -0,0 +1,235 @@ +//===- ChainedIncludesSource.cpp - Chained PCHs in Memory -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ChainedIncludesSource class, which converts headers +// to chained PCHs in memory, mainly used for testing. +// +//===----------------------------------------------------------------------===// + +#include "clang/Serialization/ChainedIncludesSource.h" +#include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/ASTWriter.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Parse/ParseAST.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace clang; + +static ASTReader *createASTReader(CompilerInstance &CI, + llvm::StringRef pchFile, + llvm::MemoryBuffer **memBufs, + unsigned numBufs, + ASTDeserializationListener *deserialListener = 0) { + Preprocessor &PP = CI.getPreprocessor(); + llvm::OwningPtr<ASTReader> Reader; + Reader.reset(new ASTReader(PP, &CI.getASTContext(), /*isysroot=*/0, + /*DisableValidation=*/true)); + Reader->setASTMemoryBuffers(memBufs, numBufs); + Reader->setDeserializationListener(deserialListener); + switch (Reader->ReadAST(pchFile, ASTReader::PCH)) { + case ASTReader::Success: + // Set the predefines buffer as suggested by the PCH reader. + PP.setPredefines(Reader->getSuggestedPredefines()); + return Reader.take(); + + case ASTReader::Failure: + case ASTReader::IgnorePCH: + break; + } + return 0; +} + +ChainedIncludesSource::~ChainedIncludesSource() { + for (unsigned i = 0, e = CIs.size(); i != e; ++i) + delete CIs[i]; +} + +ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { + + std::vector<std::string> &includes = CI.getPreprocessorOpts().ChainedIncludes; + assert(!includes.empty() && "No '-chain-include' in options!"); + + llvm::OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource()); + InputKind IK = CI.getFrontendOpts().Inputs[0].first; + + llvm::SmallVector<llvm::MemoryBuffer *, 4> serialBufs; + + for (unsigned i = 0, e = includes.size(); i != e; ++i) { + bool firstInclude = (i == 0); + llvm::OwningPtr<CompilerInvocation> CInvok; + CInvok.reset(new CompilerInvocation(CI.getInvocation())); + + CInvok->getPreprocessorOpts().ChainedIncludes.clear(); + CInvok->getPreprocessorOpts().ImplicitPCHInclude.clear(); + CInvok->getPreprocessorOpts().ImplicitPTHInclude.clear(); + CInvok->getPreprocessorOpts().DisablePCHValidation = true; + CInvok->getPreprocessorOpts().Includes.clear(); + CInvok->getPreprocessorOpts().MacroIncludes.clear(); + CInvok->getPreprocessorOpts().Macros.clear(); + + CInvok->getFrontendOpts().Inputs.clear(); + CInvok->getFrontendOpts().Inputs.push_back(std::make_pair(IK, includes[i])); + + TextDiagnosticPrinter *DiagClient = + new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); + llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + llvm::IntrusiveRefCntPtr<Diagnostic> Diags(new Diagnostic(DiagID, + DiagClient)); + + llvm::OwningPtr<CompilerInstance> Clang(new CompilerInstance()); + Clang->setInvocation(CInvok.take()); + Clang->setDiagnostics(Diags.getPtr()); + Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), + Clang->getTargetOpts())); + Clang->createFileManager(); + Clang->createSourceManager(Clang->getFileManager()); + Clang->createPreprocessor(); + Clang->getDiagnosticClient().BeginSourceFile(Clang->getLangOpts(), + &Clang->getPreprocessor()); + Clang->createASTContext(); + + llvm::SmallVector<char, 256> serialAST; + llvm::raw_svector_ostream OS(serialAST); + llvm::OwningPtr<ASTConsumer> consumer; + consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", + /*Chaining=*/!firstInclude, + /*isysroot=*/0, &OS)); + Clang->getASTContext().setASTMutationListener( + consumer->GetASTMutationListener()); + Clang->setASTConsumer(consumer.take()); + Clang->createSema(/*CompleteTranslationUnit=*/false, 0); + + if (firstInclude) { + Preprocessor &PP = Clang->getPreprocessor(); + PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), + PP.getLangOptions()); + } else { + assert(!serialBufs.empty()); + llvm::SmallVector<llvm::MemoryBuffer *, 4> bufs; + for (unsigned si = 0, se = serialBufs.size(); si != se; ++si) { + bufs.push_back(llvm::MemoryBuffer::getMemBufferCopy( + llvm::StringRef(serialBufs[si]->getBufferStart(), + serialBufs[si]->getBufferSize()))); + } + std::string pchName = includes[i-1]; + llvm::raw_string_ostream os(pchName); + os << ".pch" << i-1; + os.flush(); + llvm::OwningPtr<ExternalASTSource> Reader; + Reader.reset(createASTReader(*Clang, pchName, bufs.data(), bufs.size(), + Clang->getASTConsumer().GetASTDeserializationListener())); + if (!Reader) + return 0; + Clang->getASTContext().setExternalSource(Reader); + } + + if (!Clang->InitializeSourceManager(includes[i])) + return 0; + + ParseAST(Clang->getSema()); + OS.flush(); + Clang->getDiagnosticClient().EndSourceFile(); + serialBufs.push_back( + llvm::MemoryBuffer::getMemBufferCopy(llvm::StringRef(serialAST.data(), + serialAST.size()))); + source->CIs.push_back(Clang.take()); + } + + assert(!serialBufs.empty()); + std::string pchName = includes.back() + ".pch-final"; + llvm::OwningPtr<ASTReader> Reader; + Reader.reset(createASTReader(CI, pchName, + serialBufs.data(), serialBufs.size())); + if (!Reader) + return 0; + + source->FinalReader.reset(Reader.take()); + return source.take(); +} + +//===----------------------------------------------------------------------===// +// ExternalASTSource interface. +//===----------------------------------------------------------------------===// + +Decl *ChainedIncludesSource::GetExternalDecl(uint32_t ID) { + return getFinalReader().GetExternalDecl(ID); +} +Selector ChainedIncludesSource::GetExternalSelector(uint32_t ID) { + return getFinalReader().GetExternalSelector(ID); +} +uint32_t ChainedIncludesSource::GetNumExternalSelectors() { + return getFinalReader().GetNumExternalSelectors(); +} +Stmt *ChainedIncludesSource::GetExternalDeclStmt(uint64_t Offset) { + return getFinalReader().GetExternalDeclStmt(Offset); +} +CXXBaseSpecifier * +ChainedIncludesSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) { + return getFinalReader().GetExternalCXXBaseSpecifiers(Offset); +} +DeclContextLookupResult +ChainedIncludesSource::FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name) { + return getFinalReader().FindExternalVisibleDeclsByName(DC, Name); +} +void ChainedIncludesSource::MaterializeVisibleDecls(const DeclContext *DC) { + return getFinalReader().MaterializeVisibleDecls(DC); +} +bool ChainedIncludesSource::FindExternalLexicalDecls(const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + llvm::SmallVectorImpl<Decl*> &Result) { + return getFinalReader().FindExternalLexicalDecls(DC, isKindWeWant, Result); +} +void ChainedIncludesSource::CompleteType(TagDecl *Tag) { + return getFinalReader().CompleteType(Tag); +} +void ChainedIncludesSource::CompleteType(ObjCInterfaceDecl *Class) { + return getFinalReader().CompleteType(Class); +} +void ChainedIncludesSource::StartedDeserializing() { + return getFinalReader().StartedDeserializing(); +} +void ChainedIncludesSource::FinishedDeserializing() { + return getFinalReader().FinishedDeserializing(); +} +void ChainedIncludesSource::StartTranslationUnit(ASTConsumer *Consumer) { + return getFinalReader().StartTranslationUnit(Consumer); +} +void ChainedIncludesSource::PrintStats() { + return getFinalReader().PrintStats(); +} +void ChainedIncludesSource::getMemoryBufferSizes(MemoryBufferSizes &sizes)const{ + for (unsigned i = 0, e = CIs.size(); i != e; ++i) { + if (const ExternalASTSource *eSrc = + CIs[i]->getASTContext().getExternalSource()) { + eSrc->getMemoryBufferSizes(sizes); + } + } + + getFinalReader().getMemoryBufferSizes(sizes); +} + +void ChainedIncludesSource::InitializeSema(Sema &S) { + return getFinalReader().InitializeSema(S); +} +void ChainedIncludesSource::ForgetSema() { + return getFinalReader().ForgetSema(); +} +std::pair<ObjCMethodList,ObjCMethodList> +ChainedIncludesSource::ReadMethodPool(Selector Sel) { + return getFinalReader().ReadMethodPool(Sel); +} +bool ChainedIncludesSource::LookupUnqualified(LookupResult &R, Scope *S) { + return getFinalReader().LookupUnqualified(R, S); +} + diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp index 8832b05..8fc6d2a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp @@ -13,34 +13,25 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" using namespace clang; using namespace ento; namespace { class AdjustedReturnValueChecker : - public CheckerVisitor<AdjustedReturnValueChecker> { + public Checker< check::PostStmt<CallExpr> > { public: - AdjustedReturnValueChecker() {} - - void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE); - - static void *getTag() { - static int x = 0; return &x; - } + void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; }; } -void ento::RegisterAdjustedReturnValueChecker(ExprEngine &Eng) { - Eng.registerCheck(new AdjustedReturnValueChecker()); -} - -void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C, - const CallExpr *CE) { +void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE, + CheckerContext &C) const { // Get the result type of the call. QualType expectedResultTy = CE->getType(); @@ -94,3 +85,7 @@ void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C, C.generateNode(state->BindExpr(CE, V)); } } + +void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) { + mgr.registerChecker<AdjustedReturnValueChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp index 7b68887..983427a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp @@ -9,13 +9,13 @@ // This file reports various statistics about analyzer visitation. //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" -// FIXME: Restructure checker registration. -#include "ExperimentalChecks.h" - #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallPtrSet.h" @@ -23,32 +23,20 @@ using namespace clang; using namespace ento; namespace { -class AnalyzerStatsChecker : public CheckerVisitor<AnalyzerStatsChecker> { +class AnalyzerStatsChecker : public Checker<check::EndAnalysis> { public: - static void *getTag(); - void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng); - -private: - llvm::SmallPtrSet<const CFGBlock*, 256> reachable; + void checkEndAnalysis(ExplodedGraph &G, BugReporter &B,ExprEngine &Eng) const; }; } -void *AnalyzerStatsChecker::getTag() { - static int x = 0; - return &x; -} - -void ento::RegisterAnalyzerStatsChecker(ExprEngine &Eng) { - Eng.registerCheck(new AnalyzerStatsChecker()); -} - -void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G, +void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &B, - ExprEngine &Eng) { + ExprEngine &Eng) const { const CFG *C = 0; const Decl *D = 0; const LocationContext *LC = 0; const SourceManager &SM = B.getSourceManager(); + llvm::SmallPtrSet<const CFGBlock*, 256> reachable; // Iterate over explodedgraph for (ExplodedGraph::node_iterator I = G.nodes_begin(); @@ -100,8 +88,8 @@ void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G, } output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: " - << unreachable << " | Aborted Block: " - << (Eng.wasBlockAborted() ? "yes" : "no") + << unreachable << " | Exhausted Block: " + << (Eng.wasBlocksExhausted() ? "yes" : "no") << " | Empty WorkList: " << (Eng.hasEmptyWorkList() ? "yes" : "no"); @@ -109,10 +97,10 @@ void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G, D->getLocation()); // Emit warning for each block we bailed out on - typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator; + typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator; const CoreEngine &CE = Eng.getCoreEngine(); - for (AbortedIterator I = CE.blocks_aborted_begin(), - E = CE.blocks_aborted_end(); I != E; ++I) { + for (ExhaustedIterator I = CE.blocks_exhausted_begin(), + E = CE.blocks_exhausted_end(); I != E; ++I) { const BlockEdge &BE = I->first; const CFGBlock *Exit = BE.getDst(); const CFGElement &CE = Exit->front(); @@ -121,3 +109,7 @@ void AnalyzerStatsChecker::VisitEndAnalysis(ExplodedGraph &G, "stopped analyzing at this point", CS->getStmt()->getLocStart()); } } + +void ento::registerAnalyzerStatsChecker(CheckerManager &mgr) { + mgr.registerChecker<AnalyzerStatsChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp index 25e224e..eb9665a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -24,7 +24,7 @@ using namespace ento; namespace { class ArrayBoundChecker : - public CheckerV2<check::Location> { + public Checker<check::Location> { mutable llvm::OwningPtr<BuiltinBug> BT; public: void checkLocation(SVal l, bool isLoad, CheckerContext &C) const; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp index f803d27..65a6e63 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -12,9 +12,11 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/AST/CharUnits.h" @@ -23,18 +25,16 @@ using namespace ento; namespace { class ArrayBoundCheckerV2 : - public CheckerVisitor<ArrayBoundCheckerV2> { - BuiltinBug *BT; + public Checker<check::Location> { + mutable llvm::OwningPtr<BuiltinBug> BT; enum OOB_Kind { OOB_Precedes, OOB_Excedes }; void reportOOB(CheckerContext &C, const GRState *errorState, - OOB_Kind kind); + OOB_Kind kind) const; public: - ArrayBoundCheckerV2() : BT(0) {} - static void *getTag() { static int x = 0; return &x; } - void visitLocation(CheckerContext &C, const Stmt *S, SVal l, bool isLoad); + void checkLocation(SVal l, bool isLoad, CheckerContext &C) const; }; // FIXME: Eventually replace RegionRawOffset with this class. @@ -62,13 +62,24 @@ public: }; } -void ento::RegisterArrayBoundCheckerV2(ExprEngine &Eng) { - Eng.registerCheck(new ArrayBoundCheckerV2()); +static SVal computeExtentBegin(SValBuilder &svalBuilder, + const MemRegion *region) { + while (true) + switch (region->getKind()) { + default: + return svalBuilder.makeZeroArrayIndex(); + case MemRegion::SymbolicRegionKind: + // FIXME: improve this later by tracking symbolic lower bounds + // for symbolic regions. + return UnknownVal(); + case MemRegion::ElementRegionKind: + region = cast<SubRegion>(region)->getSuperRegion(); + continue; + } } -void ArrayBoundCheckerV2::visitLocation(CheckerContext &checkerContext, - const Stmt *S, - SVal location, bool isLoad) { +void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad, + CheckerContext &checkerContext) const { // NOTE: Instead of using GRState::assumeInBound(), we are prototyping // some new logic here that reasons directly about memory region extents. @@ -89,31 +100,36 @@ void ArrayBoundCheckerV2::visitLocation(CheckerContext &checkerContext, if (!rawOffset.getRegion()) return; - // CHECK LOWER BOUND: Is byteOffset < 0? If so, we are doing a load/store + // CHECK LOWER BOUND: Is byteOffset < extent begin? + // If so, we are doing a load/store // before the first valid offset in the memory region. - SVal lowerBound - = svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(), - svalBuilder.makeZeroArrayIndex(), - svalBuilder.getConditionType()); + SVal extentBegin = computeExtentBegin(svalBuilder, rawOffset.getRegion()); + + if (isa<NonLoc>(extentBegin)) { + SVal lowerBound + = svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(), + cast<NonLoc>(extentBegin), + svalBuilder.getConditionType()); - NonLoc *lowerBoundToCheck = dyn_cast<NonLoc>(&lowerBound); - if (!lowerBoundToCheck) - return; + NonLoc *lowerBoundToCheck = dyn_cast<NonLoc>(&lowerBound); + if (!lowerBoundToCheck) + return; - const GRState *state_precedesLowerBound, *state_withinLowerBound; - llvm::tie(state_precedesLowerBound, state_withinLowerBound) = + const GRState *state_precedesLowerBound, *state_withinLowerBound; + llvm::tie(state_precedesLowerBound, state_withinLowerBound) = state->assume(*lowerBoundToCheck); - // Are we constrained enough to definitely precede the lower bound? - if (state_precedesLowerBound && !state_withinLowerBound) { - reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes); - return; - } + // Are we constrained enough to definitely precede the lower bound? + if (state_precedesLowerBound && !state_withinLowerBound) { + reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes); + return; + } - // Otherwise, assume the constraint of the lower bound. - assert(state_withinLowerBound); - state = state_withinLowerBound; + // Otherwise, assume the constraint of the lower bound. + assert(state_withinLowerBound); + state = state_withinLowerBound; + } do { // CHECK UPPER BOUND: Is byteOffset >= extent(baseRegion)? If so, @@ -153,14 +169,14 @@ void ArrayBoundCheckerV2::visitLocation(CheckerContext &checkerContext, void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext, const GRState *errorState, - OOB_Kind kind) { + OOB_Kind kind) const { ExplodedNode *errorNode = checkerContext.generateSink(errorState); if (!errorNode) return; if (!BT) - BT = new BuiltinBug("Out-of-bound access"); + BT.reset(new BuiltinBug("Out-of-bound access")); // FIXME: This diagnostics are preliminary. We should get far better // diagnostics for explaining buffer overruns. @@ -237,9 +253,11 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const GRState *state, while (region) { switch (region->getKind()) { default: { - if (const SubRegion *subReg = dyn_cast<SubRegion>(region)) + if (const SubRegion *subReg = dyn_cast<SubRegion>(region)) { + offset = getValue(offset, svalBuilder); if (!offset.isUnknownOrUndef()) return RegionRawOffsetV2(subReg, offset); + } return RegionRawOffsetV2(); } case MemRegion::ElementRegionKind: { @@ -274,4 +292,6 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const GRState *state, } - +void ento::registerArrayBoundCheckerV2(CheckerManager &mgr) { + mgr.registerChecker<ArrayBoundCheckerV2>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp index e4865b1..d88a111 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp @@ -12,33 +12,27 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" using namespace clang; using namespace ento; namespace { class AttrNonNullChecker - : public CheckerVisitor<AttrNonNullChecker> { - BugType *BT; + : public Checker< check::PreStmt<CallExpr> > { + mutable llvm::OwningPtr<BugType> BT; public: - AttrNonNullChecker() : BT(0) {} - static void *getTag() { - static int x = 0; - return &x; - } - void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); + + void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; }; } // end anonymous namespace -void ento::RegisterAttrNonNullChecker(ExprEngine &Eng) { - Eng.registerCheck(new AttrNonNullChecker()); -} - -void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, - const CallExpr *CE) { +void AttrNonNullChecker::checkPreStmt(const CallExpr *CE, + CheckerContext &C) const { const GRState *state = C.getState(); // Check if the callee has a 'nonnull' attribute. @@ -103,8 +97,8 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, // created. Ownership is transferred to the BugReporter object once // the BugReport is passed to 'EmitWarning'. if (!BT) - BT = new BugType("Argument with 'nonnull' attribute passed null", - "API"); + BT.reset(new BugType("Argument with 'nonnull' attribute passed null", + "API")); EnhancedBugReport *R = new EnhancedBugReport(*BT, @@ -134,3 +128,7 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C, // If 'state' has been updated generated a new node. C.addTransition(state); } + +void ento::registerAttrNonNullChecker(CheckerManager &mgr) { + mgr.registerChecker<AttrNonNullChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 7aff201..235b400 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -13,10 +13,9 @@ // //===----------------------------------------------------------------------===// -#include "BasicObjCFoundationChecks.h" - #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/Analysis/DomainSpecific/CocoaConventions.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" @@ -24,7 +23,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" -#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" @@ -44,20 +42,21 @@ public: // Utility functions. //===----------------------------------------------------------------------===// -static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) { +static const char* GetReceiverNameType(const ObjCMessage &msg) { if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface()) - return ID->getTypeForDecl()->getAs<ObjCInterfaceType>(); - return NULL; + return ID->getIdentifier()->getNameStart(); + return 0; } -static const char* GetReceiverNameType(const ObjCMessage &msg) { - if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg)) - return ReceiverType->getDecl()->getIdentifier()->getNameStart(); - return NULL; -} +static bool isReceiverClassOrSuperclass(const ObjCInterfaceDecl *ID, + llvm::StringRef ClassName) { + if (ID->getIdentifier()->getName() == ClassName) + return true; -static bool isNSString(llvm::StringRef ClassName) { - return ClassName == "NSString" || ClassName == "NSMutableString"; + if (const ObjCInterfaceDecl *Super = ID->getSuperClass()) + return isReceiverClassOrSuperclass(Super, ClassName); + + return false; } static inline bool isNil(SVal X) { @@ -69,7 +68,7 @@ static inline bool isNil(SVal X) { //===----------------------------------------------------------------------===// namespace { - class NilArgChecker : public CheckerV2<check::PreObjCMessage> { + class NilArgChecker : public Checker<check::PreObjCMessage> { mutable llvm::OwningPtr<APIMisuse> BT; void WarnNilArg(CheckerContext &C, @@ -101,11 +100,11 @@ void NilArgChecker::WarnNilArg(CheckerContext &C, void NilArgChecker::checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const { - const ObjCInterfaceType *ReceiverType = GetReceiverType(msg); - if (!ReceiverType) + const ObjCInterfaceDecl *ID = msg.getReceiverInterface(); + if (!ID) return; - if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) { + if (isReceiverClassOrSuperclass(ID, "NSString")) { Selector S = msg.getSelector(); if (S.isUnarySelector()) @@ -140,7 +139,7 @@ void NilArgChecker::checkPreObjCMessage(ObjCMessage msg, //===----------------------------------------------------------------------===// namespace { -class CFNumberCreateChecker : public CheckerV2< check::PreStmt<CallExpr> > { +class CFNumberCreateChecker : public Checker< check::PreStmt<CallExpr> > { mutable llvm::OwningPtr<APIMisuse> BT; mutable IdentifierInfo* II; public: @@ -347,7 +346,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, //===----------------------------------------------------------------------===// namespace { -class CFRetainReleaseChecker : public CheckerV2< check::PreStmt<CallExpr> > { +class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > { mutable llvm::OwningPtr<APIMisuse> BT; mutable IdentifierInfo *Retain, *Release; public: @@ -429,7 +428,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr* CE, //===----------------------------------------------------------------------===// namespace { -class ClassReleaseChecker : public CheckerV2<check::PreObjCMessage> { +class ClassReleaseChecker : public Checker<check::PreObjCMessage> { mutable Selector releaseS; mutable Selector retainS; mutable Selector autoreleaseS; @@ -479,6 +478,165 @@ void ClassReleaseChecker::checkPreObjCMessage(ObjCMessage msg, } //===----------------------------------------------------------------------===// +// Check for passing non-Objective-C types to variadic methods that expect +// only Objective-C types. +//===----------------------------------------------------------------------===// + +namespace { +class VariadicMethodTypeChecker : public Checker<check::PreObjCMessage> { + mutable Selector arrayWithObjectsS; + mutable Selector dictionaryWithObjectsAndKeysS; + mutable Selector setWithObjectsS; + mutable Selector initWithObjectsS; + mutable Selector initWithObjectsAndKeysS; + mutable llvm::OwningPtr<BugType> BT; + + bool isVariadicMessage(const ObjCMessage &msg) const; + +public: + void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const; +}; +} + +/// isVariadicMessage - Returns whether the given message is a variadic message, +/// where all arguments must be Objective-C types. +bool +VariadicMethodTypeChecker::isVariadicMessage(const ObjCMessage &msg) const { + const ObjCMethodDecl *MD = msg.getMethodDecl(); + + if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext())) + return false; + + Selector S = msg.getSelector(); + + if (msg.isInstanceMessage()) { + // FIXME: Ideally we'd look at the receiver interface here, but that's not + // useful for init, because alloc returns 'id'. In theory, this could lead + // to false positives, for example if there existed a class that had an + // initWithObjects: implementation that does accept non-Objective-C pointer + // types, but the chance of that happening is pretty small compared to the + // gains that this analysis gives. + const ObjCInterfaceDecl *Class = MD->getClassInterface(); + + // -[NSArray initWithObjects:] + if (isReceiverClassOrSuperclass(Class, "NSArray") && + S == initWithObjectsS) + return true; + + // -[NSDictionary initWithObjectsAndKeys:] + if (isReceiverClassOrSuperclass(Class, "NSDictionary") && + S == initWithObjectsAndKeysS) + return true; + + // -[NSSet initWithObjects:] + if (isReceiverClassOrSuperclass(Class, "NSSet") && + S == initWithObjectsS) + return true; + } else { + const ObjCInterfaceDecl *Class = msg.getReceiverInterface(); + + // -[NSArray arrayWithObjects:] + if (isReceiverClassOrSuperclass(Class, "NSArray") && + S == arrayWithObjectsS) + return true; + + // -[NSDictionary dictionaryWithObjectsAndKeys:] + if (isReceiverClassOrSuperclass(Class, "NSDictionary") && + S == dictionaryWithObjectsAndKeysS) + return true; + + // -[NSSet setWithObjects:] + if (isReceiverClassOrSuperclass(Class, "NSSet") && + S == setWithObjectsS) + return true; + } + + return false; +} + +void VariadicMethodTypeChecker::checkPreObjCMessage(ObjCMessage msg, + CheckerContext &C) const { + if (!BT) { + BT.reset(new APIMisuse("Arguments passed to variadic method aren't all " + "Objective-C pointer types")); + + ASTContext &Ctx = C.getASTContext(); + arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx); + dictionaryWithObjectsAndKeysS = + GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx); + setWithObjectsS = GetUnarySelector("setWithObjects", Ctx); + + initWithObjectsS = GetUnarySelector("initWithObjects", Ctx); + initWithObjectsAndKeysS = GetUnarySelector("initWithObjectsAndKeys", Ctx); + } + + if (!isVariadicMessage(msg)) + return; + + // We are not interested in the selector arguments since they have + // well-defined types, so the compiler will issue a warning for them. + unsigned variadicArgsBegin = msg.getSelector().getNumArgs(); + + // We're not interested in the last argument since it has to be nil or the + // compiler would have issued a warning for it elsewhere. + unsigned variadicArgsEnd = msg.getNumArgs() - 1; + + if (variadicArgsEnd <= variadicArgsBegin) + return; + + // Verify that all arguments have Objective-C types. + llvm::Optional<ExplodedNode*> errorNode; + const GRState *state = C.getState(); + + for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) { + QualType ArgTy = msg.getArgType(I); + if (ArgTy->isObjCObjectPointerType()) + continue; + + // Block pointers are treaded as Objective-C pointers. + if (ArgTy->isBlockPointerType()) + continue; + + // Ignore pointer constants. + if (isa<loc::ConcreteInt>(msg.getArgSVal(I, state))) + continue; + + // Ignore pointer types annotated with 'NSObject' attribute. + if (C.getASTContext().isObjCNSObjectType(ArgTy)) + continue; + + // Ignore CF references, which can be toll-free bridged. + if (cocoa::isCFObjectRef(ArgTy)) + continue; + + // Generate only one error node to use for all bug reports. + if (!errorNode.hasValue()) { + errorNode = C.generateNode(); + } + + if (!errorNode.getValue()) + continue; + + llvm::SmallString<128> sbuf; + llvm::raw_svector_ostream os(sbuf); + + if (const char *TypeName = GetReceiverNameType(msg)) + os << "Argument to '" << TypeName << "' method '"; + else + os << "Argument to method '"; + + os << msg.getSelector().getAsString() + << "' should be an Objective-C pointer type, not '" + << ArgTy.getAsString() << "'"; + + RangedBugReport *R = new RangedBugReport(*BT, os.str(), + errorNode.getValue()); + R->addRange(msg.getArgSourceRange(I)); + C.EmitReport(R); + } +} + +//===----------------------------------------------------------------------===// // Check registration. //===----------------------------------------------------------------------===// @@ -497,3 +655,7 @@ void ento::registerCFRetainReleaseChecker(CheckerManager &mgr) { void ento::registerClassReleaseChecker(CheckerManager &mgr) { mgr.registerChecker<ClassReleaseChecker>(); } + +void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) { + mgr.registerChecker<VariadicMethodTypeChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.h deleted file mode 100644 index 92cfb1a..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.h +++ /dev/null @@ -1,35 +0,0 @@ -//== BasicObjCFoundationChecks.h - Simple Apple-Foundation checks -*- C++ -*--// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines BasicObjCFoundationChecks, a class that encapsulates -// a set of simple checks to run on Objective-C code using Apple's Foundation -// classes. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_GR_BASICOBJCFOUNDATIONCHECKS -#define LLVM_CLANG_GR_BASICOBJCFOUNDATIONCHECKS - -namespace clang { - -class ASTContext; -class Decl; - -namespace ento { - -class BugReporter; -class ExprEngine; - -void RegisterNSErrorChecks(BugReporter& BR, ExprEngine &Eng, const Decl &D); - -} // end GR namespace - -} // end clang namespace - -#endif diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp index 417b015..12ac652 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -11,8 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/Basic/Builtins.h" using namespace clang; @@ -20,19 +22,15 @@ using namespace ento; namespace { -class BuiltinFunctionChecker : public Checker { +class BuiltinFunctionChecker : public Checker<eval::Call> { public: - static void *getTag() { static int tag = 0; return &tag; } - virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE); + bool evalCall(const CallExpr *CE, CheckerContext &C) const; }; } -void ento::RegisterBuiltinFunctionChecker(ExprEngine &Eng) { - Eng.registerCheck(new BuiltinFunctionChecker()); -} - -bool BuiltinFunctionChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE){ +bool BuiltinFunctionChecker::evalCall(const CallExpr *CE, + CheckerContext &C) const{ const GRState *state = C.getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); @@ -81,3 +79,7 @@ bool BuiltinFunctionChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE){ return false; } + +void ento::registerBuiltinFunctionChecker(CheckerManager &mgr) { + mgr.registerChecker<BuiltinFunctionChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 2566e3c..a6a256a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -24,7 +24,7 @@ using namespace clang; using namespace ento; namespace { -class CStringChecker : public CheckerV2< eval::Call, +class CStringChecker : public Checker< eval::Call, check::PreStmt<DeclStmt>, check::LiveSymbols, check::DeadSymbols, @@ -49,11 +49,14 @@ public: const CallExpr *) const; void evalMemcpy(CheckerContext &C, const CallExpr *CE) const; + void evalMempcpy(CheckerContext &C, const CallExpr *CE) const; void evalMemmove(CheckerContext &C, const CallExpr *CE) const; void evalBcopy(CheckerContext &C, const CallExpr *CE) const; - void evalCopyCommon(CheckerContext &C, const GRState *state, + void evalCopyCommon(CheckerContext &C, const CallExpr *CE, + const GRState *state, const Expr *Size, const Expr *Source, const Expr *Dest, - bool Restricted = false) const; + bool Restricted = false, + bool IsMempcpy = false) const; void evalMemcmp(CheckerContext &C, const CallExpr *CE) const; @@ -66,7 +69,16 @@ public: void evalStrncpy(CheckerContext &C, const CallExpr *CE) const; void evalStpcpy(CheckerContext &C, const CallExpr *CE) const; void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd, - bool isStrncpy) const; + bool isBounded, bool isAppending) const; + + void evalStrcat(CheckerContext &C, const CallExpr *CE) const; + void evalStrncat(CheckerContext &C, const CallExpr *CE) const; + + void evalStrcmp(CheckerContext &C, const CallExpr *CE) const; + void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; + void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const; + void evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, + bool isBounded = false, bool ignoreCase = false) const; // Utility methods std::pair<const GRState*, const GRState*> @@ -81,6 +93,11 @@ public: SVal getCStringLength(CheckerContext &C, const GRState *&state, const Expr *Ex, SVal Buf) const; + const StringLiteral *getCStringLiteral(CheckerContext &C, + const GRState *&state, + const Expr *expr, + SVal val) const; + static const GRState *InvalidateBuffer(CheckerContext &C, const GRState *state, const Expr *Ex, SVal V); @@ -275,7 +292,7 @@ const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C, NonLoc LastOffset = cast<NonLoc>(svalBuilder.evalBinOpNN(state, BO_Sub, *Length, One, sizeTy)); - // Check that the first buffer is sufficently long. + // Check that the first buffer is sufficiently long. SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType()); if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) { SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, @@ -581,6 +598,26 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state, } } +const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C, + const GRState *&state, const Expr *expr, SVal val) const { + + // Get the memory region pointed to by the val. + const MemRegion *bufRegion = val.getAsRegion(); + if (!bufRegion) + return NULL; + + // Strip casts off the memory region. + bufRegion = bufRegion->StripCasts(); + + // Cast the memory region to a string region. + const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion); + if (!strRegion) + return NULL; + + // Return the actual string in the string region. + return strRegion->getStringLiteral(); +} + const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C, const GRState *state, const Expr *E, SVal V) { @@ -655,9 +692,12 @@ bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx, // evaluation of individual function calls. //===----------------------------------------------------------------------===// -void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state, +void CStringChecker::evalCopyCommon(CheckerContext &C, + const CallExpr *CE, + const GRState *state, const Expr *Size, const Expr *Dest, - const Expr *Source, bool Restricted) const { + const Expr *Source, bool Restricted, + bool IsMempcpy) const { // See if the size argument is zero. SVal sizeVal = state->getSVal(Size); QualType sizeTy = Size->getType(); @@ -665,12 +705,39 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state, const GRState *stateZeroSize, *stateNonZeroSize; llvm::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, sizeVal, sizeTy); - // If the size is zero, there won't be any actual memory access. - if (stateZeroSize) + // Get the value of the Dest. + SVal destVal = state->getSVal(Dest); + + // If the size is zero, there won't be any actual memory access, so + // just bind the return value to the destination buffer and return. + if (stateZeroSize) { C.addTransition(stateZeroSize); + if (IsMempcpy) + state->BindExpr(CE, destVal); + else + state->BindExpr(CE, sizeVal); + return; + } // If the size can be nonzero, we have to check the other arguments. if (stateNonZeroSize) { + + // Ensure the destination is not null. If it is NULL there will be a + // NULL pointer dereference. + state = checkNonNull(C, state, Dest, destVal); + if (!state) + return; + + // Get the value of the Src. + SVal srcVal = state->getSVal(Source); + + // Ensure the source is not null. If it is NULL there will be a + // NULL pointer dereference. + state = checkNonNull(C, state, Source, srcVal); + if (!state) + return; + + // Ensure the buffers do not overlap. state = stateNonZeroSize; state = CheckBufferAccess(C, state, Size, Dest, Source, /* FirstIsDst = */ true); @@ -678,6 +745,26 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state, state = CheckOverlap(C, state, Size, Dest, Source); if (state) { + + // If this is mempcpy, get the byte after the last byte copied and + // bind the expr. + if (IsMempcpy) { + loc::MemRegionVal *destRegVal = dyn_cast<loc::MemRegionVal>(&destVal); + + // Get the length to copy. + SVal lenVal = state->getSVal(Size); + NonLoc *lenValNonLoc = dyn_cast<NonLoc>(&lenVal); + + // Get the byte after the last byte copied. + SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add, + *destRegVal, + *lenValNonLoc, + Dest->getType()); + + // The byte after the last byte copied is the return value. + state = state->BindExpr(CE, lastElement); + } + // Invalidate the destination. // FIXME: Even if we can't perfectly model the copy, we should see if we // can use LazyCompoundVals to copy the source values into the destination. @@ -696,7 +783,16 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const { const Expr *Dest = CE->getArg(0); const GRState *state = C.getState(); state = state->BindExpr(CE, state->getSVal(Dest)); - evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1), true); + evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true); +} + +void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const { + // void *mempcpy(void *restrict dst, const void *restrict src, size_t n); + // The return value is a pointer to the byte following the last written byte. + const Expr *Dest = CE->getArg(0); + const GRState *state = C.getState(); + + evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true, true); } void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { @@ -705,12 +801,13 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { const Expr *Dest = CE->getArg(0); const GRState *state = C.getState(); state = state->BindExpr(CE, state->getSVal(Dest)); - evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1)); + evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1)); } void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const { // void bcopy(const void *src, void *dst, size_t n); - evalCopyCommon(C, C.getState(), CE->getArg(2), CE->getArg(1), CE->getArg(0)); + evalCopyCommon(C, CE, C.getState(), + CE->getArg(2), CE->getArg(1), CE->getArg(0)); } void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { @@ -849,24 +946,50 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const { // char *strcpy(char *restrict dst, const char *restrict src); - evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ false); + evalStrcpyCommon(C, CE, + /* returnEnd = */ false, + /* isBounded = */ false, + /* isAppending = */ false); } void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const { // char *strcpy(char *restrict dst, const char *restrict src); - evalStrcpyCommon(C, CE, /* returnEnd = */ false, /* isStrncpy = */ true); + evalStrcpyCommon(C, CE, + /* returnEnd = */ false, + /* isBounded = */ true, + /* isAppending = */ false); } void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const { // char *stpcpy(char *restrict dst, const char *restrict src); - evalStrcpyCommon(C, CE, /* returnEnd = */ true, /* isStrncpy = */ false); + evalStrcpyCommon(C, CE, + /* returnEnd = */ true, + /* isBounded = */ false, + /* isAppending = */ false); +} + +void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const { + //char *strcat(char *restrict s1, const char *restrict s2); + evalStrcpyCommon(C, CE, + /* returnEnd = */ false, + /* isBounded = */ false, + /* isAppending = */ true); +} + +void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const { + //char *strncat(char *restrict s1, const char *restrict s2, size_t n); + evalStrcpyCommon(C, CE, + /* returnEnd = */ false, + /* isBounded = */ true, + /* isAppending = */ true); } void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, - bool returnEnd, bool isStrncpy) const { + bool returnEnd, bool isBounded, + bool isAppending) const { const GRState *state = C.getState(); - // Check that the destination is non-null + // Check that the destination is non-null. const Expr *Dst = CE->getArg(0); SVal DstVal = state->getSVal(Dst); @@ -888,18 +1011,26 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, if (strLength.isUndef()) return; - if (isStrncpy) { - // Get the max number of characters to copy + // If the function is strncpy, strncat, etc... it is bounded. + if (isBounded) { + // Get the max number of characters to copy. const Expr *lenExpr = CE->getArg(2); SVal lenVal = state->getSVal(lenExpr); + // Cast the length to a NonLoc SVal. If it is not a NonLoc then give up. NonLoc *strLengthNL = dyn_cast<NonLoc>(&strLength); + if (!strLengthNL) + return; + + // Cast the max length to a NonLoc SVal. If it is not a NonLoc then give up. NonLoc *lenValNL = dyn_cast<NonLoc>(&lenVal); + if (!lenValNL) + return; QualType cmpTy = C.getSValBuilder().getContext().IntTy; const GRState *stateTrue, *stateFalse; - // Check if the max number to copy is less than the length of the src + // Check if the max number to copy is less than the length of the src. llvm::tie(stateTrue, stateFalse) = state->assume(cast<DefinedOrUnknownSVal> (C.getSValBuilder().evalBinOpNN(state, BO_GT, @@ -913,6 +1044,29 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, } } + // If this is an appending function (strcat, strncat...) then set the + // string length to strlen(src) + strlen(dst) since the buffer will + // ultimately contain both. + if (isAppending) { + // Get the string length of the destination, or give up. + SVal dstStrLength = getCStringLength(C, state, Dst, DstVal); + if (dstStrLength.isUndef()) + return; + + NonLoc *srcStrLengthNL = dyn_cast<NonLoc>(&strLength); + NonLoc *dstStrLengthNL = dyn_cast<NonLoc>(&dstStrLength); + + // If src or dst cast to NonLoc is NULL, give up. + if ((!srcStrLengthNL) || (!dstStrLengthNL)) + return; + + QualType addTy = C.getSValBuilder().getContext().getSizeType(); + + strLength = C.getSValBuilder().evalBinOpNN(state, BO_Add, + *srcStrLengthNL, *dstStrLengthNL, + addTy); + } + SVal Result = (returnEnd ? UnknownVal() : DstVal); // If the destination is a MemRegion, try to check for a buffer overflow and @@ -958,6 +1112,113 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, C.addTransition(state); } +void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const { + //int strcmp(const char *restrict s1, const char *restrict s2); + evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ false); +} + +void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const { + //int strncmp(const char *restrict s1, const char *restrict s2, size_t n); + evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ false); +} + +void CStringChecker::evalStrcasecmp(CheckerContext &C, + const CallExpr *CE) const { + //int strcasecmp(const char *restrict s1, const char *restrict s2); + evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true); +} + +void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, + bool isBounded, bool ignoreCase) const { + const GRState *state = C.getState(); + + // Check that the first string is non-null + const Expr *s1 = CE->getArg(0); + SVal s1Val = state->getSVal(s1); + state = checkNonNull(C, state, s1, s1Val); + if (!state) + return; + + // Check that the second string is non-null. + const Expr *s2 = CE->getArg(1); + SVal s2Val = state->getSVal(s2); + state = checkNonNull(C, state, s2, s2Val); + if (!state) + return; + + // Get the string length of the first string or give up. + SVal s1Length = getCStringLength(C, state, s1, s1Val); + if (s1Length.isUndef()) + return; + + // Get the string length of the second string or give up. + SVal s2Length = getCStringLength(C, state, s2, s2Val); + if (s2Length.isUndef()) + return; + + // Get the string literal of the first string. + const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val); + if (!s1StrLiteral) + return; + llvm::StringRef s1StrRef = s1StrLiteral->getString(); + + // Get the string literal of the second string. + const StringLiteral *s2StrLiteral = getCStringLiteral(C, state, s2, s2Val); + if (!s2StrLiteral) + return; + llvm::StringRef s2StrRef = s2StrLiteral->getString(); + + int result; + if (isBounded) { + // Get the max number of characters to compare. + const Expr *lenExpr = CE->getArg(2); + SVal lenVal = state->getSVal(lenExpr); + + // Dynamically cast the length to a ConcreteInt. If it is not a ConcreteInt + // then give up, otherwise get the value and use it as the bounds. + nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&lenVal); + if (!CI) + return; + llvm::APSInt lenInt(CI->getValue()); + + // Compare using the bounds provided like strncmp() does. + if (ignoreCase) { + // TODO Implement compare_lower(RHS, n) in LLVM StringRef. + // result = s1StrRef.compare_lower(s2StrRef, + // (size_t)lenInt.getLimitedValue()); + + // For now, give up. + return; + } else { + // Create substrings of each to compare the prefix. + llvm::StringRef s1SubStr = + s1StrRef.substr(0, (size_t)lenInt.getLimitedValue()); + llvm::StringRef s2SubStr = + s2StrRef.substr(0, (size_t)lenInt.getLimitedValue()); + + // Compare the substrings. + result = s1SubStr.compare(s2SubStr); + } + } else { + // Compare string 1 to string 2 the same way strcmp() does. + if (ignoreCase) { + result = s1StrRef.compare_lower(s2StrRef); + } else { + result = s1StrRef.compare(s2StrRef); + } + } + + // Build the SVal of the comparison to bind the return value. + SValBuilder &svalBuilder = C.getSValBuilder(); + QualType intTy = svalBuilder.getContext().IntTy; + SVal resultVal = svalBuilder.makeIntVal(result, intTy); + + // Bind the return value of the expression. + // Set the return value. + state = state->BindExpr(CE, resultVal); + C.addTransition(state); +} + //===----------------------------------------------------------------------===// // The driver method, and other Checker callbacks. //===----------------------------------------------------------------------===// @@ -982,13 +1243,19 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name) .Cases("memcpy", "__memcpy_chk", &CStringChecker::evalMemcpy) + .Case("mempcpy", &CStringChecker::evalMempcpy) .Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp) .Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove) .Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy) .Cases("strncpy", "__strncpy_chk", &CStringChecker::evalStrncpy) .Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy) + .Cases("strcat", "__strcat_chk", &CStringChecker::evalStrcat) + .Cases("strncat", "__strncat_chk", &CStringChecker::evalStrncat) .Case("strlen", &CStringChecker::evalstrLength) .Case("strnlen", &CStringChecker::evalstrnLength) + .Case("strcmp", &CStringChecker::evalStrcmp) + .Case("strncmp", &CStringChecker::evalStrncmp) + .Case("strcasecmp", &CStringChecker::evalStrcasecmp) .Case("bcopy", &CStringChecker::evalBcopy) .Default(NULL); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 415900e..dfe0a0e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -12,62 +12,51 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/AST/ParentMap.h" #include "clang/Basic/TargetInfo.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" using namespace clang; using namespace ento; namespace { class CallAndMessageChecker - : public CheckerVisitor<CallAndMessageChecker> { - BugType *BT_call_null; - BugType *BT_call_undef; - BugType *BT_call_arg; - BugType *BT_msg_undef; - BugType *BT_msg_arg; - BugType *BT_msg_ret; + : public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage > { + mutable llvm::OwningPtr<BugType> BT_call_null; + mutable llvm::OwningPtr<BugType> BT_call_undef; + mutable llvm::OwningPtr<BugType> BT_call_arg; + mutable llvm::OwningPtr<BugType> BT_msg_undef; + mutable llvm::OwningPtr<BugType> BT_msg_arg; + mutable llvm::OwningPtr<BugType> BT_msg_ret; public: - CallAndMessageChecker() : - BT_call_null(0), BT_call_undef(0), BT_call_arg(0), - BT_msg_undef(0), BT_msg_arg(0), BT_msg_ret(0) {} - - static void *getTag() { - static int x = 0; - return &x; - } - void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE); - void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg); - bool evalNilReceiver(CheckerContext &C, ObjCMessage msg); + void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; + void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const; private: - void PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg, - const char *BT_desc, BugType *&BT); - bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange, - const Expr *argEx, const char *BT_desc, BugType *&BT); + static void PreVisitProcessArgs(CheckerContext &C,CallOrObjCMessage callOrMsg, + const char *BT_desc, llvm::OwningPtr<BugType> &BT); + static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange, + const Expr *argEx, const char *BT_desc, llvm::OwningPtr<BugType> &BT); - void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); + static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE); void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg, - ExplodedNode *N); + ExplodedNode *N) const; void HandleNilReceiver(CheckerContext &C, const GRState *state, - ObjCMessage msg); + ObjCMessage msg) const; - void LazyInit_BT(const char *desc, BugType *&BT) { + static void LazyInit_BT(const char *desc, llvm::OwningPtr<BugType> &BT) { if (!BT) - BT = new BuiltinBug(desc); + BT.reset(new BuiltinBug(desc)); } }; } // end anonymous namespace -void ento::RegisterCallAndMessageChecker(ExprEngine &Eng) { - Eng.registerCheck(new CallAndMessageChecker()); -} - void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE) { ExplodedNode *N = C.generateSink(); @@ -83,7 +72,7 @@ void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C, void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg, const char *BT_desc, - BugType *&BT) { + llvm::OwningPtr<BugType> &BT) { for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i) if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i), callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i), @@ -95,7 +84,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange, const Expr *argEx, const char *BT_desc, - BugType *&BT) { + llvm::OwningPtr<BugType> &BT) { if (V.isUndef()) { if (ExplodedNode *N = C.generateSink()) { @@ -198,25 +187,25 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, return false; } -void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, - const CallExpr *CE){ +void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, + CheckerContext &C) const{ const Expr *Callee = CE->getCallee()->IgnoreParens(); SVal L = C.getState()->getSVal(Callee); if (L.isUndef()) { if (!BT_call_undef) - BT_call_undef = - new BuiltinBug("Called function pointer is an uninitalized pointer value"); - EmitBadCall(BT_call_undef, C, CE); + BT_call_undef.reset(new BuiltinBug("Called function pointer is an " + "uninitalized pointer value")); + EmitBadCall(BT_call_undef.get(), C, CE); return; } if (isa<loc::ConcreteInt>(L)) { if (!BT_call_null) - BT_call_null = - new BuiltinBug("Called function pointer is null (null dereference)"); - EmitBadCall(BT_call_null, C, CE); + BT_call_null.reset( + new BuiltinBug("Called function pointer is null (null dereference)")); + EmitBadCall(BT_call_null.get(), C, CE); } PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState()), @@ -224,18 +213,19 @@ void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, BT_call_arg); } -void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C, - ObjCMessage msg) { +void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg, + CheckerContext &C) const { const GRState *state = C.getState(); // FIXME: Handle 'super'? - if (const Expr *receiver = msg.getInstanceReceiver()) - if (state->getSVal(receiver).isUndef()) { + if (const Expr *receiver = msg.getInstanceReceiver()) { + SVal recVal = state->getSVal(receiver); + if (recVal.isUndef()) { if (ExplodedNode *N = C.generateSink()) { if (!BT_msg_undef) - BT_msg_undef = - new BuiltinBug("Receiver in message expression is an uninitialized value"); + BT_msg_undef.reset(new BuiltinBug("Receiver in message expression is " + "an uninitialized value")); EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N); R->addRange(receiver->getSourceRange()); @@ -244,7 +234,20 @@ void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C, C.EmitReport(R); } return; + } else { + // Bifurcate the state into nil and non-nil ones. + DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); + + const GRState *notNilState, *nilState; + llvm::tie(notNilState, nilState) = state->assume(receiverVal); + + // Handle receiver must be nil. + if (nilState && !notNilState) { + HandleNilReceiver(C, state, msg); + return; + } } + } const char *bugDesc = msg.isPropertySetter() ? "Argument for property setter is an uninitialized value" @@ -253,20 +256,14 @@ void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C, PreVisitProcessArgs(C, CallOrObjCMessage(msg, state), bugDesc, BT_msg_arg); } -bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C, - ObjCMessage msg) { - HandleNilReceiver(C, C.getState(), msg); - return true; // Nil receiver is not handled elsewhere. -} - void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg, - ExplodedNode *N) { + ExplodedNode *N) const { if (!BT_msg_ret) - BT_msg_ret = + BT_msg_ret.reset( new BuiltinBug("Receiver in message expression is " - "'nil' and returns a garbage value"); + "'nil' and returns a garbage value")); llvm::SmallString<200> buf; llvm::raw_svector_ostream os(buf); @@ -292,7 +289,7 @@ static bool supportsNilWithFloatRet(const llvm::Triple &triple) { void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, const GRState *state, - ObjCMessage msg) { + ObjCMessage msg) const { ASTContext &Ctx = C.getASTContext(); // Check the return type of the message expression. A message to nil will @@ -356,3 +353,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C, C.addTransition(state); } + +void ento::registerCallAndMessageChecker(CheckerManager &mgr) { + mgr.registerChecker<CallAndMessageChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp index 6a4506b..585a87d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -22,7 +22,7 @@ using namespace clang; using namespace ento; namespace { -class CastSizeChecker : public CheckerV2< check::PreStmt<CastExpr> > { +class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > { mutable llvm::OwningPtr<BuiltinBug> BT; public: void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp index 04cc253..3210b0a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -23,7 +23,7 @@ using namespace clang; using namespace ento; namespace { -class CastToStructChecker : public CheckerV2< check::PreStmt<CastExpr> > { +class CastToStructChecker : public Checker< check::PreStmt<CastExpr> > { mutable llvm::OwningPtr<BuiltinBug> BT; public: diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index ad3bab6..0c693a0 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" @@ -267,7 +267,7 @@ static void checkObjCDealloc(const ObjCImplementationDecl* D, //===----------------------------------------------------------------------===// namespace { -class ObjCDeallocChecker : public CheckerV2< +class ObjCDeallocChecker : public Checker< check::ASTDecl<ObjCImplementationDecl> > { public: void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp index 369ba0b..fec06a9 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/AST/DeclObjC.h" @@ -125,7 +125,7 @@ static void CheckObjCInstMethSignature(const ObjCImplementationDecl* ID, //===----------------------------------------------------------------------===// namespace { -class ObjCMethSigsChecker : public CheckerV2< +class ObjCMethSigsChecker : public Checker< check::ASTDecl<ObjCImplementationDecl> > { public: void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index 185520c..53810ee 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -12,11 +12,12 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/Basic/TargetInfo.h" #include "clang/AST/StmtVisitor.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; using namespace ento; @@ -33,21 +34,13 @@ static bool isArc4RandomAvailable(const ASTContext &Ctx) { namespace { class WalkAST : public StmtVisitor<WalkAST> { BugReporter &BR; - IdentifierInfo *II_gets; - IdentifierInfo *II_getpw; - IdentifierInfo *II_mktemp; - enum { num_rands = 9 }; - IdentifierInfo *II_rand[num_rands]; - IdentifierInfo *II_random; enum { num_setids = 6 }; IdentifierInfo *II_setid[num_setids]; const bool CheckRand; public: - WalkAST(BugReporter &br) : BR(br), - II_gets(0), II_getpw(0), II_mktemp(0), - II_rand(), II_random(0), II_setid(), + WalkAST(BugReporter &br) : BR(br), II_setid(), CheckRand(isArc4RandomAvailable(BR.getContext())) {} // Statement visitor methods. @@ -59,16 +52,22 @@ public: void VisitChildren(Stmt *S); // Helpers. - IdentifierInfo *GetIdentifier(IdentifierInfo *& II, const char *str); + IdentifierInfo *getIdentifier(IdentifierInfo *& II, const char *str); + bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD); + + typedef void (WalkAST::*FnCheck)(const CallExpr *, + const FunctionDecl *); // Checker-specific methods. - void CheckLoopConditionForFloat(const ForStmt *FS); - void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD); - void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD); - void CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD); - void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD); - void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD); - void CheckUncheckedReturnValue(CallExpr *CE); + void checkLoopConditionForFloat(const ForStmt *FS); + void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD); + void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD); + void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD); + void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD); + void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD); + void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD); + void checkCall_random(const CallExpr *CE, const FunctionDecl *FD); + void checkUncheckedReturnValue(CallExpr *CE); }; } // end anonymous namespace @@ -76,7 +75,7 @@ public: // Helper methods. //===----------------------------------------------------------------------===// -IdentifierInfo *WalkAST::GetIdentifier(IdentifierInfo *& II, const char *str) { +IdentifierInfo *WalkAST::getIdentifier(IdentifierInfo *& II, const char *str) { if (!II) II = &BR.getContext().Idents.get(str); @@ -94,15 +93,43 @@ void WalkAST::VisitChildren(Stmt *S) { } void WalkAST::VisitCallExpr(CallExpr *CE) { - if (const FunctionDecl *FD = CE->getDirectCallee()) { - CheckCall_gets(CE, FD); - CheckCall_getpw(CE, FD); - CheckCall_mktemp(CE, FD); - if (CheckRand) { - CheckCall_rand(CE, FD); - CheckCall_random(CE, FD); - } - } + // Get the callee. + const FunctionDecl *FD = CE->getDirectCallee(); + + if (!FD) + return; + + // Get the name of the callee. If it's a builtin, strip off the prefix. + IdentifierInfo *II = FD->getIdentifier(); + if (!II) // if no identifier, not a simple C function + return; + llvm::StringRef Name = II->getName(); + if (Name.startswith("__builtin_")) + Name = Name.substr(10); + + // Set the evaluation function by switching on the callee name. + FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name) + .Case("gets", &WalkAST::checkCall_gets) + .Case("getpw", &WalkAST::checkCall_getpw) + .Case("mktemp", &WalkAST::checkCall_mktemp) + .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy) + .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat) + .Case("drand48", &WalkAST::checkCall_rand) + .Case("erand48", &WalkAST::checkCall_rand) + .Case("jrand48", &WalkAST::checkCall_rand) + .Case("lrand48", &WalkAST::checkCall_rand) + .Case("mrand48", &WalkAST::checkCall_rand) + .Case("nrand48", &WalkAST::checkCall_rand) + .Case("lcong48", &WalkAST::checkCall_rand) + .Case("rand", &WalkAST::checkCall_rand) + .Case("rand_r", &WalkAST::checkCall_rand) + .Case("random", &WalkAST::checkCall_random) + .Default(NULL); + + // If the callee isn't defined, it is not of security concern. + // Check and evaluate the call. + if (evalFunction) + (this->*evalFunction)(CE, FD); // Recurse and check children. VisitChildren(CE); @@ -112,13 +139,13 @@ void WalkAST::VisitCompoundStmt(CompoundStmt *S) { for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I) if (Stmt *child = *I) { if (CallExpr *CE = dyn_cast<CallExpr>(child)) - CheckUncheckedReturnValue(CE); + checkUncheckedReturnValue(CE); Visit(child); } } void WalkAST::VisitForStmt(ForStmt *FS) { - CheckLoopConditionForFloat(FS); + checkLoopConditionForFloat(FS); // Recurse and check children. VisitChildren(FS); @@ -131,7 +158,7 @@ void WalkAST::VisitForStmt(ForStmt *FS) { //===----------------------------------------------------------------------===// static const DeclRefExpr* -GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) { +getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) { expr = expr->IgnoreParenCasts(); if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) { @@ -139,10 +166,10 @@ GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) { B->getOpcode() == BO_Comma)) return NULL; - if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y)) + if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y)) return lhs; - if (const DeclRefExpr *rhs = GetIncrementedVar(B->getRHS(), x, y)) + if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y)) return rhs; return NULL; @@ -155,7 +182,7 @@ GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) { if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr)) return U->isIncrementDecrementOp() - ? GetIncrementedVar(U->getSubExpr(), x, y) : NULL; + ? getIncrementedVar(U->getSubExpr(), x, y) : NULL; return NULL; } @@ -164,7 +191,7 @@ GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) { /// use a floating point variable as a loop counter. /// CERT: FLP30-C, FLP30-CPP. /// -void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) { +void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) { // Does the loop have a condition? const Expr *condition = FS->getCond(); @@ -211,7 +238,7 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) { return; // Does either variable appear in increment? - const DeclRefExpr *drInc = GetIncrementedVar(increment, vdLHS, vdRHS); + const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS); if (!drInc) return; @@ -243,10 +270,7 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) { // CWE-242: Use of Inherently Dangerous Function //===----------------------------------------------------------------------===// -void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) { - if (FD->getIdentifier() != GetIdentifier(II_gets, "gets")) - return; - +void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) { const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens()); if (!FPT) @@ -278,10 +302,7 @@ void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) { // CWE-477: Use of Obsolete Functions //===----------------------------------------------------------------------===// -void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { - if (FD->getIdentifier() != GetIdentifier(II_getpw, "getpw")) - return; - +void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens()); if (!FPT) @@ -317,16 +338,13 @@ void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) { // CWE-377: Insecure Temporary File //===----------------------------------------------------------------------===// -void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { - if (FD->getIdentifier() != GetIdentifier(II_mktemp, "mktemp")) - return; - +void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens()); if(!FPT) return; - // Verify that the funcion takes a single argument. + // Verify that the function takes a single argument. if (FPT->getNumArgs() != 1) return; @@ -349,32 +367,86 @@ void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) { } //===----------------------------------------------------------------------===// -// Check: Linear congruent random number generators should not be used -// Originally: <rdar://problem/63371000> -// CWE-338: Use of cryptographically weak prng +// Check: Any use of 'strcpy' is insecure. +// +// CWE-119: Improper Restriction of Operations within +// the Bounds of a Memory Buffer //===----------------------------------------------------------------------===// +void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) { + if (!checkCall_strCommon(CE, FD)) + return; -void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) { - if (II_rand[0] == NULL) { - // This check applies to these functions - static const char * const identifiers[num_rands] = { - "drand48", "erand48", "jrand48", "lrand48", "mrand48", "nrand48", - "lcong48", - "rand", "rand_r" - }; + // Issue a warning. + SourceRange R = CE->getCallee()->getSourceRange(); + BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in " + "call 'strcpy'", + "Security", + "Call to function 'strcpy' is insecure as it does not " + "provide bounding of the memory buffer. Replace " + "unbounded copy functions with analogous functions that " + "support length arguments such as 'strncpy'. CWE-119.", + CE->getLocStart(), &R, 1); +} + +//===----------------------------------------------------------------------===// +// Check: Any use of 'strcat' is insecure. +// +// CWE-119: Improper Restriction of Operations within +// the Bounds of a Memory Buffer +//===----------------------------------------------------------------------===// +void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) { + if (!checkCall_strCommon(CE, FD)) + return; + + // Issue a warning. + SourceRange R = CE->getCallee()->getSourceRange(); + BR.EmitBasicReport("Potential insecure memory buffer bounds restriction in " + "call 'strcat'", + "Security", + "Call to function 'strcat' is insecure as it does not " + "provide bounding of the memory buffer. Replace " + "unbounded copy functions with analogous functions that " + "support length arguments such as 'strncat'. CWE-119.", + CE->getLocStart(), &R, 1); +} - for (size_t i = 0; i < num_rands; i++) - II_rand[i] = &BR.getContext().Idents.get(identifiers[i]); +//===----------------------------------------------------------------------===// +// Common check for str* functions with no bounds parameters. +//===----------------------------------------------------------------------===// +bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) { + const FunctionProtoType *FPT + = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens()); + if (!FPT) + return false; + + // Verify the function takes two arguments, three in the _chk version. + int numArgs = FPT->getNumArgs(); + if (numArgs != 2 && numArgs != 3) + return false; + + // Verify the type for both arguments. + for (int i = 0; i < 2; i++) { + // Verify that the arguments are pointers. + const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(i)); + if (!PT) + return false; + + // Verify that the argument is a 'char*'. + if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy) + return false; } - const IdentifierInfo *id = FD->getIdentifier(); - size_t identifierid; + return true; +} - for (identifierid = 0; identifierid < num_rands; identifierid++) - if (id == II_rand[identifierid]) - break; +//===----------------------------------------------------------------------===// +// Check: Linear congruent random number generators should not be used +// Originally: <rdar://problem/63371000> +// CWE-338: Use of cryptographically weak prng +//===----------------------------------------------------------------------===// - if (identifierid >= num_rands) +void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) { + if (!CheckRand) return; const FunctionProtoType *FTP @@ -415,8 +487,8 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) { // Originally: <rdar://problem/63371000> //===----------------------------------------------------------------------===// -void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) { - if (FD->getIdentifier() != GetIdentifier(II_random, "random")) +void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) { + if (!CheckRand) return; const FunctionProtoType *FTP @@ -442,7 +514,7 @@ void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) { // Originally: <rdar://problem/6337132> //===----------------------------------------------------------------------===// -void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) { +void WalkAST::checkUncheckedReturnValue(CallExpr *CE) { const FunctionDecl *FD = CE->getDirectCallee(); if (!FD) return; @@ -502,7 +574,7 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) { //===----------------------------------------------------------------------===// namespace { -class SecuritySyntaxChecker : public CheckerV2<check::ASTCodeBody> { +class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp index d46ac81..abf53fd 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSizeofPointer.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/AST/StmtVisitor.h" @@ -26,7 +26,7 @@ class WalkAST : public StmtVisitor<WalkAST> { public: WalkAST(BugReporter &br) : BR(br) {} - void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E); + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); void VisitStmt(Stmt *S) { VisitChildren(S); } void VisitChildren(Stmt *S); }; @@ -39,8 +39,8 @@ void WalkAST::VisitChildren(Stmt *S) { } // CWE-467: Use of sizeof() on a Pointer Type -void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { - if (!E->isSizeOf()) +void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { + if (E->getKind() != UETT_SizeOf) return; // If an explicit type is used in the code, usually the coder knows what he is @@ -72,7 +72,7 @@ void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) { //===----------------------------------------------------------------------===// namespace { -class SizeofPointerChecker : public CheckerV2<check::ASTCodeBody> { +class SizeofPointerChecker : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td index 894b961..1a71fc4 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td @@ -10,204 +10,366 @@ include "clang/StaticAnalyzer/Checkers/CheckerBase.td" //===----------------------------------------------------------------------===// +// Groups. +//===----------------------------------------------------------------------===// + +def AllExperimental : CheckerGroup<"all-experimental">; + +//===----------------------------------------------------------------------===// // Packages. //===----------------------------------------------------------------------===// def Core : Package<"core">; -def Cocoa : Package<"cocoa">; -def Unix : Package<"unix">; -def MacOSX : Package<"macosx">; +def CoreBuiltin : Package<"builtin">, InPackage<Core>; +def CoreUninitialized : Package<"uninitialized">, InPackage<Core>; +def CoreExperimental : Package<"experimental">, InPackage<Core>, + InGroup<AllExperimental>, Hidden; -def CoreExperimental : Package<"experimental">, - InPackage<Core>, Hidden; +def Cplusplus : Package<"cplusplus">; +def CplusplusExperimental : Package<"experimental">, InPackage<Cplusplus>, + InGroup<AllExperimental>, Hidden; -def CocoaExperimental : Package<"experimental">, - InPackage<Cocoa>, Hidden; +def DeadCode : Package<"deadcode">; +def DeadCodeExperimental : Package<"experimental">, InPackage<DeadCode>, + InGroup<AllExperimental>, Hidden; -def UnixExperimental : Package<"experimental">, - InPackage<Unix>, Hidden; +def Security : Package <"security">; +def SecurityExperimental : Package<"experimental">, InPackage<Security>, + InGroup<AllExperimental>, Hidden; + +def Unix : Package<"unix">; +def UnixExperimental : Package<"experimental">, InPackage<Unix>, + InGroup<AllExperimental>, Hidden; + +def OSX : Package<"osx">; +def Cocoa : Package<"cocoa">, InPackage<OSX>; +def CocoaExperimental : Package<"experimental">, InPackage<Cocoa>, + InGroup<AllExperimental>, Hidden; +def CoreFoundation : Package<"coreFoundation">, InPackage<OSX>; def LLVM : Package<"llvm">; def Debug : Package<"debug">; //===----------------------------------------------------------------------===// -// Groups. +// Core Checkers. //===----------------------------------------------------------------------===// -def AllExperimental : CheckerGroup<"all-experimental">, - Hidden; +let ParentPackage = Core in { -//===----------------------------------------------------------------------===// -// Checkers. -//===----------------------------------------------------------------------===// +def DereferenceChecker : Checker<"NullDereference">, + HelpText<"Check for dereferences of null pointers">, + DescFile<"DereferenceChecker.cpp">; -let ParentPackage = Cocoa in { +def CallAndMessageChecker : Checker<"CallAndMessage">, + HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)">, + DescFile<"CallAndMessageChecker.cpp">; -def ObjCSelfInitChecker : Checker<"SelfInit">, - HelpText<"Check that 'self' is propely initialized inside an initializer method">, - DescFile<"ObjCSelfInitChecker.cpp">; +def AdjustedReturnValueChecker : Checker<"AdjustedReturnValue">, + HelpText<"Check to see if the return value of a function call is different than the caller expects (e.g., from calls through function pointers)">, + DescFile<"AdjustedReturnValueChecker.cpp">; -def ObjCAtSyncChecker : Checker<"AtSync">, - HelpText<"Check for null pointers used as mutexes for @synchronized">, - DescFile<"ObjCAtSyncChecker.cpp">; +def AttrNonNullChecker : Checker<"AttributeNonNull">, + HelpText<"Check for null pointers passed as arguments to a function whose arguments are marked with the 'nonnull' attribute">, + DescFile<"AttrNonNullChecker.cpp">; -def NilArgChecker : Checker<"NilArg">, - HelpText<"Check for prohibited nil arguments to ObjC method calls">, - DescFile<"BasicObjCFoundationChecks.cpp">; +def VLASizeChecker : Checker<"VLASize">, + HelpText<"Check for declarations of VLA of undefined or zero size">, + DescFile<"VLASizeChecker.cpp">; -def ClassReleaseChecker : Checker<"ClassRelease">, - HelpText<"Check for sending 'retain', 'release', or 'autorelease' directly to a Class">, - DescFile<"BasicObjCFoundationChecks.cpp">; +def DivZeroChecker : Checker<"DivideZero">, + HelpText<"Check for division by zero">, + DescFile<"DivZeroChecker.cpp">; -def NSAutoreleasePoolChecker : Checker<"NSAutoreleasePool">, - HelpText<"Warn for subpar uses of NSAutoreleasePool">, - DescFile<"NSAutoreleasePoolChecker.cpp">; +def UndefResultChecker : Checker<"UndefinedBinaryOperatorResult">, + HelpText<"Check for undefined results of binary operators">, + DescFile<"UndefResultChecker.cpp">; -def ObjCMethSigsChecker : Checker<"MethodSigs">, - HelpText<"Warn about Objective-C method signatures with type incompatibilities">, - DescFile<"CheckObjCInstMethSignature.cpp">; +def StackAddrEscapeChecker : Checker<"StackAddressEscape">, + HelpText<"Check that addresses to stack memory do not escape the function">, + DescFile<"StackAddrEscapeChecker.cpp">; -def ObjCUnusedIvarsChecker : Checker<"UnusedIvars">, - HelpText<"Warn about private ivars that are never used">, - DescFile<"ObjCUnusedIVarsChecker.cpp">; +} // end "core" -} // end "cocoa" +let ParentPackage = CoreExperimental in { -def StackAddrEscapeChecker : Checker<"StackAddrEscape">, - InPackage<Core>, - HelpText<"Check that addresses to stack memory do not escape the function">, - DescFile<"StackAddrEscapeChecker.cpp">; +def CastSizeChecker : Checker<"CastSize">, + HelpText<"Check when casting a malloc'ed type T, whether the size is a multiple of the size of T">, + DescFile<"CastSizeChecker.cpp">; -def DeadStoresChecker : Checker<"DeadStores">, - InPackage<Core>, - HelpText<"Check for values stored to a variables that are never read afterwards">, - DescFile<"DeadStoresChecker.cpp">; +def CastToStructChecker : Checker<"CastToStruct">, + HelpText<"Check for cast from non-struct pointer to struct pointer">, + DescFile<"CastToStructChecker.cpp">; -def UnixAPIChecker : Checker<"API">, - InPackage<Unix>, - HelpText<"Check calls to various UNIX/Posix functions">, - DescFile<"UnixAPIChecker.cpp">; +def FixedAddressChecker : Checker<"FixedAddr">, + HelpText<"Check for assignment of a fixed address to a pointer">, + DescFile<"FixedAddressChecker.cpp">; -def MacOSXAPIChecker : Checker<"API">, - InPackage<MacOSX>, - HelpText<"Check for proper uses of various Mac OS X APIs">, - DescFile<"MacOSXAPIChecker.cpp">; +def PointerArithChecker : Checker<"PointerArithm">, + HelpText<"Check for pointer arithmetic on locations other than array elements">, + DescFile<"PointerArithChecker">; -def CFNumberCreateChecker : Checker<"CFNumber">, - InPackage<MacOSX>, - HelpText<"Check for proper uses of CFNumberCreate">, - DescFile<"BasicObjCFoundationChecks.cpp">; +def PointerSubChecker : Checker<"PointerSub">, + HelpText<"Check for pointer subtractions on two pointers pointing to different memory chunks">, + DescFile<"PointerSubChecker">; -def CFRetainReleaseChecker : Checker<"CFRetainRelease">, - InPackage<MacOSX>, - HelpText<"Check for null arguments to CFRetain/CFRelease">, - DescFile<"BasicObjCFoundationChecks.cpp">; +def SizeofPointerChecker : Checker<"SizeofPtr">, + HelpText<"Warn about unintended use of sizeof() on pointer expressions">, + DescFile<"CheckSizeofPointer.cpp">; -def LLVMConventionsChecker : Checker<"Conventions">, - InPackage<LLVM>, - HelpText<"Check code for LLVM codebase conventions">, - DescFile<"LLVMConventionsChecker.cpp">; +} // end "core.experimental" -def LiveVariablesDumper : Checker<"DumpLiveVars">, - InPackage<Debug>, - HelpText<"Print results of live variable analysis">, - DescFile<"DebugCheckers.cpp">; +//===----------------------------------------------------------------------===// +// Evaluate "builtin" functions. +//===----------------------------------------------------------------------===// -def CFGViewer : Checker<"ViewCFG">, - InPackage<Debug>, - HelpText<"View Control-Flow Graphs using GraphViz">, - DescFile<"DebugCheckers.cpp">; +let ParentPackage = CoreBuiltin in { -def CFGDumper : Checker<"DumpCFG">, - InPackage<Debug>, - HelpText<"Display Control-Flow Graphs">, - DescFile<"DebugCheckers.cpp">; +def NoReturnFunctionChecker : Checker<"NoReturnFunctions">, + HelpText<"Evaluate \"panic\" functions that are known to not return to the caller">, + DescFile<"NoReturnFunctionChecker.cpp">; + +def BuiltinFunctionChecker : Checker<"BuiltinFunctions">, + HelpText<"Evaluate compiler builtin functions (e.g., alloca())">, + DescFile<"BuiltinFunctionChecker.cpp">; + +} // end "core.builtin" //===----------------------------------------------------------------------===// -// Hidden experimental checkers. +// Uninitialized values checkers. //===----------------------------------------------------------------------===// -let Group = AllExperimental in { +let ParentPackage = CoreUninitialized in { + +def UndefinedArraySubscriptChecker : Checker<"ArraySubscript">, + HelpText<"Check for uninitialized values used as array subscripts">, + DescFile<"UndefinedArraySubscriptChecker.cpp">; + +def UndefinedAssignmentChecker : Checker<"Assign">, + HelpText<"Check for assigning uninitialized values">, + DescFile<"UndefinedAssignmentChecker.cpp">; + +def UndefBranchChecker : Checker<"Branch">, + HelpText<"Check for uninitialized values used as branch conditions">, + DescFile<"UndefBranchChecker.cpp">; + +def UndefCapturedBlockVarChecker : Checker<"CapturedBlockVariable">, + HelpText<"Check for blocks that capture uninitialized values">, + DescFile<"UndefCapturedBlockVarChecker.cpp">; + +def ReturnUndefChecker : Checker<"UndefReturn">, + HelpText<"Check for uninitialized values being returned to the caller">, + DescFile<"ReturnUndefChecker.cpp">; + +} // end "core.uninitialized" + +//===----------------------------------------------------------------------===// +// C++ checkers. +//===----------------------------------------------------------------------===// + +let ParentPackage = CplusplusExperimental in { def CStringChecker : Checker<"CString">, - InPackage<CoreExperimental>, HelpText<"Check calls to functions in <string.h>">, DescFile<"CStringChecker.cpp">; -def UnreachableCodeChecker : Checker<"UnreachableCode">, - InPackage<CoreExperimental>, - HelpText<"Check unreachable code">, - DescFile<"UnreachableCodeChecker.cpp">, - Hidden; // Must be specified explicitly in order to run. +def IteratorsChecker : Checker<"Iterators">, + HelpText<"Check improper uses of STL vector iterators">, + DescFile<"IteratorsChecker.cpp">; + +} // end: "cplusplus.experimental" + +//===----------------------------------------------------------------------===// +// Deadcode checkers. +//===----------------------------------------------------------------------===// -def IdempotentOperationChecker : Checker<"IdempotentOps">, - InPackage<CoreExperimental>, +let ParentPackage = DeadCode in { + +def DeadStoresChecker : Checker<"DeadStores">, + HelpText<"Check for values stored to variables that are never read afterwards">, + DescFile<"DeadStoresChecker.cpp">; + +def IdempotentOperationChecker : Checker<"IdempotentOperations">, HelpText<"Warn about idempotent operations">, DescFile<"IdempotentOperationChecker.cpp">; -def CastToStructChecker : Checker<"CastToStruct">, - InPackage<CoreExperimental>, - HelpText<"Check for cast from non-struct pointer to struct pointer">, - DescFile<"CastToStructChecker.cpp">; +} // end DeadCode -def FixedAddressChecker : Checker<"FixedAddr">, - InPackage<CoreExperimental>, - HelpText<"Check for assignment of a fixed address to a pointer">, - DescFile<"FixedAddressChecker.cpp">; +let ParentPackage = DeadCodeExperimental in { -def PointerArithChecker : Checker<"PointerArithm">, - InPackage<CoreExperimental>, - HelpText<"Check for pointer arithmetic on locations other than array elements">, - DescFile<"PointerArithChecker">; +def UnreachableCodeChecker : Checker<"UnreachableCode">, + HelpText<"Check unreachable code">, + DescFile<"UnreachableCodeChecker.cpp">; -def PointerSubChecker : Checker<"PointerSub">, - InPackage<CoreExperimental>, - HelpText<"Check for pointer subtractions on two pointers pointing to different memory chunks">, - DescFile<"PointerSubChecker">; +} // end "deadcode.experimental" -def SizeofPointerChecker : Checker<"SizeofPtr">, - InPackage<CoreExperimental>, - HelpText<"Warn about unintended use of sizeof() on pointer expressions">, - DescFile<"CheckSizeofPointer.cpp">; +//===----------------------------------------------------------------------===// +// Security checkers. +//===----------------------------------------------------------------------===// + +let ParentPackage = SecurityExperimental in { def SecuritySyntaxChecker : Checker<"SecuritySyntactic">, - InPackage<CoreExperimental>, - HelpText<"Perform quick security checks that require no data flow">, + HelpText<"Perform quick security API checks that require no data flow">, DescFile<"CheckSecuritySyntaxOnly.cpp">; +def ArrayBoundChecker : Checker<"ArrayBound">, + HelpText<"Warn about buffer overflows (older checker)">, + DescFile<"ArrayBoundChecker.cpp">; + +def ArrayBoundCheckerV2 : Checker<"ArrayBoundV2">, + HelpText<"Warn about buffer overflows (newer checker)">, + DescFile<"ArrayBoundCheckerV2.cpp">; + def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">, - InPackage<CoreExperimental>, HelpText<"Check for an out-of-bound pointer being returned to callers">, DescFile<"ReturnPointerRangeChecker.cpp">; -def ArrayBoundChecker : Checker<"ArrayBound">, - InPackage<CoreExperimental>, - HelpText<"Check for an out-of-bound pointer being returned to callers">, - DescFile<"ArrayBoundChecker.cpp">; +} // end "security.experimental" -def CastSizeChecker : Checker<"CastSize">, - InPackage<CoreExperimental>, - HelpText<"Check when casting a malloc'ed type T, whether the size is a multiple of the size of T">, - DescFile<"CastSizeChecker.cpp">; +//===----------------------------------------------------------------------===// +// Unix API checkers. +//===----------------------------------------------------------------------===// -def ObjCDeallocChecker : Checker<"Dealloc">, - InPackage<CocoaExperimental>, - HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">, - DescFile<"CheckObjCDealloc.cpp">; +let ParentPackage = Unix in { + +def UnixAPIChecker : Checker<"API">, + HelpText<"Check calls to various UNIX/Posix functions">, + DescFile<"UnixAPIChecker.cpp">; + +} // end "unix" + +let ParentPackage = UnixExperimental in { def ChrootChecker : Checker<"Chroot">, - InPackage<UnixExperimental>, HelpText<"Check improper use of chroot">, DescFile<"ChrootChecker.cpp">; +def MallocChecker : Checker<"Malloc">, + HelpText<"Check for potential memory leaks, double free, and use-after-free problems">, + DescFile<"MallocChecker.cpp">; + def PthreadLockChecker : Checker<"PthreadLock">, - InPackage<UnixExperimental>, HelpText<"Simple lock -> unlock checker">, DescFile<"PthreadLockChecker.cpp">; def StreamChecker : Checker<"Stream">, - InPackage<UnixExperimental>, HelpText<"Check stream handling functions">, DescFile<"StreamChecker.cpp">; +} // end "unix.experimental" + +//===----------------------------------------------------------------------===// +// Mac OS X, Cocoa, and Core Foundation checkers. +//===----------------------------------------------------------------------===// + +let ParentPackage = OSX in { + +def MacOSXAPIChecker : Checker<"API">, + InPackage<OSX>, + HelpText<"Check for proper uses of various Mac OS X APIs">, + DescFile<"MacOSXAPIChecker.cpp">; + +def OSAtomicChecker : Checker<"AtomicCAS">, + InPackage<OSX>, + HelpText<"Evaluate calls to OSAtomic functions">, + DescFile<"OSAtomicChecker.cpp">; + +} // end "macosx" + +let ParentPackage = Cocoa in { + +def ObjCAtSyncChecker : Checker<"AtSync">, + HelpText<"Check for null pointers used as mutexes for @synchronized">, + DescFile<"ObjCAtSyncChecker.cpp">; + +def NilArgChecker : Checker<"NilArg">, + HelpText<"Check for prohibited nil arguments to ObjC method calls">, + DescFile<"BasicObjCFoundationChecks.cpp">; + +def ClassReleaseChecker : Checker<"ClassRelease">, + HelpText<"Check for sending 'retain', 'release', or 'autorelease' directly to a Class">, + DescFile<"BasicObjCFoundationChecks.cpp">; + +def VariadicMethodTypeChecker : Checker<"VariadicMethodTypes">, + HelpText<"Check for passing non-Objective-C types to variadic methods that expect" + "only Objective-C types">, + DescFile<"BasicObjCFoundationChecks.cpp">; + +def NSAutoreleasePoolChecker : Checker<"NSAutoreleasePool">, + HelpText<"Warn for suboptimal uses of NSAutoreleasePool in Objective-C GC mode">, + DescFile<"NSAutoreleasePoolChecker.cpp">; + +def ObjCMethSigsChecker : Checker<"IncompatibleMethodTypes">, + HelpText<"Warn about Objective-C method signatures with type incompatibilities">, + DescFile<"CheckObjCInstMethSignature.cpp">; + +def ObjCUnusedIvarsChecker : Checker<"UnusedIvars">, + HelpText<"Warn about private ivars that are never used">, + DescFile<"ObjCUnusedIVarsChecker.cpp">; + +def NSErrorChecker : Checker<"NSError">, + HelpText<"Check usage of NSError** parameters">, + DescFile<"NSErrorChecker.cpp">; + +} // end "cocoa" + +let ParentPackage = CocoaExperimental in { + +def ObjCSelfInitChecker : Checker<"SelfInit">, + HelpText<"Check that 'self' is properly initialized inside an initializer method">, + DescFile<"ObjCSelfInitChecker.cpp">; + +def ObjCDeallocChecker : Checker<"Dealloc">, + HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">, + DescFile<"CheckObjCDealloc.cpp">; + +} // end "cocoa.experimental" + +let ParentPackage = CoreFoundation in { + +def CFNumberCreateChecker : Checker<"CFNumber">, + HelpText<"Check for proper uses of CFNumberCreate">, + DescFile<"BasicObjCFoundationChecks.cpp">; + +def CFRetainReleaseChecker : Checker<"CFRetainRelease">, + HelpText<"Check for null arguments to CFRetain/CFRelease">, + DescFile<"BasicObjCFoundationChecks.cpp">; + +def CFErrorChecker : Checker<"CFError">, + HelpText<"Check usage of CFErrorRef* parameters">, + DescFile<"NSErrorChecker.cpp">; } + +//===----------------------------------------------------------------------===// +// Checkers for LLVM development. +//===----------------------------------------------------------------------===// + +def LLVMConventionsChecker : Checker<"Conventions">, + InPackage<LLVM>, + HelpText<"Check code for LLVM codebase conventions">, + DescFile<"LLVMConventionsChecker.cpp">; + +//===----------------------------------------------------------------------===// +// Debugging checkers (for analyzer development). +//===----------------------------------------------------------------------===// + +let ParentPackage = Debug in { + +def LiveVariablesDumper : Checker<"DumpLiveVars">, + HelpText<"Print results of live variable analysis">, + DescFile<"DebugCheckers.cpp">; + +def CFGViewer : Checker<"ViewCFG">, + HelpText<"View Control-Flow Graphs using GraphViz">, + DescFile<"DebugCheckers.cpp">; + +def CFGDumper : Checker<"DumpCFG">, + HelpText<"Display Control-Flow Graphs">, + DescFile<"DebugCheckers.cpp">; + +def AnalyzerStatsChecker : Checker<"Stats">, + HelpText<"Emit warnings with analyzer statistics">, + DescFile<"AnalyzerStatsChecker.cpp">; + +} // end "debug" + diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp index b6eef6d..50b57d1 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -38,7 +38,7 @@ bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; } // ROOT_CHANGED<--chdir(..)-- JAIL_ENTERED<--chdir(..)-- // | | // bug<--foo()-- JAIL_ENTERED<--foo()-- -class ChrootChecker : public CheckerV2<eval::Call, check::PreStmt<CallExpr> > { +class ChrootChecker : public Checker<eval::Call, check::PreStmt<CallExpr> > { mutable IdentifierInfo *II_chroot, *II_chdir; // This bug refers to possibly break out of a chroot() jail. mutable llvm::OwningPtr<BuiltinBug> BT_BreakJail; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp index 5c0c950..291f8e0 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckerProvider.cpp @@ -45,17 +45,54 @@ struct StaticCheckerInfoRec { const char *FullName; void (*RegFunc)(CheckerManager &mgr); const char *HelpText; + int GroupIndex; bool Hidden; }; +struct StaticPackageInfoRec { + const char *FullName; + int GroupIndex; + bool Hidden; +}; + +struct StaticGroupInfoRec { + const char *FullName; +}; + } // end anonymous namespace. +static const StaticPackageInfoRec StaticPackageInfo[] = { +#define GET_PACKAGES +#define PACKAGE(FULLNAME, GROUPINDEX, HIDDEN) \ + { FULLNAME, GROUPINDEX, HIDDEN }, +#include "Checkers.inc" + { 0, -1, 0 } +#undef PACKAGE +#undef GET_PACKAGES +}; + +static const unsigned NumPackages = sizeof(StaticPackageInfo) + / sizeof(StaticPackageInfoRec) - 1; + +static const StaticGroupInfoRec StaticGroupInfo[] = { +#define GET_GROUPS +#define GROUP(FULLNAME) \ + { FULLNAME }, +#include "Checkers.inc" + { 0 } +#undef GROUP +#undef GET_GROUPS +}; + +static const unsigned NumGroups = sizeof(StaticGroupInfo) + / sizeof(StaticGroupInfoRec) - 1; + static const StaticCheckerInfoRec StaticCheckerInfo[] = { #define GET_CHECKERS -#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,HIDDEN) \ - { FULLNAME, register##CLASS, HELPTEXT, HIDDEN }, +#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \ + { FULLNAME, register##CLASS, HELPTEXT, GROUPINDEX, HIDDEN }, #include "Checkers.inc" - { 0, 0, 0, 0} + { 0, 0, 0, -1, 0} #undef CHECKER #undef GET_CHECKERS }; @@ -101,8 +138,9 @@ static void collectCheckers(const CheckNameOption *checkName, if (const short *member = checkName->Members) { if (enable) { - if (collectHidden || !StaticCheckerInfo[*member].Hidden) - checkers.insert(&StaticCheckerInfo[*member]); + for (; *member != -1; ++member) + if (collectHidden || !StaticCheckerInfo[*member].Hidden) + checkers.insert(&StaticCheckerInfo[*member]); } else { for (; *member != -1; ++member) checkers.erase(&StaticCheckerInfo[*member]); @@ -144,6 +182,48 @@ void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr, } } +//===----------------------------------------------------------------------===// +// Printing Help. +//===----------------------------------------------------------------------===// + +static void printPackageOption(llvm::raw_ostream &OS) { + // Find the maximum option length. + unsigned OptionFieldWidth = 0; + for (unsigned i = 0; i != NumPackages; ++i) { + // Limit the amount of padding we are willing to give up for alignment. + unsigned Length = strlen(StaticPackageInfo[i].FullName); + if (Length <= 30) + OptionFieldWidth = std::max(OptionFieldWidth, Length); + } + + const unsigned InitialPad = 2; + for (unsigned i = 0; i != NumPackages; ++i) { + const StaticPackageInfoRec &package = StaticPackageInfo[i]; + const std::string &Option = package.FullName; + int Pad = OptionFieldWidth - int(Option.size()); + OS.indent(InitialPad) << Option; + + if (package.GroupIndex != -1 || package.Hidden) { + // Break on long option names. + if (Pad < 0) { + OS << "\n"; + Pad = OptionFieldWidth + InitialPad; + } + OS.indent(Pad + 1) << "["; + if (package.GroupIndex != -1) { + OS << "Group=" << StaticGroupInfo[package.GroupIndex].FullName; + if (package.Hidden) + OS << ", "; + } + if (package.Hidden) + OS << "Hidden"; + OS << "]"; + } + + OS << "\n"; + } +} + typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers; static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) { @@ -161,6 +241,7 @@ static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) { for (SortedCheckers::iterator I = checkers.begin(), E = checkers.end(); I != E; ++I) { const std::string &Option = I->first; + const StaticCheckerInfoRec &checker = *I->second; int Pad = OptionFieldWidth - int(Option.size()); OS.indent(InitialPad) << Option; @@ -169,11 +250,36 @@ static void printCheckerOption(llvm::raw_ostream &OS,SortedCheckers &checkers) { OS << "\n"; Pad = OptionFieldWidth + InitialPad; } - OS.indent(Pad + 1) << I->second->HelpText << '\n'; + OS.indent(Pad + 1) << checker.HelpText; + + if (checker.GroupIndex != -1 || checker.Hidden) { + OS << " ["; + if (checker.GroupIndex != -1) { + OS << "Group=" << StaticGroupInfo[checker.GroupIndex].FullName; + if (checker.Hidden) + OS << ", "; + } + if (checker.Hidden) + OS << "Hidden"; + OS << "]"; + } + + OS << "\n"; } } void ClangSACheckerProvider::printHelp(llvm::raw_ostream &OS) { + OS << "USAGE: -analyzer-checker <CHECKER or PACKAGE or GROUP,...>\n"; + + OS << "\nGROUPS:\n"; + for (unsigned i = 0; i != NumGroups; ++i) + OS.indent(2) << StaticGroupInfo[i].FullName << "\n"; + + OS << "\nPACKAGES:\n"; + printPackageOption(OS); + + OS << "\nCHECKERS:\n"; + // Sort checkers according to their full name. SortedCheckers checkers; for (unsigned i = 0; i != NumCheckers; ++i) diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h index 73239f5..5524b0f 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ClangSACheckers.h @@ -21,7 +21,7 @@ namespace ento { class CheckerManager; #define GET_CHECKERS -#define CHECKER(FULLNAME,CLASS,CXXFILE,HELPTEXT,HIDDEN) \ +#define CHECKER(FULLNAME,CLASS,CXXFILE,HELPTEXT,GROUPINDEX,HIDDEN) \ void register##CLASS(CheckerManager &mgr); #include "Checkers.inc" #undef CHECKER diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 3b39372..bc1d823 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -13,8 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" -#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" @@ -342,7 +341,7 @@ public: //===----------------------------------------------------------------------===// namespace { -class DeadStoresChecker : public CheckerV2<check::ASTCodeBody> { +class DeadStoresChecker : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp index 091d99b..486b7f7 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/Analysis/Analyses/LiveVariables.h" @@ -24,7 +24,7 @@ using namespace ento; //===----------------------------------------------------------------------===// namespace { -class LiveVariablesDumper : public CheckerV2<check::ASTCodeBody> { +class LiveVariablesDumper : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { @@ -44,7 +44,7 @@ void ento::registerLiveVariablesDumper(CheckerManager &mgr) { //===----------------------------------------------------------------------===// namespace { -class CFGViewer : public CheckerV2<check::ASTCodeBody> { +class CFGViewer : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { @@ -64,7 +64,7 @@ void ento::registerCFGViewer(CheckerManager &mgr) { //===----------------------------------------------------------------------===// namespace { -class CFGDumper : public CheckerV2<check::ASTCodeBody> { +class CFGDumper : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) const { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index 606ac4a..baaf8b3 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -12,51 +12,31 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" using namespace clang; using namespace ento; namespace { -class DereferenceChecker : public Checker { - BuiltinBug *BT_null; - BuiltinBug *BT_undef; - llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes; +class DereferenceChecker + : public Checker< check::Location, + EventDispatcher<ImplicitNullDerefEvent> > { + mutable llvm::OwningPtr<BuiltinBug> BT_null; + mutable llvm::OwningPtr<BuiltinBug> BT_undef; + public: - DereferenceChecker() : BT_null(0), BT_undef(0) {} - static void *getTag() { static int tag = 0; return &tag; } - void visitLocation(CheckerContext &C, const Stmt *S, SVal location, - bool isLoad); - - std::pair<ExplodedNode * const*, ExplodedNode * const*> - getImplicitNodes() const { - return std::make_pair(ImplicitNullDerefNodes.data(), - ImplicitNullDerefNodes.data() + - ImplicitNullDerefNodes.size()); - } - void AddDerefSource(llvm::raw_ostream &os, - llvm::SmallVectorImpl<SourceRange> &Ranges, - const Expr *Ex, bool loadedFrom = false); + void checkLocation(SVal location, bool isLoad, CheckerContext &C) const; + + static void AddDerefSource(llvm::raw_ostream &os, + llvm::SmallVectorImpl<SourceRange> &Ranges, + const Expr *Ex, bool loadedFrom = false); }; } // end anonymous namespace -void ento::RegisterDereferenceChecker(ExprEngine &Eng) { - Eng.registerCheck(new DereferenceChecker()); -} - -std::pair<ExplodedNode * const *, ExplodedNode * const *> -ento::GetImplicitNullDereferences(ExprEngine &Eng) { - DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>(); - if (!checker) - return std::make_pair((ExplodedNode * const *) 0, - (ExplodedNode * const *) 0); - return checker->getImplicitNodes(); -} - void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os, llvm::SmallVectorImpl<SourceRange> &Ranges, const Expr *Ex, @@ -85,13 +65,13 @@ void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os, } } -void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S, - SVal l, bool isLoad) { +void DereferenceChecker::checkLocation(SVal l, bool isLoad, + CheckerContext &C) const { // Check for dereference of an undefined value. if (l.isUndef()) { if (ExplodedNode *N = C.generateSink()) { if (!BT_undef) - BT_undef = new BuiltinBug("Dereference of undefined pointer value"); + BT_undef.reset(new BuiltinBug("Dereference of undefined pointer value")); EnhancedBugReport *report = new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N); @@ -108,6 +88,7 @@ void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S, if (!isa<Loc>(location)) return; + const Stmt *S = C.getStmt(); const GRState *state = C.getState(); const GRState *notNullState, *nullState; llvm::tie(notNullState, nullState) = state->assume(location); @@ -123,7 +104,7 @@ void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S, // We know that 'location' cannot be non-null. This is what // we call an "explicit" null dereference. if (!BT_null) - BT_null = new BuiltinBug("Dereference of null pointer"); + BT_null.reset(new BuiltinBug("Dereference of null pointer")); llvm::SmallString<100> buf; llvm::SmallVector<SourceRange, 2> Ranges; @@ -195,11 +176,17 @@ void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S, // Otherwise, we have the case where the location could either be // null or not-null. Record the error node as an "implicit" null // dereference. - if (ExplodedNode *N = C.generateSink(nullState)) - ImplicitNullDerefNodes.push_back(N); + if (ExplodedNode *N = C.generateSink(nullState)) { + ImplicitNullDerefEvent event = { l, isLoad, N, &C.getBugReporter() }; + dispatchEvent(event); + } } } // From this point forward, we know that the location is not null. C.addTransition(notNullState); } + +void ento::registerDereferenceChecker(CheckerManager &mgr) { + mgr.registerChecker<DereferenceChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 20cc904..07fb5aa 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -12,34 +12,25 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" using namespace clang; using namespace ento; namespace { -class DivZeroChecker : public CheckerVisitor<DivZeroChecker> { - BuiltinBug *BT; +class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > { + mutable llvm::OwningPtr<BuiltinBug> BT; public: - DivZeroChecker() : BT(0) {} - static void *getTag(); - void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); + void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; }; } // end anonymous namespace -void ento::RegisterDivZeroChecker(ExprEngine &Eng) { - Eng.registerCheck(new DivZeroChecker()); -} - -void *DivZeroChecker::getTag() { - static int x; - return &x; -} - -void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, - const BinaryOperator *B) { +void DivZeroChecker::checkPreStmt(const BinaryOperator *B, + CheckerContext &C) const { BinaryOperator::Opcode Op = B->getOpcode(); if (Op != BO_Div && Op != BO_Rem && @@ -67,7 +58,7 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, if (stateZero && !stateNotZero) { if (ExplodedNode *N = C.generateSink(stateZero)) { if (!BT) - BT = new BuiltinBug("Division by zero"); + BT.reset(new BuiltinBug("Division by zero")); EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(), N); @@ -84,3 +75,7 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C, // zero denom case for now. C.addTransition(stateNotZero); } + +void ento::registerDivZeroChecker(CheckerManager &mgr) { + mgr.registerChecker<DivZeroChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp deleted file mode 100644 index 990ba1c0..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExperimentalChecks.cpp +++ /dev/null @@ -1,26 +0,0 @@ -//=-- ExperimentalChecks.h ----------------------------------------*- C++ -*-=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines functions to instantiate and register experimental -// checks in ExprEngine. -// -//===----------------------------------------------------------------------===// - -#include "InternalChecks.h" -#include "ExperimentalChecks.h" -#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" - -using namespace clang; -using namespace ento; - -void ento::RegisterExperimentalChecks(ExprEngine &Eng) { - // These are checks that never belong as internal checks - // within ExprEngine. - RegisterMallocChecker(Eng); // ArrayBoundChecker depends on this. -} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExperimentalChecks.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExperimentalChecks.h deleted file mode 100644 index 1f38ad7..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExperimentalChecks.h +++ /dev/null @@ -1,31 +0,0 @@ -//=-- ExperimentalChecks.h ----------------------------------------*- C++ -*-=// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines functions to instantiate and register experimental -// checks in ExprEngine. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_GR_ExprEngine_EXPERIMENTAL_CHECKS -#define LLVM_CLANG_GR_ExprEngine_EXPERIMENTAL_CHECKS - -namespace clang { - -namespace ento { - -class ExprEngine; - -void RegisterAnalyzerStatsChecker(ExprEngine &Eng); -void RegisterMallocChecker(ExprEngine &Eng); - -} // end GR namespace - -} // end clang namespace - -#endif diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp index d7b27b5..d699dee 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -24,7 +24,7 @@ using namespace ento; namespace { class FixedAddressChecker - : public CheckerV2< check::PreStmt<BinaryOperator> > { + : public Checker< check::PreStmt<BinaryOperator> > { mutable llvm::OwningPtr<BuiltinBug> BT; public: diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp index 83d9668..b0c07fc 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp @@ -46,7 +46,7 @@ #include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/Analyses/PseudoConstantAnalysis.h" #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" @@ -59,14 +59,13 @@ #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/BitVector.h" #include "llvm/Support/ErrorHandling.h" -#include <deque> using namespace clang; using namespace ento; namespace { class IdempotentOperationChecker - : public CheckerV2<check::PreStmt<BinaryOperator>, + : public Checker<check::PreStmt<BinaryOperator>, check::PostStmt<BinaryOperator>, check::EndAnalysis> { public: @@ -336,10 +335,9 @@ void IdempotentOperationChecker::checkPostStmt(const BinaryOperator *B, = cast<StmtPoint>(C.getPredecessor()->getLocation()).getStmt(); // Ignore implicit calls to setters. - if (isa<ObjCPropertyRefExpr>(predStmt)) + if (!isa<BinaryOperator>(predStmt)) return; - - assert(isa<BinaryOperator>(predStmt)); + Data.explodedNodes.Add(C.getPredecessor()); } @@ -532,12 +530,12 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC, const CFGBlock *CB, const CoreEngine &CE) { - CFGReachabilityAnalysis *CRA = AC->getCFGReachablityAnalysis(); + CFGReverseBlockReachabilityAnalysis *CRA = AC->getCFGReachablityAnalysis(); // Test for reachability from any aborted blocks to this block - typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator; - for (AbortedIterator I = CE.blocks_aborted_begin(), - E = CE.blocks_aborted_end(); I != E; ++I) { + typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator; + for (ExhaustedIterator I = CE.blocks_exhausted_begin(), + E = CE.blocks_exhausted_end(); I != E; ++I) { const BlockEdge &BE = I->first; // The destination block on the BlockEdge is the first block that was not @@ -551,16 +549,25 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC, if (destBlock == CB || CRA->isReachable(destBlock, CB)) return false; } + + // Test for reachability from blocks we just gave up on. + typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator; + for (AbortedIterator I = CE.blocks_aborted_begin(), + E = CE.blocks_aborted_end(); I != E; ++I) { + const CFGBlock *destBlock = I->first; + if (destBlock == CB || CRA->isReachable(destBlock, CB)) + return false; + } // For the items still on the worklist, see if they are in blocks that // can eventually reach 'CB'. class VisitWL : public WorkList::Visitor { const CFGStmtMap *CBM; const CFGBlock *TargetBlock; - CFGReachabilityAnalysis &CRA; + CFGReverseBlockReachabilityAnalysis &CRA; public: VisitWL(const CFGStmtMap *cbm, const CFGBlock *targetBlock, - CFGReachabilityAnalysis &cra) + CFGReverseBlockReachabilityAnalysis &cra) : CBM(cbm), TargetBlock(targetBlock), CRA(cra) {} virtual bool visit(const WorkListUnit &U) { ProgramPoint P = U.getNode()->getLocation(); @@ -580,7 +587,7 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC, if (!B) return true; - return CRA.isReachable(B, TargetBlock); + return B == TargetBlock || CRA.isReachable(B, TargetBlock); } }; VisitWL visitWL(AC->getCFGStmtMap(), CB, *CRA); @@ -641,9 +648,10 @@ bool IdempotentOperationChecker::CanVary(const Expr *Ex, return false; // Cases requiring custom logic - case Stmt::SizeOfAlignOfExprClass: { - const SizeOfAlignOfExpr *SE = cast<const SizeOfAlignOfExpr>(Ex); - if (!SE->isSizeOf()) + case Stmt::UnaryExprOrTypeTraitExprClass: { + const UnaryExprOrTypeTraitExpr *SE = + cast<const UnaryExprOrTypeTraitExpr>(Ex); + if (SE->getKind() != UETT_SizeOf) return false; return SE->getTypeOfArgument()->isVariableArrayType(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/InternalChecks.h b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/InternalChecks.h deleted file mode 100644 index e7c38ee..0000000 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/InternalChecks.h +++ /dev/null @@ -1,48 +0,0 @@ -//=-- InternalChecks.h- Builtin ExprEngine Checks -------------------*- C++ -*-= -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines functions to instantiate and register the "built-in" -// checks in ExprEngine. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_GR_ExprEngine_INTERNAL_CHECKS -#define LLVM_CLANG_GR_ExprEngine_INTERNAL_CHECKS - -namespace clang { - -namespace ento { - -class ExprEngine; - -// Foundational checks that handle basic semantics. -void RegisterAdjustedReturnValueChecker(ExprEngine &Eng); -void RegisterArrayBoundCheckerV2(ExprEngine &Eng); -void RegisterAttrNonNullChecker(ExprEngine &Eng); -void RegisterBuiltinFunctionChecker(ExprEngine &Eng); -void RegisterCallAndMessageChecker(ExprEngine &Eng); -void RegisterDereferenceChecker(ExprEngine &Eng); -void RegisterDivZeroChecker(ExprEngine &Eng); -void RegisterNoReturnFunctionChecker(ExprEngine &Eng); -void RegisterReturnUndefChecker(ExprEngine &Eng); -void RegisterUndefBranchChecker(ExprEngine &Eng); -void RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng); -void RegisterUndefResultChecker(ExprEngine &Eng); -void RegisterUndefinedArraySubscriptChecker(ExprEngine &Eng); -void RegisterUndefinedAssignmentChecker(ExprEngine &Eng); -void RegisterVLASizeChecker(ExprEngine &Eng); - -// API checks. -void RegisterOSAtomicChecker(ExprEngine &Eng); - -} // end GR namespace - -} // end clang namespace - -#endif diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp new file mode 100644 index 0000000..e4e5f54 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IteratorsChecker.cpp @@ -0,0 +1,582 @@ +//=== IteratorsChecker.cpp - Check for Invalidated Iterators ------*- C++ -*---- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines IteratorsChecker, a number of small checks for conditions +// leading to invalid iterators being used. +// FIXME: Currently only supports 'vector' and 'deque' +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclTemplate.h" +#include "clang/Basic/SourceManager.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "clang/AST/PrettyPrinter.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringSwitch.h" + + +using namespace clang; +using namespace ento; + +// This is the state associated with each iterator which includes both the +// kind of state and the instance used to initialize it. +// FIXME: add location where invalidated for better error reporting. +namespace { +class RefState { + enum Kind { BeginValid, EndValid, Invalid, Undefined, Unknown } K; + const void *VR; + +public: + RefState(Kind k, const void *vr) : K(k), VR(vr) {} + + bool isValid() const { return K == BeginValid || K == EndValid; } + bool isInvalid() const { return K == Invalid; } + bool isUndefined() const { return K == Undefined; } + bool isUnknown() const { return K == Unknown; } + const MemRegion *getMemRegion() const { + if (K == BeginValid || K == EndValid) + return(const MemRegion *)VR; + return 0; + } + const MemberExpr *getMemberExpr() const { + if (K == Invalid) + return(const MemberExpr *)VR; + return 0; + } + + bool operator==(const RefState &X) const { + return K == X.K && VR == X.VR; + } + + static RefState getBeginValid(const MemRegion *vr) { + assert(vr); + return RefState(BeginValid, vr); + } + static RefState getEndValid(const MemRegion *vr) { + assert(vr); + return RefState(EndValid, vr); + } + static RefState getInvalid( const MemberExpr *ME ) { + return RefState(Invalid, ME); + } + static RefState getUndefined( void ) { + return RefState(Undefined, 0); + } + static RefState getUnknown( void ) { + return RefState(Unknown, 0); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(K); + ID.AddPointer(VR); + } +}; + +enum RefKind { NoKind, VectorKind, VectorIteratorKind }; + +class IteratorsChecker : + public Checker<check::PreStmt<CXXOperatorCallExpr>, + check::PreStmt<DeclStmt>, + check::PreStmt<CXXMemberCallExpr>, + check::PreStmt<CallExpr> > + { + // Used when parsing iterators and vectors and deques. + BuiltinBug *BT_Invalid, *BT_Undefined, *BT_Incompatible; + +public: + IteratorsChecker() : + BT_Invalid(0), BT_Undefined(0), BT_Incompatible(0) + {} + static void *getTag() { static int tag; return &tag; } + + // Checker entry points. + void checkPreStmt(const CXXOperatorCallExpr *OCE, + CheckerContext &C) const; + + void checkPreStmt(const DeclStmt *DS, + CheckerContext &C) const; + + void checkPreStmt(const CXXMemberCallExpr *MCE, + CheckerContext &C) const; + + void checkPreStmt(const CallExpr *CE, + CheckerContext &C) const; + +private: + const GRState *handleAssign(const GRState *state, const Expr *lexp, + const Expr *rexp, const LocationContext *LC) const; + const GRState *handleAssign(const GRState *state, const MemRegion *MR, + const Expr *rexp, const LocationContext *LC) const; + const GRState *invalidateIterators(const GRState *state, const MemRegion *MR, + const MemberExpr *ME) const; + void checkExpr(CheckerContext &C, const Expr *E) const; + void checkArgs(CheckerContext &C, const CallExpr *CE) const; + const MemRegion *getRegion(const GRState *state, const Expr *E, + const LocationContext *LC) const; + const DeclRefExpr *getDeclRefExpr(const Expr *E) const; +}; + +class IteratorState { +public: + typedef llvm::ImmutableMap<const MemRegion *, RefState> EntryMap; +}; +} //end anonymous namespace + +namespace clang { + namespace ento { + template <> + struct GRStateTrait<IteratorState> + : public GRStatePartialTrait<IteratorState::EntryMap> { + static void *GDMIndex() { return IteratorsChecker::getTag(); } + }; + } +} + +void ento::registerIteratorsChecker(CheckerManager &mgr) { + mgr.registerChecker<IteratorsChecker>(); +} + +// =============================================== +// Utility functions used by visitor functions +// =============================================== + +// check a templated type for std::vector or std::deque +static RefKind getTemplateKind(const NamedDecl *td) { + const DeclContext *dc = td->getDeclContext(); + const NamespaceDecl *nameSpace = dyn_cast<NamespaceDecl>(dc); + if (!nameSpace || !isa<TranslationUnitDecl>(nameSpace->getDeclContext()) + || nameSpace->getName() != "std") + return NoKind; + + llvm::StringRef name = td->getName(); + return llvm::StringSwitch<RefKind>(name) + .Cases("vector", "deque", VectorKind) + .Default(NoKind); +} + +static RefKind getTemplateKind(const DeclContext *dc) { + if (const ClassTemplateSpecializationDecl *td = + dyn_cast<ClassTemplateSpecializationDecl>(dc)) + return getTemplateKind(cast<NamedDecl>(td)); + return NoKind; +} + +static RefKind getTemplateKind(const TypedefType *tdt) { + const TypedefNameDecl *td = tdt->getDecl(); + RefKind parentKind = getTemplateKind(td->getDeclContext()); + if (parentKind == VectorKind) { + return llvm::StringSwitch<RefKind>(td->getName()) + .Cases("iterator", + "const_iterator", + "reverse_iterator", VectorIteratorKind) + .Default(NoKind); + } + return NoKind; +} + +static RefKind getTemplateKind(const TemplateSpecializationType *tsp) { + const TemplateName &tname = tsp->getTemplateName(); + TemplateDecl *td = tname.getAsTemplateDecl(); + if (!td) + return NoKind; + return getTemplateKind(td); +} + +static RefKind getTemplateKind(QualType T) { + if (const TemplateSpecializationType *tsp = + T->getAs<TemplateSpecializationType>()) { + return getTemplateKind(tsp); + } + if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(T)) { + QualType namedType = ET->getNamedType(); + if (const TypedefType *tdt = namedType->getAs<TypedefType>()) + return getTemplateKind(tdt); + if (const TemplateSpecializationType *tsp = + namedType->getAs<TemplateSpecializationType>()) { + return getTemplateKind(tsp); + } + } + return NoKind; +} + +// Iterate through our map and invalidate any iterators that were +// initialized fromt the specified instance MemRegion. +const GRState *IteratorsChecker::invalidateIterators(const GRState *state, + const MemRegion *MR, const MemberExpr *ME) const { + IteratorState::EntryMap Map = state->get<IteratorState>(); + if (Map.isEmpty()) + return state; + + // Loop over the entries in the current state. + // The key doesn't change, so the map iterators won't change. + for (IteratorState::EntryMap::iterator I = Map.begin(), E = Map.end(); + I != E; ++I) { + RefState RS = I.getData(); + if (RS.getMemRegion() == MR) + state = state->set<IteratorState>(I.getKey(), RefState::getInvalid(ME)); + } + + return state; +} + +// Handle assigning to an iterator where we don't have the LValue MemRegion. +const GRState *IteratorsChecker::handleAssign(const GRState *state, + const Expr *lexp, const Expr *rexp, const LocationContext *LC) const { + // Skip the cast if present. + if (isa<ImplicitCastExpr>(lexp)) + lexp = dyn_cast<ImplicitCastExpr>(lexp)->getSubExpr(); + SVal sv = state->getSVal(lexp); + const MemRegion *MR = sv.getAsRegion(); + if (!MR) + return state; + RefKind kind = getTemplateKind(lexp->getType()); + + // If assigning to a vector, invalidate any iterators currently associated. + if (kind == VectorKind) + return invalidateIterators(state, MR, 0); + + // Make sure that we are assigning to an iterator. + if (getTemplateKind(lexp->getType()) != VectorIteratorKind) + return state; + return handleAssign(state, MR, rexp, LC); +} + +// handle assigning to an iterator +const GRState *IteratorsChecker::handleAssign(const GRState *state, + const MemRegion *MR, const Expr *rexp, const LocationContext *LC) const { + // Assume unknown until we find something definite. + state = state->set<IteratorState>(MR, RefState::getUnknown()); + if (isa<ImplicitCastExpr>(rexp)) + rexp = dyn_cast<ImplicitCastExpr>(rexp)->getSubExpr(); + // Need to handle three cases: MemberCall, copy, copy with addition. + if (const CallExpr *CE = dyn_cast<CallExpr>(rexp)) { + // Handle MemberCall. + if (const MemberExpr *ME = dyn_cast<MemberExpr>(CE->getCallee())) { + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase()); + if (!DRE) + return state; + // Verify that the type is std::vector<T>. + if (getTemplateKind(DRE->getType()) != VectorKind) + return state; + // Now get the MemRegion associated with the instance. + const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); + if (!VD) + return state; + const MemRegion *IMR = state->getRegion(VD, LC); + if (!IMR) + return state; + // Finally, see if it is one of the calls that will create + // a valid iterator and mark it if so, else mark as Unknown. + llvm::StringRef mName = ME->getMemberDecl()->getName(); + + if (llvm::StringSwitch<bool>(mName) + .Cases("begin", "insert", "erase", true).Default(false)) { + return state->set<IteratorState>(MR, RefState::getBeginValid(IMR)); + } + if (mName == "end") + return state->set<IteratorState>(MR, RefState::getEndValid(IMR)); + + return state->set<IteratorState>(MR, RefState::getUnknown()); + } + } + // Handle straight copy from another iterator. + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(rexp)) { + if (getTemplateKind(DRE->getType()) != VectorIteratorKind) + return state; + // Now get the MemRegion associated with the instance. + const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); + if (!VD) + return state; + const MemRegion *IMR = state->getRegion(VD, LC); + if (!IMR) + return state; + // Get the RefState of the iterator being copied. + const RefState *RS = state->get<IteratorState>(IMR); + if (!RS) + return state; + // Use it to set the state of the LValue. + return state->set<IteratorState>(MR, *RS); + } + // If we have operator+ or operator- ... + if (const CXXOperatorCallExpr *OCE = dyn_cast<CXXOperatorCallExpr>(rexp)) { + OverloadedOperatorKind Kind = OCE->getOperator(); + if (Kind == OO_Plus || Kind == OO_Minus) { + // Check left side of tree for a valid value. + state = handleAssign( state, MR, OCE->getArg(0), LC); + const RefState *RS = state->get<IteratorState>(MR); + // If found, return it. + if (!RS->isUnknown()) + return state; + // Otherwise return what we find in the right side. + return handleAssign(state, MR, OCE->getArg(1), LC); + } + } + // Fall through if nothing matched. + return state; +} + +// Iterate through the arguments looking for an Invalid or Undefined iterator. +void IteratorsChecker::checkArgs(CheckerContext &C, const CallExpr *CE) const { + for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end(); + I != E; ++I) { + checkExpr(C, *I); + } +} + +// Get the DeclRefExpr associated with the expression. +const DeclRefExpr *IteratorsChecker::getDeclRefExpr(const Expr *E) const { + // If it is a CXXConstructExpr, need to get the subexpression. + if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E)) { + if (CE->getNumArgs()== 1) { + CXXConstructorDecl *CD = CE->getConstructor(); + if (CD->isTrivial()) + E = CE->getArg(0); + } + } + if (isa<ImplicitCastExpr>(E)) + E = dyn_cast<ImplicitCastExpr>(E)->getSubExpr(); + // If it isn't one of our types, don't do anything. + if (getTemplateKind(E->getType()) != VectorIteratorKind) + return NULL; + return dyn_cast<DeclRefExpr>(E); +} + +// Get the MemRegion associated with the expresssion. +const MemRegion *IteratorsChecker::getRegion(const GRState *state, + const Expr *E, const LocationContext *LC) const { + const DeclRefExpr *DRE = getDeclRefExpr(E); + if (!DRE) + return NULL; + const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()); + if (!VD) + return NULL; + // return the MemRegion associated with the iterator + return state->getRegion(VD, LC); +} + +// Check the expression and if it is an iterator, generate a diagnostic +// if the iterator is not valid. +// FIXME: this method can generate new nodes, and subsequent logic should +// use those nodes. We also cannot create multiple nodes at one ProgramPoint +// with the same tag. +void IteratorsChecker::checkExpr(CheckerContext &C, const Expr *E) const { + const GRState *state = C.getState(); + const MemRegion *MR = getRegion(state, E, + C.getPredecessor()->getLocationContext()); + if (!MR) + return; + + // Get the state associated with the iterator. + const RefState *RS = state->get<IteratorState>(MR); + if (!RS) + return; + if (RS->isInvalid()) { + if (ExplodedNode *N = C.generateNode()) { + if (!BT_Invalid) + // FIXME: We are eluding constness here. + const_cast<IteratorsChecker*>(this)->BT_Invalid = new BuiltinBug(""); + + std::string msg; + const MemberExpr *ME = RS->getMemberExpr(); + if (ME) { + std::string name = ME->getMemberNameInfo().getAsString(); + msg = "Attempt to use an iterator made invalid by call to '" + + name + "'"; + } + else { + msg = "Attempt to use an iterator made invalid by copying another " + "container to its container"; + } + + EnhancedBugReport *R = new EnhancedBugReport(*BT_Invalid, msg, N); + R->addRange(getDeclRefExpr(E)->getSourceRange()); + C.EmitReport(R); + } + } + else if (RS->isUndefined()) { + if (ExplodedNode *N = C.generateNode()) { + if (!BT_Undefined) + // FIXME: We are eluding constness here. + const_cast<IteratorsChecker*>(this)->BT_Undefined = + new BuiltinBug("Use of iterator that is not defined"); + + EnhancedBugReport *R = new EnhancedBugReport(*BT_Undefined, + BT_Undefined->getDescription(), N); + R->addRange(getDeclRefExpr(E)->getSourceRange()); + C.EmitReport(R); + } + } +} + +// =============================================== +// Path analysis visitor functions +// =============================================== + +// For a generic Call, just check the args for bad iterators. +void IteratorsChecker::checkPreStmt(const CallExpr *CE, + CheckerContext &C) const{ + + // FIXME: These checks are to currently work around a bug + // in CheckerManager. + if (isa<CXXOperatorCallExpr>(CE)) + return; + if (isa<CXXMemberCallExpr>(CE)) + return; + + checkArgs(C, CE); +} + +// Handle operator calls. First, if it is operator=, check the argument, +// and handle assigning and set target state appropriately. Otherwise, for +// other operators, check the args for bad iterators and handle comparisons. +void IteratorsChecker::checkPreStmt(const CXXOperatorCallExpr *OCE, + CheckerContext &C) const +{ + const LocationContext *LC = C.getPredecessor()->getLocationContext(); + const GRState *state = C.getState(); + OverloadedOperatorKind Kind = OCE->getOperator(); + if (Kind == OO_Equal) { + checkExpr(C, OCE->getArg(1)); + state = handleAssign(state, OCE->getArg(0), OCE->getArg(1), LC); + C.addTransition(state); + return; + } + else { + checkArgs(C, OCE); + // If it is a compare and both are iterators, ensure that they are for + // the same container. + if (Kind == OO_EqualEqual || Kind == OO_ExclaimEqual || + Kind == OO_Less || Kind == OO_LessEqual || + Kind == OO_Greater || Kind == OO_GreaterEqual) { + const MemRegion *MR0, *MR1; + MR0 = getRegion(state, OCE->getArg(0), LC); + if (!MR0) + return; + MR1 = getRegion(state, OCE->getArg(1), LC); + if (!MR1) + return; + const RefState *RS0, *RS1; + RS0 = state->get<IteratorState>(MR0); + if (!RS0) + return; + RS1 = state->get<IteratorState>(MR1); + if (!RS1) + return; + if (RS0->getMemRegion() != RS1->getMemRegion()) { + if (ExplodedNode *N = C.generateNode()) { + if (!BT_Incompatible) + const_cast<IteratorsChecker*>(this)->BT_Incompatible = + new BuiltinBug( + "Cannot compare iterators from different containers"); + + EnhancedBugReport *R = new EnhancedBugReport(*BT_Incompatible, + BT_Incompatible->getDescription(), N); + R->addRange(OCE->getSourceRange()); + C.EmitReport(R); + } + } + } + } +} + +// Need to handle DeclStmts to pick up initializing of iterators and to mark +// uninitialized ones as Undefined. +void IteratorsChecker::checkPreStmt(const DeclStmt *DS, + CheckerContext &C) const { + const Decl* D = *DS->decl_begin(); + const VarDecl* VD = dyn_cast<VarDecl>(D); + // Only care about iterators. + if (getTemplateKind(VD->getType()) != VectorIteratorKind) + return; + + // Get the MemRegion associated with the iterator and mark it as Undefined. + const GRState *state = C.getState(); + Loc VarLoc = state->getLValue(VD, C.getPredecessor()->getLocationContext()); + const MemRegion *MR = VarLoc.getAsRegion(); + if (!MR) + return; + state = state->set<IteratorState>(MR, RefState::getUndefined()); + + // if there is an initializer, handle marking Valid if a proper initializer + const Expr* InitEx = VD->getInit(); + if (InitEx) { + // FIXME: This is too syntactic. Since 'InitEx' will be analyzed first + // it should resolve to an SVal that we can check for validity + // *semantically* instead of walking through the AST. + if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(InitEx)) { + if (CE->getNumArgs() == 1) { + const Expr *E = CE->getArg(0); + if (isa<ImplicitCastExpr>(E)) + InitEx = dyn_cast<ImplicitCastExpr>(E)->getSubExpr(); + state = handleAssign(state, MR, InitEx, + C.getPredecessor()->getLocationContext()); + } + } + } + C.addTransition(state); +} + + +namespace { struct CalledReserved {}; } +namespace clang { namespace ento { +template<> struct GRStateTrait<CalledReserved> + : public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > { + static void *GDMIndex() { static int index = 0; return &index; } +}; +}} + +// on a member call, first check the args for any bad iterators +// then, check to see if it is a call to a function that will invalidate +// the iterators +void IteratorsChecker::checkPreStmt(const CXXMemberCallExpr *MCE, + CheckerContext &C) const { + // Check the arguments. + checkArgs(C, MCE); + const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()); + if (!ME) + return; + // Make sure we have the right kind of container. + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ME->getBase()); + if (!DRE || getTemplateKind(DRE->getType()) != VectorKind) + return; + SVal tsv = C.getState()->getSVal(DRE); + // Get the MemRegion associated with the container instance. + const MemRegion *MR = tsv.getAsRegion(); + if (!MR) + return; + // If we are calling a function that invalidates iterators, mark them + // appropriately by finding matching instances. + const GRState *state = C.getState(); + llvm::StringRef mName = ME->getMemberDecl()->getName(); + if (llvm::StringSwitch<bool>(mName) + .Cases("insert", "reserve", "push_back", true) + .Cases("erase", "pop_back", "clear", "resize", true) + .Default(false)) { + // If there was a 'reserve' call, assume iterators are good. + if (!state->contains<CalledReserved>(MR)) + state = invalidateIterators(state, MR, ME); + } + // Keep track of instances that have called 'reserve' + // note: do this after we invalidate any iterators by calling + // 'reserve' itself. + if (mName == "reserve") + state = state->add<CalledReserved>(MR); + + if (state != C.getState()) + C.addTransition(state); +} + diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp index 9e3adc8..3d1b5e2 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/LLVMConventionsChecker.cpp @@ -13,8 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" -#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/StmtVisitor.h" @@ -57,7 +56,7 @@ static bool IsStdString(QualType T) { if (!TT) return false; - const TypedefDecl *TD = TT->getDecl(); + const TypedefNameDecl *TD = TT->getDecl(); if (!InNamespace(TD, "std")) return false; @@ -289,7 +288,7 @@ void ASTFieldVisitor::ReportError(QualType T) { //===----------------------------------------------------------------------===// namespace { -class LLVMConventionsChecker : public CheckerV2< +class LLVMConventionsChecker : public Checker< check::ASTDecl<CXXRecordDecl>, check::ASTCodeBody > { public: diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp index d70c65a..12ce866 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp @@ -16,7 +16,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -30,7 +30,7 @@ using namespace clang; using namespace ento; namespace { -class MacOSXAPIChecker : public CheckerV2< check::PreStmt<CallExpr> > { +class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > { enum SubChecks { DispatchOnce = 0, DispatchOnceF, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 794740a..9100215 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -12,9 +12,11 @@ // //===----------------------------------------------------------------------===// -#include "ExperimentalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" #include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" @@ -62,55 +64,52 @@ public: class RegionState {}; -class MallocChecker : public CheckerVisitor<MallocChecker> { - BuiltinBug *BT_DoubleFree; - BuiltinBug *BT_Leak; - BuiltinBug *BT_UseFree; - BuiltinBug *BT_UseRelinquished; - BuiltinBug *BT_BadFree; - IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc; +class MallocChecker : public Checker<eval::Call, check::DeadSymbols, check::EndPath, check::PreStmt<ReturnStmt>, check::Location, + check::Bind, eval::Assume> { + mutable llvm::OwningPtr<BuiltinBug> BT_DoubleFree; + mutable llvm::OwningPtr<BuiltinBug> BT_Leak; + mutable llvm::OwningPtr<BuiltinBug> BT_UseFree; + mutable llvm::OwningPtr<BuiltinBug> BT_UseRelinquished; + mutable llvm::OwningPtr<BuiltinBug> BT_BadFree; + mutable IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc; public: - MallocChecker() - : BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0), BT_UseRelinquished(0), - BT_BadFree(0), - II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {} - static void *getTag(); - bool evalCallExpr(CheckerContext &C, const CallExpr *CE); - void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper); - void evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExprEngine &Eng); - void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S); - const GRState *evalAssume(const GRState *state, SVal Cond, bool Assumption, - bool *respondsToCallback); - void visitLocation(CheckerContext &C, const Stmt *S, SVal l, bool isLoad); - virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE, - SVal location, SVal val); + MallocChecker() : II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {} + + bool evalCall(const CallExpr *CE, CheckerContext &C) const; + void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; + void checkEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng) const; + void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const; + const GRState *evalAssume(const GRState *state, SVal Cond, + bool Assumption) const; + void checkLocation(SVal l, bool isLoad, CheckerContext &C) const; + void checkBind(SVal location, SVal val, CheckerContext &C) const; private: - void MallocMem(CheckerContext &C, const CallExpr *CE); - void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, - const OwnershipAttr* Att); - const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, - const Expr *SizeEx, SVal Init, - const GRState *state) { + static void MallocMem(CheckerContext &C, const CallExpr *CE); + static void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, + const OwnershipAttr* Att); + static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, + const Expr *SizeEx, SVal Init, + const GRState *state) { return MallocMemAux(C, CE, state->getSVal(SizeEx), Init, state); } - const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, - SVal SizeEx, SVal Init, - const GRState *state); + static const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE, + SVal SizeEx, SVal Init, + const GRState *state); - void FreeMem(CheckerContext &C, const CallExpr *CE); + void FreeMem(CheckerContext &C, const CallExpr *CE) const; void FreeMemAttr(CheckerContext &C, const CallExpr *CE, - const OwnershipAttr* Att); + const OwnershipAttr* Att) const; const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE, - const GRState *state, unsigned Num, bool Hold); + const GRState *state, unsigned Num, bool Hold) const; - void ReallocMem(CheckerContext &C, const CallExpr *CE); - void CallocMem(CheckerContext &C, const CallExpr *CE); + void ReallocMem(CheckerContext &C, const CallExpr *CE) const; + static void CallocMem(CheckerContext &C, const CallExpr *CE); - bool SummarizeValue(llvm::raw_ostream& os, SVal V); - bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR); - void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range); + static bool SummarizeValue(llvm::raw_ostream& os, SVal V); + static bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR); + void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range) const; }; } // end anonymous namespace @@ -121,21 +120,12 @@ namespace ento { template <> struct GRStateTrait<RegionState> : public GRStatePartialTrait<RegionStateTy> { - static void *GDMIndex() { return MallocChecker::getTag(); } + static void *GDMIndex() { static int x; return &x; } }; } } -void ento::RegisterMallocChecker(ExprEngine &Eng) { - Eng.registerCheck(new MallocChecker()); -} - -void *MallocChecker::getTag() { - static int x; - return &x; -} - -bool MallocChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) { +bool MallocChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { const GRState *state = C.getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); @@ -256,7 +246,7 @@ const GRState *MallocChecker::MallocMemAux(CheckerContext &C, return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE)); } -void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { +void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) const { const GRState *state = FreeMemAux(C, CE, C.getState(), 0, false); if (state) @@ -264,7 +254,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) { } void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE, - const OwnershipAttr* Att) { + const OwnershipAttr* Att) const { if (Att->getModule() != "malloc") return; @@ -279,7 +269,7 @@ void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE, const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, const GRState *state, unsigned Num, - bool Hold) { + bool Hold) const { const Expr *ArgExpr = CE->getArg(Num); SVal ArgVal = state->getSVal(ArgExpr); @@ -357,9 +347,9 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, if (RS->isReleased()) { if (ExplodedNode *N = C.generateSink()) { if (!BT_DoubleFree) - BT_DoubleFree - = new BuiltinBug("Double free", - "Try to free a memory block that has been released"); + BT_DoubleFree.reset( + new BuiltinBug("Double free", + "Try to free a memory block that has been released")); // FIXME: should find where it's freed last time. BugReport *R = new BugReport(*BT_DoubleFree, BT_DoubleFree->getDescription(), N); @@ -463,10 +453,10 @@ bool MallocChecker::SummarizeRegion(llvm::raw_ostream& os, } void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, - SourceRange range) { + SourceRange range) const { if (ExplodedNode *N = C.generateSink()) { if (!BT_BadFree) - BT_BadFree = new BuiltinBug("Bad free"); + BT_BadFree.reset(new BuiltinBug("Bad free")); llvm::SmallString<100> buf; llvm::raw_svector_ostream os(buf); @@ -500,7 +490,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, } } -void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) { +void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) const { const GRState *state = C.getState(); const Expr *arg0Expr = CE->getArg(0); DefinedOrUnknownSVal arg0Val @@ -511,8 +501,24 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) { DefinedOrUnknownSVal PtrEQ = svalBuilder.evalEQ(state, arg0Val, svalBuilder.makeNull()); - // If the ptr is NULL, the call is equivalent to malloc(size). - if (const GRState *stateEqual = state->assume(PtrEQ, true)) { + // Get the size argument. If there is no size arg then give up. + const Expr *Arg1 = CE->getArg(1); + if (!Arg1) + return; + + // Get the value of the size argument. + DefinedOrUnknownSVal Arg1Val = + cast<DefinedOrUnknownSVal>(state->getSVal(Arg1)); + + // Compare the size argument to 0. + DefinedOrUnknownSVal SizeZero = + svalBuilder.evalEQ(state, Arg1Val, + svalBuilder.makeIntValWithPtrWidth(0, false)); + + // If the ptr is NULL and the size is not 0, the call is equivalent to + // malloc(size). + const GRState *stateEqual = state->assume(PtrEQ, true); + if (stateEqual && state->assume(SizeZero, false)) { // Hack: set the NULL symbolic region to released to suppress false warning. // In the future we should add more states for allocated regions, e.g., // CheckedNull, CheckedNonNull. @@ -527,17 +533,17 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) { } if (const GRState *stateNotEqual = state->assume(PtrEQ, false)) { - const Expr *Arg1 = CE->getArg(1); - DefinedOrUnknownSVal Arg1Val = - cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1)); - DefinedOrUnknownSVal SizeZero = - svalBuilder.evalEQ(stateNotEqual, Arg1Val, - svalBuilder.makeIntValWithPtrWidth(0, false)); - + // If the size is 0, free the memory. if (const GRState *stateSizeZero = stateNotEqual->assume(SizeZero, true)) - if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero, 0, false)) - C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true)); + if (const GRState *stateFree = + FreeMemAux(C, CE, stateSizeZero, 0, false)) { + + // Add the state transition to set input pointer argument to be free. + C.addTransition(stateFree); + // Bind the return value to UndefinedVal because it is now free. + C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true)); + } if (const GRState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false)) if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero, 0, false)) { @@ -562,7 +568,8 @@ void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) { C.addTransition(MallocMemAux(C, CE, TotalSize, zeroVal, state)); } -void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) +void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, + CheckerContext &C) const { if (!SymReaper.hasDeadSymbols()) return; @@ -576,8 +583,8 @@ void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) if (I->second.isAllocated()) { if (ExplodedNode *N = C.generateNode()) { if (!BT_Leak) - BT_Leak = new BuiltinBug("Memory leak", - "Allocated memory never released. Potential memory leak."); + BT_Leak.reset(new BuiltinBug("Memory leak", + "Allocated memory never released. Potential memory leak.")); // FIXME: where it is allocated. BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); C.EmitReport(R); @@ -591,8 +598,8 @@ void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) C.generateNode(state->set<RegionState>(RS)); } -void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, - ExprEngine &Eng) { +void MallocChecker::checkEndPath(EndOfFunctionNodeBuilder &B, + ExprEngine &Eng) const { const GRState *state = B.getState(); RegionStateTy M = state->get<RegionState>(); @@ -602,8 +609,8 @@ void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, ExplodedNode *N = B.generateNode(state); if (N) { if (!BT_Leak) - BT_Leak = new BuiltinBug("Memory leak", - "Allocated memory never released. Potential memory leak."); + BT_Leak.reset(new BuiltinBug("Memory leak", + "Allocated memory never released. Potential memory leak.")); BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N); Eng.getBugReporter().EmitReport(R); } @@ -611,7 +618,7 @@ void MallocChecker::evalEndPath(EndOfFunctionNodeBuilder &B, void *tag, } } -void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) { +void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { const Expr *retExpr = S->getRetValue(); if (!retExpr) return; @@ -634,14 +641,14 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) { } const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond, - bool Assumption, - bool * /* respondsToCallback */) { + bool Assumption) const { // If a symblic region is assumed to NULL, set its state to AllocateFailed. // FIXME: should also check symbols assumed to non-null. RegionStateTy RS = state->get<RegionState>(); for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { + // If the symbol is assumed to NULL, this will return an APSInt*. if (state->getSymVal(I.getKey())) state = state->set<RegionState>(I.getKey(),RefState::getAllocateFailed()); } @@ -650,16 +657,15 @@ const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond, } // Check if the location is a freed symbolic region. -void MallocChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l, - bool isLoad) { +void MallocChecker::checkLocation(SVal l, bool isLoad,CheckerContext &C) const { SymbolRef Sym = l.getLocSymbolInBase(); if (Sym) { const RefState *RS = C.getState()->get<RegionState>(Sym); if (RS && RS->isReleased()) { if (ExplodedNode *N = C.generateNode()) { if (!BT_UseFree) - BT_UseFree = new BuiltinBug("Use dynamically allocated memory after" - " it is freed."); + BT_UseFree.reset(new BuiltinBug("Use dynamically allocated memory " + "after it is freed.")); BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(), N); @@ -669,10 +675,7 @@ void MallocChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l, } } -void MallocChecker::PreVisitBind(CheckerContext &C, - const Stmt *StoreE, - SVal location, - SVal val) { +void MallocChecker::checkBind(SVal location, SVal val,CheckerContext &C) const { // The PreVisitBind implements the same algorithm as already used by the // Objective C ownership checker: if the pointer escaped from this scope by // assignment, let it go. However, assigning to fields of a stack-storage @@ -721,7 +724,7 @@ void MallocChecker::PreVisitBind(CheckerContext &C, // We no longer own this pointer. notNullState = notNullState->set<RegionState>(Sym, - RefState::getRelinquished(StoreE)); + RefState::getRelinquished(C.getStmt())); } while (false); } @@ -729,3 +732,7 @@ void MallocChecker::PreVisitBind(CheckerContext &C, } } } + +void ento::registerMallocChecker(CheckerManager &mgr) { + mgr.registerChecker<MallocChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp index fed6a99..f11db64 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp @@ -16,7 +16,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" @@ -29,7 +29,7 @@ using namespace ento; namespace { class NSAutoreleasePoolChecker - : public CheckerV2<check::PreObjCMessage> { + : public Checker<check::PreObjCMessage> { mutable Selector releaseS; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 7a1b978..63a5917 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -1,4 +1,4 @@ -//=- NSErrorCheckerer.cpp - Coding conventions for uses of NSError -*- C++ -*-==// +//=- NSErrorChecker.cpp - Coding conventions for uses of NSError -*- C++ -*-==// // // The LLVM Compiler Infrastructure // @@ -15,11 +15,12 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h" -#include "BasicObjCFoundationChecks.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Decl.h" #include "llvm/ADT/SmallVector.h" @@ -27,142 +28,263 @@ using namespace clang; using namespace ento; -namespace { -class NSErrorChecker : public BugType { - const Decl &CodeDecl; - const bool isNSErrorWarning; - IdentifierInfo * const II; - ExprEngine &Eng; +static bool IsNSError(QualType T, IdentifierInfo *II); +static bool IsCFError(QualType T, IdentifierInfo *II); - void CheckSignature(const ObjCMethodDecl& MD, QualType& ResultTy, - llvm::SmallVectorImpl<VarDecl*>& ErrorParams); +//===----------------------------------------------------------------------===// +// NSErrorMethodChecker +//===----------------------------------------------------------------------===// - void CheckSignature(const FunctionDecl& MD, QualType& ResultTy, - llvm::SmallVectorImpl<VarDecl*>& ErrorParams); +namespace { +class NSErrorMethodChecker + : public Checker< check::ASTDecl<ObjCMethodDecl> > { + mutable IdentifierInfo *II; - bool CheckNSErrorArgument(QualType ArgTy); - bool CheckCFErrorArgument(QualType ArgTy); +public: + NSErrorMethodChecker() : II(0) { } - void CheckParamDeref(const VarDecl *V, const LocationContext *LC, - const GRState *state, BugReporter& BR); + void checkASTDecl(const ObjCMethodDecl *D, + AnalysisManager &mgr, BugReporter &BR) const; +}; +} - void EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl); +void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D, + AnalysisManager &mgr, + BugReporter &BR) const { + if (!D->isThisDeclarationADefinition()) + return; + if (!D->getResultType()->isVoidType()) + return; -public: - NSErrorChecker(const Decl &D, bool isNSError, ExprEngine& eng) - : BugType(isNSError ? "NSError** null dereference" - : "CFErrorRef* null dereference", - "Coding conventions (Apple)"), - CodeDecl(D), - isNSErrorWarning(isNSError), - II(&eng.getContext().Idents.get(isNSErrorWarning ? "NSError":"CFErrorRef")), - Eng(eng) {} - - void FlushReports(BugReporter& BR); -}; + if (!II) + II = &D->getASTContext().Idents.get("NSError"); -} // end anonymous namespace + bool hasNSError = false; + for (ObjCMethodDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) { + if (IsNSError((*I)->getType(), II)) { + hasNSError = true; + break; + } + } -void ento::RegisterNSErrorChecks(BugReporter& BR, ExprEngine &Eng, - const Decl &D) { - BR.Register(new NSErrorChecker(D, true, Eng)); - BR.Register(new NSErrorChecker(D, false, Eng)); + if (hasNSError) { + const char *err = "Method accepting NSError** " + "should have a non-void return value to indicate whether or not an " + "error occurred"; + BR.EmitBasicReport("Bad return type when passing NSError**", + "Coding conventions (Apple)", err, D->getLocation()); + } } -void NSErrorChecker::FlushReports(BugReporter& BR) { - // Get the analysis engine and the exploded analysis graph. - ExplodedGraph& G = Eng.getGraph(); +//===----------------------------------------------------------------------===// +// CFErrorFunctionChecker +//===----------------------------------------------------------------------===// - // Get the ASTContext, which is useful for querying type information. - ASTContext &Ctx = BR.getContext(); +namespace { +class CFErrorFunctionChecker + : public Checker< check::ASTDecl<FunctionDecl> > { + mutable IdentifierInfo *II; - QualType ResultTy; - llvm::SmallVector<VarDecl*, 5> ErrorParams; +public: + CFErrorFunctionChecker() : II(0) { } - if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CodeDecl)) - CheckSignature(*MD, ResultTy, ErrorParams); - else if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(&CodeDecl)) - CheckSignature(*FD, ResultTy, ErrorParams); - else - return; + void checkASTDecl(const FunctionDecl *D, + AnalysisManager &mgr, BugReporter &BR) const; +}; +} - if (ErrorParams.empty()) +void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, + AnalysisManager &mgr, + BugReporter &BR) const { + if (!D->isThisDeclarationADefinition()) return; + if (!D->getResultType()->isVoidType()) + return; + + if (!II) + II = &D->getASTContext().Idents.get("CFErrorRef"); - if (ResultTy == Ctx.VoidTy) EmitRetTyWarning(BR, CodeDecl); + bool hasCFError = false; + for (FunctionDecl::param_const_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) { + if (IsCFError((*I)->getType(), II)) { + hasCFError = true; + break; + } + } - for (ExplodedGraph::roots_iterator RI=G.roots_begin(), RE=G.roots_end(); - RI!=RE; ++RI) { - // Scan the parameters for an implicit null dereference. - for (llvm::SmallVectorImpl<VarDecl*>::iterator I=ErrorParams.begin(), - E=ErrorParams.end(); I!=E; ++I) - CheckParamDeref(*I, (*RI)->getLocationContext(), (*RI)->getState(), BR); + if (hasCFError) { + const char *err = "Function accepting CFErrorRef* " + "should have a non-void return value to indicate whether or not an " + "error occurred"; + BR.EmitBasicReport("Bad return type when passing CFErrorRef*", + "Coding conventions (Apple)", err, D->getLocation()); } } -void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) { - std::string sbuf; - llvm::raw_string_ostream os(sbuf); +//===----------------------------------------------------------------------===// +// NSOrCFErrorDerefChecker +//===----------------------------------------------------------------------===// - if (isa<ObjCMethodDecl>(CodeDecl)) - os << "Method"; - else - os << "Function"; +namespace { - os << " accepting "; - os << (isNSErrorWarning ? "NSError**" : "CFErrorRef*"); - os << " should have a non-void return value to indicate whether or not an " - "error occurred"; +class NSErrorDerefBug : public BugType { +public: + NSErrorDerefBug() : BugType("NSError** null dereference", + "Coding conventions (Apple)") {} +}; + +class CFErrorDerefBug : public BugType { +public: + CFErrorDerefBug() : BugType("CFErrorRef* null dereference", + "Coding conventions (Apple)") {} +}; - BR.EmitBasicReport(isNSErrorWarning - ? "Bad return type when passing NSError**" - : "Bad return type when passing CFError*", - getCategory(), os.str(), - CodeDecl.getLocation()); } -void -NSErrorChecker::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy, - llvm::SmallVectorImpl<VarDecl*>& ErrorParams) { +namespace { +class NSOrCFErrorDerefChecker + : public Checker< check::Location, + check::Event<ImplicitNullDerefEvent> > { + mutable IdentifierInfo *NSErrorII, *CFErrorII; +public: + bool ShouldCheckNSError, ShouldCheckCFError; + NSOrCFErrorDerefChecker() : NSErrorII(0), CFErrorII(0), + ShouldCheckNSError(0), ShouldCheckCFError(0) { } + + void checkLocation(SVal loc, bool isLoad, CheckerContext &C) const; + void checkEvent(ImplicitNullDerefEvent event) const; +}; +} - ResultTy = M.getResultType(); +namespace { struct NSErrorOut {}; } +namespace { struct CFErrorOut {}; } + +typedef llvm::ImmutableMap<SymbolRef, unsigned> ErrorOutFlag; + +namespace clang { +namespace ento { + template <> + struct GRStateTrait<NSErrorOut> : public GRStatePartialTrait<ErrorOutFlag> { + static void *GDMIndex() { static int index = 0; return &index; } + }; + template <> + struct GRStateTrait<CFErrorOut> : public GRStatePartialTrait<ErrorOutFlag> { + static void *GDMIndex() { static int index = 0; return &index; } + }; +} +} - for (ObjCMethodDecl::param_iterator I=M.param_begin(), - E=M.param_end(); I!=E; ++I) { +template <typename T> +static bool hasFlag(SVal val, const GRState *state) { + if (SymbolRef sym = val.getAsSymbol()) + if (const unsigned *attachedFlags = state->get<T>(sym)) + return *attachedFlags; + return false; +} - QualType T = (*I)->getType(); +template <typename T> +static void setFlag(const GRState *state, SVal val, CheckerContext &C) { + // We tag the symbol that the SVal wraps. + if (SymbolRef sym = val.getAsSymbol()) + C.addTransition(state->set<T>(sym, true)); +} - if (isNSErrorWarning) { - if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I); - } - else if (CheckCFErrorArgument(T)) - ErrorParams.push_back(*I); +static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) { + const StackFrameContext * + SFC = C.getPredecessor()->getLocationContext()->getCurrentStackFrame(); + if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(&val)) { + const MemRegion* R = X->getRegion(); + if (const VarRegion *VR = R->getAs<VarRegion>()) + if (const StackArgumentsSpaceRegion * + stackReg = dyn_cast<StackArgumentsSpaceRegion>(VR->getMemorySpace())) + if (stackReg->getStackFrame() == SFC) + return VR->getValueType(); } + + return QualType(); } -void -NSErrorChecker::CheckSignature(const FunctionDecl& F, QualType& ResultTy, - llvm::SmallVectorImpl<VarDecl*>& ErrorParams) { +void NSOrCFErrorDerefChecker::checkLocation(SVal loc, bool isLoad, + CheckerContext &C) const { + if (!isLoad) + return; + if (loc.isUndef() || !isa<Loc>(loc)) + return; - ResultTy = F.getResultType(); + ASTContext &Ctx = C.getASTContext(); + const GRState *state = C.getState(); - for (FunctionDecl::param_const_iterator I = F.param_begin(), - E = F.param_end(); I != E; ++I) { + // If we are loading from NSError**/CFErrorRef* parameter, mark the resulting + // SVal so that we can later check it when handling the + // ImplicitNullDerefEvent event. + // FIXME: Cumbersome! Maybe add hook at construction of SVals at start of + // function ? - QualType T = (*I)->getType(); + QualType parmT = parameterTypeFromSVal(loc, C); + if (parmT.isNull()) + return; - if (isNSErrorWarning) { - if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I); - } - else if (CheckCFErrorArgument(T)) - ErrorParams.push_back(*I); + if (!NSErrorII) + NSErrorII = &Ctx.Idents.get("NSError"); + if (!CFErrorII) + CFErrorII = &Ctx.Idents.get("CFErrorRef"); + + if (ShouldCheckNSError && IsNSError(parmT, NSErrorII)) { + setFlag<NSErrorOut>(state, state->getSVal(cast<Loc>(loc)), C); + return; + } + + if (ShouldCheckCFError && IsCFError(parmT, CFErrorII)) { + setFlag<CFErrorOut>(state, state->getSVal(cast<Loc>(loc)), C); + return; } } +void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const { + if (event.IsLoad) + return; + + SVal loc = event.Location; + const GRState *state = event.SinkNode->getState(); + BugReporter &BR = *event.BR; + + bool isNSError = hasFlag<NSErrorOut>(loc, state); + bool isCFError = false; + if (!isNSError) + isCFError = hasFlag<CFErrorOut>(loc, state); + + if (!(isNSError || isCFError)) + return; -bool NSErrorChecker::CheckNSErrorArgument(QualType ArgTy) { + // Storing to possible null NSError/CFErrorRef out parameter. - const PointerType* PPT = ArgTy->getAs<PointerType>(); + // Emit an error. + std::string err; + llvm::raw_string_ostream os(err); + os << "Potential null dereference. According to coding standards "; + + if (isNSError) + os << "in 'Creating and Returning NSError Objects' the parameter '"; + else + os << "documented in CoreFoundation/CFError.h the parameter '"; + + os << "' may be null."; + + BugType *bug = 0; + if (isNSError) + bug = new NSErrorDerefBug(); + else + bug = new CFErrorDerefBug(); + EnhancedBugReport *report = new EnhancedBugReport(*bug, os.str(), + event.SinkNode); + BR.EmitReport(report); +} + +static bool IsNSError(QualType T, IdentifierInfo *II) { + + const PointerType* PPT = T->getAs<PointerType>(); if (!PPT) return false; @@ -181,9 +303,8 @@ bool NSErrorChecker::CheckNSErrorArgument(QualType ArgTy) { return false; } -bool NSErrorChecker::CheckCFErrorArgument(QualType ArgTy) { - - const PointerType* PPT = ArgTy->getAs<PointerType>(); +static bool IsCFError(QualType T, IdentifierInfo *II) { + const PointerType* PPT = T->getAs<PointerType>(); if (!PPT) return false; const TypedefType* TT = PPT->getPointeeType()->getAs<TypedefType>(); @@ -192,47 +313,16 @@ bool NSErrorChecker::CheckCFErrorArgument(QualType ArgTy) { return TT->getDecl()->getIdentifier() == II; } -void NSErrorChecker::CheckParamDeref(const VarDecl *Param, - const LocationContext *LC, - const GRState *rootState, - BugReporter& BR) { - - SVal ParamL = rootState->getLValue(Param, LC); - const MemRegion* ParamR = cast<loc::MemRegionVal>(ParamL).getRegionAs<VarRegion>(); - assert (ParamR && "Parameters always have VarRegions."); - SVal ParamSVal = rootState->getSVal(ParamR); - - // FIXME: For now assume that ParamSVal is symbolic. We need to generalize - // this later. - SymbolRef ParamSym = ParamSVal.getAsLocSymbol(); - if (!ParamSym) - return; +void ento::registerNSErrorChecker(CheckerManager &mgr) { + mgr.registerChecker<NSErrorMethodChecker>(); + NSOrCFErrorDerefChecker * + checker = mgr.registerChecker<NSOrCFErrorDerefChecker>(); + checker->ShouldCheckNSError = true; +} - // Iterate over the implicit-null dereferences. - ExplodedNode *const* I, *const* E; - llvm::tie(I, E) = GetImplicitNullDereferences(Eng); - for ( ; I != E; ++I) { - const GRState *state = (*I)->getState(); - SVal location = state->getSVal((*I)->getLocationAs<StmtPoint>()->getStmt()); - if (location.getAsSymbol() != ParamSym) - continue; - - // Emit an error. - std::string sbuf; - llvm::raw_string_ostream os(sbuf); - os << "Potential null dereference. According to coding standards "; - - if (isNSErrorWarning) - os << "in 'Creating and Returning NSError Objects' the parameter '"; - else - os << "documented in CoreFoundation/CFError.h the parameter '"; - - os << Param << "' may be null."; - - BugReport *report = new BugReport(*this, os.str(), *I); - // FIXME: Notable symbols are now part of the report. We should - // add support for notable symbols in BugReport. - // BR.addNotableSymbol(SV->getSymbol()); - BR.EmitReport(report); - } +void ento::registerCFErrorChecker(CheckerManager &mgr) { + mgr.registerChecker<CFErrorFunctionChecker>(); + NSOrCFErrorDerefChecker * + checker = mgr.registerChecker<NSOrCFErrorDerefChecker>(); + checker->ShouldCheckCFError = true; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp index 40040ea..2d0af9c 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp @@ -12,8 +12,10 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; @@ -21,20 +23,15 @@ using namespace ento; namespace { -class NoReturnFunctionChecker : public CheckerVisitor<NoReturnFunctionChecker> { +class NoReturnFunctionChecker : public Checker< check::PostStmt<CallExpr> > { public: - static void *getTag() { static int tag = 0; return &tag; } - void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE); + void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; }; } -void ento::RegisterNoReturnFunctionChecker(ExprEngine &Eng) { - Eng.registerCheck(new NoReturnFunctionChecker()); -} - -void NoReturnFunctionChecker::PostVisitCallExpr(CheckerContext &C, - const CallExpr *CE) { +void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE, + CheckerContext &C) const { const GRState *state = C.getState(); const Expr *Callee = CE->getCallee(); @@ -78,3 +75,7 @@ void NoReturnFunctionChecker::PostVisitCallExpr(CheckerContext &C, if (BuildSinks) C.generateSink(CE); } + +void ento::registerNoReturnFunctionChecker(CheckerManager &mgr) { + mgr.registerChecker<NoReturnFunctionChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp index e1126b6..7262bc3 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp @@ -11,8 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/Basic/Builtins.h" using namespace clang; @@ -20,22 +22,17 @@ using namespace ento; namespace { -class OSAtomicChecker : public Checker { +class OSAtomicChecker : public Checker<eval::Call> { public: - static void *getTag() { static int tag = 0; return &tag; } - virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE); + bool evalCall(const CallExpr *CE, CheckerContext &C) const; private: - bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE); + static bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE); }; } -void ento::RegisterOSAtomicChecker(ExprEngine &Eng) { - Eng.registerCheck(new OSAtomicChecker()); -} - -bool OSAtomicChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE) { +bool OSAtomicChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { const GRState *state = C.getState(); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); @@ -130,7 +127,12 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, ExplodedNode *N = *I; const GRState *stateLoad = N->getState(); - SVal theValueVal_untested = stateLoad->getSVal(theValueExpr); + + // Use direct bindings from the environment since we are forcing a load + // from a location that the Environment would typically not be used + // to bind a value. + SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, true); + SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr); // FIXME: Issue an error. @@ -201,3 +203,7 @@ bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C, return true; } + +void ento::registerOSAtomicChecker(CheckerManager &mgr) { + mgr.registerChecker<OSAtomicChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp index 7746719..a118049 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -25,7 +25,7 @@ using namespace ento; namespace { class ObjCAtSyncChecker - : public CheckerV2< check::PreStmt<ObjCAtSynchronizedStmt> > { + : public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > { mutable llvm::OwningPtr<BuiltinBug> BT_null; mutable llvm::OwningPtr<BuiltinBug> BT_undef; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp index 5f32bb8..4c05867 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp @@ -16,7 +16,7 @@ // result of an initialization call (e.g. [super init], or [self initWith..]) // before using 'self' or any instance variable. // -// To perform the required checking, values are tagged wih flags that indicate +// To perform the required checking, values are tagged with flags that indicate // 1) if the object is the one pointed to by 'self', and 2) if the object // is the result of an initializer (e.g. [super init]). // @@ -47,12 +47,11 @@ // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocAllocInit.html #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/AST/ParentMap.h" using namespace clang; @@ -64,7 +63,7 @@ static bool isInitMessage(const ObjCMessage &msg); static bool isSelfVar(SVal location, CheckerContext &C); namespace { -class ObjCSelfInitChecker : public CheckerV2< +class ObjCSelfInitChecker : public Checker< check::PostObjCMessage, check::PostStmt<ObjCIvarRefExpr>, check::PreStmt<ReturnStmt>, @@ -347,15 +346,11 @@ static bool isSelfVar(SVal location, CheckerContext &C) { } static bool isInitializationMethod(const ObjCMethodDecl *MD) { - // Init methods with prefix like '-(id)_init' are private and the requirements - // are less strict so we don't check those. - return MD->isInstanceMethod() && - cocoa::deriveNamingConvention(MD->getSelector(), - /*ignorePrefix=*/false) == cocoa::InitRule; + return MD->getMethodFamily() == OMF_init; } static bool isInitMessage(const ObjCMessage &msg) { - return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule; + return msg.getMethodFamily() == OMF_init; } //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp index 6e92498..d78e5ce 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ObjCUnusedIVarsChecker.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/AST/ExprObjC.h" @@ -169,7 +169,7 @@ static void checkObjCUnusedIvar(const ObjCImplementationDecl *D, //===----------------------------------------------------------------------===// namespace { -class ObjCUnusedIvarsChecker : public CheckerV2< +class ObjCUnusedIvarsChecker : public Checker< check::ASTDecl<ObjCImplementationDecl> > { public: void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& mgr, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp index 034a2aa..7c21acc 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -23,7 +23,7 @@ using namespace ento; namespace { class PointerArithChecker - : public CheckerV2< check::PreStmt<BinaryOperator> > { + : public Checker< check::PreStmt<BinaryOperator> > { mutable llvm::OwningPtr<BuiltinBug> BT; public: diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp index bf85b95..16ede20 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -24,7 +24,7 @@ using namespace ento; namespace { class PointerSubChecker - : public CheckerV2< check::PreStmt<BinaryOperator> > { + : public Checker< check::PreStmt<BinaryOperator> > { mutable llvm::OwningPtr<BuiltinBug> BT; public: diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp index 6c6901f..74199bb 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" @@ -25,7 +25,7 @@ using namespace ento; namespace { class PthreadLockChecker - : public CheckerV2< check::PostStmt<CallExpr> > { + : public Checker< check::PostStmt<CallExpr> > { public: void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp index 2985156..1729b25 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -24,7 +24,7 @@ using namespace ento; namespace { class ReturnPointerRangeChecker : - public CheckerV2< check::PreStmt<ReturnStmt> > { + public Checker< check::PreStmt<ReturnStmt> > { mutable llvm::OwningPtr<BuiltinBug> BT; public: void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index 555eaf4..7c215b7 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -13,35 +13,26 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" using namespace clang; using namespace ento; namespace { class ReturnUndefChecker : - public CheckerVisitor<ReturnUndefChecker> { - BuiltinBug *BT; + public Checker< check::PreStmt<ReturnStmt> > { + mutable llvm::OwningPtr<BuiltinBug> BT; public: - ReturnUndefChecker() : BT(0) {} - static void *getTag(); - void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS); + void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const; }; } -void ento::RegisterReturnUndefChecker(ExprEngine &Eng) { - Eng.registerCheck(new ReturnUndefChecker()); -} - -void *ReturnUndefChecker::getTag() { - static int x = 0; return &x; -} - -void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C, - const ReturnStmt *RS) { +void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, + CheckerContext &C) const { const Expr *RetE = RS->getRetValue(); if (!RetE) @@ -56,8 +47,8 @@ void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C, return; if (!BT) - BT = new BuiltinBug("Garbage return value", - "Undefined or garbage value returned to caller"); + BT.reset(new BuiltinBug("Garbage return value", + "Undefined or garbage value returned to caller")); EnhancedBugReport *report = new EnhancedBugReport(*BT, BT->getDescription(), N); @@ -67,3 +58,7 @@ void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C, C.EmitReport(report); } + +void ento::registerReturnUndefChecker(CheckerManager &mgr) { + mgr.registerChecker<ReturnUndefChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index 6a9a37d..07de870 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -24,7 +24,7 @@ using namespace clang; using namespace ento; namespace { -class StackAddrEscapeChecker : public CheckerV2< check::PreStmt<ReturnStmt>, +class StackAddrEscapeChecker : public Checker< check::PreStmt<ReturnStmt>, check::EndPath > { mutable llvm::OwningPtr<BuiltinBug> BT_stackleak; mutable llvm::OwningPtr<BuiltinBug> BT_returnstack; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index d0626b8..711c672 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -56,7 +56,7 @@ struct StreamState { } }; -class StreamChecker : public CheckerV2<eval::Call, +class StreamChecker : public Checker<eval::Call, check::DeadSymbols, check::EndPath, check::PreStmt<ReturnStmt> > { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp index 14ae9ed..1fb1815 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp @@ -12,17 +12,19 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h" using namespace clang; using namespace ento; namespace { -class UndefBranchChecker : public Checker { - BuiltinBug *BT; +class UndefBranchChecker : public Checker<check::BranchCondition> { + mutable llvm::OwningPtr<BuiltinBug> BT; struct FindUndefExpr { GRStateManager& VM; @@ -48,26 +50,15 @@ class UndefBranchChecker : public Checker { }; public: - UndefBranchChecker() : BT(0) {} - static void *getTag(); - void VisitBranchCondition(BranchNodeBuilder &Builder, ExprEngine &Eng, - const Stmt *Condition, void *tag); + void checkBranchCondition(const Stmt *Condition, BranchNodeBuilder &Builder, + ExprEngine &Eng) const; }; } -void ento::RegisterUndefBranchChecker(ExprEngine &Eng) { - Eng.registerCheck(new UndefBranchChecker()); -} - -void *UndefBranchChecker::getTag() { - static int x; - return &x; -} - -void UndefBranchChecker::VisitBranchCondition(BranchNodeBuilder &Builder, - ExprEngine &Eng, - const Stmt *Condition, void *tag){ +void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, + BranchNodeBuilder &Builder, + ExprEngine &Eng) const { const GRState *state = Builder.getState(); SVal X = state->getSVal(Condition); if (X.isUndef()) { @@ -75,7 +66,8 @@ void UndefBranchChecker::VisitBranchCondition(BranchNodeBuilder &Builder, if (N) { N->markAsSink(); if (!BT) - BT = new BuiltinBug("Branch condition evaluates to a garbage value"); + BT.reset( + new BuiltinBug("Branch condition evaluates to a garbage value")); // What's going on here: we want to highlight the subexpression of the // condition that is the most likely source of the "uninitialized @@ -118,3 +110,7 @@ void UndefBranchChecker::VisitBranchCondition(BranchNodeBuilder &Builder, Builder.markInfeasible(false); } } + +void ento::registerUndefBranchChecker(CheckerManager &mgr) { + mgr.registerChecker<UndefBranchChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp index 6d3c966..69958d1 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp @@ -11,8 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "llvm/Support/raw_ostream.h" @@ -22,20 +24,14 @@ using namespace ento; namespace { class UndefCapturedBlockVarChecker - : public CheckerVisitor<UndefCapturedBlockVarChecker> { - BugType *BT; + : public Checker< check::PostStmt<BlockExpr> > { + mutable llvm::OwningPtr<BugType> BT; public: - UndefCapturedBlockVarChecker() : BT(0) {} - static void *getTag() { static int tag = 0; return &tag; } - void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE); + void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; }; } // end anonymous namespace -void ento::RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng) { - Eng.registerCheck(new UndefCapturedBlockVarChecker()); -} - static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S, const VarDecl *VD){ if (const BlockDeclRefExpr *BR = dyn_cast<BlockDeclRefExpr>(S)) @@ -54,8 +50,8 @@ static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S, } void -UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C, - const BlockExpr *BE) { +UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, + CheckerContext &C) const { if (!BE->getBlockDecl()->hasCaptures()) return; @@ -82,7 +78,7 @@ UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C, if (state->getSVal(VR).isUndef()) if (ExplodedNode *N = C.generateSink()) { if (!BT) - BT = new BuiltinBug("uninitialized variable captured by block"); + BT.reset(new BuiltinBug("uninitialized variable captured by block")); // Generate a bug report. llvm::SmallString<128> buf; @@ -100,3 +96,7 @@ UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C, } } } + +void ento::registerUndefCapturedBlockVarChecker(CheckerManager &mgr) { + mgr.registerChecker<UndefCapturedBlockVarChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index 64a3567..7fa3804 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -12,9 +12,11 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" using namespace clang; @@ -22,23 +24,17 @@ using namespace ento; namespace { class UndefResultChecker - : public CheckerVisitor<UndefResultChecker> { + : public Checker< check::PostStmt<BinaryOperator> > { - BugType *BT; + mutable llvm::OwningPtr<BugType> BT; public: - UndefResultChecker() : BT(0) {} - static void *getTag() { static int tag = 0; return &tag; } - void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B); + void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const; }; } // end anonymous namespace -void ento::RegisterUndefResultChecker(ExprEngine &Eng) { - Eng.registerCheck(new UndefResultChecker()); -} - -void UndefResultChecker::PostVisitBinaryOperator(CheckerContext &C, - const BinaryOperator *B) { +void UndefResultChecker::checkPostStmt(const BinaryOperator *B, + CheckerContext &C) const { const GRState *state = C.getState(); if (state->getSVal(B).isUndef()) { // Generate an error node. @@ -47,7 +43,7 @@ void UndefResultChecker::PostVisitBinaryOperator(CheckerContext &C, return; if (!BT) - BT = new BuiltinBug("Result of operation is garbage or undefined"); + BT.reset(new BuiltinBug("Result of operation is garbage or undefined")); llvm::SmallString<256> sbuf; llvm::raw_svector_ostream OS(sbuf); @@ -85,3 +81,7 @@ void UndefResultChecker::PostVisitBinaryOperator(CheckerContext &C, C.EmitReport(report); } } + +void ento::registerUndefResultChecker(CheckerManager &mgr) { + mgr.registerChecker<UndefResultChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp index ff03448..e51ab20 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp @@ -12,39 +12,32 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" using namespace clang; using namespace ento; namespace { class UndefinedArraySubscriptChecker - : public CheckerVisitor<UndefinedArraySubscriptChecker> { - BugType *BT; + : public Checker< check::PreStmt<ArraySubscriptExpr> > { + mutable llvm::OwningPtr<BugType> BT; + public: - UndefinedArraySubscriptChecker() : BT(0) {} - static void *getTag() { - static int x = 0; - return &x; - } - void PreVisitArraySubscriptExpr(CheckerContext &C, - const ArraySubscriptExpr *A); + void checkPreStmt(const ArraySubscriptExpr *A, CheckerContext &C) const; }; } // end anonymous namespace -void ento::RegisterUndefinedArraySubscriptChecker(ExprEngine &Eng) { - Eng.registerCheck(new UndefinedArraySubscriptChecker()); -} - void -UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C, - const ArraySubscriptExpr *A) { +UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A, + CheckerContext &C) const { if (C.getState()->getSVal(A->getIdx()).isUndef()) { if (ExplodedNode *N = C.generateSink()) { if (!BT) - BT = new BuiltinBug("Array subscript is undefined"); + BT.reset(new BuiltinBug("Array subscript is undefined")); // Generate a report for this bug. EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N); @@ -55,3 +48,7 @@ UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C, } } } + +void ento::registerUndefinedArraySubscriptChecker(CheckerManager &mgr) { + mgr.registerChecker<UndefinedArraySubscriptChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp index e53cbba..28806e3 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -7,43 +7,32 @@ // //===----------------------------------------------------------------------===// // -// This defines UndefinedAssginmentChecker, a builtin check in ExprEngine that +// This defines UndefinedAssignmentChecker, a builtin check in ExprEngine that // checks for assigning undefined values. // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" using namespace clang; using namespace ento; namespace { class UndefinedAssignmentChecker - : public CheckerVisitor<UndefinedAssignmentChecker> { - BugType *BT; + : public Checker<check::Bind> { + mutable llvm::OwningPtr<BugType> BT; + public: - UndefinedAssignmentChecker() : BT(0) {} - static void *getTag(); - virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE, - SVal location, SVal val); + void checkBind(SVal location, SVal val, CheckerContext &C) const; }; } -void ento::RegisterUndefinedAssignmentChecker(ExprEngine &Eng){ - Eng.registerCheck(new UndefinedAssignmentChecker()); -} - -void *UndefinedAssignmentChecker::getTag() { - static int x = 0; - return &x; -} - -void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, - const Stmt *StoreE, - SVal location, - SVal val) { +void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, + CheckerContext &C) const { if (!val.isUndef()) return; @@ -55,11 +44,12 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, const char *str = "Assigned value is garbage or undefined"; if (!BT) - BT = new BuiltinBug(str); + BT.reset(new BuiltinBug(str)); // Generate a report for this bug. const Expr *ex = 0; + const Stmt *StoreE = C.getStmt(); while (StoreE) { if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) { if (B->isCompoundAssignmentOp()) { @@ -92,3 +82,6 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C, C.EmitReport(R); } +void ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) { + mgr.registerChecker<UndefinedAssignmentChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index be4fbf6..48d7c36 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -27,7 +27,7 @@ using namespace ento; using llvm::Optional; namespace { -class UnixAPIChecker : public CheckerV2< check::PreStmt<CallExpr> > { +class UnixAPIChecker : public Checker< check::PreStmt<CallExpr> > { enum SubChecks { OpenFn = 0, PthreadOnceFn = 1, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp index 1bc487a..b540bce 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp @@ -14,7 +14,7 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" @@ -34,7 +34,7 @@ using namespace clang; using namespace ento; namespace { -class UnreachableCodeChecker : public CheckerV2<check::EndAnalysis> { +class UnreachableCodeChecker : public Checker<check::EndAnalysis> { public: void checkEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng) const; @@ -112,8 +112,8 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G, // such as llvm_unreachable. if (!CB->empty()) { CFGElement First = CB->front(); - if (CFGStmt S = First.getAs<CFGStmt>()) { - if (const CallExpr *CE = dyn_cast<CallExpr>(S.getStmt())) { + if (const CFGStmt *S = First.getAs<CFGStmt>()) { + if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) { if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable) continue; } @@ -164,8 +164,8 @@ void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB, // Find the Stmt* in a CFGBlock for reporting a warning const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) { for (CFGBlock::const_iterator I = CB->begin(), E = CB->end(); I != E; ++I) { - if (CFGStmt S = I->getAs<CFGStmt>()) - return S; + if (const CFGStmt *S = I->getAs<CFGStmt>()) + return S->getStmt(); } if (const Stmt *S = CB->getTerminator()) return S; @@ -204,7 +204,7 @@ bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB, // Run each of the checks on the conditions if (containsMacro(cond) || containsEnum(cond) || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond) - || containsStmt<SizeOfAlignOfExpr>(cond)) + || containsStmt<UnaryExprOrTypeTraitExpr>(cond)) return true; return false; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp index ba46e17..875dce2 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -14,32 +14,27 @@ // //===----------------------------------------------------------------------===// -#include "InternalChecks.h" -#include "clang/AST/CharUnits.h" +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/AST/CharUnits.h" using namespace clang; using namespace ento; namespace { -class VLASizeChecker : public CheckerVisitor<VLASizeChecker> { - BugType *BT_zero; - BugType *BT_undef; +class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > { + mutable llvm::OwningPtr<BugType> BT_zero; + mutable llvm::OwningPtr<BugType> BT_undef; public: - VLASizeChecker() : BT_zero(0), BT_undef(0) {} - static void *getTag() { static int tag = 0; return &tag; } - void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS); + void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; }; } // end anonymous namespace -void ento::RegisterVLASizeChecker(ExprEngine &Eng) { - Eng.registerCheck(new VLASizeChecker()); -} - -void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { +void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { if (!DS->isSingleDecl()) return; @@ -64,8 +59,8 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { return; if (!BT_undef) - BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a " - "garbage value as its size"); + BT_undef.reset(new BuiltinBug("Declared variable-length array (VLA) " + "uses a garbage value as its size")); EnhancedBugReport *report = new EnhancedBugReport(*BT_undef, BT_undef->getName(), N); @@ -89,8 +84,8 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { if (stateZero && !stateNotZero) { ExplodedNode* N = C.generateSink(stateZero); if (!BT_zero) - BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero " - "size"); + BT_zero.reset(new BuiltinBug("Declared variable-length array (VLA) has " + "zero size")); EnhancedBugReport *report = new EnhancedBugReport(*BT_zero, BT_zero->getName(), N); @@ -136,3 +131,7 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) { // Remember our assumptions! C.addTransition(state); } + +void ento::registerVLASizeChecker(CheckerManager &mgr) { + mgr.registerChecker<VLASizeChecker>(); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AggExprVisitor.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AggExprVisitor.cpp index e80cf9b..901190d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AggExprVisitor.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/AggExprVisitor.cpp @@ -60,7 +60,7 @@ void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) { } void AggExprVisitor::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { - Eng.VisitCXXMemberCallExpr(E, Pred, DstSet); + Eng.Visit(E, Pred, DstSet); } void ExprEngine::VisitAggExpr(const Expr *E, const MemRegion *Dest, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicStore.cpp index 98365e7..4faa84c 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicStore.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicStore.cpp @@ -429,12 +429,15 @@ StoreRef BasicStoreManager::getInitialStore(const LocationContext *InitLoc) { } if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(InitLoc->getDecl())) { - // For C++ methods add symbolic region for 'this' in initial stack frame. - QualType ThisT = MD->getThisType(StateMgr.getContext()); - MemRegionManager &RegMgr = svalBuilder.getRegionManager(); - const CXXThisRegion *ThisR = RegMgr.getCXXThisRegion(ThisT, InitLoc); - SVal ThisV = svalBuilder.getRegionValueSymbolVal(ThisR); - St = Bind(St.getStore(), svalBuilder.makeLoc(ThisR), ThisV); + // For C++ non-static member variables, add a symbolic region for 'this' in + // the initial stack frame. + if (MD->isInstance()) { + QualType ThisT = MD->getThisType(StateMgr.getContext()); + MemRegionManager &RegMgr = svalBuilder.getRegionManager(); + const CXXThisRegion *ThisR = RegMgr.getCXXThisRegion(ThisT, InitLoc); + SVal ThisV = svalBuilder.getRegionValueSymbolVal(ThisR); + St = Bind(St.getStore(), svalBuilder.makeLoc(ThisR), ThisV); + } } return St; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp index 6315d83..ae8a04c 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" using namespace clang; using namespace ento; @@ -25,8 +26,9 @@ void CompoundValData::Profile(llvm::FoldingSetNodeID& ID, QualType T, } void LazyCompoundValData::Profile(llvm::FoldingSetNodeID& ID, - const void *store,const TypedRegion *region) { - ID.AddPointer(store); + const StoreRef &store, + const TypedRegion *region) { + ID.AddPointer(store.getStore()); ID.AddPointer(region); } @@ -124,7 +126,7 @@ BasicValueFactory::getCompoundValData(QualType T, } const LazyCompoundValData* -BasicValueFactory::getLazyCompoundValData(const void *store, +BasicValueFactory::getLazyCompoundValData(const StoreRef &store, const TypedRegion *region) { llvm::FoldingSetNodeID ID; LazyCompoundValData::Profile(ID, store, region); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index 672982a..8b5d383 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -432,7 +432,7 @@ public: else if (const DeclStmt* DS = dyn_cast<DeclStmt>(S)) { // FIXME: Eventually CFGs won't have DeclStmts. Right now we // assume that each DeclStmt has a single Decl. This invariant - // holds by contruction in the CFG. + // holds by construction in the CFG. VD = dyn_cast<VarDecl>(*DS->decl_begin()); } @@ -859,7 +859,8 @@ class EdgeBuilder { default: break; case Stmt::ParenExprClass: - S = cast<ParenExpr>(S)->IgnoreParens(); + case Stmt::GenericSelectionExprClass: + S = cast<Expr>(S)->IgnoreParens(); firstCharOnly = true; continue; case Stmt::BinaryConditionalOperatorClass: @@ -1170,13 +1171,14 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, } if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) { - if (CFGStmt S = BE->getFirstElement().getAs<CFGStmt>()) { - if (IsControlFlowExpr(S)) { + if (const CFGStmt *S = BE->getFirstElement().getAs<CFGStmt>()) { + const Stmt *stmt = S->getStmt(); + if (IsControlFlowExpr(stmt)) { // Add the proper context for '&&', '||', and '?'. - EB.addContext(S); + EB.addContext(stmt); } else - EB.addExtendedContext(PDB.getEnclosingStmtLocation(S).asStmt()); + EB.addExtendedContext(PDB.getEnclosingStmtLocation(stmt).asStmt()); } break; diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp index b3721d7..d9b1ce8 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CFRefCount.cpp @@ -12,7 +12,11 @@ // //===----------------------------------------------------------------------===// +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" @@ -20,7 +24,6 @@ #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h" #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" @@ -1198,7 +1201,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(RetainSummary &Summ, // Effects on the parameters. unsigned parm_idx = 0; for (FunctionDecl::param_const_iterator pi = FD->param_begin(), - pe = FD->param_end(); pi != pe; ++pi) { + pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) { const ParmVarDecl *pd = *pi; if (pd->getAttr<NSConsumedAttr>()) { if (!GCEnabled) @@ -2428,7 +2431,7 @@ CFRefLeakReport::CFRefLeakReport(CFRefBug& D, const CFRefCount &tf, SymbolRef sym, ExprEngine& Eng) : CFRefReport(D, tf, n, sym) { - // Most bug reports are cached at the location where they occured. + // Most bug reports are cached at the location where they occurred. // With leaks, we want to unique them by the location where they were // allocated, and only report a single path. To do this, we need to find // the allocation site of a piece of tracked memory, which we do via a @@ -2526,6 +2529,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst, RegionsToInvalidate.push_back(region); } + // Invalidate all instance variables for the callee of a C++ method call. + // FIXME: We should be able to do better with inter-procedural analysis. + // FIXME: we can probably do better for const versus non-const methods. + if (callOrMsg.isCXXCall()) { + if (const MemRegion *callee = callOrMsg.getCXXCallee().getAsRegion()) + RegionsToInvalidate.push_back(callee); + } + for (unsigned idx = 0, e = callOrMsg.getNumArgs(); idx != e; ++idx) { SVal V = callOrMsg.getArgSValAsScalarOrLoc(idx); SymbolRef Sym = V.getAsLocSymbol(); @@ -2678,11 +2689,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst, // FIXME: We eventually should handle structs and other compound types // that are returned by value. - QualType T = callOrMsg.getResultType(Eng.getContext()); - if (Loc::isLocType(T) || (T->isIntegerType() && T->isScalarType())) { + // Use the result type from callOrMsg as it automatically adjusts + // for methods/functions that return references. + QualType resultTy = callOrMsg.getResultType(Eng.getContext()); + if (Loc::isLocType(resultTy) || + (resultTy->isIntegerType() && resultTy->isScalarType())) { unsigned Count = Builder.getCurrentBlockCount(); SValBuilder &svalBuilder = Eng.getSValBuilder(); - SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, T, Count); + SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, resultTy, Count); state = state->BindExpr(Ex, X, false); } @@ -2709,9 +2723,12 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst, unsigned Count = Builder.getCurrentBlockCount(); SValBuilder &svalBuilder = Eng.getSValBuilder(); SymbolRef Sym = svalBuilder.getConjuredSymbol(Ex, Count); - QualType RetT = GetReturnType(Ex, svalBuilder.getContext()); + + // Use the result type from callOrMsg as it automatically adjusts + // for methods/functions that return references. + QualType resultTy = callOrMsg.getResultType(Eng.getContext()); state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(), - RetT)); + resultTy)); state = state->BindExpr(Ex, svalBuilder.makeLoc(Sym), false); // FIXME: Add a flag to the checker where allocations are assumed to @@ -2764,11 +2781,17 @@ void CFRefCount::evalCall(ExplodedNodeSet& Dst, if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) { Summ = Summaries.getPersistentStopSummary(); } - else { - const FunctionDecl* FD = L.getAsFunctionDecl(); - Summ = !FD ? Summaries.getDefaultSummary() : - Summaries.getSummary(FD); + else if (const FunctionDecl* FD = L.getAsFunctionDecl()) { + Summ = Summaries.getSummary(FD); + } + else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) { + if (const CXXMethodDecl *MD = me->getMethodDecl()) + Summ = Summaries.getSummary(MD); + else + Summ = Summaries.getDefaultSummary(); } + else + Summ = Summaries.getDefaultSummary(); assert(Summ); evalSummary(Dst, Eng, Builder, CE, @@ -3395,19 +3418,15 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, namespace { class RetainReleaseChecker - : public CheckerVisitor<RetainReleaseChecker> { - CFRefCount *TF; + : public Checker< check::PostStmt<BlockExpr> > { public: - RetainReleaseChecker(CFRefCount *tf) : TF(tf) {} - static void* getTag() { static int x = 0; return &x; } - - void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE); + void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; }; } // end anonymous namespace -void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C, - const BlockExpr *BE) { +void RetainReleaseChecker::checkPostStmt(const BlockExpr *BE, + CheckerContext &C) const { // Scan the BlockDecRefExprs for any object the retain/release checker // may be tracking. @@ -3510,7 +3529,9 @@ void CFRefCount::RegisterChecks(ExprEngine& Eng) { // Register the RetainReleaseChecker with the ExprEngine object. // Functionality in CFRefCount will be migrated to RetainReleaseChecker // over time. - Eng.registerCheck(new RetainReleaseChecker(this)); + // FIXME: HACK! Remove TransferFuncs and turn all of CFRefCount into fully + // using the checker mechanism. + Eng.getCheckerManager().registerChecker<RetainReleaseChecker>(); } TransferFuncs* ento::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CXXExprEngine.cpp index 56dfe8c..54cbca0 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CXXExprEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CXXExprEngine.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/AST/DeclCXX.h" @@ -61,6 +62,34 @@ void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE, } } +void ExprEngine::evalCallee(const CallExpr *callExpr, + const ExplodedNodeSet &src, + ExplodedNodeSet &dest) { + + const Expr *callee = 0; + + switch (callExpr->getStmtClass()) { + case Stmt::CXXMemberCallExprClass: { + // Evaluate the implicit object argument that is the recipient of the + // call. + callee = cast<CXXMemberCallExpr>(callExpr)->getImplicitObjectArgument(); + + // FIXME: handle member pointers. + if (!callee) + return; + + break; + } + default: { + callee = callExpr->getCallee()->IgnoreParens(); + break; + } + } + + for (ExplodedNodeSet::iterator i = src.begin(), e = src.end(); i != e; ++i) + Visit(callee, *i, dest); +} + const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D, const StackFrameContext *SFC) { const Type *T = D->getTypeForDecl(); @@ -95,50 +124,121 @@ void ExprEngine::CreateCXXTemporaryObject(const Expr *Ex, ExplodedNode *Pred, } void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, - const MemRegion *Dest, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - if (!Dest) - Dest = svalBuilder.getRegionManager().getCXXTempObjectRegion(E, - Pred->getLocationContext()); - - if (E->isElidable()) { - VisitAggExpr(E->getArg(0), Dest, Pred, Dst); - return; - } + const MemRegion *Dest, + ExplodedNode *Pred, + ExplodedNodeSet &destNodes) { const CXXConstructorDecl *CD = E->getConstructor(); assert(CD); - + +#if 0 if (!(CD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) // FIXME: invalidate the object. return; - +#endif // Evaluate other arguments. ExplodedNodeSet argsEvaluated; const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>(); evalArguments(E->arg_begin(), E->arg_end(), FnType, Pred, argsEvaluated); - // The callee stack frame context used to create the 'this' parameter region. - const StackFrameContext *SFC = AMgr.getStackFrame(CD, - Pred->getLocationContext(), - E, Builder->getBlock(), - Builder->getIndex()); - const CXXThisRegion *ThisR =getCXXThisRegion(E->getConstructor()->getParent(), - SFC); - - CallEnter Loc(E, SFC, Pred->getLocationContext()); - for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(), - NE = argsEvaluated.end(); NI != NE; ++NI) { - const GRState *state = GetState(*NI); - // Setup 'this' region, so that the ctor is evaluated on the object pointed - // by 'Dest'. - state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); - ExplodedNode *N = Builder->generateNode(Loc, state, Pred); - if (N) - Dst.Add(N); +#if 0 + // Is the constructor elidable? + if (E->isElidable()) { + VisitAggExpr(E->getArg(0), destNodes, Pred, Dst); + // FIXME: this is here to force propagation if VisitAggExpr doesn't + if (destNodes.empty()) + destNodes.Add(Pred); + return; + } +#endif + + // Perform the previsit of the constructor. + ExplodedNodeSet destPreVisit; + getCheckerManager().runCheckersForPreStmt(destPreVisit, argsEvaluated, E, + *this); + + // Evaluate the constructor. Currently we don't now allow checker-specific + // implementations of specific constructors (as we do with ordinary + // function calls. We can re-evaluate this in the future. + +#if 0 + // Inlining currently isn't fully implemented. + + if (AMgr.shouldInlineCall()) { + if (!Dest) + Dest = + svalBuilder.getRegionManager().getCXXTempObjectRegion(E, + Pred->getLocationContext()); + + // The callee stack frame context used to create the 'this' + // parameter region. + const StackFrameContext *SFC = + AMgr.getStackFrame(CD, Pred->getLocationContext(), + E, Builder->getBlock(), Builder->getIndex()); + + // Create the 'this' region. + const CXXThisRegion *ThisR = + getCXXThisRegion(E->getConstructor()->getParent(), SFC); + + CallEnter Loc(E, SFC, Pred->getLocationContext()); + + + for (ExplodedNodeSet::iterator NI = argsEvaluated.begin(), + NE = argsEvaluated.end(); NI != NE; ++NI) { + const GRState *state = GetState(*NI); + // Setup 'this' region, so that the ctor is evaluated on the object pointed + // by 'Dest'. + state = state->bindLoc(loc::MemRegionVal(ThisR), loc::MemRegionVal(Dest)); + if (ExplodedNode *N = Builder->generateNode(Loc, state, *NI)) + destNodes.Add(N); + } + } +#endif + + // Default semantics: invalidate all regions passed as arguments. + llvm::SmallVector<const MemRegion*, 10> regionsToInvalidate; + + // FIXME: We can have collisions on the conjured symbol if the + // expression *I also creates conjured symbols. We probably want + // to identify conjured symbols by an expression pair: the enclosing + // expression (the context) and the expression itself. This should + // disambiguate conjured symbols. + unsigned blockCount = Builder->getCurrentBlockCount(); + + // NOTE: Even if RegionsToInvalidate is empty, we must still invalidate + // global variables. + ExplodedNodeSet destCall; + + for (ExplodedNodeSet::iterator + i = destPreVisit.begin(), e = destPreVisit.end(); + i != e; ++i) + { + ExplodedNode *Pred = *i; + const GRState *state = GetState(Pred); + + // Accumulate list of regions that are invalidated. + for (CXXConstructExpr::const_arg_iterator + ai = E->arg_begin(), ae = E->arg_end(); + ai != ae; ++ai) + { + SVal val = state->getSVal(*ai); + if (const MemRegion *region = val.getAsRegion()) + regionsToInvalidate.push_back(region); + } + + // Invalidate the regions. + state = state->invalidateRegions(regionsToInvalidate.data(), + regionsToInvalidate.data() + + regionsToInvalidate.size(), + E, blockCount, 0, + /* invalidateGlobals = */ true); + + Builder->MakeNode(destCall, E, Pred, state); } + + // Do the post visit. + getCheckerManager().runCheckersForPostStmt(destNodes, destCall, E, *this); } void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, @@ -165,105 +265,25 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, Dst.Add(N); } -void ExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - // Get the method type. - const FunctionProtoType *FnType = - MCE->getCallee()->getType()->getAs<FunctionProtoType>(); - assert(FnType && "Method type not available"); - - // Evaluate explicit arguments with a worklist. - ExplodedNodeSet argsEvaluated; - evalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, argsEvaluated); - - // Evaluate the implicit object argument. - ExplodedNodeSet AllargsEvaluated; - const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens()); - if (!ME) - return; - Expr *ObjArgExpr = ME->getBase(); - for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), - E = argsEvaluated.end(); I != E; ++I) { - Visit(ObjArgExpr, *I, AllargsEvaluated); - } - - // Now evaluate the call itself. - const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); - assert(MD && "not a CXXMethodDecl?"); - evalMethodCall(MCE, MD, ObjArgExpr, Pred, AllargsEvaluated, Dst); -} - -void ExprEngine::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(C->getCalleeDecl()); - if (!MD) { - // If the operator doesn't represent a method call treat as regural call. - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); - return; - } - - // Determine the type of function we're calling (if available). - const FunctionProtoType *Proto = NULL; - QualType FnType = C->getCallee()->IgnoreParens()->getType(); - if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) - Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>(); - - // Evaluate arguments treating the first one (object method is called on) - // as alvalue. - ExplodedNodeSet argsEvaluated; - evalArguments(C->arg_begin(), C->arg_end(), Proto, Pred, argsEvaluated, true); - - // Now evaluate the call itself. - evalMethodCall(C, MD, C->getArg(0), Pred, argsEvaluated, Dst); -} - -void ExprEngine::evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD, - const Expr *ThisExpr, ExplodedNode *Pred, - ExplodedNodeSet &Src, ExplodedNodeSet &Dst) { - // Allow checkers to pre-visit the member call. - ExplodedNodeSet PreVisitChecks; - CheckerVisit(MCE, PreVisitChecks, Src, PreVisitStmtCallback); - - if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) { - // FIXME: conservative method call evaluation. - CheckerVisit(MCE, Dst, PreVisitChecks, PostVisitStmtCallback); - return; - } - - const StackFrameContext *SFC = AMgr.getStackFrame(MD, - Pred->getLocationContext(), - MCE, - Builder->getBlock(), - Builder->getIndex()); - const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); - CallEnter Loc(MCE, SFC, Pred->getLocationContext()); - for (ExplodedNodeSet::iterator I = PreVisitChecks.begin(), - E = PreVisitChecks.end(); I != E; ++I) { - // Set up 'this' region. - const GRState *state = GetState(*I); - state = state->bindLoc(loc::MemRegionVal(ThisR), state->getSVal(ThisExpr)); - Dst.Add(Builder->generateNode(Loc, state, *I)); - } -} - void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - if (CNE->isArray()) { - // FIXME: allocating an array has not been handled. - return; - } - - unsigned Count = Builder->getCurrentBlockCount(); + + unsigned blockCount = Builder->getCurrentBlockCount(); DefinedOrUnknownSVal symVal = - svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), Count); - const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion(); - + svalBuilder.getConjuredSymbolVal(NULL, CNE, CNE->getType(), blockCount); + const MemRegion *NewReg = cast<loc::MemRegionVal>(symVal).getRegion(); QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType(); - const ElementRegion *EleReg = - getStoreManager().GetElementZeroRegion(NewReg, ObjTy); + getStoreManager().GetElementZeroRegion(NewReg, ObjTy); + + if (CNE->isArray()) { + // FIXME: allocating an array requires simulating the constructors. + // For now, just return a symbolicated region. + const GRState *state = GetState(Pred); + state = state->BindExpr(CNE, loc::MemRegionVal(EleReg)); + MakeNode(Dst, CNE, Pred, state); + return; + } // Evaluate constructor arguments. const FunctionProtoType *FnType = NULL; @@ -277,11 +297,39 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // Initialize the object region and bind the 'new' expression. for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), E = argsEvaluated.end(); I != E; ++I) { + const GRState *state = GetState(*I); + + // Accumulate list of regions that are invalidated. + // FIXME: Eventually we should unify the logic for constructor + // processing in one place. + llvm::SmallVector<const MemRegion*, 10> regionsToInvalidate; + for (CXXNewExpr::const_arg_iterator + ai = CNE->constructor_arg_begin(), ae = CNE->constructor_arg_end(); + ai != ae; ++ai) + { + SVal val = state->getSVal(*ai); + if (const MemRegion *region = val.getAsRegion()) + regionsToInvalidate.push_back(region); + } if (ObjTy->isRecordType()) { - state = state->invalidateRegion(EleReg, CNE, Count); + regionsToInvalidate.push_back(EleReg); + // Invalidate the regions. + state = state->invalidateRegions(regionsToInvalidate.data(), + regionsToInvalidate.data() + + regionsToInvalidate.size(), + CNE, blockCount, 0, + /* invalidateGlobals = */ true); + } else { + // Invalidate the regions. + state = state->invalidateRegions(regionsToInvalidate.data(), + regionsToInvalidate.data() + + regionsToInvalidate.size(), + CNE, blockCount, 0, + /* invalidateGlobals = */ true); + if (CNE->hasInitializer()) { SVal V = state->getSVal(*CNE->constructor_arg_begin()); state = state->bindLoc(loc::MemRegionVal(EleReg), V); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp index a014eec..f6fb8f2 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Checker.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp @@ -1,4 +1,4 @@ -//== Checker.h - Abstract interface for checkers -----------------*- C++ -*--=// +//== CheckerContext.cpp - Context info for path-sensitive checkers-----------=// // // The LLVM Compiler Infrastructure // @@ -7,17 +7,15 @@ // //===----------------------------------------------------------------------===// // -// This file defines Checker and CheckerVisitor, classes used for creating -// domain-specific checks. +// This file defines CheckerContext that provides contextual info for +// path-sensitive checkers. // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" using namespace clang; using namespace ento; -Checker::~Checker() {} - CheckerContext::~CheckerContext() { // Do we need to autotransition? 'Dst' can get populated in a variety of // ways, including 'addTransition()' adding the predecessor node to Dst diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index 75d331a..4a25490 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -20,6 +20,32 @@ using namespace clang; using namespace ento; +bool CheckerManager::hasPathSensitiveCheckers() const { + return !StmtCheckers.empty() || + !PreObjCMessageCheckers.empty() || + !PostObjCMessageCheckers.empty() || + !LocationCheckers.empty() || + !BindCheckers.empty() || + !EndAnalysisCheckers.empty() || + !EndPathCheckers.empty() || + !BranchConditionCheckers.empty() || + !LiveSymbolsCheckers.empty() || + !DeadSymbolsCheckers.empty() || + !RegionChangesCheckers.empty() || + !EvalAssumeCheckers.empty() || + !EvalCallCheckers.empty(); +} + +void CheckerManager::finishedCheckerRegistration() { +#ifndef NDEBUG + // Make sure that for every event that has listeners, there is at least + // one dispatcher registered for it. + for (llvm::DenseMap<EventTag, EventInfo>::iterator + I = Events.begin(), E = Events.end(); I != E; ++I) + assert(I->second.HasDispatcher && "No dispatcher registered for an event"); +#endif +} + //===----------------------------------------------------------------------===// // Functions for running checkers for AST traversing.. //===----------------------------------------------------------------------===// @@ -205,6 +231,40 @@ void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, expandGraphWithCheckers(C, Dst, Src); } +namespace { + struct CheckBindContext { + typedef std::vector<CheckerManager::CheckBindFunc> CheckersTy; + const CheckersTy &Checkers; + SVal Loc; + SVal Val; + const Stmt *S; + ExprEngine &Eng; + + CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } + CheckersTy::const_iterator checkers_end() { return Checkers.end(); } + + CheckBindContext(const CheckersTy &checkers, + SVal loc, SVal val, const Stmt *s, ExprEngine &eng) + : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng) { } + + void runChecker(CheckerManager::CheckBindFunc checkFn, + ExplodedNodeSet &Dst, ExplodedNode *Pred) { + CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, checkFn.Checker, + ProgramPoint::PreStmtKind, 0, S); + checkFn(Loc, Val, C); + } + }; +} + +/// \brief Run checkers for binding of a value to a location. +void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + SVal location, SVal val, + const Stmt *S, ExprEngine &Eng) { + CheckBindContext C(BindCheckers, location, val, S, Eng); + expandGraphWithCheckers(C, Dst, Src); +} + void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, ExprEngine &Eng) { @@ -222,6 +282,16 @@ void CheckerManager::runCheckersForEndPath(EndOfFunctionNodeBuilder &B, } } +/// \brief Run checkers for branch condition. +void CheckerManager::runCheckersForBranchCondition(const Stmt *condition, + BranchNodeBuilder &B, + ExprEngine &Eng) { + for (unsigned i = 0, e = BranchConditionCheckers.size(); i != e; ++i) { + CheckBranchConditionFunc fn = BranchConditionCheckers[i]; + fn(condition, B, Eng); + } +} + /// \brief Run checkers for live symbols. void CheckerManager::runCheckersForLiveSymbols(const GRState *state, SymbolReaper &SymReaper) { @@ -287,6 +357,20 @@ CheckerManager::runCheckersForRegionChanges(const GRState *state, return state; } +/// \brief Run checkers for handling assumptions on symbolic values. +const GRState * +CheckerManager::runCheckersForEvalAssume(const GRState *state, + SVal Cond, bool Assumption) { + for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) { + // If any checker declares the state infeasible (or if it starts that way), + // bail out. + if (!state) + return NULL; + state = EvalAssumeCheckers[i](state, Cond, Assumption); + } + return state; +} + /// \brief Run checkers for evaluating a call. /// Only one checker will evaluate the call. void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, @@ -371,6 +455,10 @@ void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { LocationCheckers.push_back(checkfn); } +void CheckerManager::_registerForBind(CheckBindFunc checkfn) { + BindCheckers.push_back(checkfn); +} + void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) { EndAnalysisCheckers.push_back(checkfn); } @@ -379,6 +467,11 @@ void CheckerManager::_registerForEndPath(CheckEndPathFunc checkfn) { EndPathCheckers.push_back(checkfn); } +void CheckerManager::_registerForBranchCondition( + CheckBranchConditionFunc checkfn) { + BranchConditionCheckers.push_back(checkfn); +} + void CheckerManager::_registerForLiveSymbols(CheckLiveSymbolsFunc checkfn) { LiveSymbolsCheckers.push_back(checkfn); } @@ -393,6 +486,10 @@ void CheckerManager::_registerForRegionChanges(CheckRegionChangesFunc checkfn, RegionChangesCheckers.push_back(info); } +void CheckerManager::_registerForEvalAssume(EvalAssumeFunc checkfn) { + EvalAssumeCheckers.push_back(checkfn); +} + void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { EvalCallCheckers.push_back(checkfn); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index 08a2068..34cd6e8 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -19,8 +19,6 @@ #include "clang/AST/Expr.h" #include "llvm/Support/Casting.h" #include "llvm/ADT/DenseMap.h" -#include <vector> -#include <queue> using llvm::cast; using llvm::isa; @@ -310,7 +308,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge& L, ExplodedNode* Pred) { for (llvm::SmallVectorImpl<ExplodedNode*>::const_iterator I = nodeBuilder.sinks().begin(), E = nodeBuilder.sinks().end(); I != E; ++I) { - blocksAborted.push_back(std::make_pair(L, *I)); + blocksExhausted.push_back(std::make_pair(L, *I)); } } @@ -602,6 +600,25 @@ StmtNodeBuilder::generateNodeInternal(const ProgramPoint &Loc, return NULL; } +// This function generate a new ExplodedNode but not a new branch(block edge). +ExplodedNode* BranchNodeBuilder::generateNode(const Stmt* Condition, + const GRState* State) { + bool IsNew; + + ExplodedNode* Succ + = Eng.G->getNode(PostCondition(Condition, Pred->getLocationContext()), State, + &IsNew); + + Succ->addPredecessor(Pred, *Eng.G); + + Pred = Succ; + + if (IsNew) + return Succ; + + return NULL; +} + ExplodedNode* BranchNodeBuilder::generateNode(const GRState* State, bool branch) { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp index 1bffa30..a00f9dc1 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Environment.cpp @@ -27,7 +27,17 @@ SVal Environment::lookupExpr(const Stmt* E) const { return UnknownVal(); } -SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder) const { +SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder, + bool useOnlyDirectBindings) const { + + if (useOnlyDirectBindings) { + // This branch is rarely taken, but can be exercised by + // checkers that explicitly bind values to arbitrary + // expressions. It is crucial that we do not ignore any + // expression here, and do a direct lookup. + return lookupExpr(E); + } + for (;;) { switch (E->getStmtClass()) { case Stmt::AddrLabelExprClass: @@ -41,6 +51,10 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder) const { // ParenExprs are no-ops. E = cast<ParenExpr>(E)->getSubExpr(); continue; + case Stmt::GenericSelectionExprClass: + // GenericSelectionExprs are no-ops. + E = cast<GenericSelectionExpr>(E)->getResultExpr(); + continue; case Stmt::CharacterLiteralClass: { const CharacterLiteral* C = cast<CharacterLiteral>(E); return svalBuilder.makeIntVal(C->getValue(), C->getType()); @@ -60,6 +74,9 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder) const { else return svalBuilder.makeIntVal(cast<IntegerLiteral>(E)); } + // For special C0xx nullptr case, make a null pointer SVal. + case Stmt::CXXNullPtrLiteralExprClass: + return svalBuilder.makeNull(); case Stmt::ImplicitCastExprClass: case Stmt::CXXFunctionalCastExprClass: case Stmt::CStyleCastExprClass: { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index 2a8364d..fa16fea 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -374,7 +374,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, WL2.push_back(*I); } - // Finally, explictly mark all nodes without any successors as sinks. + // Finally, explicitly mark all nodes without any successors as sinks. if (N->isSink()) NewN->markAsSink(); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index c1b1e65..657420d 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -13,15 +13,11 @@ // //===----------------------------------------------------------------------===// -// FIXME: Restructure checker registration. -#include "InternalChecks.h" - #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h" #include "clang/AST/CharUnits.h" #include "clang/AST/ParentMap.h" #include "clang/AST/StmtObjC.h" @@ -63,278 +59,9 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { } //===----------------------------------------------------------------------===// -// Checker worklist routines. -//===----------------------------------------------------------------------===// - -void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, CallbackKind Kind) { - - // Determine if we already have a cached 'CheckersOrdered' vector - // specifically tailored for the provided <CallbackKind, Stmt kind>. This - // can reduce the number of checkers actually called. - CheckersOrdered *CO = &Checkers; - llvm::OwningPtr<CheckersOrdered> NewCO; - - // The cache key is made up of the and the callback kind (pre- or post-visit) - // and the statement kind. - CallbackTag K = GetCallbackTag(Kind, S->getStmtClass()); - - CheckersOrdered *& CO_Ref = COCache[K]; - - if (!CO_Ref) { - // If we have no previously cached CheckersOrdered vector for this - // statement kind, then create one. - NewCO.reset(new CheckersOrdered); - } - else { - // Use the already cached set. - CO = CO_Ref; - } - - if (CO->empty()) { - // If there are no checkers, just delegate to the checker manager. - getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback, - Dst, Src, S, *this); - return; - } - - ExplodedNodeSet CheckersV1Dst; - ExplodedNodeSet Tmp; - ExplodedNodeSet *PrevSet = &Src; - unsigned checkersEvaluated = 0; - - for (CheckersOrdered::iterator I=CO->begin(), E=CO->end(); I!=E; ++I) { - // If all nodes are sunk, bail out early. - if (PrevSet->empty()) - break; - ExplodedNodeSet *CurrSet = 0; - if (I+1 == E) - CurrSet = &CheckersV1Dst; - else { - CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); - } - void *tag = I->first; - Checker *checker = I->second; - bool respondsToCallback = true; - - for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) { - - checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, - Kind == PreVisitStmtCallback, respondsToCallback); - - } - - PrevSet = CurrSet; - - if (NewCO.get()) { - ++checkersEvaluated; - if (respondsToCallback) - NewCO->push_back(*I); - } - } - - // If we built NewCO, check if we called all the checkers. This is important - // so that we know that we accurately determined the entire set of checkers - // that responds to this callback. Note that 'checkersEvaluated' might - // not be the same as Checkers.size() if one of the Checkers generates - // a sink node. - if (NewCO.get() && checkersEvaluated == Checkers.size()) - CO_Ref = NewCO.take(); - - // Don't autotransition. The CheckerContext objects should do this - // automatically. - - getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback, - Dst, CheckersV1Dst, S, *this); -} - -void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg, - ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, - bool isPrevisit) { - - if (Checkers.empty()) { - getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, Src, msg, - *this); - return; - } - - ExplodedNodeSet CheckersV1Dst; - ExplodedNodeSet Tmp; - ExplodedNodeSet *PrevSet = &Src; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) - { - ExplodedNodeSet *CurrSet = 0; - if (I+1 == E) - CurrSet = &CheckersV1Dst; - else { - CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); - } - - void *tag = I->first; - Checker *checker = I->second; - - for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checker->GR_visitObjCMessage(*CurrSet, *Builder, *this, msg, - *NI, tag, isPrevisit); - - // Update which NodeSet is the current one. - PrevSet = CurrSet; - } - - getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, CheckersV1Dst, - msg, *this); -} - -void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg, - ExplodedNodeSet &Dst, - const GRState *state, - ExplodedNode *Pred) { - bool evaluated = false; - ExplodedNodeSet DstTmp; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { - void *tag = I->first; - Checker *checker = I->second; - - if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, msg, Pred, state, - tag)) { - evaluated = true; - break; - } else - // The checker didn't evaluate the expr. Restore the Dst. - DstTmp.clear(); - } - - if (evaluated) - Dst.insert(DstTmp); - else - Dst.insert(Pred); -} - -// CheckerEvalCall returns true if one of the checkers processed the node. -// This may return void when all call evaluation logic goes to some checker -// in the future. -bool ExprEngine::CheckerEvalCall(const CallExpr *CE, - ExplodedNodeSet &Dst, - ExplodedNode *Pred) { - bool evaluated = false; - ExplodedNodeSet DstTmp; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { - void *tag = I->first; - Checker *checker = I->second; - - if (checker->GR_evalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) { - evaluated = true; - break; - } else - // The checker didn't evaluate the expr. Restore the DstTmp set. - DstTmp.clear(); - } - - if (evaluated) { - Dst.insert(DstTmp); - return evaluated; - } - - class DefaultEval : public GraphExpander { - bool &Evaluated; - public: - DefaultEval(bool &evaluated) : Evaluated(evaluated) { } - virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) { - Evaluated = false; - Dst.insert(Pred); - } - }; - - evaluated = true; - DefaultEval defaultEval(evaluated); - getCheckerManager().runCheckersForEvalCall(Dst, Pred, CE, *this, - &defaultEval); - return evaluated; -} - -// FIXME: This is largely copy-paste from CheckerVisit(). Need to -// unify. -void ExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, SVal location, - SVal val, bool isPrevisit) { - - if (Checkers.empty()) { - Dst.insert(Src); - return; - } - - ExplodedNodeSet Tmp; - ExplodedNodeSet *PrevSet = &Src; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) - { - ExplodedNodeSet *CurrSet = 0; - if (I+1 == E) - CurrSet = &Dst; - else { - CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); - } - - void *tag = I->first; - Checker *checker = I->second; - - for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checker->GR_VisitBind(*CurrSet, *Builder, *this, StoreE, - *NI, tag, location, val, isPrevisit); - - // Update which NodeSet is the current one. - PrevSet = CurrSet; - } - - // Don't autotransition. The CheckerContext objects should do this - // automatically. -} -//===----------------------------------------------------------------------===// // Engine construction and deletion. //===----------------------------------------------------------------------===// -static void RegisterInternalChecks(ExprEngine &Eng) { - // Register internal "built-in" BugTypes with the BugReporter. These BugTypes - // are different than what probably many checks will do since they don't - // create BugReports on-the-fly but instead wait until ExprEngine finishes - // analyzing a function. Generation of BugReport objects is done via a call - // to 'FlushReports' from BugReporter. - // The following checks do not need to have their associated BugTypes - // explicitly registered with the BugReporter. If they issue any BugReports, - // their associated BugType will get registered with the BugReporter - // automatically. Note that the check itself is owned by the ExprEngine - // object. - RegisterAdjustedReturnValueChecker(Eng); - // CallAndMessageChecker should be registered before AttrNonNullChecker, - // where we assume arguments are not undefined. - RegisterCallAndMessageChecker(Eng); - RegisterAttrNonNullChecker(Eng); - RegisterDereferenceChecker(Eng); - RegisterVLASizeChecker(Eng); - RegisterDivZeroChecker(Eng); - RegisterReturnUndefChecker(Eng); - RegisterUndefinedArraySubscriptChecker(Eng); - RegisterUndefinedAssignmentChecker(Eng); - RegisterUndefBranchChecker(Eng); - RegisterUndefCapturedBlockVarChecker(Eng); - RegisterUndefResultChecker(Eng); - - // This is not a checker yet. - RegisterNoReturnFunctionChecker(Eng); - RegisterBuiltinFunctionChecker(Eng); - RegisterOSAtomicChecker(Eng); -} - ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf) : AMgr(mgr), Engine(*this), @@ -349,8 +76,6 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf) NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), RaiseSel(GetNullarySelector("raise", getContext())), BR(mgr, *this), TF(tf) { - // Register internal checks. - RegisterInternalChecks(*this); // FIXME: Eventually remove the TF object entirely. TF->RegisterChecks(*this); @@ -365,14 +90,6 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf) ExprEngine::~ExprEngine() { BR.FlushReports(); delete [] NSExceptionInstanceRaiseSelectors; - - // Delete the set of checkers. - for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I) - delete I->second; - - for (CheckersOrderedCache::iterator I=COCache.begin(), E=COCache.end(); - I!=E;++I) - delete I->second; } //===----------------------------------------------------------------------===// @@ -447,51 +164,7 @@ const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) { /// logic for handling assumptions on symbolic values. const GRState *ExprEngine::processAssume(const GRState *state, SVal cond, bool assumption) { - // Determine if we already have a cached 'CheckersOrdered' vector - // specifically tailored for processing assumptions. This - // can reduce the number of checkers actually called. - CheckersOrdered *CO = &Checkers; - llvm::OwningPtr<CheckersOrdered> NewCO; - - CallbackTag K = GetCallbackTag(processAssumeCallback); - CheckersOrdered *& CO_Ref = COCache[K]; - - if (!CO_Ref) { - // If we have no previously cached CheckersOrdered vector for this - // statement kind, then create one. - NewCO.reset(new CheckersOrdered); - } - else { - // Use the already cached set. - CO = CO_Ref; - } - - if (!CO->empty()) { - // Let the checkers have a crack at the assume before the transfer functions - // get their turn. - for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I!=E; ++I) { - - // If any checker declares the state infeasible (or if it starts that - // way), bail out. - if (!state) - return NULL; - - Checker *C = I->second; - bool respondsToCallback = true; - - state = C->evalAssume(state, cond, assumption, &respondsToCallback); - - // Check if we're building the cache of checkers that care about - // assumptions. - if (NewCO.get() && respondsToCallback) - NewCO->push_back(*I); - } - - // If we got through all the checkers, and we built a list of those that - // care about assumptions, save it. - if (NewCO.get()) - CO_Ref = NewCO.take(); - } + state = getCheckerManager().runCheckersForEvalAssume(state, cond, assumption); // If the state is infeasible at this point, bail out. if (!state) @@ -501,18 +174,6 @@ const GRState *ExprEngine::processAssume(const GRState *state, SVal cond, } bool ExprEngine::wantsRegionChangeUpdate(const GRState* state) { - CallbackTag K = GetCallbackTag(EvalRegionChangesCallback); - CheckersOrdered *CO = COCache[K]; - - if (!CO) - CO = &Checkers; - - for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) { - Checker *C = I->second; - if (C->wantsRegionChangeUpdate(state)) - return true; - } - return getCheckerManager().wantsRegionChangeUpdate(state); } @@ -520,78 +181,30 @@ const GRState * ExprEngine::processRegionChanges(const GRState *state, const MemRegion * const *Begin, const MemRegion * const *End) { - // FIXME: Most of this method is copy-pasted from processAssume. - - // Determine if we already have a cached 'CheckersOrdered' vector - // specifically tailored for processing region changes. This - // can reduce the number of checkers actually called. - CheckersOrdered *CO = &Checkers; - llvm::OwningPtr<CheckersOrdered> NewCO; - - CallbackTag K = GetCallbackTag(EvalRegionChangesCallback); - CheckersOrdered *& CO_Ref = COCache[K]; - - if (!CO_Ref) { - // If we have no previously cached CheckersOrdered vector for this - // callback, then create one. - NewCO.reset(new CheckersOrdered); - } - else { - // Use the already cached set. - CO = CO_Ref; - } - - // If there are no checkers, just delegate to the checker manager. - if (CO->empty()) - return getCheckerManager().runCheckersForRegionChanges(state, Begin, End); - - for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) { - // If any checker declares the state infeasible (or if it starts that way), - // bail out. - if (!state) - return NULL; - - Checker *C = I->second; - bool respondsToCallback = true; - - state = C->EvalRegionChanges(state, Begin, End, &respondsToCallback); - - // See if we're building a cache of checkers that care about region changes. - if (NewCO.get() && respondsToCallback) - NewCO->push_back(*I); - } - - // If we got through all the checkers, and we built a list of those that - // care about region changes, save it. - if (NewCO.get()) - CO_Ref = NewCO.take(); - return getCheckerManager().runCheckersForRegionChanges(state, Begin, End); } void ExprEngine::processEndWorklist(bool hasWorkRemaining) { - for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { - I->second->VisitEndAnalysis(G, BR, *this); - } getCheckerManager().runCheckersForEndAnalysis(G, BR, *this); } void ExprEngine::processCFGElement(const CFGElement E, StmtNodeBuilder& builder) { switch (E.getKind()) { - case CFGElement::Statement: - ProcessStmt(E.getAs<CFGStmt>(), builder); - break; - case CFGElement::Initializer: - ProcessInitializer(E.getAs<CFGInitializer>(), builder); - break; - case CFGElement::ImplicitDtor: - ProcessImplicitDtor(E.getAs<CFGImplicitDtor>(), builder); - break; - default: - // Suppress compiler warning. - llvm_unreachable("Unexpected CFGElement kind."); + case CFGElement::Invalid: + llvm_unreachable("Unexpected CFGElement kind."); + case CFGElement::Statement: + ProcessStmt(E.getAs<CFGStmt>()->getStmt(), builder); + return; + case CFGElement::Initializer: + ProcessInitializer(E.getAs<CFGInitializer>()->getInitializer(), builder); + return; + case CFGElement::AutomaticObjectDtor: + case CFGElement::BaseDtor: + case CFGElement::MemberDtor: + case CFGElement::TemporaryDtor: + ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), builder); + return; } } @@ -615,13 +228,6 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) { if (AMgr.shouldPurgeDead()) { const GRState *St = EntryNode->getState(); - - for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { - Checker *checker = I->second; - checker->MarkLiveSymbols(St, SymReaper); - } - getCheckerManager().runCheckersForLiveSymbols(St, SymReaper); const StackFrameContext *SFC = LC->getCurrentStackFrame(); @@ -647,33 +253,7 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) { getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode, CleanedState, SymReaper); - ExplodedNodeSet checkersV1Tmp; - if (Checkers.empty()) - checkersV1Tmp.insert(Tmp2); - else { - ExplodedNodeSet Tmp3; - ExplodedNodeSet *SrcSet = &Tmp2; - for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { - ExplodedNodeSet *DstSet = 0; - if (I+1 == E) - DstSet = &checkersV1Tmp; - else { - DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2; - DstSet->clear(); - } - - void *tag = I->first; - Checker *checker = I->second; - for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end(); - NI != NE; ++NI) - checker->GR_evalDeadSymbols(*DstSet, *Builder, *this, currentStmt, - *NI, SymReaper, tag); - SrcSet = DstSet; - } - } - - getCheckerManager().runCheckersForDeadSymbols(Tmp, checkersV1Tmp, + getCheckerManager().runCheckersForDeadSymbols(Tmp, Tmp2, SymReaper, currentStmt, *this); if (!Builder->BuildSinks && !Builder->hasGeneratedNode) @@ -767,7 +347,7 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, StmtNodeBuilder &builder) { Builder = &builder; - switch (D.getDtorKind()) { + switch (D.getKind()) { case CFGElement::AutomaticObjectDtor: ProcessAutomaticObjDtor(cast<CFGAutomaticObjDtor>(D), builder); break; @@ -842,10 +422,8 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, // C++ stuff we don't support yet. case Stmt::CXXBindTemporaryExprClass: case Stmt::CXXCatchStmtClass: - case Stmt::CXXDefaultArgExprClass: case Stmt::CXXDependentScopeMemberExprClass: - case Stmt::ExprWithCleanupsClass: - case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::CXXForRangeStmtClass: case Stmt::CXXPseudoDestructorExprClass: case Stmt::CXXTemporaryObjectExprClass: case Stmt::CXXThrowExprClass: @@ -857,20 +435,35 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, case Stmt::DependentScopeDeclRefExprClass: case Stmt::UnaryTypeTraitExprClass: case Stmt::BinaryTypeTraitExprClass: + case Stmt::ArrayTypeTraitExprClass: + case Stmt::ExpressionTraitExprClass: case Stmt::UnresolvedLookupExprClass: case Stmt::UnresolvedMemberExprClass: case Stmt::CXXNoexceptExprClass: case Stmt::PackExpansionExprClass: case Stmt::SubstNonTypeTemplateParmPackExprClass: + case Stmt::SEHTryStmtClass: + case Stmt::SEHExceptStmtClass: + case Stmt::SEHFinallyStmtClass: { SaveAndRestore<bool> OldSink(Builder->BuildSinks); Builder->BuildSinks = true; - MakeNode(Dst, S, Pred, GetState(Pred)); + const ExplodedNode *node = MakeNode(Dst, S, Pred, GetState(Pred)); + Engine.addAbortedBlock(node, Builder->getBlock()); break; } - + + // We don't handle default arguments either yet, but we can fake it + // for now by just skipping them. + case Stmt::CXXDefaultArgExprClass: { + Dst.Add(Pred); + break; + } + case Stmt::ParenExprClass: llvm_unreachable("ParenExprs already handled."); + case Stmt::GenericSelectionExprClass: + llvm_unreachable("GenericSelectionExprs already handled."); // Cases that should never be evaluated simply because they shouldn't // appear in the CFG. case Stmt::BreakStmtClass: @@ -879,11 +472,15 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, case Stmt::ContinueStmtClass: case Stmt::DefaultStmtClass: case Stmt::DoStmtClass: + case Stmt::ForStmtClass: case Stmt::GotoStmtClass: + case Stmt::IfStmtClass: case Stmt::IndirectGotoStmtClass: case Stmt::LabelStmtClass: case Stmt::NoStmtClass: case Stmt::NullStmtClass: + case Stmt::SwitchStmtClass: + case Stmt::WhileStmtClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); break; @@ -927,8 +524,10 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, case Stmt::IntegerLiteralClass: case Stmt::CharacterLiteralClass: case Stmt::CXXBoolLiteralExprClass: + case Stmt::ExprWithCleanupsClass: case Stmt::FloatingLiteralClass: case Stmt::SizeOfPackExprClass: + case Stmt::CXXNullPtrLiteralExprClass: Dst.Add(Pred); // No-op. Simply propagate the current state unchanged. break; @@ -974,9 +573,10 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; } - case Stmt::CallExprClass: { - const CallExpr* C = cast<CallExpr>(S); - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); + case Stmt::CallExprClass: + case Stmt::CXXOperatorCallExprClass: + case Stmt::CXXMemberCallExprClass: { + VisitCallExpr(cast<CallExpr>(S), Pred, Dst); break; } @@ -988,18 +588,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; } - case Stmt::CXXMemberCallExprClass: { - const CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S); - VisitCXXMemberCallExpr(MCE, Pred, Dst); - break; - } - - case Stmt::CXXOperatorCallExprClass: { - const CXXOperatorCallExpr *C = cast<CXXOperatorCallExpr>(S); - VisitCXXOperatorCallExpr(C, Pred, Dst); - break; - } - case Stmt::CXXNewExprClass: { const CXXNewExpr *NE = cast<CXXNewExpr>(S); VisitCXXNewExpr(NE, Pred, Dst); @@ -1050,12 +638,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst); break; - case Stmt::ForStmtClass: - // This case isn't for branch processing, but for handling the - // initialization of a condition variable. - VisitCondInit(cast<ForStmt>(S)->getConditionVariable(), S, Pred, Dst); - break; - case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: case Stmt::CXXStaticCastExprClass: @@ -1068,12 +650,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; } - case Stmt::IfStmtClass: - // This case isn't for branch processing, but for handling the - // initialization of a condition variable. - VisitCondInit(cast<IfStmt>(S)->getConditionVariable(), S, Pred, Dst); - break; - case Stmt::InitListExprClass: VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst); break; @@ -1110,8 +686,9 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst); break; - case Stmt::SizeOfAlignOfExprClass: - VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst); + case Stmt::UnaryExprOrTypeTraitExprClass: + VisitUnaryExprOrTypeTraitExpr(cast<UnaryExprOrTypeTraitExpr>(S), + Pred, Dst); break; case Stmt::StmtExprClass: { @@ -1142,12 +719,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, return; } - case Stmt::SwitchStmtClass: - // This case isn't for branch processing, but for handling the - // initialization of a condition variable. - VisitCondInit(cast<SwitchStmt>(S)->getConditionVariable(), S, Pred, Dst); - break; - case Stmt::UnaryOperatorClass: { const UnaryOperator *U = cast<UnaryOperator>(S); if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UO_LNot)) { @@ -1159,12 +730,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, VisitUnaryOperator(U, Pred, Dst); break; } - - case Stmt::WhileStmtClass: - // This case isn't for branch processing, but for handling the - // initialization of a condition variable. - VisitCondInit(cast<WhileStmt>(S)->getConditionVariable(), S, Pred, Dst); - break; } } @@ -1313,11 +878,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term, Condition->getLocStart(), "Error evaluating branch"); - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { - void *tag = I->first; - Checker *checker = I->second; - checker->VisitBranchCondition(builder, *this, Condition, tag); - } + getCheckerManager().runCheckersForBranchCondition(Condition, builder, *this); // If the branch condition is undefined, return; if (!builder.isFeasible(true) && !builder.isFeasible(false)) @@ -1326,7 +887,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term, const GRState* PrevState = builder.getState(); SVal X = PrevState->getSVal(Condition); - if (X.isUnknown()) { + if (X.isUnknownOrUndef()) { // Give it a chance to recover from unknown. if (const Expr *Ex = dyn_cast<Expr>(Condition)) { if (Ex->getType()->isIntegerType()) { @@ -1344,7 +905,7 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term, } } // If the condition is still unknown, give up. - if (X.isUnknown()) { + if (X.isUnknownOrUndef()) { builder.generateNode(MarkBranch(PrevState, Term, true), true); builder.generateNode(MarkBranch(PrevState, Term, false), false); return; @@ -1441,12 +1002,6 @@ void ExprEngine::VisitGuardedExpr(const Expr* Ex, const Expr* L, void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) { getTF().evalEndPath(*this, builder); StateMgr.EndPath(builder.getState()); - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){ - void *tag = I->first; - Checker *checker = I->second; - EndOfFunctionNodeBuilder B = builder.withCheckerTag(tag); - checker->evalEndPath(B, tag, *this); - } getCheckerManager().runCheckersForEndPath(builder, *this); } @@ -1473,6 +1028,10 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { bool defaultIsFeasible = I == EI; for ( ; I != EI; ++I) { + // Successor may be pruned out during CFG construction. + if (!I.getBlock()) + continue; + const CaseStmt* Case = I.getCase(); // Evaluate the LHS of the case value. @@ -1666,7 +1225,7 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, ProgramPoint::PostLValueKind); // Post-visit the BlockExpr. - CheckerVisit(BE, Dst, Tmp, PostVisitStmtCallback); + getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); } void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, @@ -1723,7 +1282,7 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* A, ExplodedNodeSet Tmp2; Visit(Idx, *I1, Tmp2); // Evaluate the index. ExplodedNodeSet Tmp3; - CheckerVisit(A, Tmp3, Tmp2, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(Tmp3, Tmp2, A, *this); for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) { const GRState* state = GetState(*I2); @@ -1784,7 +1343,8 @@ void ExprEngine::evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, // Do a previsit of the bind. ExplodedNodeSet CheckedSet, Src; Src.Add(Pred); - CheckerVisitBind(StoreE, CheckedSet, Src, location, Val, true); + getCheckerManager().runCheckersForBind(CheckedSet, Src, location, Val, StoreE, + *this); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I!=E; ++I) { @@ -1862,7 +1422,8 @@ void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE, if (Tmp.empty()) return; - assert(!location.isUndef()); + if (location.isUndef()) + return; SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind, ProgramPoint::PostStoreKind); @@ -1922,7 +1483,8 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex, if (Tmp.empty()) return; - assert(!location.isUndef()); + if (location.isUndef()) + return; SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind); @@ -1955,57 +1517,36 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, return; } - if (Checkers.empty()) { - ExplodedNodeSet Src; - if (Builder->GetState(Pred) == state) { - Src.Add(Pred); - } else { - // Associate this new state with an ExplodedNode. - Src.Add(Builder->generateNode(S, state, Pred)); - } - getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S, - *this); - return; - } - ExplodedNodeSet Src; - Src.Add(Pred); - ExplodedNodeSet CheckersV1Dst; - ExplodedNodeSet Tmp; - ExplodedNodeSet *PrevSet = &Src; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) - { - ExplodedNodeSet *CurrSet = 0; - if (I+1 == E) - CurrSet = &CheckersV1Dst; - else { - CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); - } - - void *tag = I->first; - Checker *checker = I->second; - - for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) { - // Use the 'state' argument only when the predecessor node is the - // same as Pred. This allows us to catch updates to the state. - checker->GR_visitLocation(*CurrSet, *Builder, *this, S, *NI, - *NI == Pred ? state : GetState(*NI), - location, tag, isLoad); - } - - // Update which NodeSet is the current one. - PrevSet = CurrSet; + if (Builder->GetState(Pred) == state) { + Src.Add(Pred); + } else { + // Associate this new state with an ExplodedNode. + // FIXME: If I pass null tag, the graph is incorrect, e.g for + // int *p; + // p = 0; + // *p = 0xDEADBEEF; + // "p = 0" is not noted as "Null pointer value stored to 'p'" but + // instead "int *p" is noted as + // "Variable 'p' initialized to a null pointer value" + ExplodedNode *N = Builder->generateNode(S, state, Pred, this); + Src.Add(N ? N : Pred); } - - getCheckerManager().runCheckersForLocation(Dst, CheckersV1Dst, location, - isLoad, S, *this); + getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S, + *this); } bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred) { + return false; + + // Inlining isn't correct right now because we: + // (a) don't generate CallExit nodes. + // (b) we need a way to postpone doing post-visits of CallExprs until + // the CallExit. This means we need CallExits for the non-inline + // cases as well. + +#if 0 const GRState *state = GetState(Pred); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); @@ -2014,6 +1555,29 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, if (!FD) return false; + // Specially handle CXXMethods. + const CXXMethodDecl *methodDecl = 0; + + switch (CE->getStmtClass()) { + default: break; + case Stmt::CXXOperatorCallExprClass: { + const CXXOperatorCallExpr *opCall = cast<CXXOperatorCallExpr>(CE); + methodDecl = + llvm::dyn_cast_or_null<CXXMethodDecl>(opCall->getCalleeDecl()); + break; + } + case Stmt::CXXMemberCallExprClass: { + const CXXMemberCallExpr *memberCall = cast<CXXMemberCallExpr>(CE); + const MemberExpr *memberExpr = + cast<MemberExpr>(memberCall->getCallee()->IgnoreParens()); + methodDecl = cast<CXXMethodDecl>(memberExpr->getMemberDecl()); + break; + } + } + + + + // Check if the function definition is in the same translation unit. if (FD->hasBody(FD)) { const StackFrameContext *stackFrame = @@ -2041,14 +1605,15 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, Dst.Add(N); return true; } + + // Generate the CallExit node. return false; +#endif } -void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred, - CallExpr::const_arg_iterator AI, - CallExpr::const_arg_iterator AE, - ExplodedNodeSet& Dst) { +void ExprEngine::VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred, + ExplodedNodeSet& dst) { // Determine the type of function we're calling (if available). const FunctionProtoType *Proto = NULL; @@ -2056,72 +1621,78 @@ void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred, if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>(); - // Evaluate the arguments. - ExplodedNodeSet ArgsEvaluated; - evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, ArgsEvaluated); - - // Now process the call itself. - ExplodedNodeSet DstTmp; - const Expr* Callee = CE->getCallee()->IgnoreParens(); - - for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(), - NE=ArgsEvaluated.end(); NI != NE; ++NI) { - // Evaluate the callee. - ExplodedNodeSet DstTmp2; - Visit(Callee, *NI, DstTmp2); - // Perform the previsit of the CallExpr, storing the results in DstTmp. - CheckerVisit(CE, DstTmp, DstTmp2, PreVisitStmtCallback); + // Should the first argument be evaluated as an lvalue? + bool firstArgumentAsLvalue = false; + switch (CE->getStmtClass()) { + case Stmt::CXXOperatorCallExprClass: + firstArgumentAsLvalue = true; + break; + default: + break; } + + // Evaluate the arguments. + ExplodedNodeSet dstArgsEvaluated; + evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, dstArgsEvaluated, + firstArgumentAsLvalue); + + // Evaluate the callee. + ExplodedNodeSet dstCalleeEvaluated; + evalCallee(CE, dstArgsEvaluated, dstCalleeEvaluated); + + // Perform the previsit of the CallExpr. + ExplodedNodeSet dstPreVisit; + getCheckerManager().runCheckersForPreStmt(dstPreVisit, dstCalleeEvaluated, + CE, *this); + + // Now evaluate the call itself. + class DefaultEval : public GraphExpander { + ExprEngine &Eng; + const CallExpr *CE; + public: + + DefaultEval(ExprEngine &eng, const CallExpr *ce) + : Eng(eng), CE(ce) {} + virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) { + // Should we inline the call? + if (Eng.getAnalysisManager().shouldInlineCall() && + Eng.InlineCall(Dst, CE, Pred)) { + return; + } - // Finally, evaluate the function call. We try each of the checkers - // to see if the can evaluate the function call. - ExplodedNodeSet DstTmp3; - - for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); - DI != DE; ++DI) { + StmtNodeBuilder &Builder = Eng.getBuilder(); + assert(&Builder && "StmtNodeBuilder must be defined."); - const GRState* state = GetState(*DI); - SVal L = state->getSVal(Callee); + // Dispatch to the plug-in transfer function. + unsigned oldSize = Dst.size(); + SaveOr OldHasGen(Builder.hasGeneratedNode); - // FIXME: Add support for symbolic function calls (calls involving - // function pointer values that are symbolic). - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - ExplodedNodeSet DstChecker; + // Dispatch to transfer function logic to handle the call itself. + const Expr* Callee = CE->getCallee()->IgnoreParens(); + const GRState* state = Eng.GetState(Pred); + SVal L = state->getSVal(Callee); + Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred); - // If the callee is processed by a checker, skip the rest logic. - if (CheckerEvalCall(CE, DstChecker, *DI)) - DstTmp3.insert(DstChecker); - else if (AMgr.shouldInlineCall() && InlineCall(Dst, CE, *DI)) { - // Callee is inlined. We shouldn't do post call checking. - return; - } - else { - for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(), - DE_Checker = DstChecker.end(); - DI_Checker != DE_Checker; ++DI_Checker) { - - // Dispatch to the plug-in transfer function. - unsigned oldSize = DstTmp3.size(); - SaveOr OldHasGen(Builder->hasGeneratedNode); - Pred = *DI_Checker; - - // Dispatch to transfer function logic to handle the call itself. - // FIXME: Allow us to chain together transfer functions. - assert(Builder && "StmtNodeBuilder must be defined."); - getTF().evalCall(DstTmp3, *this, *Builder, CE, L, Pred); - - // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. - if (!Builder->BuildSinks && DstTmp3.size() == oldSize && - !Builder->hasGeneratedNode) - MakeNode(DstTmp3, CE, Pred, state); - } + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!Builder.BuildSinks && Dst.size() == oldSize && + !Builder.hasGeneratedNode) + Eng.MakeNode(Dst, CE, Pred, state); } - } + }; + + // Finally, evaluate the function call. We try each of the checkers + // to see if the can evaluate the function call. + ExplodedNodeSet dstCallEvaluated; + DefaultEval defEval(*this, CE); + getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, + dstPreVisit, + CE, *this, &defEval); // Finally, perform the post-condition check of the CallExpr and store // the created nodes in 'Dst'. - CheckerVisit(CE, Dst, DstTmp3, PostVisitStmtCallback); + getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE, + *this); } //===----------------------------------------------------------------------===// @@ -2213,7 +1784,7 @@ void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, // Pre-visit the ObjCAtSynchronizedStmt. ExplodedNodeSet Tmp; Tmp.Add(Pred); - CheckerVisit(S, Dst, Tmp, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(Dst, Tmp, S, *this); } //===----------------------------------------------------------------------===// @@ -2244,7 +1815,7 @@ void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* Ex, // Perform the post-condition check of the ObjCIvarRefExpr and store // the created nodes in 'Dst'. - CheckerVisit(Ex, Dst, dstIvar, PostVisitStmtCallback); + getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this); } //===----------------------------------------------------------------------===// @@ -2414,7 +1985,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, // Handle the previsits checks. ExplodedNodeSet DstPrevisit; - CheckerVisitObjCMessage(msg, DstPrevisit, Src, /*isPreVisit=*/true); + getCheckerManager().runCheckersForPreObjCMessage(DstPrevisit, Src, msg,*this); // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; @@ -2430,33 +2001,34 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, if (const Expr *Receiver = msg.getInstanceReceiver()) { const GRState *state = GetState(Pred); - - // Bifurcate the state into nil and non-nil ones. - DefinedOrUnknownSVal receiverVal = - cast<DefinedOrUnknownSVal>(state->getSVal(Receiver)); - - const GRState *notNilState, *nilState; - llvm::tie(notNilState, nilState) = state->assume(receiverVal); - - // There are three cases: can be nil or non-nil, must be nil, must be - // non-nil. We handle must be nil, and merge the rest two into non-nil. - if (nilState && !notNilState) { - CheckerEvalNilReceiver(msg, dstEval, nilState, Pred); - continue; + SVal recVal = state->getSVal(Receiver); + if (!recVal.isUndef()) { + // Bifurcate the state into nil and non-nil ones. + DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal); + + const GRState *notNilState, *nilState; + llvm::tie(notNilState, nilState) = state->assume(receiverVal); + + // There are three cases: can be nil or non-nil, must be nil, must be + // non-nil. We ignore must be nil, and merge the rest two into non-nil. + if (nilState && !notNilState) { + dstEval.insert(Pred); + continue; + } + + // Check if the "raise" message was sent. + assert(notNilState); + if (msg.getSelector() == RaiseSel) + RaisesException = true; + + // Check if we raise an exception. For now treat these as sinks. + // Eventually we will want to handle exceptions properly. + if (RaisesException) + Builder->BuildSinks = true; + + // Dispatch to plug-in transfer function. + evalObjCMessage(dstEval, msg, Pred, notNilState); } - - // Check if the "raise" message was sent. - assert(notNilState); - if (msg.getSelector() == RaiseSel) - RaisesException = true; - - // Check if we raise an exception. For now treat these as sinks. - // Eventually we will want to handle exceptions properly. - if (RaisesException) - Builder->BuildSinks = true; - - // Dispatch to plug-in transfer function. - evalObjCMessage(dstEval, msg, Pred, notNilState); } else if (const ObjCInterfaceDecl *Iface = msg.getReceiverInterface()) { IdentifierInfo* ClsName = Iface->getIdentifier(); @@ -2516,7 +2088,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. - CheckerVisitObjCMessage(msg, Dst, dstEval, /*isPreVisit=*/false); + getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this); } //===----------------------------------------------------------------------===// @@ -2529,7 +2101,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNodeSet S1; Visit(Ex, Pred, S1); ExplodedNodeSet S2; - CheckerVisit(CastE, S2, S1, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(S2, S1, CastE, *this); if (CastE->getCastKind() == CK_LValueToRValue || CastE->getCastKind() == CK_GetObjCProperty) { @@ -2547,106 +2119,95 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) T = ExCast->getTypeAsWritten(); - -#if 0 - // If we are evaluating the cast in an lvalue context, we implicitly want - // the cast to evaluate to a location. - if (asLValue) { - ASTContext &Ctx = getContext(); - T = Ctx.getPointerType(Ctx.getCanonicalType(T)); - ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy)); - } -#endif - - switch (CastE->getCastKind()) { - case CK_ToVoid: - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) - Dst.Add(*I); - return; - - case CK_LValueToRValue: - case CK_NoOp: - case CK_FunctionToPointerDecay: - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { - // Copy the SVal of Ex to CastE. - ExplodedNode *N = *I; - const GRState *state = GetState(N); - SVal V = state->getSVal(Ex); - state = state->BindExpr(CastE, V); - MakeNode(Dst, CastE, N, state); - } - return; - case CK_GetObjCProperty: - case CK_Dependent: - case CK_ArrayToPointerDecay: - case CK_BitCast: - case CK_LValueBitCast: - case CK_IntegralCast: - case CK_NullToPointer: - case CK_IntegralToPointer: - case CK_PointerToIntegral: - case CK_PointerToBoolean: - case CK_IntegralToBoolean: - case CK_IntegralToFloating: - case CK_FloatingToIntegral: - case CK_FloatingToBoolean: - case CK_FloatingCast: - case CK_FloatingRealToComplex: - case CK_FloatingComplexToReal: - case CK_FloatingComplexToBoolean: - case CK_FloatingComplexCast: - case CK_FloatingComplexToIntegralComplex: - case CK_IntegralRealToComplex: - case CK_IntegralComplexToReal: - case CK_IntegralComplexToBoolean: - case CK_IntegralComplexCast: - case CK_IntegralComplexToFloatingComplex: - case CK_AnyPointerToObjCPointerCast: - case CK_AnyPointerToBlockPointerCast: - - case CK_ObjCObjectLValueCast: { - // Delegate to SValBuilder to process. - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { - ExplodedNode* N = *I; - const GRState* state = GetState(N); - SVal V = state->getSVal(Ex); - V = svalBuilder.evalCast(V, T, ExTy); - state = state->BindExpr(CastE, V); - MakeNode(Dst, CastE, N, state); - } - return; - } + for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { + Pred = *I; - case CK_DerivedToBase: - case CK_UncheckedDerivedToBase: - // For DerivedToBase cast, delegate to the store manager. - for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) { - ExplodedNode *node = *I; - const GRState *state = GetState(node); - SVal val = state->getSVal(Ex); - val = getStoreManager().evalDerivedToBase(val, T); - state = state->BindExpr(CastE, val); - MakeNode(Dst, CastE, node, state); + switch (CastE->getCastKind()) { + case CK_ToVoid: + Dst.Add(Pred); + continue; + case CK_LValueToRValue: + case CK_NoOp: + case CK_FunctionToPointerDecay: { + // Copy the SVal of Ex to CastE. + const GRState *state = GetState(Pred); + SVal V = state->getSVal(Ex); + state = state->BindExpr(CastE, V); + MakeNode(Dst, CastE, Pred, state); + continue; + } + case CK_GetObjCProperty: + case CK_Dependent: + case CK_ArrayToPointerDecay: + case CK_BitCast: + case CK_LValueBitCast: + case CK_IntegralCast: + case CK_NullToPointer: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_PointerToBoolean: + case CK_IntegralToBoolean: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingToBoolean: + case CK_FloatingCast: + case CK_FloatingRealToComplex: + case CK_FloatingComplexToReal: + case CK_FloatingComplexToBoolean: + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralRealToComplex: + case CK_IntegralComplexToReal: + case CK_IntegralComplexToBoolean: + case CK_IntegralComplexCast: + case CK_IntegralComplexToFloatingComplex: + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_ObjCObjectLValueCast: { + // Delegate to SValBuilder to process. + const GRState* state = GetState(Pred); + SVal V = state->getSVal(Ex); + V = svalBuilder.evalCast(V, T, ExTy); + state = state->BindExpr(CastE, V); + MakeNode(Dst, CastE, Pred, state); + continue; + } + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: { + // For DerivedToBase cast, delegate to the store manager. + const GRState *state = GetState(Pred); + SVal val = state->getSVal(Ex); + val = getStoreManager().evalDerivedToBase(val, T); + state = state->BindExpr(CastE, val); + MakeNode(Dst, CastE, Pred, state); + continue; + } + // Various C++ casts that are not handled yet. + case CK_Dynamic: + case CK_ToUnion: + case CK_BaseToDerived: + case CK_NullToMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_UserDefinedConversion: + case CK_ConstructorConversion: + case CK_VectorSplat: + case CK_MemberPointerToBoolean: { + // Recover some path-sensitivty by conjuring a new value. + QualType resultType = CastE->getType(); + if (CastE->isLValue()) + resultType = getContext().getPointerType(resultType); + + SVal result = + svalBuilder.getConjuredSymbolVal(NULL, CastE, resultType, + Builder->getCurrentBlockCount()); + + const GRState *state = GetState(Pred)->BindExpr(CastE, result); + MakeNode(Dst, CastE, Pred, state); + continue; + } } - return; - - // Various C++ casts that are not handled yet. - case CK_Dynamic: - case CK_ToUnion: - case CK_BaseToDerived: - case CK_NullToMemberPointer: - case CK_BaseToDerivedMemberPointer: - case CK_DerivedToBaseMemberPointer: - case CK_UserDefinedConversion: - case CK_ConstructorConversion: - case CK_VectorSplat: - case CK_MemberPointerToBoolean: { - SaveAndRestore<bool> OldSink(Builder->BuildSinks); - Builder->BuildSinks = true; - MakeNode(Dst, CastE, Pred, GetState(Pred)); - return; - } } } @@ -2702,7 +2263,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, Tmp.Add(Pred); ExplodedNodeSet Tmp2; - CheckerVisit(DS, Tmp2, Tmp, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(Tmp2, Tmp, DS, *this); for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) { ExplodedNode *N = *I; @@ -2741,33 +2302,6 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, } } -void ExprEngine::VisitCondInit(const VarDecl *VD, const Stmt *S, - ExplodedNode *Pred, ExplodedNodeSet& Dst) { - - const Expr* InitEx = VD->getInit(); - ExplodedNodeSet Tmp; - Visit(InitEx, Pred, Tmp); - - for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - ExplodedNode *N = *I; - const GRState *state = GetState(N); - - const LocationContext *LC = N->getLocationContext(); - SVal InitVal = state->getSVal(InitEx); - - // Recover some path-sensitivity if a scalar value evaluated to - // UnknownVal. - if (InitVal.isUnknown() || - !getConstraintManager().canReasonAbout(InitVal)) { - InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, - Builder->getCurrentBlockCount()); - } - - evalBind(Dst, S, N, state, - loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true); - } -} - namespace { // This class is used by VisitInitListExpr as an item in a worklist // for processing the values contained in an InitListExpr. @@ -2861,19 +2395,15 @@ void ExprEngine::VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred, assert(0 && "unprocessed InitListExpr type"); } -/// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type). -void ExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, +/// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof(type). +void ExprEngine::VisitUnaryExprOrTypeTraitExpr( + const UnaryExprOrTypeTraitExpr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst) { QualType T = Ex->getTypeOfArgument(); - CharUnits amt; - if (Ex->isSizeOf()) { - if (T == getContext().VoidTy) { - // sizeof(void) == 1 byte. - amt = CharUnits::One(); - } - else if (!T->isConstantSizeType()) { + if (Ex->getKind() == UETT_SizeOf) { + if (!T->isIncompleteType() && !T->isConstantSizeType()) { assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); // FIXME: Add support for VLA type arguments, not just VLA expressions. @@ -2914,13 +2444,11 @@ void ExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex, Dst.Add(Pred); return; } - else { - // All other cases. - amt = getContext().getTypeSizeInChars(T); - } } - else // Get alignment of the type. - amt = getContext().getTypeAlignInChars(T); + + Expr::EvalResult Result; + Ex->Evaluate(Result, getContext()); + CharUnits amt = CharUnits::fromQuantity(Result.Val.getInt().getZExtValue()); MakeNode(Dst, Ex, Pred, GetState(Pred)->BindExpr(Ex, @@ -3263,7 +2791,7 @@ void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, } ExplodedNodeSet CheckedSet; - CheckerVisit(RS, CheckedSet, Src, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(CheckedSet, Src, RS, *this); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) { @@ -3305,7 +2833,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, Visit(RHS, *I1, Tmp2); ExplodedNodeSet CheckedSet; - CheckerVisit(B, CheckedSet, Tmp2, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(CheckedSet, Tmp2, B, *this); // With both the LHS and RHS evaluated, process the operation itself. @@ -3432,16 +2960,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, } } - CheckerVisit(B, Dst, Tmp3, PostVisitStmtCallback); -} - -//===----------------------------------------------------------------------===// -// Checker registration/lookup. -//===----------------------------------------------------------------------===// - -Checker *ExprEngine::lookupChecker(void *tag) const { - CheckerMap::const_iterator I = CheckerM.find(tag); - return (I == CheckerM.end()) ? NULL : Checkers[I->second].second; + getCheckerManager().runCheckersForPostStmt(Dst, Tmp3, B, *this); } //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FlatStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FlatStore.cpp index 99a5ead..7bdca6b 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FlatStore.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/FlatStore.cpp @@ -90,6 +90,19 @@ StoreManager *ento::CreateFlatStoreManager(GRStateManager &StMgr) { } SVal FlatStoreManager::Retrieve(Store store, Loc L, QualType T) { + // For access to concrete addresses, return UnknownVal. Checks + // for null dereferences (and similar errors) are done by checkers, not + // the Store. + // FIXME: We can consider lazily symbolicating such memory, but we really + // should defer this when we can reason easily about symbolicating arrays + // of bytes. + if (isa<loc::ConcreteInt>(L)) { + return UnknownVal(); + } + if (!isa<loc::MemRegionVal>(L)) { + return UnknownVal(); + } + const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion(); RegionInterval RI = RegionToInterval(R); // FIXME: FlatStore should handle regions with unknown intervals. diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp index 2e370d6..c005819 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/ObjCMessage.cpp @@ -37,6 +37,35 @@ Selector ObjCMessage::getSelector() const { return propE->getGetterSelector(); } +ObjCMethodFamily ObjCMessage::getMethodFamily() const { + assert(isValid() && "This ObjCMessage is uninitialized!"); + // Case 1. Explicit message send. + if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) + return msgE->getMethodFamily(); + + const ObjCPropertyRefExpr *propE = cast<ObjCPropertyRefExpr>(MsgOrPropE); + + // Case 2. Reference to implicit property. + if (propE->isImplicitProperty()) { + if (isPropertySetter()) + return propE->getImplicitPropertySetter()->getMethodFamily(); + else + return propE->getImplicitPropertyGetter()->getMethodFamily(); + } + + // Case 3. Reference to explicit property. + const ObjCPropertyDecl *prop = propE->getExplicitProperty(); + if (isPropertySetter()) { + if (prop->getSetterMethodDecl()) + return prop->getSetterMethodDecl()->getMethodFamily(); + return prop->getSetterName().getMethodFamily(); + } else { + if (prop->getGetterMethodDecl()) + return prop->getGetterMethodDecl()->getMethodFamily(); + return prop->getGetterName().getMethodFamily(); + } +} + const ObjCMethodDecl *ObjCMessage::getMethodDecl() const { assert(isValid() && "This ObjCMessage is uninitialized!"); if (const ObjCMessageExpr *msgE = dyn_cast<ObjCMessageExpr>(MsgOrPropE)) @@ -80,13 +109,27 @@ const Expr *ObjCMessage::getArgExpr(unsigned i) const { } QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const { + QualType resultTy; + bool isLVal = false; + if (CallE) { + isLVal = CallE->isLValue(); const Expr *Callee = CallE->getCallee(); if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl()) - return FD->getResultType(); - return CallE->getType(); + resultTy = FD->getResultType(); + else + resultTy = CallE->getType(); + } + else { + isLVal = isa<ObjCMessageExpr>(Msg.getOriginExpr()) && + Msg.getOriginExpr()->isLValue(); + resultTy = Msg.getResultType(ctx); } - return Msg.getResultType(ctx); + + if (isLVal) + resultTy = ctx.getPointerType(resultTy); + + return resultTy; } SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const { @@ -97,3 +140,10 @@ SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const { return Msg.getArgSVal(i, State); return UnknownVal(); } + +SVal CallOrObjCMessage::getCXXCallee() const { + assert(isCXXCall()); + const Expr *callee = + cast<CXXMemberCallExpr>(CallE)->getImplicitObjectArgument(); + return State->getSVal(callee); +} diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 19e0e12..4522f97 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -337,6 +337,9 @@ public: // Part of public interface to class. SVal RetrieveFieldOrElementCommon(Store store, const TypedRegion *R, QualType Ty, const MemRegion *superR); + + SVal RetrieveLazyBinding(const MemRegion *lazyBindingRegion, + Store lazyBindingStore); /// Retrieve the values in a struct and return a CompoundVal, used when doing /// struct copy: @@ -355,7 +358,8 @@ public: // Part of public interface to class. /// Get the state and region whose binding this region R corresponds to. std::pair<Store, const MemRegion*> - GetLazyBinding(RegionBindings B, const MemRegion *R); + GetLazyBinding(RegionBindings B, const MemRegion *R, + const MemRegion *originalRegion); StoreRef CopyLazyBindings(nonloc::LazyCompoundVal V, Store store, const TypedRegion *R); @@ -684,11 +688,11 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { QualType T = TR->getValueType(); // Invalidate the binding. - if (T->isStructureType()) { + if (T->isStructureOrClassType()) { // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. - DefinedOrUnknownSVal V = svalBuilder.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy, - Count); + DefinedOrUnknownSVal V = + svalBuilder.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy, Count); B = RM.addBinding(B, baseR, BindingKey::Default, V); return; } @@ -976,15 +980,20 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) { } std::pair<Store, const MemRegion *> -RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) { - if (Optional<SVal> OV = getDirectBinding(B, R)) - if (const nonloc::LazyCompoundVal *V = - dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer())) - return std::make_pair(V->getStore(), V->getRegion()); - +RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R, + const MemRegion *originalRegion) { + + if (originalRegion != R) { + if (Optional<SVal> OV = getDefaultBinding(B, R)) { + if (const nonloc::LazyCompoundVal *V = + dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer())) + return std::make_pair(V->getStore(), V->getRegion()); + } + } + if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { const std::pair<Store, const MemRegion *> &X = - GetLazyBinding(B, ER->getSuperRegion()); + GetLazyBinding(B, ER->getSuperRegion(), originalRegion); if (X.second) return std::make_pair(X.first, @@ -992,7 +1001,7 @@ RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) { } else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) { const std::pair<Store, const MemRegion *> &X = - GetLazyBinding(B, FR->getSuperRegion()); + GetLazyBinding(B, FR->getSuperRegion(), originalRegion); if (X.second) return std::make_pair(X.first, @@ -1003,12 +1012,13 @@ RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) { else if (const CXXBaseObjectRegion *baseReg = dyn_cast<CXXBaseObjectRegion>(R)) { const std::pair<Store, const MemRegion *> &X = - GetLazyBinding(B, baseReg->getSuperRegion()); + GetLazyBinding(B, baseReg->getSuperRegion(), originalRegion); if (X.second) return std::make_pair(X.first, MRMgr.getCXXBaseObjectRegionWithSuper(baseReg, X.second)); } + // The NULL MemRegion indicates an non-existent lazy binding. A NULL Store is // possible for a valid lazy binding. return std::make_pair((Store) 0, (const MemRegion *) 0); @@ -1098,14 +1108,19 @@ RegionStoreManager::RetrieveDerivedDefaultValue(RegionBindings B, QualType Ty) { if (const Optional<SVal> &D = getDefaultBinding(B, superR)) { - if (SymbolRef parentSym = D->getAsSymbol()) + const SVal &val = D.getValue(); + if (SymbolRef parentSym = val.getAsSymbol()) return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R); - if (D->isZeroConstant()) + if (val.isZeroConstant()) return svalBuilder.makeZeroVal(Ty); - if (D->isUnknownOrUndef()) - return *D; + if (val.isUnknownOrUndef()) + return val; + + // Lazy bindings are handled later. + if (isa<nonloc::LazyCompoundVal>(val)) + return Optional<SVal>(); assert(0 && "Unknown default value"); } @@ -1113,6 +1128,15 @@ RegionStoreManager::RetrieveDerivedDefaultValue(RegionBindings B, return Optional<SVal>(); } +SVal RegionStoreManager::RetrieveLazyBinding(const MemRegion *lazyBindingRegion, + Store lazyBindingStore) { + if (const ElementRegion *ER = dyn_cast<ElementRegion>(lazyBindingRegion)) + return RetrieveElement(lazyBindingStore, ER); + + return RetrieveField(lazyBindingStore, + cast<FieldRegion>(lazyBindingRegion)); +} + SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store, const TypedRegion *R, QualType Ty, @@ -1140,14 +1164,10 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(Store store, // Lazy binding? Store lazyBindingStore = NULL; const MemRegion *lazyBindingRegion = NULL; - llvm::tie(lazyBindingStore, lazyBindingRegion) = GetLazyBinding(B, R); + llvm::tie(lazyBindingStore, lazyBindingRegion) = GetLazyBinding(B, R, R); - if (lazyBindingRegion) { - if (const ElementRegion *ER = dyn_cast<ElementRegion>(lazyBindingRegion)) - return RetrieveElement(lazyBindingStore, ER); - return RetrieveField(lazyBindingStore, - cast<FieldRegion>(lazyBindingRegion)); - } + if (lazyBindingRegion) + return RetrieveLazyBinding(lazyBindingRegion, lazyBindingStore); if (R->hasStackNonParametersStorage()) { if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { @@ -1250,12 +1270,12 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) { SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) { QualType T = R->getValueType(); assert(T->isStructureOrClassType()); - return svalBuilder.makeLazyCompoundVal(store, R); + return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R); } SVal RegionStoreManager::RetrieveArray(Store store, const TypedRegion * R) { assert(Ctx.getAsConstantArrayType(R->getValueType())); - return svalBuilder.makeLazyCompoundVal(store, R); + return svalBuilder.makeLazyCompoundVal(StoreRef(store, *this), R); } //===----------------------------------------------------------------------===// @@ -1378,7 +1398,8 @@ StoreRef RegionStoreManager::BindArray(Store store, const TypedRegion* R, // Treat the string as a lazy compound value. nonloc::LazyCompoundVal LCV = - cast<nonloc::LazyCompoundVal>(svalBuilder.makeLazyCompoundVal(store, S)); + cast<nonloc::LazyCompoundVal>(svalBuilder. + makeLazyCompoundVal(StoreRef(store, *this), S)); return CopyLazyBindings(LCV, store, R); } @@ -1529,7 +1550,7 @@ StoreRef RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V, // Now copy the bindings. This amounts to just binding 'V' to 'R'. This // results in a zero-copy algorithm. - return StoreRef(addBinding(B, R, BindingKey::Direct, + return StoreRef(addBinding(B, R, BindingKey::Default, V).getRootWithoutRetain(), *this); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index b0fd497..71f2b4a 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -25,12 +25,12 @@ using namespace ento; // Basic SVal creation. //===----------------------------------------------------------------------===// -DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType T) { - if (Loc::isLocType(T)) +DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType type) { + if (Loc::isLocType(type)) return makeNull(); - if (T->isIntegerType()) - return makeIntVal(0, T); + if (type->isIntegerType()) + return makeIntVal(0, type); // FIXME: Handle floats. // FIXME: Handle structs. @@ -39,44 +39,44 @@ DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType T) { NonLoc SValBuilder::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, - const llvm::APSInt& v, QualType T) { + const llvm::APSInt& rhs, QualType type) { // The Environment ensures we always get a persistent APSInt in // BasicValueFactory, so we don't need to get the APSInt from // BasicValueFactory again. - assert(!Loc::isLocType(T)); - return nonloc::SymExprVal(SymMgr.getSymIntExpr(lhs, op, v, T)); + assert(!Loc::isLocType(type)); + return nonloc::SymExprVal(SymMgr.getSymIntExpr(lhs, op, rhs, type)); } NonLoc SValBuilder::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, - const SymExpr *rhs, QualType T) { + const SymExpr *rhs, QualType type) { assert(SymMgr.getType(lhs) == SymMgr.getType(rhs)); - assert(!Loc::isLocType(T)); - return nonloc::SymExprVal(SymMgr.getSymSymExpr(lhs, op, rhs, T)); + assert(!Loc::isLocType(type)); + return nonloc::SymExprVal(SymMgr.getSymSymExpr(lhs, op, rhs, type)); } -SVal SValBuilder::convertToArrayIndex(SVal V) { - if (V.isUnknownOrUndef()) - return V; +SVal SValBuilder::convertToArrayIndex(SVal val) { + if (val.isUnknownOrUndef()) + return val; // Common case: we have an appropriately sized integer. - if (nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&V)) { + if (nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&val)) { const llvm::APSInt& I = CI->getValue(); if (I.getBitWidth() == ArrayIndexWidth && I.isSigned()) - return V; + return val; } - return evalCastNL(cast<NonLoc>(V), ArrayIndexTy); + return evalCastFromNonLoc(cast<NonLoc>(val), ArrayIndexTy); } DefinedOrUnknownSVal -SValBuilder::getRegionValueSymbolVal(const TypedRegion* R) { - QualType T = R->getValueType(); +SValBuilder::getRegionValueSymbolVal(const TypedRegion* region) { + QualType T = region->getValueType(); if (!SymbolManager::canSymbolicate(T)) return UnknownVal(); - SymbolRef sym = SymMgr.getRegionValueSymbol(R); + SymbolRef sym = SymMgr.getRegionValueSymbol(region); if (Loc::isLocType(T)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); @@ -84,15 +84,15 @@ SValBuilder::getRegionValueSymbolVal(const TypedRegion* R) { return nonloc::SymbolVal(sym); } -DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *SymbolTag, - const Expr *E, - unsigned Count) { - QualType T = E->getType(); +DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *symbolTag, + const Expr *expr, + unsigned count) { + QualType T = expr->getType(); if (!SymbolManager::canSymbolicate(T)) return UnknownVal(); - SymbolRef sym = SymMgr.getConjuredSymbol(E, Count, SymbolTag); + SymbolRef sym = SymMgr.getConjuredSymbol(expr, count, symbolTag); if (Loc::isLocType(T)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); @@ -100,31 +100,32 @@ DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *SymbolTag, return nonloc::SymbolVal(sym); } -DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *SymbolTag, - const Expr *E, - QualType T, - unsigned Count) { +DefinedOrUnknownSVal SValBuilder::getConjuredSymbolVal(const void *symbolTag, + const Expr *expr, + QualType type, + unsigned count) { - if (!SymbolManager::canSymbolicate(T)) + if (!SymbolManager::canSymbolicate(type)) return UnknownVal(); - SymbolRef sym = SymMgr.getConjuredSymbol(E, T, Count, SymbolTag); + SymbolRef sym = SymMgr.getConjuredSymbol(expr, type, count, symbolTag); - if (Loc::isLocType(T)) + if (Loc::isLocType(type)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); return nonloc::SymbolVal(sym); } -DefinedSVal SValBuilder::getMetadataSymbolVal(const void *SymbolTag, - const MemRegion *MR, - const Expr *E, QualType T, - unsigned Count) { - assert(SymbolManager::canSymbolicate(T) && "Invalid metadata symbol type"); +DefinedSVal SValBuilder::getMetadataSymbolVal(const void *symbolTag, + const MemRegion *region, + const Expr *expr, QualType type, + unsigned count) { + assert(SymbolManager::canSymbolicate(type) && "Invalid metadata symbol type"); - SymbolRef sym = SymMgr.getMetadataSymbol(MR, E, T, Count, SymbolTag); + SymbolRef sym = + SymMgr.getMetadataSymbol(region, expr, type, count, symbolTag); - if (Loc::isLocType(T)) + if (Loc::isLocType(type)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); return nonloc::SymbolVal(sym); @@ -132,13 +133,13 @@ DefinedSVal SValBuilder::getMetadataSymbolVal(const void *SymbolTag, DefinedOrUnknownSVal SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, - const TypedRegion *R) { - QualType T = R->getValueType(); + const TypedRegion *region) { + QualType T = region->getValueType(); if (!SymbolManager::canSymbolicate(T)) return UnknownVal(); - SymbolRef sym = SymMgr.getDerivedSymbol(parentSymbol, R); + SymbolRef sym = SymMgr.getDerivedSymbol(parentSymbol, region); if (Loc::isLocType(T)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); @@ -146,53 +147,53 @@ SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, return nonloc::SymbolVal(sym); } -DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl* FD) { - return loc::MemRegionVal(MemMgr.getFunctionTextRegion(FD)); +DefinedSVal SValBuilder::getFunctionPointer(const FunctionDecl* func) { + return loc::MemRegionVal(MemMgr.getFunctionTextRegion(func)); } -DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *D, - CanQualType locTy, - const LocationContext *LC) { +DefinedSVal SValBuilder::getBlockPointer(const BlockDecl *block, + CanQualType locTy, + const LocationContext *locContext) { const BlockTextRegion *BC = - MemMgr.getBlockTextRegion(D, locTy, LC->getAnalysisContext()); - const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC); + MemMgr.getBlockTextRegion(block, locTy, locContext->getAnalysisContext()); + const BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, locContext); return loc::MemRegionVal(BD); } //===----------------------------------------------------------------------===// -SVal SValBuilder::evalBinOp(const GRState *ST, BinaryOperator::Opcode Op, - SVal L, SVal R, QualType T) { +SVal SValBuilder::evalBinOp(const GRState *state, BinaryOperator::Opcode op, + SVal lhs, SVal rhs, QualType type) { - if (L.isUndef() || R.isUndef()) + if (lhs.isUndef() || rhs.isUndef()) return UndefinedVal(); - if (L.isUnknown() || R.isUnknown()) + if (lhs.isUnknown() || rhs.isUnknown()) return UnknownVal(); - if (isa<Loc>(L)) { - if (isa<Loc>(R)) - return evalBinOpLL(ST, Op, cast<Loc>(L), cast<Loc>(R), T); + if (isa<Loc>(lhs)) { + if (isa<Loc>(rhs)) + return evalBinOpLL(state, op, cast<Loc>(lhs), cast<Loc>(rhs), type); - return evalBinOpLN(ST, Op, cast<Loc>(L), cast<NonLoc>(R), T); + return evalBinOpLN(state, op, cast<Loc>(lhs), cast<NonLoc>(rhs), type); } - if (isa<Loc>(R)) { + if (isa<Loc>(rhs)) { // Support pointer arithmetic where the addend is on the left // and the pointer on the right. - assert(Op == BO_Add); + assert(op == BO_Add); // Commute the operands. - return evalBinOpLN(ST, Op, cast<Loc>(R), cast<NonLoc>(L), T); + return evalBinOpLN(state, op, cast<Loc>(rhs), cast<NonLoc>(lhs), type); } - return evalBinOpNN(ST, Op, cast<NonLoc>(L), cast<NonLoc>(R), T); + return evalBinOpNN(state, op, cast<NonLoc>(lhs), cast<NonLoc>(rhs), type); } -DefinedOrUnknownSVal SValBuilder::evalEQ(const GRState *ST, - DefinedOrUnknownSVal L, - DefinedOrUnknownSVal R) { - return cast<DefinedOrUnknownSVal>(evalBinOp(ST, BO_EQ, L, R, +DefinedOrUnknownSVal SValBuilder::evalEQ(const GRState *state, + DefinedOrUnknownSVal lhs, + DefinedOrUnknownSVal rhs) { + return cast<DefinedOrUnknownSVal>(evalBinOp(state, BO_EQ, lhs, rhs, Context.IntTy)); } @@ -213,11 +214,11 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { // Check for casts from integers to integers. if (castTy->isIntegerType() && originalTy->isIntegerType()) - return evalCastNL(cast<NonLoc>(val), castTy); + return evalCastFromNonLoc(cast<NonLoc>(val), castTy); // Check for casts from pointers to integers. if (castTy->isIntegerType() && Loc::isLocType(originalTy)) - return evalCastL(cast<Loc>(val), castTy); + return evalCastFromLoc(cast<Loc>(val), castTy); // Check for casts from integers to pointers. if (Loc::isLocType(castTy) && originalTy->isIntegerType()) { @@ -256,7 +257,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { // need the original decayed type. // QualType elemTy = cast<ArrayType>(originalTy)->getElementType(); // QualType pointerTy = C.getPointerType(elemTy); - return evalCastL(cast<Loc>(val), castTy); + return evalCastFromLoc(cast<Loc>(val), castTy); } // Check for casts from a region to a specific type. @@ -305,6 +306,6 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) { DispatchCast: // All other cases. - return isa<Loc>(val) ? evalCastL(cast<Loc>(val), castTy) - : evalCastNL(cast<NonLoc>(val), castTy); + return isa<Loc>(val) ? evalCastFromLoc(cast<Loc>(val), castTy) + : evalCastFromNonLoc(cast<NonLoc>(val), castTy); } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp index e0b61ab..1ee694e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp @@ -15,7 +15,6 @@ #include "SimpleConstraintManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/Checker.h" namespace clang { diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 9a46bd6..5d80251 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -20,8 +20,8 @@ using namespace ento; namespace { class SimpleSValBuilder : public SValBuilder { protected: - virtual SVal evalCastNL(NonLoc val, QualType castTy); - virtual SVal evalCastL(Loc val, QualType castTy); + virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy); + virtual SVal evalCastFromLoc(Loc val, QualType castTy); public: SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, @@ -57,7 +57,7 @@ SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc, // Transfer function for Casts. //===----------------------------------------------------------------------===// -SVal SimpleSValBuilder::evalCastNL(NonLoc val, QualType castTy) { +SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { bool isLocType = Loc::isLocType(castTy); @@ -106,7 +106,7 @@ SVal SimpleSValBuilder::evalCastNL(NonLoc val, QualType castTy) { return makeIntVal(i); } -SVal SimpleSValBuilder::evalCastL(Loc val, QualType castTy) { +SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) { // Casts from pointers -> pointers, just return the lval. // @@ -255,11 +255,12 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS, } // Idempotent ops (like a*1) can still change the type of an expression. - // Wrap the LHS up in a NonLoc again and let evalCastNL do the dirty work. + // Wrap the LHS up in a NonLoc again and let evalCastFromNonLoc do the + // dirty work. if (isIdempotent) { if (SymbolRef LHSSym = dyn_cast<SymbolData>(LHS)) - return evalCastNL(nonloc::SymbolVal(LHSSym), resultTy); - return evalCastNL(nonloc::SymExprVal(LHS), resultTy); + return evalCastFromNonLoc(nonloc::SymbolVal(LHSSym), resultTy); + return evalCastFromNonLoc(nonloc::SymExprVal(LHS), resultTy); } // If we reach this point, the expression cannot be simplified. @@ -289,7 +290,7 @@ SVal SimpleSValBuilder::evalBinOpNN(const GRState *state, return makeIntVal(0, resultTy); case BO_Or: case BO_And: - return evalCastNL(lhs, resultTy); + return evalCastFromNonLoc(lhs, resultTy); } while (1) { @@ -552,7 +553,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state, default: break; case BO_Sub: - return evalCastL(lhs, resultTy); + return evalCastFromLoc(lhs, resultTy); case BO_EQ: case BO_LE: case BO_LT: @@ -588,7 +589,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state, SVal ResultVal = cast<loc::ConcreteInt>(lhs).evalBinOp(BasicVals, op, *rInt); if (Loc *Result = dyn_cast<Loc>(&ResultVal)) - return evalCastL(*Result, resultTy); + return evalCastFromLoc(*Result, resultTy); else return UnknownVal(); } @@ -633,7 +634,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state, default: break; case BO_Sub: - return evalCastL(lhs, resultTy); + return evalCastFromLoc(lhs, resultTy); case BO_EQ: case BO_LT: case BO_LE: @@ -698,7 +699,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state, NonLoc *LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal); if (!LeftIndex) return UnknownVal(); - LeftIndexVal = evalCastNL(*LeftIndex, resultTy); + LeftIndexVal = evalCastFromNonLoc(*LeftIndex, resultTy); LeftIndex = dyn_cast<NonLoc>(&LeftIndexVal); if (!LeftIndex) return UnknownVal(); @@ -708,7 +709,7 @@ SVal SimpleSValBuilder::evalBinOpLL(const GRState *state, NonLoc *RightIndex = dyn_cast<NonLoc>(&RightIndexVal); if (!RightIndex) return UnknownVal(); - RightIndexVal = evalCastNL(*RightIndex, resultTy); + RightIndexVal = evalCastFromNonLoc(*RightIndex, resultTy); RightIndex = dyn_cast<NonLoc>(&RightIndexVal); if (!RightIndex) return UnknownVal(); @@ -872,7 +873,8 @@ SVal SimpleSValBuilder::evalBinOpLN(const GRState *state, QualType elementType; if (const ElementRegion *elemReg = dyn_cast<ElementRegion>(region)) { - index = evalBinOpNN(state, BO_Add, elemReg->getIndex(), rhs, + assert(op == BO_Add || op == BO_Sub); + index = evalBinOpNN(state, op, elemReg->getIndex(), rhs, getArrayIndexType()); superR = elemReg->getSuperRegion(); elementType = elemReg->getElementType(); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp index 7225170..b936738 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Core/Store.cpp @@ -230,9 +230,9 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R, } if (const Loc *L = dyn_cast<Loc>(&V)) - return svalBuilder.evalCastL(*L, castTy); + return svalBuilder.evalCastFromLoc(*L, castTy); else if (const NonLoc *NL = dyn_cast<NonLoc>(&V)) - return svalBuilder.evalCastNL(*NL, castTy); + return svalBuilder.evalCastFromNonLoc(*NL, castTy); return V; } diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index e3e7ee9..fe6e1fd 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -17,8 +17,6 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ParentMap.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/Analyses/UninitializedValues.h" #include "clang/Analysis/CFG.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" @@ -30,12 +28,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" #include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h" -// FIXME: Restructure checker registration. -#include "../Checkers/ClangSACheckers.h" -#include "../Checkers/ExperimentalChecks.h" -#include "../Checkers/InternalChecks.h" -#include "../Checkers/BasicObjCFoundationChecks.h" - #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/AnalyzerOptions.h" @@ -70,20 +62,6 @@ namespace { class AnalysisConsumer : public ASTConsumer { public: - typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); - typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M, - TranslationUnitDecl &TU); - -private: - typedef std::vector<CodeAction> Actions; - typedef std::vector<TUAction> TUActions; - - Actions FunctionActions; - Actions ObjCMethodActions; - Actions ObjCImplementationActions; - Actions CXXMethodActions; - -public: ASTContext* Ctx; const Preprocessor &PP; const std::string OutDir; @@ -163,16 +141,6 @@ public: } } - void addCodeAction(CodeAction action) { - FunctionActions.push_back(action); - ObjCMethodActions.push_back(action); - CXXMethodActions.push_back(action); - } - - void addObjCImplementationAction(CodeAction action) { - ObjCImplementationActions.push_back(action); - } - virtual void Initialize(ASTContext &Context) { Ctx = &Context; checkerMgr.reset(registerCheckers(Opts, PP.getLangOptions(), @@ -194,7 +162,7 @@ public: virtual void HandleTranslationUnit(ASTContext &C); void HandleDeclContext(ASTContext &C, DeclContext *dc); - void HandleCode(Decl *D, Actions& actions); + void HandleCode(Decl *D); }; } // end anonymous namespace @@ -228,23 +196,25 @@ void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) { FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction) break; DisplayFunction(FD); - HandleCode(FD, FunctionActions); + HandleCode(FD); } break; } case Decl::ObjCImplementation: { ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I); - HandleCode(ID, ObjCImplementationActions); + HandleCode(ID); for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(), ME = ID->meth_end(); MI != ME; ++MI) { + checkerMgr->runCheckersOnASTDecl(*MI, *Mgr, BR); + if ((*MI)->isThisDeclarationADefinition()) { if (!Opts.AnalyzeSpecificFunction.empty() && Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString()) break; DisplayFunction(*MI); - HandleCode(*MI, ObjCMethodActions); + HandleCode(*MI); } } break; @@ -279,9 +249,12 @@ static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) { FindBlocks(DC, WL); } -void AnalysisConsumer::HandleCode(Decl *D, Actions& actions) { +static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, + Decl *D); + +void AnalysisConsumer::HandleCode(Decl *D) { - // Don't run the actions if an error has occured with parsing the file. + // Don't run the actions if an error has occurred with parsing the file. Diagnostic &Diags = PP.getDiagnostics(); if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) return; @@ -306,27 +279,17 @@ void AnalysisConsumer::HandleCode(Decl *D, Actions& actions) { BugReporter BR(*Mgr); for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); WI != WE; ++WI) - if ((*WI)->hasBody()) + if ((*WI)->hasBody()) { checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR); - - for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) - for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); - WI != WE; ++WI) - (*I)(*this, *Mgr, *WI); + if (checkerMgr->hasPathSensitiveCheckers()) + ActionObjCMemChecker(*this, *Mgr, *WI); + } } //===----------------------------------------------------------------------===// -// Analyses +// Path-sensitive checking. //===----------------------------------------------------------------------===// -static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, - Decl *D) { - if (CFG* c = mgr.getCFG(D)) { - CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic()); - } -} - - static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D, TransferFuncs* tf) { @@ -340,18 +303,6 @@ static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, return; ExprEngine Eng(mgr, TF.take()); - RegisterNSErrorChecks(Eng.getBugReporter(), Eng, *D); - - if (C.Opts.EnableExperimentalChecks) - RegisterExperimentalChecks(Eng); - - if (C.Opts.BufferOverflows) - RegisterArrayBoundCheckerV2(Eng); - - // Enable AnalyzerStatsChecker if it was given as an argument - if (C.Opts.AnalyzerStats) - RegisterAnalyzerStatsChecker(Eng); - // Set the graph auditor. llvm::OwningPtr<ExplodedNode::Auditor> Auditor; if (mgr.shouldVisualizeUbigraph()) { @@ -414,16 +365,6 @@ ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp, const AnalyzerOptions& Opts) { llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts)); - for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i) - switch (Opts.AnalysisList[i]) { -#define ANALYSIS(NAME, CMD, DESC, SCOPE)\ - case NAME:\ - C->add ## SCOPE ## Action(&Action ## NAME);\ - break; -#include "clang/Frontend/Analyses.def" - default: break; - } - // Last, disable the effects of '-Werror' when using the AnalysisConsumer. pp.getDiagnostics().setWarningsAsErrors(false); diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index 677e20c..d7edc7e 100644 --- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -43,6 +43,8 @@ CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts, // FIXME: Load CheckerProviders from plugins. + checkerMgr->finishedCheckerRegistration(); + for (unsigned i = 0, e = checkerOpts.size(); i != e; ++i) { if (checkerOpts[i].isUnclaimed()) diags.Report(diag::warn_unkwown_analyzer_checker) @@ -55,9 +57,6 @@ CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts, void ento::printCheckerHelp(llvm::raw_ostream &OS) { OS << "OVERVIEW: Clang Static Analyzer Checkers List\n"; OS << '\n'; - OS << "USAGE: -analyzer-checker <check1,check2,...>\n"; - OS << '\n'; - OS << "CHECKERS:\n"; llvm::OwningPtr<CheckerProvider> provider(createClangSACheckerProvider()); provider->printHelp(OS); diff --git a/contrib/llvm/tools/clang/lib/Tooling/CMakeLists.txt b/contrib/llvm/tools/clang/lib/Tooling/CMakeLists.txt new file mode 100644 index 0000000..f52cf6c --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/CMakeLists.txt @@ -0,0 +1,6 @@ +SET(LLVM_USED_LIBS clangBasic clangFrontend clangAST) + +add_clang_library(clangTooling + JsonCompileCommandLineDatabase.cpp + Tooling.cpp + ) diff --git a/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp b/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp new file mode 100644 index 0000000..7f027cf --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp @@ -0,0 +1,214 @@ +//===--- JsonCompileCommandLineDatabase.cpp - Simple JSON database --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements reading a compile command line database, as written +// out for example by CMake. +// +//===----------------------------------------------------------------------===// + +#include "JsonCompileCommandLineDatabase.h" +#include "llvm/ADT/Twine.h" + +namespace clang { +namespace tooling { + +namespace { + +// A parser for JSON escaped strings of command line arguments with \-escaping +// for quoted arguments (see the documentation of UnescapeJsonCommandLine(...)). +class CommandLineArgumentParser { + public: + CommandLineArgumentParser(llvm::StringRef CommandLine) + : Input(CommandLine), Position(Input.begin()-1) {} + + std::vector<std::string> Parse() { + bool HasMoreInput = true; + while (HasMoreInput && NextNonWhitespace()) { + std::string Argument; + HasMoreInput = ParseStringInto(Argument); + CommandLine.push_back(Argument); + } + return CommandLine; + } + + private: + // All private methods return true if there is more input available. + + bool ParseStringInto(std::string &String) { + do { + if (*Position == '"') { + if (!ParseQuotedStringInto(String)) return false; + } else { + if (!ParseFreeStringInto(String)) return false; + } + } while (*Position != ' '); + return true; + } + + bool ParseQuotedStringInto(std::string &String) { + if (!Next()) return false; + while (*Position != '"') { + if (!SkipEscapeCharacter()) return false; + String.push_back(*Position); + if (!Next()) return false; + } + return Next(); + } + + bool ParseFreeStringInto(std::string &String) { + do { + if (!SkipEscapeCharacter()) return false; + String.push_back(*Position); + if (!Next()) return false; + } while (*Position != ' ' && *Position != '"'); + return true; + } + + bool SkipEscapeCharacter() { + if (*Position == '\\') { + return Next(); + } + return true; + } + + bool NextNonWhitespace() { + do { + if (!Next()) return false; + } while (*Position == ' '); + return true; + } + + bool Next() { + ++Position; + if (Position == Input.end()) return false; + // Remove the JSON escaping first. This is done unconditionally. + if (*Position == '\\') ++Position; + return Position != Input.end(); + } + + const llvm::StringRef Input; + llvm::StringRef::iterator Position; + std::vector<std::string> CommandLine; +}; + +} // end namespace + +std::vector<std::string> UnescapeJsonCommandLine( + llvm::StringRef JsonEscapedCommandLine) { + CommandLineArgumentParser parser(JsonEscapedCommandLine); + return parser.Parse(); +} + +JsonCompileCommandLineParser::JsonCompileCommandLineParser( + const llvm::StringRef Input, CompileCommandHandler *CommandHandler) + : Input(Input), Position(Input.begin()-1), CommandHandler(CommandHandler) {} + +bool JsonCompileCommandLineParser::Parse() { + NextNonWhitespace(); + return ParseTranslationUnits(); +} + +std::string JsonCompileCommandLineParser::GetErrorMessage() const { + return ErrorMessage; +} + +bool JsonCompileCommandLineParser::ParseTranslationUnits() { + if (!ConsumeOrError('[', "at start of compile command file")) return false; + if (!ParseTranslationUnit(/*First=*/true)) return false; + while (Consume(',')) { + if (!ParseTranslationUnit(/*First=*/false)) return false; + } + if (!ConsumeOrError(']', "at end of array")) return false; + if (CommandHandler != NULL) { + CommandHandler->EndTranslationUnits(); + } + return true; +} + +bool JsonCompileCommandLineParser::ParseTranslationUnit(bool First) { + if (First) { + if (!Consume('{')) return true; + } else { + if (!ConsumeOrError('{', "at start of object")) return false; + } + if (!Consume('}')) { + if (!ParseObjectKeyValuePairs()) return false; + if (!ConsumeOrError('}', "at end of object")) return false; + } + if (CommandHandler != NULL) { + CommandHandler->EndTranslationUnit(); + } + return true; +} + +bool JsonCompileCommandLineParser::ParseObjectKeyValuePairs() { + do { + llvm::StringRef Key; + if (!ParseString(Key)) return false; + if (!ConsumeOrError(':', "between name and value")) return false; + llvm::StringRef Value; + if (!ParseString(Value)) return false; + if (CommandHandler != NULL) { + CommandHandler->HandleKeyValue(Key, Value); + } + } while (Consume(',')); + return true; +} + +bool JsonCompileCommandLineParser::ParseString(llvm::StringRef &String) { + if (!ConsumeOrError('"', "at start of string")) return false; + llvm::StringRef::iterator First = Position; + llvm::StringRef::iterator Last = Position; + while (!Consume('"')) { + Consume('\\'); + ++Position; + // We need to store Position, as Consume will change Last before leaving + // the loop. + Last = Position; + } + String = llvm::StringRef(First, Last - First); + return true; +} + +bool JsonCompileCommandLineParser::Consume(char C) { + if (Position == Input.end()) return false; + if (*Position != C) return false; + NextNonWhitespace(); + return true; +} + +bool JsonCompileCommandLineParser::ConsumeOrError( + char C, llvm::StringRef Message) { + if (!Consume(C)) { + SetExpectError(C, Message); + return false; + } + return true; +} + +void JsonCompileCommandLineParser::SetExpectError( + char C, llvm::StringRef Message) { + ErrorMessage = (llvm::Twine("'") + llvm::StringRef(&C, 1) + + "' expected " + Message + ".").str(); +} + +void JsonCompileCommandLineParser::NextNonWhitespace() { + do { + ++Position; + } while (IsWhitespace()); +} + +bool JsonCompileCommandLineParser::IsWhitespace() { + if (Position == Input.end()) return false; + return (*Position == ' ' || *Position == '\t' || + *Position == '\n' || *Position == '\r'); +} + +} // end namespace tooling +} // end namespace clang diff --git a/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.h b/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.h new file mode 100644 index 0000000..9e776d6 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/JsonCompileCommandLineDatabase.h @@ -0,0 +1,107 @@ +//===--- JsonCompileCommandLineDatabase - Simple JSON database --*- 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 reading a compile command line database, as written +// out for example by CMake. It only supports the subset of the JSON standard +// that is needed to parse the CMake output. +// See http://www.json.org/ for the full standard. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H +#define LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H + +#include "llvm/ADT/StringRef.h" +#include <string> +#include <vector> + +namespace clang { +namespace tooling { + +/// \brief Converts a JSON escaped command line to a vector of arguments. +/// +/// \param JsonEscapedCommandLine The escaped command line as a string. This +/// is assumed to be escaped as a JSON string (e.g. " and \ are escaped). +/// In addition, any arguments containing spaces are assumed to be \-escaped +/// +/// For example, the input (|| denoting non C-escaped strings): +/// |./call a \"b \\\" c \\\\ \" d| +/// would yield: +/// [ |./call|, |a|, |b " c \ |, |d| ]. +std::vector<std::string> UnescapeJsonCommandLine( + llvm::StringRef JsonEscapedCommandLine); + +/// \brief Interface for users of the JsonCompileCommandLineParser. +class CompileCommandHandler { + public: + virtual ~CompileCommandHandler() {} + + /// \brief Called after all translation units are parsed. + virtual void EndTranslationUnits() {} + + /// \brief Called at the end of a single translation unit. + virtual void EndTranslationUnit() {} + + /// \brief Called for every (Key, Value) pair in a translation unit + /// description. + virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {} +}; + +/// \brief A JSON parser that supports the subset of JSON needed to parse +/// JSON compile command line databases as written out by CMake. +/// +/// The supported subset describes a list of compile command lines for +/// each processed translation unit. The translation units are stored in a +/// JSON array, where each translation unit is described by a JSON object +/// containing (Key, Value) pairs for the working directory the compile command +/// line was executed from, the main C/C++ input file of the translation unit +/// and the actual compile command line, for example: +/// [ +/// { +/// "file":"/file.cpp", +/// "directory":"/", +/// "command":"/cc /file.cpp" +/// } +/// ] +class JsonCompileCommandLineParser { + public: + /// \brief Create a parser on 'Input', calling 'CommandHandler' to handle the + /// parsed constructs. 'CommandHandler' may be NULL in order to just check + /// the validity of 'Input'. + JsonCompileCommandLineParser(const llvm::StringRef Input, + CompileCommandHandler *CommandHandler); + + /// \brief Parses the specified input. Returns true if no parsing errors were + /// foudn. + bool Parse(); + + /// \brief Returns an error message if Parse() returned false previously. + std::string GetErrorMessage() const; + + private: + bool ParseTranslationUnits(); + bool ParseTranslationUnit(bool First); + bool ParseObjectKeyValuePairs(); + bool ParseString(llvm::StringRef &String); + bool Consume(char C); + bool ConsumeOrError(char C, llvm::StringRef Message); + void NextNonWhitespace(); + bool IsWhitespace(); + void SetExpectError(char C, llvm::StringRef Message); + + const llvm::StringRef Input; + llvm::StringRef::iterator Position; + std::string ErrorMessage; + CompileCommandHandler * const CommandHandler; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H diff --git a/contrib/llvm/tools/clang/lib/Tooling/Makefile b/contrib/llvm/tools/clang/lib/Tooling/Makefile new file mode 100644 index 0000000..501a00c --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/Makefile @@ -0,0 +1,15 @@ +##===- clang/lib/Tooling/Makefile ---------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. +LIBRARYNAME := clangTooling + +include $(CLANG_LEVEL)/Makefile + + diff --git a/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp new file mode 100644 index 0000000..c1714a9 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp @@ -0,0 +1,322 @@ +//===--- Tooling.cpp - Running clang standalone tools --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements functions to run clang tools standalone instead +// of running them as a plugin. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Tool.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendAction.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" +#include "JsonCompileCommandLineDatabase.h" +#include <map> +#include <cstdio> + +namespace clang { +namespace tooling { + +namespace { + +// Checks that the input conforms to the argv[] convention as in +// main(). Namely: +// - it must contain at least a program path, +// - argv[0], ..., and argv[argc - 1] mustn't be NULL, and +// - argv[argc] must be NULL. +void ValidateArgv(int argc, char* argv[]) { + if (argc < 1) { + fprintf(stderr, "ERROR: argc is %d. It must be >= 1.\n", argc); + abort(); + } + + for (int i = 0; i < argc; ++i) { + if (argv[i] == NULL) { + fprintf(stderr, "ERROR: argv[%d] is NULL.\n", i); + abort(); + } + } + + if (argv[argc] != NULL) { + fprintf(stderr, "ERROR: argv[argc] isn't NULL.\n"); + abort(); + } +} + +} // end namespace + +// FIXME: This file contains structural duplication with other parts of the +// code that sets up a compiler to run tools on it, and we should refactor +// it to be based on the same framework. + +static clang::Diagnostic* NewTextDiagnostics() { + llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs( + new clang::DiagnosticIDs()); + clang::TextDiagnosticPrinter *DiagClient = new clang::TextDiagnosticPrinter( + llvm::errs(), clang::DiagnosticOptions()); + return new clang::Diagnostic(DiagIDs, DiagClient); +} + +// Exists solely for the purpose of lookup of the main executable. +static int StaticSymbol; + +/// \brief Builds a clang driver initialized for running clang tools. +static clang::driver::Driver* NewDriver(clang::Diagnostic* Diagnostics, + const char* BinaryName) { + // This just needs to be some symbol in the binary. + void* const SymbolAddr = &StaticSymbol; + const llvm::sys::Path ExePath = + llvm::sys::Path::GetMainExecutable(BinaryName, SymbolAddr); + + const std::string DefaultOutputName = "a.out"; + clang::driver::Driver* CompilerDriver = new clang::driver::Driver( + ExePath.str(), llvm::sys::getHostTriple(), + DefaultOutputName, false, false, *Diagnostics); + CompilerDriver->setTitle("clang_based_tool"); + return CompilerDriver; +} + +/// \brief Retrieves the clang CC1 specific flags out of the compilation's jobs. +/// Returns NULL on error. +static const clang::driver::ArgStringList* GetCC1Arguments( + clang::Diagnostic* Diagnostics, clang::driver::Compilation* Compilation) { + // We expect to get back exactly one Command job, if we didn't something + // failed. Extract that job from the Compilation. + const clang::driver::JobList &Jobs = Compilation->getJobs(); + if (Jobs.size() != 1 || !isa<clang::driver::Command>(*Jobs.begin())) { + llvm::SmallString<256> error_msg; + llvm::raw_svector_ostream error_stream(error_msg); + Compilation->PrintJob(error_stream, Compilation->getJobs(), "; ", true); + Diagnostics->Report(clang::diag::err_fe_expected_compiler_job) + << error_stream.str(); + return NULL; + } + + // The one job we find should be to invoke clang again. + const clang::driver::Command *Cmd = + cast<clang::driver::Command>(*Jobs.begin()); + if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") { + Diagnostics->Report(clang::diag::err_fe_expected_clang_command); + return NULL; + } + + return &Cmd->getArguments(); +} + +/// \brief Returns a clang build invocation initialized from the CC1 flags. +static clang::CompilerInvocation* NewInvocation( + clang::Diagnostic* Diagnostics, + const clang::driver::ArgStringList& CC1Args) { + clang::CompilerInvocation* Invocation = new clang::CompilerInvocation; + clang::CompilerInvocation::CreateFromArgs( + *Invocation, CC1Args.data(), CC1Args.data() + CC1Args.size(), + *Diagnostics); + Invocation->getFrontendOpts().DisableFree = false; + return Invocation; +} + +/// \brief Runs the specified clang tool action and returns whether it executed +/// successfully. +static bool RunInvocation(const char* BinaryName, + clang::driver::Compilation* Compilation, + clang::CompilerInvocation* Invocation, + const clang::driver::ArgStringList& CC1Args, + clang::FrontendAction* ToolAction) { + llvm::OwningPtr<clang::FrontendAction> ScopedToolAction(ToolAction); + // Show the invocation, with -v. + if (Invocation->getHeaderSearchOpts().Verbose) { + llvm::errs() << "clang Invocation:\n"; + Compilation->PrintJob(llvm::errs(), Compilation->getJobs(), "\n", true); + llvm::errs() << "\n"; + } + + // Create a compiler instance to handle the actual work. + clang::CompilerInstance Compiler; + Compiler.setInvocation(Invocation); + + // Create the compilers actual diagnostics engine. + Compiler.createDiagnostics(CC1Args.size(), + const_cast<char**>(CC1Args.data())); + if (!Compiler.hasDiagnostics()) + return false; + + // Infer the builtin include path if unspecified. + if (Compiler.getHeaderSearchOpts().UseBuiltinIncludes && + Compiler.getHeaderSearchOpts().ResourceDir.empty()) { + // This just needs to be some symbol in the binary. + void* const SymbolAddr = &StaticSymbol; + Compiler.getHeaderSearchOpts().ResourceDir = + clang::CompilerInvocation::GetResourcesPath(BinaryName, SymbolAddr); + } + + const bool Success = Compiler.ExecuteAction(*ToolAction); + return Success; +} + +/// \brief Converts a string vector representing a Command line into a C +/// string vector representing the Argv (including the trailing NULL). +std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command) { + std::vector<char*> Result(Command->size() + 1); + for (std::vector<char*>::size_type I = 0; I < Command->size(); ++I) { + Result[I] = const_cast<char*>((*Command)[I].c_str()); + } + Result[Command->size()] = NULL; + return Result; +} + +bool RunToolWithFlags( + clang::FrontendAction* ToolAction, int Args, char* Argv[]) { + ValidateArgv(Args, Argv); + const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics()); + const llvm::OwningPtr<clang::driver::Driver> Driver( + NewDriver(Diagnostics.get(), Argv[0])); + const llvm::OwningPtr<clang::driver::Compilation> Compilation( + Driver->BuildCompilation(llvm::ArrayRef<const char*>(Argv, Args))); + const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments( + Diagnostics.get(), Compilation.get()); + if (CC1Args == NULL) { + return false; + } + llvm::OwningPtr<clang::CompilerInvocation> Invocation( + NewInvocation(Diagnostics.get(), *CC1Args)); + return RunInvocation(Argv[0], Compilation.get(), Invocation.take(), + *CC1Args, ToolAction); +} + +/// \brief Runs 'ToolAction' on the code specified by 'FileContents'. +/// +/// \param FileContents A mapping from file name to source code. For each +/// entry a virtual file mapping will be created when running the tool. +bool RunToolWithFlagsOnCode( + const std::vector<std::string>& CommandLine, + const std::map<std::string, std::string>& FileContents, + clang::FrontendAction* ToolAction) { + const std::vector<char*> Argv = CommandLineToArgv(&CommandLine); + const char* const BinaryName = Argv[0]; + + const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics()); + const llvm::OwningPtr<clang::driver::Driver> Driver( + NewDriver(Diagnostics.get(), BinaryName)); + + // Since the Input is only virtual, don't check whether it exists. + Driver->setCheckInputsExist(false); + + const llvm::OwningPtr<clang::driver::Compilation> Compilation( + Driver->BuildCompilation(llvm::ArrayRef<const char*>(&Argv[0], + Argv.size() - 1))); + const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments( + Diagnostics.get(), Compilation.get()); + if (CC1Args == NULL) { + return false; + } + llvm::OwningPtr<clang::CompilerInvocation> Invocation( + NewInvocation(Diagnostics.get(), *CC1Args)); + + for (std::map<std::string, std::string>::const_iterator + It = FileContents.begin(), End = FileContents.end(); + It != End; ++It) { + // Inject the code as the given file name into the preprocessor options. + const llvm::MemoryBuffer* Input = + llvm::MemoryBuffer::getMemBuffer(It->second.c_str()); + Invocation->getPreprocessorOpts().addRemappedFile(It->first.c_str(), Input); + } + + return RunInvocation(BinaryName, Compilation.get(), + Invocation.take(), *CC1Args, ToolAction); +} + +bool RunSyntaxOnlyToolOnCode( + clang::FrontendAction *ToolAction, llvm::StringRef Code) { + const char* const FileName = "input.cc"; + const char* const CommandLine[] = { + "clang-tool", "-fsyntax-only", FileName + }; + std::map<std::string, std::string> FileContents; + FileContents[FileName] = Code; + return RunToolWithFlagsOnCode( + std::vector<std::string>( + CommandLine, + CommandLine + sizeof(CommandLine)/sizeof(CommandLine[0])), + FileContents, ToolAction); +} + +namespace { + +// A CompileCommandHandler implementation that finds compile commands for a +// specific input file. +// +// FIXME: Implement early exit when JsonCompileCommandLineParser supports it. +class FindHandler : public clang::tooling::CompileCommandHandler { + public: + explicit FindHandler(llvm::StringRef File) + : FileToMatch(File), FoundMatchingCommand(false) {} + + virtual void EndTranslationUnits() { + if (!FoundMatchingCommand && ErrorMessage.empty()) { + ErrorMessage = "ERROR: No matching command found."; + } + } + + virtual void EndTranslationUnit() { + if (File == FileToMatch) { + FoundMatchingCommand = true; + MatchingCommand.Directory = Directory; + MatchingCommand.CommandLine = UnescapeJsonCommandLine(Command); + } + } + + virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) { + if (Key == "directory") { Directory = Value; } + else if (Key == "file") { File = Value; } + else if (Key == "command") { Command = Value; } + else { + ErrorMessage = (llvm::Twine("Unknown key: \"") + Key + "\"").str(); + } + } + + const llvm::StringRef FileToMatch; + bool FoundMatchingCommand; + CompileCommand MatchingCommand; + std::string ErrorMessage; + + llvm::StringRef Directory; + llvm::StringRef File; + llvm::StringRef Command; +}; + +} // end namespace + +CompileCommand FindCompileArgsInJsonDatabase( + llvm::StringRef FileName, llvm::StringRef JsonDatabase, + std::string &ErrorMessage) { + FindHandler find_handler(FileName); + JsonCompileCommandLineParser parser(JsonDatabase, &find_handler); + if (!parser.Parse()) { + ErrorMessage = parser.GetErrorMessage(); + return CompileCommand(); + } + return find_handler.MatchingCommand; +} + +} // end namespace tooling +} // end namespace clang + |